diff options
Diffstat (limited to 'mac')
43 files changed, 27298 insertions, 0 deletions
diff --git a/mac/MW_TkHeader.pch b/mac/MW_TkHeader.pch new file mode 100644 index 0000000..7b7e2a4 --- /dev/null +++ b/mac/MW_TkHeader.pch @@ -0,0 +1,129 @@ +/* + * MW_TkHeader.pch -- + * + * This file is the source for a pre-compilied header that gets used + * for all files in the Tk projects. This make compilies go a bit + * faster. This file is only intended to be used in the MetroWerks + * CodeWarrior environment. It essentially acts as a place to set + * compiler flags. See MetroWerks documention for more details. + * + * Copyright (c) 1995-1997 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) MW_TkHeader.pch 1.26 97/11/20 19:37:29 + */ + +/* + * To use the compilied header you need to set the "Prefix file" in + * the "C/C++ Language" preference panel to point to the created + * compilied header. The name of the header depends on the + * architecture we are compiling for (see the code below). For + * example, for a 68k app the prefix file should be: MW_TclHeader68K. + */ + +#if __POWERPC__ +#pragma precompile_target "MW_TkHeaderPPC" +#elif __CFM68K__ +#pragma precompile_target "MW_TkHeaderCFM68K" +#else +#pragma precompile_target "MW_TkHeader68K" +#endif + +/* + * Macintosh Tcl must be compiled with certain compiler options to + * ensure that it will work correctly. The following pragmas are + * used to ensure that those options are set correctly. An error + * will occur at compile time if they are not set correctly. + */ + +#if !__option(enumsalwaysint) +#error Tcl requires the Metrowerks setting "Enums always ints". +#endif + +#if !defined(__POWERPC__) +#if !__option(far_data) +#error Tcl requires the Metrowerks setting "Far data". +#endif +#endif + +#if !defined(__POWERPC__) +#if !__option(fourbyteints) +#error Tcl requires the Metrowerks setting "4 byte ints". +#endif +#endif + +#if !defined(__POWERPC__) +#if !__option(IEEEdoubles) +#error Tcl requires the Metrowerks setting "8 byte doubles". +#endif +#endif + +/* + * The define is used most everywhere to tell Tk (or any Tk + * extensions) that we are compiling for the Macintosh platform. + */ +#define MAC_TCL + +/* + * The following defines are for the Xlib.h file to force + * it to generate prototypes in the way we need it. This is + * defined here in case X.h & company are ever included before + * tk.h. + */ + +#define NeedFunctionPrototypes 1 +#define NeedWidePrototypes 0 + +/* + * The following defines control the behavior of the Macintosh + * Universial Headers. + */ + +#define SystemSevenOrLater 1 +#define STRICT_CONTROLS 0 +#define STRICT_WINDOWS 0 + +/* + * The appearance manager has not yet been shiped by Apple (10/29/97). + * It's currently in beta testing which is why we were able to write + * some code that depends on it. If you have access to the appearance + * manager you can define the symbol HAVE_APPEARANCE below to compile + * the code that uses the new appearance manager. + */ + +/* #define HAVE_APPEARANCE 1 */ + +/* + * Define the following symbol if you want + * comprehensive debugging turned on. + */ + +/* #define TCL_DEBUG */ + +#ifdef TCL_DEBUG +# define TCL_MEM_DEBUG +# define TK_TEST +# define TCL_TEST +#endif + +/* + * Apple's Universal Headers 2.0 & 3.0 change alot of names and constants. + * We will switch to the new names as soon as we can be reasonably sure the + * number of people with older versions of CodeWarrior, who will then not be + * able to build Tcl/Tk, is negligible. + */ + +#define OLDROUTINENAMES 1 + +/* + * Place any includes below that will are needed by the majority of the + * and is OK to be in any file in the system. + */ + +#include <tcl.h> +#pragma export on +#include "tk.h" +#include "tkInt.h" +#pragma export off diff --git a/mac/README b/mac/README new file mode 100644 index 0000000..3c8824a --- /dev/null +++ b/mac/README @@ -0,0 +1,299 @@ +Tk 8.0 for Macintosh + +by Ray Johnson +Sun Microsystems Laboratories +rjohnson@eng.sun.com + +SCCS: @(#) README 1.30 97/11/20 22:06:57 + +1. Introduction +--------------- + +This is the README file for the Macintosh version of the Tk +extension for the Tcl scripting language. The file consists of +information specific to the Macintosh version of Tcl and Tk. For more +general information please read the README file in the main Tk +directory. + +2. What's new? +------------- + +Native Look & Feel!!! We now try really hard to support the +Macintosh Look & Feel with Tcl/Tk 8.0. We aren't finished but +it look pretty good. Let me know what are the most "un-mac like" +problems and I'll fix them as quickly as I can. + +The button, checkbutton, radiobutton, and scrollbar widgets actually +use the Mac toolbox controls. This means that they will track the +look&feel if you use extension that change the appearance of +applications (like Aaron.) We also use "system" colors so the default +backgrounds etc. will also change colors. We plan to support this +feature - so let me know if something doesn't work quite right. +Unfortunantly, we are not able to change the colors of buttons under +MacOS 8. We are working on a solution to this. +In the meantime, if you really must have colored buttons, turn off the +"System-wide platinum appearance" option in the Appearance Control Panel, +and you will get the System 7, colorable, buttons back. + +We also now support native menus! By using the new -menu option +on toplevels you can have a menubar that is cross platform. You +can also place Tk menus in the Apple and Help menus! Check out +the documentation for more details. Syd Polk <icepick@eng.sun.com> is +the author of the new menu code. Feel free to contact him if you +have questions or comments about the menu mechanism. + +The "tk_messageBox" command on the Macintosh is now much more +mac-like. I'll probably still need to adjust this more - but it +looks a hell of alot better than it did before. + +I've also added a command that allows you to get more native window +styles. However, we have yet to decide on a cross platform solution +to the problem of varying window styles. None the less, I thought +it would be use full to add the capability in an unsupported means +to tide you over until a better solution is available. The command +is called "unsupported1". It can be used in the following way: + + toplevel .foo; unsupported1 style .foo zoomDocProc + +The above command will create a document window with a zoom box. +Type "unsupported1 style . ???" to get a list of the supported +styles. The command works like "wm overrideredirect" - you must +make the call before the window is mapped. + +As always - report the bugs you find - including asthetic ones +in the look & feel of widgets. + +3. Mac specific features +------------------------ + +There are several features or enhancements in Tk that are unique to +the Macintosh version of Tk. Here is a list of those features and +pointers to where you can find more information about the feature. + +* The menu command has special rules for accessing the Macintosh + Apple and Help menus. See the menu.m man page for details. + +* If you have the special Tcl function "tkAboutDialog" defined, it + will be called instead of displaying the default About Box in the + console or other parts of the Wish application. See below for + details. + +* In addition to the standard X cursors, the Mac version of Tk will + let you use any Mac cursor that is named and installed in your + application. See the GetCursor.3 man page for details. + +* The wish application has a couple of hooks to know about the exit, + "open document" and "Do Script" Mac High Level events. + See below for details. + +* The command unsupported1 will allow you to set the style of new + toplevel windows on the Macintosh. It is not really supported. + See below for details. + +* In addition to the standard built-in bitmaps that Tk supports, the + Mac version of Tk allows you to use several Mac specific icons. See + the GetBitmap.3 man page for a complete list. + +* The send command does not yet work on the Macintosh. We hope to + have it available in Tk 8.1. + +* The -use and -container options almost work. The focus bugs that + were in Tk8.0 final have been fixed. But there are still some + known bugs that cause some major problems. Be careful, if you + decide to use these features. (See bugs.doc for details.) + +4. The Distribution +------------------- + +Macintosh Tk is distributed in three different forms. This +should make it easier to only download what you need. The +packages are as follows: + +mactk8.0.sea.hqx + + This distribution is a "binary" only release. It contains an + installer program that will install a 68k, PowerPC, or Fat + version of the "Wish" application. In addition, in installs + the Tcl & Tk libraries in the Extensions folder inside your + System Folder. (No "INIT"'s or Control Pannels are installed.) + +mactcltk-full-8.0.sea.hqx + + This release contains the full release of Tcl and Tk for the + Macintosh plus the More Files package on which Macintosh Tcl and + Tk rely. + +mactk-source-8.0.sea.hqx + + This release contains the complete source to Tk for the Macintosh + In addition, Metrowerks CodeWarrior libraries and project files + are included. However, you must already have the More Files + package to compile this code. + +5. Documentation +---------------- + +Two books are currently available for Tcl. Both provide a good +introduction to the language. It is a good way to get started +if you haven't used the language before: + + Title: Tcl and the Tk Toolkit + Author: John K. Ousterhout + Publisher: Addison-Wesley + ISBN: 0-201-63337-X + + Title: Practical Programming in Tcl and Tk + Author: Brent Welch + Publisher: Prentice Hall + ISBN: 0-13-182007-9 + +The "doc" subdirectory contains reference in documentation +in the "man" format found on most UNIX machines. Unfortunately, +there is not a suitable way to view these pages on the Macintosh. +A version suitable for viewing on the Macintosh has yet to be +developed. We are working are having better documentation for +the Macintosh platform in the future. However, if you have WWW +access you may access the Man pages at the following URL: + + http://sunscript.sun.com/man/tcl8.0/contents.html + +Other documentation and sample Tcl scripts can be found at +the Tcl ftp site: + + ftp://ftp.neosoft.com/tcl/ + +The internet news group comp.lang.tcl is also a valuable +source of information about Tcl. A mailing list is also +available (see below). + +6. Compiling Tk +--------------- + +In order to compile Macintosh Tk you must have the +following items: + + CodeWarrior Pro 1 or higher (CodeWarrior release 9 or higher can work + and we have project files, but we are depricating support) + Mac Tcl 8.0 (source) + (which requires More Files 1.4.2 or 1.4.3) + Mac Tk 8.0 (source) + +The project files included with the Mac Tcl source should work +fine. The only thing you may need to update are the access paths. +As with Tcl, there is something in the initial release of the CW Pro 2 +linker that rendersthe CFM68K version of Wish very unstable. I am +working with Metrowerks to resolve the issue. + +Special notes: + +* Check out the file bugs.doc for information about known bugs. + +* We are starting to support the new Appearance Manager that shipped + with MacOS 8. At this point, the only feature that we are using is + the API to Iconify windows (so that wm iconify will work). However, + as of the release of Tk8.0p1, the SDK from Apple is still in Beta, so + we cannot ship it. So support for the Appearance Manager is turned off + in the source version of Tk8.0p1. + If you want to build Tk, and want to get the Appearance Manager features, + then need to do the following: + 1) get the SDK from Apple + 2) Uncomment the #define HAVE_APPEARANCE line in tk8.0:mac:MW_TkHeader.pch + 3) Add the Appearance.lib to tk8.0:mac:TkShells.¼, and put the include + directory of the SDK on your path in this project, and TkLibraries.¼. + +7. About Dialog +--------------- + +There is now a way to replace the default dialog box for the Wish +application. If you create the tcl procedure "tkAboutDialog" it will +be called instead of creating the default dialog box. Your procedure +is then responsible for displaying a window, removing it, etc. This +interface is experimental and may change in the future - tell me what +you think of it. + +8. Apple Events +--------------- + +Tcl/Tk currently doesn't have much in the way of support for Mac +Apple Events. There is no way to send an apple event (although you +could write an extension to do this) and no general purpose way to +recieve apple events. However, there are a couple of hooks for +dealing with some of the standard apple events. + + exit - Generally, Tcl cleans up after it self when you exit. + However, your application may want to do application specifc + cleanup like saving a users data. To do this you can rename + the exit command to something else. Define your own exit + command to do whatever clean up you like and then call the + origional exit command. For example, + + rename exit __exit + proc exit {} { + # Do your clean up hear + __exit + } + + Both incoming quit events and hitting the Quit menu item + will call the exit command. However, don't expect you can + abort the exit. Tk may exit anyway if the exit command it + calls does not actually quit the application. + + open - The other apple event Tk supports is the open event. The + open event is sent to Tk if, for example, you drop a file on + the Wish icon. If you define a Tcl procedure with the name + "tkOpenDocument" it will be invoked on any Open Document + events that the application receives. The a list of paths to + the various documents will be passed to the Tcl function. + Here is an example, + + proc tkOpenDocument args { + foreach file $args { + # Deal with passed in file path + } + } + + Note: This isn't every thing you need to do to make your + application dropable. You must still define a FREF resource + that makes sense for your application domain. (Out of the + box, you will not be able to drop files on the Wish + application. See the Inside Macintosh documentation for + details about the FREF resource. + + do script - This is a way for external applications to drive MacTk, or + to recieve information from it. From AppleScript, you can say: + + tell application "Wish8.0" + do script "console hide + pack [button .b1 -text {Hello world} -command exit]" + end tell + + which will get Tk to run the canonical hello world application. + +8. unsupported1 +--------------- + +The unsupported1 command is a short term hack we made available to +allow you to set the window style of a new toplevel window. It works +much like the "wm overrideredirect" and "wm transient" commands in +that it must be run before the window it's being applied to is mapped. + +The syntax of the command is as follows: + + unsupported1 style <window> ?style? + +The <window> must be a toplevel window. If the style is not given +then the current style for the window is returned. If you want to set +the style you must do so before the window gets mapped for the first +time. The possible window styles include: + + documentProc, dBoxProc, plainDBox, altDBoxProc, + movableDBoxProc, zoomDocProc, rDocProc, floatProc, + floatZoomProc, floatSideProc, or floatSideZoomProc + +NOTE: this is an unsupported command and it WILL go away in the +future. + + +If you have comments or Bug reports send them to: +Jim Ingham +jingham@eng.sun.com diff --git a/mac/bugs.doc b/mac/bugs.doc new file mode 100644 index 0000000..e522d8c --- /dev/null +++ b/mac/bugs.doc @@ -0,0 +1,40 @@ +Known bug list for Tk 8.0 for Macintosh + +by Ray Johnson +Sun Microsystems Laboratories +rjohnson@eng.sun.com + +SCCS: @(#) bugs.doc 1.10 97/11/03 17:16:00 + +We are now very close to passing the test suite for Tk. We are very +interested in finding remaining bugs that still linger. Please let us +know (and send us test cases) of any bugs you find. + +Known bugs: + +* Transient windows (set by wm transient) do not go away when the + master does. + +* Tearoff menus should be floating windows & floating windows should + float. They also shouldn't be resizable. + +* The -use and -container windows only work with other Tk windows in + the same process. Also, if you try really hard (for instance by binding + on Destroy of an embedded window and destroying the container's toplevel) + you can get Tk to crash. This should never be necessary, however, since + the destruction of the embedded window triggers the destruction of the + container, so you can watch that instead. + All the focus bugs in Tk8.0 have been fixed, however. + +* The send command is not yet implemented. + +* Drawing is not really correct. This shows up mostly in the canvas + when line widths are greater than one. Unfortunantly, this will not + be easy to fix. + +There are many other bugs. However, will no get listed until they +are reported at least once. Send those bug reports in! + + + +Ray diff --git a/mac/tclets.tcl b/mac/tclets.tcl new file mode 100644 index 0000000..c8726a8 --- /dev/null +++ b/mac/tclets.tcl @@ -0,0 +1,215 @@ +# tclets.tcl -- +# +# Drag & Drop Tclets +# by Ray Johnson +# +# A simple way to create Tcl applications. This applications will copy a droped Tcl file +# into a copy of a stub application (the user can pick). The file is placed into the +# TEXT resource named "tclshrc" which is automatically executed on startup. +# +# SCCS: @(#) tclets.tcl 1.2 97/08/15 09:25:56 +# +# Copyright (c) 1997 Sun Microsystems, Inc. +# +# See the file "license.terms" for information on usage and redistribution +# of this file, and for a DISCLAIMER OF ALL WARRANTIES. +# + +# tkOpenDocument -- +# +# This procedure is a called whenever Wish recieves an "Open" event. The +# procedure must be named tkOpenDocument for this to work. Passed in files +# are assumed to be Tcl files that the user wants to be made into Tclets. +# (Only the first one is used.) The procedure then creates a copy of the +# stub app and places the Tcl file in the new application's resource fork. +# +# Parameters: +# args List of files +# +# Results: +# One success a new Tclet is created. + +proc tkOpenDocument {args} { + global droped_to_start + + # We only deal with the one file droped on the App + set tclFile [lindex $args 0] + set stub [GetStub] + + # Give a helper screen to guide user + toplevel .helper -menu .bar + unsupported1 style .helper dBoxProc + message .helper.m -aspect 300 -text \ + "Select the name & location of your target Tcl application." + pack .helper.m + wm geometry .helper +20+40 + update idletasks + + # Get the target file from the end user + set target [tk_getSaveFile] + destroy .helper + if {$target == ""} return + + # Copy stub, copy the droped file into the stubs text resource + file copy $stub $target + set id [open $tclFile r] + set rid [resource open $target w] + resource write -name tclshrc -file $rid TEXT [read $id] + resource close $rid + close $id + + # This is a hint to the start-up code - always set to true + set droped_to_start true +} + +# GetStub -- +# +# Get the location of our stub application. The value may be cached, +# in the preferences file, or we may need to ask the user. +# +# Parameters: +# None. +# +# Results: +# A path to the stub application. + +proc GetStub {} { + global env stub_location + + if {[info exists stub_location]} { + return $stub_location + } + + set file $env(PREF_FOLDER) + append file "D&D Tclet Preferences" + + + if {[file exists $file]} { + uplevel #0 [list source $file] + if {[info exists stub_location] && [file exists $stub_location]} { + return $stub_location + } + } + + SelectStub + + if {[info exists stub_location]} { + return $stub_location + } else { + exit + } +} + +# SelectStub -- +# +# This procedure uses tk_getOpenFile to allow the user to select +# the copy of "Wish" that is used as the basis for Tclets. The +# result is stored in a preferences file. +# +# Parameters: +# None. +# +# Results: +# None. The prefernce file is updated. + +proc SelectStub {} { + global env stub_location + + # Give a helper screen to guide user + toplevel .helper -menu .bar + unsupported1 style .helper dBoxProc + message .helper.m -aspect 300 -text \ + "Select \"Wish\" stub to clone. A copy of this application will be made to create your Tclet." \ + + pack .helper.m + wm geometry .helper +20+40 + update idletasks + + set new_location [tk_getOpenFile] + destroy .helper + if {$new_location != ""} { + set stub_location $new_location + set file [file join $env(PREF_FOLDER) "D&D Tclet Preferences"] + + set id [open $file w] + puts $id [list set stub_location $stub_location] + close $id + } +} + +# CreateMenus -- +# +# Create the menubar for this application. +# +# Parameters: +# None. +# +# Results: +# None. + +proc CreateMenus {} { + menu .bar + .bar add cascade -menu .bar.file -label File + .bar add cascade -menu .bar.apple + . configure -menu .bar + + menu .bar.apple -tearoff 0 + .bar.apple add command -label "About Drag & Drop Tclets..." -command {ShowAbout} + + menu .bar.file -tearoff 0 + .bar.file add command -label "Show Console..." -command {console show} + .bar.file add command -label "Select Wish Stub..." -command {SelectStub} + .bar.file add separator + .bar.file add command -label "Quit" -accel Command-Q -command exit +} + +# ShowAbout -- +# +# Show the about box for Drag & Drop Tclets. +# +# Parameters: +# None. +# +# Results: +# None. + +proc ShowAbout {} { + tk_messageBox -icon info -type ok -message \ +"Drag & Drop Tclets +by Ray Johnson\n\n\ +Copyright (c) 1997 Sun Microsystems, Inc." +} + +# Start -- +# +# This procedure provides the main start-up code for the application. +# It should be run first thing on start up. It will create the UI +# and set up the rest of the state of the application. +# +# Parameters: +# None. +# +# Results: +# None. + +proc Start {} { + global droped_to_start + + # Hide . & console - see if we ran as a droped item + wm geometry . 1x1-25000-25000 + console hide + + # Run update - if we get any drop events we know that we were + # started by a drag & drop - if so, we quit automatically when done + set droped_to_start false + update + if {$droped_to_start == "true"} { + exit + } + + # We were not started by a drag & drop - create the UI + CreateMenus +} + +# Now that everything is defined, lets start the app! +Start diff --git a/mac/tkMac.h b/mac/tkMac.h new file mode 100644 index 0000000..ce41c81 --- /dev/null +++ b/mac/tkMac.h @@ -0,0 +1,53 @@ +/* + * tkMacInt.h -- + * + * Declarations of Macintosh specific exported variables and procedures. + * + * Copyright (c) 1995-1997 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) tkMacInt.h 1.58 97/05/06 16:45:18 + */ + +#ifndef _TKMAC +#define _TKMAC + +#include <Windows.h> + +/* + * "export" is a MetroWerks specific pragma. It flags the linker that + * any symbols that are defined when this pragma is on will be exported + * to shared libraries that link with this library. + */ + +#pragma export on + +/* + * This variable is exported and can be used by extensions. It is the + * way Tk extensions should access the QD Globals. This is so Tk + * can support embedding itself in another window. + */ + +EXTERN QDGlobalsPtr tcl_macQdPtr; + +/* + * The following functions are needed to create a shell, and so they must be exported + * from the Tk library. However, these are not the final form of these interfaces, so + * they are not currently supported as public interfaces. + */ + +/* + * These functions are currently in tkMacInt.h. They are just copied over here + * so they can be exported. + */ + +EXTERN void TkMacInitMenus _ANSI_ARGS_((Tcl_Interp *interp)); +EXTERN void TkMacInitAppleEvents _ANSI_ARGS_((Tcl_Interp *interp)); + +EXTERN int TkMacConvertEvent _ANSI_ARGS_((EventRecord *eventPtr)); + +#pragma export reset + +#endif /* _TKMAC */ diff --git a/mac/tkMacAppInit.c b/mac/tkMacAppInit.c new file mode 100644 index 0000000..ebc2c18 --- /dev/null +++ b/mac/tkMacAppInit.c @@ -0,0 +1,374 @@ +/* + * tkMacAppInit.c -- + * + * Provides a version of the Tcl_AppInit procedure for the example shell. + * + * Copyright (c) 1993-1994 Lockheed Missle & Space Company, AI Center + * Copyright (c) 1995-1997 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) tkMacAppInit.c 1.35 97/07/28 11:18:55 + */ + +#include <Gestalt.h> +#include <ToolUtils.h> +#include <Fonts.h> +#include <Dialogs.h> +#include <SegLoad.h> +#include <Traps.h> + +#include "tk.h" +#include "tkInt.h" +#include "tkMacInt.h" +#include "tclMac.h" + +#ifdef TK_TEST +EXTERN int Tktest_Init _ANSI_ARGS_((Tcl_Interp *interp)); +#endif /* TK_TEST */ + +#ifdef TCL_TEST +EXTERN int TclObjTest_Init _ANSI_ARGS_((Tcl_Interp *interp)); +EXTERN int Tcltest_Init _ANSI_ARGS_((Tcl_Interp *interp)); +#endif /* TCL_TEST */ + +Tcl_Interp *gStdoutInterp = NULL; + +int TkMacConvertEvent _ANSI_ARGS_((EventRecord *eventPtr)); + +/* + * Prototypes for functions the ANSI library needs to link against. + */ +short InstallConsole _ANSI_ARGS_((short fd)); +void RemoveConsole _ANSI_ARGS_((void)); +long WriteCharsToConsole _ANSI_ARGS_((char *buff, long n)); +long ReadCharsFromConsole _ANSI_ARGS_((char *buff, long n)); +extern char * __ttyname _ANSI_ARGS_((long fildes)); +short SIOUXHandleOneEvent _ANSI_ARGS_((EventRecord *event)); + +/* + * Prototypes for functions from the tkConsole.c file. + */ + +EXTERN void TkConsoleCreate _ANSI_ARGS_((void)); +EXTERN int TkConsoleInit _ANSI_ARGS_((Tcl_Interp *interp)); +EXTERN void TkConsolePrint _ANSI_ARGS_((Tcl_Interp *interp, + int devId, char *buffer, long size)); +/* + * Forward declarations for procedures defined later in this file: + */ + +static int MacintoshInit _ANSI_ARGS_((void)); +static int SetupMainInterp _ANSI_ARGS_((Tcl_Interp *interp)); + +/* + *---------------------------------------------------------------------- + * + * main -- + * + * Main program for Wish. + * + * Results: + * None. This procedure never returns (it exits the process when + * it's done + * + * Side effects: + * This procedure initializes the wish world and then + * calls Tk_Main. + * + *---------------------------------------------------------------------- + */ + +void +main( + int argc, /* Number of arguments. */ + char **argv) /* Array of argument strings. */ +{ + char *newArgv[2]; + + if (MacintoshInit() != TCL_OK) { + Tcl_Exit(1); + } + + argc = 1; + newArgv[0] = "Wish"; + newArgv[1] = NULL; + Tk_Main(argc, newArgv, Tcl_AppInit); +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_AppInit -- + * + * This procedure performs application-specific initialization. + * Most applications, especially those that incorporate additional + * packages, will have their own version of this procedure. + * + * Results: + * Returns a standard Tcl completion code, and leaves an error + * message in interp->result if an error occurs. + * + * Side effects: + * Depends on the startup script. + * + *---------------------------------------------------------------------- + */ + +int +Tcl_AppInit( + Tcl_Interp *interp) /* Interpreter for application. */ +{ + if (Tcl_Init(interp) == TCL_ERROR) { + return TCL_ERROR; + } + if (Tk_Init(interp) == TCL_ERROR) { + return TCL_ERROR; + } + Tcl_StaticPackage(interp, "Tk", Tk_Init, Tk_SafeInit); + + /* + * Call the init procedures for included packages. Each call should + * look like this: + * + * if (Mod_Init(interp) == TCL_ERROR) { + * return TCL_ERROR; + * } + * + * where "Mod" is the name of the module. + */ + +#ifdef TCL_TEST + if (Tcltest_Init(interp) == TCL_ERROR) { + return TCL_ERROR; + } + Tcl_StaticPackage(interp, "Tcltest", Tcltest_Init, + (Tcl_PackageInitProc *) NULL); + if (TclObjTest_Init(interp) == TCL_ERROR) { + return TCL_ERROR; + } +#endif /* TCL_TEST */ + +#ifdef TK_TEST + if (Tktest_Init(interp) == TCL_ERROR) { + return TCL_ERROR; + } + Tcl_StaticPackage(interp, "Tktest", Tktest_Init, + (Tcl_PackageInitProc *) NULL); +#endif /* TK_TEST */ + + /* + * Call Tcl_CreateCommand for application-specific commands, if + * they weren't already created by the init procedures called above. + * Each call would look like this: + * + * Tcl_CreateCommand(interp, "tclName", CFuncCmd, NULL, NULL); + */ + + SetupMainInterp(interp); + + /* + * Specify a user-specific startup script to invoke if the application + * is run interactively. On the Mac we can specifiy either a TEXT resource + * which contains the script or the more UNIX like file location + * may also used. (I highly recommend using the resource method.) + */ + + Tcl_SetVar(interp, "tcl_rcRsrcName", "tclshrc", TCL_GLOBAL_ONLY); + /* Tcl_SetVar(interp, "tcl_rcFileName", "~/.tclshrc", TCL_GLOBAL_ONLY); */ + + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * MacintoshInit -- + * + * This procedure calls Mac specific initilization calls. Most of + * these calls must be made as soon as possible in the startup + * process. + * + * Results: + * Returns TCL_OK if everything went fine. If it didn't the + * application should probably fail. + * + * Side effects: + * Inits the application. + * + *---------------------------------------------------------------------- + */ + +static int +MacintoshInit() +{ + int i; + long result, mask = 0x0700; /* mask = system 7.x */ + +#if GENERATING68K && !GENERATINGCFM + SetApplLimit(GetApplLimit() - (TK_MAC_68K_STACK_GROWTH)); +#endif + MaxApplZone(); + for (i = 0; i < 4; i++) { + (void) MoreMasters(); + } + + /* + * Tk needs us to set the qd pointer it uses. This is needed + * so Tk doesn't have to assume the availablity of the qd global + * variable. Which in turn allows Tk to be used in code resources. + */ + tcl_macQdPtr = &qd; + + InitGraf(&tcl_macQdPtr->thePort); + InitFonts(); + InitWindows(); + InitMenus(); + InitDialogs((long) NULL); + InitCursor(); + + /* + * Make sure we are running on system 7 or higher + */ + + if ((NGetTrapAddress(_Gestalt, ToolTrap) == + NGetTrapAddress(_Unimplemented, ToolTrap)) + || (((Gestalt(gestaltSystemVersion, &result) != noErr) + || (result < mask)))) { + panic("Tcl/Tk requires System 7 or higher."); + } + + /* + * Make sure we have color quick draw + * (this means we can't run on 68000 macs) + */ + + if (((Gestalt(gestaltQuickdrawVersion, &result) != noErr) + || (result < gestalt32BitQD13))) { + panic("Tk requires Color QuickDraw."); + } + + + FlushEvents(everyEvent, 0); + SetEventMask(everyEvent); + + + Tcl_MacSetEventProc(TkMacConvertEvent); + TkConsoleCreate(); + + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * SetupMainInterp -- + * + * This procedure calls initalization routines require a Tcl + * interp as an argument. This call effectively makes the passed + * iterpreter the "main" interpreter for the application. + * + * Results: + * Returns TCL_OK if everything went fine. If it didn't the + * application should probably fail. + * + * Side effects: + * More initilization. + * + *---------------------------------------------------------------------- + */ + +static int +SetupMainInterp( + Tcl_Interp *interp) +{ + /* + * Initialize the console only if we are running as an interactive + * application. + */ + + TkMacInitAppleEvents(interp); + TkMacInitMenus(interp); + + if (strcmp(Tcl_GetVar(interp, "tcl_interactive", TCL_GLOBAL_ONLY), "1") + == 0) { + if (TkConsoleInit(interp) == TCL_ERROR) { + goto error; + } + } + + /* + * Attach the global interpreter to tk's expected global console + */ + + gStdoutInterp = interp; + + return TCL_OK; + +error: + panic(interp->result); + return TCL_ERROR; +} + +/* + *---------------------------------------------------------------------- + * + * InstallConsole, RemoveConsole, etc. -- + * + * The following functions provide the UI for the console package. + * Users wishing to replace SIOUX with their own console package + * need only provide the four functions below in a library. + * + * Results: + * See SIOUX documentation for details. + * + * Side effects: + * See SIOUX documentation for details. + * + *---------------------------------------------------------------------- + */ + +short +InstallConsole(short fd) +{ +#pragma unused (fd) + + return 0; +} + +void +RemoveConsole(void) +{ +} + +long +WriteCharsToConsole(char *buffer, long n) +{ + TkConsolePrint(gStdoutInterp, TCL_STDOUT, buffer, n); + return n; +} + +long +ReadCharsFromConsole(char *buffer, long n) +{ + return 0; +} + +extern char * +__ttyname(long fildes) +{ + static char *__devicename = "null device"; + + if (fildes >= 0 && fildes <= 2) { + return (__devicename); + } + + return (0L); +} + +short +SIOUXHandleOneEvent(EventRecord *event) +{ + return 0; +} diff --git a/mac/tkMacApplication.r b/mac/tkMacApplication.r new file mode 100644 index 0000000..365035d --- /dev/null +++ b/mac/tkMacApplication.r @@ -0,0 +1,267 @@ +/* + * tkMacApplication.r -- + * + * This file creates resources for use in the Wish application. + * + * Copyright (c) 1996 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) tkMacApplication.r 1.3 97/11/03 17:16:24 + */ + +#include <Types.r> +#include <SysTypes.r> +#include <AEUserTermTypes.r> + +/* + * The folowing include and defines help construct + * the version string for Tcl. + */ + +#define RESOURCE_INCLUDED +#include "tk.h" + +#if (TK_RELEASE_LEVEL == 0) +# define RELEASE_LEVEL alpha +#elif (TK_RELEASE_LEVEL == 1) +# define RELEASE_LEVEL beta +#elif (TK_RELEASE_LEVEL == 2) +# define RELEASE_LEVEL final +#endif + +#if (TK_RELEASE_LEVEL == 2) +# define MINOR_VERSION (TK_MINOR_VERSION * 16) + TK_RELEASE_SERIAL +#else +# define MINOR_VERSION TK_MINOR_VERSION * 16 +#endif + +#define RELEASE_CODE 0x00 + +resource 'vers' (1) { + TK_MAJOR_VERSION, MINOR_VERSION, + RELEASE_LEVEL, 0x00, verUS, + TK_PATCH_LEVEL, + TK_PATCH_LEVEL ", by Ray Johnson © 1993-1996" "\n" "Sun Microsystems Labratories" +}; + +resource 'vers' (2) { + TK_MAJOR_VERSION, MINOR_VERSION, + RELEASE_LEVEL, 0x00, verUS, + TK_PATCH_LEVEL, + "Wish " TK_PATCH_LEVEL " © 1993-1996" +}; + +#define TK_APP_RESOURCES 128 +#define TK_APP_CREATOR 'WIsH' + +/* + * The 'BNDL' resource is the primary link between a file's + * creator/type and its icon. This resource acts for all Tcl shared + * libraries; other libraries will not need one and ought to use + * custom icons rather than new file types for a different appearance. + */ + +resource 'BNDL' (TK_APP_RESOURCES, "Tk app bundle", purgeable) +{ + TK_APP_CREATOR, + 0, + { + 'FREF', + { + 0, TK_APP_RESOURCES, + 1, TK_APP_RESOURCES+1 + }, + 'ICN#', + { + 0, TK_APP_RESOURCES, + 1, TK_APP_RESOURCES+1 + } + } +}; + +resource 'FREF' (TK_APP_RESOURCES, purgeable) +{ + 'APPL', 0, "" +}; +resource 'FREF' (TK_APP_RESOURCES+1, purgeable) +{ + 'TEXT', 1, "" +}; + +type TK_APP_CREATOR as 'STR '; +resource TK_APP_CREATOR (0, purgeable) { + "Wish " TK_PATCH_LEVEL " © 1996" +}; + +/* + * The 'kind' resource works with a 'BNDL' in Macintosh Easy Open + * to affect the text the Finder displays in the "kind" column and + * file info dialog. This information will be applied to all files + * with the listed creator and type. + */ +resource 'kind' (TK_APP_RESOURCES, "Tcl kind", purgeable) { + TK_APP_CREATOR, + 0, /* region = USA */ + { + 'APPL', "Wish", + 'TEXT', "Tcl/Tk Script" + } +}; + +/* + * The following resource define the icon used by Tcl scripts. Any + * TEXT file with the creator of WIsH will get this icon. + */ + +data 'icl4' (TK_APP_RESOURCES + 1, "Tk Doc", purgeable) { + $"000F FFFF FFFF FFFF FFFF FFF0 0000 0000" + $"000F 3333 3333 3333 3333 33FF 0000 0000" + $"000F 3333 3333 3333 3433 33F2 F000 0000" + $"000F 3333 3333 3333 7D43 33F2 2F00 0000" + $"000F 3333 3333 3335 5623 33F2 22F0 0000" + $"000F 3333 3333 3356 6343 33FF FFFF 0000" + $"000F 3333 3333 256F 5223 3333 333F 0000" + $"000F 3333 3333 D666 2433 3333 333F 0000" + $"000F 3333 3333 D5F6 6633 3333 333F 0000" + $"000F 3333 3332 5666 6733 3333 333F 0000" + $"000F 3333 3336 E56F 6633 3333 333F 0000" + $"000F 3333 3336 5656 5733 3333 333F 0000" + $"000F 3333 3336 E5B6 5233 3333 333F 0000" + $"000F 3333 3336 5ED6 3333 3333 333F 0000" + $"000F 3333 3376 6475 6233 3333 333F 0000" + $"000F 3333 333D 5D56 7333 3333 333F 0000" + $"000F 3333 3336 6C55 6333 3333 333F 0000" + $"000F 3333 3336 5C56 7333 3333 333F 0000" + $"000F 3333 3362 6CE6 D333 3333 333F 0000" + $"000F 3333 3336 5C65 6333 3333 333F 0000" + $"000F 3333 3336 EC5E 3333 3333 333F 0000" + $"000F 3333 3336 5C56 6333 3333 333F 0000" + $"000F 3333 3333 5C75 3333 3333 333F 0000" + $"000F 3333 3333 5DD6 3333 3333 333F 0000" + $"000F 3333 3333 3CDD 3333 3333 333F 0000" + $"000F 3333 3333 3303 3333 3333 333F 0000" + $"000F 3333 3333 3C33 3333 3333 333F 0000" + $"000F 3333 3333 3C33 3333 3333 333F 0000" + $"000F 3333 3333 3C33 3333 3333 333F 0000" + $"000F 3333 3333 3333 3333 3333 333F 0000" + $"000F 3333 3333 3333 3333 3333 333F 0000" + $"000F FFFF FFFF FFFF FFFF FFFF FFFF 0000" +}; + +data 'ICN#' (TK_APP_RESOURCES + 1, "Tk Doc", purgeable) { + $"1FFF FE00 1000 0300 1000 F280 1003 F240" + $"1003 E220 1007 E3F0 100F C010 100F C010" + $"100F C010 101F F010 101F F010 101F F010" + $"101F F010 101F F010 101D E010 101D E010" + $"101D E010 101D C010 101D C010 101D C010" + $"101D C010 100D 8010 100D 8010 100D 8010" + $"1005 8010 1002 0010 1002 0010 1002 0010" + $"1002 0010 1002 0010 1000 0010 1FFF FFF0" + $"1FFF FE00 1FFF FF00 1FFF FF80 1FFF FFC0" + $"1FFF FFE0 1FFF FFF0 1FFF FFF0 1FFF FFF0" + $"1FFF FFF0 1FFF FFF0 1FFF FFF0 1FFF FFF0" + $"1FFF FFF0 1FFF FFF0 1FFF FFF0 1FFF FFF0" + $"1FFF FFF0 1FFF FFF0 1FFF FFF0 1FFF FFF0" + $"1FFF FFF0 1FFF FFF0 1FFF FFF0 1FFF FFF0" + $"1FFF FFF0 1FFF FFF0 1FFF FFF0 1FFF FFF0" + $"1FFF FFF0 1FFF FFF0 1FFF FFF0 1FFF FFF0" +}; + +data 'ics#' (TK_APP_RESOURCES + 1, "Tk Doc", purgeable) { + $"7FF0 41D8 419C 4384 43C4 47C4 47C4 4784" + $"4684 4684 4284 4284 4104 4104 4104 7FFC" + $"7FE0 7FF0 7FF8 7FFC 7FFC 7FFC 7FFC 7FFC" + $"7FFC 7FFC 7FFC 7FFC 7FFC 7FFC 7FFC 7FFC" +}; + +data 'ics4' (TK_APP_RESOURCES + 1, "Tk Doc", purgeable) { + $"0FFF FFFF FFFF 0000 0F33 3333 53F2 F000" + $"0F33 3335 52FF FF00 0F33 33E6 3333 3F00" + $"0F33 3256 6333 3F00 0F33 3556 6333 3F00" + $"0F33 3A5E 3333 3F00 0F33 65D6 D333 3F00" + $"0F33 3655 5333 3F00 0F33 65C6 3333 3F00" + $"0F33 3EC5 E333 3F00 0F33 36C6 3333 3F00" + $"0F33 33CD 3333 3F00 0F33 33C3 3333 3F00" + $"0F33 33C3 3333 3F00 0FFF FFFF FFFF FF00" +}; + +/* + * The following resources define the icons for the Wish + * application. + */ + +data 'icl4' (TK_APP_RESOURCES, "Tk App", purgeable) { + $"0000 0000 0000 000F 0000 0000 0000 0000" + $"0000 0000 0000 00FC F000 0000 0000 0000" + $"0000 0000 0000 0FCC CF66 0000 0000 0000" + $"0000 0000 0000 FCCC C556 0000 0000 0000" + $"0000 0000 000F CCCC 566F 0000 0000 0000" + $"0000 0000 00FC CCC5 6F5C F000 0000 0000" + $"0000 0000 0FCC CC66 66CC CF00 0000 0000" + $"0000 0000 FCCC CCD5 5666 CCF0 0000 0000" + $"0000 000F CCCC C656 5667 CCCF 0000 0000" + $"0000 00FC CCCC C6E5 5566 CCCC F000 0000" + $"0000 0FCC CCCC C656 5657 CCCC CF00 0000" + $"0000 FCCC CCCC C6E5 565C CCCC CCF0 0000" + $"000F CCCC CCCC C655 565C CCCC CCCF 0000" + $"00FC CCCC CCCC 7660 556C CCCC CCCC F000" + $"0FCC CCCC CCCC CD5D 567C CCCC CCCC CF00" + $"FCCC CCCC CCCC 6660 556C CCCC CCCC CCF0" + $"0FCC CCCC CCCC 665C 565C CCCC CCCC C0CF" + $"00FC CCCC CCCC 6660 E6DC CCCC CCCC CCF0" + $"000F CCCC CCCC C650 656C CCCC CCCC CF00" + $"0000 FCCC CCCC C6EC 5ECC CCCC CCCC F000" + $"0000 0FCC CCCC C650 566C CCCC CCCF 0000" + $"0000 00FC CCCC CC50 75CC CCCC CCF0 0000" + $"0000 000F CCCC CC50 56CC CCCC CF00 0000" + $"0000 0000 FCCC CCC0 5CCC CCCC F000 0000" + $"0000 0000 0FCC CCC0 CCCC CCCF 0000 0000" + $"0000 0000 00FC CCC0 CCCC CCF0 0000 0000" + $"0000 0000 000F CCC0 CCCC CF00 0000 0000" + $"0000 0000 0000 FCCC CCCC F000 0000 0000" + $"0000 0000 0000 0FCC CCCF 0000 0000 0000" + $"0000 0000 0000 00FC CCF0 0000 0000 0000" + $"0000 0000 0000 000F CF00 0000 0000 0000" + $"0000 0000 0000 0000 F000 0000 0000 0000" +}; + +data 'ICN#' (TK_APP_RESOURCES, "Tk App", purgeable) { + $"0001 0000 0002 8000 0004 7000 0008 7000" + $"0010 F000 0021 E800 0043 C400 0081 F200" + $"0107 F100 0207 F080 0407 F040 0807 E020" + $"1007 E010 200E E008 4002 E004 800E E002" + $"400E E001 200E C002 1006 E004 0806 C008" + $"0406 E010 0202 C020 0102 C040 0080 8080" + $"0041 0100 0021 0200 0011 0400 0009 0800" + $"0004 1000 0002 2000 0001 4000 0000 8000" + $"0001 0000 0003 8000 0007 F000 000F F000" + $"001F F000 003F F800 007F FC00 00FF FE00" + $"01FF FF00 03FF FF80 07FF FFC0 0FFF FFE0" + $"1FFF FFF0 3FFF FFF8 7FFF FFFC FFFF FFFE" + $"7FFF FFFF 3FFF FFFE 1FFF FFFC 0FFF FFF8" + $"07FF FFF0 03FF FFE0 01FF FFC0 00FF FF80" + $"007F FF00 003F FE00 001F FC00 000F F800" + $"0007 F000 0003 E000 0001 C000 0000 8000" +}; + +data 'ics#' (TK_APP_RESOURCES, "Tk App", purgeable) { + $"01C0 0260 04E0 09D0 1388 23C4 43C2 8281" + $"8282 4284 2188 1190 0920 0540 0280 0100" + $"01C0 03E0 07E0 0FF0 1FF8 3FFC 7FFE FFFF" + $"FFFE 7FFC 3FF8 1FF0 0FE0 07C0 0380 0100" +}; + +data 'ics4' (TK_APP_RESOURCES, "Tk App", purgeable) { + $"0000 000F C000 0000 0000 00FC 6600 0000" + $"0000 0FCC 6600 0000 0000 FCC6 66F0 0000" + $"000F CCD5 56CF 0000 00FC CC66 57CC F000" + $"0FCC CC65 56CC CF00 FCCC CC56 57CC CCF0" + $"0FCC CCC6 6CCC CCCF 00FC CCC6 5CCC CCF0" + $"000F CCC6 6CCC CF00 0000 FCCC 5CCC F000" + $"0000 0FCC CCCF 0000 0000 00FC CCF0 0000" + $"0000 000F CF00 0000 0000 0000 F000 0000" +}; + + diff --git a/mac/tkMacBitmap.c b/mac/tkMacBitmap.c new file mode 100644 index 0000000..fd08193 --- /dev/null +++ b/mac/tkMacBitmap.c @@ -0,0 +1,268 @@ +/* + * tkMacBitmap.c -- + * + * This file handles the implementation of native bitmaps. + * + * Copyright (c) 1996 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) tkMacBitmap.c 1.4 96/12/13 11:13:16 + */ + +#include "tkPort.h" +#include "tk.h" +#include "tkMacInt.h" + +#include <Icons.h> +#include <Dialogs.h> +#include <Resources.h> +#include <Strings.h> + +/* + * Depending on the resource type there are different ways to + * draw native icons. + */ +#define TYPE1 0 /* Family icon suite. */ +#define TYPE2 1 /* ICON resource. */ +#define TYPE3 2 /* cicn resource. */ + +/* + * This data structure describes the id and type of a given icon. + * It is used as the source for native icons. + */ +typedef struct { + int id; /* Resource Id for Icon. */ + long int type; /* Type of icon. */ +} NativeIcon; + +/* + * This structure holds information about native bitmaps. + */ + +typedef struct { + char *name; /* Name of icon. */ + long int type; /* Type of icon. */ + int id; /* Id of icon. */ + int size; /* Size of icon. */ +} BuiltInIcon; + +/* + * This array mapps a string name to the supported builtin icons + * on the Macintosh. + */ + +static BuiltInIcon builtInIcons[] = { + {"document", TYPE1, kGenericDocumentIconResource, 32}, + {"stationery", TYPE1, kGenericStationeryIconResource, 32}, + {"edition", TYPE1, kGenericEditionFileIconResource, 32}, + {"application", TYPE1, kGenericApplicationIconResource, 32}, + {"accessory", TYPE1, kGenericDeskAccessoryIconResource, 32}, + {"folder", TYPE1, kGenericFolderIconResource, 32}, + {"pfolder", TYPE1, kPrivateFolderIconResource, 32}, + {"trash", TYPE1, kTrashIconResource, 32}, + {"floppy", TYPE1, kFloppyIconResource, 32}, + {"ramdisk", TYPE1, kGenericRAMDiskIconResource, 32}, + {"cdrom", TYPE1, kGenericCDROMIconResource, 32}, + {"preferences", TYPE1, kGenericPreferencesIconResource, 32}, + {"querydoc", TYPE1, kGenericQueryDocumentIconResource, 32}, + {"stop", TYPE2, kStopIcon, 32}, + {"note", TYPE2, kNoteIcon, 32}, + {"caution", TYPE2, kCautionIcon, 32}, + {(char *) NULL, 0, 0, 0} +}; + +/* + *---------------------------------------------------------------------- + * + * TkpDefineNativeBitmaps -- + * + * Add native bitmaps. + * + * Results: + * A standard Tcl result. If an error occurs then TCL_ERROR is + * returned and a message is left in interp->result. + * + * Side effects: + * "Name" is entered into the bitmap table and may be used from + * here on to refer to the given bitmap. + * + *---------------------------------------------------------------------- + */ + +void +TkpDefineNativeBitmaps() +{ + int new; + Tcl_HashEntry *predefHashPtr; + TkPredefBitmap *predefPtr; + char * name; + BuiltInIcon *builtInPtr; + NativeIcon *nativeIconPtr; + + for (builtInPtr = builtInIcons; builtInPtr->name != NULL; builtInPtr++) { + name = Tk_GetUid(builtInPtr->name); + predefHashPtr = Tcl_CreateHashEntry(&tkPredefBitmapTable, name, &new); + if (!new) { + continue; + } + predefPtr = (TkPredefBitmap *) ckalloc(sizeof(TkPredefBitmap)); + nativeIconPtr = (NativeIcon *) ckalloc(sizeof(NativeIcon)); + nativeIconPtr->id = builtInPtr->id; + nativeIconPtr->type = builtInPtr->type; + predefPtr->source = (char *) nativeIconPtr; + predefPtr->width = builtInPtr->size; + predefPtr->height = builtInPtr->size; + predefPtr->native = 1; + Tcl_SetHashValue(predefHashPtr, predefPtr); + } +} + +/* + *---------------------------------------------------------------------- + * + * TkpCreateNativeBitmap -- + * + * Add native bitmaps. + * + * Results: + * A standard Tcl result. If an error occurs then TCL_ERROR is + * returned and a message is left in interp->result. + * + * Side effects: + * "Name" is entered into the bitmap table and may be used from + * here on to refer to the given bitmap. + * + *---------------------------------------------------------------------- + */ + +Pixmap +TkpCreateNativeBitmap( + Display *display, + char * source) /* Info about the icon to build. */ +{ + Pixmap pix; + GWorldPtr destPort; + Rect destRect; + Handle icon; + CGrafPtr saveWorld; + GDHandle saveDevice; + NativeIcon *nativeIconPtr; + + pix = Tk_GetPixmap(display, None, 32, 32, 0); + destPort = TkMacGetDrawablePort(pix); + + GetGWorld(&saveWorld, &saveDevice); + SetGWorld(destPort, NULL); + + nativeIconPtr = (NativeIcon *) source; + SetRect(&destRect, 0, 0, 32, 32); + if (nativeIconPtr->type == TYPE1) { + RGBColor white = {0xFFFF, 0xFFFF, 0xFFFF}; + + RGBForeColor(&white); + PaintRect(&destRect); + PlotIconID(&destRect, atAbsoluteCenter, ttNone, nativeIconPtr->id); + } else if (nativeIconPtr->type == TYPE2) { + icon = GetIcon(nativeIconPtr->id); + if (icon != NULL) { + RGBColor black = {0, 0, 0}; + + RGBForeColor(&black); + PlotIcon(&destRect, icon); + ReleaseResource(icon); + } + } + + SetGWorld(saveWorld, saveDevice); + return pix; +} + +/* + *---------------------------------------------------------------------- + * + * TkpGetNativeAppBitmap -- + * + * Add native bitmaps. + * + * Results: + * A standard Tcl result. If an error occurs then TCL_ERROR is + * returned and a message is left in interp->result. + * + * Side effects: + * "Name" is entered into the bitmap table and may be used from + * here on to refer to the given bitmap. + * + *---------------------------------------------------------------------- + */ + +Pixmap +TkpGetNativeAppBitmap( + Display *display, /* The display. */ + char *name, /* The name of the bitmap. */ + int *width, /* The width & height of the bitmap. */ + int *height) +{ + Pixmap pix; + CGrafPtr saveWorld; + GDHandle saveDevice; + GWorldPtr destPort; + Rect destRect; + Handle resource; + int type; + + c2pstr(name); + resource = GetNamedResource('cicn', (StringPtr) name); + if (resource != NULL) { + type = TYPE3; + } else { + resource = GetNamedResource('ICON', (StringPtr) name); + if (resource != NULL) { + type = TYPE2; + } + } + p2cstr((StringPtr) name); + + if (resource == NULL) { + return NULL; + } + + pix = Tk_GetPixmap(display, None, 32, 32, 0); + destPort = TkMacGetDrawablePort(pix); + + GetGWorld(&saveWorld, &saveDevice); + SetGWorld(destPort, NULL); + + SetRect(&destRect, 0, 0, 32, 32); + if (type == TYPE2) { + RGBColor black = {0, 0, 0}; + + RGBForeColor(&black); + PlotIcon(&destRect, resource); + ReleaseResource(resource); + } else if (type == TYPE3) { + RGBColor white = {0xFFFF, 0xFFFF, 0xFFFF}; + short id; + ResType theType; + Str255 dummy; + + /* + * We need to first paint the background white. Also, for + * some reason we *must* use GetCIcon instead of GetNamedResource + * for PlotCIcon to work - so we use GetResInfo to get the id. + */ + RGBForeColor(&white); + PaintRect(&destRect); + GetResInfo(resource, &id, &theType, dummy); + ReleaseResource(resource); + resource = (Handle) GetCIcon(id); + PlotCIcon(&destRect, (CIconHandle) resource); + DisposeCIcon((CIconHandle) resource); + } + + *width = 32; + *height = 32; + SetGWorld(saveWorld, saveDevice); + return pix; +} diff --git a/mac/tkMacButton.c b/mac/tkMacButton.c new file mode 100644 index 0000000..767baff --- /dev/null +++ b/mac/tkMacButton.c @@ -0,0 +1,825 @@ +/* + * tkMacButton.c -- + * + * This file implements the Macintosh specific portion of the + * button widgets. + * + * Copyright (c) 1996-1997 by Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) tkMacButton.c 1.18 97/11/20 18:27:21 + */ + +#include "tkButton.h" +#include "tkMacInt.h" +#include <Controls.h> +#include <LowMem.h> + +/* + * Some defines used to control what type of control is drawn. + */ + +#define DRAW_LABEL 0 /* Labels are treated genericly. */ +#define DRAW_CONTROL 1 /* Draw using the Native control. */ +#define DRAW_CUSTOM 2 /* Make our own button drawing. */ + +/* + * The following structures are used to draw our controls. Rather than + * having many Mac controls we just use one control of each type and + * reuse them for all Tk widgets. When the windowRef variable is NULL + * it means none of the data structures have been allocated. + */ + +static WindowRef windowRef = NULL; +static CWindowRecord windowRecord; +static ControlRef buttonHandle; +static ControlRef checkHandle; +static ControlRef radioHandle; +static CCTabHandle buttonTabHandle; +static CCTabHandle checkTabHandle; +static CCTabHandle radioTabHandle; +static PixMapHandle oldPixPtr; + +/* + * Forward declarations for procedures defined later in this file: + */ + +static int UpdateControlColors _ANSI_ARGS_((TkButton *butPtr, + ControlRef controlHandle, CCTabHandle ccTabHandle, + RGBColor *saveColorPtr)); +static void DrawBufferedControl _ANSI_ARGS_((TkButton *butPtr, + GWorldPtr destPort)); +static void ChangeBackgroundWindowColor _ANSI_ARGS_(( + WindowRef macintoshWindow, RGBColor rgbColor, + RGBColor *oldColor)); +static void ButtonExitProc _ANSI_ARGS_((ClientData clientData)); + +/* + * The class procedure table for the button widgets. + */ + +TkClassProcs tkpButtonProcs = { + NULL, /* createProc. */ + TkButtonWorldChanged, /* geometryProc. */ + NULL /* modalProc. */ +}; + +/* + *---------------------------------------------------------------------- + * + * TkpCreateButton -- + * + * Allocate a new TkButton structure. + * + * Results: + * Returns a newly allocated TkButton structure. + * + * Side effects: + * Registers an event handler for the widget. + * + *---------------------------------------------------------------------- + */ + +TkButton * +TkpCreateButton( + Tk_Window tkwin) +{ + return (TkButton *) ckalloc(sizeof(TkButton)); +} + +/* + *---------------------------------------------------------------------- + * + * TkpDisplayButton -- + * + * This procedure is invoked to display a button widget. It is + * normally invoked as an idle handler. + * + * Results: + * None. + * + * Side effects: + * Commands are output to X to display the button in its + * current mode. The REDRAW_PENDING flag is cleared. + * + *---------------------------------------------------------------------- + */ + +void +TkpDisplayButton( + ClientData clientData) /* Information about widget. */ +{ + TkButton *butPtr = (TkButton *) clientData; + Pixmap pixmap; + GC gc; + Tk_3DBorder border; + int x = 0; /* Initialization only needed to stop + * compiler warning. */ + int y, relief; + register Tk_Window tkwin = butPtr->tkwin; + int width, height; + int offset; /* 0 means this is a normal widget. 1 means + * it is an image button, so we offset the + * image to make the button appear to move + * up and down as the relief changes. */ + CGrafPtr saveWorld; + GDHandle saveDevice; + GWorldPtr destPort; + int drawType, borderWidth; + + GetGWorld(&saveWorld, &saveDevice); + + butPtr->flags &= ~REDRAW_PENDING; + if ((butPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) { + return; + } + + border = butPtr->normalBorder; + if ((butPtr->state == tkDisabledUid) && (butPtr->disabledFg != NULL)) { + gc = butPtr->disabledGC; + } else if ((butPtr->type == TYPE_BUTTON) && (butPtr->state == tkActiveUid)) { + gc = butPtr->activeTextGC; + border = butPtr->activeBorder; + } else { + gc = butPtr->normalTextGC; + } + if ((butPtr->flags & SELECTED) && (butPtr->state != tkActiveUid) + && (butPtr->selectBorder != NULL) && !butPtr->indicatorOn) { + border = butPtr->selectBorder; + } + + /* + * Override the relief specified for the button if this is a + * checkbutton or radiobutton and there's no indicator. + */ + + relief = butPtr->relief; + if ((butPtr->type >= TYPE_CHECK_BUTTON) && !butPtr->indicatorOn) { + relief = (butPtr->flags & SELECTED) ? TK_RELIEF_SUNKEN + : TK_RELIEF_RAISED; + } + + offset = ((butPtr->type == TYPE_BUTTON) && + ((butPtr->image != NULL) || (butPtr->bitmap != None))); + + /* + * In order to avoid screen flashes, this procedure redraws + * the button in a pixmap, then copies the pixmap to the + * screen in a single operation. This means that there's no + * point in time where the on-sreen image has been cleared. + */ + + pixmap = Tk_GetPixmap(butPtr->display, Tk_WindowId(tkwin), + Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin)); + Tk_Fill3DRectangle(tkwin, pixmap, butPtr->normalBorder, 0, 0, + Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT); + + + if (butPtr->type == TYPE_LABEL) { + drawType = DRAW_LABEL; + } else if (butPtr->type == TYPE_BUTTON) { + if ((butPtr->image == None) && (butPtr->bitmap == None)) { + drawType = DRAW_CONTROL; + } else { + drawType = DRAW_CUSTOM; + } + } else { + if (butPtr->indicatorOn) { + drawType = DRAW_CONTROL; + } else { + drawType = DRAW_CUSTOM; + } + } + + /* + * Draw the native portion of the buttons. Start by creating the control + * if it doesn't already exist. Then configure the Macintosh control from + * the Tk info. Finally, we call Draw1Control to draw to the screen. + */ + + if (drawType == DRAW_CONTROL) { + borderWidth = 0; + + /* + * This part uses Macintosh rather than Tk calls to draw + * to the screen. Make sure the ports etc. are set correctly. + */ + + destPort = TkMacGetDrawablePort(pixmap); + SetGWorld(destPort, NULL); + DrawBufferedControl(butPtr, destPort); + } + + if ((drawType == DRAW_CUSTOM) || (drawType == DRAW_LABEL)) { + borderWidth = butPtr->borderWidth; + } + + /* + * Display image or bitmap or text for button. + */ + + if (butPtr->image != None) { + Tk_SizeOfImage(butPtr->image, &width, &height); + + imageOrBitmap: + TkComputeAnchor(butPtr->anchor, tkwin, 0, 0, + butPtr->indicatorSpace + width, height, &x, &y); + x += butPtr->indicatorSpace; + + x += offset; + y += offset; + if (relief == TK_RELIEF_RAISED) { + x -= offset; + y -= offset; + } else if (relief == TK_RELIEF_SUNKEN) { + x += offset; + y += offset; + } + if (butPtr->image != NULL) { + if ((butPtr->selectImage != NULL) && (butPtr->flags & SELECTED)) { + Tk_RedrawImage(butPtr->selectImage, 0, 0, width, height, + pixmap, x, y); + } else { + Tk_RedrawImage(butPtr->image, 0, 0, width, height, pixmap, + x, y); + } + } else { + XSetClipOrigin(butPtr->display, gc, x, y); + XCopyPlane(butPtr->display, butPtr->bitmap, pixmap, gc, 0, 0, + (unsigned int) width, (unsigned int) height, x, y, 1); + XSetClipOrigin(butPtr->display, gc, 0, 0); + } + y += height/2; + } else if (butPtr->bitmap != None) { + Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height); + goto imageOrBitmap; + } else { + TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX, butPtr->padY, + butPtr->indicatorSpace + butPtr->textWidth, butPtr->textHeight, + &x, &y); + + x += butPtr->indicatorSpace; + + Tk_DrawTextLayout(butPtr->display, pixmap, gc, butPtr->textLayout, + x, y, 0, -1); + y += butPtr->textHeight/2; + } + + /* + * If the button is disabled with a stipple rather than a special + * foreground color, generate the stippled effect. If the widget + * is selected and we use a different background color when selected, + * must temporarily modify the GC. + */ + + if ((butPtr->state == tkDisabledUid) + && ((butPtr->disabledFg == NULL) || (butPtr->image != NULL))) { + if ((butPtr->flags & SELECTED) && !butPtr->indicatorOn + && (butPtr->selectBorder != NULL)) { + XSetForeground(butPtr->display, butPtr->disabledGC, + Tk_3DBorderColor(butPtr->selectBorder)->pixel); + } + XFillRectangle(butPtr->display, pixmap, butPtr->disabledGC, + butPtr->inset, butPtr->inset, + (unsigned) (Tk_Width(tkwin) - 2*butPtr->inset), + (unsigned) (Tk_Height(tkwin) - 2*butPtr->inset)); + if ((butPtr->flags & SELECTED) && !butPtr->indicatorOn + && (butPtr->selectBorder != NULL)) { + XSetForeground(butPtr->display, butPtr->disabledGC, + Tk_3DBorderColor(butPtr->normalBorder)->pixel); + } + } + + /* + * Draw the border and traversal highlight last. This way, if the + * button's contents overflow they'll be covered up by the border. + */ + + if (relief != TK_RELIEF_FLAT) { + int inset = butPtr->highlightWidth; + Tk_Draw3DRectangle(tkwin, pixmap, border, inset, inset, + Tk_Width(tkwin) - 2*inset, Tk_Height(tkwin) - 2*inset, + butPtr->borderWidth, relief); + } + + /* + * Copy the information from the off-screen pixmap onto the screen, + * then delete the pixmap. + */ + + XCopyArea(butPtr->display, pixmap, Tk_WindowId(tkwin), + butPtr->copyGC, 0, 0, (unsigned) Tk_Width(tkwin), + (unsigned) Tk_Height(tkwin), 0, 0); + Tk_FreePixmap(butPtr->display, pixmap); + + SetGWorld(saveWorld, saveDevice); +} + +/* + *---------------------------------------------------------------------- + * + * TkpComputeButtonGeometry -- + * + * After changes in a button's text or bitmap, this procedure + * recomputes the button's geometry and passes this information + * along to the geometry manager for the window. + * + * Results: + * None. + * + * Side effects: + * The button's window may change size. + * + *---------------------------------------------------------------------- + */ + +void +TkpComputeButtonGeometry( + TkButton *butPtr) /* Button whose geometry may have changed. */ +{ + int width, height, avgWidth; + Tk_FontMetrics fm; + + if (butPtr->highlightWidth < 0) { + butPtr->highlightWidth = 0; + } + if ((butPtr->type == TYPE_BUTTON) && (butPtr->image == None) + && (butPtr->bitmap == None)) { + butPtr->inset = 0; + } else if ((butPtr->type != TYPE_LABEL) && butPtr->indicatorOn) { + butPtr->inset = 0; + } else { + butPtr->inset = butPtr->borderWidth; + } + + /* + * The highlight width corresponds to the default ring on the Macintosh. + * As such, the highlight width is only added if the button is the default + * button. The actual width of the default ring is one less than the + * highlight width as there is also one pixel of spacing. + */ + + if (butPtr->defaultState != tkDisabledUid) { + butPtr->inset += butPtr->highlightWidth; + } + butPtr->indicatorSpace = 0; + if (butPtr->image != NULL) { + Tk_SizeOfImage(butPtr->image, &width, &height); + imageOrBitmap: + if (butPtr->width > 0) { + width = butPtr->width; + } + if (butPtr->height > 0) { + height = butPtr->height; + } + if ((butPtr->type >= TYPE_CHECK_BUTTON) && butPtr->indicatorOn) { + butPtr->indicatorSpace = height; + if (butPtr->type == TYPE_CHECK_BUTTON) { + butPtr->indicatorDiameter = (65*height)/100; + } else { + butPtr->indicatorDiameter = (75*height)/100; + } + } + } else if (butPtr->bitmap != None) { + Tk_SizeOfBitmap(butPtr->display, butPtr->bitmap, &width, &height); + goto imageOrBitmap; + } else { + Tk_FreeTextLayout(butPtr->textLayout); + butPtr->textLayout = Tk_ComputeTextLayout(butPtr->tkfont, + butPtr->text, -1, butPtr->wrapLength, butPtr->justify, 0, + &butPtr->textWidth, &butPtr->textHeight); + + width = butPtr->textWidth; + height = butPtr->textHeight; + avgWidth = Tk_TextWidth(butPtr->tkfont, "0", 1); + Tk_GetFontMetrics(butPtr->tkfont, &fm); + + if (butPtr->width > 0) { + width = butPtr->width * avgWidth; + } + if (butPtr->height > 0) { + height = butPtr->height * fm.linespace; + } + if ((butPtr->type >= TYPE_CHECK_BUTTON) && butPtr->indicatorOn) { + butPtr->indicatorDiameter = fm.linespace; + if (butPtr->type == TYPE_CHECK_BUTTON) { + butPtr->indicatorDiameter = (80*butPtr->indicatorDiameter)/100; + } + butPtr->indicatorSpace = butPtr->indicatorDiameter + avgWidth; + } + } + + /* + * When issuing the geometry request, add extra space for the indicator, + * if any, and for the border and padding, plus if this is an image two + * extra pixels so the display can be offset by 1 pixel in either + * direction for the raised or lowered effect. + */ + + if ((butPtr->image == NULL) && (butPtr->bitmap == None)) { + width += 2*butPtr->padX; + height += 2*butPtr->padY; + } + if ((butPtr->type == TYPE_BUTTON) && + ((butPtr->image != NULL) || (butPtr->bitmap != None))) { + width += 2; + height += 2; + } + Tk_GeometryRequest(butPtr->tkwin, (int) (width + butPtr->indicatorSpace + + 2*butPtr->inset), (int) (height + 2*butPtr->inset)); + Tk_SetInternalBorder(butPtr->tkwin, butPtr->inset); +} + +/* + *---------------------------------------------------------------------- + * + * TkpDestroyButton -- + * + * Free data structures associated with the button control. + * + * Results: + * None. + * + * Side effects: + * Restores the default control state. + * + *---------------------------------------------------------------------- + */ + +void +TkpDestroyButton( + TkButton *butPtr) +{ + /* Do nothing. */ +} + +/* + *-------------------------------------------------------------- + * + * DrawBufferedControl -- + * + * This function uses a dummy Macintosh window to allow + * drawing Mac controls to any GWorld (including off-screen + * bitmaps). In addition, this code may apply custom + * colors passed in the TkButton. + * + * Results: + * None. + * + * Side effects: + * Control is to the GWorld. Static state created on + * first invocation of this routine. + * + *-------------------------------------------------------------- + */ + +static void +DrawBufferedControl( + TkButton *butPtr, /* Tk button. */ + GWorldPtr destPort) /* Off screen GWorld. */ +{ + ControlRef controlHandle; + CCTabHandle ccTabHandle; + int windowColorChanged = false; + RGBColor saveBackColor; + + if (windowRef == NULL) { + Rect geometry = {0, 0, 10, 10}; + CWindowPeek windowList; + + /* + * Create a dummy window that we can draw to. We will + * actually replace this windows bitmap with a the one + * we want to draw to at a later time. This window and + * the data structures attached to it are only deallocated + * on exit of the application. + */ + + windowRef = NewCWindow(NULL, &geometry, "\pempty", false, + zoomDocProc, (WindowRef) -1, true, 0); + if (windowRef == NULL) { + panic("Can't allocate buffer window."); + } + + /* + * Now add the three standard controls to hidden window. We + * only create one of each and reuse them for every widget in + * Tk. + */ + + SetPort(windowRef); + buttonHandle = NewControl(windowRef, &geometry, "\p", + false, 1, 0, 1, pushButProc, (SInt32) 0); + checkHandle = NewControl(windowRef, &geometry, "\p", + false, 1, 0, 1, checkBoxProc, (SInt32) 0); + radioHandle = NewControl(windowRef, &geometry, "\p", + false, 1, 0, 1, radioButProc, (SInt32) 0); + ((CWindowPeek) windowRef)->visible = true; + + buttonTabHandle = (CCTabHandle) NewHandle(sizeof(CtlCTab)); + checkTabHandle = (CCTabHandle) NewHandle(sizeof(CtlCTab)); + radioTabHandle = (CCTabHandle) NewHandle(sizeof(CtlCTab)); + + /* + * Remove our window from the window list. This way our + * applications and others will not be confused that this + * window exists - but no one knows about it. + */ + + windowList = (CWindowPeek) LMGetWindowList(); + if (windowList == (CWindowPeek) windowRef) { + LMSetWindowList((WindowRef) windowList->nextWindow); + } else { + while ((windowList != NULL) + && (windowList->nextWindow != (CWindowPeek) windowRef)) { + windowList = windowList->nextWindow; + } + if (windowList != NULL) { + windowList->nextWindow = windowList->nextWindow->nextWindow; + } + } + ((CWindowPeek) windowRef)->nextWindow = NULL; + + /* + * Create an exit handler to clean up this mess if we our + * unloaded etc. We need to remember the windows portPixMap + * so it isn't leaked. + * + * TODO: The ButtonExitProc doesn't currently work and the + * code it includes will crash the Mac on exit from Tk. + + oldPixPtr = ((CWindowPeek) windowRef)->port.portPixMap; + Tcl_CreateExitHandler(ButtonExitProc, (ClientData) NULL); + */ + } + + /* + * Set up control in hidden window to match what we need + * to draw in the buffered window. + */ + + switch (butPtr->type) { + case TYPE_BUTTON: + controlHandle = buttonHandle; + ccTabHandle = buttonTabHandle; + break; + case TYPE_RADIO_BUTTON: + controlHandle = radioHandle; + ccTabHandle = radioTabHandle; + break; + case TYPE_CHECK_BUTTON: + controlHandle = checkHandle; + ccTabHandle = checkTabHandle; + break; + } + (**controlHandle).contrlRect.left = butPtr->inset; + (**controlHandle).contrlRect.top = butPtr->inset; + (**controlHandle).contrlRect.right = Tk_Width(butPtr->tkwin) + - butPtr->inset; + (**controlHandle).contrlRect.bottom = Tk_Height(butPtr->tkwin) + - butPtr->inset; + if ((**controlHandle).contrlVis != 255) { + (**controlHandle).contrlVis = 255; + } + if (butPtr->flags & SELECTED) { + (**controlHandle).contrlValue = 1; + } else { + (**controlHandle).contrlValue = 0; + } + if (butPtr->state == tkActiveUid) { + switch (butPtr->type) { + case TYPE_BUTTON: + (**controlHandle).contrlHilite = kControlButtonPart; + break; + case TYPE_RADIO_BUTTON: + (**controlHandle).contrlHilite = kControlRadioButtonPart; + break; + case TYPE_CHECK_BUTTON: + (**controlHandle).contrlHilite = kControlCheckBoxPart; + break; + } + } else if (butPtr->state == tkDisabledUid) { + (**controlHandle).contrlHilite = kControlInactivePart; + } else { + (**controlHandle).contrlHilite = kControlNoPart; + } + + /* + * Now swap in the passed in GWorld for the portBits of our fake + * window. We also adjust various fields in the WindowRecord to make + * the system think this is a normal window. + */ + + ((CWindowPeek) windowRef)->port.portPixMap = destPort->portPixMap; + ((CWindowPeek) windowRef)->port.portRect = destPort->portRect; + RectRgn(((CWindowPeek) windowRef)->port.visRgn, &destPort->portRect); + RectRgn(((CWindowPeek) windowRef)->strucRgn, &destPort->portRect); + RectRgn(((CWindowPeek) windowRef)->updateRgn, &destPort->portRect); + RectRgn(((CWindowPeek) windowRef)->contRgn, &destPort->portRect); + PortChanged(windowRef); + + /* + * Before we draw the control we must add the hidden window back to the + * main window list. Otherwise, radiobuttons and checkbuttons will draw + * incorrectly. I don't really know why - but clearly the control draw + * proc needs to have the controls window in the window list. + */ + + ((CWindowPeek) windowRef)->nextWindow = (CWindowPeek) LMGetWindowList(); + LMSetWindowList(windowRef); + + /* + * Now we can set the port to our doctered up window. We next need + * to muck with the colors for the port & window to draw the control + * with the proper Tk colors. If we need to we also draw a default + * ring for buttons. + */ + + SetPort(windowRef); + windowColorChanged = UpdateControlColors(butPtr, controlHandle, + ccTabHandle, &saveBackColor); + Draw1Control(controlHandle); + if ((butPtr->type == TYPE_BUTTON) && + (butPtr->defaultState == tkActiveUid)) { + Rect box = (**controlHandle).contrlRect; + RGBColor rgbColor; + + TkSetMacColor(butPtr->highlightColorPtr->pixel, &rgbColor); + RGBForeColor(&rgbColor); + PenSize(butPtr->highlightWidth - 1, butPtr->highlightWidth - 1); + InsetRect(&box, -butPtr->highlightWidth, -butPtr->highlightWidth); + FrameRoundRect(&box, 16, 16); + } + if (windowColorChanged) { + RGBColor dummyColor; + ChangeBackgroundWindowColor(windowRef, saveBackColor, &dummyColor); + } + + /* + * Clean up: remove the hidden window from the main window list. + */ + + LMSetWindowList((WindowRef) ((CWindowPeek) windowRef)->nextWindow); +} + +/* + *-------------------------------------------------------------- + * + * UpdateControlColors -- + * + * This function will review the colors used to display + * a Macintosh button. If any non-standard colors are + * used we create a custom palette for the button, populate + * with the colors for the button and install the palette. + * + * Results: + * None. + * + * Side effects: + * The Macintosh control may get a custom palette installed. + * + *-------------------------------------------------------------- + */ + +static int +UpdateControlColors( + TkButton *butPtr, + ControlRef controlHandle, + CCTabHandle ccTabHandle, + RGBColor *saveColorPtr) +{ + XColor *xcolor; + + xcolor = Tk_3DBorderColor(butPtr->normalBorder); + + (**ccTabHandle).ccSeed = 0; + (**ccTabHandle).ccRider = 0; + (**ccTabHandle).ctSize = 3; + (**ccTabHandle).ctTable[0].value = cBodyColor; + TkSetMacColor(xcolor->pixel, + &(**ccTabHandle).ctTable[0].rgb); + (**ccTabHandle).ctTable[1].value = cTextColor; + TkSetMacColor(butPtr->normalFg->pixel, + &(**ccTabHandle).ctTable[1].rgb); + (**ccTabHandle).ctTable[2].value = cFrameColor; + TkSetMacColor(butPtr->highlightColorPtr->pixel, + &(**ccTabHandle).ctTable[2].rgb); + SetControlColor(controlHandle, ccTabHandle); + + if (((xcolor->pixel >> 24) != CONTROL_BODY_PIXEL) && + ((butPtr->type == TYPE_CHECK_BUTTON) || + (butPtr->type == TYPE_RADIO_BUTTON))) { + RGBColor newColor; + + TkSetMacColor(xcolor->pixel, &newColor); + ChangeBackgroundWindowColor((**controlHandle).contrlOwner, + newColor, saveColorPtr); + return true; + } + + return false; +} + +/* + *-------------------------------------------------------------- + * + * ChangeBackgroundWindowColor -- + * + * This procedure will change the background color entry + * in the Window's colortable. The system isn't notified + * of the change. This call should only be used to fool + * the drawing routines for checkboxes and radiobuttons. + * Any change should be temporary and be reverted after + * the widget is drawn. + * + * Results: + * None. + * + * Side effects: + * The Window's color table will be adjusted. + * + *-------------------------------------------------------------- + */ + +static void +ChangeBackgroundWindowColor( + WindowRef macintoshWindow, /* A Mac window whose color to change. */ + RGBColor rgbColor, /* The new RGB Color for the background. */ + RGBColor *oldColor) /* The old color of the background. */ +{ + AuxWinHandle auxWinHandle; + WCTabHandle winCTabHandle; + short ctIndex; + ColorSpecPtr rgbScan; + + GetAuxWin(macintoshWindow, &auxWinHandle); + winCTabHandle = (WCTabHandle) ((**auxWinHandle).awCTable); + + /* + * Scan through the color table until we find the content + * (background) color for the window. Don't tell the system + * about the change - it will generate damage and we will get + * into an infinite loop. + */ + + ctIndex = (**winCTabHandle).ctSize; + while (ctIndex > -1) { + rgbScan = ctIndex + (**winCTabHandle).ctTable; + + if (rgbScan->value == wContentColor) { + *oldColor = rgbScan->rgb; + rgbScan->rgb = rgbColor; + break; + } + ctIndex--; + } +} + +/* + *---------------------------------------------------------------------- + * + * ButtonExitProc -- + * + * This procedure is invoked just before the application exits. + * It frees all of the control handles, our dummy window, etc. + * + * Results: + * None. + * + * Side effects: + * Memory is freed. + * + *---------------------------------------------------------------------- + */ + +static void +ButtonExitProc(clientData) + ClientData clientData; /* Not used. */ +{ + Rect pixRect = {0, 0, 10, 10}; + Rect rgnRect = {0, 0, 0, 0}; + + /* + * Restore our dummy window to it's origional state by putting it + * back in the window list and restoring it's bits. The destroy + * the controls and window. + */ + + ((CWindowPeek) windowRef)->nextWindow = (CWindowPeek) LMGetWindowList(); + LMSetWindowList(windowRef); + ((CWindowPeek) windowRef)->port.portPixMap = oldPixPtr; + ((CWindowPeek) windowRef)->port.portRect = pixRect; + RectRgn(((CWindowPeek) windowRef)->port.visRgn, &rgnRect); + RectRgn(((CWindowPeek) windowRef)->strucRgn, &rgnRect); + RectRgn(((CWindowPeek) windowRef)->updateRgn, &rgnRect); + RectRgn(((CWindowPeek) windowRef)->contRgn, &rgnRect); + PortChanged(windowRef); + + DisposeControl(buttonHandle); + DisposeControl(checkHandle); + DisposeControl(radioHandle); + DisposeWindow(windowRef); + windowRef = NULL; +} diff --git a/mac/tkMacClipboard.c b/mac/tkMacClipboard.c new file mode 100644 index 0000000..0c06f1d --- /dev/null +++ b/mac/tkMacClipboard.c @@ -0,0 +1,293 @@ +/* + * tkMacClipboard.c -- + * + * This file manages the clipboard for the Tk toolkit. + * + * Copyright (c) 1995-1997 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) tkMacClipboard.c 1.18 97/05/01 15:41:17 + */ + +#include "tkInt.h" +#include "tkPort.h" +#include "tkMacInt.h" + +#include <Scrap.h> +#include <Events.h> + +#include "tkSelect.h" + +/* + *---------------------------------------------------------------------- + * + * TkSelGetSelection -- + * + * Retrieve the specified selection from another process. For + * now, only fetching XA_STRING from CLIPBOARD is supported. + * Eventually other types should be allowed. + * + * Results: + * The return value is a standard Tcl return value. + * If an error occurs (such as no selection exists) + * then an error message is left in interp->result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +TkSelGetSelection( + Tcl_Interp *interp, /* Interpreter to use for reporting + * errors. */ + Tk_Window tkwin, /* Window on whose behalf to retrieve + * the selection (determines display + * from which to retrieve). */ + Atom selection, /* Selection to retrieve. */ + Atom target, /* Desired form in which selection + * is to be returned. */ + Tk_GetSelProc *proc, /* Procedure to call to process the + * selection, once it has been retrieved. */ + ClientData clientData) /* Arbitrary value to pass to proc. */ +{ + int result; + long length, offset = 0; + Handle handle; + + if ((selection == Tk_InternAtom(tkwin, "CLIPBOARD")) + && (target == XA_STRING)) { + /* + * Get the scrap from the Macintosh global clipboard. + */ + handle = NewHandle(1); + length = GetScrap(handle, 'TEXT', &offset); + if (length > 0) { + SetHandleSize(handle, (Size) length + 1); + HLock(handle); + (*handle)[length] = '\0'; + + result = (*proc)(clientData, interp, *handle); + + HUnlock(handle); + DisposeHandle(handle); + return result; + } + + DisposeHandle(handle); + } + + Tcl_AppendResult(interp, Tk_GetAtomName(tkwin, selection), + " selection doesn't exist or form \"", Tk_GetAtomName(tkwin, target), + "\" not defined", (char *) NULL); + return TCL_ERROR; +} + +/* + *---------------------------------------------------------------------- + * + * TkSetSelectionOwner -- + * + * This function claims ownership of the specified selection. + * If the selection is CLIPBOARD, then we empty the system + * clipboard. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +XSetSelectionOwner( + Display* display, /* X Display. */ + Atom selection, /* What selection to own. */ + Window owner, /* Window to be the owner. */ + Time time) /* The current time? */ +{ + Tk_Window tkwin; + TkDisplay *dispPtr; + + /* + * This is a gross hack because the Tk_InternAtom interface is broken. + * It expects a Tk_Window, even though it only needs a Tk_Display. + */ + + tkwin = (Tk_Window)tkMainWindowList->winPtr; + + if (selection == Tk_InternAtom(tkwin, "CLIPBOARD")) { + + /* + * Only claim and empty the clipboard if we aren't already the + * owner of the clipboard. + */ + + dispPtr = tkMainWindowList->winPtr->dispPtr; + if (dispPtr->clipboardActive) { + return; + } + ZeroScrap(); + } +} + +/* + *---------------------------------------------------------------------- + * + * TkSelUpdateClipboard -- + * + * This function is called to force the clipboard to be updated + * after new data is added. On the Mac we don't need to do + * anything. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +TkSelUpdateClipboard( + TkWindow *winPtr, /* Window associated with clipboard. */ + TkClipboardTarget *targetPtr) /* Info about the content. */ +{ +} + +/* + *-------------------------------------------------------------- + * + * TkSelEventProc -- + * + * This procedure is invoked whenever a selection-related + * event occurs. + * + * Results: + * None. + * + * Side effects: + * Lots: depends on the type of event. + * + *-------------------------------------------------------------- + */ + +void +TkSelEventProc( + Tk_Window tkwin, /* Window for which event was + * targeted. */ + register XEvent *eventPtr) /* X event: either SelectionClear, + * SelectionRequest, or + * SelectionNotify. */ +{ + if (eventPtr->type == SelectionClear) { + TkSelClearSelection(tkwin, eventPtr); + } +} + +/* + *---------------------------------------------------------------------- + * + * TkSelPropProc -- + * + * This procedure is invoked when property-change events + * occur on windows not known to the toolkit. This is a stub + * function under Windows. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +TkSelPropProc( + register XEvent *eventPtr) /* X PropertyChange event. */ +{ +} + +/* + *---------------------------------------------------------------------- + * + * TkSuspendClipboard -- + * + * Handle clipboard conversion as required by the suppend event. + * This function is also called on exit. + * + * Results: + * None. + * + * Side effects: + * The local scrap is moved to the global scrap. + * + *---------------------------------------------------------------------- + */ + +void +TkSuspendClipboard() +{ + TkClipboardTarget *targetPtr; + TkClipboardBuffer *cbPtr; + TkDisplay *dispPtr; + char *buffer, *p, *endPtr, *buffPtr; + long length; + + dispPtr = tkDisplayList; + if ((dispPtr == NULL) || !dispPtr->clipboardActive) { + return; + } + + for (targetPtr = dispPtr->clipTargetPtr; targetPtr != NULL; + targetPtr = targetPtr->nextPtr) { + if (targetPtr->type == XA_STRING) + break; + } + if (targetPtr != NULL) { + length = 0; + for (cbPtr = targetPtr->firstBufferPtr; cbPtr != NULL; + cbPtr = cbPtr->nextPtr) { + length += cbPtr->length; + } + + buffer = ckalloc(length); + buffPtr = buffer; + for (cbPtr = targetPtr->firstBufferPtr; cbPtr != NULL; + cbPtr = cbPtr->nextPtr) { + for (p = cbPtr->buffer, endPtr = p + cbPtr->length; + p < endPtr; p++) { + if (*p == '\n') { + *buffPtr++ = '\r'; + } else { + *buffPtr++ = *p; + } + } + } + + ZeroScrap(); + PutScrap(length, 'TEXT', buffer); + ckfree(buffer); + } + + /* + * The system now owns the scrap. We tell Tk that it has + * lost the selection so that it will look for it the next time + * it needs it. (Window list NULL if quiting.) + */ + + if (tkMainWindowList != NULL) { + Tk_ClearSelection((Tk_Window) tkMainWindowList->winPtr, + Tk_InternAtom((Tk_Window) tkMainWindowList->winPtr, + "CLIPBOARD")); + } + + return; +} diff --git a/mac/tkMacColor.c b/mac/tkMacColor.c new file mode 100644 index 0000000..56fe38d --- /dev/null +++ b/mac/tkMacColor.c @@ -0,0 +1,485 @@ +/* + * tkMacColor.c -- + * + * This file maintains a database of color values for the Tk + * toolkit, in order to avoid round-trips to the server to + * map color names to pixel values. + * + * Copyright (c) 1990-1994 The Regents of the University of California. + * Copyright (c) 1994-1996 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) tkMacColor.c 1.36 96/11/25 11:02:12 + */ + +#include <tkColor.h> +#include "tkMacInt.h" + +#include <LowMem.h> +#include <Palettes.h> +#include <Quickdraw.h> + +/* + * Default Auxillary Control Record for all controls. This is cached once + * and is updated by the system. We use this to get the default system + * colors used by controls. + */ +static AuxCtlHandle defaultAuxCtlHandle = NULL; + +/* + * Forward declarations for procedures defined later in this file: + */ + +static int GetControlPartColor _ANSI_ARGS_((short part, RGBColor *macColor)); +static int GetMenuPartColor _ANSI_ARGS_((int part, RGBColor *macColor)); +static int GetWindowPartColor _ANSI_ARGS_((short part, RGBColor *macColor)); + +/* + *---------------------------------------------------------------------- + * + * TkSetMacColor -- + * + * Populates a Macintosh RGBColor structure from a X style + * pixel value. + * + * Results: + * Returns false if not a real pixel, true otherwise. + * + * Side effects: + * The variable macColor is updated to the pixels value. + * + *---------------------------------------------------------------------- + */ + +int +TkSetMacColor( + unsigned long pixel, /* Pixel value to convert. */ + RGBColor *macColor) /* Mac color struct to modify. */ +{ + switch (pixel >> 24) { + case HIGHLIGHT_PIXEL: + LMGetHiliteRGB(macColor); + return true; + case HIGHLIGHT_TEXT_PIXEL: + LMGetHiliteRGB(macColor); + if ((macColor->red == 0) && (macColor->green == 0) + && (macColor->blue == 0)) { + macColor->red = macColor->green = macColor->blue = 0xFFFFFFFF; + } else { + macColor->red = macColor->green = macColor->blue = 0; + } + return true; + case CONTROL_TEXT_PIXEL: + GetControlPartColor(cTextColor, macColor); + return true; + case CONTROL_BODY_PIXEL: + GetControlPartColor(cBodyColor, macColor); + return true; + case CONTROL_FRAME_PIXEL: + GetControlPartColor(cFrameColor, macColor); + return true; + case WINDOW_BODY_PIXEL: + GetWindowPartColor(wContentColor, macColor); + return true; + case MENU_ACTIVE_PIXEL: + case MENU_ACTIVE_TEXT_PIXEL: + case MENU_BACKGROUND_PIXEL: + case MENU_DISABLED_PIXEL: + case MENU_TEXT_PIXEL: + GetMenuPartColor((pixel >> 24), macColor); + return true; + case PIXEL_MAGIC: + default: + macColor->blue = (unsigned short) ((pixel & 0xFF) << 8); + macColor->green = (unsigned short) (((pixel >> 8) & 0xFF) << 8); + macColor->red = (unsigned short) (((pixel >> 16) & 0xFF) << 8); + return true; + } +} + +/* + *---------------------------------------------------------------------- + * + * Stub functions -- + * + * These functions are just stubs for functions that either + * don't make sense on the Mac or have yet to be implemented. + * + * Results: + * None. + * + * Side effects: + * These calls do nothing - which may not be expected. + * + *---------------------------------------------------------------------- + */ + +Status +XAllocColor( + Display *display, /* Display. */ + Colormap map, /* Not used. */ + XColor *colorPtr) /* XColor struct to modify. */ +{ + display->request++; + colorPtr->pixel = TkpGetPixel(colorPtr); + return 1; +} + +Colormap +XCreateColormap( + Display *display, /* Display. */ + Window window, /* X window. */ + Visual *visual, /* Not used. */ + int alloc) /* Not used. */ +{ + static Colormap index = 1; + + /* + * Just return a new value each time. + */ + return index++; +} + +void +XFreeColormap( + Display* display, /* Display. */ + Colormap colormap) /* Colormap. */ +{ +} + +void +XFreeColors( + Display* display, /* Display. */ + Colormap colormap, /* Colormap. */ + unsigned long* pixels, /* Array of pixels. */ + int npixels, /* Number of pixels. */ + unsigned long planes) /* Number of pixel planes. */ +{ + /* + * The Macintosh version of Tk uses TrueColor. Nothing + * needs to be done to release colors as there really is + * no colormap in the Tk sense. + */ +} + +/* + *---------------------------------------------------------------------- + * + * TkpGetColor -- + * + * Allocate a new TkColor for the color with the given name. + * + * Results: + * Returns a newly allocated TkColor, or NULL on failure. + * + * Side effects: + * May invalidate the colormap cache associated with tkwin upon + * allocating a new colormap entry. Allocates a new TkColor + * structure. + * + *---------------------------------------------------------------------- + */ + +TkColor * +TkpGetColor( + Tk_Window tkwin, /* Window in which color will be used. */ + Tk_Uid name) /* Name of color to allocated (in form + * suitable for passing to XParseColor). */ +{ + Display *display = Tk_Display(tkwin); + Colormap colormap = Tk_Colormap(tkwin); + TkColor *tkColPtr; + XColor color; + + /* + * Check to see if this is a system color. Otherwise, XParseColor + * will do all the work. + */ + if (strncasecmp(name, "system", 6) == 0) { + int foundSystemColor = false; + RGBColor rgbValue; + char pixelCode; + + if (!strcasecmp(name+6, "Highlight")) { + LMGetHiliteRGB(&rgbValue); + pixelCode = HIGHLIGHT_PIXEL; + foundSystemColor = true; + } else if (!strcasecmp(name+6, "HighlightText")) { + LMGetHiliteRGB(&rgbValue); + if ((rgbValue.red == 0) && (rgbValue.green == 0) + && (rgbValue.blue == 0)) { + rgbValue.red = rgbValue.green = rgbValue.blue = 0xFFFFFFFF; + } else { + rgbValue.red = rgbValue.green = rgbValue.blue = 0; + } + pixelCode = HIGHLIGHT_TEXT_PIXEL; + foundSystemColor = true; + } else if (!strcasecmp(name+6, "ButtonText")) { + GetControlPartColor(cTextColor, &rgbValue); + pixelCode = CONTROL_TEXT_PIXEL; + foundSystemColor = true; + } else if (!strcasecmp(name+6, "ButtonFace")) { + GetControlPartColor(cBodyColor, &rgbValue); + pixelCode = CONTROL_BODY_PIXEL; + foundSystemColor = true; + } else if (!strcasecmp(name+6, "ButtonFrame")) { + GetControlPartColor(cFrameColor, &rgbValue); + pixelCode = CONTROL_FRAME_PIXEL; + foundSystemColor = true; + } else if (!strcasecmp(name+6, "WindowBody")) { + GetWindowPartColor(wContentColor, &rgbValue); + pixelCode = WINDOW_BODY_PIXEL; + foundSystemColor = true; + } else if (!strcasecmp(name+6, "MenuActive")) { + GetMenuPartColor(MENU_ACTIVE_PIXEL, &rgbValue); + pixelCode = MENU_ACTIVE_PIXEL; + foundSystemColor = true; + } else if (!strcasecmp(name+6, "MenuActiveText")) { + GetMenuPartColor(MENU_ACTIVE_TEXT_PIXEL, &rgbValue); + pixelCode = MENU_ACTIVE_TEXT_PIXEL; + foundSystemColor = true; + } else if (!strcasecmp(name+6, "Menu")) { + GetMenuPartColor(MENU_BACKGROUND_PIXEL, &rgbValue); + pixelCode = MENU_BACKGROUND_PIXEL; + foundSystemColor = true; + } else if (!strcasecmp(name+6, "MenuDisabled")) { + GetMenuPartColor(MENU_DISABLED_PIXEL, &rgbValue); + pixelCode = MENU_DISABLED_PIXEL; + foundSystemColor = true; + } else if (!strcasecmp(name+6, "MenuText")) { + GetMenuPartColor(MENU_TEXT_PIXEL, &rgbValue); + pixelCode = MENU_TEXT_PIXEL; + foundSystemColor = true; + } + + if (foundSystemColor) { + color.red = rgbValue.red; + color.green = rgbValue.green; + color.blue = rgbValue.blue; + color.pixel = ((((((pixelCode << 8) + | ((color.red >> 8) & 0xff)) << 8) + | ((color.green >> 8) & 0xff)) << 8) + | ((color.blue >> 8) & 0xff)); + + tkColPtr = (TkColor *) ckalloc(sizeof(TkColor)); + tkColPtr->color = color; + return tkColPtr; + } + } + + if (XParseColor(display, colormap, name, &color) == 0) { + return (TkColor *) NULL; + } + + tkColPtr = (TkColor *) ckalloc(sizeof(TkColor)); + tkColPtr->color = color; + + return tkColPtr; +} + +/* + *---------------------------------------------------------------------- + * + * TkpGetColorByValue -- + * + * Given a desired set of red-green-blue intensities for a color, + * locate a pixel value to use to draw that color in a given + * window. + * + * Results: + * The return value is a pointer to an TkColor structure that + * indicates the closest red, blue, and green intensities available + * to those specified in colorPtr, and also specifies a pixel + * value to use to draw in that color. + * + * Side effects: + * May invalidate the colormap cache for the specified window. + * Allocates a new TkColor structure. + * + *---------------------------------------------------------------------- + */ + +TkColor * +TkpGetColorByValue( + Tk_Window tkwin, /* Window in which color will be used. */ + XColor *colorPtr) /* Red, green, and blue fields indicate + * desired color. */ +{ + TkColor *tkColPtr = (TkColor *) ckalloc(sizeof(TkColor)); + + tkColPtr->color.red = colorPtr->red; + tkColPtr->color.green = colorPtr->green; + tkColPtr->color.blue = colorPtr->blue; + tkColPtr->color.pixel = TkpGetPixel(&tkColPtr->color); + return tkColPtr; +} + +/* + *---------------------------------------------------------------------- + * + * GetControlPartColor -- + * + * Given a part number this function will return the standard + * system default color for that part. It does this by looking + * in the system's 'cctb' resource. + * + * Results: + * True if a color is found, false otherwise. + * + * Side effects: + * If a color is found then the RGB variable will be changed to + * the parts color. + * + *---------------------------------------------------------------------- + */ + +static int +GetControlPartColor( + short part, /* Part code. */ + RGBColor *macColor) /* Pointer to Mac color. */ +{ + short index; + CCTabHandle ccTab; + + if (defaultAuxCtlHandle == NULL) { + GetAuxiliaryControlRecord(NULL, &defaultAuxCtlHandle); + } + ccTab = (**defaultAuxCtlHandle).acCTable; + if(ccTab && (ResError() == noErr)) { + for(index = 0; index <= (**ccTab).ctSize; index++) { + if((**ccTab).ctTable[index].value == part) { + *macColor = (**ccTab).ctTable[index].rgb; + return true; + } + } + } + return false; +} + +/* + *---------------------------------------------------------------------- + * + * GetWindowPartColor -- + * + * Given a part number this function will return the standard + * system default color for that part. It does this by looking + * in the system's 'wctb' resource. + * + * Results: + * True if a color is found, false otherwise. + * + * Side effects: + * If a color is found then the RGB variable will be changed to + * the parts color. + * + *---------------------------------------------------------------------- + */ + +static int +GetWindowPartColor( + short part, /* Part code. */ + RGBColor *macColor) /* Pointer to Mac color. */ +{ + short index; + WCTabHandle wcTab; + + wcTab = (WCTabHandle) GetResource('wctb', 0); + if(wcTab && (ResError() == noErr)) { + for(index = 0; index <= (**wcTab).ctSize; index++) { + if((**wcTab).ctTable[index].value == part) { + *macColor = (**wcTab).ctTable[index].rgb; + return true; + } + } + } + return false; +} + +/* + *---------------------------------------------------------------------- + * + * GetMenuPartColor -- + * + * Given a magic pixel value, returns the RGB color associated + * with it by looking the value up in the system's 'mctb' resource. + * + * Results: + * True if a color is found, false otherwise. + * + * Side effects: + * If a color is found then the RGB variable will be changed to + * the parts color. + * + *---------------------------------------------------------------------- + */ + +static int +GetMenuPartColor( + int pixel, /* The magic pixel value */ + RGBColor *macColor) /* Pointer to Mac color */ +{ + RGBColor backColor, foreColor; + GDHandle maxDevice; + Rect globalRect; + MCEntryPtr mcEntryPtr = GetMCEntry(0, 0); + + switch (pixel) { + case MENU_ACTIVE_PIXEL: + if (mcEntryPtr == NULL) { + macColor->red = macColor->blue = macColor->green = 0; + } else { + *macColor = mcEntryPtr->mctRGB3; + } + return 1; + case MENU_ACTIVE_TEXT_PIXEL: + if (mcEntryPtr == NULL) { + macColor->red = macColor->blue = macColor->green = 0xFFFF; + } else { + *macColor = mcEntryPtr->mctRGB2; + } + return 1; + case MENU_BACKGROUND_PIXEL: + if (mcEntryPtr == NULL) { + macColor->red = macColor->blue = macColor->green = 0xFFFF; + } else { + *macColor = mcEntryPtr->mctRGB2; + } + return 1; + case MENU_DISABLED_PIXEL: + if (mcEntryPtr == NULL) { + backColor.red = backColor.blue = backColor.green = 0xFFFF; + foreColor.red = foreColor.blue = foreColor.green = 0x0000; + } else { + backColor = mcEntryPtr->mctRGB2; + foreColor = mcEntryPtr->mctRGB3; + } + SetRect(&globalRect, SHRT_MIN, SHRT_MIN, SHRT_MAX, SHRT_MAX); + maxDevice = GetMaxDevice(&globalRect); + if (GetGray(maxDevice, &backColor, &foreColor)) { + *macColor = foreColor; + } else { + + /* + * Pointer may have been moved by GetMaxDevice or GetGray. + */ + + mcEntryPtr = GetMCEntry(0,0); + if (mcEntryPtr == NULL) { + macColor->red = macColor->green = macColor->blue = 0x7777; + } else { + *macColor = mcEntryPtr->mctRGB2; + } + } + return 1; + case MENU_TEXT_PIXEL: + if (mcEntryPtr == NULL) { + macColor->red = macColor->green = macColor->blue = 0; + } else { + *macColor = mcEntryPtr->mctRGB3; + } + return 1; + } + return 0; +} diff --git a/mac/tkMacCursor.c b/mac/tkMacCursor.c new file mode 100644 index 0000000..f221189 --- /dev/null +++ b/mac/tkMacCursor.c @@ -0,0 +1,360 @@ +/* + * tkMacCursor.c -- + * + * This file contains Macintosh specific cursor related routines. + * + * Copyright (c) 1995-1997 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) tkMacCursor.c 1.20 97/09/17 19:33:13 + */ + +#include "tkPort.h" +#include "tkInt.h" +#include "tkMacInt.h" + +#include <Resources.h> +#include <ToolUtils.h> +#include <Strings.h> + +/* + * There are three different ways to set the cursor on the Mac. + */ +#define ARROW 0 /* The arrow cursor. */ +#define COLOR 1 /* Cursors of type crsr. */ +#define NORMAL 2 /* Cursors of type CURS. */ + +/* + * The following data structure contains the system specific data + * necessary to control Windows cursors. + */ + +typedef struct { + TkCursor info; /* Generic cursor info used by tkCursor.c */ + Handle macCursor; /* Resource containing Macintosh cursor. */ + int type; /* Type of Mac cursor: arrow, crsr, CURS */ +} TkMacCursor; + +/* + * The table below is used to map from the name of a predefined cursor + * to its resource identifier. + */ + +static struct CursorName { + char *name; + int id; +} cursorNames[] = { + {"ibeam", 1}, + {"text", 1}, + {"xterm", 1}, + {"cross", 2}, + {"crosshair", 2}, + {"cross-hair", 2}, + {"plus", 3}, + {"watch", 4}, + {"arrow", 5}, + {NULL, 0} +}; + +/* + * Declarations of static variables used in this file. + */ + +static TkMacCursor * gCurrentCursor = NULL; /* A pointer to the current + * cursor. */ +static int gResizeOverride = false; /* A boolean indicating wether + * we should use the resize + * cursor during installations. */ + +/* + * Declarations of procedures local to this file + */ + +static void FindCursorByName _ANSI_ARGS_ ((TkMacCursor *macCursorPtr, + char *string)); + +/* + *---------------------------------------------------------------------- + * + * FindCursorByName -- + * + * Retrieve a system cursor by name, and fill the macCursorPtr + * structure. If the cursor cannot be found, the macCursor field + * will be NULL. The function first attempts to load a color + * cursor. If that fails it will attempt to load a black & white + * cursor. + * + * Results: + * Fills the macCursorPtr record. + * + * Side effects: + * None + * + *---------------------------------------------------------------------- + */ + +void +FindCursorByName( + TkMacCursor *macCursorPtr, + char *string) +{ + Handle resource; + Str255 curName; + + curName[0] = strlen(string); + if (curName[0] > 255) { + return; + } + + strcpy((char *) curName + 1, string); + resource = GetNamedResource('crsr', curName); + + if (resource != NULL) { + short id; + Str255 theName; + ResType theType; + + HLock(resource); + GetResInfo(resource, &id, &theType, theName); + HUnlock(resource); + macCursorPtr->macCursor = (Handle) GetCCursor(id); + macCursorPtr->type = COLOR; + } + + if (resource == NULL) { + macCursorPtr->macCursor = GetNamedResource('CURS', curName); + macCursorPtr->type = NORMAL; + } +} + +/* + *---------------------------------------------------------------------- + * + * TkGetCursorByName -- + * + * Retrieve a system cursor by name. + * + * Results: + * Returns a new cursor, or NULL on errors. + * + * Side effects: + * Allocates a new cursor. + * + *---------------------------------------------------------------------- + */ + +TkCursor * +TkGetCursorByName( + Tcl_Interp *interp, /* Interpreter to use for error reporting. */ + Tk_Window tkwin, /* Window in which cursor will be used. */ + Tk_Uid string) /* Description of cursor. See manual entry + * for details on legal syntax. */ +{ + struct CursorName *namePtr; + TkMacCursor *macCursorPtr; + + macCursorPtr = (TkMacCursor *) ckalloc(sizeof(TkMacCursor)); + macCursorPtr->info.cursor = (Tk_Cursor) macCursorPtr; + + /* + * To find a cursor we must first determine if it is one of the + * builtin cursors or the standard arrow cursor. Otherwise, we + * attempt to load the cursor as a named Mac resource. + */ + + for (namePtr = cursorNames; namePtr->name != NULL; namePtr++) { + if (strcmp(namePtr->name, string) == 0) { + break; + } + } + + + if (namePtr->name != NULL) { + if (namePtr->id == 5) { + macCursorPtr->macCursor = (Handle) -1; + macCursorPtr->type = ARROW; + } else { + macCursorPtr->macCursor = (Handle) GetCursor(namePtr->id); + macCursorPtr->type = NORMAL; + } + } else { + FindCursorByName(macCursorPtr, string); + + if (macCursorPtr->macCursor == NULL) { + char **argv; + int argc, err; + + /* + * The user may be trying to specify an XCursor with fore + * & back colors. We don't want this to be an error, so pick + * off the first word, and try again. + */ + + err = Tcl_SplitList(interp, string, &argc, &argv); + if (err == TCL_OK ) { + if (argc > 1) { + FindCursorByName(macCursorPtr, argv[0]); + } + + ckfree((char *) argv); + } + } + } + + if (macCursorPtr->macCursor == NULL) { + ckfree((char *)macCursorPtr); + Tcl_AppendResult(interp, "bad cursor spec \"", string, "\"", + (char *) NULL); + return NULL; + } else { + return (TkCursor *) macCursorPtr; + } +} + +/* + *---------------------------------------------------------------------- + * + * TkCreateCursorFromData -- + * + * Creates a cursor from the source and mask bits. + * + * Results: + * Returns a new cursor, or NULL on errors. + * + * Side effects: + * Allocates a new cursor. + * + *---------------------------------------------------------------------- + */ + +TkCursor * +TkCreateCursorFromData( + Tk_Window tkwin, /* Window in which cursor will be used. */ + char *source, /* Bitmap data for cursor shape. */ + char *mask, /* Bitmap data for cursor mask. */ + int width, int height, /* Dimensions of cursor. */ + int xHot, int yHot, /* Location of hot-spot in cursor. */ + XColor fgColor, /* Foreground color for cursor. */ + XColor bgColor) /* Background color for cursor. */ +{ + return NULL; +} + +/* + *---------------------------------------------------------------------- + * + * TkFreeCursor -- + * + * This procedure is called to release a cursor allocated by + * TkGetCursorByName. + * + * Results: + * None. + * + * Side effects: + * The cursor data structure is deallocated. + * + *---------------------------------------------------------------------- + */ + +void +TkFreeCursor( + TkCursor *cursorPtr) +{ + TkMacCursor *macCursorPtr = (TkMacCursor *) cursorPtr; + + switch (macCursorPtr->type) { + case COLOR: + DisposeCCursor((CCrsrHandle) macCursorPtr->macCursor); + break; + case NORMAL: + ReleaseResource(macCursorPtr->macCursor); + break; + } + + if (macCursorPtr == gCurrentCursor) { + gCurrentCursor = NULL; + } + + ckfree((char *) macCursorPtr); +} + +/* + *---------------------------------------------------------------------- + * + * TkMacInstallCursor -- + * + * Installs either the current cursor as defined by TkpSetCursor + * or a resize cursor as the cursor the Macintosh should currently + * display. + * + * Results: + * None. + * + * Side effects: + * Changes the Macintosh mouse cursor. + * + *---------------------------------------------------------------------- + */ + +void +TkMacInstallCursor( + int resizeOverride) +{ + TkMacCursor *macCursorPtr = gCurrentCursor; + CCrsrHandle ccursor; + CursHandle cursor; + + gResizeOverride = resizeOverride; + + if (resizeOverride) { + cursor = (CursHandle) GetNamedResource('CURS', "\presize"); + SetCursor(*cursor); + } else if (macCursorPtr == NULL || macCursorPtr->type == ARROW) { + SetCursor(&tcl_macQdPtr->arrow); + } else { + switch (macCursorPtr->type) { + case COLOR: + ccursor = (CCrsrHandle) macCursorPtr->macCursor; + SetCCursor(ccursor); + break; + case NORMAL: + cursor = (CursHandle) macCursorPtr->macCursor; + SetCursor(*cursor); + break; + } + } +} + +/* + *---------------------------------------------------------------------- + * + * TkpSetCursor -- + * + * Set the current cursor and install it. + * + * Results: + * None. + * + * Side effects: + * Changes the current cursor. + * + *---------------------------------------------------------------------- + */ + +void +TkpSetCursor( + TkpCursor cursor) +{ + if (cursor == None) { + gCurrentCursor = NULL; + } else { + gCurrentCursor = (TkMacCursor *) cursor; + } + + if (tkMacAppInFront) { + TkMacInstallCursor(gResizeOverride); + } +} diff --git a/mac/tkMacCursors.r b/mac/tkMacCursors.r new file mode 100644 index 0000000..44ad02e --- /dev/null +++ b/mac/tkMacCursors.r @@ -0,0 +1,130 @@ +/* + * tkMacCursors.r -- + * + * This file defines a set of Macintosh cursor resources that + * are only available on the Macintosh platform. + * + * Copyright (c) 1995-1996 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) tkMacCursors.r 1.3 96/01/25 10:24:15 + */ + +/* + * These are resource definitions for Macintosh cursors. + * The are identified and loaded by the "name" of the + * cursor. However, the ids must be unique. + */ + +data 'CURS' (1000, "hand") { + $"0180 1A70 2648 264A 124D 1249 6809 9801" + $"8802 4002 2002 2004 1004 0808 0408 0408" + $"0180 1BF0 3FF8 3FFA 1FFF 1FFF 6FFF FFFF" + $"FFFE 7FFE 3FFE 3FFC 1FFC 0FF8 07F8 07F8" + $"0009 0008" +}; + +data 'CURS' (1002, "bucket") { + $"0000 0000 0600 0980 0940 0B30 0D18 090C" + $"129C 212C 104C 088C 050C 0208 0000 0000" + $"0000 0000 0600 0980 09C0 0BF0 0FF8 0FFC" + $"1FFC 3FEC 1FCC 0F8C 070C 0208 0000 0000" + $"000D 000C" +}; + +data 'CURS' (1003, "cancel") { + $"0000 0000 0000 0000 3180 4A40 4A40 3F80" + $"0A00 3F80 4A40 4A46 3186 0000 0000 0000" + $"0000 0000 0000 3180 7BC0 FFE0 FFE0 7FC0" + $"3F80 7FC0 FFE6 FFEF 7BCF 3186 0000 0000" + $"0008 0005" +}; + +data 'CURS' (1004, "Resize") { + $"FFFF 8001 BF01 A181 A1F9 A18D A18D BF8D" + $"9F8D 880D 880D 880D 8FFD 87FD 8001 FFFF" + $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" + $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" + $"0008 0008" +}; + +data 'CURS' (1005, "eyedrop") { + $"000E 001F 001F 00FF 007E 00B8 0118 0228" + $"0440 0880 1100 2200 4400 4800 B000 4000" + $"000E 001F 001F 00FF 007E 00F8 01F8 03E8" + $"07C0 0F80 1F00 3E00 7C00 7800 F000 4000" + $"000F 0000" +}; + +data 'CURS' (1006, "eyedrop-full") { + $"000E 001F 001F 00FF 007E 00B8 0118 0328" + $"07C0 0F80 1F00 3E00 7C00 7800 F000 4000" + $"000E 001F 001F 00FF 007E 00F8 01F8 03E8" + $"07C0 0F80 1F00 3E00 7C00 7800 F000 4000" + $"000F 0000" +}; + +data 'CURS' (1007, "zoom-in") { + $"0780 1860 2790 5868 5028 A014 AFD4 AFD4" + $"A014 5028 5868 2798 187C 078E 0007 0003" + $"0780 1FE0 3FF0 7878 7038 E01C EFDC EFDC" + $"E01C 7038 7878 3FF8 1FFC 078E 0007 0003" + $"0007 0007" +}; + +data 'CURS' (1008, "zoom-out") { + $"0780 1860 2790 5868 5328 A314 AFD4 AFD4" + $"A314 5328 5868 2798 187C 078E 0007 0003" + $"0780 1FE0 3FF0 7878 7338 E31C EFDC EFDC" + $"E31C 7338 7878 3FF8 1FFC 078E 0007 0003" + $"0007 0007" +}; + +/* + * The following are resource definitions for color + * cursors on the Macintosh. If a color cursor and + * a black & white cursor are both defined with the + * same name preference will be given to the color + * cursors. + */ + +data 'crsr' (1000, "hand") { + $"8001 0000 0060 0000 0092 0000 0000 0000" + $"0000 0000 0180 1A70 2648 264A 124D 1249" + $"6809 9801 8802 4002 2002 2004 1004 0808" + $"0408 0408 0180 1BF0 3FF8 3FFA 1FFF 1FFF" + $"6FFF FFFF FFFE 7FFE 3FFE 3FFC 1FFC 0FF8" + $"07F8 07F8 0008 0008 0000 0000 0000 0000" + $"0000 0000 8004 0000 0000 0010 0010 0000" + $"0000 0000 0000 0048 0000 0048 0000 0000" + $"0002 0001 0002 0000 0000 0000 00D2 0000" + $"0000 0003 C000 03CD 7F00 0D7D 75C0 0D7D" + $"75CC 035D 75F7 035D 75D7 3CD5 55D7 D7D5" + $"5557 D5D5 555C 3555 555C 0D55 555C 0D55" + $"5570 0355 5570 00D5 55C0 0035 55C0 0035" + $"55C0 0000 0000 0000 0002 0000 FFFF FFFF" + $"FFFF 0001 FFFF CCCC 9999 0003 0000 0000" + $"0000" +}; + +data 'crsr' (1001, "fist") { + $"8001 0000 0060 0000 0092 0000 0000 0000" + $"0000 0000 0000 0000 0000 0000 0DB0 124C" + $"100A 0802 1802 2002 2002 2004 1004 0808" + $"0408 0408 0000 0000 0000 0000 0DB0 1FFC" + $"1FFE 0FFE 1FFE 3FFE 3FFE 3FFC 1FFC 0FF8" + $"07F8 07F8 0008 0008 0000 0000 0000 0000" + $"0000 0000 8004 0000 0000 0010 0010 0000" + $"0000 0000 0000 0048 0000 0048 0000 0000" + $"0002 0001 0002 0000 0000 0000 00D2 0000" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 00F3 CF00 035D 75F0 0355 55DC 00D5" + $"555C 03D5 555C 0D55 555C 0D55 555C 0D55" + $"5570 0355 5570 00D5 55C0 0035 55C0 0035" + $"55C0 0000 0000 0000 0002 0000 FFFF FFFF" + $"FFFF 0001 FFFF CCCC 9999 0003 0000 0000" + $"0000" +}; + diff --git a/mac/tkMacDefault.h b/mac/tkMacDefault.h new file mode 100644 index 0000000..372d89b --- /dev/null +++ b/mac/tkMacDefault.h @@ -0,0 +1,461 @@ +/* + * tkMacDefault.h -- + * + * This file defines the defaults for all options for all of + * the Tk widgets. + * + * Copyright (c) 1991-1994 The Regents of the University of California. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) tkMacDefault.h 1.48 97/10/09 17:45:04 + */ + +#ifndef _TKMACDEFAULT +#define _TKMACDEFAULT + +/* + * The definitions below provide symbolic names for the default colors. + * NORMAL_BG - Normal background color. + * ACTIVE_BG - Background color when widget is active. + * SELECT_BG - Background color for selected text. + * SELECT_FG - Foreground color for selected text. + * TROUGH - Background color for troughs in scales and scrollbars. + * INDICATOR - Color for indicator when button is selected. + * DISABLED - Foreground color when widget is disabled. + */ + +#define BLACK "Black" +#define WHITE "White" + +#define NORMAL_BG "systemWindowBody" +#define ACTIVE_BG "#ececec" +#define SELECT_BG "systemHighlight" +#define SELECT_FG "systemHighlightText" +#define TROUGH "#c3c3c3" +#define INDICATOR "#b03060" +#define DISABLED "#a3a3a3" + +/* + * Defaults for labels, buttons, checkbuttons, and radiobuttons: + */ + +#define DEF_BUTTON_ANCHOR "center" +#define DEF_BUTTON_ACTIVE_BG_COLOR "systemButtonText" +#define DEF_BUTTON_ACTIVE_BG_MONO BLACK +#define DEF_BUTTON_ACTIVE_FG_COLOR "systemButtonFace" +#define DEF_CHKRAD_ACTIVE_FG_COLOR DEF_BUTTON_ACTIVE_FG_COLOR +#define DEF_BUTTON_ACTIVE_FG_MONO WHITE +#define DEF_BUTTON_BG_COLOR "systemButtonFace" +#define DEF_BUTTON_BG_MONO WHITE +#define DEF_BUTTON_BITMAP "" +#define DEF_BUTTON_BORDER_WIDTH "2" +#define DEF_BUTTON_CURSOR "" +#define DEF_BUTTON_COMMAND "" +#define DEF_BUTTON_DEFAULT "disabled" +#define DEF_BUTTON_DISABLED_FG_COLOR DISABLED +#define DEF_BUTTON_DISABLED_FG_MONO "" +#define DEF_BUTTON_FG "systemButtonText" +#define DEF_CHKRAD_FG DEF_BUTTON_FG +#define DEF_BUTTON_FONT "system" +#define DEF_BUTTON_HEIGHT "0" +#define DEF_BUTTON_HIGHLIGHT_BG NORMAL_BG +#define DEF_BUTTON_HIGHLIGHT "systemButtonFrame" +#define DEF_LABEL_HIGHLIGHT_WIDTH "0" +#define DEF_BUTTON_HIGHLIGHT_WIDTH "4" +#define DEF_BUTTON_IMAGE (char *) NULL +#define DEF_BUTTON_INDICATOR "1" +#define DEF_BUTTON_JUSTIFY "center" +#define DEF_BUTTON_OFF_VALUE "0" +#define DEF_BUTTON_ON_VALUE "1" +#define DEF_BUTTON_PADX "7" +#define DEF_LABCHKRAD_PADX "1" +#define DEF_BUTTON_PADY "3" +#define DEF_LABCHKRAD_PADY "1" +#define DEF_BUTTON_RELIEF "flat" +#define DEF_LABCHKRAD_RELIEF "flat" +#define DEF_BUTTON_SELECT_COLOR INDICATOR +#define DEF_BUTTON_SELECT_MONO BLACK +#define DEF_BUTTON_SELECT_IMAGE (char *) NULL +#define DEF_BUTTON_STATE "normal" +#define DEF_LABEL_TAKE_FOCUS "0" +#define DEF_BUTTON_TAKE_FOCUS (char *) NULL +#define DEF_BUTTON_TEXT "" +#define DEF_BUTTON_TEXT_VARIABLE "" +#define DEF_BUTTON_UNDERLINE "-1" +#define DEF_BUTTON_VALUE "" +#define DEF_BUTTON_WIDTH "0" +#define DEF_BUTTON_WRAP_LENGTH "0" +#define DEF_RADIOBUTTON_VARIABLE "selectedButton" +#define DEF_CHECKBUTTON_VARIABLE "" + +/* + * Defaults for canvases: + */ + +#define DEF_CANVAS_BG_COLOR NORMAL_BG +#define DEF_CANVAS_BG_MONO WHITE +#define DEF_CANVAS_BORDER_WIDTH "0" +#define DEF_CANVAS_CLOSE_ENOUGH "1" +#define DEF_CANVAS_CONFINE "1" +#define DEF_CANVAS_CURSOR "" +#define DEF_CANVAS_HEIGHT "7c" +#define DEF_CANVAS_HIGHLIGHT_BG NORMAL_BG +#define DEF_CANVAS_HIGHLIGHT BLACK +#define DEF_CANVAS_HIGHLIGHT_WIDTH "3" +#define DEF_CANVAS_INSERT_BG BLACK +#define DEF_CANVAS_INSERT_BD_COLOR "0" +#define DEF_CANVAS_INSERT_BD_MONO "0" +#define DEF_CANVAS_INSERT_OFF_TIME "300" +#define DEF_CANVAS_INSERT_ON_TIME "600" +#define DEF_CANVAS_INSERT_WIDTH "2" +#define DEF_CANVAS_RELIEF "flat" +#define DEF_CANVAS_SCROLL_REGION "" +#define DEF_CANVAS_SELECT_COLOR SELECT_BG +#define DEF_CANVAS_SELECT_MONO BLACK +#define DEF_CANVAS_SELECT_BD_COLOR "1" +#define DEF_CANVAS_SELECT_BD_MONO "0" +#define DEF_CANVAS_SELECT_FG_COLOR BLACK +#define DEF_CANVAS_SELECT_FG_MONO WHITE +#define DEF_CANVAS_TAKE_FOCUS (char *) NULL +#define DEF_CANVAS_WIDTH "10c" +#define DEF_CANVAS_X_SCROLL_CMD "" +#define DEF_CANVAS_X_SCROLL_INCREMENT "0" +#define DEF_CANVAS_Y_SCROLL_CMD "" +#define DEF_CANVAS_Y_SCROLL_INCREMENT "0" + +/* + * Defaults for entries: + */ + +#define DEF_ENTRY_BG_COLOR NORMAL_BG +#define DEF_ENTRY_BG_MONO WHITE +/* #define DEF_ENTRY_BORDER_WIDTH "2" */ +#define DEF_ENTRY_BORDER_WIDTH "1" +#define DEF_ENTRY_CURSOR "xterm" +#define DEF_ENTRY_EXPORT_SELECTION "1" +#define DEF_ENTRY_FONT "Helvetica 12" +#define DEF_ENTRY_FG BLACK +#define DEF_ENTRY_HIGHLIGHT_BG NORMAL_BG +#define DEF_ENTRY_HIGHLIGHT BLACK +/* #define DEF_ENTRY_HIGHLIGHT_WIDTH "3" */ +#define DEF_ENTRY_HIGHLIGHT_WIDTH "0" +#define DEF_ENTRY_INSERT_BG BLACK +#define DEF_ENTRY_INSERT_BD_COLOR "0" +#define DEF_ENTRY_INSERT_BD_MONO "0" +#define DEF_ENTRY_INSERT_OFF_TIME "300" +#define DEF_ENTRY_INSERT_ON_TIME "600" +/* #define DEF_ENTRY_INSERT_WIDTH "2" */ +#define DEF_ENTRY_INSERT_WIDTH "1" +#define DEF_ENTRY_JUSTIFY "left" +/* #define DEF_ENTRY_RELIEF "sunken" */ +#define DEF_ENTRY_RELIEF "solid" +#define DEF_ENTRY_SCROLL_COMMAND "" +#define DEF_ENTRY_SELECT_COLOR SELECT_BG +#define DEF_ENTRY_SELECT_MONO BLACK +#define DEF_ENTRY_SELECT_BD_COLOR "1" +#define DEF_ENTRY_SELECT_BD_MONO "0" +#define DEF_ENTRY_SELECT_FG_COLOR SELECT_FG +#define DEF_ENTRY_SELECT_FG_MONO WHITE +#define DEF_ENTRY_SHOW (char *) NULL +#define DEF_ENTRY_STATE "normal" +#define DEF_ENTRY_TAKE_FOCUS (char *) NULL +#define DEF_ENTRY_TEXT_VARIABLE "" +#define DEF_ENTRY_WIDTH "20" + +/* + * Defaults for frames: + */ + +#define DEF_FRAME_BG_COLOR NORMAL_BG +#define DEF_FRAME_BG_MONO WHITE +#define DEF_FRAME_BORDER_WIDTH "0" +#define DEF_FRAME_CLASS "Frame" +#define DEF_FRAME_COLORMAP "" +#define DEF_FRAME_CONTAINER "0" +#define DEF_FRAME_CURSOR "" +#define DEF_FRAME_HEIGHT "0" +#define DEF_FRAME_HIGHLIGHT_BG NORMAL_BG +#define DEF_FRAME_HIGHLIGHT BLACK +#define DEF_FRAME_HIGHLIGHT_WIDTH "0" +#define DEF_FRAME_RELIEF "flat" +#define DEF_FRAME_TAKE_FOCUS "0" +#define DEF_FRAME_USE "" +#define DEF_FRAME_VISUAL "" +#define DEF_FRAME_WIDTH "0" + +/* + * Defaults for listboxes: + */ + +#define DEF_LISTBOX_BG_COLOR NORMAL_BG +#define DEF_LISTBOX_BG_MONO WHITE +#define DEF_LISTBOX_BORDER_WIDTH "1" +#define DEF_LISTBOX_CURSOR "" +#define DEF_LISTBOX_EXPORT_SELECTION "1" +#define DEF_LISTBOX_FONT "application" +#define DEF_LISTBOX_FG BLACK +#define DEF_LISTBOX_HEIGHT "10" +#define DEF_LISTBOX_HIGHLIGHT_BG NORMAL_BG +#define DEF_LISTBOX_HIGHLIGHT BLACK +#define DEF_LISTBOX_HIGHLIGHT_WIDTH "0" +#define DEF_LISTBOX_RELIEF "solid" +#define DEF_LISTBOX_SCROLL_COMMAND "" +#define DEF_LISTBOX_SELECT_COLOR SELECT_BG +#define DEF_LISTBOX_SELECT_MONO BLACK +#define DEF_LISTBOX_SELECT_BD "0" +#define DEF_LISTBOX_SELECT_FG_COLOR SELECT_FG +#define DEF_LISTBOX_SELECT_FG_MONO WHITE +#define DEF_LISTBOX_SELECT_MODE "browse" +#define DEF_LISTBOX_SET_GRID "0" +#define DEF_LISTBOX_TAKE_FOCUS (char *) NULL +#define DEF_LISTBOX_WIDTH "20" + +/* + * Defaults for individual entries of menus: + */ + +#define DEF_MENU_ENTRY_ACTIVE_BG (char *) NULL +#define DEF_MENU_ENTRY_ACTIVE_FG (char *) NULL +#define DEF_MENU_ENTRY_ACCELERATOR (char *) NULL +#define DEF_MENU_ENTRY_BG (char *) NULL +#define DEF_MENU_ENTRY_BITMAP None +#define DEF_MENU_ENTRY_COLUMN_BREAK "0" +#define DEF_MENU_ENTRY_COMMAND (char *) NULL +#define DEF_MENU_ENTRY_FG (char *) NULL +#define DEF_MENU_ENTRY_FONT (char *) NULL +#define DEF_MENU_ENTRY_HIDE_MARGIN "0" +#define DEF_MENU_ENTRY_IMAGE (char *) NULL +#define DEF_MENU_ENTRY_INDICATOR "1" +#define DEF_MENU_ENTRY_LABEL (char *) NULL +#define DEF_MENU_ENTRY_MENU (char *) NULL +#define DEF_MENU_ENTRY_OFF_VALUE "0" +#define DEF_MENU_ENTRY_ON_VALUE "1" +#define DEF_MENU_ENTRY_SELECT_IMAGE (char *) NULL +#define DEF_MENU_ENTRY_STATE "normal" +#define DEF_MENU_ENTRY_VALUE (char *) NULL +#define DEF_MENU_ENTRY_CHECK_VARIABLE (char *) NULL +#define DEF_MENU_ENTRY_RADIO_VARIABLE "selectedButton" +#define DEF_MENU_ENTRY_SELECT (char *) NULL +#define DEF_MENU_ENTRY_UNDERLINE "-1" + +/* + * Defaults for menus overall: + */ + +#define DEF_MENU_ACTIVE_BG_COLOR "SystemMenuActive" +#define DEF_MENU_ACTIVE_BG_MONO BLACK +#define DEF_MENU_ACTIVE_BORDER_WIDTH "0" +#define DEF_MENU_ACTIVE_FG_COLOR "SystemMenuActiveText" +#define DEF_MENU_ACTIVE_FG_MONO WHITE +#define DEF_MENU_BG_COLOR "SystemMenu" +#define DEF_MENU_BG_MONO WHITE +#define DEF_MENU_BORDER_WIDTH "0" +#define DEF_MENU_CURSOR "arrow" +#define DEF_MENU_DISABLED_FG_COLOR "SystemMenuDisabled" +#define DEF_MENU_DISABLED_FG_MONO "" +#define DEF_MENU_FONT "system" +#define DEF_MENU_FG "SystemMenuText" +#define DEF_MENU_POST_COMMAND "" +#define DEF_MENU_RELIEF "flat" +#define DEF_MENU_SELECT_COLOR "SystemMenuActive" +#define DEF_MENU_SELECT_MONO BLACK +#define DEF_MENU_TAKE_FOCUS "0" +#define DEF_MENU_TEAROFF "1" +#define DEF_MENU_TEAROFF_CMD (char *) NULL +#define DEF_MENU_TITLE "" +#define DEF_MENU_TYPE "normal" + +/* + * Defaults for menubuttons: + */ + +#define DEF_MENUBUTTON_ANCHOR "center" +#define DEF_MENUBUTTON_ACTIVE_BG_COLOR ACTIVE_BG +#define DEF_MENUBUTTON_ACTIVE_BG_MONO BLACK +#define DEF_MENUBUTTON_ACTIVE_FG_COLOR BLACK +#define DEF_MENUBUTTON_ACTIVE_FG_MONO WHITE +#define DEF_MENUBUTTON_BG_COLOR NORMAL_BG +#define DEF_MENUBUTTON_BG_MONO WHITE +#define DEF_MENUBUTTON_BITMAP "" +#define DEF_MENUBUTTON_BORDER_WIDTH "2" +#define DEF_MENUBUTTON_CURSOR "" +#define DEF_MENUBUTTON_DIRECTION "below" +#define DEF_MENUBUTTON_DISABLED_FG_COLOR DISABLED +#define DEF_MENUBUTTON_DISABLED_FG_MONO "" +#define DEF_MENUBUTTON_FONT "system" +#define DEF_MENUBUTTON_FG BLACK +#define DEF_MENUBUTTON_HEIGHT "0" +#define DEF_MENUBUTTON_HIGHLIGHT_BG NORMAL_BG +#define DEF_MENUBUTTON_HIGHLIGHT BLACK +#define DEF_MENUBUTTON_HIGHLIGHT_WIDTH "0" +#define DEF_MENUBUTTON_IMAGE (char *) NULL +#define DEF_MENUBUTTON_INDICATOR "0" +/* #define DEF_MENUBUTTON_JUSTIFY "center" */ +#define DEF_MENUBUTTON_JUSTIFY "left" +#define DEF_MENUBUTTON_MENU "" +#define DEF_MENUBUTTON_PADX "4p" +#define DEF_MENUBUTTON_PADY "3p" +#define DEF_MENUBUTTON_RELIEF "flat" +#define DEF_MENUBUTTON_STATE "normal" +#define DEF_MENUBUTTON_TAKE_FOCUS "0" +#define DEF_MENUBUTTON_TEXT "" +#define DEF_MENUBUTTON_TEXT_VARIABLE "" +#define DEF_MENUBUTTON_UNDERLINE "-1" +#define DEF_MENUBUTTON_WIDTH "0" +#define DEF_MENUBUTTON_WRAP_LENGTH "0" + +/* + * Defaults for messages: + */ + +#define DEF_MESSAGE_ANCHOR "center" +#define DEF_MESSAGE_ASPECT "150" +#define DEF_MESSAGE_BG_COLOR NORMAL_BG +#define DEF_MESSAGE_BG_MONO WHITE +#define DEF_MESSAGE_BORDER_WIDTH "2" +#define DEF_MESSAGE_CURSOR "" +#define DEF_MESSAGE_FG BLACK +#define DEF_MESSAGE_FONT "system" +#define DEF_MESSAGE_HIGHLIGHT_BG NORMAL_BG +#define DEF_MESSAGE_HIGHLIGHT BLACK +#define DEF_MESSAGE_HIGHLIGHT_WIDTH "0" +#define DEF_MESSAGE_JUSTIFY "left" +#define DEF_MESSAGE_PADX "-1" +#define DEF_MESSAGE_PADY "-1" +#define DEF_MESSAGE_RELIEF "flat" +#define DEF_MESSAGE_TAKE_FOCUS "0" +#define DEF_MESSAGE_TEXT "" +#define DEF_MESSAGE_TEXT_VARIABLE "" +#define DEF_MESSAGE_WIDTH "0" + +/* + * Defaults for scales: + */ + +#define DEF_SCALE_ACTIVE_BG_COLOR ACTIVE_BG +#define DEF_SCALE_ACTIVE_BG_MONO BLACK +#define DEF_SCALE_BG_COLOR NORMAL_BG +#define DEF_SCALE_BG_MONO WHITE +#define DEF_SCALE_BIG_INCREMENT "0" +#define DEF_SCALE_BORDER_WIDTH "2" +#define DEF_SCALE_COMMAND "" +#define DEF_SCALE_CURSOR "" +#define DEF_SCALE_DIGITS "0" +#define DEF_SCALE_FONT "system" +#define DEF_SCALE_FG_COLOR BLACK +#define DEF_SCALE_FG_MONO BLACK +#define DEF_SCALE_FROM "0" +#define DEF_SCALE_HIGHLIGHT_BG NORMAL_BG +#define DEF_SCALE_HIGHLIGHT BLACK +#define DEF_SCALE_HIGHLIGHT_WIDTH "0" +#define DEF_SCALE_LABEL "" +#define DEF_SCALE_LENGTH "100" +#define DEF_SCALE_ORIENT "vertical" +#define DEF_SCALE_RELIEF "flat" +#define DEF_SCALE_REPEAT_DELAY "300" +#define DEF_SCALE_REPEAT_INTERVAL "100" +#define DEF_SCALE_RESOLUTION "1" +#define DEF_SCALE_TROUGH_COLOR TROUGH +#define DEF_SCALE_TROUGH_MONO WHITE +#define DEF_SCALE_SHOW_VALUE "1" +#define DEF_SCALE_SLIDER_LENGTH "30" +#define DEF_SCALE_SLIDER_RELIEF "raised" +#define DEF_SCALE_STATE "normal" +#define DEF_SCALE_TAKE_FOCUS (char *) NULL +#define DEF_SCALE_TICK_INTERVAL "0" +#define DEF_SCALE_TO "100" +#define DEF_SCALE_VARIABLE "" +#define DEF_SCALE_WIDTH "15" + +/* + * Defaults for scrollbars: + */ + +#define DEF_SCROLLBAR_ACTIVE_BG_COLOR ACTIVE_BG +#define DEF_SCROLLBAR_ACTIVE_BG_MONO BLACK +#define DEF_SCROLLBAR_ACTIVE_RELIEF "raised" +#define DEF_SCROLLBAR_BG_COLOR NORMAL_BG +#define DEF_SCROLLBAR_BG_MONO WHITE +/* #define DEF_SCROLLBAR_BORDER_WIDTH "2" */ +#define DEF_SCROLLBAR_BORDER_WIDTH "0" +#define DEF_SCROLLBAR_COMMAND "" +#define DEF_SCROLLBAR_CURSOR "" +#define DEF_SCROLLBAR_EL_BORDER_WIDTH "-1" +#define DEF_SCROLLBAR_HIGHLIGHT_BG NORMAL_BG +#define DEF_SCROLLBAR_HIGHLIGHT BLACK +/* #define DEF_SCROLLBAR_HIGHLIGHT_WIDTH "2" */ +#define DEF_SCROLLBAR_HIGHLIGHT_WIDTH "0" +#define DEF_SCROLLBAR_JUMP "0" +#define DEF_SCROLLBAR_ORIENT "vertical" +/*#define DEF_SCROLLBAR_RELIEF "sunken" */ +#define DEF_SCROLLBAR_RELIEF "flat" +#define DEF_SCROLLBAR_REPEAT_DELAY "300" +#define DEF_SCROLLBAR_REPEAT_INTERVAL "100" +#define DEF_SCROLLBAR_TAKE_FOCUS (char *) NULL +#define DEF_SCROLLBAR_TROUGH_COLOR TROUGH +#define DEF_SCROLLBAR_TROUGH_MONO WHITE +/*#define DEF_SCROLLBAR_WIDTH "15" */ +#define DEF_SCROLLBAR_WIDTH "16" + +/* + * Defaults for texts: + */ + +#define DEF_TEXT_BG_COLOR NORMAL_BG +#define DEF_TEXT_BG_MONO WHITE +#define DEF_TEXT_BORDER_WIDTH "0" +#define DEF_TEXT_CURSOR "xterm" +#define DEF_TEXT_FG BLACK +#define DEF_TEXT_EXPORT_SELECTION "1" +#define DEF_TEXT_FONT "Courier 12" +#define DEF_TEXT_HEIGHT "24" +#define DEF_TEXT_HIGHLIGHT_BG NORMAL_BG +#define DEF_TEXT_HIGHLIGHT BLACK +#define DEF_TEXT_HIGHLIGHT_WIDTH "3" +#define DEF_TEXT_INSERT_BG BLACK +#define DEF_TEXT_INSERT_BD_COLOR "0" +#define DEF_TEXT_INSERT_BD_MONO "0" +#define DEF_TEXT_INSERT_OFF_TIME "300" +#define DEF_TEXT_INSERT_ON_TIME "600" +#define DEF_TEXT_INSERT_WIDTH "1" +#define DEF_TEXT_PADX "1" +#define DEF_TEXT_PADY "1" +#define DEF_TEXT_RELIEF "flat" +#define DEF_TEXT_SELECT_COLOR SELECT_BG +#define DEF_TEXT_SELECT_MONO BLACK +#define DEF_TEXT_SELECT_BD_COLOR "1" +#define DEF_TEXT_SELECT_BD_MONO "0" +#define DEF_TEXT_SELECT_FG_COLOR SELECT_FG +#define DEF_TEXT_SELECT_FG_MONO WHITE +#define DEF_TEXT_SELECT_RELIEF "solid" +#define DEF_TEXT_SET_GRID "0" +#define DEF_TEXT_SPACING1 "0" +#define DEF_TEXT_SPACING2 "0" +#define DEF_TEXT_SPACING3 "0" +#define DEF_TEXT_STATE "normal" +#define DEF_TEXT_TABS "" +#define DEF_TEXT_TAKE_FOCUS (char *) NULL +#define DEF_TEXT_WIDTH "80" +#define DEF_TEXT_WRAP "char" +#define DEF_TEXT_XSCROLL_COMMAND "" +#define DEF_TEXT_YSCROLL_COMMAND "" + +/* + * Defaults for canvas text: + */ + +#define DEF_CANVTEXT_FONT "Helvetica 12" + +/* + * Defaults for toplevels (most of the defaults for frames also apply + * to toplevels): + */ + +#define DEF_TOPLEVEL_CLASS "Toplevel" +#define DEF_TOPLEVEL_MENU "" +#define DEF_TOPLEVEL_SCREEN "" + +#endif /* _TKMACDEFAULT */ diff --git a/mac/tkMacDialog.c b/mac/tkMacDialog.c new file mode 100644 index 0000000..43d11a5 --- /dev/null +++ b/mac/tkMacDialog.c @@ -0,0 +1,939 @@ +/* + * tkMacDialog.c -- + * + * Contains the Mac implementation of the common dialog boxes. + * + * Copyright (c) 1996 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) tkMacDialog.c 1.12 96/12/03 11:15:12 + * + */ + +#include <Gestalt.h> +#include <Aliases.h> +#include <Errors.h> +#include <Strings.h> +#include <MoreFiles.h> +#include <MoreFilesExtras.h> +#include <StandardFile.h> +#include <ColorPicker.h> +#include <Lowmem.h> +#include "tkPort.h" +#include "tkInt.h" +#include "tclMacInt.h" +#include "tkFileFilter.h" + +/* + * The following are ID's for resources that are defined in tkMacResource.r + */ +#define OPEN_BOX 130 +#define OPEN_POPUP 131 +#define OPEN_MENU 132 +#define OPEN_POPUP_ITEM 10 + +#define SAVE_FILE 0 +#define OPEN_FILE 1 + +#define MATCHED 0 +#define UNMATCHED 1 + +/* + * The following structure is used in the GetFileName() function. It stored + * information about the file dialog and the file filters. + */ +typedef struct _OpenFileData { + Tcl_Interp * interp; + char * initialFile; /* default file to appear in the + * save dialog */ + char * defExt; /* default extension (not used on the + * Mac) */ + FileFilterList fl; /* List of file filters. */ + SInt16 curType; /* The filetype currently being + * listed */ + int isOpen; /* True if this is an Open dialog, + * false if it is a Save dialog. */ + MenuHandle menu; /* Handle of the menu in the popup*/ + short dialogId; /* resource ID of the dialog */ + int popupId; /* resource ID of the popup */ + short popupItem; /* item number of the popup in the + * dialog */ + int usePopup; /* True if we show the popup menu (this + * is an open operation and the + * -filetypes option is set) + */ +} OpenFileData; + +static pascal Boolean FileFilterProc _ANSI_ARGS_((CInfoPBPtr pb, + void *myData)); +static int GetFileName _ANSI_ARGS_ (( + ClientData clientData, Tcl_Interp *interp, + int argc, char **argv, int isOpen )); +static Boolean MatchOneType _ANSI_ARGS_((CInfoPBPtr pb, + OpenFileData * myDataPtr, FileFilter * filterPtr)); +static pascal short OpenHookProc _ANSI_ARGS_((short item, + DialogPtr theDialog, OpenFileData * myDataPtr)); +static int ParseFileDlgArgs _ANSI_ARGS_ ((Tcl_Interp * interp, + OpenFileData * myDataPtr, int argc, char ** argv, + int isOpen)); + +/* + * Filter and hook functions used by the tk_getOpenFile and tk_getSaveFile + * commands. + */ + +static FileFilterYDUPP openFilter = NULL; +static DlgHookYDUPP openHook = NULL; +static DlgHookYDUPP saveHook = NULL; + + +/* + *---------------------------------------------------------------------- + * + * EvalArgv -- + * + * Invokes the Tcl procedure with the arguments. argv[0] is set by + * the caller of this function. It may be different than cmdName. + * The TCL command will see argv[0], not cmdName, as its name if it + * invokes [lindex [info level 0] 0] + * + * Results: + * TCL_ERROR if the command does not exist and cannot be autoloaded. + * Otherwise, return the result of the evaluation of the command. + * + * Side effects: + * The command may be autoloaded. + * + *---------------------------------------------------------------------- + */ + +static int +EvalArgv( + Tcl_Interp *interp, /* Current interpreter. */ + char * cmdName, /* Name of the TCL command to call */ + int argc, /* Number of arguments. */ + char **argv) /* Argument strings. */ +{ + Tcl_CmdInfo cmdInfo; + + if (!Tcl_GetCommandInfo(interp, cmdName, &cmdInfo)) { + char * cmdArgv[2]; + + /* + * This comand is not in the interpreter yet -- looks like we + * have to auto-load it + */ + if (!Tcl_GetCommandInfo(interp, "auto_load", &cmdInfo)) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "cannot execute command \"auto_load\"", + NULL); + return TCL_ERROR; + } + + cmdArgv[0] = "auto_load"; + cmdArgv[1] = cmdName; + + if ((*cmdInfo.proc)(cmdInfo.clientData, interp, 2, cmdArgv)!= TCL_OK){ + return TCL_ERROR; + } + + if (!Tcl_GetCommandInfo(interp, cmdName, &cmdInfo)) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "cannot auto-load command \"", + cmdName, "\"",NULL); + return TCL_ERROR; + } + } + + return (*cmdInfo.proc)(cmdInfo.clientData, interp, argc, argv); +} + +/* + *---------------------------------------------------------------------- + * + * Tk_ChooseColorCmd -- + * + * This procedure implements the color dialog box for the Mac + * platform. See the user documentation for details on what it + * does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + +int +Tk_ChooseColorCmd( + ClientData clientData, /* Main window associated with interpreter. */ + Tcl_Interp *interp, /* Current interpreter. */ + int argc, /* Number of arguments. */ + char **argv) /* Argument strings. */ +{ + Tk_Window parent = Tk_MainWindow(interp); + char * colorStr = NULL; + XColor * colorPtr = NULL; + char * title = "Choose a color:"; + int i, version; + long response = 0; + OSErr err = noErr; + char buff[40]; + static RGBColor in; + static inited = 0; + + /* + * Use the gestalt manager to determine how to bring + * up the color picker. If versin 2.0 isn't available + * we can assume version 1.0 is available as it comes with + * Color Quickdraw which Tk requires to run at all. + */ + + err = Gestalt(gestaltColorPicker, &response); + if ((err == noErr) || (response == 0x0200L)) { + version = 2; + } else { + version = 1; + } + + for (i=1; i<argc; i+=2) { + int v = i+1; + int len = strlen(argv[i]); + + if (strncmp(argv[i], "-initialcolor", len)==0) { + if (v==argc) {goto arg_missing;} + + colorStr = argv[v]; + } else if (strncmp(argv[i], "-parent", len)==0) { + if (v==argc) {goto arg_missing;} + + parent=Tk_NameToWindow(interp, argv[v], Tk_MainWindow(interp)); + if (parent == NULL) { + return TCL_ERROR; + } + } else if (strncmp(argv[i], "-title", len)==0) { + if (v==argc) {goto arg_missing;} + + title = argv[v]; + } else { + Tcl_AppendResult(interp, "unknown option \"", + argv[i], "\", must be -initialcolor, -parent or -title", + NULL); + return TCL_ERROR; + } + } + + if (colorStr) { + colorPtr = Tk_GetColor(interp, parent, colorStr); + if (colorPtr == NULL) { + return TCL_ERROR; + } + } + + if (!inited) { + inited = 1; + in.red = 0xffff; + in.green = 0xffff; + in.blue = 0xffff; + } + if (colorPtr) { + in.red = colorPtr->red; + in.green = colorPtr->green; + in.blue = colorPtr->blue; + } + + if (version == 1) { + /* + * Use version 1.0 of the color picker + */ + + RGBColor out; + Str255 prompt; + Point point = {-1, -1}; + + prompt[0] = strlen(title); + strncpy((char*) prompt+1, title, 255); + + if (GetColor(point, prompt, &in, &out)) { + /* + * user selected a color + */ + sprintf(buff, "#%02x%02x%02x", out.red >> 8, out.green >> 8, + out.blue >> 8); + Tcl_SetResult(interp, buff, TCL_VOLATILE); + + /* + * Save it for the next time + */ + in.red = out.red; + in.green = out.green; + in.blue = out.blue; + } else { + Tcl_ResetResult(interp); + } + } else { + /* + * Version 2.0 of the color picker is available. Let's use it + */ + ColorPickerInfo cpinfo; + + cpinfo.theColor.profile = 0L; + cpinfo.theColor.color.rgb.red = in.red; + cpinfo.theColor.color.rgb.green = in.green; + cpinfo.theColor.color.rgb.blue = in.blue; + cpinfo.dstProfile = 0L; + cpinfo.flags = CanModifyPalette | CanAnimatePalette; + cpinfo.placeWhere = kDeepestColorScreen; + cpinfo.pickerType = 0L; + cpinfo.eventProc = NULL; + cpinfo.colorProc = NULL; + cpinfo.colorProcData = NULL; + + cpinfo.prompt[0] = strlen(title); + strncpy((char*)cpinfo.prompt+1, title, 255); + + if ((PickColor(&cpinfo) == noErr) && cpinfo.newColorChosen) { + sprintf(buff, "#%02x%02x%02x", + cpinfo.theColor.color.rgb.red >> 8, + cpinfo.theColor.color.rgb.green >> 8, + cpinfo.theColor.color.rgb.blue >> 8); + Tcl_SetResult(interp, buff, TCL_VOLATILE); + + in.blue = cpinfo.theColor.color.rgb.red; + in.green = cpinfo.theColor.color.rgb.green; + in.blue = cpinfo.theColor.color.rgb.blue; + } else { + Tcl_ResetResult(interp); + } + } + + if (colorPtr) { + Tk_FreeColor(colorPtr); + } + + return TCL_OK; + + arg_missing: + Tcl_AppendResult(interp, "value for \"", argv[argc-1], "\" missing", + NULL); + return TCL_ERROR; +} + +/* + *---------------------------------------------------------------------- + * + * Tk_GetOpenFileCmd -- + * + * This procedure implements the "open file" dialog box for the + * Mac platform. See the user documentation for details on what + * it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See user documentation. + *---------------------------------------------------------------------- + */ + +int +Tk_GetOpenFileCmd( + ClientData clientData, /* Main window associated with interpreter. */ + Tcl_Interp *interp, /* Current interpreter. */ + int argc, /* Number of arguments. */ + char **argv) /* Argument strings. */ +{ + return GetFileName(clientData, interp, argc, argv, OPEN_FILE); +} + +/* + *---------------------------------------------------------------------- + * + * Tk_GetSaveFileCmd -- + * + * Same as Tk_GetOpenFileCmd but opens a "save file" dialog box + * instead + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See user documentation. + *---------------------------------------------------------------------- + */ + +int +Tk_GetSaveFileCmd( + ClientData clientData, /* Main window associated with interpreter. */ + Tcl_Interp *interp, /* Current interpreter. */ + int argc, /* Number of arguments. */ + char **argv) /* Argument strings. */ +{ + return GetFileName(clientData, interp, argc, argv, SAVE_FILE); +} + +/* + *---------------------------------------------------------------------- + * + * GetFileName -- + * + * Calls the Mac file dialog functions for the user to choose a + * file to or save. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * If the user selects a file, the native pathname of the file + * is returned in interp->result. Otherwise an empty string + * is returned in interp->result. + * + *---------------------------------------------------------------------- + */ + +static int +GetFileName( + ClientData clientData, /* Main window associated with interpreter. */ + Tcl_Interp *interp, /* Current interpreter. */ + int argc, /* Number of arguments. */ + char **argv, /* Argument strings. */ + int isOpen) /* true if we should call GetOpenFileName(), + * false if we should call GetSaveFileName() */ +{ + int code = TCL_OK; + int i; + OpenFileData myData, *myDataPtr; + StandardFileReply reply; + Point mypoint; + Str255 str; + + myDataPtr = &myData; + + if (openFilter == NULL) { + openFilter = NewFileFilterYDProc(FileFilterProc); + openHook = NewDlgHookYDProc(OpenHookProc); + saveHook = NewDlgHookYDProc(OpenHookProc); + } + + /* + * 1. Parse the arguments. + */ + if (ParseFileDlgArgs(interp, myDataPtr, argc, argv, isOpen) + != TCL_OK) { + return TCL_ERROR; + } + + /* + * 2. Set the items in the file types popup. + */ + + /* + * Delete all the entries inside the popup menu, in case there's any + * left overs from previous invocation of this command + */ + + if (myDataPtr->usePopup) { + FileFilter * filterPtr; + + for (i=CountMItems(myDataPtr->menu); i>0; i--) { + /* + * The item indices are one based. Also, if we delete from + * the beginning, the items may be re-numbered. So we + * delete from the end + */ + DeleteMenuItem(myDataPtr->menu, i); + } + + if (myDataPtr->fl.filters) { + for (filterPtr=myDataPtr->fl.filters; filterPtr; + filterPtr=filterPtr->next) { + strncpy((char*)str+1, filterPtr->name, 254); + str[0] = strlen(filterPtr->name); + AppendMenu(myDataPtr->menu, (ConstStr255Param) str); + } + } else { + myDataPtr->usePopup = 0; + } + } + + /* + * 3. Call the toolbox file dialog function. + */ + SetPt(&mypoint, -1, -1); + TkpSetCursor(NULL); + + if (myDataPtr->isOpen) { + if (myDataPtr->usePopup) { + CustomGetFile(openFilter, (short) -1, NULL, &reply, + myDataPtr->dialogId, + mypoint, openHook, NULL, NULL, NULL, (void*)myDataPtr); + } else { + StandardGetFile(NULL, -1, NULL, &reply); + } + } else { + Str255 prompt, def; + + strcpy((char*)prompt+1, "Save as"); + prompt[0] = strlen("Save as"); + if (myDataPtr->initialFile) { + strncpy((char*)def+1, myDataPtr->initialFile, 254); + def[0] = strlen(myDataPtr->initialFile); + } else { + def[0] = 0; + } + if (myDataPtr->usePopup) { + /* + * Currently this never gets called because we don't use + * popup for the save dialog. + */ + CustomPutFile(prompt, def, &reply, myDataPtr->dialogId, mypoint, + saveHook, NULL, NULL, NULL, myDataPtr); + } else { + StandardPutFile(prompt, def, &reply); + } + } + + Tcl_ResetResult(interp); + if (reply.sfGood) { + int length; + Handle pathHandle = NULL; + char * pathName = NULL; + + FSpPathFromLocation(&reply.sfFile, &length, &pathHandle); + + if (pathHandle != NULL) { + HLock(pathHandle); + pathName = (char *) ckalloc((unsigned) (length + 1)); + strcpy(pathName, *pathHandle); + HUnlock(pathHandle); + DisposeHandle(pathHandle); + + /* + * Return the full pathname of the selected file + */ + + Tcl_SetResult(interp, pathName, TCL_DYNAMIC); + } + } + + done: + TkFreeFileFilters(&myDataPtr->fl); + return code; +} + +/* + *---------------------------------------------------------------------- + * + * ParseFileDlgArgs -- + * + * Parses the arguments passed to tk_getOpenFile and tk_getSaveFile. + * + * Results: + * A standard TCL return value. + * + * Side effects: + * The OpenFileData structure is initialized and modified according + * to the arguments. + * + *---------------------------------------------------------------------- + */ + +static int +ParseFileDlgArgs( + Tcl_Interp * interp, /* Current interpreter. */ + OpenFileData * myDataPtr, /* Information about the file dialog */ + int argc, /* Number of arguments */ + char ** argv, /* Argument strings */ + int isOpen) /* TRUE if this is an "open" dialog */ +{ + int i; + + myDataPtr->interp = interp; + myDataPtr->initialFile = NULL; + myDataPtr->curType = 0; + + TkInitFileFilters(&myDataPtr->fl); + + if (isOpen) { + myDataPtr->isOpen = 1; + myDataPtr->usePopup = 1; + myDataPtr->menu = GetMenu(OPEN_MENU); + myDataPtr->dialogId = OPEN_BOX; + myDataPtr->popupId = OPEN_POPUP; + myDataPtr->popupItem = OPEN_POPUP_ITEM; + if (myDataPtr->menu == NULL) { + Debugger(); + } + } else { + myDataPtr->isOpen = 0; + myDataPtr->usePopup = 0; + } + + for (i=1; i<argc; i+=2) { + int v = i+1; + int len = strlen(argv[i]); + + if (strncmp(argv[i], "-defaultextension", len)==0) { + if (v==argc) {goto arg_missing;} + + myDataPtr->defExt = argv[v]; + } + else if (strncmp(argv[i], "-filetypes", len)==0) { + if (v==argc) {goto arg_missing;} + + if (TkGetFileFilters(interp, &myDataPtr->fl,argv[v],0) != TCL_OK) { + return TCL_ERROR; + } + } + else if (strncmp(argv[i], "-initialdir", len)==0) { + FSSpec dirSpec; + char * dirName; + Tcl_DString dstring; + long dirID; + OSErr err; + Boolean isDirectory; + + if (v==argc) {goto arg_missing;} + + if (Tcl_TranslateFileName(interp, argv[v], &dstring) == NULL) { + return TCL_ERROR; + } + dirName = dstring.string; + if (FSpLocationFromPath(strlen(dirName), dirName, &dirSpec) != + noErr) { + Tcl_AppendResult(interp, "bad directory \"", argv[v], + "\"", NULL); + return TCL_ERROR; + } + err = FSpGetDirectoryID(&dirSpec, &dirID, &isDirectory); + if ((err != noErr) || !isDirectory) { + Tcl_AppendResult(interp, "bad directory \"", argv[v], + "\"", NULL); + return TCL_ERROR; + } + /* + * Make sure you negate -dirSpec.vRefNum because the standard file + * package wants it that way ! + */ + LMSetSFSaveDisk(-dirSpec.vRefNum); + LMSetCurDirStore(dirID); + Tcl_DStringFree(&dstring); + } + else if (strncmp(argv[i], "-initialfile", len)==0) { + if (v==argc) {goto arg_missing;} + + myDataPtr->initialFile = argv[v]; + } + else if (strncmp(argv[i], "-parent", len)==0) { + /* + * Ignored on the Mac, but make sure that it's a valid window + * pathname + */ + Tk_Window parent; + + if (v==argc) {goto arg_missing;} + + parent=Tk_NameToWindow(interp, argv[v], Tk_MainWindow(interp)); + if (parent == NULL) { + return TCL_ERROR; + } + } + else if (strncmp(argv[i], "-title", len)==0) { + if (v==argc) {goto arg_missing;} + + /* + * This option is ignored on the Mac because the Mac file + * dialog do not support titles. + */ + } + else { + Tcl_AppendResult(interp, "unknown option \"", + argv[i], "\", must be -defaultextension, ", + "-filetypes, -initialdir, -initialfile, -parent or -title", + NULL); + return TCL_ERROR; + } + } + + return TCL_OK; + + arg_missing: + Tcl_AppendResult(interp, "value for \"", argv[argc-1], "\" missing", + NULL); + return TCL_ERROR; +} + +/* + *---------------------------------------------------------------------- + * + * OpenHookProc -- + * + * Gets called for various events that occur in the file dialog box. + * Initializes the popup menu or rebuild the file list depending on + * the type of the event. + * + * Results: + * A standard result understood by the Mac file dialog event dispatcher. + * + * Side effects: + * The contents in the file dialog may be changed depending on + * the type of the event. + *---------------------------------------------------------------------- + */ + +static pascal short +OpenHookProc( + short item, /* Event description. */ + DialogPtr theDialog, /* The dialog where the event occurs. */ + OpenFileData * myDataPtr) /* Information about the file dialog. */ +{ + short ignore; + Rect rect; + Handle handle; + int newType; + + switch (item) { + case sfHookFirstCall: + if (myDataPtr->usePopup) { + /* + * Set the popup list to display the selected type. + */ + GetDialogItem(theDialog, myDataPtr->popupItem, + &ignore, &handle, &rect); + SetControlValue((ControlRef) handle, myDataPtr->curType + 1); + } + return sfHookNullEvent; + + case OPEN_POPUP_ITEM: + if (myDataPtr->usePopup) { + GetDialogItem(theDialog, myDataPtr->popupItem, + &ignore, &handle, &rect); + newType = GetCtlValue((ControlRef) handle) - 1; + if (myDataPtr->curType != newType) { + if (newType<0 || newType>myDataPtr->fl.numFilters) { + /* + * Sanity check. Looks like the user selected an + * non-existent menu item?? Don't do anything. + */ + } else { + myDataPtr->curType = newType; + } + return sfHookRebuildList; + } + } + break; + } + + return item; +} + +/* + *---------------------------------------------------------------------- + * + * FileFilterProc -- + * + * Filters files according to file types. Get called whenever the + * file list needs to be updated inside the dialog box. + * + * Results: + * Returns MATCHED if the file should be shown in the listbox, returns + * UNMATCHED otherwise. + * + * Side effects: + * If MATCHED is returned, the file is shown in the listbox. + * + *---------------------------------------------------------------------- + */ + +static pascal Boolean +FileFilterProc( + CInfoPBPtr pb, /* Information about the file */ + void *myData) /* Client data for this file dialog */ +{ + int i; + OpenFileData * myDataPtr = (OpenFileData*)myData; + FileFilter * filterPtr; + + if (myDataPtr->fl.numFilters == 0) { + /* + * No types have been specified. List all files by default + */ + return MATCHED; + } + + if (pb->dirInfo.ioFlAttrib & 0x10) { + /* + * This is a directory: always show it + */ + return MATCHED; + } + + if (myDataPtr->usePopup) { + i = myDataPtr->curType; + for (filterPtr=myDataPtr->fl.filters; filterPtr && i>0; i--) { + filterPtr = filterPtr->next; + } + if (filterPtr) { + return MatchOneType(pb, myDataPtr, filterPtr); + } else { + return UNMATCHED; + } + } else { + /* + * We are not using the popup menu. In this case, the file is + * considered matched if it matches any of the file filters. + */ + + for (filterPtr=myDataPtr->fl.filters; filterPtr; + filterPtr=filterPtr->next) { + if (MatchOneType(pb, myDataPtr, filterPtr) == MATCHED) { + return MATCHED; + } + } + return UNMATCHED; + } +} + +/* + *---------------------------------------------------------------------- + * + * MatchOneType -- + * + * Match a file with one file type in the list of file types. + * + * Results: + * Returns MATCHED if the file matches with the file type; returns + * UNMATCHED otherwise. + * + * Side effects: + * None + * + *---------------------------------------------------------------------- + */ + +static Boolean +MatchOneType( + CInfoPBPtr pb, /* Information about the file */ + OpenFileData * myDataPtr, /* Information about this file dialog */ + FileFilter * filterPtr) /* Match the file described by pb against + * this filter */ +{ + FileFilterClause * clausePtr; + + /* + * A file matches with a file type if it matches with at least one + * clause of the type. + * + * If the clause has both glob patterns and ostypes, the file must + * match with at least one pattern AND at least one ostype. + * + * If the clause has glob patterns only, the file must match with at least + * one pattern. + * + * If the clause has mac types only, the file must match with at least + * one mac type. + * + * If the clause has neither glob patterns nor mac types, it's + * considered an error. + */ + + for (clausePtr=filterPtr->clauses; clausePtr; clausePtr=clausePtr->next) { + int macMatched = 0; + int globMatched = 0; + GlobPattern * globPtr; + MacFileType * mfPtr; + + if (clausePtr->patterns == NULL) { + globMatched = 1; + } + if (clausePtr->macTypes == NULL) { + macMatched = 1; + } + + for (globPtr=clausePtr->patterns; globPtr; globPtr=globPtr->next) { + char filename[256]; + int len; + char * p, *q, *ext; + + if (pb->hFileInfo.ioNamePtr == NULL) { + continue; + } + p = (char*)(pb->hFileInfo.ioNamePtr); + len = p[0]; + strncpy(filename, p+1, len); + filename[len] = '\0'; + ext = globPtr->pattern; + + if (ext[0] == '\0') { + /* + * We don't want any extensions: OK if the filename doesn't + * have "." in it + */ + for (q=filename; *q; q++) { + if (*q == '.') { + goto glob_unmatched; + } + } + goto glob_matched; + } + + if (Tcl_StringMatch(filename, ext)) { + goto glob_matched; + } else { + goto glob_unmatched; + } + + glob_unmatched: + continue; + + glob_matched: + globMatched = 1; + break; + } + + for (mfPtr=clausePtr->macTypes; mfPtr; mfPtr=mfPtr->next) { + if (pb->hFileInfo.ioFlFndrInfo.fdType == mfPtr->type) { + macMatched = 1; + break; + } + } + + if (globMatched && macMatched) { + return MATCHED; + } + } + + return UNMATCHED; +} + +/* + *---------------------------------------------------------------------- + * + * Tk_MessageBoxCmd -- + * + * This procedure implements the MessageBox window for the + * Mac platform. See the user documentation for details on what + * it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See user documentation. + * + *---------------------------------------------------------------------- + */ + +int +Tk_MessageBoxCmd( + ClientData clientData, /* Main window associated with interpreter. */ + Tcl_Interp *interp, /* Current interpreter. */ + int argc, /* Number of arguments. */ + char **argv) /* Argument strings. */ +{ + return EvalArgv(interp, "tkMessageBox", argc, argv); +} diff --git a/mac/tkMacDraw.c b/mac/tkMacDraw.c new file mode 100644 index 0000000..9624041 --- /dev/null +++ b/mac/tkMacDraw.c @@ -0,0 +1,1130 @@ +/* + * tkMacDraw.c -- + * + * This file contains functions that preform drawing to + * Xlib windows. Most of the functions simple emulate + * Xlib functions. + * + * Copyright (c) 1995-1997 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) tkMacDraw.c 1.55 97/11/20 18:28:56 + */ + +#include "tkInt.h" +#include "X.h" +#include "Xlib.h" +#include <stdio.h> +#include <tcl.h> + +#include <Windows.h> +#include <Fonts.h> +#include <QDOffscreen.h> +#include "tkMacInt.h" + +#ifndef PI +# define PI 3.14159265358979323846 +#endif + +/* + * Temporary regions that can be reused. + */ +static RgnHandle tmpRgn = NULL; +static RgnHandle tmpRgn2 = NULL; + +static PixPatHandle gPenPat = NULL; + +/* + * Prototypes for functions used only in this file. + */ +static unsigned char InvertByte _ANSI_ARGS_((unsigned char data)); + +/* + *---------------------------------------------------------------------- + * + * XCopyArea -- + * + * Copies data from one drawable to another using block transfer + * routines. + * + * Results: + * None. + * + * Side effects: + * Data is moved from a window or bitmap to a second window or + * bitmap. + * + *---------------------------------------------------------------------- + */ + +void +XCopyArea( + Display* display, /* Display. */ + Drawable src, /* Source drawable. */ + Drawable dest, /* Destination drawable. */ + GC gc, /* GC to use. */ + int src_x, /* X & Y, width & height */ + int src_y, /* define the source rectangle */ + unsigned int width, /* the will be copied. */ + unsigned int height, + int dest_x, /* Dest X & Y on dest rect. */ + int dest_y) +{ + Rect srcRect, destRect; + BitMapPtr srcBit, destBit; + MacDrawable *srcDraw = (MacDrawable *) src; + MacDrawable *destDraw = (MacDrawable *) dest; + GWorldPtr srcPort, destPort; + CGrafPtr saveWorld; + GDHandle saveDevice; + short tmode; + RGBColor origForeColor, origBackColor, whiteColor, blackColor; + + destPort = TkMacGetDrawablePort(dest); + srcPort = TkMacGetDrawablePort(src); + + display->request++; + GetGWorld(&saveWorld, &saveDevice); + SetGWorld(destPort, NULL); + GetForeColor(&origForeColor); + GetBackColor(&origBackColor); + whiteColor.red = 0; + whiteColor.blue = 0; + whiteColor.green = 0; + RGBForeColor(&whiteColor); + blackColor.red = 0xFFFF; + blackColor.blue = 0xFFFF; + blackColor.green = 0xFFFF; + RGBBackColor(&blackColor); + + + TkMacSetUpClippingRgn(dest); + + /* + * We will change the clip rgn in this routine, so we need to + * be able to restore it when we exit. + */ + + if (tmpRgn2 == NULL) { + tmpRgn2 = NewRgn(); + } + GetClip(tmpRgn2); + + if (((TkpClipMask*)gc->clip_mask)->type == TKP_CLIP_REGION) { + RgnHandle clipRgn = (RgnHandle) + ((TkpClipMask*)gc->clip_mask)->value.region; + + int xOffset, yOffset; + + if (tmpRgn == NULL) { + tmpRgn = NewRgn(); + } + + xOffset = destDraw->xOff + gc->clip_x_origin; + yOffset = destDraw->yOff + gc->clip_y_origin; + + OffsetRgn(clipRgn, xOffset, yOffset); + + GetClip(tmpRgn); + SectRgn(tmpRgn, clipRgn, tmpRgn); + + SetClip(tmpRgn); + + OffsetRgn(clipRgn, -xOffset, -yOffset); + } + + srcBit = &((GrafPtr) srcPort)->portBits; + destBit = &((GrafPtr) destPort)->portBits; + SetRect(&srcRect, (short) (srcDraw->xOff + src_x), + (short) (srcDraw->yOff + src_y), + (short) (srcDraw->xOff + src_x + width), + (short) (srcDraw->yOff + src_y + height)); + SetRect(&destRect, (short) (destDraw->xOff + dest_x), + (short) (destDraw->yOff + dest_y), + (short) (destDraw->xOff + dest_x + width), + (short) (destDraw->yOff + dest_y + height)); + tmode = srcCopy; + + CopyBits(srcBit, destBit, &srcRect, &destRect, tmode, NULL); + RGBForeColor(&origForeColor); + RGBBackColor(&origBackColor); + SetClip(tmpRgn2); + SetGWorld(saveWorld, saveDevice); +} + +/* + *---------------------------------------------------------------------- + * + * XCopyPlane -- + * + * Copies a bitmap from a source drawable to a destination + * drawable. The plane argument specifies which bit plane of + * the source contains the bitmap. Note that this implementation + * ignores the gc->function. + * + * Results: + * None. + * + * Side effects: + * Changes the destination drawable. + * + *---------------------------------------------------------------------- + */ + +void +XCopyPlane( + Display* display, /* Display. */ + Drawable src, /* Source drawable. */ + Drawable dest, /* Destination drawable. */ + GC gc, /* The GC to use. */ + int src_x, /* X, Y, width & height */ + int src_y, /* define the source rect. */ + unsigned int width, + unsigned int height, + int dest_x, /* X & Y on dest where we will copy. */ + int dest_y, + unsigned long plane) /* Which plane to copy. */ +{ + Rect srcRect, destRect; + BitMapPtr srcBit, destBit, maskBit; + MacDrawable *srcDraw = (MacDrawable *) src; + MacDrawable *destDraw = (MacDrawable *) dest; + GWorldPtr srcPort, destPort, maskPort; + CGrafPtr saveWorld; + GDHandle saveDevice; + RGBColor macColor; + TkpClipMask *clipPtr = (TkpClipMask*)gc->clip_mask; + short tmode; + + destPort = TkMacGetDrawablePort(dest); + srcPort = TkMacGetDrawablePort(src); + + display->request++; + GetGWorld(&saveWorld, &saveDevice); + SetGWorld(destPort, NULL); + + TkMacSetUpClippingRgn(dest); + + srcBit = &((GrafPtr) srcPort)->portBits; + destBit = &((GrafPtr) destPort)->portBits; + SetRect(&srcRect, (short) (srcDraw->xOff + src_x), + (short) (srcDraw->yOff + src_y), + (short) (srcDraw->xOff + src_x + width), + (short) (srcDraw->yOff + src_y + height)); + SetRect(&destRect, (short) (destDraw->xOff + dest_x), + (short) (destDraw->yOff + dest_y), + (short) (destDraw->xOff + dest_x + width), + (short) (destDraw->yOff + dest_y + height)); + tmode = srcOr; + tmode = srcCopy + transparent; + + if (TkSetMacColor(gc->foreground, &macColor) == true) { + RGBForeColor(&macColor); + } + + if (clipPtr == NULL || clipPtr->type == TKP_CLIP_REGION) { + + /* + * Case 1: opaque bitmaps. + */ + + TkSetMacColor(gc->background, &macColor); + RGBBackColor(&macColor); + tmode = srcCopy; + CopyBits(srcBit, destBit, &srcRect, &destRect, tmode, NULL); + } else if (clipPtr->type == TKP_CLIP_PIXMAP) { + if (clipPtr->value.pixmap == src) { + /* + * Case 2: transparent bitmaps. If it's color we ignore + * the forecolor. + */ + if ((**(srcPort->portPixMap)).pixelSize == 1) { + tmode = srcOr; + } else { + tmode = transparent; + } + CopyBits(srcBit, destBit, &srcRect, &destRect, tmode, NULL); + } else { + /* + * Case 3: two arbitrary bitmaps. + */ + tmode = srcCopy; + maskPort = TkMacGetDrawablePort(clipPtr->value.pixmap); + maskBit = &((GrafPtr) maskPort)->portBits; + CopyDeepMask(srcBit, maskBit, destBit, &srcRect, &srcRect, &destRect, tmode, NULL); + } + } + + SetGWorld(saveWorld, saveDevice); +} + +/* + *---------------------------------------------------------------------- + * + * TkPutImage -- + * + * Copies a subimage from an in-memory image to a rectangle of + * of the specified drawable. + * + * Results: + * None. + * + * Side effects: + * Draws the image on the specified drawable. + * + *---------------------------------------------------------------------- + */ + +void +TkPutImage( + unsigned long *colors, /* Unused on Macintosh. */ + int ncolors, /* Unused on Macintosh. */ + Display* display, /* Display. */ + Drawable d, /* Drawable to place image on. */ + GC gc, /* GC to use. */ + XImage* image, /* Image to place. */ + int src_x, /* Source X & Y. */ + int src_y, + int dest_x, /* Destination X & Y. */ + int dest_y, + unsigned int width, /* Same width & height for both */ + unsigned int height) /* distination and source. */ +{ + MacDrawable *destDraw = (MacDrawable *) d; + CGrafPtr saveWorld; + GDHandle saveDevice; + GWorldPtr destPort; + int i, j; + BitMap bitmap; + char *newData = NULL; + Rect destRect, srcRect; + + destPort = TkMacGetDrawablePort(d); + SetRect(&destRect, dest_x, dest_y, dest_x + width, dest_y + height); + SetRect(&srcRect, src_x, src_y, src_x + width, src_y + height); + + display->request++; + GetGWorld(&saveWorld, &saveDevice); + SetGWorld(destPort, NULL); + + TkMacSetUpClippingRgn(d); + + if (image->depth == 1) { + + /* + * This code assumes a pixel depth of 1 + */ + + bitmap.bounds.top = bitmap.bounds.left = 0; + bitmap.bounds.right = (short) image->width; + bitmap.bounds.bottom = (short) image->height; + if ((image->bytes_per_line % 2) == 1) { + char *newPtr, *oldPtr; + newData = (char *) ckalloc(image->height * + (image->bytes_per_line + 1)); + newPtr = newData; + oldPtr = image->data; + for (i = 0; i < image->height; i++) { + for (j = 0; j < image->bytes_per_line; j++) { + *newPtr = InvertByte((unsigned char) *oldPtr); + newPtr++, oldPtr++; + } + *newPtr = 0; + newPtr++; + } + bitmap.baseAddr = newData; + bitmap.rowBytes = image->bytes_per_line + 1; + } else { + newData = (char *) ckalloc(image->height * image->bytes_per_line); + for (i = 0; i < image->height * image->bytes_per_line; i++) { + newData[i] = InvertByte((unsigned char) image->data[i]); + } + bitmap.baseAddr = newData; + bitmap.rowBytes = image->bytes_per_line; + } + + CopyBits(&bitmap, &((GrafPtr) destPort)->portBits, + &srcRect, &destRect, srcCopy, NULL); + + } else { + /* Color image */ + PixMap pixmap; + + pixmap.bounds.left = 0; + pixmap.bounds.top = 0; + pixmap.bounds.right = (short) image->width; + pixmap.bounds.bottom = (short) image->height; + pixmap.pixelType = RGBDirect; + pixmap.pmVersion = 4; /* 32bit clean */ + pixmap.packType = 0; + pixmap.packSize = 0; + pixmap.hRes = 0x00480000; + pixmap.vRes = 0x00480000; + pixmap.pixelSize = 32; + pixmap.cmpCount = 3; + pixmap.cmpSize = 8; + pixmap.planeBytes = 0; + pixmap.pmTable = NULL; + pixmap.pmReserved = 0; + pixmap.baseAddr = image->data; + pixmap.rowBytes = image->bytes_per_line | 0x8000; + + CopyBits((BitMap *) &pixmap, &((GrafPtr) destPort)->portBits, + &srcRect, &destRect, srcCopy, NULL); + } + + if (newData != NULL) { + ckfree(newData); + } + SetGWorld(saveWorld, saveDevice); +} + +/* + *---------------------------------------------------------------------- + * + * XFillRectangles -- + * + * Fill multiple rectangular areas in the given drawable. + * + * Results: + * None. + * + * Side effects: + * Draws onto the specified drawable. + * + *---------------------------------------------------------------------- + */ + +void +XFillRectangles( + Display* display, /* Display. */ + Drawable d, /* Draw on this. */ + GC gc, /* Use this GC. */ + XRectangle *rectangles, /* Rectangle array. */ + int n_rectangels) /* Number of rectangles. */ +{ + MacDrawable *macWin = (MacDrawable *) d; + CGrafPtr saveWorld; + GDHandle saveDevice; + GWorldPtr destPort; + Rect theRect; + int i; + + destPort = TkMacGetDrawablePort(d); + + display->request++; + GetGWorld(&saveWorld, &saveDevice); + SetGWorld(destPort, NULL); + + TkMacSetUpClippingRgn(d); + + TkMacSetUpGraphicsPort(gc); + + for (i=0; i<n_rectangels; i++) { + theRect.left = (short) (macWin->xOff + rectangles[i].x); + theRect.top = (short) (macWin->yOff + rectangles[i].y); + theRect.right = (short) (theRect.left + rectangles[i].width); + theRect.bottom = (short) (theRect.top + rectangles[i].height); + FillCRect(&theRect, gPenPat); + } + + SetGWorld(saveWorld, saveDevice); +} + +/* + *---------------------------------------------------------------------- + * + * XDrawLines -- + * + * Draw connected lines. + * + * Results: + * None. + * + * Side effects: + * Renders a series of connected lines. + * + *---------------------------------------------------------------------- + */ + +void +XDrawLines( + Display* display, /* Display. */ + Drawable d, /* Draw on this. */ + GC gc, /* Use this GC. */ + XPoint* points, /* Array of points. */ + int npoints, /* Number of points. */ + int mode) /* Line drawing mode. */ +{ + MacDrawable *macWin = (MacDrawable *) d; + CGrafPtr saveWorld; + GWorldPtr destPort; + GDHandle saveDevice; + int i; + + destPort = TkMacGetDrawablePort(d); + + display->request++; + if (npoints < 2) { + return; /* TODO: generate BadValue error. */ + } + GetGWorld(&saveWorld, &saveDevice); + SetGWorld(destPort, NULL); + + TkMacSetUpClippingRgn(d); + + TkMacSetUpGraphicsPort(gc); + + ShowPen(); + + PenPixPat(gPenPat); + MoveTo((short) (macWin->xOff + points[0].x), + (short) (macWin->yOff + points[0].y)); + for (i = 1; i < npoints; i++) { + if (mode == CoordModeOrigin) { + LineTo((short) (macWin->xOff + points[i].x), + (short) (macWin->yOff + points[i].y)); + } else { + Line((short) (macWin->xOff + points[i].x), + (short) (macWin->yOff + points[i].y)); + } + } + + SetGWorld(saveWorld, saveDevice); +} + +/* + *---------------------------------------------------------------------- + * + * XDrawSegments -- + * + * Draw unconnected lines. + * + * Results: + * None. + * + * Side effects: + * Renders a series of connected lines. + * + *---------------------------------------------------------------------- + */ + +void XDrawSegments( + Display *display, + Drawable d, + GC gc, + XSegment *segments, + int nsegments) +{ + MacDrawable *macWin = (MacDrawable *) d; + CGrafPtr saveWorld; + GWorldPtr destPort; + GDHandle saveDevice; + int i; + + destPort = TkMacGetDrawablePort(d); + + display->request++; + + GetGWorld(&saveWorld, &saveDevice); + SetGWorld(destPort, NULL); + + TkMacSetUpClippingRgn(d); + + TkMacSetUpGraphicsPort(gc); + + ShowPen(); + + PenPixPat(gPenPat); + for (i = 0; i < nsegments; i++) { + MoveTo((short) (macWin->xOff + segments[i].x1), + (short) (macWin->yOff + segments[i].y1)); + LineTo((short) (macWin->xOff + segments[i].x2), + (short) (macWin->yOff + segments[i].y2)); + } + + SetGWorld(saveWorld, saveDevice); +} + +/* + *---------------------------------------------------------------------- + * + * XFillPolygon -- + * + * Draws a filled polygon. + * + * Results: + * None. + * + * Side effects: + * Draws a filled polygon on the specified drawable. + * + *---------------------------------------------------------------------- + */ + +void +XFillPolygon( + Display* display, /* Display. */ + Drawable d, /* Draw on this. */ + GC gc, /* Use this GC. */ + XPoint* points, /* Array of points. */ + int npoints, /* Number of points. */ + int shape, /* Shape to draw. */ + int mode) /* Drawing mode. */ +{ + MacDrawable *macWin = (MacDrawable *) d; + PolyHandle polygon; + CGrafPtr saveWorld; + GDHandle saveDevice; + GWorldPtr destPort; + int i; + + destPort = TkMacGetDrawablePort(d); + + display->request++; + GetGWorld(&saveWorld, &saveDevice); + SetGWorld(destPort, NULL); + + TkMacSetUpClippingRgn(d); + + TkMacSetUpGraphicsPort(gc); + + PenNormal(); + polygon = OpenPoly(); + + MoveTo((short) (macWin->xOff + points[0].x), + (short) (macWin->yOff + points[0].y)); + for (i = 1; i < npoints; i++) { + if (mode == CoordModePrevious) { + Line((short) (macWin->xOff + points[i].x), + (short) (macWin->yOff + points[i].y)); + } else { + LineTo((short) (macWin->xOff + points[i].x), + (short) (macWin->yOff + points[i].y)); + } + } + + ClosePoly(); + + FillCPoly(polygon, gPenPat); + + KillPoly(polygon); + SetGWorld(saveWorld, saveDevice); +} + +/* + *---------------------------------------------------------------------- + * + * XDrawRectangle -- + * + * Draws a rectangle. + * + * Results: + * None. + * + * Side effects: + * Draws a rectangle on the specified drawable. + * + *---------------------------------------------------------------------- + */ + +void +XDrawRectangle( + Display* display, /* Display. */ + Drawable d, /* Draw on this. */ + GC gc, /* Use this GC. */ + int x, /* Upper left corner. */ + int y, + unsigned int width, /* Width & height of rect. */ + unsigned int height) +{ + MacDrawable *macWin = (MacDrawable *) d; + Rect theRect; + CGrafPtr saveWorld; + GDHandle saveDevice; + GWorldPtr destPort; + + destPort = TkMacGetDrawablePort(d); + + display->request++; + GetGWorld(&saveWorld, &saveDevice); + SetGWorld(destPort, NULL); + + TkMacSetUpClippingRgn(d); + + TkMacSetUpGraphicsPort(gc); + + theRect.left = (short) (macWin->xOff + x); + theRect.top = (short) (macWin->yOff + y); + theRect.right = (short) (theRect.left + width); + theRect.bottom = (short) (theRect.top + height); + + ShowPen(); + PenPixPat(gPenPat); + FrameRect(&theRect); + + SetGWorld(saveWorld, saveDevice); +} + +/* + *---------------------------------------------------------------------- + * + * XDrawArc -- + * + * Draw an arc. + * + * Results: + * None. + * + * Side effects: + * Draws an arc on the specified drawable. + * + *---------------------------------------------------------------------- + */ + +void +XDrawArc( + Display* display, /* Display. */ + Drawable d, /* Draw on this. */ + GC gc, /* Use this GC. */ + int x, /* Upper left of */ + int y, /* bounding rect. */ + unsigned int width, /* Width & height. */ + unsigned int height, + int angle1, /* Staring angle of arc. */ + int angle2) /* Ending angle of arc. */ +{ + MacDrawable *macWin = (MacDrawable *) d; + Rect theRect; + short start, extent; + CGrafPtr saveWorld; + GDHandle saveDevice; + GWorldPtr destPort; + + destPort = TkMacGetDrawablePort(d); + + display->request++; + GetGWorld(&saveWorld, &saveDevice); + SetGWorld(destPort, NULL); + + TkMacSetUpClippingRgn(d); + + TkMacSetUpGraphicsPort(gc); + + theRect.left = (short) (macWin->xOff + x); + theRect.top = (short) (macWin->yOff + y); + theRect.right = (short) (theRect.left + width); + theRect.bottom = (short) (theRect.top + height); + start = (short) (90 - (angle1 / 64)); + extent = (short) (-(angle2 / 64)); + + ShowPen(); + PenPixPat(gPenPat); + FrameArc(&theRect, start, extent); + + SetGWorld(saveWorld, saveDevice); +} + +/* + *---------------------------------------------------------------------- + * + * XFillArc -- + * + * Draw a filled arc. + * + * Results: + * None. + * + * Side effects: + * Draws a filled arc on the specified drawable. + * + *---------------------------------------------------------------------- + */ + +void +XFillArc( + Display* display, /* Display. */ + Drawable d, /* Draw on this. */ + GC gc, /* Use this GC. */ + int x, /* Upper left of */ + int y, /* bounding rect. */ + unsigned int width, /* Width & height. */ + unsigned int height, + int angle1, /* Staring angle of arc. */ + int angle2) /* Ending angle of arc. */ +{ + MacDrawable *macWin = (MacDrawable *) d; + Rect theRect; + short start, extent; + PolyHandle polygon; + double sin1, cos1, sin2, cos2, angle; + double boxWidth, boxHeight; + double vertex[2], center1[2], center2[2]; + CGrafPtr saveWorld; + GDHandle saveDevice; + GWorldPtr destPort; + + destPort = TkMacGetDrawablePort(d); + + display->request++; + GetGWorld(&saveWorld, &saveDevice); + SetGWorld(destPort, NULL); + + TkMacSetUpClippingRgn(d); + + TkMacSetUpGraphicsPort(gc); + + theRect.left = (short) (macWin->xOff + x); + theRect.top = (short) (macWin->yOff + y); + theRect.right = (short) (theRect.left + width); + theRect.bottom = (short) (theRect.top + height); + start = (short) (90 - (angle1 / 64)); + extent = (short) (- (angle2 / 64)); + + if (gc->arc_mode == ArcChord) { + boxWidth = theRect.right - theRect.left; + boxHeight = theRect.bottom - theRect.top; + angle = -(angle1/64.0)*PI/180.0; + sin1 = sin(angle); + cos1 = cos(angle); + angle -= (angle2/64.0)*PI/180.0; + sin2 = sin(angle); + cos2 = cos(angle); + vertex[0] = (theRect.left + theRect.right)/2.0; + vertex[1] = (theRect.top + theRect.bottom)/2.0; + center1[0] = vertex[0] + cos1*boxWidth/2.0; + center1[1] = vertex[1] + sin1*boxHeight/2.0; + center2[0] = vertex[0] + cos2*boxWidth/2.0; + center2[1] = vertex[1] + sin2*boxHeight/2.0; + + polygon = OpenPoly(); + MoveTo((short) ((theRect.left + theRect.right)/2), + (short) ((theRect.top + theRect.bottom)/2)); + + LineTo((short) (center1[0] + 0.5), (short) (center1[1] + 0.5)); + LineTo((short) (center2[0] + 0.5), (short) (center2[1] + 0.5)); + ClosePoly(); + + ShowPen(); + FillCArc(&theRect, start, extent, gPenPat); + FillCPoly(polygon, gPenPat); + + KillPoly(polygon); + } else { + ShowPen(); + FillCArc(&theRect, start, extent, gPenPat); + } + + SetGWorld(saveWorld, saveDevice); +} + +/* + *---------------------------------------------------------------------- + * + * TkScrollWindow -- + * + * Scroll a rectangle of the specified window and accumulate + * a damage region. + * + * Results: + * Returns 0 if the scroll genereated no additional damage. + * Otherwise, sets the region that needs to be repainted after + * scrolling and returns 1. + * + * Side effects: + * Scrolls the bits in the window. + * + *---------------------------------------------------------------------- + */ + +int +TkScrollWindow( + Tk_Window tkwin, /* The window to be scrolled. */ + GC gc, /* GC for window to be scrolled. */ + int x, /* Position rectangle to be scrolled. */ + int y, + int width, + int height, + int dx, /* Distance rectangle should be moved. */ + int dy, + TkRegion damageRgn) /* Region to accumulate damage in. */ +{ + MacDrawable *destDraw = (MacDrawable *) Tk_WindowId(tkwin); + RgnHandle rgn = (RgnHandle) damageRgn; + CGrafPtr saveWorld; + GDHandle saveDevice; + GWorldPtr destPort; + Rect srcRect, scrollRect; + + destPort = TkMacGetDrawablePort(Tk_WindowId(tkwin)); + + GetGWorld(&saveWorld, &saveDevice); + SetGWorld(destPort, NULL); + + TkMacSetUpClippingRgn(Tk_WindowId(tkwin)); + + /* + * Due to the implementation below the behavior may be differnt + * than X in certain cases that should never occur in Tk. The + * scrollRect is the source rect extended by the offset (the union + * of the source rect and the offset rect). Everything + * in the extended scrollRect is scrolled. On X, it's possible + * to "skip" over an area if the offset makes the source and + * destination rects disjoint and non-aligned. + */ + + SetRect(&srcRect, (short) (destDraw->xOff + x), + (short) (destDraw->yOff + y), + (short) (destDraw->xOff + x + width), + (short) (destDraw->yOff + y + height)); + scrollRect = srcRect; + if (dx < 0) { + scrollRect.left += dx; + } else { + scrollRect.right += dx; + } + if (dy < 0) { + scrollRect.top += dy; + } else { + scrollRect.bottom += dy; + } + + /* + * Adjust clip region so that we don't copy any windows + * that may overlap us. + */ + RectRgn(rgn, &srcRect); + DiffRgn(rgn, destPort->visRgn, rgn); + OffsetRgn(rgn, dx, dy); + DiffRgn(destPort->clipRgn, rgn, destPort->clipRgn); + SetEmptyRgn(rgn); + + /* + * When a menu is up, the Mac does not expect drawing to occur and + * does not clip out the menu. We have to do it ourselves. This + * is pretty gross. + */ + + if (tkUseMenuCascadeRgn == 1) { + Point scratch = {0, 0}; + MacDrawable *macDraw = (MacDrawable *) Tk_WindowId(tkwin); + + LocalToGlobal(&scratch); + CopyRgn(tkMenuCascadeRgn, rgn); + OffsetRgn(rgn, -scratch.h, -scratch.v); + DiffRgn(destPort->clipRgn, rgn, destPort->clipRgn); + SetEmptyRgn(rgn); + macDraw->toplevel->flags |= TK_DRAWN_UNDER_MENU; + } + + ScrollRect(&scrollRect, dx, dy, rgn); + + SetGWorld(saveWorld, saveDevice); + + /* + * Fortunantly, the region returned by ScrollRect is symanticlly + * the same as what we need to return in this function. If the + * region is empty we return zero to denote that no damage was + * created. + */ + if (EmptyRgn(rgn)) { + return 0; + } else { + return 1; + } +} + +/* + *---------------------------------------------------------------------- + * + * TkMacSetUpGraphicsPort -- + * + * Set up the graphics port from the given GC. + * + * Results: + * None. + * + * Side effects: + * The current port is adjusted. + * + *---------------------------------------------------------------------- + */ + +void +TkMacSetUpGraphicsPort( + GC gc) /* GC to apply to current port. */ +{ + RGBColor macColor; + + if (gPenPat == NULL) { + gPenPat = NewPixPat(); + } + + if (TkSetMacColor(gc->foreground, &macColor) == true) { + /* TODO: cache RGBPats for preformace - measure gains... */ + MakeRGBPat(gPenPat, &macColor); + } + + PenNormal(); + if(gc->function == GXxor) { + PenMode(patXor); + } + if (gc->line_width > 1) { + PenSize(gc->line_width, gc->line_width); + } +} + +/* + *---------------------------------------------------------------------- + * + * TkMacSetUpClippingRgn -- + * + * Set up the clipping region so that drawing only occurs on the + * specified X subwindow. + * + * Results: + * None. + * + * Side effects: + * The clipping region in the current port is changed. + * + *---------------------------------------------------------------------- + */ + +void +TkMacSetUpClippingRgn( + Drawable drawable) /* Drawable to update. */ +{ + MacDrawable *macDraw = (MacDrawable *) drawable; + + if (macDraw->winPtr != NULL) { + if (macDraw->flags & TK_CLIP_INVALID) { + TkMacUpdateClipRgn(macDraw->winPtr); + } + + /* + * When a menu is up, the Mac does not expect drawing to occur and + * does not clip out the menu. We have to do it ourselves. This + * is pretty gross. + */ + + if (macDraw->clipRgn != NULL) { + if (tkUseMenuCascadeRgn == 1) { + Point scratch = {0, 0}; + GDHandle saveDevice; + GWorldPtr saveWorld; + + GetGWorld(&saveWorld, &saveDevice); + SetGWorld(TkMacGetDrawablePort(drawable), NULL); + LocalToGlobal(&scratch); + SetGWorld(saveWorld, saveDevice); + if (tmpRgn == NULL) { + tmpRgn = NewRgn(); + } + CopyRgn(tkMenuCascadeRgn, tmpRgn); + OffsetRgn(tmpRgn, -scratch.h, -scratch.v); + DiffRgn(macDraw->clipRgn, tmpRgn, tmpRgn); + SetClip(tmpRgn); + macDraw->toplevel->flags |= TK_DRAWN_UNDER_MENU; + } else { + SetClip(macDraw->clipRgn); + } + } + } +} + +/* + *---------------------------------------------------------------------- + * + * TkMacMakeStippleMap -- + * + * Given a drawable and a stipple pattern this function draws the + * pattern repeatedly over the drawable. The drawable can then + * be used as a mask for bit-bliting a stipple pattern over an + * object. + * + * Results: + * A BitMap data structure. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +BitMapPtr +TkMacMakeStippleMap( + Drawable drawable, /* Window to apply stipple. */ + Drawable stipple) /* The stipple pattern. */ +{ + MacDrawable *destDraw = (MacDrawable *) drawable; + GWorldPtr destPort; + BitMapPtr bitmapPtr; + int width, height, stippleHeight, stippleWidth; + int i, j; + char * data; + Rect bounds; + + destPort = TkMacGetDrawablePort(drawable); + width = destPort->portRect.right - destPort->portRect.left; + height = destPort->portRect.bottom - destPort->portRect.top; + + bitmapPtr = (BitMap *) ckalloc(sizeof(BitMap)); + data = (char *) ckalloc(height * ((width / 8) + 1)); + bitmapPtr->bounds.top = bitmapPtr->bounds.left = 0; + bitmapPtr->bounds.right = (short) width; + bitmapPtr->bounds.bottom = (short) height; + bitmapPtr->baseAddr = data; + bitmapPtr->rowBytes = (width / 8) + 1; + + destPort = TkMacGetDrawablePort(stipple); + stippleWidth = destPort->portRect.right - destPort->portRect.left; + stippleHeight = destPort->portRect.bottom - destPort->portRect.top; + + for (i = 0; i < height; i += stippleHeight) { + for (j = 0; j < width; j += stippleWidth) { + bounds.left = j; + bounds.top = i; + bounds.right = j + stippleWidth; + bounds.bottom = i + stippleHeight; + + CopyBits(&((GrafPtr) destPort)->portBits, bitmapPtr, + &((GrafPtr) destPort)->portRect, &bounds, srcCopy, NULL); + } + } + return bitmapPtr; +} + +/* + *---------------------------------------------------------------------- + * + * InvertByte -- + * + * This function reverses the bits in the passed in Byte of data. + * + * Results: + * The incoming byte in reverse bit order. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static unsigned char +InvertByte( + unsigned char data) /* Byte of data. */ +{ + unsigned char i; + unsigned char mask = 1, result = 0; + + for (i = (1 << 7); i != 0; i /= 2) { + if (data & mask) { + result |= i; + } + mask = mask << 1; + } + return result; +} diff --git a/mac/tkMacEmbed.c b/mac/tkMacEmbed.c new file mode 100644 index 0000000..7a73b54 --- /dev/null +++ b/mac/tkMacEmbed.c @@ -0,0 +1,1116 @@ +/* + * tkMacEmbed.c -- + * + * This file contains platform-specific procedures for theMac to provide + * basic operations needed for application embedding (where one + * application can use as its main window an internal window from + * some other application). + * Currently only Toplevel embedding within the same Tk application is + * allowed on the Macintosh. + * + * Copyright (c) 1996-97 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) tkMacEmbed.c 1.6 97/10/31 17:20:22 + */ + +#include "tkInt.h" +#include "tkPort.h" +#include "X.h" +#include "Xlib.h" +#include <stdio.h> + +#include <Windows.h> +#include <QDOffscreen.h> +#include "tkMacInt.h" + +/* + * One of the following structures exists for each container in this + * application. It keeps track of the container window and its + * associated embedded window. + */ + +typedef struct Container { + Window parent; /* The Mac Drawable for the parent of + * the pair (the container). */ + TkWindow *parentPtr; /* Tk's information about the container, + * or NULL if the container isn't + * in this process. */ + Window embedded; /* The MacDrawable for the embedded + * window. Starts off as None, but + * gets filled in when the window is + * eventually created. */ + TkWindow *embeddedPtr; /* Tk's information about the embedded + * window, or NULL if the + * embedded application isn't in + * this process. */ + struct Container *nextPtr; /* Next in list of all containers in + * this process. */ +} Container; + +static Container *firstContainerPtr = NULL; + /* First in list of all containers + * managed by this process. */ + +/* + * Prototypes for static procedures defined in this file: + */ + +static void ContainerEventProc _ANSI_ARGS_(( + ClientData clientData, XEvent *eventPtr)); +static void EmbeddedEventProc _ANSI_ARGS_(( + ClientData clientData, XEvent *eventPtr)); +static void EmbedActivateProc _ANSI_ARGS_((ClientData clientData, + XEvent *eventPtr)); +static void EmbedFocusProc _ANSI_ARGS_((ClientData clientData, + XEvent *eventPtr)); +static void EmbedGeometryRequest _ANSI_ARGS_(( + Container * containerPtr, int width, int height)); +static void EmbedSendConfigure _ANSI_ARGS_(( + Container *containerPtr)); +static void EmbedStructureProc _ANSI_ARGS_((ClientData clientData, + XEvent *eventPtr)); +static void EmbedWindowDeleted _ANSI_ARGS_((TkWindow *winPtr)); + +/* WARNING - HACK */ +static void GenerateFocusEvents _ANSI_ARGS_((TkWindow *sourcePtr, + TkWindow *destPtr)); + + +/* + *---------------------------------------------------------------------- + * + * TkpMakeWindow -- + * + * Creates an X Window (Mac subwindow). + * + * Results: + * The window id is returned. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +Window +TkpMakeWindow( + TkWindow *winPtr, + Window parent) +{ + MacDrawable *macWin; + XEvent event; + + /* + * If this window is marked as embedded then + * the window structure should have already been + * created in the TkpUseWindow function. + */ + + if (Tk_IsEmbedded(winPtr)) { + return (Window) winPtr->privatePtr; + } + + /* + * Allocate sub window + */ + + macWin = (MacDrawable *) ckalloc(sizeof(MacDrawable)); + if (macWin == NULL) { + winPtr->privatePtr = NULL; + return None; + } + macWin->winPtr = winPtr; + winPtr->privatePtr = macWin; + macWin->clipRgn = NewRgn(); + macWin->aboveClipRgn = NewRgn(); + macWin->referenceCount = 0; + macWin->flags = TK_CLIP_INVALID; + + if (Tk_IsTopLevel(macWin->winPtr)) { + + /* + *This will be set when we are mapped. + */ + + macWin->portPtr = (GWorldPtr) NULL; + macWin->toplevel = macWin; + macWin->xOff = 0; + macWin->yOff = 0; + } else { + macWin->portPtr = NULL; + macWin->xOff = winPtr->parentPtr->privatePtr->xOff + + winPtr->parentPtr->changes.border_width + + winPtr->changes.x; + macWin->yOff = winPtr->parentPtr->privatePtr->yOff + + winPtr->parentPtr->changes.border_width + + winPtr->changes.y; + macWin->toplevel = winPtr->parentPtr->privatePtr->toplevel; + } + + macWin->toplevel->referenceCount++; + + /* + * TODO: need general solution for visibility events. + */ + event.xany.serial = Tk_Display(winPtr)->request; + event.xany.send_event = False; + event.xany.display = Tk_Display(winPtr); + + event.xvisibility.type = VisibilityNotify; + event.xvisibility.window = (Window) macWin;; + event.xvisibility.state = VisibilityUnobscured; + Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); + + return (Window) macWin; +} + +/* + *---------------------------------------------------------------------- + * + * TkpUseWindow -- + * + * This procedure causes a Tk window to use a given X window as + * its parent window, rather than the root window for the screen. + * It is invoked by an embedded application to specify the window + * in which it is embedded. + * + * Results: + * The return value is normally TCL_OK. If an error occurs (such + * as string not being a valid window spec), then the return value + * is TCL_ERROR and an error message is left in interp->result if + * interp is non-NULL. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +TkpUseWindow( + Tcl_Interp *interp, /* If not NULL, used for error reporting + * if string is bogus. */ + Tk_Window tkwin, /* Tk window that does not yet have an + * associated X window. */ + char *string) /* String identifying an X window to use + * for tkwin; must be an integer value. */ +{ + TkWindow *winPtr = (TkWindow *) tkwin; + MacDrawable *parent, *macWin; + Container *containerPtr; + XEvent event; + int result; + + if (winPtr->window != None) { + panic("TkpUseWindow: X window already assigned"); + } + + /* + * Decode the container pointer, and look for it among the + *list of available containers. + * + * N.B. For now, we are limiting the containers to be in the same Tk + * application as tkwin, since otherwise they would not be in our list + * of containers. + * + */ + + if (Tcl_GetInt(interp, string, &result) != TCL_OK) { + return TCL_ERROR; + } + + parent = (MacDrawable *) result; + + /* + * Save information about the container and the embedded window + * in a Container structure. Currently, there must already be an existing + * Container structure, since we only allow the case where both container + * and embedded app. are in the same process. + */ + + for (containerPtr = firstContainerPtr; containerPtr != NULL; + containerPtr = containerPtr->nextPtr) { + if (containerPtr->parent == (Window) parent) { + winPtr->flags |= TK_BOTH_HALVES; + containerPtr->parentPtr->flags |= TK_BOTH_HALVES; + break; + } + } + + /* + * We should not get to this code until we start to allow + * embedding in other applications. + */ + + if (containerPtr == NULL) { + Tcl_AppendResult(interp, "The window ID ", string, + " does not correspond to a valid Tk Window.", + (char *) NULL); + return TCL_ERROR; + } + + /* + * Make the embedded window. + */ + + macWin = (MacDrawable *) ckalloc(sizeof(MacDrawable)); + if (macWin == NULL) { + winPtr->privatePtr = NULL; + return TCL_ERROR; + } + + macWin->winPtr = winPtr; + winPtr->privatePtr = macWin; + macWin->clipRgn = NewRgn(); + macWin->aboveClipRgn = NewRgn(); + macWin->referenceCount = 0; + macWin->flags = TK_CLIP_INVALID; + + winPtr->flags |= TK_EMBEDDED; + + /* + * Make a copy of the TK_EMBEDDED flag, since sometimes + * we need this to get the port after the TkWindow structure + * has been freed. + */ + + macWin->flags |= TK_EMBEDDED; + + /* + * The portPtr will be NULL for an embedded window. + * Always use TkMacGetDrawablePort to get the portPtr. + * It will correctly find the container's port. + */ + + macWin->portPtr = (GWorldPtr) NULL; + + macWin->toplevel = macWin; + macWin->xOff = parent->winPtr->privatePtr->xOff + + parent->winPtr->changes.border_width + + winPtr->changes.x; + macWin->yOff = parent->winPtr->privatePtr->yOff + + parent->winPtr->changes.border_width + + winPtr->changes.y; + + macWin->toplevel->referenceCount++; + + /* + * Finish filling up the container structure with the embedded window's + * information. + */ + + containerPtr->embedded = (Window) macWin; + containerPtr->embeddedPtr = macWin->winPtr; + + /* + * TODO: need general solution for visibility events. + */ + + event.xany.serial = Tk_Display(winPtr)->request; + event.xany.send_event = False; + event.xany.display = Tk_Display(winPtr); + + event.xvisibility.type = VisibilityNotify; + event.xvisibility.window = (Window) macWin;; + event.xvisibility.state = VisibilityUnobscured; + Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); + + /* + * Create an event handler to clean up the Container structure when + * tkwin is eventually deleted. + */ + + Tk_CreateEventHandler(tkwin, StructureNotifyMask, EmbeddedEventProc, + (ClientData) winPtr); + + + + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * TkpMakeContainer -- + * + * This procedure is called to indicate that a particular window + * will be a container for an embedded application. This changes + * certain aspects of the window's behavior, such as whether it + * will receive events anymore. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +TkpMakeContainer( + Tk_Window tkwin) /* Token for a window that is about to + * become a container. */ +{ + TkWindow *winPtr = (TkWindow *) tkwin; + Container *containerPtr; + + /* + * Register the window as a container so that, for example, we can + * make sure the argument to -use is valid. + */ + + + Tk_MakeWindowExist(tkwin); + containerPtr = (Container *) ckalloc(sizeof(Container)); + containerPtr->parent = Tk_WindowId(tkwin); + containerPtr->parentPtr = winPtr; + containerPtr->embedded = None; + containerPtr->embeddedPtr = NULL; + containerPtr->nextPtr = firstContainerPtr; + firstContainerPtr = containerPtr; + winPtr->flags |= TK_CONTAINER; + + /* + * Request SubstructureNotify events so that we can find out when + * the embedded application creates its window or attempts to + * resize it. Also watch Configure events on the container so that + * we can resize the child to match. Also, pass activate events from + * the container down to the embedded toplevel. + */ + + Tk_CreateEventHandler(tkwin, + SubstructureNotifyMask|SubstructureRedirectMask, + ContainerEventProc, (ClientData) winPtr); + Tk_CreateEventHandler(tkwin, StructureNotifyMask, EmbedStructureProc, + (ClientData) containerPtr); + Tk_CreateEventHandler(tkwin, ActivateMask, EmbedActivateProc, + (ClientData) containerPtr); + Tk_CreateEventHandler(tkwin, FocusChangeMask, EmbedFocusProc, + (ClientData) containerPtr); + +} + +/* + *---------------------------------------------------------------------- + * + * TkMacContainerId -- + * + * Given an embedded window, this procedure returns the MacDrawable + * identifier for the associated container window. + * + * Results: + * The return value is the MacDrawable for winPtr's + * container window. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +MacDrawable * +TkMacContainerId(winPtr) + TkWindow *winPtr; /* Tk's structure for an embedded window. */ +{ + Container *containerPtr; + + for (containerPtr = firstContainerPtr; containerPtr != NULL; + containerPtr = containerPtr->nextPtr) { + if (containerPtr->embeddedPtr == winPtr) { + return (MacDrawable *) containerPtr->parent; + } + } + panic("TkMacContainerId couldn't find window"); + return None; +} + +/* + *---------------------------------------------------------------------- + * + * TkMacGetHostToplevel -- + * + * Given the TkWindow, return the MacDrawable for the outermost + * toplevel containing it. This will be a real Macintosh window. + * + * Results: + * Returns a MacDrawable corresponding to a Macintosh Toplevel + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +MacDrawable * +TkMacGetHostToplevel( + TkWindow *winPtr) /* Tk's structure for a window. */ +{ + TkWindow *contWinPtr, *topWinPtr; + + topWinPtr = winPtr->privatePtr->toplevel->winPtr; + if (!Tk_IsEmbedded(topWinPtr)) { + return winPtr->privatePtr->toplevel; + } else { + contWinPtr = TkpGetOtherWindow(topWinPtr); + + /* + * NOTE: Here we should handle out of process embedding. + */ + + if (contWinPtr != NULL) { + return TkMacGetHostToplevel(contWinPtr); + } else { + return None; + } + } +} + +/* + *---------------------------------------------------------------------- + * + * TkpClaimFocus -- + * + * This procedure is invoked when someone asks for the input focus + * to be put on a window in an embedded application, but the + * application doesn't currently have the focus. It requests the + * input focus from the container application. + * + * Results: + * None. + * + * Side effects: + * The input focus may change. + * + *---------------------------------------------------------------------- + */ + +void +TkpClaimFocus( + TkWindow *topLevelPtr, /* Top-level window containing desired + * focus window; should be embedded. */ + int force) /* One means that the container should + * claim the focus if it doesn't + * currently have it. */ +{ + XEvent event; + Container *containerPtr; + + if (!(topLevelPtr->flags & TK_EMBEDDED)) { + return; + } + + for (containerPtr = firstContainerPtr; + containerPtr->embeddedPtr != topLevelPtr; + containerPtr = containerPtr->nextPtr) { + /* Empty loop body. */ + } + + + event.xfocus.type = FocusIn; + event.xfocus.serial = LastKnownRequestProcessed(topLevelPtr->display); + event.xfocus.send_event = 1; + event.xfocus.display = topLevelPtr->display; + event.xfocus.window = containerPtr->parent; + event.xfocus.mode = EMBEDDED_APP_WANTS_FOCUS; + event.xfocus.detail = force; + Tk_QueueWindowEvent(&event,TCL_QUEUE_TAIL); +} + +/* + *---------------------------------------------------------------------- + * + * TkpTestembedCmd -- + * + * This procedure implements the "testembed" command. It returns + * some or all of the information in the list pointed to by + * firstContainerPtr. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +TkpTestembedCmd( + ClientData clientData, /* Main window for application. */ + Tcl_Interp *interp, /* Current interpreter. */ + int argc, /* Number of arguments. */ + char **argv) /* Argument strings. */ +{ + int all; + Container *containerPtr; + Tcl_DString dString; + char buffer[50]; + + if ((argc > 1) && (strcmp(argv[1], "all") == 0)) { + all = 1; + } else { + all = 0; + } + Tcl_DStringInit(&dString); + for (containerPtr = firstContainerPtr; containerPtr != NULL; + containerPtr = containerPtr->nextPtr) { + Tcl_DStringStartSublist(&dString); + if (containerPtr->parent == None) { + Tcl_DStringAppendElement(&dString, ""); + } else { + if (all) { + sprintf(buffer, "0x%x", (int) containerPtr->parent); + Tcl_DStringAppendElement(&dString, buffer); + } else { + Tcl_DStringAppendElement(&dString, "XXX"); + } + } + if (containerPtr->parentPtr == NULL) { + Tcl_DStringAppendElement(&dString, ""); + } else { + Tcl_DStringAppendElement(&dString, + containerPtr->parentPtr->pathName); + } + if (containerPtr->embedded == None) { + Tcl_DStringAppendElement(&dString, ""); + } else { + if (all) { + sprintf(buffer, "0x%x", (int) containerPtr->embedded); + Tcl_DStringAppendElement(&dString, buffer); + } else { + Tcl_DStringAppendElement(&dString, "XXX"); + } + } + if (containerPtr->embeddedPtr == NULL) { + Tcl_DStringAppendElement(&dString, ""); + } else { + Tcl_DStringAppendElement(&dString, + containerPtr->embeddedPtr->pathName); + } + Tcl_DStringEndSublist(&dString); + } + Tcl_DStringResult(interp, &dString); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * TkpRedirectKeyEvent -- + * + * This procedure is invoked when a key press or release event + * arrives for an application that does not believe it owns the + * input focus. This can happen because of embedding; for example, + * X can send an event to an embedded application when the real + * focus window is in the container application and is an ancestor + * of the container. This procedure's job is to forward the event + * back to the application where it really belongs. + * + * Results: + * None. + * + * Side effects: + * The event may get sent to a different application. + * + *---------------------------------------------------------------------- + */ + +void +TkpRedirectKeyEvent( + TkWindow *winPtr, /* Window to which the event was originally + * reported. */ + XEvent *eventPtr) /* X event to redirect (should be KeyPress + * or KeyRelease). */ +{ +} + +/* + *---------------------------------------------------------------------- + * + * TkpGetOtherWindow -- + * + * If both the container and embedded window are in the same + * process, this procedure will return either one, given the other. + * + * Results: + * If winPtr is a container, the return value is the token for the + * embedded window, and vice versa. If the "other" window isn't in + * this process, NULL is returned. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +TkWindow * +TkpGetOtherWindow( + TkWindow *winPtr) /* Tk's structure for a container or + * embedded window. */ +{ + Container *containerPtr; + + /* + * TkpGetOtherWindow returns NULL if both windows are not + * in the same process... + */ + + if (!(winPtr->flags & TK_BOTH_HALVES)) { + return NULL; + } + + for (containerPtr = firstContainerPtr; containerPtr != NULL; + containerPtr = containerPtr->nextPtr) { + if (containerPtr->embeddedPtr == winPtr) { + return containerPtr->parentPtr; + } else if (containerPtr->parentPtr == winPtr) { + return containerPtr->embeddedPtr; + } + } + return NULL; +} +/* + *---------------------------------------------------------------------- + * + * EmbeddedEventProc -- + * + * This procedure is invoked by the Tk event dispatcher when various + * useful events are received for a window that is embedded in + * another application. + * + * Results: + * None. + * + * Side effects: + * Our internal state gets cleaned up when an embedded window is + * destroyed. + * + *---------------------------------------------------------------------- + */ + +static void +EmbeddedEventProc(clientData, eventPtr) + ClientData clientData; /* Token for container window. */ + XEvent *eventPtr; /* ResizeRequest event. */ +{ + TkWindow *winPtr = (TkWindow *) clientData; + + if (eventPtr->type == DestroyNotify) { + EmbedWindowDeleted(winPtr); + } +} + +/* + *---------------------------------------------------------------------- + * + * ContainerEventProc -- + * + * This procedure is invoked by the Tk event dispatcher when various + * useful events are received for the children of a container + * window. It forwards relevant information, such as geometry + * requests, from the events into the container's application. + * + * NOTE: on the Mac, only the DestroyNotify branch is ever taken. + * We don't synthesize the other events. + * + * Results: + * None. + * + * Side effects: + * Depends on the event. For example, when ConfigureRequest events + * occur, geometry information gets set for the container window. + * + *---------------------------------------------------------------------- + */ + +static void +ContainerEventProc(clientData, eventPtr) + ClientData clientData; /* Token for container window. */ + XEvent *eventPtr; /* ResizeRequest event. */ +{ + TkWindow *winPtr = (TkWindow *) clientData; + Container *containerPtr; + Tk_ErrorHandler errHandler; + + /* + * Ignore any X protocol errors that happen in this procedure + * (almost any operation could fail, for example, if the embedded + * application has deleted its window). + */ + + errHandler = Tk_CreateErrorHandler(eventPtr->xfocus.display, -1, + -1, -1, (Tk_ErrorProc *) NULL, (ClientData) NULL); + + /* + * Find the Container structure associated with the parent window. + */ + + for (containerPtr = firstContainerPtr; + containerPtr->parent != eventPtr->xmaprequest.parent; + containerPtr = containerPtr->nextPtr) { + if (containerPtr == NULL) { + panic("ContainerEventProc couldn't find Container record"); + } + } + + if (eventPtr->type == CreateNotify) { + /* + * A new child window has been created in the container. Record + * its id in the Container structure (if more than one child is + * created, just remember the last one and ignore the earlier + * ones). + */ + + containerPtr->embedded = eventPtr->xcreatewindow.window; + } else if (eventPtr->type == ConfigureRequest) { + if ((eventPtr->xconfigurerequest.x != 0) + || (eventPtr->xconfigurerequest.y != 0)) { + /* + * The embedded application is trying to move itself, which + * isn't legal. At this point, the window hasn't actually + * moved, but we need to send it a ConfigureNotify event to + * let it know that its request has been denied. If the + * embedded application was also trying to resize itself, a + * ConfigureNotify will be sent by the geometry management + * code below, so we don't need to do anything. Otherwise, + * generate a synthetic event. + */ + + if ((eventPtr->xconfigurerequest.width == winPtr->changes.width) + && (eventPtr->xconfigurerequest.height + == winPtr->changes.height)) { + EmbedSendConfigure(containerPtr); + } + } + EmbedGeometryRequest(containerPtr, + eventPtr->xconfigurerequest.width, + eventPtr->xconfigurerequest.height); + } else if (eventPtr->type == MapRequest) { + /* + * The embedded application's map request was ignored and simply + * passed on to us, so we have to map the window for it to appear + * on the screen. + */ + + XMapWindow(eventPtr->xmaprequest.display, + eventPtr->xmaprequest.window); + } else if (eventPtr->type == DestroyNotify) { + /* + * The embedded application is gone. Destroy the container window. + */ + + Tk_DestroyWindow((Tk_Window) winPtr); + } + Tk_DeleteErrorHandler(errHandler); +} + +/* + *---------------------------------------------------------------------- + * + * EmbedStructureProc -- + * + * This procedure is invoked by the Tk event dispatcher when + * a container window owned by this application gets resized + * (and also at several other times that we don't care about). + * This procedure reflects the size change in the embedded + * window that corresponds to the container. + * + * Results: + * None. + * + * Side effects: + * The embedded window gets resized to match the container. + * + *---------------------------------------------------------------------- + */ + +static void +EmbedStructureProc(clientData, eventPtr) + ClientData clientData; /* Token for container window. */ + XEvent *eventPtr; /* ResizeRequest event. */ +{ + Container *containerPtr = (Container *) clientData; + Tk_ErrorHandler errHandler; + + if (eventPtr->type == ConfigureNotify) { + if (containerPtr->embedded != None) { + /* + * Ignore errors, since the embedded application could have + * deleted its window. + */ + + errHandler = Tk_CreateErrorHandler(eventPtr->xfocus.display, -1, + -1, -1, (Tk_ErrorProc *) NULL, (ClientData) NULL); + Tk_MoveResizeWindow((Tk_Window) containerPtr->embeddedPtr, 0, 0, + (unsigned int) Tk_Width( + (Tk_Window) containerPtr->parentPtr), + (unsigned int) Tk_Height( + (Tk_Window) containerPtr->parentPtr)); + Tk_DeleteErrorHandler(errHandler); + } + } else if (eventPtr->type == DestroyNotify) { + EmbedWindowDeleted(containerPtr->parentPtr); + } +} + +/* + *---------------------------------------------------------------------- + * + * EmbedActivateProc -- + * + * This procedure is invoked by the Tk event dispatcher when + * Activate and Deactivate events occur for a container window owned + * by this application. It is responsible for forwarding an activate + * event down into the embedded toplevel. + * + * Results: + * None. + * + * Side effects: + * The X focus may change. + * + *---------------------------------------------------------------------- + */ + +static void +EmbedActivateProc(clientData, eventPtr) + ClientData clientData; /* Token for container window. */ + XEvent *eventPtr; /* ResizeRequest event. */ +{ + Container *containerPtr = (Container *) clientData; + + if (containerPtr->embeddedPtr != NULL) { + + if (eventPtr->type == ActivateNotify) { + TkGenerateActivateEvents(containerPtr->embeddedPtr, 1); + } else if (eventPtr->type == DeactivateNotify) { + TkGenerateActivateEvents(containerPtr->embeddedPtr, 0); + } + } +} + +/* + *---------------------------------------------------------------------- + * + * EmbedFocusProc -- + * + * This procedure is invoked by the Tk event dispatcher when + * FocusIn and FocusOut events occur for a container window owned + * by this application. It is responsible for moving the focus + * back and forth between a container application and an embedded + * application. + * + * Results: + * None. + * + * Side effects: + * The X focus may change. + * + *---------------------------------------------------------------------- + */ + +static void +EmbedFocusProc(clientData, eventPtr) + ClientData clientData; /* Token for container window. */ + XEvent *eventPtr; /* ResizeRequest event. */ +{ + Container *containerPtr = (Container *) clientData; + Display *display; + XEvent event; + + if (containerPtr->embeddedPtr != NULL) { + display = Tk_Display(containerPtr->parentPtr); + event.xfocus.serial = LastKnownRequestProcessed(display); + event.xfocus.send_event = false; + event.xfocus.display = display; + event.xfocus.mode = NotifyNormal; + event.xfocus.window = containerPtr->embedded; + + if (eventPtr->type == FocusIn) { + /* + * The focus just arrived at the container. Change the X focus + * to move it to the embedded application, if there is one. + * Ignore X errors that occur during this operation (it's + * possible that the new focus window isn't mapped). + */ + + event.xfocus.detail = NotifyNonlinear; + event.xfocus.type = FocusIn; + + } else if (eventPtr->type == FocusOut) { + /* When the container gets a FocusOut event, it has to tell the embedded app + * that it has lost the focus. + */ + + event.xfocus.type = FocusOut; + event.xfocus.detail = NotifyNonlinear; + } + + Tk_QueueWindowEvent(&event, TCL_QUEUE_MARK); + } +} + +/* + *---------------------------------------------------------------------- + * + * EmbedGeometryRequest -- + * + * This procedure is invoked when an embedded application requests + * a particular size. It processes the request (which may or may + * not actually honor the request) and reflects the results back + * to the embedded application. + * + * NOTE: On the Mac, this is a stub, since we don't synthesize + * ConfigureRequest events. + * + * Results: + * None. + * + * Side effects: + * If we deny the child's size change request, a Configure event + * is synthesized to let the child know how big it ought to be. + * Events get processed while we're waiting for the geometry + * managers to do their thing. + * + *---------------------------------------------------------------------- + */ + +static void +EmbedGeometryRequest(containerPtr, width, height) + Container *containerPtr; /* Information about the embedding. */ + int width, height; /* Size that the child has requested. */ +{ + TkWindow *winPtr = containerPtr->parentPtr; + + /* + * Forward the requested size into our geometry management hierarchy + * via the container window. We need to send a Configure event back + * to the embedded application if we decide not to honor its + * request; to make this happen, process all idle event handlers + * synchronously here (so that the geometry managers have had a + * chance to do whatever they want to do), and if the window's size + * didn't change then generate a configure event. + */ + + Tk_GeometryRequest((Tk_Window) winPtr, width, height); + while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)) { + /* Empty loop body. */ + } + if ((winPtr->changes.width != width) + || (winPtr->changes.height != height)) { + EmbedSendConfigure(containerPtr); + } +} + +/* + *---------------------------------------------------------------------- + * + * EmbedSendConfigure -- + * + * This is currently a stub. It is called to notify an + * embedded application of its current size and location. This + * procedure is called when the embedded application made a + * geometry request that we did not grant, so that the embedded + * application knows that its geometry didn't change after all. + * It is a response to ConfigureRequest events, which we do not + * currently synthesize on the Mac + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static void +EmbedSendConfigure(containerPtr) + Container *containerPtr; /* Information about the embedding. */ +{ +} + +/* + *---------------------------------------------------------------------- + * + * EmbedWindowDeleted -- + * + * This procedure is invoked when a window involved in embedding + * (as either the container or the embedded application) is + * destroyed. It cleans up the Container structure for the window. + * + * Results: + * None. + * + * Side effects: + * A Container structure may be freed. + * + *---------------------------------------------------------------------- + */ + +static void +EmbedWindowDeleted(winPtr) + TkWindow *winPtr; /* Tk's information about window that + * was deleted. */ +{ + Container *containerPtr, *prevPtr; + + /* + * Find the Container structure for this window. Delete the + * information about the embedded application and free the container's + * record. + */ + + prevPtr = NULL; + containerPtr = firstContainerPtr; + while (1) { + if (containerPtr->embeddedPtr == winPtr) { + + /* + * We also have to destroy our parent, to clean up the container. + * Fabricate an event to do this. + */ + + if (containerPtr->parentPtr != NULL && + containerPtr->parentPtr->flags & TK_BOTH_HALVES) { + XEvent event; + + event.xany.serial = + Tk_Display(containerPtr->parentPtr)->request; + event.xany.send_event = False; + event.xany.display = Tk_Display(containerPtr->parentPtr); + + event.xany.type = DestroyNotify; + event.xany.window = containerPtr->parent; + event.xdestroywindow.event = containerPtr->parent; + Tk_QueueWindowEvent(&event, TCL_QUEUE_HEAD); + + } + + containerPtr->embedded = None; + containerPtr->embeddedPtr = NULL; + + break; + } + if (containerPtr->parentPtr == winPtr) { + containerPtr->parentPtr = NULL; + break; + } + prevPtr = containerPtr; + containerPtr = containerPtr->nextPtr; + } + if ((containerPtr->embeddedPtr == NULL) + && (containerPtr->parentPtr == NULL)) { + if (prevPtr == NULL) { + firstContainerPtr = containerPtr->nextPtr; + } else { + prevPtr->nextPtr = containerPtr->nextPtr; + } + ckfree((char *) containerPtr); + } +} + diff --git a/mac/tkMacFont.c b/mac/tkMacFont.c new file mode 100644 index 0000000..8619880 --- /dev/null +++ b/mac/tkMacFont.c @@ -0,0 +1,678 @@ +/* + * tkMacFont.c -- + * + * Contains the Macintosh implementation of the platform-independant + * font package interface. + * + * Copyright (c) 1990-1994 The Regents of the University of California. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS:@(#) tkMacFont.c 1.52 97/11/20 18:29:51 + */ + +#include <Windows.h> +#include <Strings.h> +#include <Fonts.h> +#include <Resources.h> + +#include "tkMacInt.h" +#include "tkFont.h" +#include "tkPort.h" + +/* + * The following structure represents the Macintosh's' implementation of a + * font. + */ + +typedef struct MacFont { + TkFont font; /* Stuff used by generic font package. Must + * be first in structure. */ + short family; + short size; + short style; +} MacFont; + +static GWorldPtr gWorld = NULL; + +static TkFont * AllocMacFont _ANSI_ARGS_((TkFont *tkfont, + Tk_Window tkwin, int family, int size, int style)); + + +/* + *--------------------------------------------------------------------------- + * + * TkpGetNativeFont -- + * + * Map a platform-specific native font name to a TkFont. + * + * Results: + * The return value is a pointer to a TkFont that represents the + * native font. If a native font by the given name could not be + * found, the return value is NULL. + * + * Every call to this procedure returns a new TkFont structure, + * even if the name has already been seen before. The caller should + * call TkpDeleteFont() when the font is no longer needed. + * + * The caller is responsible for initializing the memory associated + * with the generic TkFont when this function returns and releasing + * the contents of the generics TkFont before calling TkpDeleteFont(). + * + * Side effects: + * None. + * + *--------------------------------------------------------------------------- + */ + +TkFont * +TkpGetNativeFont( + Tk_Window tkwin, /* For display where font will be used. */ + CONST char *name) /* Platform-specific font name. */ +{ + short family; + + if (strcmp(name, "system") == 0) { + family = GetSysFont(); + } else if (strcmp(name, "application") == 0) { + family = GetAppFont(); + } else { + return NULL; + } + + return AllocMacFont(NULL, tkwin, family, 0, 0); +} + +/* + *--------------------------------------------------------------------------- + * + * TkpGetFontFromAttributes -- + * + * Given a desired set of attributes for a font, find a font with + * the closest matching attributes. + * + * Results: + * The return value is a pointer to a TkFont that represents the + * font with the desired attributes. If a font with the desired + * attributes could not be constructed, some other font will be + * substituted automatically. + * + * Every call to this procedure returns a new TkFont structure, + * even if the specified attributes have already been seen before. + * The caller should call TkpDeleteFont() to free the platform- + * specific data when the font is no longer needed. + * + * The caller is responsible for initializing the memory associated + * with the generic TkFont when this function returns and releasing + * the contents of the generic TkFont before calling TkpDeleteFont(). + * + * Side effects: + * None. + * + *--------------------------------------------------------------------------- + */ +TkFont * +TkpGetFontFromAttributes( + TkFont *tkFontPtr, /* If non-NULL, store the information in + * this existing TkFont structure, rather than + * allocating a new structure to hold the + * font; the existing contents of the font + * will be released. If NULL, a new TkFont + * structure is allocated. */ + Tk_Window tkwin, /* For display where font will be used. */ + CONST TkFontAttributes *faPtr) /* Set of attributes to match. */ +{ + char buf[257]; + size_t len; + short family, size, style; + + if (faPtr->family == NULL) { + family = 0; + } else { + CONST char *familyName; + + familyName = faPtr->family; + if (strcasecmp(familyName, "Times New Roman") == 0) { + familyName = "Times"; + } else if (strcasecmp(familyName, "Courier New") == 0) { + familyName = "Courier"; + } else if (strcasecmp(familyName, "Arial") == 0) { + familyName = "Helvetica"; + } + + len = strlen(familyName); + if (len > 255) { + len = 255; + } + buf[0] = (char) len; + memcpy(buf + 1, familyName, len); + buf[len + 1] = '\0'; + GetFNum((StringPtr) buf, &family); + } + + size = faPtr->pointsize; + if (size <= 0) { + size = GetDefFontSize(); + } + + style = 0; + if (faPtr->weight != TK_FW_NORMAL) { + style |= bold; + } + if (faPtr->slant != TK_FS_ROMAN) { + style |= italic; + } + if (faPtr->underline) { + style |= underline; + } + + return AllocMacFont(tkFontPtr, tkwin, family, size, style); +} + +/* + *--------------------------------------------------------------------------- + * + * TkpDeleteFont -- + * + * Called to release a font allocated by TkpGetNativeFont() or + * TkpGetFontFromAttributes(). The caller should have already + * released the fields of the TkFont that are used exclusively by + * the generic TkFont code. + * + * Results: + * None. + * + * Side effects: + * TkFont is deallocated. + * + *--------------------------------------------------------------------------- + */ + +void +TkpDeleteFont( + TkFont *tkFontPtr) /* Token of font to be deleted. */ +{ + ckfree((char *) tkFontPtr); +} + +/* + *--------------------------------------------------------------------------- + * + * TkpGetFontFamilies -- + * + * Return information about the font families that are available + * on the display of the given window. + * + * Results: + * interp->result is modified to hold a list of all the available + * font families. + * + * Side effects: + * None. + * + *--------------------------------------------------------------------------- + */ + +void +TkpGetFontFamilies( + Tcl_Interp *interp, /* Interp to hold result. */ + Tk_Window tkwin) /* For display to query. */ +{ + MenuHandle fontMenu; + int i; + char itemText[257]; + + fontMenu = NewMenu(1, "\px"); + AddResMenu(fontMenu, 'FONT'); + + for (i = 1; i < CountMItems(fontMenu); i++) { + /* + * Each item is a pascal string. Convert it to C and append. + */ + GetMenuItemText(fontMenu, i, (unsigned char *) itemText); + itemText[itemText[0] + 1] = '\0'; + Tcl_AppendElement(interp, &itemText[1]); + } + DisposeMenu(fontMenu); +} + + +/* + *--------------------------------------------------------------------------- + * + * TkMacIsCharacterMissing -- + * + * Given a tkFont and a character determines whether the character has + * a glyph defined in the font or not. Note that this is potentially + * not compatible with Mac OS 8 as it looks at the font handle + * structure directly. Looks into the character array of the font + * handle to determine whether the glyph is defined or not. + * + * Results: + * Returns a 1 if the character is missing, a 0 if it is not. + * + * Side effects: + * None. + * + *--------------------------------------------------------------------------- + */ + +int +TkMacIsCharacterMissing( + Tk_Font tkfont, /* The font we are looking in. */ + unsigned int searchChar) /* The character we are looking for. */ +{ + MacFont *fontPtr = (MacFont *) tkfont; + FMInput fm; + FontRec **fontRecHandle; + + fm.family = fontPtr->family; + fm.size = fontPtr->size; + fm.face = fontPtr->style; + fm.needBits = 0; + fm.device = 0; + fm.numer.h = fm.numer.v = fm.denom.h = fm.denom.v = 1; + + /* + * This element of the FMOutput structure was changed between the 2.0 & 3.0 + * versions of the Universal Headers. + */ + +#if !defined(UNIVERSAL_INTERFACES_VERSION) || (UNIVERSAL_INTERFACES_VERSION < 0x0300) + fontRecHandle = (FontRec **) FMSwapFont(&fm)->fontResult; +#else + fontRecHandle = (FontRec **) FMSwapFont(&fm)->fontHandle; +#endif + return *(short *) ((long) &(*fontRecHandle)->owTLoc + + ((long)((*fontRecHandle)->owTLoc + searchChar + - (*fontRecHandle)->firstChar) * sizeof(short))) == -1; +} + + +/* + *--------------------------------------------------------------------------- + * + * Tk_MeasureChars -- + * + * Determine the number of characters from the string that will fit + * in the given horizontal span. The measurement is done under the + * assumption that Tk_DrawChars() will be used to actually display + * the characters. + * + * Results: + * The return value is the number of characters from source that + * fit into the span that extends from 0 to maxLength. *lengthPtr is + * filled with the x-coordinate of the right edge of the last + * character that did fit. + * + * Side effects: + * None. + * + *--------------------------------------------------------------------------- + */ + +int +Tk_MeasureChars( + Tk_Font tkfont, /* Font in which characters will be drawn. */ + CONST char *source, /* Characters to be displayed. Need not be + * '\0' terminated. */ + int numChars, /* Maximum number of characters to consider + * from source string. */ + int maxLength, /* If > 0, maxLength specifies the longest + * permissible line length; don't consider any + * character that would cross this + * x-position. If <= 0, then line length is + * unbounded and the flags argument is + * ignored. */ + int flags, /* Various flag bits OR-ed together: + * TK_PARTIAL_OK means include the last char + * which only partially fit on this line. + * TK_WHOLE_WORDS means stop on a word + * boundary, if possible. + * TK_AT_LEAST_ONE means return at least one + * character even if no characters fit. */ + int *lengthPtr) /* Filled with x-location just after the + * terminating character. */ +{ + short staticWidths[128]; + short *widths; + CONST char *p, *term; + int curX, termX, curIdx, sawNonSpace; + MacFont *fontPtr; + CGrafPtr saveWorld; + GDHandle saveDevice; + + if (numChars == 0) { + *lengthPtr = 0; + return 0; + } + + if (gWorld == NULL) { + Rect rect = {0, 0, 1, 1}; + + if (NewGWorld(&gWorld, 0, &rect, NULL, NULL, 0) != noErr) { + panic("NewGWorld failed in Tk_MeasureChars"); + } + } + GetGWorld(&saveWorld, &saveDevice); + SetGWorld(gWorld, NULL); + + fontPtr = (MacFont *) tkfont; + TextFont(fontPtr->family); + TextSize(fontPtr->size); + TextFace(fontPtr->style); + + if (maxLength <= 0) { + *lengthPtr = TextWidth(source, 0, numChars); + SetGWorld(saveWorld, saveDevice); + return numChars; + } + + if (numChars > maxLength) { + /* + * Assume that all chars are at least 1 pixel wide, so there's no + * need to measure more characters than there are pixels. This + * assumption could be refined to an iterative approach that would + * use that as a starting point and try more chars if necessary (if + * there actually were some zero-width chars). + */ + + numChars = maxLength; + } + if (numChars > SHRT_MAX) { + /* + * If they are trying to measure more than 32767 chars at one time, + * it would require several separate measurements. + */ + + numChars = SHRT_MAX; + } + + widths = staticWidths; + if (numChars >= sizeof(staticWidths) / sizeof(staticWidths[0])) { + widths = (short *) ckalloc((numChars + 1) * sizeof(short)); + } + + MeasureText((short) numChars, source, widths); + + if (widths[numChars] <= maxLength) { + curX = widths[numChars]; + curIdx = numChars; + } else { + p = term = source; + curX = termX = 0; + + sawNonSpace = !isspace(UCHAR(*p)); + for (curIdx = 1; ; curIdx++) { + if (isspace(UCHAR(*p))) { + if (sawNonSpace) { + term = p; + termX = widths[curIdx - 1]; + sawNonSpace = 0; + } + } else { + sawNonSpace = 1; + } + if (widths[curIdx] > maxLength) { + curIdx--; + curX = widths[curIdx]; + break; + } + p++; + } + if (flags & TK_PARTIAL_OK) { + curIdx++; + curX = widths[curIdx]; + } + if ((curIdx == 0) && (flags & TK_AT_LEAST_ONE)) { + /* + * The space was too small to hold even one character. Since at + * least one character must always fit on a line, return the width + * of the first character. + */ + + curX = TextWidth(source, 0, 1); + curIdx = 1; + } else if (flags & TK_WHOLE_WORDS) { + /* + * Break at last word that fits on the line. + */ + + if ((flags & TK_AT_LEAST_ONE) && (term == source)) { + /* + * The space was too small to hold an entire word. This + * is the only word on the line, so just return the part of th + * word that fit. + */ + + ; + } else { + curIdx = term - source; + curX = termX; + } + } + } + + if (widths != staticWidths) { + ckfree((char *) widths); + } + + *lengthPtr = curX; + + SetGWorld(saveWorld, saveDevice); + + return curIdx; +} + +/* + *--------------------------------------------------------------------------- + * + * Tk_DrawChars -- + * + * Draw a string of characters on the screen. + * + * Results: + * None. + * + * Side effects: + * Information gets drawn on the screen. + * + *--------------------------------------------------------------------------- + */ + +void +Tk_DrawChars( + Display *display, /* Display on which to draw. */ + Drawable drawable, /* Window or pixmap in which to draw. */ + GC gc, /* Graphics context for drawing characters. */ + Tk_Font tkfont, /* Font in which characters will be drawn; + * must be the same as font used in GC. */ + CONST char *source, /* Characters to be displayed. Need not be + * '\0' terminated. All Tk meta-characters + * (tabs, control characters, and newlines) + * should be stripped out of the string that + * is passed to this function. If they are + * not stripped out, they will be displayed as + * regular printing characters. */ + int numChars, /* Number of characters in string. */ + int x, int y) /* Coordinates at which to place origin of + * string when drawing. */ +{ + MacFont *fontPtr; + MacDrawable *macWin; + RGBColor macColor, origColor; + GWorldPtr destPort; + CGrafPtr saveWorld; + GDHandle saveDevice; + short txFont, txFace, txSize; + BitMapPtr stippleMap; + + fontPtr = (MacFont *) tkfont; + macWin = (MacDrawable *) drawable; + + destPort = TkMacGetDrawablePort(drawable); + GetGWorld(&saveWorld, &saveDevice); + SetGWorld(destPort, NULL); + + TkMacSetUpClippingRgn(drawable); + TkMacSetUpGraphicsPort(gc); + + txFont = tcl_macQdPtr->thePort->txFont; + txFace = tcl_macQdPtr->thePort->txFace; + txSize = tcl_macQdPtr->thePort->txSize; + GetForeColor(&origColor); + + if ((gc->fill_style == FillStippled + || gc->fill_style == FillOpaqueStippled) + && gc->stipple != None) { + Pixmap pixmap; + GWorldPtr bufferPort; + + stippleMap = TkMacMakeStippleMap(drawable, gc->stipple); + + pixmap = Tk_GetPixmap(display, drawable, + stippleMap->bounds.right, stippleMap->bounds.bottom, 0); + + bufferPort = TkMacGetDrawablePort(pixmap); + SetGWorld(bufferPort, NULL); + + TextFont(fontPtr->family); + TextSize(fontPtr->size); + TextFace(fontPtr->style); + + if (TkSetMacColor(gc->foreground, &macColor) == true) { + RGBForeColor(&macColor); + } + + ShowPen(); + MoveTo((short) 0, (short) 0); + FillRect(&stippleMap->bounds, &tcl_macQdPtr->white); + MoveTo((short) x, (short) y); + DrawText(source, 0, (short) numChars); + + SetGWorld(destPort, NULL); + CopyDeepMask(&((GrafPtr) bufferPort)->portBits, stippleMap, + &((GrafPtr) destPort)->portBits, &stippleMap->bounds, + &stippleMap->bounds, &((GrafPtr) destPort)->portRect, + srcOr, NULL); + + /* TODO: this doesn't work quite right - it does a blend. you can't + * draw white text when you have a stipple. + */ + + Tk_FreePixmap(display, pixmap); + ckfree(stippleMap->baseAddr); + ckfree((char *)stippleMap); + } else { + TextFont(fontPtr->family); + TextSize(fontPtr->size); + TextFace(fontPtr->style); + + if (TkSetMacColor(gc->foreground, &macColor) == true) { + RGBForeColor(&macColor); + } + + ShowPen(); + MoveTo((short) (macWin->xOff + x), (short) (macWin->yOff + y)); + DrawText(source, 0, (short) numChars); + } + + TextFont(txFont); + TextSize(txSize); + TextFace(txFace); + RGBForeColor(&origColor); + SetGWorld(saveWorld, saveDevice); +} + +/* + *--------------------------------------------------------------------------- + * + * AllocMacFont -- + * + * Helper for TkpGetNativeFont() and TkpGetFontFromAttributes(). + * Allocates and intializes the memory for a new TkFont that + * wraps the platform-specific data. + * + * Results: + * Returns pointer to newly constructed TkFont. + * + * The caller is responsible for initializing the fields of the + * TkFont that are used exclusively by the generic TkFont code, and + * for releasing those fields before calling TkpDeleteFont(). + * + * Side effects: + * Memory allocated. + * + *--------------------------------------------------------------------------- + */ + +static TkFont * +AllocMacFont( + TkFont *tkFontPtr, /* If non-NULL, store the information in + * this existing TkFont structure, rather than + * allocating a new structure to hold the + * font; the existing contents of the font + * will be released. If NULL, a new TkFont + * structure is allocated. */ + Tk_Window tkwin, /* For display where font will be used. */ + int family, /* Macintosh font family. */ + int size, /* Point size for Macintosh font. */ + int style) /* Macintosh style bits. */ +{ + char buf[257]; + FontInfo fi; + MacFont *fontPtr; + TkFontAttributes *faPtr; + TkFontMetrics *fmPtr; + CGrafPtr saveWorld; + GDHandle saveDevice; + + if (gWorld == NULL) { + Rect rect = {0, 0, 1, 1}; + + if (NewGWorld(&gWorld, 0, &rect, NULL, NULL, 0) != noErr) { + panic("NewGWorld failed in AllocMacFont"); + } + } + GetGWorld(&saveWorld, &saveDevice); + SetGWorld(gWorld, NULL); + + if (tkFontPtr == NULL) { + fontPtr = (MacFont *) ckalloc(sizeof(MacFont)); + } else { + fontPtr = (MacFont *) tkFontPtr; + } + + fontPtr->font.fid = (Font) fontPtr; + + faPtr = &fontPtr->font.fa; + GetFontName(family, (StringPtr) buf); + buf[UCHAR(buf[0]) + 1] = '\0'; + faPtr->family = Tk_GetUid(buf + 1); + faPtr->pointsize = size; + faPtr->weight = (style & bold) ? TK_FW_BOLD : TK_FW_NORMAL; + faPtr->slant = (style & italic) ? TK_FS_ITALIC : TK_FS_ROMAN; + faPtr->underline = ((style & underline) != 0); + faPtr->overstrike = 0; + + fmPtr = &fontPtr->font.fm; + TextFont(family); + TextSize(size); + TextFace(style); + GetFontInfo(&fi); + fmPtr->ascent = fi.ascent; + fmPtr->descent = fi.descent; + fmPtr->maxWidth = fi.widMax; + fmPtr->fixed = (CharWidth('i') == CharWidth('w')); + + fontPtr->family = (short) family; + fontPtr->size = (short) size; + fontPtr->style = (short) style; + + SetGWorld(saveWorld, saveDevice); + + return (TkFont *) fontPtr; +} + diff --git a/mac/tkMacHLEvents.c b/mac/tkMacHLEvents.c new file mode 100644 index 0000000..39f7836 --- /dev/null +++ b/mac/tkMacHLEvents.c @@ -0,0 +1,437 @@ +/* + * tkMacHLEvents.c -- + * + * Implements high level event support for the Macintosh. Currently, + * the only event that really does anything is the Quit event. + * + * Copyright (c) 1995-1997 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) tkMacHLEvents.c 1.21 97/09/17 17:19:00 + */ + +#include "tcl.h" +#include "tclMacInt.h" +#include "tkMacInt.h" + +#include <Aliases.h> +#include <AppleEvents.h> +#include <SegLoad.h> +#include <ToolUtils.h> + +/* + * This is a Tcl_Event structure that the Quit AppleEvent handler + * uses to schedule the tkReallyKillMe function. + */ + +typedef struct KillEvent { + Tcl_Event header; /* Information that is standard for + * all events. */ + Tcl_Interp *interp; /* Interp that was passed to the + * Quit AppleEvent */ +} KillEvent; + +/* + * Static functions used only in this file. + */ + +static pascal OSErr QuitHandler _ANSI_ARGS_((AppleEvent* event, + AppleEvent* reply, long refcon)); +static pascal OSErr OappHandler _ANSI_ARGS_((AppleEvent* event, + AppleEvent* reply, long refcon)); +static pascal OSErr OdocHandler _ANSI_ARGS_((AppleEvent* event, + AppleEvent* reply, long refcon)); +static pascal OSErr PrintHandler _ANSI_ARGS_((AppleEvent* event, + AppleEvent* reply, long refcon)); +static pascal OSErr ScriptHandler _ANSI_ARGS_((AppleEvent* event, + AppleEvent* reply, long refcon)); +static int MissedAnyParameters _ANSI_ARGS_((AppleEvent *theEvent)); +static int ReallyKillMe _ANSI_ARGS_((Tcl_Event *eventPtr, int flags)); + +/* + *---------------------------------------------------------------------- + * + * TkMacInitAppleEvents -- + * + * Initilize the Apple Events on the Macintosh. This registers the + * core event handlers. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +TkMacInitAppleEvents( + Tcl_Interp *interp) /* Interp to handle basic events. */ +{ + OSErr err; + AEEventHandlerUPP OappHandlerUPP, OdocHandlerUPP, + PrintHandlerUPP, QuitHandlerUPP, ScriptHandlerUPP; + + /* + * Install event handlers for the core apple events. + */ + QuitHandlerUPP = NewAEEventHandlerProc(QuitHandler); + err = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, + QuitHandlerUPP, (long) interp, false); + + OappHandlerUPP = NewAEEventHandlerProc(OappHandler); + err = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication, + OappHandlerUPP, (long) interp, false); + + OdocHandlerUPP = NewAEEventHandlerProc(OdocHandler); + err = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments, + OdocHandlerUPP, (long) interp, false); + + PrintHandlerUPP = NewAEEventHandlerProc(PrintHandler); + err = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments, + PrintHandlerUPP, (long) interp, false); + + if (interp != NULL) { + ScriptHandlerUPP = NewAEEventHandlerProc(ScriptHandler); + err = AEInstallEventHandler('misc', 'dosc', + ScriptHandlerUPP, (long) interp, false); + } +} + +/* + *---------------------------------------------------------------------- + * + * TkMacDoHLEvent -- + * + * Dispatch incomming highlevel events. + * + * Results: + * None. + * + * Side effects: + * Depends on the incoming event. + * + *---------------------------------------------------------------------- + */ + +void +TkMacDoHLEvent( + EventRecord *theEvent) +{ + AEProcessAppleEvent(theEvent); + + return; +} + +/* + *---------------------------------------------------------------------- + * + * QuitHandler, OappHandler, etc. -- + * + * These are the core Apple event handlers. Only the Quit event does + * anything interesting. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static pascal OSErr +QuitHandler( + AppleEvent *theAppleEvent, + AppleEvent *reply, + long handlerRefcon) +{ + Tcl_Interp *interp = (Tcl_Interp *) handlerRefcon; + KillEvent *eventPtr; + + /* + * Call the exit command from the event loop, since you are not supposed + * to call ExitToShell in an Apple Event Handler. We put this at the head + * of Tcl's event queue because this message usually comes when the Mac is + * shutting down, and we want to kill the shell as quickly as possible. + */ + + eventPtr = (KillEvent *) ckalloc(sizeof(KillEvent)); + eventPtr->header.proc = ReallyKillMe; + eventPtr->interp = interp; + + Tcl_QueueEvent((Tcl_Event *) eventPtr, TCL_QUEUE_HEAD); + + return noErr; +} + +static pascal OSErr +OappHandler( + AppleEvent *theAppleEvent, + AppleEvent *reply, + long handlerRefcon) +{ + return noErr; +} + +static pascal OSErr +OdocHandler( + AppleEvent *theAppleEvent, + AppleEvent *reply, + long handlerRefcon) +{ + Tcl_Interp *interp = (Tcl_Interp *) handlerRefcon; + AEDescList fileSpecList; + FSSpec file; + OSErr err; + DescType type; + Size actual; + long count; + AEKeyword keyword; + long index; + Tcl_DString command; + Tcl_DString pathName; + Tcl_CmdInfo dummy; + + /* + * Don't bother if we don't have an interp or + * the open document procedure doesn't exist. + */ + + if ((interp == NULL) || + (Tcl_GetCommandInfo(interp, "tkOpenDocument", &dummy)) == 0) { + return noErr; + } + + /* + * If we get any errors wil retrieving our parameters + * we just return with no error. + */ + + err = AEGetParamDesc(theAppleEvent, keyDirectObject, + typeAEList, &fileSpecList); + if (err != noErr) { + return noErr; + } + + err = MissedAnyParameters(theAppleEvent); + if (err != noErr) { + return noErr; + } + + err = AECountItems(&fileSpecList, &count); + if (err != noErr) { + return noErr; + } + + Tcl_DStringInit(&command); + Tcl_DStringInit(&pathName); + Tcl_DStringAppend(&command, "tkOpenDocument", -1); + for (index = 1; index <= count; index++) { + int length; + Handle fullPath; + + Tcl_DStringSetLength(&pathName, 0); + err = AEGetNthPtr(&fileSpecList, index, typeFSS, + &keyword, &type, (Ptr) &file, sizeof(FSSpec), &actual); + if ( err != noErr ) { + continue; + } + + err = FSpPathFromLocation(&file, &length, &fullPath); + HLock(fullPath); + Tcl_DStringAppend(&pathName, *fullPath, length); + HUnlock(fullPath); + DisposeHandle(fullPath); + + Tcl_DStringAppendElement(&command, pathName.string); + } + + Tcl_GlobalEval(interp, command.string); + + Tcl_DStringFree(&command); + Tcl_DStringFree(&pathName); + return noErr; +} + +static pascal OSErr +PrintHandler( + AppleEvent *theAppleEvent, + AppleEvent *reply, + long handlerRefcon) +{ + return noErr; +} + +/* + *---------------------------------------------------------------------- + * + * DoScriptHandler -- + * + * This handler process the do script event. + * + * Results: + * Scedules the given event to be processed. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static pascal OSErr +ScriptHandler( + AppleEvent *theAppleEvent, + AppleEvent *reply, + long handlerRefcon) +{ + OSErr theErr; + AEDescList theDesc; + int tclErr = -1; + Tcl_Interp *interp; + char errString[128]; + + interp = (Tcl_Interp *) handlerRefcon; + + /* + * The do script event receives one parameter that should be data or a file. + */ + theErr = AEGetParamDesc(theAppleEvent, keyDirectObject, typeWildCard, + &theDesc); + if (theErr != noErr) { + sprintf(errString, "AEDoScriptHandler: GetParamDesc error %d", theErr); + theErr = AEPutParamPtr(reply, keyErrorString, typeChar, errString, + strlen(errString)); + } else if (MissedAnyParameters(theAppleEvent)) { + sprintf(errString, "AEDoScriptHandler: extra parameters"); + AEPutParamPtr(reply, keyErrorString, typeChar, errString, + strlen(errString)); + theErr = -1771; + } else { + if (theDesc.descriptorType == (DescType)'TEXT') { + short length, i; + + length = GetHandleSize(theDesc.dataHandle); + SetHandleSize(theDesc.dataHandle, length + 1); + *(*theDesc.dataHandle + length) = '\0'; + for (i=0; i<length; i++) { + if ((*theDesc.dataHandle)[i] == '\r') { + (*theDesc.dataHandle)[i] = '\n'; + } + } + + HLock(theDesc.dataHandle); + tclErr = Tcl_GlobalEval(interp, *theDesc.dataHandle); + HUnlock(theDesc.dataHandle); + } else if (theDesc.descriptorType == (DescType)'alis') { + Boolean dummy; + FSSpec theFSS; + Handle fullPath; + int length; + + theErr = ResolveAlias(NULL, (AliasHandle)theDesc.dataHandle, + &theFSS, &dummy); + if (theErr == noErr) { + FSpPathFromLocation(&theFSS, &length, &fullPath); + HLock(fullPath); + Tcl_EvalFile(interp, *fullPath); + HUnlock(fullPath); + DisposeHandle(fullPath); + } else { + sprintf(errString, "AEDoScriptHandler: file not found"); + AEPutParamPtr(reply, keyErrorString, typeChar, + errString, strlen(errString)); + } + } else { + sprintf(errString, + "AEDoScriptHandler: invalid script type '%-4.4s', must be 'alis' or 'TEXT'", + &theDesc.descriptorType); + AEPutParamPtr(reply, keyErrorString, typeChar, + errString, strlen(errString)); + theErr = -1770; + } + } + + /* + * If we actually go to run Tcl code - put the result in the reply. + */ + if (tclErr >= 0) { + if (tclErr == TCL_OK) { + AEPutParamPtr(reply, keyDirectObject, typeChar, + interp->result, strlen(interp->result)); + } else { + AEPutParamPtr(reply, keyErrorString, typeChar, + interp->result, strlen(interp->result)); + AEPutParamPtr(reply, keyErrorNumber, typeInteger, + (Ptr) &tclErr, sizeof(int)); + } + } + + AEDisposeDesc(&theDesc); + + return theErr; +} + +/* + *---------------------------------------------------------------------- + * + * ReallyKillMe -- + * + * This proc tries to kill the shell by running exit, and if that + * has not succeeded (e.g. because someone has renamed the exit + * command), calls Tcl_Exit to really kill the shell. Called from + * an event scheduled by the "Quit" AppleEvent handler. + * + * Results: + * Kills the shell. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +ReallyKillMe(Tcl_Event *eventPtr, int flags) +{ + Tcl_Interp *interp = ((KillEvent *) eventPtr)->interp; + if (interp != NULL) { + Tcl_GlobalEval(interp, "exit"); + } + Tcl_Exit(0); + + return 1; +} + +/* + *---------------------------------------------------------------------- + * + * MissedAnyParameters -- + * + * Checks to see if parameters are still left in the event. + * + * Results: + * True or false. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +MissedAnyParameters( + AppleEvent *theEvent) +{ + DescType returnedType; + Size actualSize; + OSErr err; + + err = AEGetAttributePtr(theEvent, keyMissedKeywordAttr, typeWildCard, + &returnedType, NULL, 0, &actualSize); + + return (err != errAEDescNotFound); +} diff --git a/mac/tkMacInit.c b/mac/tkMacInit.c new file mode 100644 index 0000000..bb1f8b3 --- /dev/null +++ b/mac/tkMacInit.c @@ -0,0 +1,240 @@ +/* + * tkMacInit.c -- + * + * This file contains Mac-specific interpreter initialization + * functions. + * + * Copyright (c) 1995-1996 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) tkMacInit.c 1.30 96/12/17 15:20:16 + */ + +#include <Resources.h> +#include <Files.h> +#include <TextUtils.h> +#include <Strings.h> +#include "tkInt.h" +#include "tkMacInt.h" +#include "tclMacInt.h" + +/* + * The following global is used by various parts of Tk to access + * information in the global qd variable. It is provided as a pointer + * in the AppInit because we don't assume that Tk is running as an + * application. For example, Tk could be a plugin and may not have + * access to the qd variable. This mechanism provides a way for the + * container application to give a pointer to the qd variable. + */ + +QDGlobalsPtr tcl_macQdPtr = NULL; + +/* + *---------------------------------------------------------------------- + * + * TkpInit -- + * + * Performs Mac-specific interpreter initialization related to the + * tk_library variable. + * + * Results: + * A standard Tcl completion code (TCL_OK or TCL_ERROR). Also + * leaves information in interp->result. + * + * Side effects: + * Sets "tk_library" Tcl variable, runs initialization scripts + * for Tk. + * + *---------------------------------------------------------------------- + */ + +int +TkpInit( + Tcl_Interp *interp) /* Interp to initialize. */ +{ + char *libDir, *tempPath; + Tcl_DString path; + int result; + + /* + * The following does not work with + * safe interps because file exists is restricted. + * to be fixed using [interp issafe] like in Unix & Windows. + */ + static char initCmd[] = + "if [file exists $tk_library:tk.tcl] {\n\ + source $tk_library:tk.tcl\n\ + source $tk_library:button.tcl\n\ + source $tk_library:entry.tcl\n\ + source $tk_library:listbox.tcl\n\ + source $tk_library:menu.tcl\n\ + source $tk_library:scale.tcl\n\ + source $tk_library:scrlbar.tcl\n\ + source $tk_library:text.tcl\n\ + source $tk_library:comdlg.tcl\n\ + source $tk_library:msgbox.tcl\n\ + } else {\n\ + set msg \"can't find tk resource or $tk_library:tk.tcl;\"\n\ + append msg \" perhaps you need to\\ninstall Tk or set your \"\n\ + append msg \"TK_LIBRARY environment variable?\"\n\ + error $msg\n\ + }"; + + Tcl_DStringInit(&path); + + /* + * The tk_library path can be found in several places. Here is the order + * in which the are searched. + * 1) the variable may already exist + * 2) env array + * 3) System Folder:Extensions:Tool Command Language: + */ + + libDir = Tcl_GetVar(interp, "tk_library", TCL_GLOBAL_ONLY); + if (libDir == NULL) { + libDir = Tcl_GetVar2(interp, "env", "TK_LIBRARY", TCL_GLOBAL_ONLY); + } + if (libDir == NULL) { + tempPath = Tcl_GetVar2(interp, "env", "EXT_FOLDER", TCL_GLOBAL_ONLY); + if (tempPath != NULL) { + Tcl_DString libPath; + + Tcl_JoinPath(1, &tempPath, &path); + + Tcl_DStringInit(&libPath); + Tcl_DStringAppend(&libPath, ":Tool Command Language:tk", -1); + Tcl_DStringAppend(&libPath, TK_VERSION, -1); + Tcl_JoinPath(1, &libPath.string, &path); + Tcl_DStringFree(&libPath); + libDir = path.string; + } + } + if (libDir == NULL) { + libDir = "no library"; + } + + /* + * Assign path to the global Tcl variable tcl_library. + */ + Tcl_SetVar(interp, "tk_library", libDir, TCL_GLOBAL_ONLY); + Tcl_DStringFree(&path); + + /* + * Source the needed Tk libraries from the resource + * fork of the application. + */ + result = Tcl_MacEvalResource(interp, "tk", 0, NULL); + result |= Tcl_MacEvalResource(interp, "button", 0, NULL); + result |= Tcl_MacEvalResource(interp, "entry", 0, NULL); + result |= Tcl_MacEvalResource(interp, "listbox", 0, NULL); + result |= Tcl_MacEvalResource(interp, "menu", 0, NULL); + result |= Tcl_MacEvalResource(interp, "scale", 0, NULL); + result |= Tcl_MacEvalResource(interp, "scrollbar", 0, NULL); + result |= Tcl_MacEvalResource(interp, "text", 0, NULL); + result |= Tcl_MacEvalResource(interp, "dialog", 0, NULL); + result |= Tcl_MacEvalResource(interp, "focus", 0, NULL); + result |= Tcl_MacEvalResource(interp, "optionMenu", 0, NULL); + result |= Tcl_MacEvalResource(interp, "palette", 0, NULL); + result |= Tcl_MacEvalResource(interp, "tearoff", 0, NULL); + result |= Tcl_MacEvalResource(interp, "tkerror", 0, NULL); + result |= Tcl_MacEvalResource(interp, "comdlg", 0, NULL); + result |= Tcl_MacEvalResource(interp, "msgbox", 0, NULL); + + if (result != TCL_OK) { + result = Tcl_Eval(interp, initCmd); + } + return result; +} + +/* + *---------------------------------------------------------------------- + * + * TkpGetAppName -- + * + * Retrieves the name of the current application from a platform + * specific location. On the Macintosh we look to see if the + * App Name is specified in a resource. If not, the application + * name is the root of the tail of the path contained in the tcl + * variable argv0. + * + * Results: + * Returns the application name in the given Tcl_DString. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +TkpGetAppName( + Tcl_Interp *interp, /* The main interpreter. */ + Tcl_DString *namePtr) /* A previously initialized Tcl_DString. */ +{ + int argc; + char **argv = NULL, *name, *p; + Handle h = NULL; + + h = GetNamedResource('STR ', "\pTk App Name"); + if (h != NULL) { + HLock(h); + Tcl_DStringAppend(namePtr, (*h)+1, **h); + HUnlock(h); + ReleaseResource(h); + return; + } + + name = Tcl_GetVar(interp, "argv0", TCL_GLOBAL_ONLY); + if (name != NULL) { + Tcl_SplitPath(name, &argc, &argv); + if (argc > 0) { + name = argv[argc-1]; + p = strrchr(name, '.'); + if (p != NULL) { + *p = '\0'; + } + } else { + name = NULL; + } + } + if ((name == NULL) || (*name == 0)) { + name = "tk"; + } + Tcl_DStringAppend(namePtr, name, -1); + if (argv != NULL) { + ckfree((char *)argv); + } +} + +/* + *---------------------------------------------------------------------- + * + * TkpDisplayWarning -- + * + * This routines is called from Tk_Main to display warning + * messages that occur during startup. + * + * Results: + * None. + * + * Side effects: + * Displays a message box. + * + *---------------------------------------------------------------------- + */ + +void +TkpDisplayWarning( + char *msg, /* Message to be displayed. */ + char *title) /* Title of warning. */ +{ + Tcl_DString ds; + Tcl_DStringInit(&ds); + Tcl_DStringAppend(&ds, title, -1); + Tcl_DStringAppend(&ds, ": ", -1); + Tcl_DStringAppend(&ds, msg, -1); + panic(Tcl_DStringValue(&ds)); + Tcl_DStringFree(&ds); +} diff --git a/mac/tkMacInt.h b/mac/tkMacInt.h new file mode 100644 index 0000000..fcb8174 --- /dev/null +++ b/mac/tkMacInt.h @@ -0,0 +1,282 @@ +/* + * tkMacInt.h -- + * + * Declarations of Macintosh specific shared variables and procedures. + * + * Copyright (c) 1995-1997 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) tkMacInt.h 1.67 97/11/20 18:30:38 + */ + +#ifndef _TKMACINT +#define _TKMACINT + +#include "tkInt.h" +#include "tkPort.h" + +#ifndef _TKMAC +# include "tkMac.h" +#endif /* _TKMAC */ + + +#include <AppleEvents.h> +#include <Windows.h> +#include <QDOffscreen.h> +#include <Menus.h> + +#define TK_MAC_68K_STACK_GROWTH (256*1024) + +struct TkWindowPrivate { + TkWindow *winPtr; /* Ptr to tk window or NULL if Pixmap */ + GWorldPtr portPtr; /* Either WindowRef or off screen world */ + int xOff; /* X offset from toplevel window */ + int yOff; /* Y offset from toplevel window */ + RgnHandle clipRgn; /* Visable region of window */ + RgnHandle aboveClipRgn; /* Visable region of window & it's children */ + int referenceCount; /* Don't delete toplevel until children are + * gone. */ + struct TkWindowPrivate *toplevel; /* Pointer to the toplevel + * datastruct. */ + int flags; /* Various state see defines below. */ +}; +typedef struct TkWindowPrivate MacDrawable; + +/* + * This list is used to keep track of toplevel windows that have a Mac + * window attached. This is useful for several things, not the least + * of which is maintaining floating windows. + */ + +typedef struct TkMacWindowList { + struct TkMacWindowList *nextPtr; /* The next window in the list. */ + TkWindow *winPtr; /* This window */ +} TkMacWindowList; + +/* + * Defines use for the flags field of the MacDrawable data structure. + */ + +#define TK_SCROLLBAR_GROW 1 +#define TK_CLIP_INVALID 2 +#define TK_HOST_EXISTS 4 +#define TK_DRAWN_UNDER_MENU 8 + +/* + * I am reserving TK_EMBEDDED = 0x100 in the MacDrawable flags + * This is defined in tk.h. We need to duplicate the TK_EMBEDDED flag in the + * TkWindow structure for the window, but in the MacWin. This way we can still tell + * what the correct port is after the TKWindow structure has been freed. This + * actually happens when you bind destroy of a toplevel to Destroy of a child. + */ + +/* + * Defines used for TkMacInvalidateWindow + */ + +#define TK_WINDOW_ONLY 0 +#define TK_PARENT_WINDOW 1 + +/* + * Accessor for the privatePtr flags field for the TK_HOST_EXISTS field + */ + +#define TkMacHostToplevelExists(tkwin) \ + (((TkWindow *) (tkwin))->privatePtr->toplevel->flags & TK_HOST_EXISTS) + +/* + * Defines use for the flags argument to TkGenWMConfigureEvent. + */ + +#define TK_LOCATION_CHANGED 1 +#define TK_SIZE_CHANGED 2 +#define TK_BOTH_CHANGED 3 + +/* + * Variables shared among various Mac Tk modules but are not + * exported to the outside world. + */ + +extern int tkMacAppInFront; + +/* + * Globals shared among Macintosh Tk + */ + +extern MenuHandle tkAppleMenu; /* Handle to the Apple Menu */ +extern MenuHandle tkFileMenu; /* Handles to menus */ +extern MenuHandle tkEditMenu; /* Handles to menus */ +extern RgnHandle tkMenuCascadeRgn; /* A region to clip with. */ +extern int tkUseMenuCascadeRgn; /* If this is 1, clipping code + * should intersect tkMenuCascadeRgn + * before drawing occurs. + * tkMenuCascadeRgn will only + * be valid when the value of this + * variable is 1. */ +extern TkMacWindowList *tkMacWindowListPtr; + /* The list of toplevels */ + +/* + * The following types and defines are for MDEF support. + */ + +#if STRUCTALIGNMENTSUPPORTED +#pragma options align=mac8k +#endif +typedef struct TkMenuLowMemGlobals { + long menuDisable; /* A combination of the menu and the item + * that the mouse is currently over. */ + short menuTop; /* Where in global coords the top of the + * menu is. */ + short menuBottom; /* Where in global coords the bottom of + * the menu is. */ + Rect itemRect; /* This is the rectangle of the currently + * selected item. */ + short scrollFlag; /* This is used by the MDEF and the + * Menu Manager to control when scrolling + * starts. With hierarchicals, an + * mChooseMsg can come before an + * mDrawMsg, and scrolling should not + * occur until after the mDrawMsg. + * The mDrawMsg sets this flag; + * mChooseMsg checks the flag and + * does not scroll if it is set; + * and then resets the flag. */ +} TkMenuLowMemGlobals; +#if STRUCTALIGNMENTSUPPORTED +#pragma options align=reset +#endif + +typedef pascal void (*TkMenuDefProcPtr) (short message, MenuHandle theMenu, + Rect *menuRectPtr, Point hitPt, short *whichItemPtr, + TkMenuLowMemGlobals *globalsPtr); +enum { + tkUppMenuDefProcInfo = kPascalStackBased + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(short))) + | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(MenuRef))) + | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(Rect*))) + | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(Point))) + | STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(short*))) + | STACK_ROUTINE_PARAMETER(6, SIZE_CODE(sizeof(TkMenuLowMemGlobals *))) +}; + +#if GENERATINGCFM +typedef UniversalProcPtr TkMenuDefUPP; +#else +typedef TkMenuDefProcPtr TkMenuDefUPP; +#endif + +#if GENERATINGCFM +#define TkNewMenuDefProc(userRoutine) \ + (TkMenuDefUPP) NewRoutineDescriptor((ProcPtr)(userRoutine), \ + tkUppMenuDefProcInfo, GetCurrentArchitecture()) +#else +#define TkNewMenuDefProc(userRoutine) \ + ((TkMenuDefUPP) (userRoutine)) +#endif + +#if GENERATINGCFM +#define TkCallMenuDefProc(userRoutine, message, theMenu, menuRectPtr, hitPt, \ + whichItemPtr, globalsPtr) \ + CallUniversalProc((UniversalProcPtr)(userRoutine), TkUppMenuDefProcInfo, \ + (message), (theMenu), (menuRectPtr), (hitPt), (whichItemPtr), \ + (globalsPtr)) +#else +#define TkCallMenuDefProc(userRoutine, message, theMenu, menuRectPtr, hitPt, \ + whichItemPtr, globalsPtr) \ + (*(userRoutine))((message), (theMenu), (menuRectPtr), (hitPt), \ + (whichItemPtr), (globalsPtr)) +#endif + +/* + * Internal procedures shared among Macintosh Tk modules but not exported + * to the outside world: + */ + +extern int HandleWMEvent _ANSI_ARGS_((EventRecord *theEvent)); +extern void TkAboutDlg _ANSI_ARGS_((void)); +extern void TkCreateMacEventSource _ANSI_ARGS_((void)); +extern void TkFontList _ANSI_ARGS_((Tcl_Interp *interp, + Display *display)); +extern Window TkGetTransientMaster _ANSI_ARGS_((TkWindow *winPtr)); +extern int TkGenerateButtonEvent _ANSI_ARGS_((int x, int y, + Window window, unsigned int state)); +extern int TkGetCharPositions _ANSI_ARGS_(( + XFontStruct *font_struct, char *string, + int count, short *buffer)); +extern void TkGenWMDestroyEvent _ANSI_ARGS_((Tk_Window tkwin)); +extern void TkGenWMConfigureEvent _ANSI_ARGS_((Tk_Window tkwin, + int x, int y, int width, int height, int flags)); +extern unsigned int TkMacButtonKeyState _ANSI_ARGS_((void)); +extern void TkMacClearMenubarActive _ANSI_ARGS_((void)); +extern int TkMacConvertEvent _ANSI_ARGS_((EventRecord *eventPtr)); +extern int TkMacDispatchMenuEvent _ANSI_ARGS_((int menuID, + int index)); +extern void TkMacInstallCursor _ANSI_ARGS_((int resizeOverride)); +extern int TkMacConvertTkEvent _ANSI_ARGS_((EventRecord *eventPtr, + Window window)); +extern void TkMacHandleTearoffMenu _ANSI_ARGS_((void)); +extern void tkMacInstallMWConsole _ANSI_ARGS_(( + Tcl_Interp *interp)); +extern void TkMacInvalClipRgns _ANSI_ARGS_((TkWindow *winPtr)); +extern void TkMacDoHLEvent _ANSI_ARGS_((EventRecord *theEvent)); +extern void TkMacFontInfo _ANSI_ARGS_((Font fontId, short *family, + short *style, short *size)); +extern Time TkMacGenerateTime _ANSI_ARGS_(()); +extern GWorldPtr TkMacGetDrawablePort _ANSI_ARGS_((Drawable drawable)); +extern TkWindow * TkMacGetScrollbarGrowWindow _ANSI_ARGS_(( + TkWindow *winPtr)); +extern Window TkMacGetXWindow _ANSI_ARGS_((WindowRef macWinPtr)); +extern int TkMacGrowToplevel _ANSI_ARGS_((WindowRef whichWindow, + Point start)); +extern void TkMacHandleMenuSelect _ANSI_ARGS_((long mResult, + int optionKeyPressed)); +extern void TkMacInitAppleEvents _ANSI_ARGS_((Tcl_Interp *interp)); +extern void TkMacInitMenus _ANSI_ARGS_((Tcl_Interp *interp)); +extern void TkMacInvalidateWindow _ANSI_ARGS_((MacDrawable *macWin, int flag)); +extern int TkMacIsCharacterMissing _ANSI_ARGS_((Tk_Font tkfont, + unsigned int searchChar)); +extern void TkMacMakeRealWindowExist _ANSI_ARGS_(( + TkWindow *winPtr)); +extern BitMapPtr TkMacMakeStippleMap(Drawable, Drawable); +extern void TkMacMenuClick _ANSI_ARGS_((void)); +extern void TkMacRegisterOffScreenWindow _ANSI_ARGS_((Window window, + GWorldPtr portPtr)); +extern int TkMacResizable _ANSI_ARGS_((TkWindow *winPtr)); +extern void TkMacSetEmbedRgn _ANSI_ARGS_((TkWindow *winPtr, RgnHandle rgn)); +extern void TkMacSetHelpMenuItemCount _ANSI_ARGS_((void)); +extern void TkMacSetScrollbarGrow _ANSI_ARGS_((TkWindow *winPtr, + int flag)); +extern void TkMacSetUpClippingRgn _ANSI_ARGS_((Drawable drawable)); +extern void TkMacSetUpGraphicsPort _ANSI_ARGS_((GC gc)); +extern void TkMacUpdateClipRgn _ANSI_ARGS_((TkWindow *winPtr)); +extern void TkMacUnregisterMacWindow _ANSI_ARGS_((GWorldPtr portPtr)); +extern int TkMacUseMenuID _ANSI_ARGS_((short macID)); +extern RgnHandle TkMacVisableClipRgn _ANSI_ARGS_((TkWindow *winPtr)); +extern void TkMacWinBounds _ANSI_ARGS_((TkWindow *winPtr, + Rect *geometry)); +extern void TkMacWindowOffset _ANSI_ARGS_((WindowRef wRef, + int *xOffset, int *yOffset)); +extern void TkResumeClipboard _ANSI_ARGS_((void)); +extern int TkSetMacColor _ANSI_ARGS_((unsigned long pixel, + RGBColor *macColor)); +extern void TkSetWMName _ANSI_ARGS_((TkWindow *winPtr, + Tk_Uid titleUid)); +extern void TkSuspendClipboard _ANSI_ARGS_((void)); +extern int TkWMGrowToplevel _ANSI_ARGS_((WindowRef whichWindow, + Point start)); +extern int TkMacZoomToplevel _ANSI_ARGS_((WindowPtr whichWindow, + Point where, short zoomPart)); +extern Tk_Window Tk_TopCoordsToWindow _ANSI_ARGS_((Tk_Window tkwin, + int rootX, int rootY, int *newX, int *newY)); +extern MacDrawable * TkMacContainerId _ANSI_ARGS_((TkWindow *winPtr)); +extern MacDrawable * TkMacGetHostToplevel _ANSI_ARGS_((TkWindow *winPtr)); +/* + * The following prototypes need to go into tkMac.h + */ +EXTERN void Tk_UpdatePointer _ANSI_ARGS_((Tk_Window tkwin, + int x, int y, int state)); + +#endif /* _TKMACINT */ diff --git a/mac/tkMacKeyboard.c b/mac/tkMacKeyboard.c new file mode 100644 index 0000000..a1dfad8 --- /dev/null +++ b/mac/tkMacKeyboard.c @@ -0,0 +1,384 @@ +/* + * tkMacKeyboard.c -- + * + * Routines to support keyboard events on the Macintosh. + * + * Copyright (c) 1995-1996 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) tkMacKeyboard.c 1.14 96/08/15 15:34:00 + */ + +#include "tkInt.h" +#include "Xlib.h" +#include "keysym.h" + +#include <Events.h> +#include <Script.h> + +typedef struct { + short keycode; /* Macintosh keycode */ + KeySym keysym; /* X windows Keysym */ +} KeyInfo; + +static KeyInfo keyArray[] = { + {0x4C, XK_Return}, + {0x24, XK_Return}, + {0x33, XK_BackSpace}, + {0x75, XK_Delete}, + {0x30, XK_Tab}, + {0x74, XK_Page_Up}, + {0x79, XK_Page_Down}, + {0x73, XK_Home}, + {0x77, XK_End}, + {0x7B, XK_Left}, + {0x7C, XK_Right}, + {0x7E, XK_Up}, + {0x7D, XK_Down}, + {0x72, XK_Help}, + {0x35, XK_Escape}, + {0x47, XK_Clear}, + {0, 0} +}; + +static KeyInfo vituralkeyArray[] = { + {122, XK_F1}, + {120, XK_F2}, + {99, XK_F3}, + {118, XK_F4}, + {96, XK_F5}, + {97, XK_F6}, + {98, XK_F7}, + {100, XK_F8}, + {101, XK_F9}, + {109, XK_F10}, + {103, XK_F11}, + {111, XK_F12}, + {105, XK_F13}, + {107, XK_F14}, + {113, XK_F15}, + {0, 0} +}; + +static int initialized = 0; +static Tcl_HashTable keycodeTable; /* keyArray hashed by keycode value. */ +static Tcl_HashTable vkeyTable; /* vituralkeyArray hashed by virtual + keycode value. */ +static Ptr KCHRPtr; /* Pointer to 'KCHR' resource. */ + +/* + * Prototypes for static functions used in this file. + */ +static void InitKeyMaps _ANSI_ARGS_((void)); + + +/* + *---------------------------------------------------------------------- + * + * InitKeyMaps -- + * + * Creates hash tables used by some of the functions in this file. + * + * Results: + * None. + * + * Side effects: + * Allocates memory & creates some hash tables. + * + *---------------------------------------------------------------------- + */ + +static void +InitKeyMaps() +{ + register Tcl_HashEntry *hPtr; + register KeyInfo *kPtr; + int dummy; + + Tcl_InitHashTable(&keycodeTable, TCL_ONE_WORD_KEYS); + for (kPtr = keyArray; kPtr->keycode != 0; kPtr++) { + hPtr = Tcl_CreateHashEntry(&keycodeTable, (char *) kPtr->keycode, + &dummy); + Tcl_SetHashValue(hPtr, kPtr->keysym); + } + Tcl_InitHashTable(&vkeyTable, TCL_ONE_WORD_KEYS); + for (kPtr = vituralkeyArray; kPtr->keycode != 0; kPtr++) { + hPtr = Tcl_CreateHashEntry(&vkeyTable, (char *) kPtr->keycode, + &dummy); + Tcl_SetHashValue(hPtr, kPtr->keysym); + } + KCHRPtr = (Ptr) GetScriptManagerVariable(smKCHRCache); + initialized = 1; +} + +/* + *---------------------------------------------------------------------- + * + * XKeycodeToKeysym -- + * + * Translate from a system-dependent keycode to a + * system-independent keysym. + * + * Results: + * Returns the translated keysym, or NoSymbol on failure. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +KeySym +XKeycodeToKeysym( + Display* display, + KeyCode keycode, + int index) +{ + register Tcl_HashEntry *hPtr; + register char c; + char virtualKey; + int newKeycode; + unsigned long dummy, newChar; + + if (!initialized) { + InitKeyMaps(); + } + + c = keycode & charCodeMask; + virtualKey = (keycode & keyCodeMask) >> 8; + + /* + * When determining what keysym to produce we firt check to see if + * the key is a function key. We then check to see if the character + * is another non-printing key. Finally, we return the key syms + * for all ASCI chars. + */ + if (c == 0x10) { + hPtr = Tcl_FindHashEntry(&vkeyTable, (char *) virtualKey); + if (hPtr != NULL) { + return (KeySym) Tcl_GetHashValue(hPtr); + } + } + + + hPtr = Tcl_FindHashEntry(&keycodeTable, (char *) virtualKey); + if (hPtr != NULL) { + return (KeySym) Tcl_GetHashValue(hPtr); + } + + /* + * Recompute the character based on the Shift key only. + * TODO: The index may also specify the NUM_LOCK. + */ + newKeycode = virtualKey; + if (index & 0x01) { + newKeycode += 0x0200; + } + dummy = 0; + newChar = KeyTranslate(KCHRPtr, (short) newKeycode, &dummy); + c = newChar & charCodeMask; + + if (c >= XK_space && c < XK_asciitilde) { + return c; + } + + return NoSymbol; +} + +/* + *---------------------------------------------------------------------- + * + * XLookupString -- + * + * Retrieve the string equivalent for the given keyboard event. + * + * Results: + * Returns the number of characters stored in buffer_return. + * + * Side effects: + * Retrieves the characters stored in the event and inserts them + * into buffer_return. + * + *---------------------------------------------------------------------- + */ + +int +XLookupString( + XKeyEvent* event_struct, + char* buffer_return, + int bytes_buffer, + KeySym* keysym_return, + XComposeStatus* status_in_out) +{ + register Tcl_HashEntry *hPtr; + char string[3]; + char virtualKey; + char c; + + if (!initialized) { + InitKeyMaps(); + } + + c = event_struct->keycode & charCodeMask; + string[0] = c; + string[1] = '\0'; + + /* + * Just return NULL if the character is a function key or another + * non-printing key. + */ + if (c == 0x10) { + string[0] = '\0'; + } else { + virtualKey = (event_struct->keycode & keyCodeMask) >> 8; + hPtr = Tcl_FindHashEntry(&keycodeTable, (char *) virtualKey); + if (hPtr != NULL) { + string[0] = '\0'; + } + } + + if (buffer_return != NULL) { + strncpy(buffer_return, string, bytes_buffer); + } + + return strlen(string); +} + +/* + *---------------------------------------------------------------------- + * + * XGetModifierMapping -- + * + * Fetch the current keycodes used as modifiers. + * + * Results: + * Returns a new modifier map. + * + * Side effects: + * Allocates a new modifier map data structure. + * + *---------------------------------------------------------------------- + */ + +XModifierKeymap * +XGetModifierMapping( + Display* display) +{ + XModifierKeymap * modmap; + + modmap = (XModifierKeymap *) ckalloc(sizeof(XModifierKeymap)); + modmap->max_keypermod = 0; + modmap->modifiermap = NULL; + return modmap; +} + +/* + *---------------------------------------------------------------------- + * + * XFreeModifiermap -- + * + * Deallocate a modifier map that was created by + * XGetModifierMapping. + * + * Results: + * None. + * + * Side effects: + * Frees the datastructure referenced by modmap. + * + *---------------------------------------------------------------------- + */ + +void +XFreeModifiermap( + XModifierKeymap *modmap) +{ + if (modmap->modifiermap != NULL) { + ckfree((char *) modmap->modifiermap); + } + ckfree((char *) modmap); +} + +/* + *---------------------------------------------------------------------- + * + * XKeysymToString, XStringToKeysym -- + * + * These X window functions map Keysyms to strings & strings to + * keysyms. However, Tk already does this for the most common keysyms. + * Therefor, these functions only need to support keysyms that will be + * specific to the Macintosh. Currently, there are none. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +char * +XKeysymToString( + KeySym keysym) +{ + return NULL; +} + +KeySym +XStringToKeysym( + const char* string) +{ + return NoSymbol; +} + +/* + *---------------------------------------------------------------------- + * + * XKeysymToKeycode -- + * + * The function XKeysymToKeycode is only used by tkTest.c and + * currently only implementes the support for keys used in the + * Tk test suite. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +KeyCode +XKeysymToKeycode( + Display* display, + KeySym keysym) +{ + KeyCode keycode = 0; + char virtualKeyCode = 0; + + if ((keysym >= XK_space) && (XK_asciitilde)) { + if (keysym == 'a') { + virtualKeyCode = 0x00; + } else if (keysym == 'b' || keysym == 'B') { + virtualKeyCode = 0x0B; + } else if (keysym == 'c') { + virtualKeyCode = 0x08; + } else if (keysym == 'x' || keysym == 'X') { + virtualKeyCode = 0x07; + } else if (keysym == 'z') { + virtualKeyCode = 0x06; + } else if (keysym == ' ') { + virtualKeyCode = 0x31; + } else if (keysym == XK_Return) { + virtualKeyCode = 0x24; + keysym = '\r'; + } + keycode = keysym + ((virtualKeyCode << 8) & keyCodeMask); + } + + return keycode; +} diff --git a/mac/tkMacLibrary.r b/mac/tkMacLibrary.r new file mode 100644 index 0000000..c86954a --- /dev/null +++ b/mac/tkMacLibrary.r @@ -0,0 +1,510 @@ +/* + * tkMacLibrary.r -- + * + * This file creates resources for use in most Tk applications. + * This is designed to be an example of using the Tcl/Tk + * libraries in a Macintosh Application. + * + * Copyright (c) 1996 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) tkMacLibrary.r 1.9 97/11/20 18:31:20 + */ + +/* + * New style DLOG templates have an extra field for the positioning + * options for the Dialog Box. We will not use this, for now, so we + * turn it off here. + */ + +#define DLOG_RezTemplateVersion 0 + +#include <Types.r> +#include <SysTypes.r> +#include <AEUserTermTypes.r> + +/* + * The folowing include and defines help construct + * the version string for Tcl. + */ + +#define RESOURCE_INCLUDED +#include <tcl.h> +#include "tk.h" + +#if (TK_RELEASE_LEVEL == 0) +# define RELEASE_LEVEL alpha +#elif (TK_RELEASE_LEVEL == 1) +# define RELEASE_LEVEL beta +#elif (TK_RELEASE_LEVEL == 2) +# define RELEASE_LEVEL final +#endif + +#if (TK_RELEASE_LEVEL == 2) +# define MINOR_VERSION (TK_MINOR_VERSION * 16) + TK_RELEASE_SERIAL +#else +# define MINOR_VERSION TK_MINOR_VERSION * 16 +#endif + +#define RELEASE_CODE 0x00 + +resource 'vers' (1) { + TK_MAJOR_VERSION, MINOR_VERSION, + RELEASE_LEVEL, 0x00, verUS, + TK_PATCH_LEVEL, + TK_PATCH_LEVEL ", by Ray Johnson © 1993-1996" "\n" "Sun Microsystems Labratories" +}; + +resource 'vers' (2) { + TK_MAJOR_VERSION, MINOR_VERSION, + RELEASE_LEVEL, 0x00, verUS, + TK_PATCH_LEVEL, + "Tk Library " TK_PATCH_LEVEL " © 1993-1996" +}; + +#define TK_LIBRARY_RESOURCES 3000 +/* + * The -16397 string will be displayed by Finder when a user + * tries to open the shared library. The string should + * give the user a little detail about the library's capabilities + * and enough information to install the library in the correct location. + * A similar string should be placed in all shared libraries. + */ +resource 'STR ' (-16397, purgeable) { + "Tk Library\n\n" + "This is the library needed to run Tcl/Tk programs. " + "To work properly, it should be placed in the ŒTool Command Language¹ folder " + "within the Extensions folder." +}; + + +/* + * We now load the Tk library into the resource fork of the library. + */ + +read 'TEXT' (TK_LIBRARY_RESOURCES+1, "tk", purgeable) + "::library:tk.tcl"; +read 'TEXT' (TK_LIBRARY_RESOURCES+2, "button", purgeable) + "::library:button.tcl"; +read 'TEXT' (TK_LIBRARY_RESOURCES+3, "dialog", purgeable) + "::library:dialog.tcl"; +read 'TEXT' (TK_LIBRARY_RESOURCES+4, "entry", purgeable) + "::library:entry.tcl"; +read 'TEXT' (TK_LIBRARY_RESOURCES+5, "focus", purgeable) + "::library:focus.tcl"; +read 'TEXT' (TK_LIBRARY_RESOURCES+6, "listbox", purgeable) + "::library:listbox.tcl"; +read 'TEXT' (TK_LIBRARY_RESOURCES+7, "menu", purgeable) + "::library:menu.tcl"; +read 'TEXT' (TK_LIBRARY_RESOURCES+8, "optionMenu", purgeable) + "::library:optMenu.tcl"; +read 'TEXT' (TK_LIBRARY_RESOURCES+9, "palette", purgeable) + "::library:palette.tcl"; +read 'TEXT' (TK_LIBRARY_RESOURCES+10, "scale", purgeable) + "::library:scale.tcl"; +read 'TEXT' (TK_LIBRARY_RESOURCES+11, "scrollbar", purgeable) + "::library:scrlbar.tcl"; +read 'TEXT' (TK_LIBRARY_RESOURCES+12, "tearoff", purgeable) + "::library:tearoff.tcl"; +read 'TEXT' (TK_LIBRARY_RESOURCES+13, "text", purgeable) + "::library:text.tcl"; +read 'TEXT' (TK_LIBRARY_RESOURCES+14, "tkerror", purgeable) + "::library:bgerror.tcl"; +read 'TEXT' (TK_LIBRARY_RESOURCES+15, "Console", purgeable) + "::library:console.tcl"; +read 'TEXT' (TK_LIBRARY_RESOURCES+16, "msgbox", purgeable, preload) + "::library:msgbox.tcl"; +read 'TEXT' (TK_LIBRARY_RESOURCES+17, "comdlg", purgeable, preload) + "::library:comdlg.tcl"; +read 'TEXT' (TK_LIBRARY_RESOURCES+18, "prolog", purgeable, preload) + "::library:prolog.ps"; + +/* + * The following two resources define the default "About Box" for Mac Tk. + * This dialog appears if the "About Tk..." menu item is selected from + * the Apple menu. This dialog may be overridden by defining a Tcl procedure + * with the name of "tkAboutDialog". If this procedure is defined the + * default dialog will not be shown and the Tcl procedure is expected to + * create and manage an About Dialog box. + */ + +data 'DLOG' (128, "Default About Box", purgeable) { + $"0055 006B 00F3 0196 0001 0100 0100 0000" + $"0000 0081 0000 280A" +}; + +resource 'DITL' (129, "About Box", purgeable) { + { + {128, 128, 148, 186}, Button {enabled, "Ok"}, + { 14, 108, 117, 298}, StaticText {disabled, + "Wish - Windowing Shell" "\n" "based on Tcl " + TCL_PATCH_LEVEL " & Tk " TK_PATCH_LEVEL "\n\n" "Ray Johnson" + "Sun Microsystems Labs" "\n" "ray.johnson@eng.sun.com"}, + { 11, 24, 111, 92}, Picture {enabled, 128} + } +}; + +data 'PICT' (128, purgeable) { + $"13A4 0000 0000 0064 0044 0011 02FF 0C00" + $"FFFE 0000 0048 0000 0048 0000 0000 0000" + $"0064 0044 0000 0000 0001 000A 0000 0000" + $"0064 0044 0099 8044 0000 0000 0064 0044" + $"0000 0000 0000 0000 0048 0000 0048 0000" + $"0000 0008 0001 0008 0000 0000 0108 00D8" + $"0000 0000 0001 5A5A 8000 00FF 3736 FF00" + $"FF00 FF00 3535 FF00 FF00 CC00 3434 FF00" + $"FF00 9900 3333 FF00 FF00 6600 3736 FF00" + $"FF00 3300 3535 FF00 FF00 0000 3434 FF00" + $"CC00 FF00 3333 FF00 CC00 CC00 3736 FF00" + $"CC00 9900 3535 FF00 CC00 6600 FAFA FF00" + $"CC00 3300 3333 FF00 CC00 0000 3130 FF00" + $"9900 FF00 2F2F FF00 9900 CC00 FAFA FF00" + $"9900 9900 F9F9 FF00 9900 6600 3130 FF00" + $"9900 3300 2F2F FF00 9900 0000 2E2E FF00" + $"6600 FF00 F9F9 FF00 6600 CC00 3130 FF00" + $"6600 9900 2F2F FF00 6600 6600 2E2E FF00" + $"6600 3300 2D2D FF00 6600 0000 3130 FF00" + $"3300 FF00 2F2F FF00 3300 CC00 2E2E FF00" + $"3300 9900 2D2D FF00 3300 6600 3130 FF00" + $"3300 3300 2F2F FF00 3300 0000 2E2E FF00" + $"0000 FF00 2D2D FF00 0000 CC00 3130 FF00" + $"0000 9900 2F2F FF00 0000 6600 2E2E FF00" + $"0000 3300 2DF8 FF00 0000 0000 2B2A CC00" + $"FF00 FF00 2929 CC00 FF00 CC00 2828 CC00" + $"FF00 9900 27F8 CC00 FF00 6600 2B2A CC00" + $"FF00 3300 2929 CC00 FF00 0000 2828 CC00" + $"CC00 FF00 2727 CC00 CC00 CC00 2B2A CC00" + $"CC00 9900 2929 CC00 CC00 6600 2828 CC00" + $"CC00 3300 2727 CC00 CC00 0000 2B2A CC00" + $"9900 FF00 2929 CC00 9900 CC00 2828 CC00" + $"9900 9900 2727 CC00 9900 6600 DBDB CC00" + $"9900 3300 4747 CC00 9900 0000 4646 CC00" + $"6600 FF00 4545 CC00 6600 CC00 DBDB CC00" + $"6600 9900 4747 CC00 6600 6600 4646 CC00" + $"6600 3300 4545 CC00 6600 0000 DBDB CC00" + $"3300 FF00 4747 CC00 3300 CC00 4646 CC00" + $"3300 9900 4545 CC00 3300 6600 DBDB CC00" + $"3300 3300 4141 CC00 3300 0000 4040 CC00" + $"0000 FF00 3F3F CC00 0000 CC00 4342 CC00" + $"0000 9900 4141 CC00 0000 6600 4040 CC00" + $"0000 3300 3F3F CC00 0000 0000 4342 9900" + $"FF00 FF00 4141 9900 FF00 CC00 4040 9900" + $"FF00 9900 3F3F 9900 FF00 6600 4342 9900" + $"FF00 3300 4141 9900 FF00 0000 4040 9900" + $"CC00 FF00 3F3F 9900 CC00 CC00 4342 9900" + $"CC00 9900 4141 9900 CC00 6600 4040 9900" + $"CC00 3300 3F3F 9900 CC00 0000 4342 9900" + $"9900 FF00 4141 9900 9900 CC00 4040 9900" + $"9900 9900 3F3F 9900 9900 6600 3D3C 9900" + $"9900 3300 3B3B 9900 9900 0000 3A3A 9900" + $"6600 FF00 3939 9900 6600 CC00 3D3C 9900" + $"6600 9900 3B3B 9900 6600 6600 3A3A 9900" + $"6600 3300 3939 9900 6600 0000 3D3C 9900" + $"3300 FF00 3B3B 9900 3300 CC00 3A3A 9900" + $"3300 9900 3939 9900 3300 6600 3D3C 9900" + $"3300 3300 3B3B 9900 3300 0000 3A3A 9900" + $"0000 FF00 3939 9900 0000 CC00 3D3C 9900" + $"0000 9900 3B3B 9900 0000 6600 3A3A 9900" + $"0000 3300 3939 9900 0000 0000 3D3C 6600" + $"FF00 FF00 3B3B 6600 FF00 CC00 3A3A 6600" + $"FF00 9900 3939 6600 FF00 6600 3D3C 6600" + $"FF00 3300 3B3B 6600 FF00 0000 3A3A 6600" + $"CC00 FF00 3939 6600 CC00 CC00 3736 6600" + $"CC00 9900 3535 6600 CC00 6600 3434 6600" + $"CC00 3300 3333 6600 CC00 0000 3736 6600" + $"9900 FF00 3535 6600 9900 CC00 3434 6600" + $"9900 9900 3333 6600 9900 6600 3736 6600" + $"9900 3300 3535 6600 9900 0000 3434 6600" + $"6600 FF00 3333 6600 6600 CC00 3736 6600" + $"6600 9900 3535 6600 6600 6600 3434 6600" + $"6600 3300 3333 6600 6600 0000 3736 6600" + $"3300 FF00 3535 6600 3300 CC00 3434 6600" + $"3300 9900 3333 6600 3300 6600 3736 6600" + $"3300 3300 3535 6600 3300 0000 3434 6600" + $"0000 FF00 3333 6600 0000 CC00 3130 6600" + $"0000 9900 2F2F 6600 0000 6600 2E2E 6600" + $"0000 3300 F9F9 6600 0000 0000 3130 3300" + $"FF00 FF00 2F2F 3300 FF00 CC00 2E2E 3300" + $"FF00 9900 F9F9 3300 FF00 6600 3130 3300" + $"FF00 3300 2F2F 3300 FF00 0000 2E2E 3300" + $"CC00 FF00 2D2D 3300 CC00 CC00 3130 3300" + $"CC00 9900 2F2F 3300 CC00 6600 2E2E 3300" + $"CC00 3300 2D2D 3300 CC00 0000 3130 3300" + $"9900 FF00 2F2F 3300 9900 CC00 2E2E 3300" + $"9900 9900 2D2D 3300 9900 6600 3130 3300" + $"9900 3300 2F2F 3300 9900 0000 2E2E 3300" + $"6600 FF00 2DF8 3300 6600 CC00 2B2A 3300" + $"6600 9900 2929 3300 6600 6600 2828 3300" + $"6600 3300 27F8 3300 6600 0000 2B2A 3300" + $"3300 FF00 2929 3300 3300 CC00 2828 3300" + $"3300 9900 2727 3300 3300 6600 2B2A 3300" + $"3300 3300 2929 3300 3300 0000 2828 3300" + $"0000 FF00 2727 3300 0000 CC00 2B2A 3300" + $"0000 9900 2929 3300 0000 6600 2828 3300" + $"0000 3300 2727 3300 0000 0000 4948 0000" + $"FF00 FF00 4747 0000 FF00 CC00 4646 0000" + $"FF00 9900 4545 0000 FF00 6600 4948 0000" + $"FF00 3300 4747 0000 FF00 0000 4646 0000" + $"CC00 FF00 4545 0000 CC00 CC00 4948 0000" + $"CC00 9900 4747 0000 CC00 6600 4646 0000" + $"CC00 3300 4545 0000 CC00 0000 4342 0000" + $"9900 FF00 4141 0000 9900 CC00 4040 0000" + $"9900 9900 3F3F 0000 9900 6600 4342 0000" + $"9900 3300 4141 0000 9900 0000 4040 0000" + $"6600 FF00 3F3F 0000 6600 CC00 4342 0000" + $"6600 9900 4141 0000 6600 6600 4040 0000" + $"6600 3300 3F3F 0000 6600 0000 4342 0000" + $"3300 FF00 4141 0000 3300 CC00 4040 0000" + $"3300 9900 3F3F 0000 3300 6600 4342 0000" + $"3300 3300 4141 0000 3300 0000 4040 0000" + $"0000 FF00 3F3F 0000 0000 CC00 4342 0000" + $"0000 9900 4141 0000 0000 6600 4040 0000" + $"0000 3300 3F3F EE00 0000 0000 3D3C DD00" + $"0000 0000 3B3B BB00 0000 0000 3A3A AA00" + $"0000 0000 3939 8800 0000 0000 3D3C 7700" + $"0000 0000 3B3B 5500 0000 0000 3A3A 4400" + $"0000 0000 3939 2200 0000 0000 3D3C 1100" + $"0000 0000 3B3B 0000 EE00 0000 3A3A 0000" + $"DD00 0000 3939 0000 BB00 0000 3D3C 0000" + $"AA00 0000 3B3B 0000 8800 0000 3A3A 0000" + $"7700 0000 3939 0000 5500 0000 3D3C 0000" + $"4400 0000 3B3B 0000 2200 0000 3A3A 0000" + $"1100 0000 3939 0000 0000 EE00 3D3C 0000" + $"0000 DD00 3B3B 0000 0000 BB00 3A3A 0000" + $"0000 AA00 3939 0000 0000 8800 3D3C 0000" + $"0000 7700 3B3B 0000 0000 5500 3A3A 0000" + $"0000 4400 3939 0000 0000 2200 3736 0000" + $"0000 1100 3535 EE00 EE00 EE00 3434 DD00" + $"DD00 DD00 3333 BB00 BB00 BB00 3736 AA00" + $"AA00 AA00 3535 8800 8800 8800 3434 7700" + $"7700 7700 3333 5500 5500 5500 3736 4400" + $"4400 4400 3535 2200 2200 2200 3434 1100" + $"1100 1100 3333 0000 0000 0000 0000 0000" + $"0064 0044 0000 0000 0064 0044 0000 000A" + $"0000 0000 0064 0044 02BD 0013 E800 01F5" + $"F6FE 07FE 0E02 3232 33FD 3900 0EE6 001D" + $"FC00 01F5 F5FE 0700 08FE 0E02 3232 33FE" + $"3900 3AFC 40F2 4102 4033 07E9 0017 0100" + $"0EFC 40DC 4102 390E F5F5 0002 F5F5 F6FE" + $"0702 0E07 0016 0100 32D5 4104 4039 0E32" + $"33FD 3900 3AFC 40FC 4101 3200 0801 000E" + $"C141 010E 0008 0100 0EC1 4101 0800 0801" + $"000E C141 0107 0008 0100 0EC1 4101 0700" + $"0901 0007 C241 0240 F500 0E01 0007 E841" + $"0147 47DD 4102 4000 0012 0100 07F0 4100" + $"47FA 4101 3B3B DD41 0240 0000 1901 0007" + $"F141 0C47 3B0B 3B47 4141 4711 0505 3B47" + $"DF41 023A 0000 1701 00F6 F041 010B 0BFE" + $"4105 473B 0505 113B DE41 0239 0000 1A02" + $"00F5 40F3 410C 473B 053B 4741 4741 0B0B" + $"3B47 47DE 4102 3900 0018 0200 F540 F341" + $"0247 110B FE41 0447 1105 4147 DC41 0233" + $"0000 1B02 0000 40F3 4103 4711 1147 FE41" + $"0205 3547 F741 FD47 E941 0232 0000 1E02" + $"0000 40F2 4106 113B 4741 4735 0BF7 4106" + $"4741 390E 0E40 47EA 4102 0E00 0021 0200" + $"0040 F241 0711 3B47 4141 0B35 47F9 4102" + $"4740 07FE 0002 F640 47EB 4102 0E00 0023" + $"0200 0040 F341 0847 3541 4147 3B05 4147" + $"FA41 0947 3AF6 00F5 4F55 F50E 47EB 4102" + $"0700 0022 0200 003A F341 0147 3BFE 4101" + $"0B0B F941 0547 3AF5 0055 C8FE CE01 5640" + $"EB41 0207 0000 1F02 0000 39F0 4104 4741" + $"053B 47FB 4104 4740 F5F5 A4FC CE01 C85D" + $"EB41 02F6 0000 1F02 0000 39F0 4104 473B" + $"0541 47FC 4104 4740 07F6 C8FA CE00 64EC" + $"4103 40F5 0000 1C02 0000 39F0 4102 4711" + $"0BFA 4103 4708 2AC8 FACE 0164 D8EC 4100" + $"40FE 0025 0200 0039 EF41 020B 3B47 FC41" + $"0347 0FF5 A4FB CE02 C887 D8FC 41FE 47FC" + $"4100 47F9 4100 3AFE 0028 0200 0039 EF41" + $"020B 3B47 FD41 0347 3900 A4FA CE00 ABFA" + $"4109 3B11 3B41 4147 3B0B 3B47 FA41 0039" + $"FE00 2402 0000 33F1 4102 4741 0BFA 4101" + $"0779 F9CE 0064 FA41 0235 050B FD41 010B" + $"0BF9 4100 39FE 0028 0200 0032 F141 0247" + $"3B0B FC41 0247 39F6 F9CE 0187 D8FB 4103" + $"4741 050B FE41 0247 110B F941 0039 FE00" + $"2C02 0000 32F1 4102 473B 11FB 4101 0879" + $"FACE 05AA 4041 4147 47FE 410A 4741 0511" + $"4741 4147 3511 47FA 4100 32FE 002F 0200" + $"000E F141 0347 3B11 47FE 4103 4740 F6C8" + $"FACE 0564 D841 4039 39FE 4104 473B 053B" + $"47FE 4102 3541 47FA 4100 0EFE 0027 0200" + $"000E F141 0347 3B3B 47FE 4102 470F 79FA" + $"CE0C 8741 4032 F500 003A 4741 473B 05F2" + $"4100 0EFE 0027 0200 000E F141 0347 3B3B" + $"47FD 4101 0EA4 FACE 01AB AAFE C808 7900" + $"3947 4147 110B 47F3 4100 07FE 001C 0200" + $"000E EA41 0240 2BC8 F5CE 0881 0033 4741" + $"410B 3B47 F341 0007 FE00 1A02 0000 08EB" + $"4102 473A 55F4 CE06 5D00 3947 4741 0BF1" + $"4100 F6FE 001C 0200 0007 EB41 0247 3979" + $"F4CE 0739 0039 4747 3511 47F3 4101 40F5" + $"FE00 1C02 0000 07EB 4102 4739 A4F5 CE08" + $"AB0E 0040 4741 1141 47F3 4100 40FD 001B" + $"0200 0007 EB41 0247 39A4 F5CE 0787 0707" + $"4147 4111 47F2 4100 40FD 001B 0200 0007" + $"EB41 0247 39C8 F5CE 0763 F532 4747 3B3B" + $"47F2 4100 3AFD 001A 0300 00F6 40EC 4102" + $"4739 C8F5 CE05 39F5 4047 413B F041 0039" + $"FD00 1C03 0000 F540 EB41 0140 C8FD CE01" + $"C8A4 FCCE 03AB 080E 47ED 4100 39FD 001A" + $"FE00 0040 EB41 0040 FCCE 01A4 C8FC CE03" + $"FA07 4047 ED41 0032 FD00 1AFE 0000 40EA" + $"4100 AAFE CE02 87F9 C8FC CE02 560F 47EC" + $"4100 32FD 0019 FE00 0040 EA41 00AB FECE" + $"0264 56C8 FDCE 01C8 32EA 4100 0EFD 001B" + $"FE00 0040 ED41 030E 4047 87FE CE01 4055" + $"FCCE 01FA 40EA 4100 08FD 001A FE00 003A" + $"ED41 0807 0740 FBCE CEAB 3979 FDCE 00AB" + $"E841 0007 FD00 1CFE 0000 3AED 4108 0700" + $"F6A4 CECE 8733 79FD CE02 4147 47EA 4100" + $"07FD 001E FE00 0039 ED41 0807 2AA4 C8CE" + $"CE88 0E9D FECE 0364 1C39 39EB 4101 40F5" + $"FD00 1CFE 0000 39ED 4101 074F FDCE 0264" + $"F7A4 FECE 03AB 80F6 07EB 4100 40FC 001C" + $"FE00 0039 ED41 0108 79FE CE03 AB40 2BA4" + $"FCCE 02F7 0E47 EC41 0040 FC00 1CFE 0000" + $"39ED 4101 0879 FECE 03AB 40F6 C8FC CE02" + $"F615 47EC 4100 40FC 001E FE00 003A EE41" + $"0247 0E79 FECE 03AB 40F5 C8FD CE03 A4F5" + $"3A47 EC41 0040 FC00 1EFE 0000 3AEE 4102" + $"470E 56FE CE03 FB3A F6C8 FDCE 0280 F540" + $"EB41 0140 F5FD 001E FE00 0040 EE41 0947" + $"0F56 CECE C888 39F6 C8FD CE02 5601 40EB" + $"4101 40F5 FD00 1CFE 0000 40EE 4109 4739" + $"32CE CEC8 8839 2AC8 FDCE 0156 07E9 4100" + $"F6FD 001B FE00 0040 EE41 0847 3A32 CECE" + $"C864 152A FCCE 0132 07E9 4100 07FD 001A" + $"FE00 0040 ED41 0740 32AB CEC8 6439 4EFC" + $"CE01 3A07 E941 0007 FD00 1D03 0000 F540" + $"ED41 0740 0EAB CECE 640F 4EFD CE03 AB40" + $"0840 EA41 0007 FD00 1B03 0000 F540 EC41" + $"060F 81CE CE64 334E FDCE 02AB 400E E941" + $"000E FD00 1C02 0000 F6EC 4107 4715 FACE" + $"CE64 334E FDCE 0387 0F0E 47EA 4100 0EFD" + $"001C 0200 0007 EC41 0747 16F9 CEC8 6433" + $"4EFD CE03 6308 4047 EA41 000E FD00 1A02" + $"0000 07EB 4106 40F9 CEC8 6439 4EFD CE02" + $"3940 47E9 4100 32FD 001B 0200 0007 EA41" + $"0539 CECE 8839 F6FE CE04 AB41 4139 40EA" + $"4100 32FD 001C 0200 0007 EB41 0E47 3AC8" + $"CE88 39F6 C8CE CE64 15F6 F540 EA41 0033" + $"FD00 1A02 0000 07EA 410C 40A4 CE87 392A" + $"C8CE AB41 40F8 F6E9 4100 39FD 001B 0200" + $"000E EB41 0D47 41AB C887 39F5 C8CE ABAB" + $"CEA4 07E9 4100 39FD 001C 0200 000E ED41" + $"0947 3939 4787 C8AB 40F5 C8FD CE01 A40E" + $"E941 0039 FD00 1D02 0000 0EED 4109 473A" + $"0007 80CE AB40 F5C8 FDCE 0255 0E47 EA41" + $"0039 FD00 1B02 0000 0EEB 4107 0779 C8CE" + $"CE40 F6A4 FDCE 022B 3947 EA41 003A FD00" + $"1C02 0000 0EEC 4102 4739 79FE CE02 6407" + $"A4FE CE02 A407 40E9 4100 40FD 001A 0200" + $"0032 EA41 0632 A4CE CE88 0879 FECE 02F9" + $"0F47 E941 0040 FD00 1A02 0000 32EB 4107" + $"4740 F7C8 CE87 0E79 FECE 0132 40E8 4100" + $"40FD 0019 0200 0033 EA41 0B47 40F8 C8AB" + $"0E55 CECE 8015 47E8 4100 40FD 0017 0200" + $"0033 E941 0847 40F9 A439 4FCE CE5D E641" + $"0140 F5FE 0014 0200 0039 E841 0647 64FB" + $"392B C8AB E441 00F6 FE00 1102 0000 39E5" + $"4103 40F6 8764 E441 0007 FE00 1E02 0000" + $"39EB 4102 3A0E 0EFD 4102 0740 47F6 4104" + $"400F 0839 47F4 4100 07FE 0027 0200 0039" + $"FB41 0147 47F2 4102 0800 40FE 4102 0839" + $"47FC 4101 4747 FC41 0339 0039 47F4 4100" + $"07FE 0029 0200 0039 FB41 0140 39F3 4109" + $"470E F540 4141 470E 3347 FC41 0139 3AFD" + $"4104 4739 0039 47F4 4100 08FE 0036 0200" + $"003A FC41 0347 0E00 40FC 4102 4741 40FC" + $"4109 470E F540 4141 4733 0E47 FE41 0447" + $"4000 0E47 FE41 0447 3900 3941 FE40 F741" + $"000E FE00 3A02 0000 3AFD 410E 4740 0700" + $"0E40 4741 4147 390E 390E 40FE 4108 470E" + $"F540 4141 4739 0EFC 4103 0F00 0739 FE41" + $"0747 3900 3940 080F 39F7 4100 0EFE 0035" + $"0200 0040 FB41 020E 0040 FE41 0D47 4000" + $"3941 0032 4741 4147 0EF5 40FE 4101 4008" + $"FC41 023A 000E FD41 0547 3900 3939 33F5" + $"4100 0EFE 0039 0200 0040 FC41 0347 0E00" + $"40FE 4106 4732 0040 4139 40FE 4103 470E" + $"F540 FD41 0108 40FE 4104 4740 000E 47FE" + $"4106 4739 0007 F540 47F6 4100 32FE 003A" + $"0200 0040 FC41 0C47 0E00 4047 4141 470E" + $"0040 4747 FD41 0347 0EF5 40FE 410A 470E" + $"3947 4141 4740 000E 47FE 4107 4739 000E" + $"0007 4147 F741 0032 FE00 3802 0000 40FC" + $"4102 470E 00FD 4106 4739 003A 4740 39FE" + $"4102 470E F5FD 410A 4733 3347 4141 4740" + $"000E 47FE 4106 4739 0039 3900 0EF6 4100" + $"33FE 003A 0200 F540 FC41 0447 3200 0E39" + $"FD41 0B0E 0E40 333A 4741 413A 07F5 39FE" + $"4102 473A 0EFD 410F 40F5 0733 4041 4140" + $"0E00 0E40 0700 0E40 F841 0039 FE00 2902" + $"00F5 40FA 4101 3939 FB41 023A 3A40 FD41" + $"FD40 FD41 0240 0E40 FD41 0240 3940 FD41" + $"FA40 F741 0039 FE00 2A01 00F6 F941 0147" + $"47FB 4101 4747 FB41 0147 47FB 4101 3940" + $"FD41 0147 47FB 4100 47FE 4100 47F6 4100" + $"39FE 000D 0100 07E1 4100 40E4 4100 3AFE" + $"0009 0100 07C3 4100 3AFE 0009 0100 07C3" + $"4100 40FE 0009 0100 07C3 4100 40FE 0009" + $"0100 07C3 4100 40FE 000A 0100 0EC3 4103" + $"40F5 0000 0901 000E C241 02F6 0000 0901" + $"000E C241 0207 0000 0901 000E C241 0207" + $"0000 1101 000E ED41 FE40 003A F940 E241" + $"0207 0000 2B01 0032 F941 FE40 FE39 0632" + $"0E0E 0707 F6F5 F800 02F5 F5F6 FB07 FB0E" + $"0332 3233 33FB 3901 3A3A FB40 0207 0000" + $"0E0A 000E 3939 320E 0E07 07F6 F5C8 0002" + $"BD00 00FF" +}; + +/* + * Here is the custom file open dialog. This dialog is used instead of + * the default file dialog if the -filetypes flag is specified. + */ + +#define DLOG_RezTemplateVersion 0 + +resource 'DLOG' (130, purgeable) { + {0, 0, 195, 344}, dBoxProc, invisible, noGoAway, 0, + 130, "" +}; + +resource 'DITL' (130, "File Open Box", purgeable) { + { + {135, 252, 155, 332}, Button {enabled, "Open"}, + {104, 252, 124, 332}, Button {enabled, "Cancel"}, + { 0, 0, 0, 0}, HelpItem {disabled, HMScanhdlg {130}}, + { 8, 235, 24, 337}, UserItem {enabled}, + { 32, 252, 52, 332}, Button {enabled, "Eject"}, + { 60, 252, 80, 332}, Button {enabled, "Desktop"}, + { 29, 12, 159, 230}, UserItem {enabled}, + { 6, 12, 25, 230}, UserItem {enabled}, + { 91, 251, 92, 333}, Picture {disabled, 11}, + {168, 20, 187, 300}, Control {enabled, 131} + } +}; + +resource 'CNTL' (131, "File Types menu", purgeable) { + {168, 20, 187, 300}, + popupTitleLeftJust, + visible, + 80, + 132, + popupMenuCDEFProc, + 0, + "File Type:" +}; + + +resource 'MENU' (132, preload) { + 132, + textMenuProc, + 0xFFFF, enabled, "", {} +}; diff --git a/mac/tkMacMDEF.c b/mac/tkMacMDEF.c new file mode 100644 index 0000000..f7ce485 --- /dev/null +++ b/mac/tkMacMDEF.c @@ -0,0 +1,116 @@ +/* + * TkMacMDEF.c -- + * + * This module is implements the MDEF for tkMenus. The address of the + * real entry proc will be blasted into the MDEF. + * + * Copyright (c) 1996 by Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) tkMacMDEF.c 1.5 97/07/11 %V% + */ + +#define MAC_TCL +#define NeedFunctionPrototypes 1 +#define NeedWidePrototypes 0 + +#include <Menus.h> +#include <LowMem.h> +#include "tkMacInt.h" + + +/* + * The following structure is built from assembly equates in MPW 3.0 + * AIncludes file: "Private.a." We're forced to update several locations not + * documented in "Inside Mac" to make our MDEF behave properly with hierarchical + * menus. + */ + +#if STRUCTALIGNMENTSUPPORTED +#pragma options align=mac68k +#endif +typedef struct mbPrivate { + Byte unknown[6]; + Rect mbItemRect; /* rect of currently chosen menu item */ +} mbPrivate; +#if STRUCTALIGNMENTSUPPORTED +#pragma options align=reset +#endif + +/* + * We are forced to update a low-memory global to get cascades to work. This + * global does not have a LMEquate associated with it. + */ + +#define SELECTRECT (*(Rect *)0x09fa) /* Menu select seems to need this */ +#define MBSAVELOC (*(short *)0x0B5C) /* address of handle to mbarproc private data redefined below */ + +pascal void main _ANSI_ARGS_((short message, + MenuHandle menu, Rect *menuRect, + Point hitPt, short *whichItem)); + + +/* + *---------------------------------------------------------------------- + * + * TkMacStdMenu -- + * + * The dispatch routine called by the system to handle menu drawing, + * scrolling, etc. This is a stub; the address of the real routine + * is blasted in. The real routine will be a UniversalProcPtr, + * which will give the real dispatch routine in Tk globals + * and the like. + * + * Results: + * None. + * + * Side effects: + * This routine causes menus to be drawn and will certainly allocate + * memory as a result. Also, the menu can scroll up and down, and + * various other interface actions can take place + * + *---------------------------------------------------------------------- + */ + +pascal void +main( + short message, /* What action are we taking? */ + MenuHandle menu, /* The menu we are working with */ + Rect *menuRect, /* A pointer to the rect we are working with */ + Point hitPt, /* Where the mouse was hit for appropriate + * messages. */ + short *whichItemPtr) /* Output result. Which item was hit by + * the user? */ +{ + /* + * The constant 'MDEF' is what will be punched during menu intialization. + */ + + TkMenuDefProcPtr procPtr = (TkMenuDefProcPtr) 'MDEF'; + TkMenuLowMemGlobals globals; + short oldItem; + + globals.menuDisable = LMGetMenuDisable(); + globals.menuTop = LMGetTopMenuItem(); + globals.menuBottom = LMGetAtMenuBottom(); + if (MBSAVELOC == -1) { + globals.itemRect = (**(mbPrivate***)&MBSAVELOC)->mbItemRect; + } + if (message == mChooseMsg) { + oldItem = *whichItemPtr; + } + + TkCallMenuDefProc(procPtr, message, menu, menuRect, hitPt, whichItemPtr, + &globals); + + LMSetMenuDisable(globals.menuDisable); + LMSetTopMenuItem(globals.menuTop); + LMSetAtMenuBottom(globals.menuBottom); + if ((message == mChooseMsg) && (oldItem != *whichItemPtr) + && (MBSAVELOC != -1)) { + (**(mbPrivate***)&MBSAVELOC)->mbItemRect = globals.itemRect; + SELECTRECT = globals.itemRect; + } +} diff --git a/mac/tkMacMDEF.r b/mac/tkMacMDEF.r new file mode 100644 index 0000000..5c18104 --- /dev/null +++ b/mac/tkMacMDEF.r @@ -0,0 +1,45 @@ +/* + * tkMacMDEF.r -- + * + * This file contains the actual MDEF. Since this is not likely to + * change much, this seems the easiest method to use. The address + * of the routine descriptor is written into offset 0x24 hex, and + * then when the MDEF is called, the Mixed Mode Manager will take + * care of the setup. + * + * This file also contains the icons 'SICN' used by the menu code + * in menu items. + * + * Copyright (c) 1996-1997 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) tkMacMDEF.r 1.6 97/07/11 18:09:47 + */ + +#include <Types.r> + +/* + * This code was generated by a project file and will not need to be changed. + * It is just a stub. The address of the real MDEF handler will be blasted + * in. + */ + +data 'MDEF' (591, preload) { + $"600A 0000 4D44 4546 024F 0000 4EFA 0004" /* `...MDEF.O..Nú.. */ + $"4E75 4E56 FFEE 48E7 1830 362E 0018 246E" /* NuNVÿîHç.06...$n */ + $"0008 267C 4D44 4546 594F 2EB8 0B54 201F" /* ..&|MDEFYO.¸.T . */ + $"2D40 FFEE 554F 3EB8 0A0A 301F 3D40 FFF2" /* -@ÿîUO>¸..0.=@ÿò */ + $"554F 3EB8 0A0C 301F 3D40 FFF4 0C78 FFFF" /* UO>¸..0.=@ÿô.xÿÿ */ + $"0B5C 6612 2078 0B5C 2050 2D68 0006 FFF6" /* .\f. x.\ P-h..ÿö */ + $"2D68 000A FFFA 0C43 0001 6602 3812 3F03" /* -h..ÿú.C..f.8.?. */ + $"2F2E 0014 2F2E 0010 2F2E 000C 2F0A 486E" /* /.../.../.../.Hn */ + $"FFEE 4E93 2F2E FFEE 21DF 0B54 3F2E FFF2" /* ÿîN“/.ÿî!ß.T?.ÿò */ + $"31DF 0A0A 3F2E FFF4 31DF 0A0C 0C43 0001" /* 1ß..?.ÿô1ß...C.. */ + $"662A B852 6726 0C78 FFFF 0B5C 671E 2078" /* f*¸Rg&.xÿÿ.\g. x */ + $"0B5C 2050 216E FFF6 0006 216E FFFA 000A" /* .\ P!nÿö..!nÿú.. */ + $"21EE FFF6 09FA 21EE FFFA 09FE 4CDF 0C18" /* !îÿöÆú!îÿúÆþLß.. */ + $"4E5E 205F 4FEF 0012 4ED0 846D 6169 6E00" /* N^ _Oï..NЄmain. */ + $"0000" /* .. */ +}; diff --git a/mac/tkMacMenu.c b/mac/tkMacMenu.c new file mode 100644 index 0000000..33bb82b --- /dev/null +++ b/mac/tkMacMenu.c @@ -0,0 +1,3994 @@ +/* + * tkMacMenu.c -- + * + * This module implements the Mac-platform specific features of menus. + * + * Copyright (c) 1996-1997 by Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) tkMacMenu.c 1.107 97/11/20 18:33:09 + */ + +#include <Menus.h> +#include <OSUtils.h> +#include <Palettes.h> +#include <Resources.h> +#include <string.h> +#include <ToolUtils.h> +#include <Balloons.h> +#undef Status +#include <Devices.h> +#include "tkMenu.h" +#include "tkMacInt.h" +#include "tkMenuButton.h" + +typedef struct MacMenu { + MenuHandle menuHdl; /* The Menu Manager data structure. */ + Rect menuRect; /* The rectangle as calculated in the + * MDEF. This is used to figure ou the + * clipping rgn before we push + * the <<MenuSelect>> virtual binding + * through. */ +} MacMenu; + +/* + * Various geometry definitions: + */ + +#define CASCADE_ARROW_HEIGHT 10 +#define CASCADE_ARROW_WIDTH 8 +#define DECORATION_BORDER_WIDTH 2 +#define MAC_MARGIN_WIDTH 8 + +/* + * The following are constants relating to the SICNs used for drawing the MDEF. + */ + +#define SICN_RESOURCE_NUMBER 128 + +#define SICN_HEIGHT 16 +#define SICN_ROWS 2 +#define CASCADE_ICON_WIDTH 7 +#define SHIFT_ICON_WIDTH 10 +#define OPTION_ICON_WIDTH 16 +#define CONTROL_ICON_WIDTH 12 +#define COMMAND_ICON_WIDTH 10 + +#define CASCADE_ARROW 0 +#define SHIFT_ICON 1 +#define OPTION_ICON 2 +#define CONTROL_ICON 3 +#define COMMAND_ICON 4 +#define DOWN_ARROW 5 +#define UP_ARROW 6 + +/* + * Platform specific flags for menu entries + * + * ENTRY_COMMAND_ACCEL Indicates the entry has the command key + * in its accelerator string. + * ENTRY_OPTION_ACCEL Indicates the entry has the option key + * in its accelerator string. + * ENTRY_SHIFT_ACCEL Indicates the entry has the shift key + * in its accelerator string. + * ENTRY_CONTROL_ACCEL Indicates the entry has the control key + * in its accelerator string. + */ + +#define ENTRY_COMMAND_ACCEL ENTRY_PLATFORM_FLAG1 +#define ENTRY_OPTION_ACCEL ENTRY_PLATFORM_FLAG2 +#define ENTRY_SHIFT_ACCEL ENTRY_PLATFORM_FLAG3 +#define ENTRY_CONTROL_ACCEL ENTRY_PLATFORM_FLAG4 +#define ENTRY_ACCEL_MASK (ENTRY_COMMAND_ACCEL | ENTRY_OPTION_ACCEL \ + | ENTRY_SHIFT_ACCEL | ENTRY_CONTROL_ACCEL) + +/* + * This structure is used to keep track of subfields within Macintosh menu + * items. + */ + +typedef struct EntryGeometry { + int accelTextStart; /* Offset into the accel string where + * the text starts. Everything before + * this is modifier key descriptions. + */ + int modifierWidth; /* Width of modifier symbols. */ + int accelTextWidth; /* Width of the text after the modifier + * keys. */ + int nonAccelMargin; /* The width of the margin for entries + * without accelerators. */ +} EntryGeometry; + +/* + * Structure to keep track of toplevel windows and their menubars. + */ + +typedef struct TopLevelMenubarList { + struct TopLevelMenubarList *nextPtr; + /* The next window in the list. */ + Tk_Window tkwin; /* The toplevel window. */ + TkMenu *menuPtr; /* The menu associated with this + * toplevel. */ +} TopLevelMenubarList; + +/* + * Platform-specific flags for menus. + * + * MENU_APPLE_MENU 0 indicates a custom Apple menu has + * not been installed; 1 a custom Apple + * menu has been installed. + * MENU_HELP_MENU 0 indicates a custom Help menu has + * not been installed; 1 a custom Help + * menu has been installed. + * MENU_RECONFIGURE_PENDING 1 indicates that an idle handler has + * been scheduled to reconfigure the + * Macintosh MenuHandle. + */ + +#define MENU_APPLE_MENU MENU_PLATFORM_FLAG1 +#define MENU_HELP_MENU MENU_PLATFORM_FLAG2 +#define MENU_RECONFIGURE_PENDING MENU_PLATFORM_FLAG3 + +#define CASCADE_CMD (0x1b) + /* The special command char for cascade + * menus. */ +#define SEPARATOR_TEXT "\p(-" + /* The text for a menu separator. */ + +#define MENUBAR_REDRAW_PENDING 1 + +RgnHandle tkMenuCascadeRgn = NULL; + /* The region to clip drawing to when the + * MDEF is up. */ +int tkUseMenuCascadeRgn = 0; /* If this is 1, clipping code + * should intersect tkMenuCascadeRgn + * before drawing occurs. + * tkMenuCascadeRgn will only + * be valid when the value of this + * variable is 1. */ + +static Tcl_HashTable commandTable; + /* The list of menuInstancePtrs associated with + * menu ids */ +static short currentAppleMenuID; + /* The id of the current Apple menu. 0 for + * none. */ +static short currentHelpMenuID; /* The id of the current Help menu. 0 for + * none. */ +static Tcl_Interp *currentMenuBarInterp; + /* The interpreter of the window that owns + * the current menubar. */ +static char *currentMenuBarName; + /* Malloced. Name of current menu in menu bar. + * NULL if no menu set. TO DO: make this a + * DString. */ +static Tk_Window currentMenuBarOwner; + /* Which window owns the current menu bar. */ +static int helpItemCount; /* The number of items in the help menu. + * -1 means that the help menu is + * unavailable. This does not include + * the automatically generated separator. */ +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; + /* Cascades have to have ids that are + * less than 256. */ +static MacDrawable macMDEFDrawable; + /* Drawable for use by MDEF code */ +static MDEFScrollFlag = 0; /* Used so that popups don't scroll too soon. */ +static int menuBarFlags; /* Used for whether the menu bar needs + * redrawing or not. */ +static TkMenuDefUPP menuDefProc;/* The routine descriptor to the MDEF proc. + * The MDEF is needed to draw menus with + * non-standard attributes and to support + * tearoff menus. */ +static struct TearoffSelect { + TkMenu *menuPtr; /* The menu that is torn off */ + Point point; /* The point to place the new menu */ + Rect excludeRect; /* We don't want to drag tearoff highlights + * when we are in this menu */ +} tearoffStruct; + +static RgnHandle totalMenuRgn = NULL; + /* Used to update windows which have been + * obscured by menus. */ +static RgnHandle utilRgn = NULL;/* Used when creating the region that is to + * be clipped out while the MDEF is active. */ + +static TopLevelMenubarList *windowListPtr; + /* A list of windows that have menubars set. */ + +/* + * Forward declarations for procedures defined later in this file: + */ + +static void CompleteIdlers _ANSI_ARGS_((TkMenu *menuPtr)); +static void DrawMenuBarWhenIdle _ANSI_ARGS_(( + ClientData clientData)); +static void DrawMenuEntryAccelerator _ANSI_ARGS_(( + TkMenu *menuPtr, TkMenuEntry *mePtr, + Drawable d, GC gc, Tk_Font tkfont, + CONST Tk_FontMetrics *fmPtr, + Tk_3DBorder activeBorder, int x, int y, + int width, int height, int drawArrow)); +static void DrawMenuEntryBackground _ANSI_ARGS_(( + TkMenu *menuPtr, TkMenuEntry *mePtr, + Drawable d, Tk_3DBorder activeBorder, + Tk_3DBorder bgBorder, int x, int y, + int width, int heigth)); +static void DrawMenuEntryIndicator _ANSI_ARGS_(( + TkMenu *menuPtr, TkMenuEntry *mePtr, + Drawable d, GC gc, GC indicatorGC, + Tk_Font tkfont, + CONST Tk_FontMetrics *fmPtr, int x, int y, + int width, int height)); +static void DrawMenuEntryLabel _ANSI_ARGS_(( + TkMenu * menuPtr, TkMenuEntry *mePtr, Drawable d, + GC gc, Tk_Font tkfont, + CONST Tk_FontMetrics *fmPtr, int x, int y, + int width, int height)); +static void DrawMenuSeparator _ANSI_ARGS_((TkMenu *menuPtr, + TkMenuEntry *mePtr, Drawable d, GC gc, + Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, + int x, int y, int width, int height)); +static void DrawTearoffEntry _ANSI_ARGS_((TkMenu *menuPtr, + TkMenuEntry *mePtr, Drawable d, GC gc, + Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, + int x, int y, int width, int height)); +static void FixMDEF _ANSI_ARGS_((void)); +static void GetMenuAccelGeometry _ANSI_ARGS_((TkMenu *menuPtr, + TkMenuEntry *mePtr, Tk_Font tkfont, + CONST Tk_FontMetrics *fmPtr, int *modWidthPtr, + int *textWidthPtr, int *heightPtr)); +static void GetMenuLabelGeometry _ANSI_ARGS_((TkMenuEntry *mePtr, + Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, + int *widthPtr, int *heightPtr)); +static void GetMenuIndicatorGeometry _ANSI_ARGS_(( + TkMenu *menuPtr, TkMenuEntry *mePtr, + Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, + int *widthPtr, int *heightPtr)); +static void GetMenuSeparatorGeometry _ANSI_ARGS_(( + TkMenu *menuPtr, TkMenuEntry *mePtr, + Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, + int *widthPtr, int *heightPtr)); +static void GetTearoffEntryGeometry _ANSI_ARGS_((TkMenu *menuPtr, + TkMenuEntry *mePtr, Tk_Font tkfont, + CONST Tk_FontMetrics *fmPtr, int *widthPtr, + int *heightPtr)); +static int GetNewID _ANSI_ARGS_((Tcl_Interp *interp, + TkMenu *menuInstPtr, int cascade, + short *menuIDPtr)); +static char FindMarkCharacter _ANSI_ARGS_((TkMenuEntry *mePtr)); +static void FreeID _ANSI_ARGS_((short menuID)); +static void InvalidateMDEFRgns _ANSI_ARGS_((void)); +static void MenuDefProc _ANSI_ARGS_((short message, + MenuHandle menu, Rect *menuRectPtr, + Point hitPt, short *whichItem, + TkMenuLowMemGlobals *globalsPtr)); +static void MenuSelectEvent _ANSI_ARGS_((TkMenu *menuPtr)); +static void ReconfigureIndividualMenu _ANSI_ARGS_(( + TkMenu *menuPtr, MenuHandle macMenuHdl, + int base)); +static void ReconfigureMacintoshMenu _ANSI_ARGS_ (( + ClientData clientData)); +static void RecursivelyClearActiveMenu _ANSI_ARGS_(( + TkMenu *menuPtr)); +static void RecursivelyDeleteMenu _ANSI_ARGS_(( + TkMenu *menuPtr)); +static void RecursivelyInsertMenu _ANSI_ARGS_(( + TkMenu *menuPtr)); +static void SetDefaultMenubar _ANSI_ARGS_((void)); +static int SetMenuCascade _ANSI_ARGS_((TkMenu *menuPtr)); +static void SetMenuIndicator _ANSI_ARGS_((TkMenuEntry *mePtr)); + + +/* + *---------------------------------------------------------------------- + * + * TkMacUseID -- + * + * Take the ID out of the available list for new menus. Used by the + * default menu bar's menus so that they do not get created at the tk + * level. See GetNewID for more information. + * + * Results: + * Returns TCL_OK if the id was not in use. Returns TCL_ERROR if the + * id was in use. + * + * Side effects: + * A hash table entry in the command table is created with a NULL + * value. + * + *---------------------------------------------------------------------- + */ + +int +TkMacUseMenuID( + short macID) /* The id to take out of the table */ +{ + Tcl_HashEntry *commandEntryPtr; + int newEntry; + + TkMenuInit(); + commandEntryPtr = Tcl_CreateHashEntry(&commandTable, (char *) macID, + &newEntry); + if (newEntry == 1) { + Tcl_SetHashValue(commandEntryPtr, NULL); + return TCL_OK; + } else { + return TCL_ERROR; + } +} + +/* + *---------------------------------------------------------------------- + * + * GetNewID -- + * + * Allocates a new menu id and marks it in use. Each menu on the + * mac must be designated by a unique id, which is a short. In + * addition, some ids are reserved by the system. Since Tk uses + * mostly dynamic menus, we must allocate and free these ids on + * 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. + * + * Results: + * Returns TCL_OK if succesful; TCL_ERROR if there are no more + * ids of the appropriate type to allocate. menuIDPtr contains + * the new id if succesful. + * + * Side effects: + * An entry is created for the menu in the command hash table, + * and the hash entry is stored in the appropriate field in the + * menu data structure. + * + *---------------------------------------------------------------------- + */ + +static int +GetNewID( + Tcl_Interp *interp, /* Used for error reporting */ + TkMenu *menuPtr, /* The menu we are working with */ + int cascade, /* 0 if we are working with a normal menu; + 1 if we are working with a cascade */ + short *menuIDPtr) /* The resulting id */ +{ + int found = 0; + int newEntry; + Tcl_HashEntry *commandEntryPtr; + short returnID = *menuIDPtr; + + /* + * The following code relies on shorts and unsigned chars wrapping + * when the highest value is incremented. Also, the values between + * 236 and 255 inclusive are reserved for DA's by the Mac OS. + */ + + if (!cascade) { + short curID = lastMenuID + 1; + if (curID == 236) { + curID = 256; + } + + while (curID != lastMenuID) { + commandEntryPtr = Tcl_CreateHashEntry(&commandTable, + (char *) curID, &newEntry); + if (newEntry == 1) { + found = 1; + lastMenuID = returnID = curID; + break; + } + curID++; + if (curID == 236) { + curID = 256; + } + } + } else { + + /* + * Cascade ids must be between 0 and 235 only, so they must be + * dealt with separately. + */ + + unsigned char curID = lastCascadeID + 1; + if (curID == 236) { + curID = 0; + } + + while (curID != lastCascadeID) { + commandEntryPtr = Tcl_CreateHashEntry(&commandTable, + (char *) curID, &newEntry); + if (newEntry == 1) { + found = 1; + lastCascadeID = returnID = curID; + break; + } + curID++; + if (curID == 236) { + curID = 0; + } + } + } + + if (found) { + Tcl_SetHashValue(commandEntryPtr, (char *) menuPtr); + *menuIDPtr = returnID; + return TCL_OK; + } else { + Tcl_AppendResult(interp, "No more menus can be allocated.", + (char *) NULL); + return TCL_ERROR; + } +} + +/* + *---------------------------------------------------------------------- + * + * FreeID -- + * + * Marks the id as free. + * + * Results: + * None. + * + * Side effects: + * The hash table entry for the ID is cleared. + * + *---------------------------------------------------------------------- + */ + +static void +FreeID( + short menuID) /* The id to free */ +{ + Tcl_HashEntry *entryPtr = Tcl_FindHashEntry(&commandTable, + (char *) menuID); + + if (entryPtr != NULL) { + Tcl_DeleteHashEntry(entryPtr); + } + if (menuID == currentAppleMenuID) { + currentAppleMenuID = 0; + } + if (menuID == currentHelpMenuID) { + currentHelpMenuID = 0; + } +} + +/* + *---------------------------------------------------------------------- + * + * TkpNewMenu -- + * + * Gets a new blank menu. Only the platform specific options are filled + * in. + * + * Results: + * Returns a standard TCL error. + * + * Side effects: + * Allocates a Macintosh menu handle and puts in the platformData + * field of the menuPtr. + * + *---------------------------------------------------------------------- + */ + +int +TkpNewMenu( + TkMenu *menuPtr) /* The common structure we are making the + * platform structure for. */ +{ + short menuID; + Str255 itemText; + int length; + MenuHandle macMenuHdl; + int error = TCL_OK; + + error = GetNewID(menuPtr->interp, menuPtr, 0, &menuID); + if (error != TCL_OK) { + return error; + } + length = strlen(Tk_PathName(menuPtr->tkwin)); + memmove(&itemText[1], Tk_PathName(menuPtr->tkwin), + (length > 230) ? 230 : length); + itemText[0] = (length > 230) ? 230 : length; + macMenuHdl = NewMenu(menuID, itemText); +#ifdef GENERATINGCFM + { + Handle mdefProc = GetResource('MDEF', 591); + Handle sicnHandle = GetResource('SICN', SICN_RESOURCE_NUMBER); + if ((mdefProc != NULL) && (sicnHandle != NULL)) { + (*macMenuHdl)->menuProc = mdefProc; + } + } +#endif + menuPtr->platformData = (TkMenuPlatformData) ckalloc(sizeof(MacMenu)); + ((MacMenu *) menuPtr->platformData)->menuHdl = macMenuHdl; + SetRect(&((MacMenu *) menuPtr->platformData)->menuRect, 0, 0, 0, 0); + + if ((currentMenuBarInterp == menuPtr->interp) + && (currentMenuBarName != NULL)) { + Tk_Window parentWin = Tk_Parent(menuPtr->tkwin); + + if (strcmp(currentMenuBarName, Tk_PathName(parentWin)) == 0) { + if ((strcmp(Tk_PathName(menuPtr->tkwin) + + strlen(Tk_PathName(parentWin)), ".apple") == 0) + || (strcmp(Tk_PathName(menuPtr->tkwin) + + strlen(Tk_PathName(parentWin)), ".help") == 0)) { + if (!(menuBarFlags & MENUBAR_REDRAW_PENDING)) { + Tcl_DoWhenIdle(DrawMenuBarWhenIdle, (ClientData *) NULL); + menuBarFlags |= MENUBAR_REDRAW_PENDING; + } + } + } + } + + menuPtr->menuFlags |= MENU_RECONFIGURE_PENDING; + Tcl_DoWhenIdle(ReconfigureMacintoshMenu, (ClientData) menuPtr); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * TkpDestroyMenu -- + * + * Destroys platform-specific menu structures. + * + * Results: + * None. + * + * Side effects: + * All platform-specific allocations are freed up. + * + *---------------------------------------------------------------------- + */ + +void +TkpDestroyMenu( + TkMenu *menuPtr) /* The common menu structure */ +{ + MenuHandle macMenuHdl = ((MacMenu *) menuPtr->platformData)->menuHdl; + + if (menuPtr->menuFlags & MENU_RECONFIGURE_PENDING) { + Tcl_CancelIdleCall(ReconfigureMacintoshMenu, (ClientData) menuPtr); + menuPtr->menuFlags &= ~MENU_RECONFIGURE_PENDING; + } + + if ((*macMenuHdl)->menuID == currentHelpMenuID) { + MenuHandle helpMenuHdl; + + if ((HMGetHelpMenuHandle(&helpMenuHdl) == noErr) + && (helpMenuHdl != NULL)) { + int i, count = CountMItems(helpMenuHdl); + + for (i = helpItemCount; i <= count; i++) { + DeleteMenuItem(helpMenuHdl, helpItemCount); + } + } + currentHelpMenuID = 0; + } + + if (menuPtr->platformData != NULL) { + DeleteMenu((*macMenuHdl)->menuID); + FreeID((*macMenuHdl)->menuID); + DisposeMenu(macMenuHdl); + ckfree((char *) menuPtr->platformData); + menuPtr->platformData = NULL; + } +} + +/* + *---------------------------------------------------------------------- + * + * SetMenuCascade -- + * + * Does any cleanup to change a menu from a normal to a cascade. + * + * Results: + * Standard Tcl error. + * + * Side effects: + * The mac menu id is reset. + * + *---------------------------------------------------------------------- + */ + +static int +SetMenuCascade( + TkMenu* menuPtr) /* The menu we are setting up to be a + * cascade. */ +{ + MenuHandle macMenuHdl = ((MacMenu *) menuPtr->platformData)->menuHdl; + short newMenuID, menuID = (*macMenuHdl)->menuID; + int error = TCL_OK; + + if (menuID >= 256) { + error = GetNewID(menuPtr->interp, menuPtr, 1, &newMenuID); + if (error == TCL_OK) { + FreeID(menuID); + (*macMenuHdl)->menuID = newMenuID; + } + } + return error; +} + +/* + *---------------------------------------------------------------------- + * + * TkpDestroyMenuEntry -- + * + * Cleans up platform-specific menu entry items. + * + * Results: + * None + * + * Side effects: + * All platform-specific allocations are freed up. + * + *---------------------------------------------------------------------- + */ + +void +TkpDestroyMenuEntry( + TkMenuEntry *mePtr) /* The common structure for the menu + * entry. */ +{ + TkMenu *menuPtr = mePtr->menuPtr; + + ckfree((char *) mePtr->platformEntryData); + if ((menuPtr->platformData != NULL) + && !(menuPtr->menuFlags & MENU_RECONFIGURE_PENDING)) { + menuPtr->menuFlags |= MENU_RECONFIGURE_PENDING; + Tcl_DoWhenIdle(ReconfigureMacintoshMenu, (ClientData) menuPtr); + } +} + +/* + *---------------------------------------------------------------------- + * + * GetEntryText -- + * + * Given a menu entry, gives back the text that should go in it. + * Separators should be done by the caller, as they have to be + * handled specially. + * + * Results: + * itemText points to the new text for the item. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static void +GetEntryText( + TkMenuEntry *mePtr, /* A pointer to the menu entry. */ + Str255 itemText) /* The pascal string containing the text */ +{ + if (mePtr->type == TEAROFF_ENTRY) { + strcpy((char *)itemText, (const char *)"\p(Tear-off)"); + } else if (mePtr->imageString != NULL) { + strcpy((char *)itemText, (const char *)"\p(Image)"); + } else if (mePtr->bitmap != None) { + strcpy((char *)itemText, (const char *)"\p(Pixmap)"); + } else if (mePtr->label == NULL || mePtr->labelLength == 0) { + + /* + * The Mac menu manager does not like null strings. + */ + + strcpy((char *)itemText, (const char *)"\p "); + } else { + char *text = mePtr->label; + int i; + + itemText[0] = 0; + for (i = 1; (*text != '\0') && (i <= 230); i++, text++) { + if ((*text == '.') + && (*(text + 1) != '\0') && (*(text + 1) == '.') + && (*(text + 2) != '\0') && (*(text + 2) == '.')) { + itemText[i] = 'É'; + text += 2; + } else { + itemText[i] = *text; + } + itemText[0] += 1; + } + } +} + +/* + *---------------------------------------------------------------------- + * + * FindMarkCharacter -- + * + * Finds the Macintosh mark character based on the font of the + * item. We calculate a good mark character based on the font + * that this item is rendered in. + * + * We try the following special mac characters. If none of them + * are present, just use the check mark. + * '' - Check mark character + * '¥' - Bullet character + * '' - Filled diamond + * '×' - Hollow diamond + * 'Ñ' = Long dash ("em dash") + * '-' = short dash (minus, "en dash"); + * + * Results: + * None. + * + * Side effects: + * New item is added to platform menu + * + *---------------------------------------------------------------------- + */ + +static char +FindMarkCharacter( + TkMenuEntry *mePtr) /* The entry we are finding the character + * for. */ +{ + char markChar; + Tk_Font tkfont = (mePtr->tkfont == NULL) ? mePtr->menuPtr->tkfont + : mePtr->tkfont; + + if (!TkMacIsCharacterMissing(tkfont, '')) { + markChar = ''; + } else if (!TkMacIsCharacterMissing(tkfont, '¥')) { + markChar = '¥'; + } else if (!TkMacIsCharacterMissing(tkfont, '')) { + markChar = ''; + } else if (!TkMacIsCharacterMissing(tkfont, '×')) { + markChar = '×'; + } else if (!TkMacIsCharacterMissing(tkfont, 'Ñ')) { + markChar = 'Ñ'; + } else if (!TkMacIsCharacterMissing(tkfont, '-')) { + markChar = '-'; + } else { + markChar = ''; + } + return markChar; +} + +/* + *---------------------------------------------------------------------- + * + * SetMenuIndicator -- + * + * Sets the Macintosh mark character based on the font of the + * item. + * + * Results: + * None. + * + * Side effects: + * New item is added to platform menu + * + *---------------------------------------------------------------------- + */ + +static void +SetMenuIndicator( + TkMenuEntry *mePtr) /* The entry we are setting */ +{ + TkMenu *menuPtr = mePtr->menuPtr; + MenuHandle macMenuHdl = ((MacMenu *) menuPtr->platformData)->menuHdl; + char markChar; + + /* + * There can be no indicators on menus that are not checkbuttons + * or radiobuttons. However, we should go ahead and set them + * so that menus look right when they are displayed. We should + * not set cascade entries, however, as the mark character + * means something different for cascade items on the Mac. + * Also, we do reflect the tearOff menu items in the Mac menu + * handle, so we ignore them. + */ + + if (mePtr->type == CASCADE_ENTRY) { + return; + } + + if (((mePtr->type == RADIO_BUTTON_ENTRY) + || (mePtr->type == CHECK_BUTTON_ENTRY)) + && (mePtr->indicatorOn) + && (mePtr->entryFlags & ENTRY_SELECTED)) { + markChar = FindMarkCharacter(mePtr); + } else { + markChar = 0; + } + SetItemMark(macMenuHdl, mePtr->index + 1, markChar); +} + +/* + *---------------------------------------------------------------------- + * + * SetMenuTitle -- + * + * Sets title of menu so that the text displays correctly in menubar. + * This code directly manipulates menu handle data. This code + * was originally part of an ancient Apple Developer Response mail. + * + * Results: + * None. + * + * Side effects: + * The menu handle will change size depending on the length of the + * title + * + *---------------------------------------------------------------------- + */ + +static void +SetMenuTitle( + MenuHandle menuHdl, /* The menu we are setting the title of. */ + char *title) /* The C string to set the title to. */ +{ + int oldLength, newLength, oldHandleSize, dataLength; + Ptr menuDataPtr; + + menuDataPtr = (Ptr) (*menuHdl)->menuData; + + if (strncmp(title, menuDataPtr + 1, menuDataPtr[0]) != 0) { + newLength = strlen(title) + 1; + oldLength = menuDataPtr[0] + 1; + oldHandleSize = GetHandleSize((Handle) menuHdl); + dataLength = oldHandleSize - (sizeof(MenuInfo) - sizeof(Str255)) + - oldLength; + if (newLength > oldLength) { + SetHandleSize((Handle) menuHdl, oldHandleSize + (newLength + - oldLength)); + menuDataPtr = (Ptr) (*menuHdl)->menuData; + } + + BlockMove(menuDataPtr + oldLength, menuDataPtr + newLength, + dataLength); + BlockMove(title, menuDataPtr + 1, newLength - 1); + menuDataPtr[0] = newLength - 1; + + if (newLength < oldLength) { + SetHandleSize((Handle) menuHdl, oldHandleSize + (newLength + - oldLength)); + } + } +} + +/* + *---------------------------------------------------------------------- + * + * TkpConfigureMenuEntry -- + * + * Processes configurations for menu entries. + * + * Results: + * Returns standard TCL result. If TCL_ERROR is returned, then + * interp->result contains an error message. + * + * Side effects: + * Configuration information get set for mePtr; old resources + * get freed, if any need it. + * + *---------------------------------------------------------------------- + */ + +int +TkpConfigureMenuEntry( + register TkMenuEntry *mePtr) /* Information about menu entry; may + * or may not already have values for + * some fields. */ +{ + TkMenu *menuPtr = mePtr->menuPtr; + int index = mePtr->index; + MenuHandle macMenuHdl = ((MacMenu *) menuPtr->platformData)->menuHdl; + MenuHandle helpMenuHdl = NULL; + + /* + * Cascade menus have to have menu IDs of less than 256. So + * we need to change the child menu if this has been configured + * for a cascade item. + */ + + if (mePtr->type == CASCADE_ENTRY) { + if ((mePtr->childMenuRefPtr != NULL) + && (mePtr->childMenuRefPtr->menuPtr != NULL)) { + MenuHandle childMenuHdl = ((MacMenu *) mePtr + ->childMenuRefPtr->menuPtr->platformData)->menuHdl; + + if (childMenuHdl != NULL) { + int error = SetMenuCascade(mePtr->childMenuRefPtr->menuPtr); + + if (error != TCL_OK) { + return error; + } + + if (menuPtr->menuType == MENUBAR) { + SetMenuTitle(childMenuHdl, mePtr->label); + } + } + } + } + + /* + * We need to parse the accelerator string. If it has the strings + * for Command, Control, Shift or Option, we need to flag it + * so we can draw the symbols for it. We also need to precalcuate + * the position of the first real character we are drawing. + */ + + if (0 == mePtr->accelLength) { + ((EntryGeometry *)mePtr->platformEntryData)->accelTextStart = -1; + } else { + char *accelString = mePtr->accel; + mePtr->entryFlags |= ~ENTRY_ACCEL_MASK; + + while (1) { + if ((0 == strncasecmp("Control", accelString, 6)) + && (('-' == accelString[6]) || ('+' == accelString[6]))) { + mePtr->entryFlags |= ENTRY_CONTROL_ACCEL; + accelString += 7; + } else if ((0 == strncasecmp("Ctrl", accelString, 4)) + && (('-' == accelString[4]) || ('+' == accelString[4]))) { + mePtr->entryFlags |= ENTRY_CONTROL_ACCEL; + accelString += 5; + } else if ((0 == strncasecmp("Shift", accelString, 5)) + && (('-' == accelString[5]) || ('+' == accelString[5]))) { + mePtr->entryFlags |= ENTRY_SHIFT_ACCEL; + accelString += 6; + } else if ((0 == strncasecmp("Option", accelString, 6)) + && (('-' == accelString[6]) || ('+' == accelString[6]))) { + mePtr->entryFlags |= ENTRY_OPTION_ACCEL; + accelString += 7; + } else if ((0 == strncasecmp("Opt", accelString, 3)) + && (('-' == accelString[3]) || ('+' == accelString[3]))) { + mePtr->entryFlags |= ENTRY_OPTION_ACCEL; + accelString += 4; + } else if ((0 == strncasecmp("Command", accelString, 7)) + && (('-' == accelString[7]) || ('+' == accelString[7]))) { + mePtr->entryFlags |= ENTRY_COMMAND_ACCEL; + accelString += 8; + } else if ((0 == strncasecmp("Cmd", accelString, 3)) + && (('-' == accelString[3]) || ('+' == accelString[3]))) { + mePtr->entryFlags |= ENTRY_COMMAND_ACCEL; + accelString += 4; + } else if ((0 == strncasecmp("Alt", accelString, 3)) + && (('-' == accelString[3]) || ('+' == accelString[3]))) { + mePtr->entryFlags |= ENTRY_OPTION_ACCEL; + accelString += 4; + } else if ((0 == strncasecmp("Meta", accelString, 4)) + && (('-' == accelString[4]) || ('+' == accelString[4]))) { + mePtr->entryFlags |= ENTRY_COMMAND_ACCEL; + accelString += 5; + } else { + break; + } + } + + ((EntryGeometry *)mePtr->platformEntryData)->accelTextStart + = ((long) accelString - (long) mePtr->accel); + } + + if (!(menuPtr->menuFlags & MENU_RECONFIGURE_PENDING)) { + menuPtr->menuFlags |= MENU_RECONFIGURE_PENDING; + Tcl_DoWhenIdle(ReconfigureMacintoshMenu, (ClientData) menuPtr); + } + + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * ReconfigureIndividualMenu -- + * + * This routine redoes the guts of the menu. It works from + * a base item and offset, so that a regular menu will + * just have all of its items added, but the help menu will + * have all of its items appended after the apple-defined + * items. + * + * Results: + * None. + * + * Side effects: + * The Macintosh menu handle is updated + * + *---------------------------------------------------------------------- + */ + +static void +ReconfigureIndividualMenu( + TkMenu *menuPtr, /* The menu we are affecting. */ + MenuHandle macMenuHdl, /* The macintosh menu we are affecting. + * Will not necessarily be + * menuPtr->platformData because this could + * be the help menu. */ + int base) /* The last index that we do not want + * touched. 0 for normal menus; + * helpMenuItemCount for help menus. */ +{ + int count; + int index; + TkMenuEntry *mePtr; + Str255 itemText; + int parentDisabled = 0; + + for (mePtr = menuPtr->menuRefPtr->parentEntryPtr; mePtr != NULL; + mePtr = mePtr->nextCascadePtr) { + if (strcmp(Tk_PathName(menuPtr->tkwin), mePtr->name) == 0) { + if (mePtr->state == tkDisabledUid) { + parentDisabled = 1; + } + break; + } + } + + /* + * First, we get rid of all of the old items. + */ + + count = CountMItems(macMenuHdl); + for (index = base; index < count; index++) { + DeleteMenuItem(macMenuHdl, base + 1); + } + + count = menuPtr->numEntries; + + for (index = 1; index <= count; index++) { + mePtr = menuPtr->entries[index - 1]; + + /* + * We have to do separators separately because SetMenuItemText + * does not parse meta-characters. + */ + + if (mePtr->type == SEPARATOR_ENTRY) { + AppendMenu(macMenuHdl, SEPARATOR_TEXT); + } else { + GetEntryText(mePtr, itemText); + AppendMenu(macMenuHdl, "\px"); + SetMenuItemText(macMenuHdl, base + index, itemText); + + /* + * Set enabling and disabling correctly. + */ + + if (parentDisabled || (mePtr->state == tkDisabledUid)) { + DisableItem(macMenuHdl, base + index); + } else { + EnableItem(macMenuHdl, base + index); + } + + /* + * Set the check mark for check entries and radio entries. + */ + + SetItemMark(macMenuHdl, base + index, 0); + if ((mePtr->type == CHECK_BUTTON_ENTRY) + || (mePtr->type == RADIO_BUTTON_ENTRY)) { + CheckItem(macMenuHdl, base + index, (mePtr->entryFlags + & ENTRY_SELECTED) && (mePtr->indicatorOn)); + if ((mePtr->indicatorOn) + && (mePtr->entryFlags & ENTRY_SELECTED)) { + SetItemMark(macMenuHdl, base + index, + FindMarkCharacter(mePtr)); + } + } + + if (mePtr->type == CASCADE_ENTRY) { + if ((mePtr->childMenuRefPtr != NULL) + && (mePtr->childMenuRefPtr->menuPtr != NULL)) { + MenuHandle childMenuHdl = + ((MacMenu *) mePtr->childMenuRefPtr + ->menuPtr->platformData)->menuHdl; + + if (childMenuHdl == NULL) { + childMenuHdl = ((MacMenu *) mePtr->childMenuRefPtr + ->menuPtr->platformData)->menuHdl; + } + if (childMenuHdl != NULL) { + SetItemMark(macMenuHdl, base + index, + (*childMenuHdl)->menuID); + SetItemCmd(macMenuHdl, base + index, CASCADE_CMD); + } + /* + * If we changed the highligthing of this menu, its + * children all have to be reconfigured so that + * their state will be reflected in the menubar. + */ + + if (!(mePtr->childMenuRefPtr->menuPtr->menuFlags + & MENU_RECONFIGURE_PENDING)) { + mePtr->childMenuRefPtr->menuPtr->menuFlags + |= MENU_RECONFIGURE_PENDING; + Tcl_DoWhenIdle(ReconfigureMacintoshMenu, + (ClientData) mePtr->childMenuRefPtr->menuPtr); + } + } + } + + if ((mePtr->type != CASCADE_ENTRY) + && (ENTRY_COMMAND_ACCEL + == (mePtr->entryFlags & ENTRY_ACCEL_MASK))) { + SetItemCmd(macMenuHdl, index, mePtr + ->accel[((EntryGeometry *)mePtr->platformEntryData) + ->accelTextStart]); + } + } + } +} + +/* + *---------------------------------------------------------------------- + * + * ReconfigureMacintoshMenu -- + * + * Rebuilds the Macintosh MenuHandle items from the menu. Called + * usually as an idle handler, but can be called synchronously + * if the menu is about to be posted. + * + * Results: + * None. + * + * Side effects: + * Configuration information get set for mePtr; old resources + * get freed, if any need it. + * + *---------------------------------------------------------------------- + */ + +static void +ReconfigureMacintoshMenu( + ClientData clientData) /* Information about menu entry; may + * or may not already have values for + * some fields. */ +{ + TkMenu *menuPtr = (TkMenu *) clientData; + MenuHandle macMenuHdl = ((MacMenu *) menuPtr->platformData)->menuHdl; + MenuHandle helpMenuHdl = NULL; + + menuPtr->menuFlags &= ~MENU_RECONFIGURE_PENDING; + + if (NULL == macMenuHdl) { + return; + } + + ReconfigureIndividualMenu(menuPtr, macMenuHdl, 0); + + if (menuPtr->menuFlags & MENU_APPLE_MENU) { + AddResMenu(macMenuHdl, 'DRVR'); + } + + if ((*macMenuHdl)->menuID == currentHelpMenuID) { + HMGetHelpMenuHandle(&helpMenuHdl); + if (helpMenuHdl != NULL) { + ReconfigureIndividualMenu(menuPtr, helpMenuHdl, helpItemCount); + } + } + + if (menuPtr->menuType == MENUBAR) { + if (!(menuBarFlags & MENUBAR_REDRAW_PENDING)) { + Tcl_DoWhenIdle(DrawMenuBarWhenIdle, (ClientData *) NULL); + menuBarFlags |= MENUBAR_REDRAW_PENDING; + } + } +} + +/* + *---------------------------------------------------------------------- + * + * CompleteIdlers -- + * + * Completes all idle handling so that the menus are in sync when + * the user invokes them with the mouse. + * + * Results: + * None. + * + * Side effects: + * The Macintosh menu handles are flushed out. + * + *---------------------------------------------------------------------- + */ + +static void +CompleteIdlers( + TkMenu *menuPtr) /* The menu we are completing. */ +{ + int i; + + if (menuPtr->menuFlags & MENU_RECONFIGURE_PENDING) { + Tcl_CancelIdleCall(ReconfigureMacintoshMenu, (ClientData) menuPtr); + ReconfigureMacintoshMenu((ClientData) menuPtr); + } + + for (i = 0; i < menuPtr->numEntries; i++) { + if (menuPtr->entries[i]->type == CASCADE_ENTRY) { + if ((menuPtr->entries[i]->childMenuRefPtr != NULL) + && (menuPtr->entries[i]->childMenuRefPtr->menuPtr + != NULL)) { + CompleteIdlers(menuPtr->entries[i]->childMenuRefPtr + ->menuPtr); + } + } + } +} + +/* + *---------------------------------------------------------------------- + * + * TkpPostMenu -- + * + * Posts a menu on the screen + * + * Results: + * None. + * + * Side effects: + * The menu is posted and handled. + * + *---------------------------------------------------------------------- + */ + +int +TkpPostMenu( + Tcl_Interp *interp, /* The interpreter this menu lives in */ + 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 */ +{ + MenuHandle macMenuHdl = ((MacMenu *) menuPtr->platformData)->menuHdl; + long popUpResult; + int result; + int oldMode; + + if (inPostMenu) { + Tcl_AppendResult(interp, + "Cannot call post menu while already posting menu", + (char *) NULL); + result = TCL_ERROR; + } else { + Window dummyWin; + unsigned int state; + int dummy, mouseX, mouseY; + short menuID; + Window window; + int oldWidth = menuPtr->totalWidth; + Tk_Window parentWindow = Tk_Parent(menuPtr->tkwin); + + inPostMenu++; + + result = TkPreprocessMenu(menuPtr); + if (result != TCL_OK) { + inPostMenu--; + return result; + } + + /* + * The post commands could have deleted the menu, which means + * we are dead and should go away. + */ + + if (menuPtr->tkwin == NULL) { + inPostMenu--; + return TCL_OK; + } + + CompleteIdlers(menuPtr); + if (menuBarFlags & MENUBAR_REDRAW_PENDING) { + Tcl_CancelIdleCall(DrawMenuBarWhenIdle, (ClientData *) NULL); + DrawMenuBarWhenIdle((ClientData *) NULL); + } + + if (NULL == parentWindow) { + tearoffStruct.excludeRect.top = tearoffStruct.excludeRect.left + = tearoffStruct.excludeRect.bottom + = tearoffStruct.excludeRect.right = SHRT_MAX; + } else { + int left, top; + + Tk_GetRootCoords(parentWindow, &left, &top); + tearoffStruct.excludeRect.left = left; + tearoffStruct.excludeRect.top = top; + tearoffStruct.excludeRect.right = left + Tk_Width(parentWindow); + tearoffStruct.excludeRect.bottom = top + Tk_Height(parentWindow); + if (Tk_Class(parentWindow) == Tk_GetUid("Menubutton")) { + TkWindow *parentWinPtr = (TkWindow *) parentWindow; + TkMenuButton *mbPtr = + (TkMenuButton *) parentWinPtr->instanceData; + int menuButtonWidth = Tk_Width(parentWindow) + - 2 * (mbPtr->highlightWidth + mbPtr->borderWidth + 1); + menuPtr->totalWidth = menuButtonWidth > menuPtr->totalWidth + ? menuButtonWidth : menuPtr->totalWidth; + } + } + + InsertMenu(macMenuHdl, -1); + RecursivelyInsertMenu(menuPtr); + CountMItems(macMenuHdl); + + FixMDEF(); + oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL); + popUpResult = PopUpMenuSelect(macMenuHdl, y, x, menuPtr->active); + Tcl_SetServiceMode(oldMode); + + menuPtr->totalWidth = oldWidth; + RecursivelyDeleteMenu(menuPtr); + DeleteMenu((*macMenuHdl)->menuID); + + /* + * Simulate the mouse up. + */ + + XQueryPointer(NULL, None, &dummyWin, &dummyWin, &mouseX, + &mouseY, &dummy, &dummy, &state); + window = Tk_WindowId(menuPtr->tkwin); + TkGenerateButtonEvent(mouseX, mouseY, window, state); + + /* + * Dispatch the command. + */ + + menuID = HiWord(popUpResult); + if (menuID != 0) { + result = TkMacDispatchMenuEvent(menuID, LoWord(popUpResult)); + } else { + TkMacHandleTearoffMenu(); + result = TCL_OK; + } + InvalidateMDEFRgns(); + RecursivelyClearActiveMenu(menuPtr); + + inPostMenu--; + } + return result; +} + +/* + *---------------------------------------------------------------------- + * + * TkpMenuNewEntry -- + * + * Adds a pointer to a new menu entry structure with the platform- + * specific fields filled in. The Macintosh uses the + * platformEntryData field of the TkMenuEntry record to store + * geometry information. + * + * Results: + * Standard TCL error. + * + * Side effects: + * Storage gets allocated. New menu entry data is put into the + * platformEntryData field of the mePtr. + * + *---------------------------------------------------------------------- + */ + +int +TkpMenuNewEntry( + TkMenuEntry *mePtr) /* The menu we are adding an entry to */ +{ + EntryGeometry *geometryPtr = + (EntryGeometry *) ckalloc(sizeof(EntryGeometry)); + TkMenu *menuPtr = mePtr->menuPtr; + + geometryPtr->accelTextStart = 0; + geometryPtr->accelTextWidth = 0; + geometryPtr->nonAccelMargin = 0; + geometryPtr->modifierWidth = 0; + mePtr->platformEntryData = (TkMenuPlatformEntryData) geometryPtr; + if (!(menuPtr->menuFlags & MENU_RECONFIGURE_PENDING)) { + menuPtr->menuFlags |= MENU_RECONFIGURE_PENDING; + Tcl_DoWhenIdle(ReconfigureMacintoshMenu, (ClientData) menuPtr); + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * + * DrawMenuBarWhenIdle -- + * + * Update the menu bar next time there is an idle event. + * + * Results: + * None. + * + * Side effects: + * Menu bar is redrawn. + * + *---------------------------------------------------------------------- + */ + +static void +DrawMenuBarWhenIdle( + ClientData clientData) /* ignored here */ +{ + TkMenuReferences *menuRefPtr; + TkMenu *appleMenuPtr, *helpMenuPtr; + MenuHandle macMenuHdl; + Tcl_HashEntry *hashEntryPtr; + + /* + * We need to clear the apple and help menus of any extra items. + */ + + if (currentAppleMenuID != 0) { + hashEntryPtr = Tcl_FindHashEntry(&commandTable, + (char *) currentAppleMenuID); + appleMenuPtr = (TkMenu *) Tcl_GetHashValue(hashEntryPtr); + TkpDestroyMenu(appleMenuPtr); + TkpNewMenu(appleMenuPtr); + appleMenuPtr->menuFlags &= ~MENU_APPLE_MENU; + appleMenuPtr->menuFlags |= MENU_RECONFIGURE_PENDING; + Tcl_DoWhenIdle(ReconfigureMacintoshMenu, + (ClientData) appleMenuPtr); + } + + if (currentHelpMenuID != 0) { + hashEntryPtr = Tcl_FindHashEntry(&commandTable, + (char *) currentHelpMenuID); + helpMenuPtr = (TkMenu *) Tcl_GetHashValue(hashEntryPtr); + TkpDestroyMenu(helpMenuPtr); + TkpNewMenu(helpMenuPtr); + helpMenuPtr->menuFlags &= ~MENU_HELP_MENU; + helpMenuPtr->menuFlags |= MENU_RECONFIGURE_PENDING; + Tcl_DoWhenIdle(ReconfigureMacintoshMenu, + (ClientData) helpMenuPtr); + } + + /* + * We need to find the clone of this menu that is the menubar. + * Once we do that, for every cascade in the menu, we need to + * insert the Mac menu in the Mac menubar. Finally, we need + * to redraw the menubar. + */ + + menuRefPtr = NULL; + if (currentMenuBarName != NULL) { + menuRefPtr = TkFindMenuReferences(currentMenuBarInterp, + currentMenuBarName); + } + if (menuRefPtr != NULL) { + TkMenu *menuPtr, *menuBarPtr; + TkMenu *cascadeMenuPtr; + char *appleMenuName, *helpMenuName; + int appleIndex = -1, helpIndex = -1; + int i; + + menuPtr = menuRefPtr->menuPtr; + if (menuPtr != NULL) { + TkMenuReferences *specialMenuRefPtr; + TkMenuEntry *specialEntryPtr; + + appleMenuName = ckalloc(strlen(currentMenuBarName) + + 1 + strlen(".apple") + 1); + sprintf(appleMenuName, "%s.apple", + Tk_PathName(menuPtr->tkwin)); + specialMenuRefPtr = TkFindMenuReferences(currentMenuBarInterp, + appleMenuName); + if ((specialMenuRefPtr != NULL) + && (specialMenuRefPtr->menuPtr != NULL)) { + for (specialEntryPtr + = specialMenuRefPtr->parentEntryPtr; + specialEntryPtr != NULL; + specialEntryPtr + = specialEntryPtr->nextCascadePtr) { + if (specialEntryPtr->menuPtr == menuPtr) { + appleIndex = specialEntryPtr->index; + break; + } + } + } + ckfree(appleMenuName); + + helpMenuName = ckalloc(strlen(currentMenuBarName) + + 1 + strlen(".help") + 1); + sprintf(helpMenuName, "%s.help", + Tk_PathName(menuPtr->tkwin)); + specialMenuRefPtr = TkFindMenuReferences(currentMenuBarInterp, + helpMenuName); + if ((specialMenuRefPtr != NULL) + && (specialMenuRefPtr->menuPtr != NULL)) { + for (specialEntryPtr + = specialMenuRefPtr->parentEntryPtr; + specialEntryPtr != NULL; + specialEntryPtr + = specialEntryPtr->nextCascadePtr) { + if (specialEntryPtr->menuPtr == menuPtr) { + helpIndex = specialEntryPtr->index; + break; + } + } + } + ckfree(helpMenuName); + + } + + for (menuBarPtr = menuPtr; + (menuBarPtr != NULL) + && (menuBarPtr->menuType != MENUBAR); + menuBarPtr = menuBarPtr->nextInstancePtr) { + + /* + * Null loop body. + */ + + } + + if (menuBarPtr == NULL) { + SetDefaultMenubar(); + } else { + if (menuBarPtr->tearOff != menuPtr->tearOff) { + if (menuBarPtr->tearOff) { + appleIndex = (-1 == appleIndex) ? appleIndex + : appleIndex + 1; + helpIndex = (-1 == helpIndex) ? helpIndex + : helpIndex + 1; + } else { + appleIndex = (-1 == appleIndex) ? appleIndex + : appleIndex - 1; + helpIndex = (-1 == helpIndex) ? helpIndex + : helpIndex - 1; + } + } + ClearMenuBar(); + + if (appleIndex == -1) { + InsertMenu(tkAppleMenu, 0); + currentAppleMenuID = 0; + } else { + short appleID; + appleMenuPtr = menuBarPtr->entries[appleIndex] + ->childMenuRefPtr->menuPtr; + TkpDestroyMenu(appleMenuPtr); + GetNewID(appleMenuPtr->interp, appleMenuPtr, 0, + &appleID); + macMenuHdl = NewMenu(appleID, "\p\024"); + appleMenuPtr->platformData = + (TkMenuPlatformData) ckalloc(sizeof(MacMenu)); + ((MacMenu *)appleMenuPtr->platformData)->menuHdl + = macMenuHdl; + SetRect(&((MacMenu *) appleMenuPtr->platformData)->menuRect, + 0, 0, 0, 0); + appleMenuPtr->menuFlags |= MENU_APPLE_MENU; + if (!(appleMenuPtr->menuFlags + & MENU_RECONFIGURE_PENDING)) { + appleMenuPtr->menuFlags |= MENU_RECONFIGURE_PENDING; + Tcl_DoWhenIdle(ReconfigureMacintoshMenu, + (ClientData) appleMenuPtr); + } + InsertMenu(macMenuHdl, 0); + RecursivelyInsertMenu(appleMenuPtr); + currentAppleMenuID = appleID; + } + if (helpIndex == -1) { + currentHelpMenuID = 0; + } + + for (i = 0; i < menuBarPtr->numEntries; i++) { + if (i == appleIndex) { + if (menuBarPtr->entries[i]->state == tkDisabledUid) { + DisableItem(((MacMenu *) menuBarPtr->entries[i] + ->childMenuRefPtr->menuPtr + ->platformData)->menuHdl, + 0); + } else { + EnableItem(((MacMenu *) menuBarPtr->entries[i] + ->childMenuRefPtr->menuPtr + ->platformData)->menuHdl, + 0); + } + continue; + } else if (i == helpIndex) { + TkMenu *helpMenuPtr = menuBarPtr->entries[i] + ->childMenuRefPtr->menuPtr; + MenuHandle helpMenuHdl = NULL; + + if (helpMenuPtr == NULL) { + continue; + } + helpMenuPtr->menuFlags |= MENU_HELP_MENU; + if (!(helpMenuPtr->menuFlags + & MENU_RECONFIGURE_PENDING)) { + helpMenuPtr->menuFlags + |= MENU_RECONFIGURE_PENDING; + Tcl_DoWhenIdle(ReconfigureMacintoshMenu, + (ClientData) helpMenuPtr); + } + macMenuHdl = + ((MacMenu *) helpMenuPtr->platformData)->menuHdl; + currentHelpMenuID = (*macMenuHdl)->menuID; + } else if (menuBarPtr->entries[i]->type + == CASCADE_ENTRY) { + if ((menuBarPtr->entries[i]->childMenuRefPtr != NULL) + && menuBarPtr->entries[i]->childMenuRefPtr + ->menuPtr != NULL) { + cascadeMenuPtr = menuBarPtr->entries[i] + ->childMenuRefPtr->menuPtr; + macMenuHdl = ((MacMenu *) cascadeMenuPtr + ->platformData)->menuHdl; + DeleteMenu((*macMenuHdl)->menuID); + InsertMenu(macMenuHdl, 0); + RecursivelyInsertMenu(cascadeMenuPtr); + if (menuBarPtr->entries[i]->state == tkDisabledUid) { + DisableItem(((MacMenu *) menuBarPtr->entries[i] + ->childMenuRefPtr->menuPtr + ->platformData)->menuHdl, + 0); + } else { + EnableItem(((MacMenu *) menuBarPtr->entries[i] + ->childMenuRefPtr->menuPtr + ->platformData)->menuHdl, + 0); + } + } + } + } + } + } else { + SetDefaultMenubar(); + } + DrawMenuBar(); + menuBarFlags &= ~MENUBAR_REDRAW_PENDING; +} + + +/* + *---------------------------------------------------------------------- + * + * RecursivelyInsertMenu -- + * + * Puts all of the cascades of this menu in the Mac hierarchical list. + * + * + * Results: + * None. + * + * Side effects: + * The menubar is changed. + * + *---------------------------------------------------------------------- + */ + +static void +RecursivelyInsertMenu( + TkMenu *menuPtr) /* All of the cascade items in this menu + * will be inserted into the mac menubar. */ +{ + int i; + TkMenu *cascadeMenuPtr; + MenuHandle macMenuHdl; + + for (i = 0; i < menuPtr->numEntries; i++) { + if (menuPtr->entries[i]->type == CASCADE_ENTRY) { + if ((menuPtr->entries[i]->childMenuRefPtr != NULL) + && (menuPtr->entries[i]->childMenuRefPtr->menuPtr + != NULL)) { + cascadeMenuPtr = menuPtr->entries[i]->childMenuRefPtr->menuPtr; + macMenuHdl = ((MacMenu *) cascadeMenuPtr->platformData)->menuHdl; + InsertMenu(macMenuHdl, -1); + RecursivelyInsertMenu(cascadeMenuPtr); + } + } + } +} + +/* + *---------------------------------------------------------------------- + * + * RecursivelyDeleteMenu -- + * + * Takes all of the cascades of this menu out of the Mac hierarchical + * list. + * + * + * Results: + * None. + * + * Side effects: + * The menubar is changed. + * + *---------------------------------------------------------------------- + */ + +static void +RecursivelyDeleteMenu( + TkMenu *menuPtr) /* All of the cascade items in this menu + * will be inserted into the mac menubar. */ +{ + int i; + TkMenu *cascadeMenuPtr; + MenuHandle macMenuHdl; + + for (i = 0; i < menuPtr->numEntries; i++) { + if (menuPtr->entries[i]->type == CASCADE_ENTRY) { + if ((menuPtr->entries[i]->childMenuRefPtr != NULL) + && (menuPtr->entries[i]->childMenuRefPtr->menuPtr + != NULL)) { + cascadeMenuPtr = menuPtr->entries[i]->childMenuRefPtr->menuPtr; + macMenuHdl = ((MacMenu *) cascadeMenuPtr->platformData)->menuHdl; + DeleteMenu((*macMenuHdl)->menuID); + RecursivelyInsertMenu(cascadeMenuPtr); + } + } + } +} + +/* + *---------------------------------------------------------------------- + * + * SetDefaultMenubar -- + * + * Puts the Apple, File and Edit menus into the Macintosh menubar. + * + * Results: + * None. + * + * Side effects: + * The menubar is changed. + * + *---------------------------------------------------------------------- + */ + +static void +SetDefaultMenubar() +{ + if (currentMenuBarName != NULL) { + ckfree(currentMenuBarName); + currentMenuBarName = NULL; + } + currentMenuBarOwner = NULL; + ClearMenuBar(); + InsertMenu(tkAppleMenu, 0); + InsertMenu(tkFileMenu, 0); + InsertMenu(tkEditMenu, 0); + if (!(menuBarFlags & MENUBAR_REDRAW_PENDING)) { + Tcl_DoWhenIdle(DrawMenuBarWhenIdle, (ClientData *) NULL); + menuBarFlags |= MENUBAR_REDRAW_PENDING; + } +} + +/* + *---------------------------------------------------------------------- + * + * TkpSetMainMenubar -- + * + * Puts the menu associated with a window into the menubar. Should + * only be called when the window is in front. + * + * Results: + * None. + * + * Side effects: + * The menubar is changed. + * + *---------------------------------------------------------------------- + */ + +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. + */ +{ + TkWindow *winPtr = (TkWindow *) tkwin; + WindowRef macWindowPtr = (WindowRef) TkMacGetDrawablePort(winPtr->window); + + if ((macWindowPtr == NULL) || (macWindowPtr != FrontWindow())) { + return; + } + + if ((currentMenuBarInterp != interp) + || (currentMenuBarOwner != tkwin) + || (currentMenuBarName == NULL) + || (menuName == NULL) + || (strcmp(menuName, currentMenuBarName) != 0)) { + Tk_Window searchWindow; + TopLevelMenubarList *listPtr; + + if (currentMenuBarName != NULL) { + ckfree(currentMenuBarName); + } + + if (menuName == NULL) { + searchWindow = tkwin; + if (strcmp(Tk_Class(searchWindow), "Menu") == 0) { + TkMenuReferences *menuRefPtr; + + menuRefPtr = TkFindMenuReferences(interp, Tk_PathName(tkwin)); + if (menuRefPtr != NULL) { + TkMenu *menuPtr = menuRefPtr->menuPtr; + if (menuPtr != NULL) { + menuPtr = menuPtr->masterMenuPtr; + searchWindow = menuPtr->tkwin; + } + } + } + for (; searchWindow != NULL; + searchWindow = Tk_Parent(searchWindow)) { + + for (listPtr = windowListPtr; listPtr != NULL; + listPtr = listPtr->nextPtr) { + if (listPtr->tkwin == searchWindow) { + break; + } + } + if (listPtr != NULL) { + menuName = Tk_PathName(listPtr->menuPtr->masterMenuPtr->tkwin); + break; + } + } + } + + if (menuName == NULL) { + currentMenuBarName = NULL; + } else { + currentMenuBarName = ckalloc(strlen(menuName) + 1); + strcpy(currentMenuBarName, menuName); + } + currentMenuBarOwner = tkwin; + currentMenuBarInterp = interp; + } + if (!(menuBarFlags & MENUBAR_REDRAW_PENDING)) { + Tcl_DoWhenIdle(DrawMenuBarWhenIdle, (ClientData *) NULL); + menuBarFlags |= MENUBAR_REDRAW_PENDING; + } +} + +/* + *---------------------------------------------------------------------- + * + * TkpSetWindowMenuBar -- + * + * Associates a given menu with a window. + * + * Results: + * None. + * + * Side effects: + * On Windows and UNIX, associates the platform menu with the + * platform window. + * + *---------------------------------------------------------------------- + */ + +void +TkpSetWindowMenuBar( + Tk_Window tkwin, /* The window we are setting the menu in */ + TkMenu *menuPtr) /* The menu we are setting */ +{ + TopLevelMenubarList *listPtr, *prevPtr; + + /* + * Remove any existing reference to this window. + */ + + for (prevPtr = NULL, listPtr = windowListPtr; + listPtr != NULL; + prevPtr = listPtr, listPtr = listPtr->nextPtr) { + if (listPtr->tkwin == tkwin) { + break; + } + } + + if (listPtr != NULL) { + if (prevPtr != NULL) { + prevPtr->nextPtr = listPtr->nextPtr; + } else { + windowListPtr = listPtr->nextPtr; + } + ckfree((char *) listPtr); + } + + if (menuPtr != NULL) { + listPtr = (TopLevelMenubarList *) ckalloc(sizeof(TopLevelMenubarList)); + listPtr->nextPtr = windowListPtr; + windowListPtr = listPtr; + listPtr->tkwin = tkwin; + listPtr->menuPtr = menuPtr; + } +} + +/* + *---------------------------------------------------------------------- + * + * TkMacDispatchMenuEvent -- + * + * Given a menu id and an item, dispatches the command associated + * with it. + * + * Results: + * None. + * + * Side effects: + * Commands get executed. + * + *---------------------------------------------------------------------- + */ + +int +TkMacDispatchMenuEvent( + int menuID, /* The menu id of the menu we are invoking */ + int index) /* The one-based index of the item that was + * selected. */ +{ + int result = TCL_OK; + if (menuID != 0) { + if (menuID == kHMHelpMenuID) { + if (currentMenuBarOwner != NULL) { + TkMenuReferences *helpMenuRef; + char *helpMenuName = ckalloc(strlen(currentMenuBarName) + + strlen(".help") + 1); + sprintf(helpMenuName, "%s.help", currentMenuBarName); + helpMenuRef = TkFindMenuReferences(currentMenuBarInterp, + helpMenuName); + ckfree(helpMenuName); + if ((helpMenuRef != NULL) && (helpMenuRef->menuPtr != NULL)) { + int newIndex = index - helpItemCount - 1; + result = TkInvokeMenu(currentMenuBarInterp, + helpMenuRef->menuPtr, newIndex); + } + } + } else { + Tcl_HashEntry *commandEntryPtr = + Tcl_FindHashEntry(&commandTable, (char *) menuID); + TkMenu *menuPtr = (TkMenu *) Tcl_GetHashValue(commandEntryPtr); + if ((currentAppleMenuID == menuID) + && (index > menuPtr->numEntries + 1)) { + Str255 itemText; + + GetMenuItemText(GetMenuHandle(menuID), index, itemText); + OpenDeskAcc(itemText); + result = TCL_OK; + } else { + result = TkInvokeMenu(menuPtr->interp, menuPtr, index - 1); + } + } + } + return result; +} + +/* + *---------------------------------------------------------------------- + * + * GetMenuIndicatorGeometry -- + * + * Gets the width and height of the indicator area of a menu. + * + * Results: + * widthPtr and heightPtr are set. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static void +GetMenuIndicatorGeometry ( + TkMenu *menuPtr, /* The menu we are drawing */ + TkMenuEntry *mePtr, /* The entry we are measuring */ + Tk_Font tkfont, /* Precalculated font */ + CONST Tk_FontMetrics *fmPtr, /* Precalculated font metrics */ + int *widthPtr, /* The resulting width */ + int *heightPtr) /* The resulting height */ +{ + char markChar; + + *heightPtr = fmPtr->linespace; + + markChar = (char) FindMarkCharacter(mePtr); + *widthPtr = Tk_TextWidth(tkfont, &markChar, 1) + 4; +} + +/* + *---------------------------------------------------------------------- + * + * GetMenuAccelGeometry -- + * + * Gets the width and height of the accelerator area of a menu. + * + * Results: + * widthPtr and heightPtr are set. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static void +GetMenuAccelGeometry ( + TkMenu *menuPtr, /* The menu we are measuring */ + TkMenuEntry *mePtr, /* The entry we are measuring */ + Tk_Font tkfont, /* The precalculated font */ + CONST Tk_FontMetrics *fmPtr, /* The precalculated font metrics */ + int *modWidthPtr, /* The width of all of the key + * modifier symbols. */ + int *textWidthPtr, /* The resulting width */ + int *heightPtr) /* The resulting height */ +{ + *heightPtr = fmPtr->linespace; + *modWidthPtr = 0; + if (mePtr->type == CASCADE_ENTRY) { + *textWidthPtr = SICN_HEIGHT; + *modWidthPtr = Tk_TextWidth(tkfont, "W", 1); + } else if (0 == mePtr->accelLength) { + *textWidthPtr = 0; + } else { + + if (NULL == GetResource('SICN', SICN_RESOURCE_NUMBER)) { + *textWidthPtr = Tk_TextWidth(tkfont, mePtr->accel, + mePtr->accelLength); + } else { + int emWidth = Tk_TextWidth(tkfont, "W", 1) + 1; + if ((mePtr->entryFlags & ENTRY_ACCEL_MASK) == 0) { + int width = Tk_TextWidth(tkfont, mePtr->accel, + mePtr->accelLength); + *textWidthPtr = emWidth; + if (width < emWidth) { + *modWidthPtr = 0; + } else { + *modWidthPtr = width - emWidth; + } + } else { + int length = ((EntryGeometry *)mePtr->platformEntryData) + ->accelTextStart; + if (mePtr->entryFlags & ENTRY_CONTROL_ACCEL) { + *modWidthPtr += CONTROL_ICON_WIDTH; + } + if (mePtr->entryFlags & ENTRY_SHIFT_ACCEL) { + *modWidthPtr += SHIFT_ICON_WIDTH; + } + if (mePtr->entryFlags & ENTRY_OPTION_ACCEL) { + *modWidthPtr += OPTION_ICON_WIDTH; + } + if (mePtr->entryFlags & ENTRY_COMMAND_ACCEL) { + *modWidthPtr += COMMAND_ICON_WIDTH; + } + if (1 == (mePtr->accelLength - length)) { + *textWidthPtr = emWidth; + } else { + *textWidthPtr += Tk_TextWidth(tkfont, mePtr->accel + + length, mePtr->accelLength - length); + } + } + } + } +} + +/* + *---------------------------------------------------------------------- + * + * GetTearoffEntryGeometry -- + * + * Gets the width and height of of a tearoff entry. + * + * Results: + * widthPtr and heightPtr are set. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static void +GetTearoffEntryGeometry ( + TkMenu *menuPtr, /* The menu we are drawing */ + TkMenuEntry *mePtr, /* The entry we are measuring */ + Tk_Font tkfont, /* The precalculated font */ + CONST Tk_FontMetrics *fmPtr, /* The precalculated font metrics */ + int *widthPtr, /* The resulting width */ + int *heightPtr) /* The resulting height */ +{ + if ((GetResource('MDEF', 591) == NULL) && + (menuPtr->menuType == MASTER_MENU)) { + *heightPtr = fmPtr->linespace; + *widthPtr = 0; + } else { + *widthPtr = *heightPtr = 0; + } +} + +/* + *---------------------------------------------------------------------- + * + * GetMenuSeparatorGeometry -- + * + * Gets the width and height of menu separator. + * + * Results: + * widthPtr and heightPtr are set. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static void +GetMenuSeparatorGeometry( + TkMenu *menuPtr, /* The menu we are drawing */ + TkMenuEntry *mePtr, /* The entry we are measuring */ + Tk_Font tkfont, /* The precalculated font */ + CONST Tk_FontMetrics *fmPtr, /* The precalcualted font metrics */ + int *widthPtr, /* The resulting width */ + int *heightPtr) /* The resulting height */ +{ + *widthPtr = 0; + *heightPtr = fmPtr->linespace; +} + +/* + *---------------------------------------------------------------------- + * + * DrawMenuEntryIndicator -- + * + * This procedure draws the indicator part of a menu. + * + * Results: + * None. + * + * Side effects: + * Commands are output to X to display the menu in its + * current mode. + * + *---------------------------------------------------------------------- + */ + +static void +DrawMenuEntryIndicator( + TkMenu *menuPtr, /* The menu we are drawing */ + TkMenuEntry *mePtr, /* The entry we are drawing */ + Drawable d, /* The drawable we are drawing */ + GC gc, /* The GC we are drawing with */ + GC indicatorGC, /* The GC to use for the indicator */ + Tk_Font tkfont, /* The precalculated font */ + CONST Tk_FontMetrics *fmPtr, /* The precalculated font metrics */ + int x, /* topleft hand corner of entry */ + int y, /* topleft hand corner of entry */ + int width, /* width of entry */ + int height) /* height of entry */ +{ + if (((mePtr->type == CHECK_BUTTON_ENTRY) || + (mePtr->type == RADIO_BUTTON_ENTRY)) + && (mePtr->indicatorOn) + && (mePtr->entryFlags & ENTRY_SELECTED)) { + int baseline; + short markShort; + char markChar; + + baseline = y + (height + fmPtr->ascent - fmPtr->descent) / 2; + GetItemMark(((MacMenu *) menuPtr->platformData)->menuHdl, + mePtr->index + 1, &markShort); + if (markShort != 0) { + markChar = (char) markShort; + Tk_DrawChars(menuPtr->display, d, gc, tkfont, &markChar, 1, + x + 2, baseline); + } + } +} + +/* + *---------------------------------------------------------------------- + * + * DrawSICN -- + * + * Given a resource id and an index, loads the appropriate SICN + * and draws it into a given drawable using the given gc. + * + * Results: + * Returns 1 if the SICN was found, 0 if not found. + * + * Side effects: + * Commands are output to X to display the menu in its + * current mode. + * + *---------------------------------------------------------------------- + */ +static int +DrawSICN( + int resourceID, /* The resource # of the SICN table */ + int index, /* The index into the SICN table of the + * icon we want. */ + Drawable d, /* What we are drawing into */ + GC gc, /* The GC to draw with */ + int x, /* The left hand coord of the SICN */ + int y) /* The top coord of the SICN */ +{ + Handle sicnHandle = (Handle) GetResource('SICN', SICN_RESOURCE_NUMBER); + + if (NULL == sicnHandle) { + return 0; + } else { + BitMap sicnBitmap; + Rect destRect; + CGrafPtr saveWorld; + GDHandle saveDevice; + GWorldPtr destPort; + BitMapPtr destBitMap; + RGBColor origForeColor, origBackColor, foreColor, backColor; + + HLock(sicnHandle); + destPort = TkMacGetDrawablePort(d); + GetGWorld(&saveWorld, &saveDevice); + SetGWorld(destPort, NULL); + TkMacSetUpClippingRgn(d); + TkMacSetUpGraphicsPort(gc); + GetForeColor(&origForeColor); + GetBackColor(&origBackColor); + + if (TkSetMacColor(gc->foreground, &foreColor) == true) { + RGBForeColor(&foreColor); + } + + if (TkSetMacColor(gc->background, &backColor) == true) { + RGBBackColor(&backColor); + } + + SetRect(&destRect, x, y, x + SICN_HEIGHT, y + SICN_HEIGHT); + sicnBitmap.baseAddr = (Ptr) (*sicnHandle) + index * SICN_HEIGHT + * SICN_ROWS; + sicnBitmap.rowBytes = SICN_ROWS; + SetRect(&sicnBitmap.bounds, 0, 0, 16, 16); + destBitMap = &((GrafPtr) destPort)->portBits; + CopyBits(&sicnBitmap, destBitMap, &sicnBitmap.bounds, &destRect, + destPort->txMode, NULL); + HUnlock(sicnHandle); + RGBForeColor(&origForeColor); + RGBBackColor(&origBackColor); + SetGWorld(saveWorld, saveDevice); + return 1; + } +} + +/* + *---------------------------------------------------------------------- + * + * DrawMenuEntryAccelerator -- + * + * This procedure draws the accelerator part of a menu. We + * need to decide what to draw here. Should we replace strings + * like "Control", "Command", etc? + * + * Results: + * None. + * + * Side effects: + * Commands are output to X to display the menu in its + * current mode. + * + *---------------------------------------------------------------------- + */ + +static void +DrawMenuEntryAccelerator( + TkMenu *menuPtr, /* The menu we are drawing */ + TkMenuEntry *mePtr, /* The entry we are drawing */ + Drawable d, /* The drawable we are drawing in */ + GC gc, /* The gc to draw into */ + Tk_Font tkfont, /* The precalculated font */ + CONST Tk_FontMetrics *fmPtr, /* The precalculated font metrics */ + Tk_3DBorder activeBorder, /* border for menu background */ + int x, /* The left side of the entry */ + int y, /* The top of the entry */ + int width, /* The width of the entry */ + int height, /* The height of the entry */ + int drawArrow) /* Whether or not to draw cascade arrow */ +{ + if (mePtr->type == CASCADE_ENTRY) { + if (0 == DrawSICN(SICN_RESOURCE_NUMBER, CASCADE_ARROW, d, gc, + x + width - SICN_HEIGHT, (y + (height / 2)) + - (SICN_HEIGHT / 2))) { + XPoint points[3]; + Tk_Window tkwin = menuPtr->tkwin; + + if (mePtr->type == CASCADE_ENTRY) { + points[0].x = width - menuPtr->activeBorderWidth + - MAC_MARGIN_WIDTH - CASCADE_ARROW_WIDTH; + points[0].y = y + (height - CASCADE_ARROW_HEIGHT)/2; + points[1].x = points[0].x; + points[1].y = points[0].y + CASCADE_ARROW_HEIGHT; + points[2].x = points[0].x + CASCADE_ARROW_WIDTH; + points[2].y = points[0].y + CASCADE_ARROW_HEIGHT/2; + Tk_Fill3DPolygon(menuPtr->tkwin, d, activeBorder, points, + 3, DECORATION_BORDER_WIDTH, TK_RELIEF_FLAT); + } + } + } else if (mePtr->accelLength != 0) { + int leftEdge = x + width; + int baseline = y + (height + fmPtr->ascent - fmPtr->descent) / 2; + + if (NULL == GetResource('SICN', SICN_RESOURCE_NUMBER)) { + leftEdge -= ((EntryGeometry *) mePtr->platformEntryData) + ->accelTextWidth; + Tk_DrawChars(menuPtr->display, d, gc, tkfont, mePtr->accel, + mePtr->accelLength, leftEdge, baseline); + } else { + EntryGeometry *geometryPtr = + (EntryGeometry *) mePtr->platformEntryData; + int length = mePtr->accelLength - geometryPtr->accelTextStart; + + leftEdge -= geometryPtr->accelTextWidth; + if ((mePtr->entryFlags & ENTRY_ACCEL_MASK) == 0) { + leftEdge -= geometryPtr->modifierWidth; + } + + Tk_DrawChars(menuPtr->display, d, gc, tkfont, mePtr->accel + + geometryPtr->accelTextStart, length, leftEdge, baseline); + + if (mePtr->entryFlags & ENTRY_COMMAND_ACCEL) { + leftEdge -= COMMAND_ICON_WIDTH; + DrawSICN(SICN_RESOURCE_NUMBER, COMMAND_ICON, d, gc, + leftEdge, (y + (height / 2)) - (SICN_HEIGHT / 2) - 1); + } + + if (mePtr->entryFlags & ENTRY_OPTION_ACCEL) { + leftEdge -= OPTION_ICON_WIDTH; + DrawSICN(SICN_RESOURCE_NUMBER, OPTION_ICON, d, gc, + leftEdge, (y + (height / 2)) - (SICN_HEIGHT / 2) - 1); + } + + if (mePtr->entryFlags & ENTRY_SHIFT_ACCEL) { + leftEdge -= SHIFT_ICON_WIDTH; + DrawSICN(SICN_RESOURCE_NUMBER, SHIFT_ICON, d, gc, + leftEdge, (y + (height / 2)) - (SICN_HEIGHT / 2) - 1); + } + + if (mePtr->entryFlags & ENTRY_CONTROL_ACCEL) { + leftEdge -= CONTROL_ICON_WIDTH; + DrawSICN(SICN_RESOURCE_NUMBER, CONTROL_ICON, d, gc, + leftEdge, (y + (height / 2)) - (SICN_HEIGHT / 2) - 1); + } + } + } +} + +/* + *---------------------------------------------------------------------- + * + * DrawMenuSeparator -- + * + * The menu separator is drawn. + * + * Results: + * None. + * + * Side effects: + * Commands are output to X to display the menu in its + * current mode. + * + *---------------------------------------------------------------------- + */ + +static void +DrawMenuSeparator( + TkMenu *menuPtr, /* The menu we are drawing */ + TkMenuEntry *mePtr, /* The entry we are drawing */ + Drawable d, /* The drawable we are drawing into */ + GC gc, /* The gc we are drawing with */ + Tk_Font tkfont, /* The precalculated font */ + CONST Tk_FontMetrics *fmPtr, /* The precalculated font metrics */ + int x, /* left coordinate of entry */ + int y, /* top coordinate of entry */ + int width, /* width of entry */ + int height) /* height of entry */ +{ + CGrafPtr saveWorld; + GDHandle saveDevice; + GWorldPtr destPort; + + destPort = TkMacGetDrawablePort(d); + GetGWorld(&saveWorld, &saveDevice); + SetGWorld(destPort, NULL); + TkMacSetUpClippingRgn(d); + + /* + * We don't want to use the text GC for drawing the separator. It + * needs to be the same color as disabled items. + */ + + TkMacSetUpGraphicsPort(mePtr->disabledGC != None ? mePtr->disabledGC + : menuPtr->disabledGC); + + MoveTo(x, y + (height / 2)); + Line(width, 0); + + SetGWorld(saveWorld, saveDevice); +} + +/* + *---------------------------------------------------------------------- + * + * MenuDefProc -- + * + * This routine is the MDEF handler for Tk. It receives all messages + * for the menu and dispatches them. + * + * Results: + * None. + * + * Side effects: + * This routine causes menus to be drawn and will certainly allocate + * memory as a result. Also, the menu can scroll up and down, and + * various other interface actions can take place. + * + *---------------------------------------------------------------------- + */ + +static void +MenuDefProc( + short message, /* What action are we taking? */ + MenuHandle menu, /* The menu we are working with */ + Rect *menuRectPtr, /* A pointer to the rect for the + * whole menu. */ + Point hitPt, /* Where the mouse was clicked for + * the appropriate messages. */ + short *whichItem, /* Output result. Which item was + * hit by the user? */ + TkMenuLowMemGlobals *globalsPtr) /* The low mem globals we have + * to change */ +{ +#define SCREEN_MARGIN 5 + TkMenu *menuPtr; + TkMenuEntry *parentEntryPtr; + Tcl_HashEntry *commandEntryPtr; + GrafPtr windowMgrPort; + Tk_Font tkfont; + Tk_FontMetrics fontMetrics, entryMetrics; + Tk_FontMetrics *fmPtr; + TkMenuEntry *mePtr; + int i; + int maxMenuHeight; + int oldItem; + int newItem = -1; + GDHandle device; + Rect itemRect; + short windowPart; + WindowRef whichWindow; + RGBColor bgColor; + RGBColor fgColor; + RGBColor origFgColor; + PenState origPenState; + Rect dragRect; + Rect scratchRect = {-32768, -32768, 32767, 32767}; + RgnHandle oldClipRgn; + TkMenuReferences *menuRefPtr; + TkMenu *searchMenuPtr; + Rect menuClipRect; + + HLock((Handle) menu); + commandEntryPtr = Tcl_FindHashEntry(&commandTable, + (char *) (*menu)->menuID); + HUnlock((Handle) menu); + menuPtr = (TkMenu *) Tcl_GetHashValue(commandEntryPtr); + + switch (message) { + case mSizeMsg: + GetWMgrPort(&windowMgrPort); + maxMenuHeight = windowMgrPort->portRect.bottom + - windowMgrPort->portRect.top + - GetMBarHeight() - SCREEN_MARGIN; + (*menu)->menuWidth = menuPtr->totalWidth; + (*menu)->menuHeight = maxMenuHeight < menuPtr->totalHeight ? + maxMenuHeight : menuPtr->totalHeight; + break; + + case mDrawMsg: + + /* + * Store away the menu rectangle so we can keep track of the + * different regions that the menu obscures. + */ + + ((MacMenu *) menuPtr->platformData)->menuRect = *menuRectPtr; + if (tkMenuCascadeRgn == NULL) { + tkMenuCascadeRgn = NewRgn(); + } + if (utilRgn == NULL) { + utilRgn = NewRgn(); + } + if (totalMenuRgn == NULL) { + totalMenuRgn = NewRgn(); + } + SetEmptyRgn(tkMenuCascadeRgn); + for (searchMenuPtr = menuPtr; searchMenuPtr != NULL; ) { + RectRgn(utilRgn, + &((MacMenu *) searchMenuPtr->platformData)->menuRect); + InsetRgn(utilRgn, -1, -1); + UnionRgn(tkMenuCascadeRgn, utilRgn, tkMenuCascadeRgn); + OffsetRgn(utilRgn, 1, 1); + UnionRgn(tkMenuCascadeRgn, utilRgn, tkMenuCascadeRgn); + + if (searchMenuPtr->menuRefPtr->parentEntryPtr != NULL) { + searchMenuPtr = searchMenuPtr->menuRefPtr + ->parentEntryPtr->menuPtr; + } else { + break; + } + if (searchMenuPtr->menuType == MENUBAR) { + break; + } + } + UnionRgn(totalMenuRgn, tkMenuCascadeRgn, totalMenuRgn); + SetEmptyRgn(utilRgn); + + /* + * Next, figure out scrolling information. + */ + + GetGWorld(&macMDEFDrawable.portPtr, &device); + menuClipRect = *menuRectPtr; + if ((menuClipRect.bottom - menuClipRect.top) + < menuPtr->totalHeight) { + if (globalsPtr->menuTop < menuRectPtr->top) { + DrawSICN(SICN_RESOURCE_NUMBER, UP_ARROW, + (Drawable) &macMDEFDrawable, + menuPtr->textGC, + menuRectPtr->left + + menuPtr->entries[1]->indicatorSpace, + menuRectPtr->top); + menuClipRect.top += SICN_HEIGHT; + } + if ((globalsPtr->menuTop + menuPtr->totalHeight) + > menuRectPtr->bottom) { + DrawSICN(SICN_RESOURCE_NUMBER, DOWN_ARROW, + (Drawable) &macMDEFDrawable, + menuPtr->textGC, + menuRectPtr->left + + menuPtr->entries[1]->indicatorSpace, + menuRectPtr->bottom - SICN_HEIGHT); + menuClipRect.bottom -= SICN_HEIGHT; + } + GetClip(utilRgn); + } + + /* + * Now, actually draw the menu. Don't draw entries that + * are higher than the top arrow, and don't draw entries + * that are lower than the bottom. + */ + + Tk_GetFontMetrics(menuPtr->tkfont, &fontMetrics); + for (i = 0; i < menuPtr->numEntries; i++) { + mePtr = menuPtr->entries[i]; + if (globalsPtr->menuTop + mePtr->y + mePtr->height + < menuClipRect.top) { + continue; + } else if (globalsPtr->menuTop + mePtr->y + > menuClipRect.bottom) { + continue; + } + ClipRect(&menuClipRect); + if (mePtr->tkfont == NULL) { + fmPtr = &fontMetrics; + tkfont = menuPtr->tkfont; + } else { + tkfont = mePtr->tkfont; + Tk_GetFontMetrics(tkfont, &entryMetrics); + fmPtr = &entryMetrics; + } + TkpDrawMenuEntry(mePtr, (Drawable) &macMDEFDrawable, + tkfont, fmPtr, menuRectPtr->left + mePtr->x, + globalsPtr->menuTop + mePtr->y, + (mePtr->entryFlags & ENTRY_LAST_COLUMN) ? + menuPtr->totalWidth - mePtr->x : mePtr->width, + menuPtr->entries[i]->height, 0, 1); + } + globalsPtr->menuBottom = globalsPtr->menuTop + + menuPtr->totalHeight; + if (!EmptyRgn(utilRgn)) { + SetClip(utilRgn); + SetEmptyRgn(utilRgn); + } + MDEFScrollFlag = 1; + break; + + case mChooseMsg: { + int hasTopScroll, hasBottomScroll; + enum { + DONT_SCROLL, DOWN_SCROLL, UP_SCROLL + } scrollDirection; + Rect updateRect; + short scrollAmt; + RGBColor origForeColor, origBackColor, foreColor, backColor; + + GetGWorld(&macMDEFDrawable.portPtr, &device); + GetForeColor(&origForeColor); + GetBackColor(&origBackColor); + + if (TkSetMacColor(menuPtr->textGC->foreground, + &foreColor) == true) { + RGBForeColor(&foreColor); + } + if (TkSetMacColor(menuPtr->textGC->background, + &backColor) == true) { + RGBBackColor(&backColor); + } + + /* + * Find out which item was hit. If it is the same as the old item, + * we don't need to do anything. + */ + + oldItem = *whichItem - 1; + + if (PtInRect(hitPt, menuRectPtr)) { + for (i = 0; i < menuPtr->numEntries; i++) { + mePtr = menuPtr->entries[i]; + itemRect.left = menuRectPtr->left + mePtr->x; + itemRect.top = globalsPtr->menuTop + mePtr->y; + if (mePtr->entryFlags & ENTRY_LAST_COLUMN) { + itemRect.right = itemRect.left + menuPtr->totalWidth + - mePtr->x; + } else { + itemRect.right = itemRect.left + mePtr->width; + } + itemRect.bottom = itemRect.top + + menuPtr->entries[i]->height; + if (PtInRect(hitPt, &itemRect)) { + if ((mePtr->type == SEPARATOR_ENTRY) + || (mePtr->state == tkDisabledUid)) { + newItem = -1; + } else { + TkMenuEntry *cascadeEntryPtr; + int parentDisabled = 0; + + for (cascadeEntryPtr + = menuPtr->menuRefPtr->parentEntryPtr; + cascadeEntryPtr != NULL; + cascadeEntryPtr + = cascadeEntryPtr->nextCascadePtr) { + if (strcmp(cascadeEntryPtr->name, + Tk_PathName(menuPtr->tkwin)) == 0) { + if (cascadeEntryPtr->state + == tkDisabledUid) { + parentDisabled = 1; + } + break; + } + } + if (parentDisabled) { + newItem = -1; + } else { + newItem = i; + if ((mePtr->type == CASCADE_ENTRY) + && (oldItem != newItem)) { + globalsPtr->itemRect = itemRect; + } + } + } + break; + } + } + } + + /* + * Now we need to take care of scrolling the menu. + */ + + hasTopScroll = globalsPtr->menuTop < menuRectPtr->top; + hasBottomScroll = globalsPtr->menuBottom > menuRectPtr->bottom; + scrollDirection = DONT_SCROLL; + if (hasTopScroll + && (hitPt.v < menuRectPtr->top + SICN_HEIGHT)) { + newItem = -1; + scrollDirection = DOWN_SCROLL; + } else if (hasBottomScroll + && (hitPt.v > menuRectPtr->bottom - SICN_HEIGHT)) { + newItem = -1; + scrollDirection = UP_SCROLL; + } + menuClipRect = *menuRectPtr; + if (hasTopScroll) { + menuClipRect.top += SICN_HEIGHT; + } + if (hasBottomScroll) { + menuClipRect.bottom -= SICN_HEIGHT; + } + if (MDEFScrollFlag) { + scrollDirection = DONT_SCROLL; + MDEFScrollFlag = 0; + } + GetClip(utilRgn); + ClipRect(&menuClipRect); + + if (oldItem != newItem) { + if (oldItem >= 0) { + mePtr = menuPtr->entries[oldItem]; + tkfont = mePtr->tkfont ? mePtr->tkfont : menuPtr->tkfont; + Tk_GetFontMetrics(tkfont, &fontMetrics); + TkpDrawMenuEntry(mePtr, (Drawable) &macMDEFDrawable, + tkfont, &fontMetrics, + menuRectPtr->left + mePtr->x, + globalsPtr->menuTop + mePtr->y, + (mePtr->entryFlags & ENTRY_LAST_COLUMN) + ? menuPtr->totalWidth - mePtr->x + : mePtr->width, mePtr->height, 0, 1); + } + if (newItem != -1) { + int oldActiveItem = menuPtr->active; + + mePtr = menuPtr->entries[newItem]; + if (mePtr->state != tkDisabledUid) { + TkActivateMenuEntry(menuPtr, newItem); + } + tkfont = mePtr->tkfont ? mePtr->tkfont : menuPtr->tkfont; + Tk_GetFontMetrics(tkfont, &fontMetrics); + TkpDrawMenuEntry(mePtr, (Drawable) &macMDEFDrawable, + tkfont, &fontMetrics, + menuRectPtr->left + mePtr->x, + globalsPtr->menuTop + mePtr->y, + (mePtr->entryFlags & ENTRY_LAST_COLUMN) + ? menuPtr->totalWidth - mePtr->x + : mePtr->width, mePtr->height, + 0, 1); + } + + tkUseMenuCascadeRgn = 1; + MenuSelectEvent(menuPtr); + Tcl_ServiceAll(); + tkUseMenuCascadeRgn = 0; + if (mePtr->state != tkDisabledUid) { + TkActivateMenuEntry(menuPtr, -1); + } + *whichItem = newItem + 1; + } + globalsPtr->menuDisable = ((*menu)->menuID << 16) | (newItem + 1); + + if (scrollDirection == UP_SCROLL) { + scrollAmt = menuClipRect.bottom - hitPt.v; + if (scrollAmt < menuRectPtr->bottom + - globalsPtr->menuBottom) { + scrollAmt = menuRectPtr->bottom - globalsPtr->menuBottom; + } + if (!hasTopScroll && ((globalsPtr->menuTop + scrollAmt) < menuRectPtr->top)) { + SetRect(&updateRect, menuRectPtr->left, + globalsPtr->menuTop, menuRectPtr->right, + globalsPtr->menuTop + SICN_HEIGHT); + EraseRect(&updateRect); + DrawSICN(SICN_RESOURCE_NUMBER, UP_ARROW, + (Drawable) &macMDEFDrawable, + menuPtr->textGC, menuRectPtr->left + + menuPtr->entries[1]->indicatorSpace, + menuRectPtr->top); + menuClipRect.top += SICN_HEIGHT; + } + } else if (scrollDirection == DOWN_SCROLL) { + scrollAmt = menuClipRect.top - hitPt.v; + if (scrollAmt > menuRectPtr->top - globalsPtr->menuTop) { + scrollAmt = menuRectPtr->top - globalsPtr->menuTop; + } + if (!hasBottomScroll && ((globalsPtr->menuBottom + scrollAmt) + > menuRectPtr->bottom)) { + SetRect(&updateRect, menuRectPtr->left, + globalsPtr->menuBottom - SICN_HEIGHT, + menuRectPtr->right, globalsPtr->menuBottom); + EraseRect(&updateRect); + DrawSICN(SICN_RESOURCE_NUMBER, DOWN_ARROW, + (Drawable) &macMDEFDrawable, + menuPtr->textGC, menuRectPtr->left + + menuPtr->entries[1]->indicatorSpace, + menuRectPtr->bottom - SICN_HEIGHT); + menuClipRect.bottom -= SICN_HEIGHT; + } + } + if (scrollDirection != DONT_SCROLL) { + RgnHandle updateRgn = NewRgn(); + ScrollRect(&menuClipRect, 0, scrollAmt, updateRgn); + updateRect = (*updateRgn)->rgnBBox; + DisposeRgn(updateRgn); + globalsPtr->menuTop += scrollAmt; + globalsPtr->menuBottom += scrollAmt; + if (globalsPtr->menuTop == menuRectPtr->top) { + updateRect.top -= SICN_HEIGHT; + } + if (globalsPtr->menuBottom == menuRectPtr->bottom) { + updateRect.bottom += SICN_HEIGHT; + } + ClipRect(&updateRect); + EraseRect(&updateRect); + Tk_GetFontMetrics(menuPtr->tkfont, &fontMetrics); + for (i = 0; i < menuPtr->numEntries; i++) { + mePtr = menuPtr->entries[i]; + if (globalsPtr->menuTop + mePtr->y + mePtr->height + < updateRect.top) { + continue; + } else if (globalsPtr->menuTop + mePtr->y + > updateRect.bottom) { + continue; + } + if (mePtr->tkfont == NULL) { + fmPtr = &fontMetrics; + tkfont = menuPtr->tkfont; + } else { + tkfont = mePtr->tkfont; + Tk_GetFontMetrics(tkfont, &entryMetrics); + fmPtr = &entryMetrics; + } + TkpDrawMenuEntry(mePtr, (Drawable) &macMDEFDrawable, + tkfont, fmPtr, menuRectPtr->left + mePtr->x, + globalsPtr->menuTop + mePtr->y, + (mePtr->entryFlags & ENTRY_LAST_COLUMN) ? + menuPtr->totalWidth - mePtr->x : mePtr->width, + menuPtr->entries[i]->height, 0, 1); + } + } + + SetClip(utilRgn); + SetEmptyRgn(utilRgn); + RGBForeColor(&origForeColor); + RGBBackColor(&origBackColor); + + /* + * If the menu is a tearoff, and the mouse is outside the menu, + * we need to draw the drag rectangle. + * + * In order for tearoffs to work properly, we need to set + * the active member of the containing menubar. + */ + + menuRefPtr = TkFindMenuReferences(menuPtr->interp, + Tk_PathName(menuPtr->tkwin)); + if ((menuRefPtr != NULL) && (menuRefPtr->parentEntryPtr != NULL)) { + for (parentEntryPtr = menuRefPtr->parentEntryPtr; + strcmp(parentEntryPtr->name, + Tk_PathName(menuPtr->tkwin)) == 0; + parentEntryPtr = parentEntryPtr->nextCascadePtr) { + } + if (parentEntryPtr != NULL) { + TkActivateMenuEntry(parentEntryPtr->menuPtr, + parentEntryPtr->index); + } + } + + if (menuPtr->tearOff) { + scratchRect = *menuRectPtr; + if (tearoffStruct.menuPtr == NULL) { + scratchRect.top -= 10; + scratchRect.bottom += 10; + scratchRect.left -= 10; + scratchRect.right += 10; + } + + windowPart = FindWindow(hitPt, &whichWindow); + if ((windowPart != inMenuBar) && (newItem == -1) + && (hitPt.v != 0) && (hitPt.h != 0) + && (!PtInRect(hitPt, &scratchRect)) + && (!PtInRect(hitPt, &tearoffStruct.excludeRect))) { +/* + * This is the second argument to the Toolbox Delay function. It changed + * from long to unsigned long between Universal Headers 2.0 & 3.0 + */ +#if !defined(UNIVERSAL_INTERFACES_VERSION) || (UNIVERSAL_INTERFACES_VERSION < 0x0300) + long dummy; +#else + unsigned long dummy; +#endif + oldClipRgn = NewRgn(); + GetClip(oldClipRgn); + GetForeColor(&origFgColor); + GetPenState(&origPenState); + GetForeColor(&fgColor); + GetBackColor(&bgColor); + GetGray(device, &bgColor, &fgColor); + RGBForeColor(&fgColor); + SetRect(&scratchRect, -32768, -32768, 32767, 32767); + ClipRect(&scratchRect); + + dragRect = *menuRectPtr; + tearoffStruct.menuPtr = menuPtr; + + PenMode(srcXor); + dragRect = *menuRectPtr; + OffsetRect(&dragRect, -dragRect.left, -dragRect.top); + OffsetRect(&dragRect, tearoffStruct.point.h, + tearoffStruct.point.v); + if ((dragRect.top != 0) && (dragRect.left != 0)) { + FrameRect(&dragRect); + Delay(1, &dummy); + FrameRect(&dragRect); + } + tearoffStruct.point = hitPt; + + SetClip(oldClipRgn); + DisposeRgn(oldClipRgn); + RGBForeColor(&origFgColor); + SetPenState(&origPenState); + } else { + tearoffStruct.menuPtr = NULL; + tearoffStruct.point.h = tearoffStruct.point.v = 0; + } + } else { + tearoffStruct.menuPtr = NULL; + tearoffStruct.point.h = tearoffStruct.point.v = 0; + } + + break; + } + + case mPopUpMsg: + + /* + * Note that for some oddball reason, h and v are reversed in the + * point given to us by the MDEF. + */ + + oldItem = *whichItem; + if (oldItem >= menuPtr->numEntries) { + oldItem = -1; + } + GetWMgrPort(&windowMgrPort); + maxMenuHeight = windowMgrPort->portRect.bottom + - windowMgrPort->portRect.top + - GetMBarHeight() - SCREEN_MARGIN; + if (menuPtr->totalHeight > maxMenuHeight) { + menuRectPtr->top = GetMBarHeight(); + } else { + menuRectPtr->top = hitPt.h; + if (oldItem >= 0) { + menuRectPtr->top -= menuPtr->entries[oldItem]->y; + } + if (menuRectPtr->top + menuPtr->totalHeight > maxMenuHeight) { + menuRectPtr->top -= maxMenuHeight - menuPtr->totalHeight; + } + } + menuRectPtr->left = hitPt.v; + menuRectPtr->right = menuRectPtr->left + menuPtr->totalWidth; + menuRectPtr->bottom = menuRectPtr->top + + ((maxMenuHeight < menuPtr->totalHeight) + ? maxMenuHeight : menuPtr->totalHeight); + if (menuRectPtr->top == GetMBarHeight()) { + *whichItem = hitPt.h; + } else { + *whichItem = menuRectPtr->top; + } + break; + } +} + +/* + *---------------------------------------------------------------------- + * + * TkMacHandleTearoffMenu() -- + * + * This routine sees if the MDEF has set a menu and a mouse position + * for tearing off and makes a tearoff menu if it has. + * + * Results: + * menuPtr->interp will have the result of the tearoff command. + * + * Side effects: + * A new tearoff menu is created if it is supposed to be. + * + *---------------------------------------------------------------------- + */ + +void +TkMacHandleTearoffMenu(void) +{ + if (tearoffStruct.menuPtr != NULL) { + Tcl_DString tearoffCmdStr; + char intString[20]; + short windowPart; + WindowRef whichWindow; + + windowPart = FindWindow(tearoffStruct.point, &whichWindow); + + if (windowPart != inMenuBar) { + Tcl_DStringInit(&tearoffCmdStr); + Tcl_DStringAppendElement(&tearoffCmdStr, "tkTearOffMenu"); + Tcl_DStringAppendElement(&tearoffCmdStr, + Tk_PathName(tearoffStruct.menuPtr->tkwin)); + sprintf(intString, "%d", tearoffStruct.point.h); + Tcl_DStringAppendElement(&tearoffCmdStr, intString); + sprintf(intString, "%d", tearoffStruct.point.v); + Tcl_DStringAppendElement(&tearoffCmdStr, intString); + Tcl_Eval(tearoffStruct.menuPtr->interp, + Tcl_DStringValue(&tearoffCmdStr)); + Tcl_DStringFree(&tearoffCmdStr); + tearoffStruct.menuPtr = NULL; + } + } +} + +/* + *-------------------------------------------------------------- + * + * TkpInitializeMenuBindings -- + * + * For every interp, initializes the bindings for Windows + * menus. Does nothing on Mac or XWindows. + * + * Results: + * None. + * + * Side effects: + * C-level bindings are setup for the interp which will + * handle Alt-key sequences for menus without beeping + * or interfering with user-defined Alt-key bindings. + * + *-------------------------------------------------------------- + */ + +void +TkpInitializeMenuBindings(interp, bindingTable) + Tcl_Interp *interp; /* The interpreter to set. */ + Tk_BindingTable bindingTable; /* The table to add to. */ +{ + /* + * Nothing to do. + */ +} + +/* + *-------------------------------------------------------------- + * + * TkpComputeMenubarGeometry -- + * + * This procedure is invoked to recompute the size and + * layout of a menu that is a menubar clone. + * + * Results: + * None. + * + * Side effects: + * Fields of menu entries are changed to reflect their + * current positions, and the size of the menu window + * itself may be changed. + * + *-------------------------------------------------------------- + */ + +void +TkpComputeMenubarGeometry(menuPtr) + TkMenu *menuPtr; /* Structure describing menu. */ +{ + TkpComputeStandardMenuGeometry(menuPtr); +} + +/* + *---------------------------------------------------------------------- + * + * DrawTearoffEntry -- + * + * This procedure draws the background part of a menu. + * + * Results: + * None. + * + * Side effects: + * Commands are output to X to display the menu in its + * current mode. + * + *---------------------------------------------------------------------- + */ + +void +DrawTearoffEntry( + TkMenu *menuPtr, /* The menu we are drawing */ + TkMenuEntry *mePtr, /* The entry we are drawing */ + Drawable d, /* The drawable we are drawing into */ + GC gc, /* The gc we are drawing with */ + Tk_Font tkfont, /* The font we are drawing with */ + CONST Tk_FontMetrics *fmPtr, /* The metrics we are drawing with */ + int x, /* Left edge of entry. */ + int y, /* Top edge of entry. */ + int width, /* Width of entry. */ + int height) /* Height of entry. */ +{ + XPoint points[2]; + int margin, segmentWidth, maxX; + + if ((menuPtr->menuType != MASTER_MENU) || (GetResource('MDEF', 591) != NULL)) { + return; + } + + margin = (fmPtr->ascent + fmPtr->descent)/2; + points[0].x = x; + points[0].y = y + height/2; + points[1].y = points[0].y; + segmentWidth = 6; + maxX = width - 1; + + while (points[0].x < maxX) { + points[1].x = points[0].x + segmentWidth; + if (points[1].x > maxX) { + points[1].x = maxX; + } + Tk_Draw3DPolygon(menuPtr->tkwin, d, menuPtr->border, points, 2, 1, + TK_RELIEF_RAISED); + points[0].x += 2*segmentWidth; + } +} + +/* + *---------------------------------------------------------------------- + * + * TkMacSetHelpMenuItemCount -- + * + * Has to be called after the first call to InsertMenu. Sets + * up the global variable for the number of items in the + * unmodified help menu. + * + * Results: + * None. + * + * Side effects: + * Sets the global helpItemCount. + * + *---------------------------------------------------------------------- + */ + +void +TkMacSetHelpMenuItemCount() +{ + MenuHandle helpMenuHandle; + + if ((HMGetHelpMenuHandle(&helpMenuHandle) != noErr) + || (helpMenuHandle == NULL)) { + helpItemCount = -1; + } else { + helpItemCount = CountMItems(helpMenuHandle); + DeleteMenuItem(helpMenuHandle, helpItemCount); + } +} + +/* + *---------------------------------------------------------------------- + * + * TkMacMenuClick -- + * + * Prepares a menubar for MenuSelect or MenuKey. + * + * Results: + * None. + * + * Side effects: + * Any pending configurations of the menubar are completed. + * + *---------------------------------------------------------------------- + */ + +void +TkMacMenuClick() +{ + TkMenu *menuPtr; + TkMenuReferences *menuRefPtr; + + if ((currentMenuBarInterp != NULL) && (currentMenuBarName != NULL)) { + menuRefPtr = TkFindMenuReferences(currentMenuBarInterp, + currentMenuBarName); + for (menuPtr = menuRefPtr->menuPtr->masterMenuPtr; + menuPtr != NULL; menuPtr = menuPtr->nextInstancePtr) { + if (menuPtr->menuType == MENUBAR) { + CompleteIdlers(menuPtr); + break; + } + } + } + + if (menuBarFlags & MENUBAR_REDRAW_PENDING) { + Tcl_CancelIdleCall(DrawMenuBarWhenIdle, (ClientData *) NULL); + DrawMenuBarWhenIdle((ClientData *) NULL); + } +} + +/* + *---------------------------------------------------------------------- + * + * TkpDrawMenuEntry -- + * + * Draws the given menu entry at the given coordinates with the + * given attributes. + * + * Results: + * None. + * + * Side effects: + * X Server commands are executed to display the menu entry. + * + *---------------------------------------------------------------------- + */ + +void +TkpDrawMenuEntry( + TkMenuEntry *mePtr, /* The entry to draw */ + Drawable d, /* What to draw into */ + Tk_Font tkfont, /* Precalculated font for menu */ + 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. */ +{ + GC gc, indicatorGC; + TkMenu *menuPtr = mePtr->menuPtr; + Tk_3DBorder bgBorder, activeBorder; + CONST Tk_FontMetrics *fmPtr; + Tk_FontMetrics entryMetrics; + int padY = (menuPtr->menuType == MENUBAR) ? 3 : 0; + int adjustedY = y + padY; + int adjustedHeight = height - 2 * padY; + + /* + * Choose the gc for drawing the foreground part of the entry. + */ + + if ((mePtr->state == tkActiveUid) + && !strictMotif) { + gc = mePtr->activeGC; + if (gc == NULL) { + gc = menuPtr->activeGC; + } + } else { + TkMenuEntry *cascadeEntryPtr; + int parentDisabled = 0; + + for (cascadeEntryPtr = menuPtr->menuRefPtr->parentEntryPtr; + cascadeEntryPtr != NULL; + cascadeEntryPtr = cascadeEntryPtr->nextCascadePtr) { + if (strcmp(cascadeEntryPtr->name, + Tk_PathName(menuPtr->tkwin)) == 0) { + if (cascadeEntryPtr->state == tkDisabledUid) { + parentDisabled = 1; + } + break; + } + } + + if (((parentDisabled || (mePtr->state == tkDisabledUid))) + && (menuPtr->disabledFg != NULL)) { + gc = mePtr->disabledGC; + if (gc == NULL) { + gc = menuPtr->disabledGC; + } + } else { + gc = mePtr->textGC; + if (gc == NULL) { + gc = menuPtr->textGC; + } + } + } + indicatorGC = mePtr->indicatorGC; + if (indicatorGC == NULL) { + indicatorGC = menuPtr->indicatorGC; + } + + bgBorder = mePtr->border; + if (bgBorder == NULL) { + bgBorder = menuPtr->border; + } + if (strictMotif) { + activeBorder = bgBorder; + } else { + activeBorder = mePtr->activeBorder; + if (activeBorder == NULL) { + activeBorder = menuPtr->activeBorder; + } + } + + if (mePtr->tkfont == NULL) { + fmPtr = menuMetricsPtr; + } else { + tkfont = mePtr->tkfont; + Tk_GetFontMetrics(tkfont, &entryMetrics); + fmPtr = &entryMetrics; + } + + /* + * Need to draw the entire background, including padding. On Unix, + * for menubars, we have to draw the rest of the entry taking + * into account the padding. + */ + + DrawMenuEntryBackground(menuPtr, mePtr, d, activeBorder, + bgBorder, x, y, width, height); + + if (mePtr->type == SEPARATOR_ENTRY) { + DrawMenuSeparator(menuPtr, mePtr, d, gc, tkfont, + fmPtr, x, adjustedY, width, adjustedHeight); + } else if (mePtr->type == TEAROFF_ENTRY) { + DrawTearoffEntry(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, adjustedY, + width, adjustedHeight); + } else { + DrawMenuEntryLabel(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, + adjustedY, width, adjustedHeight); + DrawMenuEntryAccelerator(menuPtr, mePtr, d, gc, tkfont, fmPtr, + activeBorder, x, adjustedY, width, adjustedHeight, drawArrow); + if (!mePtr->hideMargin) { + DrawMenuEntryIndicator(menuPtr, mePtr, d, gc, indicatorGC, tkfont, + fmPtr, x, adjustedY, width, adjustedHeight); + } + } +} + +/* + *-------------------------------------------------------------- + * + * TkpComputeStandardMenuGeometry -- + * + * This procedure is invoked to recompute the size and + * layout of a menu that is not a menubar clone. + * + * Results: + * None. + * + * Side effects: + * Fields of menu entries are changed to reflect their + * current positions, and the size of the menu window + * itself may be changed. + * + *-------------------------------------------------------------- + */ + +void +TkpComputeStandardMenuGeometry( + TkMenu *menuPtr) /* Structure describing menu. */ +{ + Tk_Font tkfont; + Tk_FontMetrics menuMetrics, entryMetrics, *fmPtr; + int x, y, height, modifierWidth, labelWidth, indicatorSpace; + int windowWidth, windowHeight, accelWidth, maxAccelTextWidth; + int i, j, lastColumnBreak, maxModifierWidth, maxWidth, nonAccelMargin; + int maxNonAccelMargin, maxEntryWithAccelWidth, maxEntryWithoutAccelWidth; + int entryWidth, maxIndicatorSpace; + TkMenuEntry *mePtr, *columnEntryPtr; + EntryGeometry *geometryPtr; + + if (menuPtr->tkwin == NULL) { + return; + } + + x = y = menuPtr->borderWidth; + indicatorSpace = labelWidth = accelWidth = maxAccelTextWidth = 0; + windowHeight = windowWidth = maxWidth = lastColumnBreak = 0; + maxModifierWidth = nonAccelMargin = maxNonAccelMargin = 0; + maxEntryWithAccelWidth = maxEntryWithoutAccelWidth = 0; + maxIndicatorSpace = 0; + + /* + * On the Mac especially, getting font metrics can be quite slow, + * so we want to do it intelligently. We are going to precalculate + * them and pass them down to all of the measuring and drawing + * routines. We will measure the font metrics of the menu once. + * If an entry does not have its own font set, then we give + * the geometry/drawing routines the menu's font and metrics. + * If an entry has its own font, we will measure that font and + * give all of the geometry/drawing the entry's font and metrics. + */ + + Tk_GetFontMetrics(menuPtr->tkfont, &menuMetrics); + + for (i = 0; i < menuPtr->numEntries; i++) { + mePtr = menuPtr->entries[i]; + tkfont = mePtr->tkfont; + if (tkfont == NULL) { + tkfont = menuPtr->tkfont; + fmPtr = &menuMetrics; + } else { + Tk_GetFontMetrics(tkfont, &entryMetrics); + fmPtr = &entryMetrics; + } + + if ((i > 0) && mePtr->columnBreak) { + if (maxIndicatorSpace != 0) { + maxIndicatorSpace += 2; + } + for (j = lastColumnBreak; j < i; j++) { + columnEntryPtr = menuPtr->entries[j]; + geometryPtr = + (EntryGeometry *) columnEntryPtr->platformEntryData; + + columnEntryPtr->indicatorSpace = maxIndicatorSpace; + columnEntryPtr->width = maxIndicatorSpace + maxWidth + + 2 * menuPtr->activeBorderWidth; + geometryPtr->accelTextWidth = maxAccelTextWidth; + geometryPtr->modifierWidth = maxModifierWidth; + columnEntryPtr->x = x; + columnEntryPtr->entryFlags &= ~ENTRY_LAST_COLUMN; + if (maxEntryWithoutAccelWidth > maxEntryWithAccelWidth) { + geometryPtr->nonAccelMargin = maxEntryWithoutAccelWidth + - maxEntryWithAccelWidth; + if (geometryPtr->nonAccelMargin > maxNonAccelMargin) { + geometryPtr->nonAccelMargin = maxNonAccelMargin; + } + } else { + geometryPtr->nonAccelMargin = 0; + } + } + x += maxIndicatorSpace + maxWidth + 2 * menuPtr->borderWidth; + windowWidth = x; + maxWidth = maxIndicatorSpace = maxAccelTextWidth = 0; + maxModifierWidth = maxNonAccelMargin = maxEntryWithAccelWidth = 0; + maxEntryWithoutAccelWidth = 0; + lastColumnBreak = i; + y = menuPtr->borderWidth; + } + + if (mePtr->type == SEPARATOR_ENTRY) { + GetMenuSeparatorGeometry(menuPtr, mePtr, tkfont, + fmPtr, &entryWidth, &height); + mePtr->height = height; + } else if (mePtr->type == TEAROFF_ENTRY) { + GetTearoffEntryGeometry(menuPtr, mePtr, tkfont, + fmPtr, &entryWidth, &height); + mePtr->height = height; + } else { + + /* + * For each entry, compute the height required by that + * particular entry, plus three widths: the width of the + * label, the width to allow for an indicator to be displayed + * to the left of the label (if any), and the width of the + * accelerator to be displayed to the right of the label + * (if any). These sizes depend, of course, on the type + * of the entry. + */ + + GetMenuLabelGeometry(mePtr, tkfont, fmPtr, &labelWidth, + &height); + mePtr->height = height; + + if (mePtr->type == CASCADE_ENTRY) { + GetMenuAccelGeometry(menuPtr, mePtr, tkfont, fmPtr, + &modifierWidth, &accelWidth, &height); + nonAccelMargin = 0; + } else if (mePtr->accelLength == 0) { + nonAccelMargin = mePtr->hideMargin ? 0 + : Tk_TextWidth(tkfont, "m", 1); + accelWidth = modifierWidth = 0; + } else { + labelWidth += Tk_TextWidth(tkfont, "m", 1); + GetMenuAccelGeometry(menuPtr, mePtr, tkfont, + fmPtr, &modifierWidth, &accelWidth, &height); + if (height > mePtr->height) { + mePtr->height = height; + } + nonAccelMargin = 0; + } + + if (!(mePtr->hideMargin)) { + GetMenuIndicatorGeometry(menuPtr, mePtr, tkfont, + fmPtr, &indicatorSpace, &height); + if (height > mePtr->height) { + mePtr->height = height; + } + } else { + indicatorSpace = 0; + } + + if (nonAccelMargin > maxNonAccelMargin) { + maxNonAccelMargin = nonAccelMargin; + } + if (accelWidth > maxAccelTextWidth) { + maxAccelTextWidth = accelWidth; + } + if (modifierWidth > maxModifierWidth) { + maxModifierWidth = modifierWidth; + } + if (indicatorSpace > maxIndicatorSpace) { + maxIndicatorSpace = indicatorSpace; + } + + entryWidth = labelWidth + modifierWidth + accelWidth + + nonAccelMargin; + + if (entryWidth > maxWidth) { + maxWidth = entryWidth; + } + + if (mePtr->accelLength > 0) { + if (entryWidth > maxEntryWithAccelWidth) { + maxEntryWithAccelWidth = entryWidth; + } + } else { + if (entryWidth > maxEntryWithoutAccelWidth) { + maxEntryWithoutAccelWidth = entryWidth; + } + } + + mePtr->height += 2 * menuPtr->activeBorderWidth; + } + mePtr->y = y; + y += menuPtr->entries[i]->height + menuPtr->borderWidth; + if (y > windowHeight) { + windowHeight = y; + } + } + + for (j = lastColumnBreak; j < menuPtr->numEntries; j++) { + columnEntryPtr = menuPtr->entries[j]; + geometryPtr = (EntryGeometry *) columnEntryPtr->platformEntryData; + + columnEntryPtr->indicatorSpace = maxIndicatorSpace; + columnEntryPtr->width = maxIndicatorSpace + maxWidth + + 2 * menuPtr->activeBorderWidth; + geometryPtr->accelTextWidth = maxAccelTextWidth; + geometryPtr->modifierWidth = maxModifierWidth; + columnEntryPtr->x = x; + columnEntryPtr->entryFlags |= ENTRY_LAST_COLUMN; + if (maxEntryWithoutAccelWidth > maxEntryWithAccelWidth) { + geometryPtr->nonAccelMargin = maxEntryWithoutAccelWidth + - maxEntryWithAccelWidth; + if (geometryPtr->nonAccelMargin > maxNonAccelMargin) { + geometryPtr->nonAccelMargin = maxNonAccelMargin; + } + } else { + geometryPtr->nonAccelMargin = 0; + } + } + windowWidth = x + maxIndicatorSpace + maxWidth + + 2 * menuPtr->activeBorderWidth + menuPtr->borderWidth; + windowHeight += menuPtr->borderWidth; + + /* + * The X server doesn't like zero dimensions, so round up to at least + * 1 (a zero-sized menu should never really occur, anyway). + */ + + if (windowWidth <= 0) { + windowWidth = 1; + } + if (windowHeight <= 0) { + windowHeight = 1; + } + menuPtr->totalWidth = windowWidth; + menuPtr->totalHeight = windowHeight; +} + +/* + *---------------------------------------------------------------------- + * + * DrawMenuEntryLabel -- + * + * This procedure draws the label part of a menu. + * + * Results: + * None. + * + * Side effects: + * Commands are output to X to display the menu in its + * current mode. + * + *---------------------------------------------------------------------- + */ + +static void +DrawMenuEntryLabel( + TkMenu *menuPtr, /* The menu we are drawing */ + TkMenuEntry *mePtr, /* The entry we are drawing */ + Drawable d, /* What we are drawing into */ + GC gc, /* The gc we are drawing into */ + Tk_Font tkfont, /* The precalculated font */ + CONST Tk_FontMetrics *fmPtr, /* The precalculated font metrics */ + int x, /* left edge */ + int y, /* right edge */ + int width, /* width of entry */ + int height) /* height of entry */ +{ + int baseline; + int indicatorSpace = mePtr->indicatorSpace; + int leftEdge = x + indicatorSpace; + int imageHeight, imageWidth; + + /* + * Draw label or bitmap or image for entry. + */ + + baseline = y + (height + fmPtr->ascent - fmPtr->descent) / 2; + if (mePtr->image != NULL) { + Tk_SizeOfImage(mePtr->image, &imageWidth, &imageHeight); + if ((mePtr->selectImage != NULL) + && (mePtr->entryFlags & ENTRY_SELECTED)) { + Tk_RedrawImage(mePtr->selectImage, 0, 0, + imageWidth, imageHeight, d, leftEdge, + (int) (y + (mePtr->height - imageHeight)/2)); + } else { + Tk_RedrawImage(mePtr->image, 0, 0, imageWidth, + imageHeight, d, leftEdge, + (int) (y + (mePtr->height - imageHeight)/2)); + } + } else if (mePtr->bitmap != None) { + int width, height; + + Tk_SizeOfBitmap(menuPtr->display, + mePtr->bitmap, &width, &height); + XCopyPlane(menuPtr->display, + mePtr->bitmap, d, + gc, 0, 0, (unsigned) width, (unsigned) height, leftEdge, + (int) (y + (mePtr->height - height)/2), 1); + } else { + if (mePtr->labelLength > 0) { + Str255 itemText; + + GetEntryText(mePtr, itemText); + Tk_DrawChars(menuPtr->display, d, gc, + tkfont, (char *) itemText + 1, itemText[0], + leftEdge, baseline); +/* TkpDrawMenuUnderline(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, y, + width, height);*/ + } + } + + if (mePtr->state == tkDisabledUid) { + if (menuPtr->disabledFg == NULL) { + XFillRectangle(menuPtr->display, d, menuPtr->disabledGC, x, y, + (unsigned) width, (unsigned) height); + } else if ((mePtr->image != NULL) + && (menuPtr->disabledImageGC != None)) { + XFillRectangle(menuPtr->display, d, menuPtr->disabledImageGC, + leftEdge, + (int) (y + (mePtr->height - imageHeight)/2), + (unsigned) imageWidth, (unsigned) imageHeight); + } + } +} + +/* + *---------------------------------------------------------------------- + * + * DrawMenuEntryBackground -- + * + * This procedure draws the background part of a menu. + * + * Results: + * None. + * + * Side effects: + * Commands are output to X to display the menu in its + * current mode. + * + *---------------------------------------------------------------------- + */ + +static void +DrawMenuEntryBackground( + TkMenu *menuPtr, /* The menu we are drawing. */ + TkMenuEntry *mePtr, /* The entry we are drawing. */ + Drawable d, /* What we are drawing into */ + Tk_3DBorder activeBorder, /* Border for active items */ + Tk_3DBorder bgBorder, /* Border for the background */ + int x, /* left edge */ + int y, /* top edge */ + int width, /* width of rectangle to draw */ + int height) /* height of rectangle to draw */ +{ + if (mePtr->state == tkActiveUid) { + bgBorder = activeBorder; + } + Tk_Fill3DRectangle(menuPtr->tkwin, d, bgBorder, + x, y, width, height, 0, TK_RELIEF_FLAT); +} + +/* + *---------------------------------------------------------------------- + * + * GetMenuLabelGeometry -- + * + * Figures out the size of the label portion of a menu item. + * + * Results: + * widthPtr and heightPtr are filled in with the correct geometry + * information. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static void +GetMenuLabelGeometry( + TkMenuEntry *mePtr, /* The entry we are computing */ + Tk_Font tkfont, /* The precalculated font */ + CONST Tk_FontMetrics *fmPtr, /* The precalculated metrics */ + int *widthPtr, /* The resulting width of the label + * portion */ + int *heightPtr) /* The resulting height of the label + * portion */ +{ + TkMenu *menuPtr = mePtr->menuPtr; + + if (mePtr->image != NULL) { + Tk_SizeOfImage(mePtr->image, widthPtr, heightPtr); + } else if (mePtr->bitmap != (Pixmap) NULL) { + Tk_SizeOfBitmap(menuPtr->display, mePtr->bitmap, widthPtr, heightPtr); + } else { + *heightPtr = fmPtr->linespace; + + if (mePtr->label != NULL) { + Str255 itemText; + + GetEntryText(mePtr, itemText); + *widthPtr = Tk_TextWidth(tkfont, (char *) itemText + 1, + itemText[0]); + } else { + *widthPtr = 0; + } + } + *heightPtr += 1; +} + +/* + *---------------------------------------------------------------------- + * + * MenuSelectEvent -- + * + * Generates a "MenuSelect" virtual event. This can be used to + * do context-sensitive menu help. + * + * Results: + * None. + * + * Side effects: + * Places a virtual event on the event queue. + * + *---------------------------------------------------------------------- + */ + +static void +MenuSelectEvent( + TkMenu *menuPtr) /* the menu we have selected. */ +{ + XVirtualEvent event; + Point where; + + event.type = VirtualEvent; + event.serial = menuPtr->display->request; + event.send_event = false; + event.display = menuPtr->display; + Tk_MakeWindowExist(menuPtr->tkwin); + event.event = Tk_WindowId(menuPtr->tkwin); + event.root = XRootWindow(menuPtr->display, 0); + event.subwindow = None; + event.time = TkpGetMS(); + + GetMouse(&where); + event.x_root = where.h; + event.y_root = where.v; + event.state = TkMacButtonKeyState(); + event.same_screen = true; + event.name = Tk_GetUid("MenuSelect"); + Tk_QueueWindowEvent((XEvent *) &event, TCL_QUEUE_TAIL); +} + +/* + *---------------------------------------------------------------------- + * + * RecursivelyClearActiveMenu -- + * + * Recursively clears the active entry in the menu's cascade hierarchy. + * + * Results: + * None. + * + * Side effects: + * Generates <<MenuSelect>> virtual events. + * + *---------------------------------------------------------------------- + */ + +void +RecursivelyClearActiveMenu( + TkMenu *menuPtr) /* The menu to reset. */ +{ + int i; + TkMenuEntry *mePtr; + + TkActivateMenuEntry(menuPtr, -1); + MenuSelectEvent(menuPtr); + 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); + } + } + } +} + +/* + *---------------------------------------------------------------------- + * + * InvalidateMDEFRgns -- + * + * Invalidates the regions covered by menus that did redrawing and + * might be damaged. + * + * Results: + * None. + * + * Side effects: + * Generates Mac update events for affected windows. + * + *---------------------------------------------------------------------- + */ + +void +InvalidateMDEFRgns(void) { + GDHandle saveDevice; + GWorldPtr saveWorld, destPort; + Point scratch; + MacDrawable *macDraw; + TkMacWindowList *listPtr; + + if (totalMenuRgn == NULL) { + return; + } + + GetGWorld(&saveWorld, &saveDevice); + for (listPtr = tkMacWindowListPtr ; listPtr != NULL; + listPtr = listPtr->nextPtr) { + macDraw = (MacDrawable *) Tk_WindowId(listPtr->winPtr); + if (macDraw->flags & TK_DRAWN_UNDER_MENU) { + destPort = TkMacGetDrawablePort(Tk_WindowId(listPtr->winPtr)); + SetGWorld(destPort, NULL); + scratch.h = scratch.v = 0; + GlobalToLocal(&scratch); + OffsetRgn(totalMenuRgn, scratch.v, scratch.h); + InvalRgn(totalMenuRgn); + OffsetRgn(totalMenuRgn, -scratch.v, -scratch.h); + macDraw->flags &= ~TK_DRAWN_UNDER_MENU; + } + } + + SetGWorld(saveWorld, saveDevice); + SetEmptyRgn(totalMenuRgn); +} + +/* + *---------------------------------------------------------------------- + * + * TkMacClearMenubarActive -- + * + * Recursively clears the active entry in the current menubar hierarchy. + * + * Results: + * None. + * + * Side effects: + * Generates <<MenuSelect>> virtual events. + * + *---------------------------------------------------------------------- + */ + +void +TkMacClearMenubarActive(void) { + TkMenuReferences *menuBarRefPtr; + + if (currentMenuBarName != NULL) { + menuBarRefPtr = TkFindMenuReferences(currentMenuBarInterp, + currentMenuBarName); + if ((menuBarRefPtr != NULL) && (menuBarRefPtr->menuPtr != NULL)) { + TkMenu *menuPtr; + + for (menuPtr = menuBarRefPtr->menuPtr->masterMenuPtr; menuPtr != NULL; + menuPtr = menuPtr->nextInstancePtr) { + if (menuPtr->menuType == MENUBAR) { + RecursivelyClearActiveMenu(menuPtr); + } + } + } + } + InvalidateMDEFRgns(); + FixMDEF(); +} + +/* + *---------------------------------------------------------------------- + * + * 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. + */ +} + +/* + *---------------------------------------------------------------------- + * + * FixMDEF -- + * + * Loads the MDEF and blasts our routine descriptor into it. + * We have to set up the MDEF. This is pretty slimy. The real MDEF + * resource is 68K code. All this code does is call another procedure. + * When the application in launched, a dummy value for the procedure + * is compiled into the MDEF. We are going to replace that dummy + * value with a routine descriptor. When the routine descriptor + * is invoked, the globals and everything will be setup, and we + * can do what we need. This will not work from 68K or CFM 68k + * currently, so we will conditional compile this until we + * figure it out. + * + * Results: + * None. + * + * Side effects: + * Allcates a hash table. + * + *---------------------------------------------------------------------- + */ + +static void +FixMDEF(void) +{ +#ifdef GENERATINGCFM + Handle MDEFHandle = GetResource('MDEF', 591); + Handle SICNHandle = GetResource('SICN', SICN_RESOURCE_NUMBER); + if ((MDEFHandle != NULL) && (SICNHandle != NULL)) { + MoveHHi(MDEFHandle); + HLock(MDEFHandle); + menuDefProc = TkNewMenuDefProc(MenuDefProc); + memmove((void *) (((long) (*MDEFHandle)) + 0x24), &menuDefProc, 4); + } +#endif +} + +/* + *---------------------------------------------------------------------- + * + * TkpMenuInit -- + * + * Initializes Mac-specific menu data. + * + * Results: + * None. + * + * Side effects: + * Allcates a hash table. + * + *---------------------------------------------------------------------- + */ + +void +TkpMenuInit(void) +{ + lastMenuID = 256; + Tcl_InitHashTable(&commandTable, TCL_ONE_WORD_KEYS); + currentMenuBarOwner = NULL; + tearoffStruct.menuPtr = NULL; + currentAppleMenuID = 0; + currentHelpMenuID = 0; + currentMenuBarInterp = NULL; + currentMenuBarName = NULL; + windowListPtr = NULL; +} diff --git a/mac/tkMacMenu.r b/mac/tkMacMenu.r new file mode 100644 index 0000000..9952cea --- /dev/null +++ b/mac/tkMacMenu.r @@ -0,0 +1,47 @@ +/* + * tkMacMenu.r -- + * + * Resources needed by menus. + * + * This file also contains the icons 'SICN' used by the menu code + * in menu items. + * + * Copyright (c) 1997 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) tkMacMenu.r 1.1 97/07/11 18:06:27 + */ + +#include <Types.r> + +/* + * Icons used in menu items. + */ + +resource 'SICN' (128, preload) { + { /* array: 7 elements */ + /* [1] */ + $"0000 0000 8000 C000 E000 F000 F800 FC00" + $"F800 F000 E000 C000 80", + /* [2] */ + $"0000 0000 0000 0800 1400 2200 4100 8080" + $"E380 2200 2200 2200 3E", + /* [3] */ + $"0000 0000 0000 0000 0000 F8F0 C4F0 F270" + $"0900 0480 0270 0130 00F0", + /* [4] */ + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 E4E0 CE60 1B00 3180", + /* [5] */ + $"0000 0000 0000 0000 6300 9480 9480 7F00" + $"1400 7F00 9480 9480 63", + /* [6] */ + $"0000 0000 0000 0000 0000 3FF8 1FF0 0FE0" + $"07C0 0380 01", + /* [7] */ + $"0000 0000 0000 0000 0000 0100 0380 07C0" + $"0FE0 1FF0 3FF8" + } +}; diff --git a/mac/tkMacMenubutton.c b/mac/tkMacMenubutton.c new file mode 100644 index 0000000..42b8d2b --- /dev/null +++ b/mac/tkMacMenubutton.c @@ -0,0 +1,339 @@ +/* + * tkMacMenubutton.c -- + * + * This file implements the Macintosh specific portion of the + * menubutton widget. + * + * Copyright (c) 1996 by Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) tkMacMenubutton.c 1.4 97/01/03 13:55:19 + */ + +#include "tkMenubutton.h" +#include "tkMacInt.h" +#include <Controls.h> + +#define kShadowOffset (3) /* amount to offset shadow from frame */ +#define kTriangleWidth (11) /* width of the triangle */ +#define kTriangleHeight (6) /* height of the triangle */ +#define kTriangleMargin (5) /* margin around triangle */ + +/* + * Declaration of Unix specific button structure. + */ + +typedef struct MacMenuButton { + TkMenuButton info; /* Generic button info. */ +} MacMenuButton; + +/* + * The structure below defines menubutton class behavior by means of + * procedures that can be invoked from generic window code. + */ + +TkClassProcs tkpMenubuttonClass = { + NULL, /* createProc. */ + TkMenuButtonWorldChanged, /* geometryProc. */ + NULL /* modalProc. */ +}; + +/* + *---------------------------------------------------------------------- + * + * TkpCreateMenuButton -- + * + * Allocate a new TkMenuButton structure. + * + * Results: + * Returns a newly allocated TkMenuButton structure. + * + * Side effects: + * Registers an event handler for the widget. + * + *---------------------------------------------------------------------- + */ + +TkMenuButton * +TkpCreateMenuButton( + Tk_Window tkwin) +{ + MacMenuButton *butPtr = (MacMenuButton *)ckalloc(sizeof(MacMenuButton)); + + return (TkMenuButton *) butPtr; +} + +/* + *---------------------------------------------------------------------- + * + * TkpDisplayMenuButton -- + * + * This procedure is invoked to display a menubutton widget. + * + * Results: + * None. + * + * Side effects: + * Commands are output to X to display the menubutton in its + * current mode. + * + *---------------------------------------------------------------------- + */ + +void +TkpDisplayMenuButton( + ClientData clientData) /* Information about widget. */ +{ + TkMenuButton *mbPtr = (TkMenuButton *) clientData; + GC gc; + Tk_3DBorder border; + int x = 0; /* Initialization needed only to stop + * compiler warning. */ + int y; + Tk_Window tkwin = mbPtr->tkwin; + int width, height; + MacMenuButton * macMBPtr = (MacMenuButton *) mbPtr; + GWorldPtr destPort; + CGrafPtr saveWorld; + GDHandle saveDevice; + MacDrawable *macDraw; + + mbPtr->flags &= ~REDRAW_PENDING; + if ((mbPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) { + return; + } + + GetGWorld(&saveWorld, &saveDevice); + destPort = TkMacGetDrawablePort(Tk_WindowId(tkwin)); + SetGWorld(destPort, NULL); + macDraw = (MacDrawable *) Tk_WindowId(tkwin); + + if ((mbPtr->state == tkDisabledUid) && (mbPtr->disabledFg != NULL)) { + gc = mbPtr->disabledGC; + } else if ((mbPtr->state == tkActiveUid) && !Tk_StrictMotif(mbPtr->tkwin)) { + gc = mbPtr->activeTextGC; + } else { + gc = mbPtr->normalTextGC; + } + border = mbPtr->normalBorder; + + /* + * In order to avoid screen flashes, this procedure redraws + * the menu button in a pixmap, then copies the pixmap to the + * screen in a single operation. This means that there's no + * point in time where the on-sreen image has been cleared. + */ + + Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), border, 0, 0, + Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT); + + /* + * Display image or bitmap or text for button. + */ + + if (mbPtr->image != None) { + Tk_SizeOfImage(mbPtr->image, &width, &height); + + imageOrBitmap: + TkComputeAnchor(mbPtr->anchor, tkwin, 0, 0, + width + mbPtr->indicatorWidth, height, &x, &y); + if (mbPtr->image != NULL) { + Tk_RedrawImage(mbPtr->image, 0, 0, width, height, + Tk_WindowId(tkwin), x, y); + } else { + XCopyPlane(mbPtr->display, mbPtr->bitmap, Tk_WindowId(tkwin), + gc, 0, 0, (unsigned) width, (unsigned) height, x, y, 1); + } + } else if (mbPtr->bitmap != None) { + Tk_SizeOfBitmap(mbPtr->display, mbPtr->bitmap, &width, &height); + goto imageOrBitmap; + } else { + TkComputeAnchor(mbPtr->anchor, tkwin, mbPtr->padX, mbPtr->padY, + mbPtr->textWidth + mbPtr->indicatorWidth, mbPtr->textHeight, + &x, &y); + Tk_DrawTextLayout(mbPtr->display, Tk_WindowId(tkwin), gc, + mbPtr->textLayout, x, y, 0, -1); + } + + /* + * If the menu button is disabled with a stipple rather than a special + * foreground color, generate the stippled effect. + */ + + if ((mbPtr->state == tkDisabledUid) + && ((mbPtr->disabledFg == NULL) || (mbPtr->image != NULL))) { + XFillRectangle(mbPtr->display, Tk_WindowId(tkwin), mbPtr->disabledGC, + mbPtr->inset, mbPtr->inset, + (unsigned) (Tk_Width(tkwin) - 2*mbPtr->inset), + (unsigned) (Tk_Height(tkwin) - 2*mbPtr->inset)); + } + + /* + * Draw the cascade indicator for the menu button on the + * right side of the window, if desired. + */ + + if (mbPtr->indicatorOn) { + int w, h, i; + Rect r; + + r.left = macDraw->xOff + Tk_Width(tkwin) - mbPtr->inset + - mbPtr->indicatorWidth; + r.top = macDraw->yOff + Tk_Height(tkwin)/2 + - mbPtr->indicatorHeight/2; + r.right = macDraw->xOff + Tk_Width(tkwin) - mbPtr->inset + - kTriangleMargin; + r.bottom = macDraw->yOff + Tk_Height(tkwin)/2 + + mbPtr->indicatorHeight/2; + + h = mbPtr->indicatorHeight; + w = mbPtr->indicatorWidth - 1 - kTriangleMargin; + for (i = 0; i < h; i++) { + MoveTo(r.left + i, r.top + i); + LineTo(r.left + i + w, r.top + i); + w -= 2; + } + } + + /* + * Draw the border and traversal highlight last. This way, if the + * menu button's contents overflow onto the border they'll be covered + * up by the border. + */ + + TkMacSetUpClippingRgn(Tk_WindowId(tkwin)); + if (mbPtr->borderWidth > 0) { + Rect r; + + r.left = macDraw->xOff + mbPtr->highlightWidth + mbPtr->borderWidth; + r.top = macDraw->yOff + mbPtr->highlightWidth + mbPtr->borderWidth; + r.right = macDraw->xOff + Tk_Width(tkwin) - mbPtr->highlightWidth + - mbPtr->borderWidth; + r.bottom = macDraw->yOff + Tk_Height(tkwin) - mbPtr->highlightWidth + - mbPtr->borderWidth; + FrameRect(&r); + + PenSize(mbPtr->borderWidth - 1, mbPtr->borderWidth - 1); + MoveTo(r.right, r.top + kShadowOffset); + LineTo(r.right, r.bottom); + LineTo(r.left + kShadowOffset, r.bottom); + } + + if (mbPtr->state == tkDisabledUid) { + } + + if (mbPtr->highlightWidth != 0) { + GC gc; + + if (mbPtr->flags & GOT_FOCUS) { + gc = Tk_GCForColor(mbPtr->highlightColorPtr, Tk_WindowId(tkwin)); + } else { + gc = Tk_GCForColor(mbPtr->highlightBgColorPtr, Tk_WindowId(tkwin)); + } + Tk_DrawFocusHighlight(tkwin, gc, mbPtr->highlightWidth, + Tk_WindowId(tkwin)); + } + + SetGWorld(saveWorld, saveDevice); +} + +/* + *---------------------------------------------------------------------- + * + * TkpDestroyMenuButton -- + * + * Free data structures associated with the menubutton control. + * + * Results: + * None. + * + * Side effects: + * Restores the default control state. + * + *---------------------------------------------------------------------- + */ + +void +TkpDestroyMenuButton( + TkMenuButton *mbPtr) +{ +} + +/* + *---------------------------------------------------------------------- + * + * TkpComputeMenuButtonGeometry -- + * + * After changes in a menu button's text or bitmap, this procedure + * recomputes the menu button's geometry and passes this information + * along to the geometry manager for the window. + * + * Results: + * None. + * + * Side effects: + * The menu button's window may change size. + * + *---------------------------------------------------------------------- + */ + +void +TkpComputeMenuButtonGeometry(mbPtr) + register TkMenuButton *mbPtr; /* Widget record for menu button. */ +{ + int width, height, mm, pixels; + + mbPtr->inset = mbPtr->highlightWidth + mbPtr->borderWidth; + if (mbPtr->image != None) { + Tk_SizeOfImage(mbPtr->image, &width, &height); + if (mbPtr->width > 0) { + width = mbPtr->width; + } + if (mbPtr->height > 0) { + height = mbPtr->height; + } + } else if (mbPtr->bitmap != None) { + Tk_SizeOfBitmap(mbPtr->display, mbPtr->bitmap, &width, &height); + if (mbPtr->width > 0) { + width = mbPtr->width; + } + if (mbPtr->height > 0) { + height = mbPtr->height; + } + } else { + Tk_FreeTextLayout(mbPtr->textLayout); + mbPtr->textLayout = Tk_ComputeTextLayout(mbPtr->tkfont, mbPtr->text, + -1, mbPtr->wrapLength, mbPtr->justify, 0, &mbPtr->textWidth, + &mbPtr->textHeight); + width = mbPtr->textWidth; + height = mbPtr->textHeight; + if (mbPtr->width > 0) { + width = mbPtr->width * Tk_TextWidth(mbPtr->tkfont, "0", 1); + } + if (mbPtr->height > 0) { + Tk_FontMetrics fm; + + Tk_GetFontMetrics(mbPtr->tkfont, &fm); + height = mbPtr->height * fm.linespace; + } + width += 2*mbPtr->padX; + height += 2*mbPtr->padY; + } + + if (mbPtr->indicatorOn) { + mm = WidthMMOfScreen(Tk_Screen(mbPtr->tkwin)); + pixels = WidthOfScreen(Tk_Screen(mbPtr->tkwin)); + mbPtr->indicatorHeight= kTriangleHeight; + mbPtr->indicatorWidth = kTriangleWidth + kTriangleMargin; + width += mbPtr->indicatorWidth; + } else { + mbPtr->indicatorHeight = 0; + mbPtr->indicatorWidth = 0; + } + + Tk_GeometryRequest(mbPtr->tkwin, (int) (width + 2*mbPtr->inset), + (int) (height + 2*mbPtr->inset)); + Tk_SetInternalBorder(mbPtr->tkwin, mbPtr->inset); +} diff --git a/mac/tkMacMenus.c b/mac/tkMacMenus.c new file mode 100644 index 0000000..6eaf0ae --- /dev/null +++ b/mac/tkMacMenus.c @@ -0,0 +1,346 @@ +/* + * tkMacMenus.c -- + * + * These calls set up and manage the menubar for the + * Macintosh version of Tk. + * + * Copyright (c) 1995-1996 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) tkMacMenus.c 1.38 97/10/31 17:37:03 + */ + +#include "tcl.h" +#include "tclMacInt.h" +#include "tk.h" +#include "tkInt.h" +#include "tkMacInt.h" + +/* + * The define Status defined by Xlib.h conflicts with the function Status + * defined by Devices.h. We undefine it here to compile. + */ +#undef Status +#include <Devices.h> +#include <Menus.h> +#include <Memory.h> +#include <SegLoad.h> +#include <StandardFile.h> +#include <ToolUtils.h> +#include <Balloons.h> + +#define kAppleMenu 256 +#define kAppleAboutItem 1 +#define kFileMenu 2 +#define kEditMenu 3 + +#define kSourceItem 1 +#define kCloseItem 2 +#define kQuitItem 4 + +#define EDIT_CUT 1 +#define EDIT_COPY 2 +#define EDIT_PASTE 3 +#define EDIT_CLEAR 4 + +MenuHandle tkAppleMenu; +MenuHandle tkFileMenu; +MenuHandle tkEditMenu; + +static Tcl_Interp * gInterp; /* Interpreter for this application. */ + +static void GenerateEditEvent _ANSI_ARGS_((int flag)); +static void SourceDialog _ANSI_ARGS_((void)); + +/* + *---------------------------------------------------------------------- + * + * TkMacHandleMenuSelect -- + * + * Handles events that occur in the Menu bar. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +TkMacHandleMenuSelect( + long mResult, + int optionKeyPressed) +{ + short theItem = LoWord(mResult); + short theMenu = HiWord(mResult); + Str255 name; + Tk_Window tkwin; + Window window; + + if (mResult == 0) { + TkMacHandleTearoffMenu(); + TkMacClearMenubarActive(); + return; + } + + switch (theMenu) { + + case kAppleMenu: + switch (theItem) { + case kAppleAboutItem: + { + Tcl_CmdInfo dummy; + + if (optionKeyPressed || gInterp == NULL || + Tcl_GetCommandInfo(gInterp, + "tkAboutDialog", &dummy) == 0) { + TkAboutDlg(); + } else { + Tcl_Eval(gInterp, "tkAboutDialog"); + } + break; + } + default: + GetItem(tkAppleMenu, theItem, name); + HiliteMenu(0); + OpenDeskAcc(name); + return; + } + break; + case kFileMenu: + switch (theItem) { + case kSourceItem: + /* TODO: source script */ + SourceDialog(); + break; + case kCloseItem: + /* Send close event */ + window = TkMacGetXWindow(FrontWindow()); + tkwin = Tk_IdToWindow(tkDisplayList->display, window); + TkGenWMDestroyEvent(tkwin); + break; + case kQuitItem: + /* Exit */ + if (optionKeyPressed || gInterp == NULL) { + Tcl_Exit(0); + } else { + Tcl_Eval(gInterp, "exit"); + } + break; + } + break; + case kEditMenu: + /* + * This implementation just send keysyms + * the Tk thinks are associated with function keys that + * do Cut, Copy & Paste on a Sun keyboard. + */ + GenerateEditEvent(theItem); + break; + default: + TkMacDispatchMenuEvent(theMenu, theItem); + TkMacClearMenubarActive(); + break; + } + + /* + * Finally we unhighlight the menu. + */ + HiliteMenu(0); +} /* TkMacHandleMenuSelect */ + +/* + *---------------------------------------------------------------------- + * + * TkMacInitMenus -- + * + * This procedure initializes the Macintosh menu bar. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +TkMacInitMenus( + Tcl_Interp *interp) +{ + gInterp = interp; + + /* + * At this point, InitMenus() should have already been called. + */ + + if (TkMacUseMenuID(256) != TCL_OK) { + panic("Menu ID 256 is already in use!"); + } + tkAppleMenu = NewMenu(256, "\p\024"); + if (tkAppleMenu == NULL) { + panic("memory - menus"); + } + InsertMenu(tkAppleMenu, 0); + AppendMenu(tkAppleMenu, "\pAbout Tcl & TkÉ"); + AppendMenu(tkAppleMenu, "\p(-"); + AddResMenu(tkAppleMenu, 'DRVR'); + + if (TkMacUseMenuID(kFileMenu) != TCL_OK) { + panic("Menu ID %d is already in use!", kFileMenu); + } + tkFileMenu = NewMenu(kFileMenu, "\pFile"); + if (tkFileMenu == NULL) { + panic("memory - menus"); + } + InsertMenu(tkFileMenu, 0); + AppendMenu(tkFileMenu, "\pSourceÉ"); + AppendMenu(tkFileMenu, "\pClose/W"); + AppendMenu(tkFileMenu, "\p(-"); + AppendMenu(tkFileMenu, "\pQuit/Q"); + + if (TkMacUseMenuID(kEditMenu) != TCL_OK) { + panic("Menu ID %d is already in use!", kEditMenu); + } + tkEditMenu = NewMenu(kEditMenu, "\pEdit"); + if (tkEditMenu == NULL) { + panic("memory - menus"); + } + InsertMenu(tkEditMenu, 0); + AppendMenu(tkEditMenu, "\pCut/X"); + AppendMenu(tkEditMenu, "\pCopy/C"); + AppendMenu(tkEditMenu, "\pPaste/V"); + AppendMenu(tkEditMenu, "\pClear"); + if (TkMacUseMenuID(kHMHelpMenuID) != TCL_OK) { + panic("Help menu ID %s is already in use!", kHMHelpMenuID); + } + + DrawMenuBar(); + TkMacSetHelpMenuItemCount(); + + return; +} + +/* + *---------------------------------------------------------------------- + * + * GenerateEditEvent -- + * + * Takes an edit menu item and posts the corasponding a virtual + * event to Tk's event queue. + * + * Results: + * None. + * + * Side effects: + * May place events of queue. + * + *---------------------------------------------------------------------- + */ + +static void +GenerateEditEvent( + int flag) +{ + XVirtualEvent event; + Point where; + Tk_Window tkwin; + Window window; + + window = TkMacGetXWindow(FrontWindow()); + tkwin = Tk_IdToWindow(tkDisplayList->display, window); + tkwin = (Tk_Window) ((TkWindow *) tkwin)->dispPtr->focusPtr; + if (tkwin == NULL) { + return; + } + + event.type = VirtualEvent; + event.serial = Tk_Display(tkwin)->request; + event.send_event = false; + event.display = Tk_Display(tkwin); + event.event = Tk_WindowId(tkwin); + event.root = XRootWindow(Tk_Display(tkwin), 0); + event.subwindow = None; + event.time = TkpGetMS(); + + GetMouse(&where); + tkwin = Tk_TopCoordsToWindow(tkwin, where.h, where.v, + &event.x, &event.y); + LocalToGlobal(&where); + event.x_root = where.h; + event.y_root = where.v; + event.state = TkMacButtonKeyState(); + event.same_screen = true; + + switch (flag) { + case EDIT_CUT: + event.name = Tk_GetUid("Cut"); + break; + + case EDIT_COPY: + event.name = Tk_GetUid("Copy"); + break; + + case EDIT_PASTE: + event.name = Tk_GetUid("Paste"); + break; + + case EDIT_CLEAR: + event.name = Tk_GetUid("Clear"); + break; + } + Tk_QueueWindowEvent((XEvent *) &event, TCL_QUEUE_TAIL); +} + +/* + *---------------------------------------------------------------------- + * + * SourceDialog -- + * + * Presents a dialog to the user for selecting a Tcl file. The + * selected file will be sourced into the main interpreter. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static void +SourceDialog() +{ + StandardFileReply reply; + OSType fileTypes[1]; + OSErr err; + int length, result; + Handle path; + + if (gInterp == NULL) { + return; + } + + fileTypes[0] = 'TEXT'; + StandardGetFile(NULL, 1, fileTypes, &reply); + if (reply.sfGood == false) { + return; + } + + err = FSpPathFromLocation(&reply.sfFile, &length, &path); + if (err == noErr) { + HLock(path); + result = Tcl_EvalFile(gInterp, *path); + HUnlock(path); + DisposeHandle(path); + } + if (result == TCL_ERROR) { + Tcl_BackgroundError(gInterp); + } +} diff --git a/mac/tkMacPort.h b/mac/tkMacPort.h new file mode 100644 index 0000000..733e745 --- /dev/null +++ b/mac/tkMacPort.h @@ -0,0 +1,145 @@ +/* + * tkMacPort.h -- + * + * This file is included by all of the Tk C files. It contains + * information that may be configuration-dependent, such as + * #includes for system include files and a few other things. + * + * Copyright (c) 1994-1996 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) tkMacPort.h 1.52 97/07/28 11:18:59 + */ + +#ifndef _TKMACPORT +#define _TKMACPORT + +/* + * Macro to use instead of "void" for arguments that must have + * type "void *" in ANSI C; maps them to type "char *" in + * non-ANSI systems. This macro may be used in some of the include + * files below, which is why it is defined here. + */ + +#ifndef VOID +# ifdef __STDC__ +# define VOID void +# else +# define VOID char +# endif +#endif + +#ifndef _TCL +# include <tcl.h> +#endif + +#include <time.h> +#include <stdlib.h> +#include <string.h> +#include "tclMath.h" +#include <ctype.h> +#include <limits.h> + +#include <Xlib.h> +#include <cursorfont.h> +#include <keysym.h> +#include <Xatom.h> +#include <Xfuncproto.h> +#include <Xutil.h> + +/* + * Not all systems declare the errno variable in errno.h. so this + * file does it explicitly. + */ + +extern int errno; + +/* + * Define "NBBY" (number of bits per byte) if it's not already defined. + */ + +#ifndef NBBY +# define NBBY 8 +#endif + +/* + * Declarations for various library procedures that may not be declared + * in any other header file. + */ + +extern void panic _ANSI_ARGS_(TCL_VARARGS(char *, string)); +extern int strcasecmp _ANSI_ARGS_((CONST char *s1, + CONST char *s2)); +extern int strncasecmp _ANSI_ARGS_((CONST char *s1, + CONST char *s2, size_t n)); + +/* + * Defines for X functions that are used by Tk but are treated as + * no-op functions on the Macintosh. + */ + +#define XFlush(display) +#define XFree(data) {if ((data) != NULL) ckfree((char *) (data));} +#define XGrabServer(display) +#define XNoOp(display) {display->request++;} +#define XUngrabServer(display) +#define XSynchronize(display, bool) {display->request++;} +#define XSync(display, bool) {display->request++;} +#define XVisualIDFromVisual(visual) (visual->visualid) + +/* + * The following functions are not used on the Mac, so we stub it out. + */ + +#define TkFreeWindowId(dispPtr,w) +#define TkInitXId(dispPtr) +#define TkpCmapStressed(tkwin,colormap) (0) +#define TkpFreeColor(tkColPtr) +#define TkSetPixmapColormap(p,c) {} +#define Tk_FreeXId(display,xid) +#define TkpSync(display) + +/* + * The following macro returns the pixel value that corresponds to the + * RGB values in the given XColor structure. + */ + +#define PIXEL_MAGIC ((unsigned char) 0x69) +#define TkpGetPixel(p) ((((((PIXEL_MAGIC << 8) \ + | (((p)->red >> 8) & 0xff)) << 8) \ + | (((p)->green >> 8) & 0xff)) << 8) \ + | (((p)->blue >> 8) & 0xff)) + +/* + * This macro stores a representation of the window handle in a string. + */ + +#define TkpPrintWindowId(buf,w) \ + sprintf((buf), "0x%x", (unsigned int) (w)) + +/* + * TkpScanWindowId is just an alias for Tcl_GetInt on Unix. + */ + +#define TkpScanWindowId(i,s,wp) \ + Tcl_GetInt((i),(s),(wp)) + +/* + * Magic pixel values for dynamic (or active) colors. + */ + +#define HIGHLIGHT_PIXEL 31 +#define HIGHLIGHT_TEXT_PIXEL 33 +#define CONTROL_TEXT_PIXEL 35 +#define CONTROL_BODY_PIXEL 37 +#define CONTROL_FRAME_PIXEL 39 +#define WINDOW_BODY_PIXEL 41 +#define MENU_ACTIVE_PIXEL 43 +#define MENU_ACTIVE_TEXT_PIXEL 45 +#define MENU_BACKGROUND_PIXEL 47 +#define MENU_DISABLED_PIXEL 49 +#define MENU_TEXT_PIXEL 51 + +#endif /* _TKMACPORT */ diff --git a/mac/tkMacProlog.c b/mac/tkMacProlog.c new file mode 100644 index 0000000..21cf67c --- /dev/null +++ b/mac/tkMacProlog.c @@ -0,0 +1,61 @@ +/* + * tkMacProlog.c -- + * + * Implements a method on the Macintosh to get the prolog + * from the resource fork of our application (or the shared + * library). + * + * Copyright (c) 1996-1997 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) tkMacProlog.c 1.6 97/05/21 10:01:07 + */ + +#include "tkInt.h" +#include "tclMacInt.h" +#include <Resources.h> + +/* + *-------------------------------------------------------------- + * + * TkGetNativeProlog -- + * + * Locate and load the postscript prolog from the resource + * fork of the application. If it can't be found then we + * will try looking for the file in the system folder. + * + * Results: + * A standard Tcl Result. If everything is OK the prolog + * will be located in the result string of the interpreter. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +int +TkGetNativeProlog( + Tcl_Interp *interp) /* Places the prolog in the result. */ +{ + Handle resource; + char *stringPtr; + int releaseIt; + + + resource = Tcl_MacFindResource(interp, 'TEXT', "prolog", -1, + NULL, &releaseIt); + + if (resource != NULL) { + stringPtr = Tcl_MacConvertTextResource(resource); + Tcl_SetResult(interp, stringPtr, TCL_DYNAMIC); + if (releaseIt) { + ReleaseResource(resource); + } + return TCL_OK; + } else { + return TkGetProlog(interp); + } +} diff --git a/mac/tkMacRegion.c b/mac/tkMacRegion.c new file mode 100644 index 0000000..534624c --- /dev/null +++ b/mac/tkMacRegion.c @@ -0,0 +1,217 @@ +/* + * tkMacRegion.c -- + * + * Implements X window calls for manipulating regions + * + * Copyright (c) 1995-1996 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) tkMacRegion.c 1.9 96/12/03 11:46:50 + */ + +#include "tkInt.h" +#include "X.h" +#include "Xlib.h" + +#include <Windows.h> +#include <QDOffscreen.h> + +/* + * Temporary region that can be reused. + */ +static RgnHandle tmpRgn = NULL; + + +/* + *---------------------------------------------------------------------- + * + * TkCreateRegion -- + * + * Implements the equivelent of the X window function + * XCreateRegion. See X window documentation for more details. + * + * Results: + * Returns an allocated region handle. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +TkRegion +TkCreateRegion() +{ + RgnHandle rgn; + + rgn = NewRgn(); + return (TkRegion) rgn; +} + +/* + *---------------------------------------------------------------------- + * + * TkDestroyRegion -- + * + * Implements the equivelent of the X window function + * XDestroyRegion. See X window documentation for more details. + * + * Results: + * None. + * + * Side effects: + * Memory is freed. + * + *---------------------------------------------------------------------- + */ + +void +TkDestroyRegion( + TkRegion r) +{ + RgnHandle rgn = (RgnHandle) r; + + DisposeRgn(rgn); +} + +/* + *---------------------------------------------------------------------- + * + * TkIntersectRegion -- + * + * Implements the equivilent of the X window function + * XIntersectRegion. See X window documentation for more details. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +TkIntersectRegion( + TkRegion sra, + TkRegion srb, + TkRegion dr_return) +{ + RgnHandle srcRgnA = (RgnHandle) sra; + RgnHandle srcRgnB = (RgnHandle) srb; + RgnHandle destRgn = (RgnHandle) dr_return; + + SectRgn(srcRgnA, srcRgnB, destRgn); +} + +/* + *---------------------------------------------------------------------- + * + * TkUnionRectWithRegion -- + * + * Implements the equivelent of the X window function + * XUnionRectWithRegion. See X window documentation for more + * details. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +TkUnionRectWithRegion( + XRectangle* rectangle, + TkRegion src_region, + TkRegion dest_region_return) +{ + RgnHandle srcRgn = (RgnHandle) src_region; + RgnHandle destRgn = (RgnHandle) dest_region_return; + + if (tmpRgn == NULL) { + tmpRgn = NewRgn(); + } + SetRectRgn(tmpRgn, rectangle->x, rectangle->y, + rectangle->x + rectangle->width, rectangle->y + rectangle->height); + UnionRgn(srcRgn, tmpRgn, destRgn); +} + +/* + *---------------------------------------------------------------------- + * + * TkRectInRegion -- + * + * Implements the equivelent of the X window function + * XRectInRegion. See X window documentation for more details. + * + * Results: + * Returns one of: RectangleOut, RectangleIn, RectanglePart. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +TkRectInRegion( + TkRegion region, + int x, + int y, + unsigned int width, + unsigned int height) +{ + RgnHandle rgn = (RgnHandle) region; + RgnHandle rectRgn, destRgn; + int result; + + rectRgn = NewRgn(); + destRgn = NewRgn(); + SetRectRgn(rectRgn, x, y, x + width, y + height); + SectRgn(rgn, rectRgn, destRgn); + if (EmptyRgn(destRgn)) { + result = RectangleOut; + } else if (EqualRgn(rgn, destRgn)) { + result = RectangleIn; + } else { + result = RectanglePart; + } + DisposeRgn(rectRgn); + DisposeRgn(destRgn); + return result; +} + +/* + *---------------------------------------------------------------------- + * + * TkClipBox -- + * + * Implements the equivelent of the X window function XClipBox. + * See X window documentation for more details. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +TkClipBox( + TkRegion r, + XRectangle* rect_return) +{ + RgnHandle rgn = (RgnHandle) r; + + rect_return->x = (**rgn).rgnBBox.left; + rect_return->y = (**rgn).rgnBBox.top; + rect_return->width = (**rgn).rgnBBox.right - (**rgn).rgnBBox.left; + rect_return->height = (**rgn).rgnBBox.bottom - (**rgn).rgnBBox.top; +} diff --git a/mac/tkMacResource.r b/mac/tkMacResource.r new file mode 100644 index 0000000..23a2000 --- /dev/null +++ b/mac/tkMacResource.r @@ -0,0 +1,507 @@ +/* + * tkMacResources.r -- + * + * This file creates resources for use in a simple shell. + * This is designed to be an example of using the Tcl/Tk + * libraries in a Macintosh Application. + * + * Copyright (c) 1993-1994 Lockheed Missle & Space Company, AI Center + * Copyright (c) 1995-1997 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) tkMacResource.r 1.35 97/11/03 17:16:34 + */ + +/* + * We define SystemSevenOrLater so that our dialogs may use the + * auto center feature. + */ +#define SystemSevenOrLater 1 + +#include <Types.r> +#include <SysTypes.r> + +/* + * The folowing include and defines help construct + * the version string for Tcl. + */ + +#define RESOURCE_INCLUDED +#include "tcl.h" +#include "tk.h" + +#if (TK_RELEASE_LEVEL == 0) +# define RELEASE_LEVEL alpha +#elif (TK_RELEASE_LEVEL == 1) +# define RELEASE_LEVEL beta +#elif (TK_RELEASE_LEVEL == 2) +# define RELEASE_LEVEL final +#endif + +#if (TK_RELEASE_LEVEL == 2) +# define MINOR_VERSION (TK_MINOR_VERSION * 16) + TK_RELEASE_SERIAL +#else +# define MINOR_VERSION TK_MINOR_VERSION * 16 +#endif + +resource 'vers' (1) { + TK_MAJOR_VERSION, MINOR_VERSION, + RELEASE_LEVEL, 0x00, verUS, + TK_PATCH_LEVEL, + TK_PATCH_LEVEL ", by Ray Johnson © 1993-1996" "\n" "Sun Microsystems Labratories" +}; + +resource 'vers' (2) { + TK_MAJOR_VERSION, MINOR_VERSION, + RELEASE_LEVEL, 0x00, verUS, + TK_PATCH_LEVEL, + "Wish " TK_PATCH_LEVEL " © 1993-1996" +}; + + +/* + * The mechanisim below loads Tcl source into the resource fork of the + * application. The example below creates a TEXT resource named + * "Init" from the file "init.tcl". This allows applications to use + * Tcl to define the behavior of the application without having to + * require some predetermined file structure - all needed Tcl "files" + * are located within the application. To source a file for the + * resource fork the source command has been modified to support + * sourcing from resources. In the below case "source -rsrc {Init}" + * will load the TEXT resource named "Init". + */ + +read 'TEXT' (0, "Init", purgeable, preload) + ":::tcl" TCL_VERSION ":library:init.tcl"; +read 'TEXT' (1, "History", purgeable, preload) + ":::tcl" TCL_VERSION ":library:history.tcl"; +read 'TEXT' (2, "Word", purgeable,preload) + ":::tcl" TCL_VERSION ":library:word.tcl"; + +read 'TEXT' (10, "tk", purgeable, preload) "::library:tk.tcl"; +read 'TEXT' (11, "button", purgeable, preload) "::library:button.tcl"; +read 'TEXT' (12, "dialog", purgeable, preload) "::library:dialog.tcl"; +read 'TEXT' (13, "entry", purgeable, preload) "::library:entry.tcl"; +read 'TEXT' (14, "focus", purgeable, preload) "::library:focus.tcl"; +read 'TEXT' (15, "listbox", purgeable, preload) "::library:listbox.tcl"; +read 'TEXT' (16, "menu", purgeable, preload) "::library:menu.tcl"; +read 'TEXT' (17, "optionMenu", purgeable, preload) "::library:optMenu.tcl"; +read 'TEXT' (18, "palette", purgeable, preload) "::library:palette.tcl"; +read 'TEXT' (19, "scale", purgeable, preload) "::library:scale.tcl"; +read 'TEXT' (20, "scrollbar", purgeable, preload) "::library:scrlbar.tcl"; +read 'TEXT' (21, "tearoff", purgeable, preload) "::library:tearoff.tcl"; +read 'TEXT' (22, "text", purgeable, preload) "::library:text.tcl"; +read 'TEXT' (23, "tkerror", purgeable, preload) "::library:bgerror.tcl"; +read 'TEXT' (24, "Console", purgeable, preload) "::library:console.tcl"; +read 'TEXT' (25, "msgbox", purgeable, preload) "::library:msgbox.tcl"; +read 'TEXT' (26, "comdlg", purgeable, preload) "::library:comdlg.tcl"; +read 'TEXT' (27, "prolog", purgeable, preload) "::library:prolog.ps"; + + +/* + * The following resource is used when creating the 'env' variable in + * the Macintosh environment. The creation mechanisim looks for the + * 'STR#' resource named "Tcl Environment Variables" rather than a + * specific resource number. (In other words, feel free to change the + * resource id if it conflicts with your application.) Each string in + * the resource must be of the form "KEYWORD=SOME STRING". See Tcl + * documentation for futher information about the env variable. + */ + +/* A good example of something you may want to set is: + * "TCL_LIBRARY=My disk:etc." + */ + +resource 'STR#' (128, "Tcl Environment Variables") { + { "SCHEDULE_NAME=Agent Controller Schedule", + "SCHEDULE_PATH=Lozoya:System Folder:Tcl Lib:Tcl-Scheduler" + }; +}; + +/* + * The following two resources define the default "About Box" for Mac Tk. + * This dialog appears if the "About Tk..." menu item is selected from + * the Apple menu. This dialog may be overridden by defining a Tcl procedure + * with the name of "tkAboutDialog". If this procedure is defined the + * default dialog will not be shown and the Tcl procedure is expected to + * create and manage an About Dialog box. + */ + +resource 'DLOG' (128, "Default About Box", purgeable) { + {85, 107, 243, 406}, dBoxProc, visible, goAway, 0, + 128, "", centerMainScreen +}; + +resource 'DITL' (128, "About Box", purgeable) { + { + {128, 128, 148, 186}, Button {enabled, "Ok"}, + { 14, 108, 117, 310}, StaticText {disabled, + "Wish - Windowing Shell" "\n" "based on Tcl " + TCL_PATCH_LEVEL " & Tk " TK_PATCH_LEVEL "\n\n" "Ray Johnson" "\n" + "Sun Microsystems Labs" "\n" "ray.johnson@eng.sun.com"}, + { 11, 24, 111, 92}, Picture {enabled, 128} + } +}; + +data 'PICT' (128) { + $"13A4 0000 0000 0064 0044 0011 02FF 0C00" + $"FFFE 0000 0048 0000 0048 0000 0000 0000" + $"0064 0044 0000 0000 0001 000A 0000 0000" + $"0064 0044 0099 8044 0000 0000 0064 0044" + $"0000 0000 0000 0000 0048 0000 0048 0000" + $"0000 0008 0001 0008 0000 0000 0108 00D8" + $"0000 0000 0001 5A5A 8000 00FF 3736 FF00" + $"FF00 FF00 3535 FF00 FF00 CC00 3434 FF00" + $"FF00 9900 3333 FF00 FF00 6600 3736 FF00" + $"FF00 3300 3535 FF00 FF00 0000 3434 FF00" + $"CC00 FF00 3333 FF00 CC00 CC00 3736 FF00" + $"CC00 9900 3535 FF00 CC00 6600 FAFA FF00" + $"CC00 3300 3333 FF00 CC00 0000 3130 FF00" + $"9900 FF00 2F2F FF00 9900 CC00 FAFA FF00" + $"9900 9900 F9F9 FF00 9900 6600 3130 FF00" + $"9900 3300 2F2F FF00 9900 0000 2E2E FF00" + $"6600 FF00 F9F9 FF00 6600 CC00 3130 FF00" + $"6600 9900 2F2F FF00 6600 6600 2E2E FF00" + $"6600 3300 2D2D FF00 6600 0000 3130 FF00" + $"3300 FF00 2F2F FF00 3300 CC00 2E2E FF00" + $"3300 9900 2D2D FF00 3300 6600 3130 FF00" + $"3300 3300 2F2F FF00 3300 0000 2E2E FF00" + $"0000 FF00 2D2D FF00 0000 CC00 3130 FF00" + $"0000 9900 2F2F FF00 0000 6600 2E2E FF00" + $"0000 3300 2DF8 FF00 0000 0000 2B2A CC00" + $"FF00 FF00 2929 CC00 FF00 CC00 2828 CC00" + $"FF00 9900 27F8 CC00 FF00 6600 2B2A CC00" + $"FF00 3300 2929 CC00 FF00 0000 2828 CC00" + $"CC00 FF00 2727 CC00 CC00 CC00 2B2A CC00" + $"CC00 9900 2929 CC00 CC00 6600 2828 CC00" + $"CC00 3300 2727 CC00 CC00 0000 2B2A CC00" + $"9900 FF00 2929 CC00 9900 CC00 2828 CC00" + $"9900 9900 2727 CC00 9900 6600 DBDB CC00" + $"9900 3300 4747 CC00 9900 0000 4646 CC00" + $"6600 FF00 4545 CC00 6600 CC00 DBDB CC00" + $"6600 9900 4747 CC00 6600 6600 4646 CC00" + $"6600 3300 4545 CC00 6600 0000 DBDB CC00" + $"3300 FF00 4747 CC00 3300 CC00 4646 CC00" + $"3300 9900 4545 CC00 3300 6600 DBDB CC00" + $"3300 3300 4141 CC00 3300 0000 4040 CC00" + $"0000 FF00 3F3F CC00 0000 CC00 4342 CC00" + $"0000 9900 4141 CC00 0000 6600 4040 CC00" + $"0000 3300 3F3F CC00 0000 0000 4342 9900" + $"FF00 FF00 4141 9900 FF00 CC00 4040 9900" + $"FF00 9900 3F3F 9900 FF00 6600 4342 9900" + $"FF00 3300 4141 9900 FF00 0000 4040 9900" + $"CC00 FF00 3F3F 9900 CC00 CC00 4342 9900" + $"CC00 9900 4141 9900 CC00 6600 4040 9900" + $"CC00 3300 3F3F 9900 CC00 0000 4342 9900" + $"9900 FF00 4141 9900 9900 CC00 4040 9900" + $"9900 9900 3F3F 9900 9900 6600 3D3C 9900" + $"9900 3300 3B3B 9900 9900 0000 3A3A 9900" + $"6600 FF00 3939 9900 6600 CC00 3D3C 9900" + $"6600 9900 3B3B 9900 6600 6600 3A3A 9900" + $"6600 3300 3939 9900 6600 0000 3D3C 9900" + $"3300 FF00 3B3B 9900 3300 CC00 3A3A 9900" + $"3300 9900 3939 9900 3300 6600 3D3C 9900" + $"3300 3300 3B3B 9900 3300 0000 3A3A 9900" + $"0000 FF00 3939 9900 0000 CC00 3D3C 9900" + $"0000 9900 3B3B 9900 0000 6600 3A3A 9900" + $"0000 3300 3939 9900 0000 0000 3D3C 6600" + $"FF00 FF00 3B3B 6600 FF00 CC00 3A3A 6600" + $"FF00 9900 3939 6600 FF00 6600 3D3C 6600" + $"FF00 3300 3B3B 6600 FF00 0000 3A3A 6600" + $"CC00 FF00 3939 6600 CC00 CC00 3736 6600" + $"CC00 9900 3535 6600 CC00 6600 3434 6600" + $"CC00 3300 3333 6600 CC00 0000 3736 6600" + $"9900 FF00 3535 6600 9900 CC00 3434 6600" + $"9900 9900 3333 6600 9900 6600 3736 6600" + $"9900 3300 3535 6600 9900 0000 3434 6600" + $"6600 FF00 3333 6600 6600 CC00 3736 6600" + $"6600 9900 3535 6600 6600 6600 3434 6600" + $"6600 3300 3333 6600 6600 0000 3736 6600" + $"3300 FF00 3535 6600 3300 CC00 3434 6600" + $"3300 9900 3333 6600 3300 6600 3736 6600" + $"3300 3300 3535 6600 3300 0000 3434 6600" + $"0000 FF00 3333 6600 0000 CC00 3130 6600" + $"0000 9900 2F2F 6600 0000 6600 2E2E 6600" + $"0000 3300 F9F9 6600 0000 0000 3130 3300" + $"FF00 FF00 2F2F 3300 FF00 CC00 2E2E 3300" + $"FF00 9900 F9F9 3300 FF00 6600 3130 3300" + $"FF00 3300 2F2F 3300 FF00 0000 2E2E 3300" + $"CC00 FF00 2D2D 3300 CC00 CC00 3130 3300" + $"CC00 9900 2F2F 3300 CC00 6600 2E2E 3300" + $"CC00 3300 2D2D 3300 CC00 0000 3130 3300" + $"9900 FF00 2F2F 3300 9900 CC00 2E2E 3300" + $"9900 9900 2D2D 3300 9900 6600 3130 3300" + $"9900 3300 2F2F 3300 9900 0000 2E2E 3300" + $"6600 FF00 2DF8 3300 6600 CC00 2B2A 3300" + $"6600 9900 2929 3300 6600 6600 2828 3300" + $"6600 3300 27F8 3300 6600 0000 2B2A 3300" + $"3300 FF00 2929 3300 3300 CC00 2828 3300" + $"3300 9900 2727 3300 3300 6600 2B2A 3300" + $"3300 3300 2929 3300 3300 0000 2828 3300" + $"0000 FF00 2727 3300 0000 CC00 2B2A 3300" + $"0000 9900 2929 3300 0000 6600 2828 3300" + $"0000 3300 2727 3300 0000 0000 4948 0000" + $"FF00 FF00 4747 0000 FF00 CC00 4646 0000" + $"FF00 9900 4545 0000 FF00 6600 4948 0000" + $"FF00 3300 4747 0000 FF00 0000 4646 0000" + $"CC00 FF00 4545 0000 CC00 CC00 4948 0000" + $"CC00 9900 4747 0000 CC00 6600 4646 0000" + $"CC00 3300 4545 0000 CC00 0000 4342 0000" + $"9900 FF00 4141 0000 9900 CC00 4040 0000" + $"9900 9900 3F3F 0000 9900 6600 4342 0000" + $"9900 3300 4141 0000 9900 0000 4040 0000" + $"6600 FF00 3F3F 0000 6600 CC00 4342 0000" + $"6600 9900 4141 0000 6600 6600 4040 0000" + $"6600 3300 3F3F 0000 6600 0000 4342 0000" + $"3300 FF00 4141 0000 3300 CC00 4040 0000" + $"3300 9900 3F3F 0000 3300 6600 4342 0000" + $"3300 3300 4141 0000 3300 0000 4040 0000" + $"0000 FF00 3F3F 0000 0000 CC00 4342 0000" + $"0000 9900 4141 0000 0000 6600 4040 0000" + $"0000 3300 3F3F EE00 0000 0000 3D3C DD00" + $"0000 0000 3B3B BB00 0000 0000 3A3A AA00" + $"0000 0000 3939 8800 0000 0000 3D3C 7700" + $"0000 0000 3B3B 5500 0000 0000 3A3A 4400" + $"0000 0000 3939 2200 0000 0000 3D3C 1100" + $"0000 0000 3B3B 0000 EE00 0000 3A3A 0000" + $"DD00 0000 3939 0000 BB00 0000 3D3C 0000" + $"AA00 0000 3B3B 0000 8800 0000 3A3A 0000" + $"7700 0000 3939 0000 5500 0000 3D3C 0000" + $"4400 0000 3B3B 0000 2200 0000 3A3A 0000" + $"1100 0000 3939 0000 0000 EE00 3D3C 0000" + $"0000 DD00 3B3B 0000 0000 BB00 3A3A 0000" + $"0000 AA00 3939 0000 0000 8800 3D3C 0000" + $"0000 7700 3B3B 0000 0000 5500 3A3A 0000" + $"0000 4400 3939 0000 0000 2200 3736 0000" + $"0000 1100 3535 EE00 EE00 EE00 3434 DD00" + $"DD00 DD00 3333 BB00 BB00 BB00 3736 AA00" + $"AA00 AA00 3535 8800 8800 8800 3434 7700" + $"7700 7700 3333 5500 5500 5500 3736 4400" + $"4400 4400 3535 2200 2200 2200 3434 1100" + $"1100 1100 3333 0000 0000 0000 0000 0000" + $"0064 0044 0000 0000 0064 0044 0000 000A" + $"0000 0000 0064 0044 02BD 0013 E800 01F5" + $"F6FE 07FE 0E02 3232 33FD 3900 0EE6 001D" + $"FC00 01F5 F5FE 0700 08FE 0E02 3232 33FE" + $"3900 3AFC 40F2 4102 4033 07E9 0017 0100" + $"0EFC 40DC 4102 390E F5F5 0002 F5F5 F6FE" + $"0702 0E07 0016 0100 32D5 4104 4039 0E32" + $"33FD 3900 3AFC 40FC 4101 3200 0801 000E" + $"C141 010E 0008 0100 0EC1 4101 0800 0801" + $"000E C141 0107 0008 0100 0EC1 4101 0700" + $"0901 0007 C241 0240 F500 0E01 0007 E841" + $"0147 47DD 4102 4000 0012 0100 07F0 4100" + $"47FA 4101 3B3B DD41 0240 0000 1901 0007" + $"F141 0C47 3B0B 3B47 4141 4711 0505 3B47" + $"DF41 023A 0000 1701 00F6 F041 010B 0BFE" + $"4105 473B 0505 113B DE41 0239 0000 1A02" + $"00F5 40F3 410C 473B 053B 4741 4741 0B0B" + $"3B47 47DE 4102 3900 0018 0200 F540 F341" + $"0247 110B FE41 0447 1105 4147 DC41 0233" + $"0000 1B02 0000 40F3 4103 4711 1147 FE41" + $"0205 3547 F741 FD47 E941 0232 0000 1E02" + $"0000 40F2 4106 113B 4741 4735 0BF7 4106" + $"4741 390E 0E40 47EA 4102 0E00 0021 0200" + $"0040 F241 0711 3B47 4141 0B35 47F9 4102" + $"4740 07FE 0002 F640 47EB 4102 0E00 0023" + $"0200 0040 F341 0847 3541 4147 3B05 4147" + $"FA41 0947 3AF6 00F5 4F55 F50E 47EB 4102" + $"0700 0022 0200 003A F341 0147 3BFE 4101" + $"0B0B F941 0547 3AF5 0055 C8FE CE01 5640" + $"EB41 0207 0000 1F02 0000 39F0 4104 4741" + $"053B 47FB 4104 4740 F5F5 A4FC CE01 C85D" + $"EB41 02F6 0000 1F02 0000 39F0 4104 473B" + $"0541 47FC 4104 4740 07F6 C8FA CE00 64EC" + $"4103 40F5 0000 1C02 0000 39F0 4102 4711" + $"0BFA 4103 4708 2AC8 FACE 0164 D8EC 4100" + $"40FE 0025 0200 0039 EF41 020B 3B47 FC41" + $"0347 0FF5 A4FB CE02 C887 D8FC 41FE 47FC" + $"4100 47F9 4100 3AFE 0028 0200 0039 EF41" + $"020B 3B47 FD41 0347 3900 A4FA CE00 ABFA" + $"4109 3B11 3B41 4147 3B0B 3B47 FA41 0039" + $"FE00 2402 0000 33F1 4102 4741 0BFA 4101" + $"0779 F9CE 0064 FA41 0235 050B FD41 010B" + $"0BF9 4100 39FE 0028 0200 0032 F141 0247" + $"3B0B FC41 0247 39F6 F9CE 0187 D8FB 4103" + $"4741 050B FE41 0247 110B F941 0039 FE00" + $"2C02 0000 32F1 4102 473B 11FB 4101 0879" + $"FACE 05AA 4041 4147 47FE 410A 4741 0511" + $"4741 4147 3511 47FA 4100 32FE 002F 0200" + $"000E F141 0347 3B11 47FE 4103 4740 F6C8" + $"FACE 0564 D841 4039 39FE 4104 473B 053B" + $"47FE 4102 3541 47FA 4100 0EFE 0027 0200" + $"000E F141 0347 3B3B 47FE 4102 470F 79FA" + $"CE0C 8741 4032 F500 003A 4741 473B 05F2" + $"4100 0EFE 0027 0200 000E F141 0347 3B3B" + $"47FD 4101 0EA4 FACE 01AB AAFE C808 7900" + $"3947 4147 110B 47F3 4100 07FE 001C 0200" + $"000E EA41 0240 2BC8 F5CE 0881 0033 4741" + $"410B 3B47 F341 0007 FE00 1A02 0000 08EB" + $"4102 473A 55F4 CE06 5D00 3947 4741 0BF1" + $"4100 F6FE 001C 0200 0007 EB41 0247 3979" + $"F4CE 0739 0039 4747 3511 47F3 4101 40F5" + $"FE00 1C02 0000 07EB 4102 4739 A4F5 CE08" + $"AB0E 0040 4741 1141 47F3 4100 40FD 001B" + $"0200 0007 EB41 0247 39A4 F5CE 0787 0707" + $"4147 4111 47F2 4100 40FD 001B 0200 0007" + $"EB41 0247 39C8 F5CE 0763 F532 4747 3B3B" + $"47F2 4100 3AFD 001A 0300 00F6 40EC 4102" + $"4739 C8F5 CE05 39F5 4047 413B F041 0039" + $"FD00 1C03 0000 F540 EB41 0140 C8FD CE01" + $"C8A4 FCCE 03AB 080E 47ED 4100 39FD 001A" + $"FE00 0040 EB41 0040 FCCE 01A4 C8FC CE03" + $"FA07 4047 ED41 0032 FD00 1AFE 0000 40EA" + $"4100 AAFE CE02 87F9 C8FC CE02 560F 47EC" + $"4100 32FD 0019 FE00 0040 EA41 00AB FECE" + $"0264 56C8 FDCE 01C8 32EA 4100 0EFD 001B" + $"FE00 0040 ED41 030E 4047 87FE CE01 4055" + $"FCCE 01FA 40EA 4100 08FD 001A FE00 003A" + $"ED41 0807 0740 FBCE CEAB 3979 FDCE 00AB" + $"E841 0007 FD00 1CFE 0000 3AED 4108 0700" + $"F6A4 CECE 8733 79FD CE02 4147 47EA 4100" + $"07FD 001E FE00 0039 ED41 0807 2AA4 C8CE" + $"CE88 0E9D FECE 0364 1C39 39EB 4101 40F5" + $"FD00 1CFE 0000 39ED 4101 074F FDCE 0264" + $"F7A4 FECE 03AB 80F6 07EB 4100 40FC 001C" + $"FE00 0039 ED41 0108 79FE CE03 AB40 2BA4" + $"FCCE 02F7 0E47 EC41 0040 FC00 1CFE 0000" + $"39ED 4101 0879 FECE 03AB 40F6 C8FC CE02" + $"F615 47EC 4100 40FC 001E FE00 003A EE41" + $"0247 0E79 FECE 03AB 40F5 C8FD CE03 A4F5" + $"3A47 EC41 0040 FC00 1EFE 0000 3AEE 4102" + $"470E 56FE CE03 FB3A F6C8 FDCE 0280 F540" + $"EB41 0140 F5FD 001E FE00 0040 EE41 0947" + $"0F56 CECE C888 39F6 C8FD CE02 5601 40EB" + $"4101 40F5 FD00 1CFE 0000 40EE 4109 4739" + $"32CE CEC8 8839 2AC8 FDCE 0156 07E9 4100" + $"F6FD 001B FE00 0040 EE41 0847 3A32 CECE" + $"C864 152A FCCE 0132 07E9 4100 07FD 001A" + $"FE00 0040 ED41 0740 32AB CEC8 6439 4EFC" + $"CE01 3A07 E941 0007 FD00 1D03 0000 F540" + $"ED41 0740 0EAB CECE 640F 4EFD CE03 AB40" + $"0840 EA41 0007 FD00 1B03 0000 F540 EC41" + $"060F 81CE CE64 334E FDCE 02AB 400E E941" + $"000E FD00 1C02 0000 F6EC 4107 4715 FACE" + $"CE64 334E FDCE 0387 0F0E 47EA 4100 0EFD" + $"001C 0200 0007 EC41 0747 16F9 CEC8 6433" + $"4EFD CE03 6308 4047 EA41 000E FD00 1A02" + $"0000 07EB 4106 40F9 CEC8 6439 4EFD CE02" + $"3940 47E9 4100 32FD 001B 0200 0007 EA41" + $"0539 CECE 8839 F6FE CE04 AB41 4139 40EA" + $"4100 32FD 001C 0200 0007 EB41 0E47 3AC8" + $"CE88 39F6 C8CE CE64 15F6 F540 EA41 0033" + $"FD00 1A02 0000 07EA 410C 40A4 CE87 392A" + $"C8CE AB41 40F8 F6E9 4100 39FD 001B 0200" + $"000E EB41 0D47 41AB C887 39F5 C8CE ABAB" + $"CEA4 07E9 4100 39FD 001C 0200 000E ED41" + $"0947 3939 4787 C8AB 40F5 C8FD CE01 A40E" + $"E941 0039 FD00 1D02 0000 0EED 4109 473A" + $"0007 80CE AB40 F5C8 FDCE 0255 0E47 EA41" + $"0039 FD00 1B02 0000 0EEB 4107 0779 C8CE" + $"CE40 F6A4 FDCE 022B 3947 EA41 003A FD00" + $"1C02 0000 0EEC 4102 4739 79FE CE02 6407" + $"A4FE CE02 A407 40E9 4100 40FD 001A 0200" + $"0032 EA41 0632 A4CE CE88 0879 FECE 02F9" + $"0F47 E941 0040 FD00 1A02 0000 32EB 4107" + $"4740 F7C8 CE87 0E79 FECE 0132 40E8 4100" + $"40FD 0019 0200 0033 EA41 0B47 40F8 C8AB" + $"0E55 CECE 8015 47E8 4100 40FD 0017 0200" + $"0033 E941 0847 40F9 A439 4FCE CE5D E641" + $"0140 F5FE 0014 0200 0039 E841 0647 64FB" + $"392B C8AB E441 00F6 FE00 1102 0000 39E5" + $"4103 40F6 8764 E441 0007 FE00 1E02 0000" + $"39EB 4102 3A0E 0EFD 4102 0740 47F6 4104" + $"400F 0839 47F4 4100 07FE 0027 0200 0039" + $"FB41 0147 47F2 4102 0800 40FE 4102 0839" + $"47FC 4101 4747 FC41 0339 0039 47F4 4100" + $"07FE 0029 0200 0039 FB41 0140 39F3 4109" + $"470E F540 4141 470E 3347 FC41 0139 3AFD" + $"4104 4739 0039 47F4 4100 08FE 0036 0200" + $"003A FC41 0347 0E00 40FC 4102 4741 40FC" + $"4109 470E F540 4141 4733 0E47 FE41 0447" + $"4000 0E47 FE41 0447 3900 3941 FE40 F741" + $"000E FE00 3A02 0000 3AFD 410E 4740 0700" + $"0E40 4741 4147 390E 390E 40FE 4108 470E" + $"F540 4141 4739 0EFC 4103 0F00 0739 FE41" + $"0747 3900 3940 080F 39F7 4100 0EFE 0035" + $"0200 0040 FB41 020E 0040 FE41 0D47 4000" + $"3941 0032 4741 4147 0EF5 40FE 4101 4008" + $"FC41 023A 000E FD41 0547 3900 3939 33F5" + $"4100 0EFE 0039 0200 0040 FC41 0347 0E00" + $"40FE 4106 4732 0040 4139 40FE 4103 470E" + $"F540 FD41 0108 40FE 4104 4740 000E 47FE" + $"4106 4739 0007 F540 47F6 4100 32FE 003A" + $"0200 0040 FC41 0C47 0E00 4047 4141 470E" + $"0040 4747 FD41 0347 0EF5 40FE 410A 470E" + $"3947 4141 4740 000E 47FE 4107 4739 000E" + $"0007 4147 F741 0032 FE00 3802 0000 40FC" + $"4102 470E 00FD 4106 4739 003A 4740 39FE" + $"4102 470E F5FD 410A 4733 3347 4141 4740" + $"000E 47FE 4106 4739 0039 3900 0EF6 4100" + $"33FE 003A 0200 F540 FC41 0447 3200 0E39" + $"FD41 0B0E 0E40 333A 4741 413A 07F5 39FE" + $"4102 473A 0EFD 410F 40F5 0733 4041 4140" + $"0E00 0E40 0700 0E40 F841 0039 FE00 2902" + $"00F5 40FA 4101 3939 FB41 023A 3A40 FD41" + $"FD40 FD41 0240 0E40 FD41 0240 3940 FD41" + $"FA40 F741 0039 FE00 2A01 00F6 F941 0147" + $"47FB 4101 4747 FB41 0147 47FB 4101 3940" + $"FD41 0147 47FB 4100 47FE 4100 47F6 4100" + $"39FE 000D 0100 07E1 4100 40E4 4100 3AFE" + $"0009 0100 07C3 4100 3AFE 0009 0100 07C3" + $"4100 40FE 0009 0100 07C3 4100 40FE 0009" + $"0100 07C3 4100 40FE 000A 0100 0EC3 4103" + $"40F5 0000 0901 000E C241 02F6 0000 0901" + $"000E C241 0207 0000 0901 000E C241 0207" + $"0000 1101 000E ED41 FE40 003A F940 E241" + $"0207 0000 2B01 0032 F941 FE40 FE39 0632" + $"0E0E 0707 F6F5 F800 02F5 F5F6 FB07 FB0E" + $"0332 3233 33FB 3901 3A3A FB40 0207 0000" + $"0E0A 000E 3939 320E 0E07 07F6 F5C8 0002" + $"BD00 00FF" +}; + +/* + * Here is the custom file open dialog. This dialog is used instead of + * the default file dialog if the -filetypes flag is specified. + */ + +resource 'DLOG' (130, purgeable) { + {0, 0, 195, 344}, dBoxProc, invisible, noGoAway, 0, + 130, "", noAutoCenter +}; + +resource 'DITL' (130, "File Open Box", purgeable) { + { + {135, 252, 155, 332}, Button {enabled, "Open"}, + {104, 252, 124, 332}, Button {enabled, "Cancel"}, + { 0, 0, 0, 0}, HelpItem {disabled, HMScanhdlg {130}}, + { 8, 235, 24, 337}, UserItem {enabled}, + { 32, 252, 52, 332}, Button {enabled, "Eject"}, + { 60, 252, 80, 332}, Button {enabled, "Desktop"}, + { 29, 12, 159, 230}, UserItem {enabled}, + { 6, 12, 25, 230}, UserItem {enabled}, + { 91, 251, 92, 333}, Picture {disabled, 11}, + {168, 20, 187, 300}, Control {enabled, 131} + } +}; + +resource 'CNTL' (131, "File Types menu", purgeable) { + {168, 20, 187, 300}, + popupTitleLeftJust, + visible, + 80, + 132, + popupMenuCDEFProc, + 0, + "File Type:" +}; + + +resource 'MENU' (132, preload) { + 132, + textMenuProc, + 0xFFFF, enabled, "", {} +}; diff --git a/mac/tkMacScale.c b/mac/tkMacScale.c new file mode 100644 index 0000000..292a064 --- /dev/null +++ b/mac/tkMacScale.c @@ -0,0 +1,603 @@ +/* + * tkMacScale.c -- + * + * This file implements the Macintosh specific portion of the + * scale widget. + * + * Copyright (c) 1996 by Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) tkMacScale.c 1.3 96/10/17 13:16:18 + */ + +#include "tkScale.h" +#include "tkInt.h" +#include <Controls.h> +#include "tkMacInt.h" + +/* + * Defines used in this file. + */ +#define slider 1110 +#define inSlider 1 +#define inInc 2 +#define inDecr 3 + +/* + * Declaration of Macintosh specific scale structure. + */ + +typedef struct MacScale { + TkScale info; /* Generic scale info. */ + int flags; /* Flags. */ + ControlRef scaleHandle; /* Handle to the Scale control struct. */ +} MacScale; + +/* + * Globals uses locally in this file. + */ +static ControlActionUPP scaleActionProc = NULL; /* Pointer to func. */ + +/* + * Forward declarations for procedures defined later in this file: + */ + +static void MacScaleEventProc _ANSI_ARGS_((ClientData clientData, + XEvent *eventPtr)); +static pascal void ScaleActionProc _ANSI_ARGS_((ControlRef theControl, + ControlPartCode partCode)); + +/* + *---------------------------------------------------------------------- + * + * TkpCreateScale -- + * + * Allocate a new TkScale structure. + * + * Results: + * Returns a newly allocated TkScale structure. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +TkScale * +TkpCreateScale(tkwin) + Tk_Window tkwin; +{ + MacScale *macScalePtr;; + + macScalePtr = (MacScale *) ckalloc(sizeof(MacScale)); + macScalePtr->scaleHandle = NULL; + if (scaleActionProc == NULL) { + scaleActionProc = NewControlActionProc(ScaleActionProc); + } + + Tk_CreateEventHandler(tkwin, ButtonPressMask, + MacScaleEventProc, (ClientData) macScalePtr); + + return (TkScale *) macScalePtr; +} + +/* + *---------------------------------------------------------------------- + * + * TkpDestroyScale -- + * + * Free Macintosh specific resources. + * + * Results: + * None + * + * Side effects: + * The slider control is destroyed. + * + *---------------------------------------------------------------------- + */ + +void +TkpDestroyScale(scalePtr) + TkScale *scalePtr; +{ + MacScale *macScalePtr = (MacScale *) scalePtr; + + /* + * Free Macintosh control. + */ + if (macScalePtr->scaleHandle != NULL) { + DisposeControl(macScalePtr->scaleHandle); + } +} + +/* + *---------------------------------------------------------------------- + * + * TkpDisplayScale -- + * + * This procedure is invoked as an idle handler to redisplay + * the contents of a scale widget. + * + * Results: + * None. + * + * Side effects: + * The scale gets redisplayed. + * + *---------------------------------------------------------------------- + */ + +void +TkpDisplayScale(clientData) + ClientData clientData; /* Widget record for scale. */ +{ + TkScale *scalePtr = (TkScale *) clientData; + Tk_Window tkwin = scalePtr->tkwin; + Tcl_Interp *interp = scalePtr->interp; + int result; + char string[PRINT_CHARS]; + MacScale *macScalePtr = (MacScale *) clientData; + Rect r; + WindowRef windowRef; + GWorldPtr destPort; + CGrafPtr saveWorld; + GDHandle saveDevice; + MacDrawable *macDraw; + + if ((scalePtr->tkwin == NULL) || !Tk_IsMapped(scalePtr->tkwin)) { + goto done; + } + + /* + * Invoke the scale's command if needed. + */ + + Tcl_Preserve((ClientData) scalePtr); + if ((scalePtr->flags & INVOKE_COMMAND) && (scalePtr->command != NULL)) { + Tcl_Preserve((ClientData) interp); + sprintf(string, scalePtr->format, scalePtr->value); + result = Tcl_VarEval(interp, scalePtr->command, " ", string, + (char *) NULL); + if (result != TCL_OK) { + Tcl_AddErrorInfo(interp, "\n (command executed by scale)"); + Tcl_BackgroundError(interp); + } + Tcl_Release((ClientData) interp); + } + scalePtr->flags &= ~INVOKE_COMMAND; + if (scalePtr->tkwin == NULL) { + Tcl_Release((ClientData) scalePtr); + return; + } + Tcl_Release((ClientData) scalePtr); + + /* + * Now handle the part of redisplay that is the same for + * horizontal and vertical scales: border and traversal + * highlight. + */ + + if (scalePtr->highlightWidth != 0) { + GC gc; + + if (scalePtr->flags & GOT_FOCUS) { + gc = Tk_GCForColor(scalePtr->highlightColorPtr, Tk_WindowId(tkwin)); + } else { + gc = Tk_GCForColor(scalePtr->highlightBgColorPtr, Tk_WindowId(tkwin)); + } + Tk_DrawFocusHighlight(tkwin, gc, scalePtr->highlightWidth, Tk_WindowId(tkwin)); + } + Tk_Draw3DRectangle(tkwin, Tk_WindowId(tkwin), scalePtr->bgBorder, + scalePtr->highlightWidth, scalePtr->highlightWidth, + Tk_Width(tkwin) - 2*scalePtr->highlightWidth, + Tk_Height(tkwin) - 2*scalePtr->highlightWidth, + scalePtr->borderWidth, scalePtr->relief); + + /* + * Set up port for drawing Macintosh control. + */ + macDraw = (MacDrawable *) Tk_WindowId(tkwin); + destPort = TkMacGetDrawablePort(Tk_WindowId(tkwin)); + GetGWorld(&saveWorld, &saveDevice); + SetGWorld(destPort, NULL); + TkMacSetUpClippingRgn(Tk_WindowId(tkwin)); + + /* + * Create Macintosh control. + */ + if (macScalePtr->scaleHandle == NULL) { + r.left = r.top = 0; + r.right = r.bottom = 1; + /* TODO: initial value. */ + /* 16*slider+4 */ + macScalePtr->scaleHandle = NewControl((WindowRef) destPort, + &r, "\p", false, (short) 35, 0, 1000, + 16*slider, (SInt32) macScalePtr); + + /* + * If we are foremost than make us active. + */ + if ((WindowPtr) destPort == FrontWindow()) { + macScalePtr->flags |= ACTIVE; + } + } + windowRef = (**macScalePtr->scaleHandle).contrlOwner; + + /* + * We can't use the Macintosh commands SizeControl and MoveControl as these + * calls will also cause a redraw which in our case will also cause + * flicker. To avoid this we adjust the control record directly. The + * Draw1Control command appears to just draw where ever the control says to + * draw so this seems right. + * + * NOTE: changing the control record directly may not work when + * Apple releases the Copland version of the MacOS in late 1996. + */ + + (**macScalePtr->scaleHandle).contrlRect.left = macDraw->xOff + scalePtr->inset; + (**macScalePtr->scaleHandle).contrlRect.top = macDraw->yOff + scalePtr->inset; + (**macScalePtr->scaleHandle).contrlRect.right = macDraw->xOff + Tk_Width(tkwin) + - scalePtr->inset; + (**macScalePtr->scaleHandle).contrlRect.bottom = macDraw->yOff + + Tk_Height(tkwin) - scalePtr->inset; + + /* + * Set the thumb and resolution etc. + */ + (**macScalePtr->scaleHandle).contrlMin = (SInt16) scalePtr->toValue; + (**macScalePtr->scaleHandle).contrlMax = (SInt16) scalePtr->fromValue; + (**macScalePtr->scaleHandle).contrlValue = (SInt16) scalePtr->value; + + /* + * Finally draw the control. + */ + (**macScalePtr->scaleHandle).contrlVis = 255; + (**macScalePtr->scaleHandle).contrlHilite = 0; + Draw1Control(macScalePtr->scaleHandle); + + SetGWorld(saveWorld, saveDevice); + + done: + scalePtr->flags &= ~REDRAW_ALL; +} + +/* + *---------------------------------------------------------------------- + * + * TkpScaleElement -- + * + * Determine which part of a scale widget lies under a given + * point. + * + * Results: + * The return value is either TROUGH1, SLIDER, TROUGH2, or + * OTHER, depending on which of the scale's active elements + * (if any) is under the point at (x,y). + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +TkpScaleElement(scalePtr, x, y) + TkScale *scalePtr; /* Widget record for scale. */ + int x, y; /* Coordinates within scalePtr's window. */ +{ + MacScale *macScalePtr = (MacScale *) scalePtr; + ControlPartCode part; + Point where; + Rect bounds; + CGrafPtr saveWorld; + GDHandle saveDevice; + GWorldPtr destPort; + + destPort = TkMacGetDrawablePort(Tk_WindowId(scalePtr->tkwin)); + GetGWorld(&saveWorld, &saveDevice); + SetGWorld(destPort, NULL); + + /* + * All of the calculations in this procedure mirror those in + * DisplayScrollbar. Be sure to keep the two consistent. + */ + + TkMacWinBounds((TkWindow *) scalePtr->tkwin, &bounds); + where.h = x + bounds.left; + where.v = y + bounds.top; + part = TestControl(macScalePtr->scaleHandle, where); + + SetGWorld(saveWorld, saveDevice); + + switch (part) { + case inSlider: + return SLIDER; + case inInc: + if (scalePtr->vertical) { + return TROUGH1; + } else { + return TROUGH2; + } + case inDecr: + if (scalePtr->vertical) { + return TROUGH2; + } else { + return TROUGH1; + } + default: + return OTHER; + } +} + +/* + *-------------------------------------------------------------- + * + * TkpSetScaleValue -- + * + * This procedure changes the value of a scale and invokes + * a Tcl command to reflect the current position of a scale + * + * Results: + * None. + * + * Side effects: + * A Tcl command is invoked, and an additional error-processing + * command may also be invoked. The scale's slider is redrawn. + * + *-------------------------------------------------------------- + */ + +void +TkpSetScaleValue(scalePtr, value, setVar, invokeCommand) + register TkScale *scalePtr; /* Info about widget. */ + double value; /* New value for scale. Gets adjusted + * if it's off the scale. */ + int setVar; /* Non-zero means reflect new value through + * to associated variable, if any. */ + int invokeCommand; /* Non-zero means invoked -command option + * to notify of new value, 0 means don't. */ +{ + char string[PRINT_CHARS]; + + value = TkRoundToResolution(scalePtr, value); + if ((value < scalePtr->fromValue) + ^ (scalePtr->toValue < scalePtr->fromValue)) { + value = scalePtr->fromValue; + } + if ((value > scalePtr->toValue) + ^ (scalePtr->toValue < scalePtr->fromValue)) { + value = scalePtr->toValue; + } + if (scalePtr->flags & NEVER_SET) { + scalePtr->flags &= ~NEVER_SET; + } else if (scalePtr->value == value) { + return; + } + scalePtr->value = value; + if (invokeCommand) { + scalePtr->flags |= INVOKE_COMMAND; + } + TkEventuallyRedrawScale(scalePtr, REDRAW_SLIDER); + + if (setVar && (scalePtr->varName != NULL)) { + sprintf(string, scalePtr->format, scalePtr->value); + scalePtr->flags |= SETTING_VAR; + Tcl_SetVar(scalePtr->interp, scalePtr->varName, string, + TCL_GLOBAL_ONLY); + scalePtr->flags &= ~SETTING_VAR; + } +} + +/* + *---------------------------------------------------------------------- + * + * TkpPixelToValue -- + * + * Given a pixel within a scale window, return the scale + * reading corresponding to that pixel. + * + * Results: + * A double-precision scale reading. If the value is outside + * the legal range for the scale then it's rounded to the nearest + * end of the scale. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +double +TkpPixelToValue(scalePtr, x, y) + register TkScale *scalePtr; /* Information about widget. */ + int x, y; /* Coordinates of point within + * window. */ +{ + double value, pixelRange; + + if (scalePtr->vertical) { + pixelRange = Tk_Height(scalePtr->tkwin) - scalePtr->sliderLength + - 2*scalePtr->inset - 2*scalePtr->borderWidth; + value = y; + } else { + pixelRange = Tk_Width(scalePtr->tkwin) - scalePtr->sliderLength + - 2*scalePtr->inset - 2*scalePtr->borderWidth; + value = x; + } + + if (pixelRange <= 0) { + /* + * Not enough room for the slider to actually slide: just return + * the scale's current value. + */ + + return scalePtr->value; + } + value -= scalePtr->sliderLength/2 + scalePtr->inset + + scalePtr->borderWidth; + value /= pixelRange; + if (value < 0) { + value = 0; + } + if (value > 1) { + value = 1; + } + value = scalePtr->fromValue + + value * (scalePtr->toValue - scalePtr->fromValue); + return TkRoundToResolution(scalePtr, value); +} + +/* + *---------------------------------------------------------------------- + * + * TkpValueToPixel -- + * + * Given a reading of the scale, return the x-coordinate or + * y-coordinate corresponding to that reading, depending on + * whether the scale is vertical or horizontal, respectively. + * + * Results: + * An integer value giving the pixel location corresponding + * to reading. The value is restricted to lie within the + * defined range for the scale. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +TkpValueToPixel(scalePtr, value) + register TkScale *scalePtr; /* Information about widget. */ + double value; /* Reading of the widget. */ +{ + int y, pixelRange; + double valueRange; + + valueRange = scalePtr->toValue - scalePtr->fromValue; + pixelRange = (scalePtr->vertical ? Tk_Height(scalePtr->tkwin) + : Tk_Width(scalePtr->tkwin)) - scalePtr->sliderLength + - 2*scalePtr->inset - 2*scalePtr->borderWidth; + if (valueRange == 0) { + y = 0; + } else { + y = (int) ((value - scalePtr->fromValue) * pixelRange + / valueRange + 0.5); + if (y < 0) { + y = 0; + } else if (y > pixelRange) { + y = pixelRange; + } + } + y += scalePtr->sliderLength/2 + scalePtr->inset + scalePtr->borderWidth; + return y; +} + +/* + *-------------------------------------------------------------- + * + * MacScaleEventProc -- + * + * This procedure is invoked by the Tk dispatcher for + * ButtonPress events on scales. + * + * Results: + * None. + * + * Side effects: + * When the window gets deleted, internal structures get + * cleaned up. When it gets exposed, it is redisplayed. + * + *-------------------------------------------------------------- + */ + +static void +MacScaleEventProc(clientData, eventPtr) + ClientData clientData; /* Information about window. */ + XEvent *eventPtr; /* Information about event. */ +{ + MacScale *macScalePtr = (MacScale *) clientData; + Point where; + Rect bounds; + int part, x, y, dummy; + unsigned int state; + CGrafPtr saveWorld; + GDHandle saveDevice; + GWorldPtr destPort; + Window dummyWin; + + /* + * To call Macintosh control routines we must have the port + * set to the window containing the control. We will then test + * which part of the control was hit and act accordingly. + */ + destPort = TkMacGetDrawablePort(Tk_WindowId(macScalePtr->info.tkwin)); + GetGWorld(&saveWorld, &saveDevice); + SetGWorld(destPort, NULL); + TkMacSetUpClippingRgn(Tk_WindowId(macScalePtr->info.tkwin)); + + TkMacWinBounds((TkWindow *) macScalePtr->info.tkwin, &bounds); + where.h = eventPtr->xbutton.x + bounds.left; + where.v = eventPtr->xbutton.y + bounds.top; + part = TestControl(macScalePtr->scaleHandle, where); + if (part == 0) { + return; + } + + part = TrackControl(macScalePtr->scaleHandle, where, scaleActionProc); + + /* + * Update the value for the widget. + */ + macScalePtr->info.value = (**macScalePtr->scaleHandle).contrlValue; + /* TkpSetScaleValue(&macScalePtr->info, macScalePtr->info.value, 1, 0); */ + + /* + * The TrackControl call will "eat" the ButtonUp event. We now + * generate a ButtonUp event so Tk will unset implicit grabs etc. + */ + GetMouse(&where); + XQueryPointer(NULL, None, &dummyWin, &dummyWin, &x, + &y, &dummy, &dummy, &state); + TkGenerateButtonEvent(x, y, Tk_WindowId(macScalePtr->info.tkwin), state); + + SetGWorld(saveWorld, saveDevice); +} + +/* + *-------------------------------------------------------------- + * + * ScaleActionProc -- + * + * Callback procedure used by the Macintosh toolbox call + * TrackControl. This call will update the display while + * the scrollbar is being manipulated by the user. + * + * Results: + * None. + * + * Side effects: + * May change the display. + * + *-------------------------------------------------------------- + */ + +static pascal void +ScaleActionProc(ControlRef theControl, ControlPartCode partCode) + /* ControlRef theControl; /* Handle to scrollbat control */ + /* ControlPartCode partCode; /* Part of scrollbar that was "hit" */ +{ + register int value; + register TkScale *scalePtr = (TkScale *) GetCRefCon(theControl); + + value = (**theControl).contrlValue; + TkpSetScaleValue(scalePtr, value, 1, 1); + Tcl_Preserve((ClientData) scalePtr); + Tcl_DoOneEvent(TCL_IDLE_EVENTS); + Tcl_Release((ClientData) scalePtr); +} + diff --git a/mac/tkMacScrlbr.c b/mac/tkMacScrlbr.c new file mode 100644 index 0000000..c76daec --- /dev/null +++ b/mac/tkMacScrlbr.c @@ -0,0 +1,1057 @@ +/* + * tkMacScrollbar.c -- + * + * This file implements the Macintosh specific portion of the scrollbar + * widget. The Macintosh scrollbar may also draw a windows grow + * region under certain cases. + * + * Copyright (c) 1996 by Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) tkMacScrlbr.c 1.9 96/12/10 20:04:39 + */ + +#include "tkScrollbar.h" +#include "tkMacInt.h" +#include <Controls.h> + +/* + * The following definitions should really be in MacOS + * header files. They are included here as this is the only + * file that needs the declarations. + */ +typedef pascal void (*ThumbActionFunc)(void); + +#if GENERATINGCFM +typedef UniversalProcPtr ThumbActionUPP; +#else +typedef ThumbActionFunc ThumbActionUPP; +#endif + +enum { + uppThumbActionProcInfo = kPascalStackBased +}; + +#if GENERATINGCFM +#define NewThumbActionProc(userRoutine) \ + (ThumbActionUPP) NewRoutineDescriptor((ProcPtr)(userRoutine), uppThumbActionProcInfo, GetCurrentArchitecture()) +#else +#define NewThumbActionProc(userRoutine) \ + ((ThumbActionUPP) (userRoutine)) +#endif + +/* + * Minimum slider length, in pixels (designed to make sure that the slider + * is always easy to grab with the mouse). + */ + +#define MIN_SLIDER_LENGTH 5 + +/* + * Declaration of Windows specific scrollbar structure. + */ + +typedef struct MacScrollbar { + TkScrollbar info; /* Generic scrollbar info. */ + ControlRef sbHandle; /* Handle to the Scrollbar control struct. */ + int macFlags; /* Various flags; see below. */ +} MacScrollbar; + +/* + * Flag bits for scrollbars on the Mac: + * + * ALREADY_DEAD: Non-zero means this scrollbar has been + * destroyed, but has not been cleaned up. + * IN_MODAL_LOOP: Non-zero means this scrollbar is in the middle + * of a modal loop. + * ACTIVE: Non-zero means this window is currently + * active (in the foreground). + * FLUSH_TOP: Flush with top of Mac window. + * FLUSH_BOTTOM: Flush with bottom of Mac window. + * FLUSH_RIGHT: Flush with right of Mac window. + * FLUSH_LEFT: Flush with left of Mac window. + * SCROLLBAR_GROW: Non-zero means this window draws the grow + * region for the toplevel window. + * AUTO_ADJUST: Non-zero means we automatically adjust + * the size of the widget to align correctly + * along a Mac window. + * DRAW_GROW: Non-zero means we draw the grow region. + */ + +#define ALREADY_DEAD 1 +#define IN_MODAL_LOOP 2 +#define ACTIVE 4 +#define FLUSH_TOP 8 +#define FLUSH_BOTTOM 16 +#define FLUSH_RIGHT 32 +#define FLUSH_LEFT 64 +#define SCROLLBAR_GROW 128 +#define AUTO_ADJUST 256 +#define DRAW_GROW 512 + +/* + * Globals uses locally in this file. + */ +static ControlActionUPP scrollActionProc = NULL; /* Pointer to func. */ +static ThumbActionUPP thumbActionProc = NULL; /* Pointer to func. */ +static TkScrollbar *activeScrollPtr = NULL; /* Non-null when in thumb */ + /* proc. */ +/* + * Forward declarations for procedures defined later in this file: + */ + +static pascal void ScrollbarActionProc _ANSI_ARGS_((ControlRef theControl, + ControlPartCode partCode)); +static int ScrollbarBindProc _ANSI_ARGS_((ClientData clientData, + Tcl_Interp *interp, XEvent *eventPtr, + Tk_Window tkwin, KeySym keySym)); +static void ScrollbarEventProc _ANSI_ARGS_(( + ClientData clientData, XEvent *eventPtr)); +static pascal void ThumbActionProc _ANSI_ARGS_((void)); +static void UpdateControlValues _ANSI_ARGS_((MacScrollbar *macScrollPtr)); + +/* + * The class procedure table for the scrollbar widget. + */ + +TkClassProcs tkpScrollbarProcs = { + NULL, /* createProc. */ + NULL, /* geometryProc. */ + NULL /* modalProc */ +}; + +/* + *---------------------------------------------------------------------- + * + * TkpCreateScrollbar -- + * + * Allocate a new TkScrollbar structure. + * + * Results: + * Returns a newly allocated TkScrollbar structure. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +TkScrollbar * +TkpCreateScrollbar( + Tk_Window tkwin) /* New Tk Window. */ +{ + MacScrollbar * macScrollPtr; + TkWindow *winPtr = (TkWindow *)tkwin; + + if (scrollActionProc == NULL) { + scrollActionProc = NewControlActionProc(ScrollbarActionProc); + thumbActionProc = NewThumbActionProc(ThumbActionProc); + } + + macScrollPtr = (MacScrollbar *) ckalloc(sizeof(MacScrollbar)); + macScrollPtr->sbHandle = NULL; + macScrollPtr->macFlags = 0; + + Tk_CreateEventHandler(tkwin, ActivateMask|ExposureMask| + StructureNotifyMask|FocusChangeMask, + ScrollbarEventProc, (ClientData) macScrollPtr); + + if (!Tcl_GetAssocData(winPtr->mainPtr->interp, "TkScrollbar", NULL)) { + Tcl_SetAssocData(winPtr->mainPtr->interp, "TkScrollbar", NULL, + (ClientData)1); + TkCreateBindingProcedure(winPtr->mainPtr->interp, + winPtr->mainPtr->bindingTable, + (ClientData)Tk_GetUid("Scrollbar"), "<ButtonPress>", + ScrollbarBindProc, NULL, NULL); + } + + return (TkScrollbar *) macScrollPtr; +} + +/* + *-------------------------------------------------------------- + * + * TkpDisplayScrollbar -- + * + * This procedure redraws the contents of a scrollbar window. + * It is invoked as a do-when-idle handler, so it only runs + * when there's nothing else for the application to do. + * + * Results: + * None. + * + * Side effects: + * Information appears on the screen. + * + *-------------------------------------------------------------- + */ + +void +TkpDisplayScrollbar( + ClientData clientData) /* Information about window. */ +{ + register TkScrollbar *scrollPtr = (TkScrollbar *) clientData; + register MacScrollbar *macScrollPtr = (MacScrollbar *) clientData; + register Tk_Window tkwin = scrollPtr->tkwin; + + MacDrawable *macDraw; + CGrafPtr saveWorld; + GDHandle saveDevice; + GWorldPtr destPort; + WindowRef windowRef; + + if ((scrollPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) { + goto done; + } + + /* + * Draw the focus or any 3D relief we may have. + */ + if (scrollPtr->highlightWidth != 0) { + GC gc; + + if (scrollPtr->flags & GOT_FOCUS) { + gc = Tk_GCForColor(scrollPtr->highlightColorPtr, + Tk_WindowId(tkwin)); + } else { + gc = Tk_GCForColor(scrollPtr->highlightBgColorPtr, + Tk_WindowId(tkwin)); + } + Tk_DrawFocusHighlight(tkwin, gc, scrollPtr->highlightWidth, + Tk_WindowId(tkwin)); + } + Tk_Draw3DRectangle(tkwin, Tk_WindowId(tkwin), scrollPtr->bgBorder, + scrollPtr->highlightWidth, scrollPtr->highlightWidth, + Tk_Width(tkwin) - 2*scrollPtr->highlightWidth, + Tk_Height(tkwin) - 2*scrollPtr->highlightWidth, + scrollPtr->borderWidth, scrollPtr->relief); + + /* + * Set up port for drawing Macintosh control. + */ + macDraw = (MacDrawable *) Tk_WindowId(tkwin); + destPort = TkMacGetDrawablePort(Tk_WindowId(tkwin)); + GetGWorld(&saveWorld, &saveDevice); + SetGWorld(destPort, NULL); + TkMacSetUpClippingRgn(Tk_WindowId(tkwin)); + + if (macScrollPtr->sbHandle == NULL) { + Rect r; + + r.left = r.top = 0; + r.right = r.bottom = 1; + macScrollPtr->sbHandle = NewControl((WindowRef) destPort, &r, "\p", + false, (short) 500, 0, 1000, + scrollBarProc, (SInt32) scrollPtr); + + /* + * If we are foremost than make us active. + */ + if ((WindowPtr) destPort == FrontWindow()) { + macScrollPtr->macFlags |= ACTIVE; + } + } + + /* + * Update the control values before we draw. + */ + windowRef = (**macScrollPtr->sbHandle).contrlOwner; + UpdateControlValues(macScrollPtr); + + if (macScrollPtr->macFlags & ACTIVE) { + Draw1Control(macScrollPtr->sbHandle); + if (macScrollPtr->macFlags & DRAW_GROW) { + DrawGrowIcon(windowRef); + } + } else { + (**macScrollPtr->sbHandle).contrlHilite = 255; + Draw1Control(macScrollPtr->sbHandle); + if (macScrollPtr->macFlags & DRAW_GROW) { + DrawGrowIcon(windowRef); + Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), scrollPtr->bgBorder, + Tk_Width(tkwin) - 13, Tk_Height(tkwin) - 13, + Tk_Width(tkwin), Tk_Height(tkwin), + 0, TK_RELIEF_FLAT); + } + } + + SetGWorld(saveWorld, saveDevice); + + done: + scrollPtr->flags &= ~REDRAW_PENDING; +} + +/* + *---------------------------------------------------------------------- + * + * TkpConfigureScrollbar -- + * + * This procedure is called after the generic code has finished + * processing configuration options, in order to configure + * platform specific options. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +TkpConfigureScrollbar(scrollPtr) + register TkScrollbar *scrollPtr; /* Information about widget; may or + * may not already have values for + * some fields. */ +{ +} + +/* + *---------------------------------------------------------------------- + * + * TkpComputeScrollbarGeometry -- + * + * After changes in a scrollbar's size or configuration, this + * procedure recomputes various geometry information used in + * displaying the scrollbar. + * + * Results: + * None. + * + * Side effects: + * The scrollbar will be displayed differently. + * + *---------------------------------------------------------------------- + */ + +void +TkpComputeScrollbarGeometry( + register TkScrollbar *scrollPtr) /* Scrollbar whose geometry may + * have changed. */ +{ + MacScrollbar *macScrollPtr = (MacScrollbar *) scrollPtr; + int width, fieldLength, adjust = 0; + + if (scrollPtr->highlightWidth < 0) { + scrollPtr->highlightWidth = 0; + } + scrollPtr->inset = scrollPtr->highlightWidth + scrollPtr->borderWidth; + width = (scrollPtr->vertical) ? Tk_Width(scrollPtr->tkwin) + : Tk_Height(scrollPtr->tkwin); + scrollPtr->arrowLength = width - 2*scrollPtr->inset + 1; + fieldLength = (scrollPtr->vertical ? Tk_Height(scrollPtr->tkwin) + : Tk_Width(scrollPtr->tkwin)) + - 2*(scrollPtr->arrowLength + scrollPtr->inset); + if (fieldLength < 0) { + fieldLength = 0; + } + scrollPtr->sliderFirst = fieldLength*scrollPtr->firstFraction; + scrollPtr->sliderLast = fieldLength*scrollPtr->lastFraction; + + /* + * Adjust the slider so that some piece of it is always + * displayed in the scrollbar and so that it has at least + * a minimal width (so it can be grabbed with the mouse). + */ + + if (scrollPtr->sliderFirst > (fieldLength - 2*scrollPtr->borderWidth)) { + scrollPtr->sliderFirst = fieldLength - 2*scrollPtr->borderWidth; + } + if (scrollPtr->sliderFirst < 0) { + scrollPtr->sliderFirst = 0; + } + if (scrollPtr->sliderLast < (scrollPtr->sliderFirst + + MIN_SLIDER_LENGTH)) { + scrollPtr->sliderLast = scrollPtr->sliderFirst + MIN_SLIDER_LENGTH; + } + if (scrollPtr->sliderLast > fieldLength) { + scrollPtr->sliderLast = fieldLength; + } + scrollPtr->sliderFirst += scrollPtr->arrowLength + scrollPtr->inset; + scrollPtr->sliderLast += scrollPtr->arrowLength + scrollPtr->inset; + + /* + * Register the desired geometry for the window (leave enough space + * for the two arrows plus a minimum-size slider, plus border around + * the whole window, if any). Then arrange for the window to be + * redisplayed. + */ + + if (scrollPtr->vertical) { + if ((macScrollPtr->macFlags & AUTO_ADJUST) && + (macScrollPtr->macFlags & (FLUSH_RIGHT|FLUSH_LEFT))) { + adjust--; + } + Tk_GeometryRequest(scrollPtr->tkwin, + scrollPtr->width + 2*scrollPtr->inset + adjust, + 2*(scrollPtr->arrowLength + scrollPtr->borderWidth + + scrollPtr->inset)); + } else { + if ((macScrollPtr->macFlags & AUTO_ADJUST) && + (macScrollPtr->macFlags & (FLUSH_TOP|FLUSH_BOTTOM))) { + adjust--; + } + Tk_GeometryRequest(scrollPtr->tkwin, + 2*(scrollPtr->arrowLength + scrollPtr->borderWidth + + scrollPtr->inset), scrollPtr->width + 2*scrollPtr->inset + adjust); + } + Tk_SetInternalBorder(scrollPtr->tkwin, scrollPtr->inset); +} + +/* + *---------------------------------------------------------------------- + * + * TkpDestroyScrollbar -- + * + * Free data structures associated with the scrollbar control. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +TkpDestroyScrollbar( + TkScrollbar *scrollPtr) /* Scrollbar to destroy. */ +{ + MacScrollbar *macScrollPtr = (MacScrollbar *)scrollPtr; + + if (macScrollPtr->sbHandle != NULL) { + if (!(macScrollPtr->macFlags & IN_MODAL_LOOP)) { + DisposeControl(macScrollPtr->sbHandle); + macScrollPtr->sbHandle = NULL; + } + } + macScrollPtr->macFlags |= ALREADY_DEAD; +} + +/* + *-------------------------------------------------------------- + * + * TkpScrollbarPosition -- + * + * Determine the scrollbar element corresponding to a + * given position. + * + * Results: + * One of TOP_ARROW, TOP_GAP, etc., indicating which element + * of the scrollbar covers the position given by (x, y). If + * (x,y) is outside the scrollbar entirely, then OUTSIDE is + * returned. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +int +TkpScrollbarPosition( + TkScrollbar *scrollPtr, /* Scrollbar widget record. */ + int x, int y) /* Coordinates within scrollPtr's + * window. */ +{ + MacScrollbar *macScrollPtr = (MacScrollbar *) scrollPtr; + GWorldPtr destPort; + int length, width, tmp, inactive = false; + ControlPartCode part; + Point where; + Rect bounds; + + if (scrollPtr->vertical) { + length = Tk_Height(scrollPtr->tkwin); + width = Tk_Width(scrollPtr->tkwin); + } else { + tmp = x; + x = y; + y = tmp; + length = Tk_Width(scrollPtr->tkwin); + width = Tk_Height(scrollPtr->tkwin); + } + + if ((x < scrollPtr->inset) || (x >= (width - scrollPtr->inset)) + || (y < scrollPtr->inset) || (y >= (length - scrollPtr->inset))) { + return OUTSIDE; + } + + /* + * All of the calculations in this procedure mirror those in + * DisplayScrollbar. Be sure to keep the two consistent. On the + * Macintosh we use the OS call TestControl to do this mapping. + * For TestControl to work, the scrollbar must be active and must + * be in the current port. + */ + + destPort = TkMacGetDrawablePort(Tk_WindowId(scrollPtr->tkwin)); + SetGWorld(destPort, NULL); + UpdateControlValues(macScrollPtr); + if ((**macScrollPtr->sbHandle).contrlHilite == 255) { + inactive = true; + (**macScrollPtr->sbHandle).contrlHilite = 0; + } + + TkMacWinBounds((TkWindow *) scrollPtr->tkwin, &bounds); + where.h = x + bounds.left; + where.v = y + bounds.top; + part = TestControl(((MacScrollbar *) scrollPtr)->sbHandle, where); + if (inactive) { + (**macScrollPtr->sbHandle).contrlHilite = 255; + } + switch (part) { + case inUpButton: + return TOP_ARROW; + case inPageUp: + return TOP_GAP; + case inThumb: + return SLIDER; + case inPageDown: + return BOTTOM_GAP; + case inDownButton: + return BOTTOM_ARROW; + default: + return OUTSIDE; + } +} + +/* + *-------------------------------------------------------------- + * + * ThumbActionProc -- + * + * Callback procedure used by the Macintosh toolbox call + * TrackControl. This call is used to track the thumb of + * the scrollbar. Unlike the ScrollbarActionProc function + * this function is called once and basically takes over + * tracking the scrollbar from the control. This is done + * to avoid conflicts with what the control plans to draw. + * + * Results: + * None. + * + * Side effects: + * May change the display. + * + *-------------------------------------------------------------- + */ + +static pascal void +ThumbActionProc() +{ + register TkScrollbar *scrollPtr = activeScrollPtr; + register MacScrollbar *macScrollPtr = (MacScrollbar *) activeScrollPtr; + Tcl_DString cmdString; + Rect nullRect = {0,0,0,0}; + int origValue, trackBarPin; + double thumbWidth, newFirstFraction, trackBarSize; + char vauleString[40]; + Point currentPoint = { 0, 0 }; + Point lastPoint = { 0, 0 }; + Rect trackRect; + Tcl_Interp *interp; + + if (scrollPtr == NULL) { + return; + } + + Tcl_DStringInit(&cmdString); + + /* + * First compute values that will remain constant during the tracking + * of the thumb. The variable trackBarSize is the length of the scrollbar + * minus the 2 arrows and half the width of the thumb on both sides + * (3 * arrowLength). The variable trackBarPin is the lower starting point + * of the drag region. + * + * Note: the arrowLength is equal to the thumb width of a Mac scrollbar. + */ + origValue = GetControlValue(macScrollPtr->sbHandle); + trackRect = (**macScrollPtr->sbHandle).contrlRect; + if (scrollPtr->vertical == true) { + trackBarSize = (double) (trackRect.bottom - trackRect.top + - (scrollPtr->arrowLength * 3)); + trackBarPin = trackRect.top + scrollPtr->arrowLength + + (scrollPtr->arrowLength / 2); + InsetRect(&trackRect, -25, -113); + + } else { + trackBarSize = (double) (trackRect.right - trackRect.left + - (scrollPtr->arrowLength * 3)); + trackBarPin = trackRect.left + scrollPtr->arrowLength + + (scrollPtr->arrowLength / 2); + InsetRect(&trackRect, -113, -25); + } + + /* + * Track the mouse while the button is held down. If the mouse is moved, + * we calculate the value that should be passed to the "command" part of + * the scrollbar. + */ + while (StillDown()) { + GetMouse(¤tPoint); + if (EqualPt(currentPoint, lastPoint)) { + continue; + } + lastPoint = currentPoint; + + /* + * Calculating this value is a little tricky. We need to calculate a + * value for where the thumb would be in a Motif widget (variable + * thumb). This value is what the "command" expects and is what will + * be resent to the scrollbar to update its value. + */ + thumbWidth = scrollPtr->lastFraction - scrollPtr->firstFraction; + if (PtInRect(currentPoint, &trackRect)) { + if (scrollPtr->vertical == true) { + newFirstFraction = (1.0 - thumbWidth) * + ((double) (currentPoint.v - trackBarPin) / trackBarSize); + } else { + newFirstFraction = (1.0 - thumbWidth) * + ((double) (currentPoint.h - trackBarPin) / trackBarSize); + } + } else { + newFirstFraction = ((double) origValue / 1000.0) + * (1.0 - thumbWidth); + } + + sprintf(vauleString, "%g", newFirstFraction); + + Tcl_DStringSetLength(&cmdString, 0); + Tcl_DStringAppend(&cmdString, scrollPtr->command, + scrollPtr->commandSize); + Tcl_DStringAppendElement(&cmdString, "moveto"); + Tcl_DStringAppendElement(&cmdString, vauleString); + + interp = scrollPtr->interp; + Tcl_Preserve((ClientData) interp); + Tcl_GlobalEval(interp, cmdString.string); + Tcl_Release((ClientData) interp); + + Tcl_DStringSetLength(&cmdString, 0); + Tcl_DStringAppend(&cmdString, "update idletasks", + strlen("update idletasks")); + Tcl_Preserve((ClientData) interp); + Tcl_GlobalEval(interp, cmdString.string); + Tcl_Release((ClientData) interp); + } + + /* + * This next bit of code is a bit of a hack - but needed. The problem is + * that the control wants to draw the drag outline if the control value + * changes during the drag (which it does). What we do here is change the + * clip region to hide this drawing from the user. + */ + ClipRect(&nullRect); + + Tcl_DStringFree(&cmdString); + return; +} + +/* + *-------------------------------------------------------------- + * + * ScrollbarActionProc -- + * + * Callback procedure used by the Macintosh toolbox call + * TrackControl. This call will update the display while + * the scrollbar is being manipulated by the user. + * + * Results: + * None. + * + * Side effects: + * May change the display. + * + *-------------------------------------------------------------- + */ + +static pascal void +ScrollbarActionProc( + ControlRef theControl, /* Handle to scrollbat control */ + ControlPartCode partCode) /* Part of scrollbar that was "hit" */ +{ + register TkScrollbar *scrollPtr = (TkScrollbar *) GetCRefCon(theControl); + Tcl_DString cmdString; + + Tcl_DStringInit(&cmdString); + Tcl_DStringAppend(&cmdString, scrollPtr->command, + scrollPtr->commandSize); + + if (partCode == inUpButton || partCode == inDownButton) { + Tcl_DStringAppendElement(&cmdString, "scroll"); + Tcl_DStringAppendElement(&cmdString, + (partCode == inUpButton ) ? "-1" : "1"); + Tcl_DStringAppendElement(&cmdString, "unit"); + } else if (partCode == inPageUp || partCode == inPageDown) { + Tcl_DStringAppendElement(&cmdString, "scroll"); + Tcl_DStringAppendElement(&cmdString, + (partCode == inPageUp ) ? "-1" : "1"); + Tcl_DStringAppendElement(&cmdString, "page"); + } + Tcl_Preserve((ClientData) scrollPtr->interp); + Tcl_DStringAppend(&cmdString, "; update idletasks", + strlen("; update idletasks")); + Tcl_GlobalEval(scrollPtr->interp, cmdString.string); + Tcl_Release((ClientData) scrollPtr->interp); + + Tcl_DStringFree(&cmdString); +} + +/* + *-------------------------------------------------------------- + * + * ScrollbarBindProc -- + * + * This procedure is invoked when the default <ButtonPress> + * binding on the Scrollbar bind tag fires. + * + * Results: + * None. + * + * Side effects: + * The event enters a modal loop. + * + *-------------------------------------------------------------- + */ + +static int +ScrollbarBindProc( + ClientData clientData, /* Not used. */ + Tcl_Interp *interp, /* Interp with binding. */ + XEvent *eventPtr, /* X event that triggered binding. */ + Tk_Window tkwin, /* Target window for event. */ + KeySym keySym) /* The KeySym if a key event. */ +{ + TkWindow *winPtr = (TkWindow*)tkwin; + TkScrollbar *scrollPtr = (TkScrollbar *) winPtr->instanceData; + MacScrollbar *macScrollPtr = (MacScrollbar *) winPtr->instanceData; + + Tcl_Preserve((ClientData)scrollPtr); + macScrollPtr->macFlags |= IN_MODAL_LOOP; + + if (eventPtr->type == ButtonPress) { + Point where; + Rect bounds; + int part, x, y, dummy; + unsigned int state; + CGrafPtr saveWorld; + GDHandle saveDevice; + GWorldPtr destPort; + Window window; + + /* + * To call Macintosh control routines we must have the port + * set to the window containing the control. We will then test + * which part of the control was hit and act accordingly. + */ + destPort = TkMacGetDrawablePort(Tk_WindowId(scrollPtr->tkwin)); + GetGWorld(&saveWorld, &saveDevice); + SetGWorld(destPort, NULL); + TkMacSetUpClippingRgn(Tk_WindowId(scrollPtr->tkwin)); + + TkMacWinBounds((TkWindow *) scrollPtr->tkwin, &bounds); + where.h = eventPtr->xbutton.x + bounds.left; + where.v = eventPtr->xbutton.y + bounds.top; + part = TestControl(macScrollPtr->sbHandle, where); + if (part == inThumb && scrollPtr->jump == false) { + /* + * Case 1: In thumb, no jump scrolling. Call track control + * with the thumb action proc which will do most of the work. + * Set the global activeScrollPtr to the current control + * so the callback may have access to it. + */ + activeScrollPtr = scrollPtr; + part = TrackControl(macScrollPtr->sbHandle, where, + (ControlActionUPP) thumbActionProc); + activeScrollPtr = NULL; + } else if (part == inThumb) { + /* + * Case 2: in thumb with jump scrolling. Call TrackControl + * with a NULL action proc. Use the new value of the control + * to set update the control. + */ + part = TrackControl(macScrollPtr->sbHandle, where, NULL); + if (part == inThumb) { + double newFirstFraction, thumbWidth; + Tcl_DString cmdString; + char vauleString[TCL_DOUBLE_SPACE]; + + /* + * The following calculation takes the new control + * value and maps it to what Tk needs for its variable + * thumb size representation. + */ + thumbWidth = scrollPtr->lastFraction + - scrollPtr->firstFraction; + newFirstFraction = (1.0 - thumbWidth) * + ((double) GetControlValue(macScrollPtr->sbHandle) / 1000.0); + sprintf(vauleString, "%g", newFirstFraction); + + Tcl_DStringInit(&cmdString); + Tcl_DStringAppend(&cmdString, scrollPtr->command, + strlen(scrollPtr->command)); + Tcl_DStringAppendElement(&cmdString, "moveto"); + Tcl_DStringAppendElement(&cmdString, vauleString); + Tcl_DStringAppend(&cmdString, "; update idletasks", + strlen("; update idletasks")); + + interp = scrollPtr->interp; + Tcl_Preserve((ClientData) interp); + Tcl_GlobalEval(interp, cmdString.string); + Tcl_Release((ClientData) interp); + Tcl_DStringFree(&cmdString); + } + } else if (part != 0) { + /* + * Case 3: in any other part of the scrollbar. We call + * TrackControl with the scrollActionProc which will do + * most all the work. + */ + TrackControl(macScrollPtr->sbHandle, where, scrollActionProc); + HiliteControl(macScrollPtr->sbHandle, 0); + } + + /* + * The TrackControl call will "eat" the ButtonUp event. We now + * generate a ButtonUp event so Tk will unset implicit grabs etc. + */ + GetMouse(&where); + XQueryPointer(NULL, None, &window, &window, &x, + &y, &dummy, &dummy, &state); + window = Tk_WindowId(scrollPtr->tkwin); + TkGenerateButtonEvent(x, y, window, state); + + SetGWorld(saveWorld, saveDevice); + } + + if (macScrollPtr->sbHandle && (macScrollPtr->macFlags & ALREADY_DEAD)) { + DisposeControl(macScrollPtr->sbHandle); + macScrollPtr->sbHandle = NULL; + } + macScrollPtr->macFlags &= ~IN_MODAL_LOOP; + Tcl_Release((ClientData)scrollPtr); + + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * ScrollbarEventProc -- + * + * This procedure is invoked by the Tk dispatcher for various + * events on scrollbars. + * + * Results: + * None. + * + * Side effects: + * When the window gets deleted, internal structures get + * cleaned up. When it gets exposed, it is redisplayed. + * + *-------------------------------------------------------------- + */ + +static void +ScrollbarEventProc( + ClientData clientData, /* Information about window. */ + XEvent *eventPtr) /* Information about event. */ +{ + TkScrollbar *scrollPtr = (TkScrollbar *) clientData; + MacScrollbar *macScrollPtr = (MacScrollbar *) clientData; + + if (eventPtr->type == UnmapNotify) { + TkMacSetScrollbarGrow((TkWindow *) scrollPtr->tkwin, false); + } else if (eventPtr->type == ActivateNotify) { + macScrollPtr->macFlags |= ACTIVE; + TkScrollbarEventuallyRedraw((ClientData) scrollPtr); + } else if (eventPtr->type == DeactivateNotify) { + macScrollPtr->macFlags &= ~ACTIVE; + TkScrollbarEventuallyRedraw((ClientData) scrollPtr); + } else { + TkScrollbarEventProc(clientData, eventPtr); + } +} + +/* + *-------------------------------------------------------------- + * + * UpdateControlValues -- + * + * This procedure updates the Macintosh scrollbar control + * to display the values defined by the Tk scrollbar. + * + * Results: + * None. + * + * Side effects: + * The Macintosh control is updated. + * + *-------------------------------------------------------------- + */ + +static void +UpdateControlValues( + MacScrollbar *macScrollPtr) /* Scrollbar data struct. */ +{ + TkScrollbar *scrollPtr = (TkScrollbar *) macScrollPtr; + Tk_Window tkwin = scrollPtr->tkwin; + MacDrawable * macDraw = (MacDrawable *) Tk_WindowId(scrollPtr->tkwin); + WindowRef windowRef = (**macScrollPtr->sbHandle).contrlOwner; + double middle; + int drawGrowRgn = false; + int flushRight = false; + int flushBottom = false; + + /* + * We can't use the Macintosh commands SizeControl and MoveControl as these + * calls will also cause a redraw which in our case will also cause + * flicker. To avoid this we adjust the control record directly. The + * Draw1Control command appears to just draw where ever the control says to + * draw so this seems right. + * + * NOTE: changing the control record directly may not work when + * Apple releases the Copland version of the MacOS (or when hell is cold). + */ + + (**macScrollPtr->sbHandle).contrlRect.left = macDraw->xOff + scrollPtr->inset; + (**macScrollPtr->sbHandle).contrlRect.top = macDraw->yOff + scrollPtr->inset; + (**macScrollPtr->sbHandle).contrlRect.right = macDraw->xOff + Tk_Width(tkwin) + - scrollPtr->inset; + (**macScrollPtr->sbHandle).contrlRect.bottom = macDraw->yOff + + Tk_Height(tkwin) - scrollPtr->inset; + + /* + * To make Tk applications look more like Macintosh applications without + * requiring additional work by the Tk developer we do some cute tricks. + * The first trick plays with the size of the widget to get it to overlap + * with the side of the window by one pixel (we don't do this if the placer + * is the geometry manager). The second trick shrinks the scrollbar if it + * it covers the area of the grow region ao the scrollbar can also draw + * the grow region if need be. + */ + if (!strcmp(macDraw->winPtr->geomMgrPtr->name, "place")) { + macScrollPtr->macFlags &= AUTO_ADJUST; + } else { + macScrollPtr->macFlags |= AUTO_ADJUST; + } + /* TODO: use accessor function!!! */ + if (windowRef->portRect.left == (**macScrollPtr->sbHandle).contrlRect.left) { + if (macScrollPtr->macFlags & AUTO_ADJUST) { + (**macScrollPtr->sbHandle).contrlRect.left--; + } + if (!(macScrollPtr->macFlags & FLUSH_LEFT)) { + macScrollPtr->macFlags |= FLUSH_LEFT; + if (scrollPtr->vertical) { + TkpComputeScrollbarGeometry(scrollPtr); + } + } + } else if (macScrollPtr->macFlags & FLUSH_LEFT) { + macScrollPtr->macFlags &= ~FLUSH_LEFT; + if (scrollPtr->vertical) { + TkpComputeScrollbarGeometry(scrollPtr); + } + } + + if (windowRef->portRect.top == (**macScrollPtr->sbHandle).contrlRect.top) { + if (macScrollPtr->macFlags & AUTO_ADJUST) { + (**macScrollPtr->sbHandle).contrlRect.top--; + } + if (!(macScrollPtr->macFlags & FLUSH_TOP)) { + macScrollPtr->macFlags |= FLUSH_TOP; + if (! scrollPtr->vertical) { + TkpComputeScrollbarGeometry(scrollPtr); + } + } + } else if (macScrollPtr->macFlags & FLUSH_TOP) { + macScrollPtr->macFlags &= ~FLUSH_TOP; + if (! scrollPtr->vertical) { + TkpComputeScrollbarGeometry(scrollPtr); + } + } + + if (windowRef->portRect.right == (**macScrollPtr->sbHandle).contrlRect.right) { + flushRight = true; + if (macScrollPtr->macFlags & AUTO_ADJUST) { + (**macScrollPtr->sbHandle).contrlRect.right++; + } + if (!(macScrollPtr->macFlags & FLUSH_RIGHT)) { + macScrollPtr->macFlags |= FLUSH_RIGHT; + if (scrollPtr->vertical) { + TkpComputeScrollbarGeometry(scrollPtr); + } + } + } else if (macScrollPtr->macFlags & FLUSH_RIGHT) { + macScrollPtr->macFlags &= ~FLUSH_RIGHT; + if (scrollPtr->vertical) { + TkpComputeScrollbarGeometry(scrollPtr); + } + } + + if (windowRef->portRect.bottom == (**macScrollPtr->sbHandle).contrlRect.bottom) { + flushBottom = true; + if (macScrollPtr->macFlags & AUTO_ADJUST) { + (**macScrollPtr->sbHandle).contrlRect.bottom++; + } + if (!(macScrollPtr->macFlags & FLUSH_BOTTOM)) { + macScrollPtr->macFlags |= FLUSH_BOTTOM; + if (! scrollPtr->vertical) { + TkpComputeScrollbarGeometry(scrollPtr); + } + } + } else if (macScrollPtr->macFlags & FLUSH_BOTTOM) { + macScrollPtr->macFlags &= ~FLUSH_BOTTOM; + if (! scrollPtr->vertical) { + TkpComputeScrollbarGeometry(scrollPtr); + } + } + + /* + * If the scrollbar is flush against the bottom right hand coner then + * it may need to draw the grow region for the window so we let the + * wm code know about this scrollbar. We don't actually draw the grow + * region, however, unless we are currently resizable. + */ + macScrollPtr->macFlags &= ~DRAW_GROW; + if (flushBottom && flushRight) { + TkMacSetScrollbarGrow((TkWindow *) tkwin, true); + if (TkMacResizable(macDraw->toplevel->winPtr)) { + if (scrollPtr->vertical) { + (**macScrollPtr->sbHandle).contrlRect.bottom -= 14; + } else { + (**macScrollPtr->sbHandle).contrlRect.right -= 14; + } + macScrollPtr->macFlags |= DRAW_GROW; + } + } else { + TkMacSetScrollbarGrow((TkWindow *) tkwin, false); + } + + /* + * Given the Tk parameters for the fractions of the start and + * end of the thumb, the following calculation determines the + * location for the fixed sized Macintosh thumb. + */ + middle = scrollPtr->firstFraction / (scrollPtr->firstFraction + + (1.0 - scrollPtr->lastFraction)); + + (**macScrollPtr->sbHandle).contrlValue = (short) (middle * 1000); + if ((**macScrollPtr->sbHandle).contrlHilite == 0 || + (**macScrollPtr->sbHandle).contrlHilite == 255) { + if (scrollPtr->firstFraction == 0.0 && + scrollPtr->lastFraction == 1.0) { + (**macScrollPtr->sbHandle).contrlHilite = 255; + } else { + (**macScrollPtr->sbHandle).contrlHilite = 0; + } + } + if ((**macScrollPtr->sbHandle).contrlVis != 255) { + (**macScrollPtr->sbHandle).contrlVis = 255; + } +} diff --git a/mac/tkMacSend.c b/mac/tkMacSend.c new file mode 100644 index 0000000..85065ac --- /dev/null +++ b/mac/tkMacSend.c @@ -0,0 +1,358 @@ +/* + * tkMacSend.c -- + * + * This file provides procedures that implement the "send" + * command, allowing commands to be passed from interpreter + * to interpreter. This current implementation for the Mac + * has most functionality stubed out. + * + * Copyright (c) 1989-1994 The Regents of the University of California. + * Copyright (c) 1994-1996 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) tkMacSend.c 1.7 96/12/03 11:48:27 + */ + +#include "tkPort.h" +#include "tkInt.h" + + /* + * The following structure is used to keep track of the + * interpreters registered by this process. + */ + +typedef struct RegisteredInterp { + char *name; /* Interpreter's name (malloc-ed). */ + Tcl_Interp *interp; /* Interpreter associated with + * name. */ + TkWindow *winPtr; /* Main window for the application. */ + struct RegisteredInterp *nextPtr; + /* Next in list of names associated + * with interps in this process. + * NULL means end of list. */ +} RegisteredInterp; + +static RegisteredInterp *registry = NULL; +/* List of all interpreters + * registered by this process. */ + +/* + * A registry of all interpreters for a display is kept in a + * property "InterpRegistry" on the root window of the display. + * It is organized as a series of zero or more concatenated strings + * (in no particular order), each of the form + * window space name '\0' + * where "window" is the hex id of the comm. window to use to talk + * to an interpreter named "name". + * + * When the registry is being manipulated by an application (e.g. to + * add or remove an entry), it is loaded into memory using a structure + * of the following type: + */ + +typedef struct NameRegistry { + TkDisplay *dispPtr; /* Display from which the registry was + * read. */ + int locked; /* Non-zero means that the display was + * locked when the property was read in. */ + int modified; /* Non-zero means that the property has + * been modified, so it needs to be written + * out when the NameRegistry is closed. */ + unsigned long propLength; /* Length of the property, in bytes. */ + char *property; /* The contents of the property. See format + * above; this is *not* terminated by the + * first null character. Dynamically + * allocated. */ + int allocedByX; /* Non-zero means must free property with + * XFree; zero means use ckfree. */ +} NameRegistry; + + /* + * When a result is being awaited from a sent command, one of + * the following structures is present on a list of all outstanding + * sent commands. The information in the structure is used to + * process the result when it arrives. You're probably wondering + * how there could ever be multiple outstanding sent commands. + * This could happen if interpreters invoke each other recursively. + * It's unlikely, but possible. + */ + +typedef struct PendingCommand { + int serial; /* Serial number expected in + * result. */ + TkDisplay *dispPtr; /* Display being used for communication. */ + char *target; /* Name of interpreter command is + * being sent to. */ + Window commWindow; /* Target's communication window. */ + Tk_TimerToken timeout; /* Token for timer handler used to check + * up on target during long sends. */ + Tcl_Interp *interp; /* Interpreter from which the send + * was invoked. */ + int code; /* Tcl return code for command + * will be stored here. */ + char *result; /* String result for command (malloc'ed), + * or NULL. */ + char *errorInfo; /* Information for "errorInfo" variable, + * or NULL (malloc'ed). */ + char *errorCode; /* Information for "errorCode" variable, + * or NULL (malloc'ed). */ + int gotResponse; /* 1 means a response has been received, + * 0 means the command is still outstanding. */ + struct PendingCommand *nextPtr; + /* Next in list of all outstanding + * commands. NULL means end of + * list. */ +} PendingCommand; + +static PendingCommand *pendingCommands = NULL; +/* List of all commands currently + * being waited for. */ + + /* + * The information below is used for communication between processes + * during "send" commands. Each process keeps a private window, never + * even mapped, with one property, "Comm". When a command is sent to + * an interpreter, the command is appended to the comm property of the + * communication window associated with the interp's process. Similarly, + * when a result is returned from a sent command, it is also appended + * to the comm property. + * + * Each command and each result takes the form of ASCII text. For a + * command, the text consists of a zero character followed by several + * null-terminated ASCII strings. The first string consists of the + * single letter "c". Subsequent strings have the form "option value" + * where the following options are supported: + * + * -r commWindow serial + * + * This option means that a response should be sent to the window + * whose X identifier is "commWindow" (in hex), and the response should + * be identified with the serial number given by "serial" (in decimal). + * If this option isn't specified then the send is asynchronous and + * no response is sent. + * + * -n name + * "Name" gives the name of the application for which the command is + * intended. This option must be present. + * + * -s script + * + * "Script" is the script to be executed. This option must be present. + * + * The options may appear in any order. The -n and -s options must be + * present, but -r may be omitted for asynchronous RPCs. For compatibility + * with future releases that may add new features, there may be additional + * options present; as long as they start with a "-" character, they will + * be ignored. + * + * A result also consists of a zero character followed by several null- + * terminated ASCII strings. The first string consists of the single + * letter "r". Subsequent strings have the form "option value" where + * the following options are supported: + * + * -s serial + * + * Identifies the command for which this is the result. It is the + * same as the "serial" field from the -s option in the command. This + * option must be present. + * + * -c code + * + * "Code" is the completion code for the script, in decimal. If the + * code is omitted it defaults to TCL_OK. + * + * -r result + * + * "Result" is the result string for the script, which may be either + * a result or an error message. If this field is omitted then it + * defaults to an empty string. + * + * -i errorInfo + * + * "ErrorInfo" gives a string with which to initialize the errorInfo + * variable. This option may be omitted; it is ignored unless the + * completion code is TCL_ERROR. + * + * -e errorCode + * + * "ErrorCode" gives a string with with to initialize the errorCode + * variable. This option may be omitted; it is ignored unless the + * completion code is TCL_ERROR. + * + * Options may appear in any order, and only the -s option must be + * present. As with commands, there may be additional options besides + * these; unknown options are ignored. + */ + + /* + * The following variable is the serial number that was used in the + * last "send" command. It is exported only for testing purposes. + */ + +int tkSendSerial = 0; + + /* + * Maximum size property that can be read at one time by + * this module: + */ + +#define MAX_PROP_WORDS 100000 + +/* + * Forward declarations for procedures defined later in this file: + */ + +static int AppendErrorProc _ANSI_ARGS_((ClientData clientData, + XErrorEvent *errorPtr)); +static void AppendPropCarefully _ANSI_ARGS_((Display *display, + Window window, Atom property, char *value, + int length, PendingCommand *pendingPtr)); +static void DeleteProc _ANSI_ARGS_((ClientData clientData)); +static void RegAddName _ANSI_ARGS_((NameRegistry *regPtr, + char *name, Window commWindow)); +static void RegClose _ANSI_ARGS_((NameRegistry *regPtr)); +static void RegDeleteName _ANSI_ARGS_((NameRegistry *regPtr, + char *name)); +static Window RegFindName _ANSI_ARGS_((NameRegistry *regPtr, + char *name)); +static NameRegistry * RegOpen _ANSI_ARGS_((Tcl_Interp *interp, + TkWindow *winPtr, int lock)); +static void SendEventProc _ANSI_ARGS_((ClientData clientData, + XEvent *eventPtr)); +static int SendInit _ANSI_ARGS_((Tcl_Interp *interp, + TkWindow *winPtr)); +static Bool SendRestrictProc _ANSI_ARGS_((Display *display, + XEvent *eventPtr, char *arg)); +static int ServerSecure _ANSI_ARGS_((TkDisplay *dispPtr)); +static void TimeoutProc _ANSI_ARGS_((ClientData clientData)); +static int ValidateName _ANSI_ARGS_((TkDisplay *dispPtr, + char *name, Window commWindow, int oldOK)); + +/* + *-------------------------------------------------------------- + * + * Tk_SetAppName -- + * + * This procedure is called to associate an ASCII name with a Tk + * application. If the application has already been named, the + * name replaces the old one. + * + * Results: + * The return value is the name actually given to the application. + * This will normally be the same as name, but if name was already + * in use for an application then a name of the form "name #2" will + * be chosen, with a high enough number to make the name unique. + * + * Side effects: + * Registration info is saved, thereby allowing the "send" command + * to be used later to invoke commands in the application. In + * addition, the "send" command is created in the application's + * interpreter. The registration will be removed automatically + * if the interpreter is deleted or the "send" command is removed. + * + *-------------------------------------------------------------- + */ + +char * +Tk_SetAppName( + Tk_Window tkwin, /* Token for any window in the application + * to be named: it is just used to identify + * the application and the display. */ + char *name) /* The name that will be used to + * refer to the interpreter in later + * "send" commands. Must be globally + * unique. */ +{ + return name; +} + +/* + *-------------------------------------------------------------- + * + * Tk_SendCmd -- + * + * This procedure is invoked to process the "send" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ + +int +Tk_SendCmd( + ClientData clientData, /* Information about sender (only + * dispPtr field is used). */ + Tcl_Interp *interp, /* Current interpreter. */ + int argc, /* Number of arguments. */ + char **argv) /* Argument strings. */ +{ + Tcl_SetResult(interp, "Send not yet implemented", TCL_STATIC); + return TCL_ERROR; +} + +/* + *---------------------------------------------------------------------- + * + * TkGetInterpNames -- + * + * This procedure is invoked to fetch a list of all the + * interpreter names currently registered for the display + * of a particular window. + * + * Results: + * A standard Tcl return value. Interp->result will be set + * to hold a list of all the interpreter names defined for + * tkwin's display. If an error occurs, then TCL_ERROR + * is returned and interp->result will hold an error message. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +TkGetInterpNames( + Tcl_Interp *interp, /* Interpreter for returning a result. */ + Tk_Window tkwin) /* Window whose display is to be used + * for the lookup. */ +{ + Tcl_SetResult(interp, "Send not yet implemented", TCL_STATIC); + return TCL_ERROR; +} + +/* + *-------------------------------------------------------------- + * + * SendInit -- + * + * This procedure is called to initialize the + * communication channels for sending commands and + * receiving results. + * + * Results: + * None. + * + * Side effects: + * Sets up various data structures and windows. + * + *-------------------------------------------------------------- + */ + +static int +SendInit( + Tcl_Interp *interp, /* Interpreter to use for error reporting + * (no errors are ever returned, but the + * interpreter is needed anyway). */ + TkWindow *winPtr) /* Window that identifies the display to + * initialize. */ +{ + return TCL_OK; +} diff --git a/mac/tkMacShLib.exp b/mac/tkMacShLib.exp new file mode 100644 index 0000000..0c28a4c --- /dev/null +++ b/mac/tkMacShLib.exp @@ -0,0 +1,766 @@ +MacMoveWindow +TkAboutDlg +TkActivateMenuEntry +TkAllocWindow +TkBTreeCharTagged +TkBTreeCharsInLine +TkBTreeCheck +TkBTreeCreate +TkBTreeDeleteChars +TkBTreeDestroy +TkBTreeFindLine +TkBTreeGetTags +TkBTreeInsertChars +TkBTreeLineIndex +TkBTreeLinkSegment +TkBTreeNextLine +TkBTreeNextTag +TkBTreeNumLines +TkBTreePrevTag +TkBTreePreviousLine +TkBTreeStartSearch +TkBTreeStartSearchBack +TkBTreeTag +TkBTreeUnlinkSegment +TkBezierPoints +TkBezierScreenPoints +TkBindDeadWindow +TkBindEventProc +TkBindFree +TkBindInit +TkButtonWorldChanged +TkCanvPostscriptCmd +TkChangeEventWindow +TkClipBox +TkClipInit +TkComputeAnchor +TkConsoleCreate +TkConsoleInit +TkConsolePrint +TkCopyAndGlobalEval +TkCreateBindingProcedure +TkCreateCursorFromData +TkCreateFrame +TkCreateMainWindow +TkCreateMenuReferences +TkCreateNamedFont +TkCreateRegion +TkCurrentTime +TkDeadAppCmd +TkDeleteAllImages +TkDestroyMenu +TkDestroyRegion +TkDoConfigureNotify +TkEventDeadWindow +TkEventuallyRecomputeMenu +TkEventuallyRedrawMenu +TkEventuallyRedrawScale +TkFillPolygon +TkFindMenuReferences +TkFindStateNum +TkFindStateString +TkFocusDeadWindow +TkFocusFilterEvent +TkFocusKeyEvent +TkFontPkgFree +TkFontPkgInit +TkFreeBindingTags +TkFreeCursor +TkFreeFileFilters +TkFreeMenuReferences +TkGenWMConfigureEvent +TkGenWMDestroyEvent +TkGenerateActivateEvents +TkGenerateButtonEvent +TkGetBitmapData +TkGetButtPoints +TkGetCursorByName +TkGetDefaultScreenName +TkGetDisplay +TkGetDisplayOf +TkGetFileFilters +TkGetInterpNames +TkGetMenuHashTable +TkGetMenuIndex +TkGetMiterPoints +TkGetNativeProlog +TkGetPointerCoords +TkGetProlog +TkGetServerInfo +TkGetTransientMaster +TkGrabDeadWindow +TkGrabState +TkInOutEvents +TkIncludePoint +TkInitFileFilters +TkInitFontAttributes +TkIntersectRegion +TkInvokeButton +TkInvokeMenu +TkKeysymToString +TkLineToArea +TkLineToPoint +TkMacButtonKeyState +TkMacClearMenubarActive +TkMacConvertEvent +TkMacConvertTkEvent +TkMacDispatchMenuEvent +TkMacDoHLEvent +TkMacGenerateTime +TkMacGetDrawablePort +TkMacGetScrollbarGrowWindow +TkMacGetXWindow +TkMacGrowToplevel +TkMacHandleMenuSelect +TkMacHandleTearoffMenu +TkMacInitAppleEvents +TkMacInitMenus +TkMacInstallCursor +TkMacInvalClipRgns +TkMacInvalidateWindow +TkMacIsCharacterMissing +TkMacMakeRealWindowExist +TkMacMakeStippleMap +TkMacMenuClick +TkMacRegisterOffScreenWindow +TkMacResizable +TkMacSetEmbedRgn +TkMacSetHelpMenuItemCount +TkMacSetScrollbarGrow +TkMacSetUpClippingRgn +TkMacSetUpGraphicsPort +TkMacUnregisterMacWindow +TkMacUpdateClipRgn +TkMacUseMenuID +TkMacVisableClipRgn +TkMacWinBounds +TkMacWindowOffset +TkMacXAddPixel +TkMacXDestroyImage +TkMacXGetPixel +TkMacXPutPixel +TkMacXSubImage +TkMacZoomToplevel +TkMakeBezierCurve +TkMakeBezierPostscript +TkMakeMenuWindow +TkMenuButtonWorldChanged +TkMenuConfigureDrawOptions +TkMenuConfigureEntryDrawOptions +TkMenuEntryFreeDrawOptions +TkMenuEventProc +TkMenuFreeDrawOptions +TkMenuImageProc +TkMenuInit +TkMenuInitializeDrawingFields +TkMenuInitializeEntryDrawingFields +TkMenuSelectImageProc +TkNewMenuName +TkOptionClassChanged +TkOptionDeadWindow +TkOvalToArea +TkOvalToPoint +TkParseXLFD +TkPointerDeadWindow +TkPointerEvent +TkPolygonToArea +TkPolygonToPoint +TkPositionInTree +TkPostCommand +TkPostSubmenu +TkPostTearoffMenu +TkPreprocessMenu +TkPutImage +TkQueueEventForAllChildren +TkRecomputeMenu +TkRectInRegion +TkRoundToResolution +TkScrollWindow +TkScrollbarEventProc +TkScrollbarEventuallyRedraw +TkSelClearSelection +TkSelDeadWindow +TkSelDefaultSelection +TkSelEventProc +TkSelGetSelection +TkSelInit +TkSelPropProc +TkSelUpdateClipboard +TkSetClassProcs +TkSetMacColor +TkSetRegion +TkSetWMName +TkSetWindowMenuBar +TkStringToKeysym +TkSuspendClipboard +TkTextBindProc +TkTextChanged +TkTextCharBbox +TkTextCharLayoutProc +TkTextCreateDInfo +TkTextCreateTag +TkTextDLineInfo +TkTextEventuallyRepick +TkTextFreeDInfo +TkTextFreeTag +TkTextGetIndex +TkTextGetTabs +TkTextImageCmd +TkTextImageIndex +TkTextIndexBackChars +TkTextIndexCmp +TkTextIndexForwChars +TkTextIndexToSeg +TkTextInsertDisplayProc +TkTextLostSelection +TkTextMakeIndex +TkTextMarkCmd +TkTextMarkNameToIndex +TkTextMarkSegToIndex +TkTextPickCurrent +TkTextPixelIndex +TkTextPrintIndex +TkTextRedrawRegion +TkTextRedrawTag +TkTextRelayoutWindow +TkTextScanCmd +TkTextSeeCmd +TkTextSegToOffset +TkTextSetMark +TkTextSetYView +TkTextTagCmd +TkTextWindowCmd +TkTextWindowIndex +TkTextXviewCmd +TkTextYviewCmd +TkThickPolyLineToArea +TkUnionRectWithRegion +TkUnsupported1Cmd +TkWmAddToColormapWindows +TkWmDeadWindow +TkWmFocusToplevel +TkWmMapWindow +TkWmNewWindow +TkWmProtocolEventProc +TkWmRemoveFromColormapWindows +TkWmRestackToplevel +TkWmSetClass +TkWmUnmapWindow +Tk_3DBorderColor +Tk_3DBorderGC +Tk_3DHorizontalBevel +Tk_3DVerticalBevel +Tk_AddOption +Tk_BellCmd +Tk_BindCmd +Tk_BindEvent +Tk_BindtagsCmd +Tk_ButtonCmd +Tk_CanvasCmd +Tk_CanvasDrawableCoords +Tk_CanvasEventuallyRedraw +Tk_CanvasGetCoord +Tk_CanvasGetTextInfo +Tk_CanvasPsBitmap +Tk_CanvasPsColor +Tk_CanvasPsFont +Tk_CanvasPsPath +Tk_CanvasPsStipple +Tk_CanvasPsY +Tk_CanvasSetStippleOrigin +Tk_CanvasTagsParseProc +Tk_CanvasTagsPrintProc +Tk_CanvasTkwin +Tk_CanvasWindowCoords +Tk_ChangeWindowAttributes +Tk_CharBbox +Tk_CheckbuttonCmd +Tk_ChooseColorCmd +Tk_ClearSelection +Tk_ClipboardAppend +Tk_ClipboardClear +Tk_ClipboardCmd +Tk_ComputeTextLayout +Tk_ConfigureInfo +Tk_ConfigureValue +Tk_ConfigureWidget +Tk_ConfigureWindow +Tk_CoordsToWindow +Tk_CreateBinding +Tk_CreateBindingTable +Tk_CreateErrorHandler +Tk_CreateEventHandler +Tk_CreateGenericHandler +Tk_CreateImageType +Tk_CreateItemType +Tk_CreatePhotoImageFormat +Tk_CreateSelHandler +Tk_CreateWindow +Tk_CreateWindowFromPath +Tk_DefineBitmap +Tk_DefineCursor +Tk_DeleteAllBindings +Tk_DeleteBinding +Tk_DeleteBindingTable +Tk_DeleteErrorHandler +Tk_DeleteEventHandler +Tk_DeleteGenericHandler +Tk_DeleteImage +Tk_DeleteSelHandler +Tk_DestroyCmd +Tk_DestroyWindow +Tk_DisplayName +Tk_DistanceToTextLayout +Tk_Draw3DPolygon +Tk_Draw3DRectangle +Tk_DrawChars +Tk_DrawFocusHighlight +Tk_DrawTextLayout +Tk_EntryCmd +Tk_EventCmd +Tk_Fill3DPolygon +Tk_Fill3DRectangle +Tk_FindPhoto +Tk_FocusCmd +Tk_FontId +Tk_FontObjCmd +Tk_FrameCmd +Tk_Free3DBorder +Tk_FreeBitmap +Tk_FreeColor +Tk_FreeColormap +Tk_FreeCursor +Tk_FreeFont +Tk_FreeGC +Tk_FreeImage +Tk_FreeOptions +Tk_FreePixmap +Tk_FreeTextLayout +Tk_GCForColor +Tk_GeometryRequest +Tk_Get3DBorder +Tk_GetAllBindings +Tk_GetAnchor +Tk_GetAtomName +Tk_GetBinding +Tk_GetBitmap +Tk_GetBitmapFromData +Tk_GetCapStyle +Tk_GetColor +Tk_GetColorByValue +Tk_GetColormap +Tk_GetCursor +Tk_GetCursorFromData +Tk_GetFont +Tk_GetFontFromObj +Tk_GetFontMetrics +Tk_GetGC +Tk_GetImage +Tk_GetItemTypes +Tk_GetJoinStyle +Tk_GetJustify +Tk_GetNumMainWindows +Tk_GetOpenFileCmd +Tk_GetOption +Tk_GetPixels +Tk_GetPixmap +Tk_GetRelief +Tk_GetRootCoords +Tk_GetSaveFileCmd +Tk_GetScreenMM +Tk_GetScrollInfo +Tk_GetSelection +Tk_GetUid +Tk_GetVRootGeometry +Tk_GetVisual +Tk_Grab +Tk_GrabCmd +Tk_GridCmd +Tk_HandleEvent +Tk_IdToWindow +Tk_ImageChanged +Tk_ImageCmd +Tk_Init +Tk_InternAtom +Tk_IntersectTextLayout +Tk_LabelCmd +Tk_ListboxCmd +Tk_LowerCmd +Tk_Main +Tk_MainLoop +Tk_MainWindow +Tk_MaintainGeometry +Tk_MakeWindowExist +Tk_ManageGeometry +Tk_MapWindow +Tk_MeasureChars +Tk_MenuCmd +Tk_MenubuttonCmd +Tk_MessageBoxCmd +Tk_MessageCmd +Tk_MoveResizeWindow +Tk_MoveToplevelWindow +Tk_MoveWindow +Tk_NameOf3DBorder +Tk_NameOfAnchor +Tk_NameOfBitmap +Tk_NameOfCapStyle +Tk_NameOfColor +Tk_NameOfCursor +Tk_NameOfFont +Tk_NameOfImage +Tk_NameOfJoinStyle +Tk_NameOfJustify +Tk_NameOfRelief +Tk_NameToWindow +Tk_OptionCmd +Tk_OwnSelection +Tk_PackCmd +Tk_ParseArgv +Tk_PhotoBlank +Tk_PhotoExpand +Tk_PhotoGetImage +Tk_PhotoGetSize +Tk_PhotoPutBlock +Tk_PhotoPutZoomedBlock +Tk_PhotoSetSize +Tk_PlaceCmd +Tk_PointToChar +Tk_PostscriptFontName +Tk_PreserveColormap +Tk_QueueWindowEvent +Tk_RadiobuttonCmd +Tk_RaiseCmd +Tk_RedrawImage +Tk_ResizeWindow +Tk_RestackWindow +Tk_RestrictEvents +Tk_SafeInit +Tk_ScaleCmd +Tk_ScrollbarCmd +Tk_SelectionCmd +Tk_SendCmd +Tk_SetAppName +Tk_SetBackgroundFromBorder +Tk_SetClass +Tk_SetGrid +Tk_SetInternalBorder +Tk_SetWindowBackground +Tk_SetWindowBackgroundPixmap +Tk_SetWindowBorder +Tk_SetWindowBorderPixmap +Tk_SetWindowBorderWidth +Tk_SetWindowColormap +Tk_SetWindowVisual +Tk_SizeOfBitmap +Tk_SizeOfImage +Tk_StrictMotif +Tk_TextCmd +Tk_TextLayoutToPostscript +Tk_TextWidth +Tk_TkObjCmd +Tk_TkwaitCmd +Tk_TopCoordsToWindow +Tk_ToplevelCmd +Tk_UndefineCursor +Tk_UnderlineChars +Tk_UnderlineTextLayout +Tk_Ungrab +Tk_UnmaintainGeometry +Tk_UnmapWindow +Tk_UnsetGrid +Tk_UpdateCmd +Tk_UpdatePointer +Tk_WinfoObjCmd +Tk_WmCmd +TkpChangeFocus +TkpClaimFocus +TkpCloseDisplay +TkpComputeButtonGeometry +TkpComputeMenuButtonGeometry +TkpComputeMenubarGeometry +TkpComputeScrollbarGeometry +TkpComputeStandardMenuGeometry +TkpConfigureMenuEntry +TkpConfigureScrollbar +TkpCreateButton +TkpCreateMenuButton +TkpCreateNativeBitmap +TkpCreateScale +TkpCreateScrollbar +TkpDefineNativeBitmaps +TkpDeleteFont +TkpDestroyButton +TkpDestroyMenu +TkpDestroyMenuButton +TkpDestroyMenuEntry +TkpDestroyScale +TkpDestroyScrollbar +TkpDisplayButton +TkpDisplayMenuButton +TkpDisplayScale +TkpDisplayScrollbar +TkpDisplayWarning +TkpDrawMenuEntry +TkpFindWindow +TkpFreeBorder +TkpGetAppName +TkpGetBorder +TkpGetColor +TkpGetColorByValue +TkpGetFontFamilies +TkpGetFontFromAttributes +TkpGetMS +TkpGetNativeAppBitmap +TkpGetNativeFont +TkpGetOtherWindow +TkpGetShadows +TkpInit +TkpInitializeMenuBindings +TkpMakeContainer +TkpMakeWindow +TkpMenuInit +TkpMenuNewEntry +TkpNewMenu +TkpOpenDisplay +TkpPixelToValue +TkpPostMenu +TkpRedirectKeyEvent +TkpScaleElement +TkpScrollbarPosition +TkpSetCapture +TkpSetCursor +TkpSetMainMenubar +TkpSetScaleValue +TkpSetWindowMenuBar +TkpTestembedCmd +TkpUseWindow +TkpValueToPixel +TkpWindowWasRecentlyDeleted +XAllocColor +XAllocSizeHints +XBell +XChangeGC +XChangeProperty +XChangeWindowAttributes +XConfigureWindow +XCopyArea +XCopyPlane +XCreateBitmapFromData +XCreateColormap +XCreateGC +XCreateImage +XDefineCursor +XDestroyWindow +XDrawArc +XDrawLine +XDrawLines +XDrawRectangle +XFillArc +XFillPolygon +XFillRectangle +XFillRectangles +XForceScreenSaver +XFreeColormap +XFreeColors +XFreeGC +XFreeModifiermap +XGContextFromGC +XGetAtomName +XGetGeometry +XGetImage +XGetModifierMapping +XGetVisualInfo +XGetWindowProperty +XGrabKeyboard +XGrabPointer +XInternAtom +XKeycodeToKeysym +XKeysymToKeycode +XKeysymToString +XLookupString +XMapWindow +XMoveResizeWindow +XMoveWindow +XParseColor +XQueryPointer +XRaiseWindow +XReadBitmapFile +XRefreshKeyboardMapping +XResizeWindow +XRootWindow +XSelectInput +XSendEvent +XSetArcMode +XSetBackground +XSetClipMask +XSetClipOrigin +XSetErrorHandler +XSetFillRule +XSetFillStyle +XSetFont +XSetForeground +XSetFunction +XSetIconName +XSetInputFocus +XSetLineAttributes +XSetSelectionOwner +XSetStipple +XSetTSOrigin +XSetWMNormalHints +XSetWindowBackground +XSetWindowBackgroundPixmap +XSetWindowBorder +XSetWindowBorderPixmap +XSetWindowBorderWidth +XSetWindowColormap +XStringToKeysym +XUngrabKeyboard +XUngrabPointer +XUnmapWindow +_Aldata +_Assert +_Atcount +_Atfuns +_Clocale +_Closreg +_Costate +_Daysto +_Dbl +_Defloc +_Environ +_Environ1 +_Fgpos +_Files +_Flt +_Fopen +_Foprep +_Fread +_Freeloc +_Frprep +_Fspos +_Fwprep +_Fwrite +_Genld +_Gentime +_Getdst +_Getfld +_Getfloat +_Getint +_Getloc +_Getmem +_Getstr +_Gettime +_Getzone +_Isdst +_Ldbl +_Ldtob +_Litob +_Locale +_Locsum +_Loctab +_Locterm +_Locvar +_MWERKS_Atcount +_MWERKS_Atfuns +_Makeloc +_Makestab +_Makewct +_Mbcurmax +_Mbstate +_Mbtowc +_Nnl +_PJP_C_Copyright +_Printf +_Putfld +_Putstr +_Puttxt +_Randseed +_Readloc +_Scanf +_Setloc +_Skip +_Stdin +_Stdout +_Stod +_Stof +_Stoflt +_Stold +_Strerror +_Strftime +_Strxfrm +_Times +_Tolower +_Toupper +_Ttotm +_WCostate +_Wcstate +_Wctob +_Wctomb +_Wctrans +_Wctype +_XInitImageFuncPtrs +__CheckForSystem7 +__RemoveConsoleHandler__ +__aborting +__ctopstring +__getcreator +__gettype +__myraise +__system7present +_atexit +_exit +_fcreator +_ftype +pendingPtr +tclFocusDebug +tcl_macQdPtr +tkActiveUid +tkAppleMenu +tkArcType +tkBTreeDebug +tkBitmapImageType +tkBitmapType +tkDisabledUid +tkDisplayList +tkEditMenu +tkFileMenu +tkImageType +tkImgFmtGIF +tkImgFmtPPM +tkLineType +tkMacAppInFront +tkMacFocusWin +tkMainWindowList +tkMenuConfigSpecs +tkMenuEntryConfigSpecs +tkNormalUid +tkOvalType +tkPhotoImageType +tkPolygonType +tkPredefBitmapTable +tkRectangleType +tkSendSerial +tkTextCharType +tkTextCharUid +tkTextDebug +tkTextDisabledUid +tkTextLeftMarkType +tkTextNoneUid +tkTextNormalUid +tkTextRightMarkType +tkTextToggleOffType +tkTextToggleOnType +tkTextType +tkTextWordUid +tkWindowType +tkpButtonConfigSpecs +tkpButtonProcs +tkpMenubuttonClass +tkpScrollbarConfigSpecs +tkpScrollbarProcs +#TclMacInitializeFragment +#TclMacTerminateFragment +#__initialize +#__ptmf_null +#__terminate diff --git a/mac/tkMacSubwindows.c b/mac/tkMacSubwindows.c new file mode 100644 index 0000000..65c1a7e --- /dev/null +++ b/mac/tkMacSubwindows.c @@ -0,0 +1,1227 @@ +/* + * tkMacSubwindows.c -- + * + * Implements subwindows for the macintosh version of Tk. + * + * Copyright (c) 1995-1997 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) tkMacSubwindows.c 1.81 97/10/29 11:46:54 + */ + +#include "tkInt.h" +#include "X.h" +#include "Xlib.h" +#include <stdio.h> + +#include <Windows.h> +#include <QDOffscreen.h> +#include "tkMacInt.h" + +/* + * Temporary region that can be reused. + */ +static RgnHandle tmpRgn = NULL; + +static void UpdateOffsets _ANSI_ARGS_((TkWindow *winPtr, int deltaX, int deltaY)); + +void MacMoveWindow _ANSI_ARGS_((WindowRef window, int x, int y)); + +/* + *---------------------------------------------------------------------- + * + * XDestroyWindow -- + * + * Dealocates the given X Window. + * + * Results: + * The window id is returned. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +XDestroyWindow( + Display* display, /* Display. */ + Window window) /* Window. */ +{ + MacDrawable *macWin = (MacDrawable *) window; + GWorldPtr destPort; + + /* + * Remove any dangling pointers that may exist if + * the window we are deleting is being tracked by + * the grab code. + */ + + TkPointerDeadWindow(macWin->winPtr); + macWin->toplevel->referenceCount--; + + + if (Tk_IsTopLevel(macWin->winPtr)) { + DisposeRgn(macWin->clipRgn); + DisposeRgn(macWin->aboveClipRgn); + + /* + * Delete the Mac window and remove it from the windowTable. + * The window could be NULL if the window was never mapped. + * However, we don't do this for embedded windows, they don't + * go in the window list, and they do not own their portPtr's. + */ + + if (!(Tk_IsEmbedded(macWin->winPtr))) { + destPort = TkMacGetDrawablePort(window); + if (destPort != NULL) { + TkMacWindowList *listPtr, *prevPtr; + + TkMacUnregisterMacWindow(destPort); + DisposeWindow((WindowRef) destPort); + + for (listPtr = tkMacWindowListPtr, prevPtr = NULL; + tkMacWindowListPtr != NULL; + prevPtr = listPtr, listPtr = listPtr->nextPtr) { + if (listPtr->winPtr == macWin->winPtr) { + if (prevPtr == NULL) { + tkMacWindowListPtr = listPtr->nextPtr; + } else { + prevPtr->nextPtr = listPtr->nextPtr; + } + ckfree((char *) listPtr); + break; + } + } + } + } + + macWin->portPtr = NULL; + + /* + * Delay deletion of a toplevel data structure untill all + * children have been deleted. + */ + if (macWin->toplevel->referenceCount == 0) { + ckfree((char *) macWin->toplevel); + } + } else { + destPort = TkMacGetDrawablePort(window); + if (destPort != NULL) { + SetGWorld(destPort, NULL); + TkMacInvalidateWindow(macWin, TK_PARENT_WINDOW); + } + if (macWin->winPtr->parentPtr != NULL) { + TkMacInvalClipRgns(macWin->winPtr->parentPtr); + } + DisposeRgn(macWin->clipRgn); + DisposeRgn(macWin->aboveClipRgn); + + if (macWin->toplevel->referenceCount == 0) { + ckfree((char *) macWin->toplevel); + } + ckfree((char *) macWin); + } +} + +/* + *---------------------------------------------------------------------- + * + * XMapWindow -- + * + * Map the given X Window to the screen. See X window documentation + * for more details. + * + * Results: + * None. + * + * Side effects: + * The subwindow or toplevel may appear on the screen. + * + *---------------------------------------------------------------------- + */ + +void +XMapWindow( + Display* display, /* Display. */ + Window window) /* Window. */ +{ + MacDrawable *macWin = (MacDrawable *) window; + XEvent event; + GWorldPtr destPort; + + /* + * Under certain situations it's possible for this function to be + * called before the toplevel window it's associated with has actually + * been mapped. In that case we need to create the real Macintosh + * window now as this function as well as other X functions assume that + * the portPtr is valid. + */ + if (!TkMacHostToplevelExists(macWin->toplevel->winPtr)) { + TkMacMakeRealWindowExist(macWin->toplevel->winPtr); + } + destPort = TkMacGetDrawablePort(window); + + display->request++; + macWin->winPtr->flags |= TK_MAPPED; + if (Tk_IsTopLevel(macWin->winPtr)) { + if (!Tk_IsEmbedded(macWin->winPtr)) { + ShowWindow((WindowRef) destPort); + } + + /* + * We only need to send the MapNotify event + * for toplevel windows. + */ + event.xany.serial = display->request; + event.xany.send_event = False; + event.xany.display = display; + + event.xmap.window = window; + event.xmap.type = MapNotify; + event.xmap.event = window; + event.xmap.override_redirect = macWin->winPtr->atts.override_redirect; + Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); + } else { + TkMacInvalClipRgns(macWin->winPtr->parentPtr); + } + + /* + * Generate damage for that area of the window + */ + SetGWorld(destPort, NULL); + TkMacUpdateClipRgn(macWin->winPtr); + TkMacInvalidateWindow(macWin, TK_PARENT_WINDOW); +} + +/* + *---------------------------------------------------------------------- + * + * XUnmapWindow -- + * + * Unmap the given X Window to the screen. See X window + * documentation for more details. + * + * Results: + * None. + * + * Side effects: + * The subwindow or toplevel may be removed from the screen. + * + *---------------------------------------------------------------------- + */ + +void +XUnmapWindow( + Display* display, /* Display. */ + Window window) /* Window. */ +{ + MacDrawable *macWin = (MacDrawable *) window; + XEvent event; + GWorldPtr destPort; + + destPort = TkMacGetDrawablePort(window); + + display->request++; + macWin->winPtr->flags &= ~TK_MAPPED; + if (Tk_IsTopLevel(macWin->winPtr)) { + if (!Tk_IsEmbedded(macWin->winPtr)) { + HideWindow((WindowRef) destPort); + } + + /* + * We only need to send the UnmapNotify event + * for toplevel windows. + */ + event.xany.serial = display->request; + event.xany.send_event = False; + event.xany.display = display; + + event.xunmap.type = UnmapNotify; + event.xunmap.window = window; + event.xunmap.event = window; + event.xunmap.from_configure = false; + Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); + } else { + /* + * Generate damage for that area of the window. + */ + SetGWorld(destPort, NULL); + TkMacInvalidateWindow(macWin, TK_PARENT_WINDOW); /* TODO: may not be valid */ + TkMacInvalClipRgns(macWin->winPtr->parentPtr); + } +} + +/* + *---------------------------------------------------------------------- + * + * XResizeWindow -- + * + * Resize a given X window. See X windows documentation for + * further details. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +XResizeWindow( + Display* display, /* Display. */ + Window window, /* Window. */ + unsigned int width, + unsigned int height) +{ + MacDrawable *macWin = (MacDrawable *) window; + GWorldPtr destPort; + + destPort = TkMacGetDrawablePort(window); + if (destPort == NULL) { + return; + } + + display->request++; + SetPort((GrafPtr) destPort); + if (Tk_IsTopLevel(macWin->winPtr) && !Tk_IsEmbedded(macWin->winPtr)) { + /* + * NOTE: we are not adding the new space to the update + * region. It is currently assumed that Tk will need + * to completely redraw anway. + */ + SizeWindow((WindowRef) destPort, + (short) width, (short) height, false); + TkMacInvalidateWindow(macWin, TK_WINDOW_ONLY); + TkMacInvalClipRgns(macWin->winPtr); + } else { + /* TODO: update all xOff & yOffs */ + int deltaX, deltaY, parentBorderwidth; + MacDrawable *macParent = macWin->winPtr->parentPtr->privatePtr; + + /* + * Find the Parent window - + * For an embedded window this will be its container. + */ + + if (Tk_IsEmbedded(macWin->winPtr)) { + TkWindow *contWinPtr; + + contWinPtr = TkpGetOtherWindow(macWin->winPtr); + if (contWinPtr == NULL) { + panic("XMoveResizeWindow could not find container"); + } + macParent = contWinPtr->privatePtr; + + /* + * NOTE: Here we should handle out of process embedding. + */ + + } else { + macParent = macWin->winPtr->parentPtr->privatePtr; + if (macParent == NULL) { + return; /* TODO: Probably should be a panic */ + } + } + + TkMacInvalClipRgns(macParent->winPtr); + TkMacInvalidateWindow(macWin, TK_PARENT_WINDOW); + + deltaX = - macWin->xOff; + deltaY = - macWin->yOff; + + /* + * If macWin->winPtr is an embedded window, don't offset by its + * parent's borderwidth... + */ + + if (!Tk_IsEmbedded(macWin->winPtr)) { + parentBorderwidth = macWin->winPtr->parentPtr->changes.border_width; + } else { + parentBorderwidth = 0; + } + deltaX += macParent->xOff + parentBorderwidth + + macWin->winPtr->changes.x; + deltaY += macParent->yOff + parentBorderwidth + + macWin->winPtr->changes.y; + + UpdateOffsets(macWin->winPtr, deltaX, deltaY); + } +} + +/* + *---------------------------------------------------------------------- + * + * XMoveResizeWindow -- + * + * Move or resize a given X window. See X windows documentation + * for further details. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +XMoveResizeWindow( + Display* display, /* Display. */ + Window window, /* Window. */ + int x, int y, + unsigned int width, + unsigned int height) +{ + MacDrawable *macWin = (MacDrawable *) window; + GWorldPtr destPort; + + destPort = TkMacGetDrawablePort(window); + if (destPort == NULL) { + return; + } + + SetPort((GrafPtr) destPort); + if (Tk_IsTopLevel(macWin->winPtr) && !Tk_IsEmbedded(macWin->winPtr)) { + /* + * NOTE: we are not adding the new space to the update + * region. It is currently assumed that Tk will need + * to completely redraw anway. + */ + + SizeWindow((WindowRef) destPort, + (short) width, (short) height, false); + MacMoveWindow((WindowRef) destPort, x, y); + + /* TODO: is the following right? */ + TkMacInvalidateWindow(macWin, TK_WINDOW_ONLY); + TkMacInvalClipRgns(macWin->winPtr); + } else { + int deltaX, deltaY, parentBorderwidth; + Rect bounds; + MacDrawable *macParent; + + /* + * Find the Parent window - + * For an embedded window this will be its container. + */ + + if (Tk_IsEmbedded(macWin->winPtr)) { + TkWindow *contWinPtr; + + contWinPtr = TkpGetOtherWindow(macWin->winPtr); + if (contWinPtr == NULL) { + panic("XMoveResizeWindow could not find container"); + } + macParent = contWinPtr->privatePtr; + + /* + * NOTE: Here we should handle out of process embedding. + */ + + + } else { + macParent = macWin->winPtr->parentPtr->privatePtr; + if (macParent == NULL) { + return; /* TODO: Probably should be a panic */ + } + } + + TkMacInvalClipRgns(macParent->winPtr); + TkMacInvalidateWindow(macWin, TK_PARENT_WINDOW); + + deltaX = - macWin->xOff; + deltaY = - macWin->yOff; + + /* + * If macWin->winPtr is an embedded window, don't offset by its + * parent's borderwidth... + */ + + if (!Tk_IsEmbedded(macWin->winPtr)) { + parentBorderwidth = macWin->winPtr->parentPtr->changes.border_width; + } else { + parentBorderwidth = 0; + } + deltaX += macParent->xOff + parentBorderwidth + + macWin->winPtr->changes.x; + deltaY += macParent->yOff + parentBorderwidth + + macWin->winPtr->changes.y; + + UpdateOffsets(macWin->winPtr, deltaX, deltaY); + TkMacWinBounds(macWin->winPtr, &bounds); + InvalRect(&bounds); + } +} + +/* + *---------------------------------------------------------------------- + * + * XMoveWindow -- + * + * Move a given X window. See X windows documentation for further + * details. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +XMoveWindow( + Display* display, /* Display. */ + Window window, /* Window. */ + int x, + int y) +{ + MacDrawable *macWin = (MacDrawable *) window; + GWorldPtr destPort; + + destPort = TkMacGetDrawablePort(window); + if (destPort == NULL) { + return; + } + + SetPort((GrafPtr) destPort); + if (Tk_IsTopLevel(macWin->winPtr) && !Tk_IsEmbedded(macWin->winPtr)) { + /* + * NOTE: we are not adding the new space to the update + * region. It is currently assumed that Tk will need + * to completely redraw anway. + */ + MacMoveWindow((WindowRef) destPort, x, y); + + /* TODO: is the following right? */ + TkMacInvalidateWindow(macWin, TK_WINDOW_ONLY); + TkMacInvalClipRgns(macWin->winPtr); + } else { + int deltaX, deltaY, parentBorderwidth; + Rect bounds; + MacDrawable *macParent; + + /* + * Find the Parent window - + * For an embedded window this will be its container. + */ + + if (Tk_IsEmbedded(macWin->winPtr)) { + TkWindow *contWinPtr; + + contWinPtr = TkpGetOtherWindow(macWin->winPtr); + if (contWinPtr == NULL) { + panic("XMoveWindow could not find container"); + } + macParent = contWinPtr->privatePtr; + + /* + * NOTE: Here we should handle out of process embedding. + */ + + } else { + macParent = macWin->winPtr->parentPtr->privatePtr; + if (macParent == NULL) { + return; /* TODO: Probably should be a panic */ + } + } + + TkMacInvalClipRgns(macParent->winPtr); + TkMacInvalidateWindow(macWin, TK_PARENT_WINDOW); + + deltaX = - macWin->xOff; + deltaY = - macWin->yOff; + + /* + * If macWin->winPtr is an embedded window, don't offset by its + * parent's borderwidth... + */ + + if (!Tk_IsEmbedded(macWin->winPtr)) { + parentBorderwidth = macWin->winPtr->parentPtr->changes.border_width; + } else { + parentBorderwidth = 0; + } + deltaX += macParent->xOff + parentBorderwidth + + macWin->winPtr->changes.x; + deltaY += macParent->yOff + parentBorderwidth + + macWin->winPtr->changes.y; + + UpdateOffsets(macWin->winPtr, deltaX, deltaY); + TkMacWinBounds(macWin->winPtr, &bounds); + InvalRect(&bounds); + } +} + +/* + *---------------------------------------------------------------------- + * + * XRaiseWindow -- + * + * Change the stacking order of a window. + * + * Results: + * None. + * + * Side effects: + * Changes the stacking order of the specified window. + * + *---------------------------------------------------------------------- + */ + +void +XRaiseWindow( + Display* display, /* Display. */ + Window window) /* Window. */ +{ + MacDrawable *macWin = (MacDrawable *) window; + + display->request++; + if (Tk_IsTopLevel(macWin->winPtr) && !Tk_IsEmbedded(macWin->winPtr)) { + TkWmRestackToplevel(macWin->winPtr, Above, NULL); + } else { + /* TODO: this should generate damage */ + } +} + +/* + *---------------------------------------------------------------------- + * + * XConfigureWindow -- + * + * Change the size, position, stacking, or border of the specified + * window. + * + * Results: + * None. + * + * Side effects: + * Changes the attributes of the specified window. Note that we + * ignore the passed in values and use the values stored in the + * TkWindow data structure. + * + *---------------------------------------------------------------------- + */ + +void +XConfigureWindow( + Display* display, /* Display. */ + Window w, /* Window. */ + unsigned int value_mask, + XWindowChanges* values) +{ + MacDrawable *macWin = (MacDrawable *) w; + TkWindow *winPtr = macWin->winPtr; + + display->request++; + + /* + * Change the shape and/or position of the window. + */ + + if (value_mask & (CWX|CWY|CWWidth|CWHeight)) { + XMoveResizeWindow(display, w, winPtr->changes.x, winPtr->changes.y, + winPtr->changes.width, winPtr->changes.height); + } + + /* + * Change the stacking order of the window. Tk actuall keeps all + * the information we need for stacking order. All we need to do + * is make sure the clipping regions get updated and generate damage + * that will ensure things get drawn correctly. + */ + + if (value_mask & CWStackMode) { + Rect bounds; + GWorldPtr destPort; + + destPort = TkMacGetDrawablePort(w); + if (destPort != NULL) { + SetPort((GrafPtr) destPort); + TkMacInvalClipRgns(winPtr->parentPtr); + TkMacWinBounds(winPtr, &bounds); + InvalRect(&bounds); + } + } + + /* TkGenWMMoveRequestEvent(macWin->winPtr, + macWin->winPtr->changes.x, macWin->winPtr->changes.y); */ +} + +/* + *---------------------------------------------------------------------- + * + * TkMacUpdateClipRgn -- + * + * This function updates the cliping regions for a given window + * and all of its children. Once updated the TK_CLIP_INVALID flag + * in the subwindow data structure is unset. The TK_CLIP_INVALID + * flag should always be unset before any drawing is attempted. + * + * Results: + * None. + * + * Side effects: + * The clip regions for the window and its children are updated. + * + *---------------------------------------------------------------------- + */ + +void +TkMacUpdateClipRgn( + TkWindow *winPtr) +{ + RgnHandle rgn; + int x, y; + TkWindow *win2Ptr; + + if (winPtr == NULL) { + return; + } + + if (winPtr->privatePtr->flags & TK_CLIP_INVALID) { + rgn = winPtr->privatePtr->aboveClipRgn; + if (tmpRgn == NULL) { + tmpRgn = NewRgn(); + } + + /* + * Start with a region defined by the window bounds. + */ + + x = winPtr->privatePtr->xOff; + y = winPtr->privatePtr->yOff; + SetRectRgn(rgn, (short) x, (short) y, + (short) (winPtr->changes.width + x), + (short) (winPtr->changes.height + y)); + + /* + * Clip away the area of any windows that may obscure this + * window. + * For a non-toplevel window, first, clip to the parents visable + * clip region. + * Second, clip away any siblings that are higher in the + * stacking order. + * For an embedded toplevel, just clip to the container's visible + * clip region. Remember, we only allow one contained window + * in a frame, and don't support any other widgets in the frame either. + * This is not currently enforced, however. + */ + + if (!Tk_IsTopLevel(winPtr)) { + TkMacUpdateClipRgn(winPtr->parentPtr); + SectRgn(rgn, + winPtr->parentPtr->privatePtr->aboveClipRgn, rgn); + + win2Ptr = winPtr->nextPtr; + while (win2Ptr != NULL) { + if (Tk_IsTopLevel(win2Ptr) || !Tk_IsMapped(win2Ptr)) { + win2Ptr = win2Ptr->nextPtr; + continue; + } + x = win2Ptr->privatePtr->xOff; + y = win2Ptr->privatePtr->yOff; + SetRectRgn(tmpRgn, (short) x, (short) y, + (short) (win2Ptr->changes.width + x), + (short) (win2Ptr->changes.height + y)); + DiffRgn(rgn, tmpRgn, rgn); + + win2Ptr = win2Ptr->nextPtr; + } + } else if (Tk_IsEmbedded(winPtr)) { + TkWindow *contWinPtr; + + contWinPtr = TkpGetOtherWindow(winPtr); + + if (contWinPtr != NULL) { + TkMacUpdateClipRgn(contWinPtr); + SectRgn(rgn, + contWinPtr->privatePtr->aboveClipRgn, rgn); + } + + /* + * NOTE: Here we should handle out of process embedding. + */ + + } + + /* + * The final clip region is the aboveClip region (or visable + * region) minus all the children of this window. + * Alternatively, if the window is a container, we must also + * subtract the region of the embedded window. + */ + + rgn = winPtr->privatePtr->clipRgn; + CopyRgn(winPtr->privatePtr->aboveClipRgn, rgn); + + win2Ptr = winPtr->childList; + while (win2Ptr != NULL) { + if (Tk_IsTopLevel(win2Ptr) || !Tk_IsMapped(win2Ptr)) { + win2Ptr = win2Ptr->nextPtr; + continue; + } + x = win2Ptr->privatePtr->xOff; + y = win2Ptr->privatePtr->yOff; + SetRectRgn(tmpRgn, (short) x, (short) y, + (short) (win2Ptr->changes.width + x), + (short) (win2Ptr->changes.height + y)); + DiffRgn(rgn, tmpRgn, rgn); + + win2Ptr = win2Ptr->nextPtr; + } + + if (Tk_IsContainer(winPtr)) { + win2Ptr = TkpGetOtherWindow(winPtr); + if (win2Ptr != NULL) { + if (Tk_IsMapped(win2Ptr)) { + x = win2Ptr->privatePtr->xOff; + y = win2Ptr->privatePtr->yOff; + SetRectRgn(tmpRgn, (short) x, (short) y, + (short) (win2Ptr->changes.width + x), + (short) (win2Ptr->changes.height + y)); + DiffRgn(rgn, tmpRgn, rgn); + } + } + + /* + * NOTE: Here we should handle out of process embedding. + */ + + } + + winPtr->privatePtr->flags &= ~TK_CLIP_INVALID; + } +} + +/* + *---------------------------------------------------------------------- + * + * TkMacVisableClipRgn -- + * + * This function returnd the Macintosh cliping region for the + * given window. A NULL Rgn means the window is not visable. + * + * Results: + * The region. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +RgnHandle +TkMacVisableClipRgn( + TkWindow *winPtr) +{ + if (winPtr->privatePtr->flags & TK_CLIP_INVALID) { + TkMacUpdateClipRgn(winPtr); + } + + return winPtr->privatePtr->clipRgn; +} + +/* + *---------------------------------------------------------------------- + * + * TkMacInvalidateWindow -- + * + * This function makes the window as invalid will generate damage + * for the window. + * + * Results: + * None. + * + * Side effects: + * Damage is created. + * + *---------------------------------------------------------------------- + */ + +void +TkMacInvalidateWindow( + MacDrawable *macWin, /* Make window that's causing damage. */ + int flag) /* Should be TK_WINDOW_ONLY or + * TK_PARENT_WINDOW */ +{ + + if (flag == TK_WINDOW_ONLY) { + InvalRgn(macWin->clipRgn); + } else { + if (!EmptyRgn(macWin->aboveClipRgn)) { + InvalRgn(macWin->aboveClipRgn); + } + } +} + +/* + *---------------------------------------------------------------------- + * + * TkMacGetDrawablePort -- + * + * This function returns the Graphics Port for a given X drawable. + * + * Results: + * A GWorld pointer. Either an off screen pixmap or a Window. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +GWorldPtr +TkMacGetDrawablePort( + Drawable drawable) +{ + MacDrawable *macWin = (MacDrawable *) drawable; + + if (macWin == NULL) { + return NULL; + } + + /* + * This is NULL for off-screen pixmaps. Then the portPtr + * always points to the off-screen port, and we don't + * have to worry about containment + */ + + if (macWin->clipRgn == NULL) { + return macWin->portPtr; + } + + /* + * If the Drawable is in an embedded window, use the Port of its container. + * + * TRICKY POINT: we can have cases when a toplevel is being destroyed + * where the winPtr for the toplevel has been freed, but the children + * are not all the way destroyed. The children will call this function + * as they are being destroyed, but Tk_IsEmbedded will return garbage. + * So we check the copy of the TK_EMBEDDED flag we put into the + * toplevel's macWin flags. + */ + + if (!(macWin->toplevel->flags & TK_EMBEDDED)) { + return macWin->toplevel->portPtr; + } else { + TkWindow *contWinPtr; + + contWinPtr = TkpGetOtherWindow(macWin->toplevel->winPtr); + + if (contWinPtr != NULL) { + return TkMacGetDrawablePort((Drawable) contWinPtr->privatePtr); + } else { + panic("TkMacGetDrawablePort couldn't find container"); + return NULL; + } + + /* + * NOTE: Here we should handle out of process embedding. + */ + + } + +} + +/* + *---------------------------------------------------------------------- + * + * TkMacInvalClipRgns -- + * + * This function invalidates the clipping regions for a given + * window and all of its children. This function should be + * called whenever changes are made to subwindows that would + * effect the size or position of windows. + * + * Results: + * None. + * + * Side effects: + * The cliping regions for the window and its children are + * mark invalid. (Make sure they are valid before drawing.) + * + *---------------------------------------------------------------------- + */ + +void +TkMacInvalClipRgns( + TkWindow *winPtr) +{ + TkWindow *childPtr; + + /* + * If already marked we can stop because all + * decendants will also already be marked. + */ + if (winPtr->privatePtr->flags & TK_CLIP_INVALID) { + return; + } + + winPtr->privatePtr->flags |= TK_CLIP_INVALID; + + /* + * Invalidate clip regions for all children & + * their decendants - unless the child is a toplevel. + */ + childPtr = winPtr->childList; + while (childPtr != NULL) { + if (!Tk_IsTopLevel(childPtr) && Tk_IsMapped(childPtr)) { + TkMacInvalClipRgns(childPtr); + } + childPtr = childPtr->nextPtr; + } + + /* + * Also, if the window is a container, mark its embedded window + */ + + if (Tk_IsContainer(winPtr)) { + childPtr = TkpGetOtherWindow(winPtr); + + if (childPtr != NULL && Tk_IsMapped(childPtr)) { + TkMacInvalClipRgns(childPtr); + } + + /* + * NOTE: Here we should handle out of process embedding. + */ + + } +} + +/* + *---------------------------------------------------------------------- + * + * TkMacWinBounds -- + * + * Given a Tk window this function determines the windows + * bounds in relation to the Macintosh window's coordinate + * system. This is also the same coordinate system as the + * Tk toplevel window in which this window is contained. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +TkMacWinBounds( + TkWindow *winPtr, + Rect *bounds) +{ + bounds->left = (short) winPtr->privatePtr->xOff; + bounds->top = (short) winPtr->privatePtr->yOff; + bounds->right = (short) (winPtr->privatePtr->xOff + + winPtr->changes.width); + bounds->bottom = (short) (winPtr->privatePtr->yOff + + winPtr->changes.height); +} + +/* + *---------------------------------------------------------------------- + * + * MacMoveWindow -- + * + * A replacement for the Macintosh MoveWindow function. This + * function adjusts the inputs to MoveWindow to offset the root of + * the window system. This has the effect of making the coords + * refer to the window dressing rather than the top of the content. + * + * Results: + * None. + * + * Side effects: + * Moves the Macintosh window. + * + *---------------------------------------------------------------------- + */ + +void +MacMoveWindow( + WindowRef window, + int x, + int y) +{ + int xOffset, yOffset; + + TkMacWindowOffset(window, &xOffset, &yOffset); + MoveWindow((WindowRef) window, + (short) (x + xOffset), (short) (y + yOffset), false); +} + +/* + *---------------------------------------------------------------------- + * + * UpdateOffsets -- + * + * Updates the X & Y offsets of the given TkWindow from the + * TopLevel it is a decendant of. + * + * Results: + * None. + * + * Side effects: + * The xOff & yOff fields for the Mac window datastructure + * is updated to the proper offset. + * + *---------------------------------------------------------------------- + */ + +static void +UpdateOffsets( + TkWindow *winPtr, + int deltaX, + int deltaY) +{ + TkWindow *childPtr; + + if (winPtr->privatePtr == NULL) { + /* + * We havn't called Tk_MakeWindowExist for this window yet. The + * offset information will be postponed and calulated at that + * time. (This will usually only happen when a mapped parent is + * being moved but has child windows that have yet to be mapped.) + */ + return; + } + + winPtr->privatePtr->xOff += deltaX; + winPtr->privatePtr->yOff += deltaY; + + childPtr = winPtr->childList; + while (childPtr != NULL) { + if (!Tk_IsTopLevel(childPtr)) { + UpdateOffsets(childPtr, deltaX, deltaY); + } + childPtr = childPtr->nextPtr; + } + + if (Tk_IsContainer(winPtr)) { + childPtr = TkpGetOtherWindow(winPtr); + if (childPtr != NULL) { + UpdateOffsets(childPtr,deltaX,deltaY); + } + + /* + * NOTE: Here we should handle out of process embedding. + */ + + } +} + +/* + *---------------------------------------------------------------------- + * + * Tk_GetPixmap -- + * + * Creates an in memory drawing surface. + * + * Results: + * Returns a handle to a new pixmap. + * + * Side effects: + * Allocates a new Macintosh GWorld. + * + *---------------------------------------------------------------------- + */ + +Pixmap +Tk_GetPixmap( + Display *display, /* Display for new pixmap (can be null). */ + Drawable d, /* Drawable where pixmap will be used (ignored). */ + int width, /* Dimensions of pixmap. */ + int height, + int depth) /* Bits per pixel for pixmap. */ +{ + QDErr err; + GWorldPtr gWorld; + Rect bounds; + MacDrawable *macPix; + PixMapHandle pixels; + + if (display != NULL) { + display->request++; + } + macPix = (MacDrawable *) ckalloc(sizeof(MacDrawable)); + macPix->winPtr = NULL; + macPix->xOff = 0; + macPix->yOff = 0; + macPix->clipRgn = NULL; + macPix->aboveClipRgn = NULL; + macPix->referenceCount = 0; + macPix->toplevel = NULL; + macPix->flags = 0; + + bounds.top = bounds.left = 0; + bounds.right = (short) width; + bounds.bottom = (short) height; + if (depth != 1) { + depth = 0; + } + + /* + * Allocate memory for the off screen pixmap. If we fail + * try again from system memory. Eventually, we may have + * to panic. + */ + err = NewGWorld(&gWorld, depth, &bounds, NULL, NULL, 0); + if (err != noErr) { + err = NewGWorld(&gWorld, depth, &bounds, NULL, NULL, useTempMem); + } + if (err != noErr) { + panic("Out of memory: NewGWorld failed in Tk_GetPixmap"); + } + + /* + * Lock down the pixels so they don't move out from under us. + */ + pixels = GetGWorldPixMap(gWorld); + LockPixels(pixels); + macPix->portPtr = gWorld; + + return (Pixmap) macPix; +} + +/* + *---------------------------------------------------------------------- + * + * Tk_FreePixmap -- + * + * Release the resources associated with a pixmap. + * + * Results: + * None. + * + * Side effects: + * Deletes the Macintosh GWorld created by Tk_GetPixmap. + * + *---------------------------------------------------------------------- + */ + +void +Tk_FreePixmap( + Display *display, /* Display. */ + Pixmap pixmap) /* Pixmap to destroy */ +{ + MacDrawable *macPix = (MacDrawable *) pixmap; + PixMapHandle pixels; + + display->request++; + pixels = GetGWorldPixMap(macPix->portPtr); + UnlockPixels(pixels); + DisposeGWorld(macPix->portPtr); + ckfree((char *) macPix); +} + diff --git a/mac/tkMacTest.c b/mac/tkMacTest.c new file mode 100644 index 0000000..46a7bb1 --- /dev/null +++ b/mac/tkMacTest.c @@ -0,0 +1,81 @@ +/* + * tkMacTest.c -- + * + * Contains commands for platform specific tests for + * the Macintosh platform. + * + * Copyright (c) 1996 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) tkMacTest.c 1.2 96/12/15 14:34:00 + */ + +#include <Types.h> + +/* + * Forward declarations of procedures defined later in this file: + */ + +int TkplatformtestInit _ANSI_ARGS_((Tcl_Interp *interp)); +static int DebuggerCmd _ANSI_ARGS_((ClientData dummy, + Tcl_Interp *interp, int argc, char **argv)); + +/* + *---------------------------------------------------------------------- + * + * TkplatformtestInit -- + * + * Defines commands that test platform specific functionality for + * Unix platforms. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * Defines new commands. + * + *---------------------------------------------------------------------- + */ + +int +TkplatformtestInit( + Tcl_Interp *interp) /* Interpreter to add commands to. */ +{ + /* + * Add commands for platform specific tests on MacOS here. + */ + + Tcl_CreateCommand(interp, "debugger", DebuggerCmd, + (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); + + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * DebuggerCmd -- + * + * This procedure simply calls the low level debugger. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +DebuggerCmd( + ClientData clientData, /* Not used. */ + Tcl_Interp *interp, /* Not used. */ + int argc, /* Not used. */ + char **argv) /* Not used. */ +{ + Debugger(); + return TCL_OK; +} diff --git a/mac/tkMacWindowMgr.c b/mac/tkMacWindowMgr.c new file mode 100644 index 0000000..7c8206c --- /dev/null +++ b/mac/tkMacWindowMgr.c @@ -0,0 +1,1591 @@ +/* + * tkMacWindowMgr.c -- + * + * Implements common window manager functions for the Macintosh. + * + * Copyright (c) 1995-1997 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) tkMacWindowMgr.c 1.59 97/11/20 18:56:39 + */ + +#include <Events.h> +#include <Dialogs.h> +#include <EPPC.h> +#include <Windows.h> +#include <ToolUtils.h> +#include <DiskInit.h> +#include <LowMem.h> +#include <Timer.h> +#include <Sound.h> + +#include "tkInt.h" +#include "tkPort.h" +#include "tkMacInt.h" + +#define TK_DEFAULT_ABOUT 128 + +/* + * Declarations of global variables defined in this file. + */ + +int tkMacAppInFront = true; /* Boolean variable for determining + * if we are the frontmost app. */ + +/* + * Non-standard event types that can be passed to HandleEvent. + * These are defined and used by Netscape's plugin architecture. + */ +#define getFocusEvent (osEvt + 16) +#define loseFocusEvent (osEvt + 17) +#define adjustCursorEvent (osEvt + 18) + +/* + * Declarations of static variables used in this file. + */ + +static int gEatButtonUp = 0; /* 1 if we need to eat the next + * up event */ +static Tk_Window gGrabWinPtr = NULL; /* Current grab window, NULL if no grab. */ +static Tk_Window gKeyboardWinPtr = NULL; /* Current keyboard grab window. */ +static RgnHandle gDamageRgn = NULL; /* Damage region used for handling + * screen updates. */ +/* + * Forward declarations of procedures used in this file. + */ + +static void BringWindowForward _ANSI_ARGS_((WindowRef wRef)); +static int CheckEventsAvail _ANSI_ARGS_((void)); +static int GenerateActivateEvents _ANSI_ARGS_((EventRecord *eventPtr, + Window window)); +static int GenerateFocusEvent _ANSI_ARGS_((EventRecord *eventPtr, + Window window)); +static int GenerateKeyEvent _ANSI_ARGS_((EventRecord *eventPtr, + Window window)); +static int GenerateUpdateEvent _ANSI_ARGS_((EventRecord *eventPtr, + Window window)); +static void GenerateUpdates _ANSI_ARGS_((RgnHandle updateRgn, + TkWindow *winPtr)); +static int GeneratePollingEvents _ANSI_ARGS_((void)); +static int GeneratePollingEvents2 _ANSI_ARGS_((Window window)); +static OSErr TellWindowDefProcToCalcRegions _ANSI_ARGS_((WindowRef wRef)); +static int WindowManagerMouse _ANSI_ARGS_((EventRecord *theEvent, + Window window)); + + +/* + *---------------------------------------------------------------------- + * + * WindowManagerMouse -- + * + * This function determines if a button event is a "Window Manager" + * function or an event that should be passed to Tk's event + * queue. + * + * Results: + * Return true if event was placed on Tk's event queue. + * + * Side effects: + * Depends on where the button event occurs. + * + *---------------------------------------------------------------------- + */ + +static int +WindowManagerMouse( + EventRecord *eventPtr, /* Macintosh event record. */ + Window window) /* Window pointer. */ +{ + WindowRef whichWindow, frontWindow; + Tk_Window tkwin; + Point where, where2; + int xOffset, yOffset; + short windowPart; + + frontWindow = FrontWindow(); + + /* + * The window manager only needs to know about mouse down events + * and sometimes we need to "eat" the mouse up. Otherwise, we + * just pass the event to Tk. + */ + if (eventPtr->what == mouseUp) { + if (gEatButtonUp) { + gEatButtonUp = false; + return false; + } + return TkGenerateButtonEvent(eventPtr->where.h, eventPtr->where.v, + window, TkMacButtonKeyState()); + } + + windowPart = FindWindow(eventPtr->where, &whichWindow); + tkwin = Tk_IdToWindow(tkDisplayList->display, window); + switch (windowPart) { + case inSysWindow: + SystemClick(eventPtr, (GrafPort *) whichWindow); + return false; + case inDrag: + if (whichWindow != frontWindow) { + if (!(eventPtr->modifiers & cmdKey)) { + if ((gGrabWinPtr != NULL) && (gGrabWinPtr != tkwin)) { + SysBeep(1); + return false; + } + } + } + + /* + * Call DragWindow to move the window around. It will + * also eat the mouse up event. + */ + SetPort((GrafPort *) whichWindow); + where.h = where.v = 0; + LocalToGlobal(&where); + DragWindow(whichWindow, eventPtr->where, + &tcl_macQdPtr->screenBits.bounds); + gEatButtonUp = false; + + where2.h = where2.v = 0; + LocalToGlobal(&where2); + if (EqualPt(where, where2)) { + return false; + } + + TkMacWindowOffset(whichWindow, &xOffset, &yOffset); + where2.h -= xOffset; + where2.v -= yOffset; + TkGenWMConfigureEvent(tkwin, where2.h, where2.v, + -1, -1, TK_LOCATION_CHANGED); + return true; + case inGrow: + case inContent: + if (whichWindow != frontWindow ) { + /* + * This click moves the window forward. We don't want + * the corasponding mouse-up to be reported to the application + * or else it will mess up some Tk scripts. + */ + if ((gGrabWinPtr != NULL) && (gGrabWinPtr != tkwin)) { + SysBeep(1); + return false; + } + BringWindowForward(whichWindow); + gEatButtonUp = true; + SetPort((GrafPort *) whichWindow); + return false; + } else { + /* + * Generally the content region is the domain of Tk + * sub-windows. However, one exception is the grow + * region. A button down in this area will be handled + * by the window manager. Note: this means that Tk + * may not get button down events in this area! + */ + + if (TkMacGrowToplevel(whichWindow, eventPtr->where) == true) { + return true; + } else { + return TkGenerateButtonEvent(eventPtr->where.h, + eventPtr->where.v, window, TkMacButtonKeyState()); + } + } + case inGoAway: + if (TrackGoAway( whichWindow, eventPtr->where)) { + if (tkwin == NULL) { + return false; + } + TkGenWMDestroyEvent(tkwin); + return true; + } + return false; + case inMenuBar: + { + int oldMode; + KeyMap theKeys; + + GetKeys(theKeys); + oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL); + TkMacClearMenubarActive(); + TkMacHandleMenuSelect(MenuSelect(eventPtr->where), + theKeys[1] & 4); + Tcl_SetServiceMode(oldMode); + return true; /* TODO: may not be on event on queue. */ + } + case inZoomIn: + case inZoomOut: + if (TkMacZoomToplevel(whichWindow, eventPtr->where, windowPart) + == true) { + return true; + } else { + return false; + } + default: + return false; + } +} + +/* + *---------------------------------------------------------------------- + * + * TkAboutDlg -- + * + * Displays the default Tk About box. This code uses Macintosh + * resources to define the content of the About Box. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +TkAboutDlg() +{ + DialogPtr aboutDlog; + short itemHit = -9; + + aboutDlog = GetNewDialog(128, NULL, (void*)(-1)); + + if (!aboutDlog) { + return; + } + + SelectWindow((WindowRef) aboutDlog); + + while (itemHit != 1) { + ModalDialog( NULL, &itemHit); + } + DisposDialog(aboutDlog); + aboutDlog = NULL; + + SelectWindow(FrontWindow()); + + return; +} + +/* + *---------------------------------------------------------------------- + * + * GenerateUpdateEvent -- + * + * Given a Macintosh update event this function generates all the + * X update events needed by Tk. + * + * Results: + * True if event(s) are generated - false otherwise. + * + * Side effects: + * Additional events may be place on the Tk event queue. + * + *---------------------------------------------------------------------- + */ + +static int +GenerateUpdateEvent( + EventRecord *eventPtr, /* Incoming Mac event */ + Window window) /* Root X window for event. */ +{ + WindowRef macWindow; + register TkWindow *winPtr; + + winPtr = (TkWindow *) Tk_IdToWindow(tkDisplayList->display, window); + + if (winPtr == NULL) { + return false; + } + + if (gDamageRgn == NULL) { + gDamageRgn = NewRgn(); + } + + /* + * After the call to BeginUpdate the visable region (visRgn) of the + * window is equal to the intersection of the real visable region and + * the update region for this event. We use this region in all of our + * calculations. + */ + + if (eventPtr->message != NULL) { + macWindow = (WindowRef) TkMacGetDrawablePort(window); + BeginUpdate(macWindow); + GenerateUpdates(macWindow->visRgn, winPtr); + EndUpdate(macWindow); + return true; + } else { + /* + * This event didn't come from the system. This might + * occur if we are running from inside of Netscape. + * In this we shouldn't call BeginUpdate as the vis region + * may be NULL. + */ + RgnHandle rgn; + Rect bounds; + + rgn = NewRgn(); + TkMacWinBounds(winPtr, &bounds); + RectRgn(rgn, &bounds); + GenerateUpdates(rgn, winPtr); + DisposeRgn(rgn); + return true; + } +} + +/* + *---------------------------------------------------------------------- + * + * GenerateUpdates -- + * + * Given a Macintosh update region and a Tk window this function + * geneates a X damage event for the window if it is within the + * update region. The function will then recursivly have each + * damaged window generate damage events for its child windows. + * + * Results: + * None. + * + * Side effects: + * Additional events may be place on the Tk event queue. + * + *---------------------------------------------------------------------- + */ + +static void +GenerateUpdates( + RgnHandle updateRgn, + TkWindow *winPtr) +{ + TkWindow *childPtr; + XEvent event; + Rect bounds; + + TkMacWinBounds(winPtr, &bounds); + + if (bounds.top > (*updateRgn)->rgnBBox.bottom || + (*updateRgn)->rgnBBox.top > bounds.bottom || + bounds.left > (*updateRgn)->rgnBBox.right || + (*updateRgn)->rgnBBox.left > bounds.right || + !RectInRgn(&bounds, updateRgn)) { + return; + } + + event.xany.serial = Tk_Display(winPtr)->request; + event.xany.send_event = false; + event.xany.window = Tk_WindowId(winPtr); + event.xany.display = Tk_Display(winPtr); + + event.type = Expose; + + /* + * Compute the bounding box of the area that the damage occured in. + */ + + /* + * CopyRgn(TkMacVisableClipRgn(winPtr), rgn); + * TODO: this call doesn't work doing resizes!!! + */ + RectRgn(gDamageRgn, &bounds); + SectRgn(gDamageRgn, updateRgn, gDamageRgn); + OffsetRgn(gDamageRgn, -bounds.left, -bounds.top); + event.xexpose.x = (**gDamageRgn).rgnBBox.left; + event.xexpose.y = (**gDamageRgn).rgnBBox.top; + event.xexpose.width = (**gDamageRgn).rgnBBox.right - + (**gDamageRgn).rgnBBox.left; + event.xexpose.height = (**gDamageRgn).rgnBBox.bottom - + (**gDamageRgn).rgnBBox.top; + event.xexpose.count = 0; + + Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); + + /* + * Generate updates for the children of this window + */ + + for (childPtr = winPtr->childList; childPtr != NULL; + childPtr = childPtr->nextPtr) { + if (!Tk_IsMapped(childPtr) || Tk_IsTopLevel(childPtr)) { + continue; + } + + GenerateUpdates(updateRgn, childPtr); + } + + /* + * Generate updates for any contained windows + */ + + if (Tk_IsContainer(winPtr)) { + childPtr = TkpGetOtherWindow(winPtr); + if (childPtr != NULL && Tk_IsMapped(childPtr)) { + GenerateUpdates(updateRgn, childPtr); + } + + /* + * NOTE: Here we should handle out of process embedding. + */ + + } + + return; +} + +/* + *---------------------------------------------------------------------- + * + * TkGenerateButtonEvent -- + * + * Given a global x & y position and the button key status this + * procedure generates the appropiate X button event. It also + * handles the state changes needed to implement implicit grabs. + * + * Results: + * True if event(s) are generated - false otherwise. + * + * Side effects: + * Additional events may be place on the Tk event queue. + * Grab state may also change. + * + *---------------------------------------------------------------------- + */ + +int +TkGenerateButtonEvent( + int x, /* X location of mouse */ + int y, /* Y location of mouse */ + Window window, /* X Window containing button event. */ + unsigned int state) /* Button Key state suitable for X event */ +{ + WindowRef whichWin, frontWin; + Point where; + Tk_Window tkwin; + int dummy; + + /* + * ButtonDown events will always occur in the front + * window. ButtonUp events, however, may occur anywhere + * on the screen. ButtonUp events should only be sent + * to Tk if in the front window or during an implicit grab. + */ + where.h = x; + where.v = y; + FindWindow(where, &whichWin); + frontWin = FrontWindow(); + + if ((frontWin == NULL) || (frontWin != whichWin && gGrabWinPtr == NULL)) { + return false; + } + + tkwin = Tk_IdToWindow(tkDisplayList->display, window); + + GlobalToLocal(&where); + if (tkwin != NULL) { + tkwin = Tk_TopCoordsToWindow(tkwin, where.h, where.v, &dummy, &dummy); + } + + Tk_UpdatePointer(tkwin, x, y, state); + + return true; +} + +/* + *---------------------------------------------------------------------- + * + * GenerateActivateEvents -- + * + * Generate Activate/Deactivate events from a Macintosh Activate + * event. Note, the activate-on-foreground bit must be set in the + * SIZE flags to ensure we get Activate/Deactivate in addition to + * Susspend/Resume events. + * + * Results: + * Returns true if events were generate. + * + * Side effects: + * Queue events on Tk's event queue. + * + *---------------------------------------------------------------------- + */ + +static int +GenerateActivateEvents( + EventRecord *eventPtr, /* Incoming Mac event */ + Window window) /* Root X window for event. */ +{ + TkWindow *winPtr; + + winPtr = (TkWindow *) Tk_IdToWindow(tkDisplayList->display, window); + if (winPtr == NULL || winPtr->window == None) { + return false; + } + + TkGenerateActivateEvents(winPtr, + (eventPtr->modifiers & activeFlag) ? 1 : 0); + return true; +} + +/* + *---------------------------------------------------------------------- + * + * XSetInputFocus -- + * + * Change the focus window for the application. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +XSetInputFocus( + Display* display, + Window focus, + int revert_to, + Time time) +{ + /* + * Don't need to do a thing. Tk manages the focus for us. + */ +} + +/* + *---------------------------------------------------------------------- + * + * TkpChangeFocus -- + * + * This procedure is a stub on the Mac because we always own the + * focus if we are a front most application. + * + * Results: + * The return value is the serial number of the command that + * changed the focus. It may be needed by the caller to filter + * out focus change events that were queued before the command. + * If the procedure doesn't actually change the focus then + * it returns 0. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +TkpChangeFocus(winPtr, force) + TkWindow *winPtr; /* Window that is to receive the X focus. */ + int force; /* Non-zero means claim the focus even + * if it didn't originally belong to + * topLevelPtr's application. */ +{ + /* + * We don't really need to do anything on the Mac. Tk will + * keep all this state for us. + */ + + if (winPtr->atts.override_redirect) { + return 0; + } + + /* + * Remember the current serial number for the X server and issue + * a dummy server request. This marks the position at which we + * changed the focus, so we can distinguish FocusIn and FocusOut + * events on either side of the mark. + */ + + return NextRequest(winPtr->display); +} + +/* + *---------------------------------------------------------------------- + * + * GenerateFocusEvent -- + * + * Generate FocusIn/FocusOut events from a Macintosh Activate + * event. Note, the activate-on-foreground bit must be set in + * the SIZE flags to ensure we get Activate/Deactivate in addition + * to Susspend/Resume events. + * + * Results: + * Returns true if events were generate. + * + * Side effects: + * Queue events on Tk's event queue. + * + *---------------------------------------------------------------------- + */ + +static int +GenerateFocusEvent( + EventRecord *eventPtr, /* Incoming Mac event */ + Window window) /* Root X window for event. */ +{ + XEvent event; + Tk_Window tkwin; + + tkwin = Tk_IdToWindow(tkDisplayList->display, window); + if (tkwin == NULL) { + return false; + } + + /* + * Generate FocusIn and FocusOut events. This event + * is only sent to the toplevel window. + */ + + if (eventPtr->modifiers & activeFlag) { + event.xany.type = FocusIn; + } else { + event.xany.type = FocusOut; + } + + event.xany.serial = tkDisplayList->display->request; + event.xany.send_event = False; + event.xfocus.display = tkDisplayList->display; + event.xfocus.window = window; + event.xfocus.mode = NotifyNormal; + event.xfocus.detail = NotifyDetailNone; + + Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); + return true; +} + +/* + *---------------------------------------------------------------------- + * + * GenerateKeyEvent -- + * + * Given Macintosh keyUp, keyDown & autoKey events this function + * generates the appropiate X key events. The window that is passed + * should represent the frontmost window - which will recieve the + * event. + * + * Results: + * True if event(s) are generated - false otherwise. + * + * Side effects: + * Additional events may be place on the Tk event queue. + * + *---------------------------------------------------------------------- + */ + +static int +GenerateKeyEvent( + EventRecord *eventPtr, /* Incoming Mac event */ + Window window) /* Root X window for event. */ +{ + Point where; + Tk_Window tkwin; + XEvent event; + + /* + * The focus must be in the FrontWindow on the Macintosh. + * We then query Tk to determine the exact Tk window + * that owns the focus. + */ + + tkwin = Tk_IdToWindow(tkDisplayList->display, window); + tkwin = (Tk_Window) ((TkWindow *) tkwin)->dispPtr->focusPtr; + if (tkwin == NULL) { + return false; + } + + where.v = eventPtr->where.v; + where.h = eventPtr->where.h; + + event.xany.send_event = False; + event.xkey.same_screen = true; + event.xkey.subwindow = None; + event.xkey.time = TkpGetMS(); + + event.xkey.x_root = where.h; + event.xkey.y_root = where.v; + GlobalToLocal(&where); + Tk_TopCoordsToWindow(tkwin, where.h, where.v, + &event.xkey.x, &event.xkey.y); + event.xkey.keycode = eventPtr->message; + + event.xany.serial = Tk_Display(tkwin)->request; + event.xkey.window = Tk_WindowId(tkwin); + event.xkey.display = Tk_Display(tkwin); + event.xkey.root = XRootWindow(Tk_Display(tkwin), 0); + event.xkey.state = TkMacButtonKeyState(); + + if (eventPtr->what == keyDown) { + event.xany.type = KeyPress; + Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); + } else if (eventPtr->what == keyUp) { + event.xany.type = KeyRelease; + Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); + } else { + /* + * Autokey events send multiple XKey events. + * + * Note: the last KeyRelease will always be missed with + * this scheme. However, most Tk scripts don't look for + * KeyUp events so we should be OK. + */ + event.xany.type = KeyRelease; + Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); + event.xany.type = KeyPress; + Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); + } + return true; +} + +/* + *---------------------------------------------------------------------- + * + * GeneratePollingEvents -- + * + * This function polls the mouse position and generates X Motion, + * Enter & Leave events. The cursor is also updated at this + * time. + * + * Results: + * True if event(s) are generated - false otherwise. + * + * Side effects: + * Additional events may be place on the Tk event queue. + * The cursor may be changed. + * + *---------------------------------------------------------------------- + */ + +static int +GeneratePollingEvents() +{ + Tk_Window tkwin, rootwin; + Window window; + WindowRef whichwindow, frontWin; + Point whereLocal, whereGlobal; + Boolean inContentRgn; + short part; + int local_x, local_y; + int generatedEvents = false; + + /* + * First we get the current mouse position and determine + * what Tk window the mouse is over (if any). + */ + frontWin = FrontWindow(); + if (frontWin == NULL) { + return false; + } + SetPort((GrafPort *) frontWin); + + GetMouse(&whereLocal); + whereGlobal = whereLocal; + LocalToGlobal(&whereGlobal); + + part = FindWindow(whereGlobal, &whichwindow); + inContentRgn = (part == inContent || part == inGrow); + + if ((frontWin != whichwindow) || !inContentRgn) { + tkwin = NULL; + } else { + window = TkMacGetXWindow(whichwindow); + rootwin = Tk_IdToWindow(tkDisplayList->display, window); + if (rootwin == NULL) { + tkwin = NULL; + } else { + tkwin = Tk_TopCoordsToWindow(rootwin, whereLocal.h, whereLocal.v, + &local_x, &local_y); + } + } + + /* + * The following call will generate the appropiate X events and + * adjust any state that Tk must remember. + */ + + if ((tkwin == NULL) && (gGrabWinPtr != NULL)) { + tkwin = gGrabWinPtr; + } + Tk_UpdatePointer(tkwin, whereGlobal.h, whereGlobal.v, + TkMacButtonKeyState()); + + /* + * Finally, we make sure the proper cursor is installed. The installation + * is polled to 1) make our resize hack work, and 2) make sure we have the + * proper cursor even if someone else changed the cursor out from under + * us. + */ + if ((gGrabWinPtr == NULL) && (part == inGrow) && + TkMacResizable((TkWindow *) tkwin) && + (TkMacGetScrollbarGrowWindow((TkWindow *) tkwin) == NULL)) { + TkMacInstallCursor(1); + } else { + TkMacInstallCursor(0); + } + + return true; +} + +/* + *---------------------------------------------------------------------- + * + * GeneratePollingEvents2 -- + * + * This function polls the mouse position and generates X Motion, + * Enter & Leave events. The cursor is also updated at this + * time. NOTE: this version is for Netscape!!! + * + * Results: + * True if event(s) are generated - false otherwise. + * + * Side effects: + * Additional events may be place on the Tk event queue. + * The cursor may be changed. + * + *---------------------------------------------------------------------- + */ + +static int +GeneratePollingEvents2( + Window window) +{ + Tk_Window tkwin, rootwin; + WindowRef whichwindow, frontWin; + Point whereLocal, whereGlobal; + int local_x, local_y; + int generatedEvents = false; + Rect bounds; + + /* + * First we get the current mouse position and determine + * what Tk window the mouse is over (if any). + */ + frontWin = FrontWindow(); + if (frontWin == NULL) { + return false; + } + SetPort((GrafPort *) frontWin); + + GetMouse(&whereLocal); + whereGlobal = whereLocal; + LocalToGlobal(&whereGlobal); + + /* + * Determine if we are in a Tk window or not. + */ + whichwindow = (WindowRef) TkMacGetDrawablePort(window); + if (whichwindow != frontWin) { + tkwin = NULL; + } else { + rootwin = Tk_IdToWindow(tkDisplayList->display, window); + TkMacWinBounds((TkWindow *) rootwin, &bounds); + if (!PtInRect(whereLocal, &bounds)) { + tkwin = NULL; + } else { + tkwin = Tk_TopCoordsToWindow(rootwin, whereLocal.h, whereLocal.v, + &local_x, &local_y); + } + } + + /* + * The following call will generate the appropiate X events and + * adjust any state that Tk must remember. + */ + + if ((tkwin == NULL) && (gGrabWinPtr != NULL)) { + tkwin = gGrabWinPtr; + } + Tk_UpdatePointer(tkwin, whereGlobal.h, whereGlobal.v, + TkMacButtonKeyState()); + + /* + * Finally, we make sure the proper cursor is installed. The installation + * is polled to 1) make our resize hack work, and 2) make sure we have the + * proper cursor even if someone else changed the cursor out from under + * us. + */ + TkMacInstallCursor(0); + + return true; +} + +/* + *---------------------------------------------------------------------- + * + * TkMacButtonKeyState -- + * + * Returns the current state of the button & modifier keys. + * + * Results: + * A bitwise inclusive OR of a subset of the following: + * Button1Mask, ShiftMask, LockMask, ControlMask, Mod?Mask, + * Mod?Mask. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +unsigned int +TkMacButtonKeyState() +{ + unsigned int state = 0; + KeyMap theKeys; + + if (Button() & !gEatButtonUp) { + state |= Button1Mask; + } + + GetKeys(theKeys); + + if (theKeys[1] & 2) { + state |= LockMask; + } + + if (theKeys[1] & 1) { + state |= ShiftMask; + } + + if (theKeys[1] & 8) { + state |= ControlMask; + } + + if (theKeys[1] & 32768) { + state |= Mod1Mask; /* command key */ + } + + if (theKeys[1] & 4) { + state |= Mod2Mask; /* option key */ + } + + return state; +} + +/* + *---------------------------------------------------------------------- + * + * XGrabKeyboard -- + * + * Simulates a keyboard grab by setting the focus. + * + * Results: + * Always returns GrabSuccess. + * + * Side effects: + * Sets the keyboard focus to the specified window. + * + *---------------------------------------------------------------------- + */ + +int +XGrabKeyboard( + Display* display, + Window grab_window, + Bool owner_events, + int pointer_mode, + int keyboard_mode, + Time time) +{ + gKeyboardWinPtr = Tk_IdToWindow(display, grab_window); + return GrabSuccess; +} + +/* + *---------------------------------------------------------------------- + * + * XUngrabKeyboard -- + * + * Releases the simulated keyboard grab. + * + * Results: + * None. + * + * Side effects: + * Sets the keyboard focus back to the value before the grab. + * + *---------------------------------------------------------------------- + */ + +void +XUngrabKeyboard( + Display* display, + Time time) +{ + gKeyboardWinPtr = NULL; +} + +/* + *---------------------------------------------------------------------- + * + * XQueryPointer -- + * + * Check the current state of the mouse. This is not a complete + * implementation of this function. It only computes the root + * coordinates and the current mask. + * + * Results: + * Sets root_x_return, root_y_return, and mask_return. Returns + * true on success. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +Bool +XQueryPointer( + Display* display, + Window w, + Window* root_return, + Window* child_return, + int* root_x_return, + int* root_y_return, + int* win_x_return, + int* win_y_return, + unsigned int* mask_return) +{ + Point where; + + GetMouse(&where); + LocalToGlobal(&where); + *root_x_return = where.h; + *root_y_return = where.v; + *mask_return = TkMacButtonKeyState(); + return True; +} + +/* + *---------------------------------------------------------------------- + * + * TkMacGenerateTime -- + * + * Returns the total number of ticks from startup This function + * is used to generate the time of generated X events. + * + * Results: + * Returns the current time (ticks from startup). + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +Time +TkMacGenerateTime() +{ + return (Time) LMGetTicks(); +} + +/* + *---------------------------------------------------------------------- + * + * TkMacConvertEvent -- + * + * This function converts a Macintosh event into zero or more + * Tcl events. + * + * Results: + * Returns 1 if event added to Tcl queue, 0 otherwse. + * + * Side effects: + * May add events to Tcl's event queue. + * + *---------------------------------------------------------------------- + */ + +int +TkMacConvertEvent( + EventRecord *eventPtr) +{ + WindowRef whichWindow; + Window window; + int eventFound = false; + + switch (eventPtr->what) { + case nullEvent: + case adjustCursorEvent: + if (GeneratePollingEvents()) { + eventFound = true; + } + break; + case updateEvt: + whichWindow = (WindowRef)eventPtr->message; + window = TkMacGetXWindow(whichWindow); + if (GenerateUpdateEvent(eventPtr, window)) { + eventFound = true; + } + break; + case mouseDown: + case mouseUp: + FindWindow(eventPtr->where, &whichWindow); + window = TkMacGetXWindow(whichWindow); + if (WindowManagerMouse(eventPtr, window)) { + eventFound = true; + } + break; + case autoKey: + case keyDown: + /* + * Handle menu-key events here. If it is *not* + * a menu key - just fall through to handle as a + * normal key event. + */ + if ((eventPtr->modifiers & cmdKey) == cmdKey) { + long menuResult; + int oldMode; + + oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL); + menuResult = MenuKey(eventPtr->message & charCodeMask); + Tcl_SetServiceMode(oldMode); + + if (HiWord(menuResult) != 0) { + TkMacHandleMenuSelect(menuResult, false); + break; + } + } + case keyUp: + whichWindow = FrontWindow(); + window = TkMacGetXWindow(whichWindow); + eventFound |= GenerateKeyEvent(eventPtr, window); + break; + case activateEvt: + window = TkMacGetXWindow((WindowRef) eventPtr->message); + eventFound |= GenerateActivateEvents(eventPtr, window); + eventFound |= GenerateFocusEvent(eventPtr, window); + break; + case getFocusEvent: + eventPtr->modifiers |= activeFlag; + window = TkMacGetXWindow((WindowRef) eventPtr->message); + eventFound |= GenerateFocusEvent(eventPtr, window); + break; + case loseFocusEvent: + eventPtr->modifiers &= ~activeFlag; + window = TkMacGetXWindow((WindowRef) eventPtr->message); + eventFound |= GenerateFocusEvent(eventPtr, window); + break; + case kHighLevelEvent: + TkMacDoHLEvent(eventPtr); + /* TODO: should return true if events were placed on event queue. */ + break; + case osEvt: + /* + * Do clipboard conversion. + */ + switch ((eventPtr->message & osEvtMessageMask) >> 24) { + case mouseMovedMessage: + if (GeneratePollingEvents()) { + eventFound = true; + } + break; + case suspendResumeMessage: + if (!(eventPtr->message & resumeFlag)) { + TkSuspendClipboard(); + } + tkMacAppInFront = (eventPtr->message & resumeFlag); + break; + } + break; + case diskEvt: + /* + * Disk insertion. + */ + if (HiWord(eventPtr->message) != noErr) { + Point pt; + + DILoad(); + pt.v = pt.h = 120; /* parameter ignored in sys 7 */ + DIBadMount(pt, eventPtr->message); + DIUnload(); + } + break; + } + + return eventFound; +} + +/* + *---------------------------------------------------------------------- + * + * TkMacConvertTkEvent -- + * + * This function converts a Macintosh event into zero or more + * Tcl events. + * + * Results: + * Returns 1 if event added to Tcl queue, 0 otherwse. + * + * Side effects: + * May add events to Tcl's event queue. + * + *---------------------------------------------------------------------- + */ + +int +TkMacConvertTkEvent( + EventRecord *eventPtr, + Window window) +{ + int eventFound = false; + Point where; + + switch (eventPtr->what) { + case nullEvent: + case adjustCursorEvent: + if (GeneratePollingEvents2(window)) { + eventFound = true; + } + break; + case updateEvt: + if (GenerateUpdateEvent(eventPtr, window)) { + eventFound = true; + } + break; + case mouseDown: + case mouseUp: + GetMouse(&where); + LocalToGlobal(&where); + eventFound |= TkGenerateButtonEvent(where.h, where.v, + window, TkMacButtonKeyState()); + break; + case autoKey: + case keyDown: + /* + * Handle menu-key events here. If it is *not* + * a menu key - just fall through to handle as a + * normal key event. + */ + if ((eventPtr->modifiers & cmdKey) == cmdKey) { + long menuResult = MenuKey(eventPtr->message & charCodeMask); + + if (HiWord(menuResult) != 0) { + TkMacHandleMenuSelect(menuResult, false); + break; + } + } + case keyUp: + eventFound |= GenerateKeyEvent(eventPtr, window); + break; + case activateEvt: + eventFound |= GenerateActivateEvents(eventPtr, window); + eventFound |= GenerateFocusEvent(eventPtr, window); + break; + case getFocusEvent: + eventPtr->modifiers |= activeFlag; + eventFound |= GenerateFocusEvent(eventPtr, window); + break; + case loseFocusEvent: + eventPtr->modifiers &= ~activeFlag; + eventFound |= GenerateFocusEvent(eventPtr, window); + break; + case kHighLevelEvent: + TkMacDoHLEvent(eventPtr); + /* TODO: should return true if events were placed on event queue. */ + break; + case osEvt: + /* + * Do clipboard conversion. + */ + switch ((eventPtr->message & osEvtMessageMask) >> 24) { + case mouseMovedMessage: + if (GeneratePollingEvents2(window)) { + eventFound = true; + } + break; + case suspendResumeMessage: + if (!(eventPtr->message & resumeFlag)) { + TkSuspendClipboard(); + } + tkMacAppInFront = (eventPtr->message & resumeFlag); + break; + } + break; + case diskEvt: + /* + * Disk insertion. + */ + if (HiWord(eventPtr->message) != noErr) { + Point pt; + + DILoad(); + pt.v = pt.h = 120; /* parameter ignored in sys 7 */ + DIBadMount(pt, eventPtr->message); + DIUnload(); + } + break; + } + + return eventFound; +} + +/* + *---------------------------------------------------------------------- + * + * CheckEventsAvail -- + * + * Checks to see if events are available on the Macintosh queue. + * This function looks for both queued events (eg. key & button) + * and generated events (update). + * + * Results: + * True is events exist, false otherwise. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +CheckEventsAvail() +{ + QHdrPtr evPtr; + WindowPeek macWinPtr; + + evPtr = GetEvQHdr(); + if (evPtr->qHead != NULL) { + return true; + } + + macWinPtr = (WindowPeek) FrontWindow(); + while (macWinPtr != NULL) { + if (!EmptyRgn(macWinPtr->updateRgn)) { + return true; + } + macWinPtr = macWinPtr->nextWindow; + } + return false; +} + +/* + *---------------------------------------------------------------------- + * + * TkpSetCapture -- + * + * This function captures the mouse so that all future events + * will be reported to this window, even if the mouse is outside + * the window. If the specified window is NULL, then the mouse + * is released. + * + * Results: + * None. + * + * Side effects: + * Sets the capture flag and captures the mouse. + * + *---------------------------------------------------------------------- + */ + +void +TkpSetCapture( + TkWindow *winPtr) /* Capture window, or NULL. */ +{ + while ((winPtr != NULL) && !Tk_IsTopLevel(winPtr)) { + winPtr = winPtr->parentPtr; + } + gGrabWinPtr = (Tk_Window) winPtr; +} + +/* + *---------------------------------------------------------------------- + * + * TkMacWindowOffset -- + * + * Determines the x and y offset from the orgin of the toplevel + * window dressing (the structure region, ie. title bar) and the + * orgin of the content area. + * + * Results: + * The x & y offset in pixels. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +TkMacWindowOffset( + WindowRef wRef, + int *xOffset, + int *yOffset) +{ + OSErr err = noErr; + WindowPeek wPeek = (WindowPeek) wRef; + RgnHandle strucRgn = wPeek->strucRgn; + RgnHandle contRgn = wPeek->contRgn; + Rect strucRect, contRect; + + if (!EmptyRgn(strucRgn) && !EmptyRgn(contRgn)) { + strucRect = (**strucRgn).rgnBBox; + contRect = (**contRgn).rgnBBox; + } else { + /* + * The current window's regions are not up to date. + * Probably because the window isn't visable. What we + * will do is save the old regions, have the window calculate + * what the regions should be, and then restore it self. + */ + strucRgn = NewRgn( ); + contRgn = NewRgn( ); + + if (!strucRgn || !contRgn) { + err = MemError( ); + } else { + CopyRgn(wPeek->strucRgn, strucRgn); + CopyRgn(wPeek->contRgn, contRgn); + + if (!(err = TellWindowDefProcToCalcRegions(wRef))) { + strucRect = (**(wPeek->strucRgn)).rgnBBox; + contRect = (**(wPeek->contRgn)).rgnBBox; + } + + CopyRgn(strucRgn, wPeek->strucRgn); + CopyRgn(contRgn, wPeek->contRgn); + } + + if (contRgn) { + DisposeRgn(contRgn); + } + + if (strucRgn) { + DisposeRgn(strucRgn); + } + } + + if (!err) { + *xOffset = contRect.left - strucRect.left; + *yOffset = contRect.top - strucRect.top; + } else { + *xOffset = 0; + *yOffset = 0; + } + + return; +} + +/* + *---------------------------------------------------------------------- + * + * TellWindowDefProcToCalcRegions -- + * + * Force a Macintosh window to recalculate it's content and + * structure regions. + * + * Results: + * An OS error. + * + * Side effects: + * The windows content and structure regions may be updated. + * + *---------------------------------------------------------------------- + */ + +static OSErr +TellWindowDefProcToCalcRegions( + WindowRef wRef) +{ + OSErr err = noErr; + SInt8 hState; + Handle wdef = ((WindowPeek) wRef)->windowDefProc; + + /* + * Load and lock the window definition procedure for + * the window. + */ + hState = HGetState(wdef); + if (!(err = MemError())) { + LoadResource(wdef); + if (!(err = ResError())) { + MoveHHi(wdef); + err = MemError(); + if (err == memLockedErr) { + err = noErr; + } else if (!err) { + HLock(wdef); + err = MemError(); + } + } + } + + /* + * Assuming there are no errors we now call the window definition + * procedure to tell it to calculate the regions for the window. + */ + + if (err == noErr) { + (void) CallWindowDefProc((UniversalProcPtr) *wdef, + GetWVariant(wRef), wRef, wCalcRgns, 0); + + HSetState(wdef, hState); + if (!err) { + err = MemError(); + } + } + + return err; +} + +/* + *---------------------------------------------------------------------- + * + * BringWindowForward -- + * + * Bring this background window to the front. We also set state + * so Tk thinks the button is currently up. + * + * Results: + * None. + * + * Side effects: + * The window is brought forward. + * + *---------------------------------------------------------------------- + */ + +static void +BringWindowForward( + WindowRef wRef) +{ + SelectWindow(wRef); +} + +/* + *---------------------------------------------------------------------- + * + * TkpGetMS -- + * + * Return a relative time in milliseconds. It doesn't matter + * when the epoch was. + * + * Results: + * Number of milliseconds. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +unsigned long +TkpGetMS() +{ + long long * int64Ptr; + UnsignedWide micros; + + Microseconds(µs); + int64Ptr = (long long *) µs; + + /* + * We need 64 bit math to do this. This is available in CW 11 + * and on. Other's will need to use a different scheme. + */ + + *int64Ptr /= 1000; + + return (long) *int64Ptr; +} diff --git a/mac/tkMacWm.c b/mac/tkMacWm.c new file mode 100644 index 0000000..56c4b8a --- /dev/null +++ b/mac/tkMacWm.c @@ -0,0 +1,4213 @@ +/* + * tkMacWm.c -- + * + * This module takes care of the interactions between a Tk-based + * application and the window manager. Among other things, it + * implements the "wm" command and passes geometry information + * to the window manager. + * + * Copyright (c) 1994-1997 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) tkMacWm.c 1.72 97/10/29 13:27:30 + */ + +#include <Gestalt.h> +#include <QDOffscreen.h> +#include <Windows.h> +#include <ToolUtils.h> + +#include "tkPort.h" +#include "tkInt.h" +#include "tkMacInt.h" +#include <errno.h> +#include "tkScrollbar.h" + +/* + * If HAVE_APPEARANCE is defined in MW_TkHeader.pch then we must have the + * Appearance manager header & library. If so we can use these new API's to + * have the iconify code do the right thing. + */ + +#ifdef HAVE_APPEARANCE +# include <Appearance.h> +#endif + +/* + * A data structure of the following type holds information for + * each window manager protocol (such as WM_DELETE_WINDOW) for + * which a handler (i.e. a Tcl command) has been defined for a + * particular top-level window. + */ + +typedef struct ProtocolHandler { + Atom protocol; /* Identifies the protocol. */ + struct ProtocolHandler *nextPtr; + /* Next in list of protocol handlers for + * the same top-level window, or NULL for + * end of list. */ + Tcl_Interp *interp; /* Interpreter in which to invoke command. */ + char command[4]; /* Tcl command to invoke when a client + * message for this protocol arrives. + * The actual size of the structure varies + * to accommodate the needs of the actual + * command. THIS MUST BE THE LAST FIELD OF + * THE STRUCTURE. */ +} ProtocolHandler; + +#define HANDLER_SIZE(cmdLength) \ +((unsigned) (sizeof(ProtocolHandler) - 3 + cmdLength)) + +/* + * A data structure of the following type holds window-manager-related + * information for each top-level window in an application. + */ + +typedef struct TkWmInfo { + TkWindow *winPtr; /* Pointer to main Tk information for + * this window. */ + Window reparent; /* If the window has been reparented, this + * gives the ID of the ancestor of the window + * that is a child of the root window (may + * not be window's immediate parent). If + * the window isn't reparented, this has the + * value None. */ + Tk_Uid titleUid; /* Title to display in window caption. If + * NULL, use name of widget. */ + Tk_Uid iconName; /* Name to display in icon. */ + Window master; /* Master window for TRANSIENT_FOR property, + * or None. */ + XWMHints hints; /* Various pieces of information for + * window manager. */ + char *leaderName; /* Path name of leader of window group + * (corresponds to hints.window_group). + * Malloc-ed. Note: this field doesn't + * get updated if leader is destroyed. */ + char *masterWindowName; /* Path name of window specified as master + * in "wm transient" command, or NULL. + * Malloc-ed. Note: this field doesn't + * get updated if masterWindowName is + * destroyed. */ + Tk_Window icon; /* Window to use as icon for this window, + * or NULL. */ + Tk_Window iconFor; /* Window for which this window is icon, or + * NULL if this isn't an icon for anyone. */ + + /* + * Information used to construct an XSizeHints structure for + * the window manager: + */ + + int sizeHintsFlags; /* Flags word for XSizeHints structure. + * If the PBaseSize flag is set then the + * window is gridded; otherwise it isn't + * gridded. */ + int minWidth, minHeight; /* Minimum dimensions of window, in + * grid units, not pixels. */ + int maxWidth, maxHeight; /* Maximum dimensions of window, in + * grid units, not pixels. */ + Tk_Window gridWin; /* Identifies the window that controls + * gridding for this top-level, or NULL if + * the top-level isn't currently gridded. */ + int widthInc, heightInc; /* Increments for size changes (# pixels + * per step). */ + struct { + int x; /* numerator */ + int y; /* denominator */ + } minAspect, maxAspect; /* Min/max aspect ratios for window. */ + int reqGridWidth, reqGridHeight; + /* The dimensions of the window (in + * grid units) requested through + * the geometry manager. */ + int gravity; /* Desired window gravity. */ + + /* + * Information used to manage the size and location of a window. + */ + + int width, height; /* Desired dimensions of window, specified + * in grid units. These values are + * set by the "wm geometry" command and by + * ConfigureNotify events (for when wm + * resizes window). -1 means user hasn't + * requested dimensions. */ + int x, y; /* Desired X and Y coordinates for window. + * These values are set by "wm geometry", + * plus by ConfigureNotify events (when wm + * moves window). These numbers are + * different than the numbers stored in + * winPtr->changes because (a) they could be + * measured from the right or bottom edge + * of the screen (see WM_NEGATIVE_X and + * WM_NEGATIVE_Y flags) and (b) if the window + * has been reparented then they refer to the + * parent rather than the window itself. */ + int parentWidth, parentHeight; + /* Width and height of reparent, in pixels + * *including border*. If window hasn't been + * reparented then these will be the outer + * dimensions of the window, including + * border. */ + int xInParent, yInParent; /* Offset of window within reparent, measured + * from upper-left outer corner of parent's + * border to upper-left outer corner of child's + * border. If not reparented then these are + * zero. */ + int configWidth, configHeight; + /* Dimensions passed to last request that we + * issued to change geometry of window. Used + * to eliminate redundant resize operations. */ + + /* + * Information about the virtual root window for this top-level, + * if there is one. + */ + + Window vRoot; /* Virtual root window for this top-level, + * or None if there is no virtual root + * window (i.e. just use the screen's root). */ + int vRootX, vRootY; /* Position of the virtual root inside the + * root window. If the WM_VROOT_OFFSET_STALE + * flag is set then this information may be + * incorrect and needs to be refreshed from + * the X server. If vRoot is None then these + * values are both 0. */ + unsigned int vRootWidth, vRootHeight; + /* Dimensions of the virtual root window. + * If vRoot is None, gives the dimensions + * of the containing screen. This information + * is never stale, even though vRootX and + * vRootY can be. */ + + /* + * List of children of the toplevel which have private colormaps. + */ + + TkWindow **cmapList; /* Array of window with private colormaps. */ + int cmapCount; /* Number of windows in array. */ + + /* + * Miscellaneous information. + */ + + ProtocolHandler *protPtr; /* First in list of protocol handlers for + * this window (NULL means none). */ + int cmdArgc; /* Number of elements in cmdArgv below. */ + char **cmdArgv; /* Array of strings to store in the + * WM_COMMAND property. NULL means nothing + * available. */ + char *clientMachine; /* String to store in WM_CLIENT_MACHINE + * property, or NULL. */ + int flags; /* Miscellaneous flags, defined below. */ + + /* + * Macintosh information. + */ + int style; /* Native window style. */ + TkWindow *scrollWinPtr; /* Ptr to scrollbar handling grow widget. */ +} WmInfo; + + +/* + * Flag values for WmInfo structures: + * + * WM_NEVER_MAPPED - non-zero means window has never been + * mapped; need to update all info when + * window is first mapped. + * WM_UPDATE_PENDING - non-zero means a call to UpdateGeometryInfo + * has already been scheduled for this + * window; no need to schedule another one. + * WM_NEGATIVE_X - non-zero means x-coordinate is measured in + * pixels from right edge of screen, rather + * than from left edge. + * WM_NEGATIVE_Y - non-zero means y-coordinate is measured in + * pixels up from bottom of screen, rather than + * down from top. + * WM_UPDATE_SIZE_HINTS - non-zero means that new size hints need to be + * propagated to window manager. + * WM_SYNC_PENDING - set to non-zero while waiting for the window + * manager to respond to some state change. + * WM_VROOT_OFFSET_STALE - non-zero means that (x,y) offset information + * about the virtual root window is stale and + * needs to be fetched fresh from the X server. + * WM_ABOUT_TO_MAP - non-zero means that the window is about to + * be mapped by TkWmMapWindow. This is used + * by UpdateGeometryInfo to modify its behavior. + * WM_MOVE_PENDING - non-zero means the application has requested + * a new position for the window, but it hasn't + * been reflected through the window manager + * yet. + * WM_COLORMAPS_EXPLICIT - non-zero means the colormap windows were + * set explicitly via "wm colormapwindows". + * WM_ADDED_TOPLEVEL_COLORMAP - non-zero means that when "wm colormapwindows" + * was called the top-level itself wasn't + * specified, so we added it implicitly at + * the end of the list. + * WM_WIDTH_NOT_RESIZABLE - non-zero means that we're not supposed to + * allow the user to change the width of the + * window (controlled by "wm resizable" + * command). + * WM_HEIGHT_NOT_RESIZABLE - non-zero means that we're not supposed to + * allow the user to change the height of the + * window (controlled by "wm resizable" + * command). + */ + +#define WM_NEVER_MAPPED 1 +#define WM_UPDATE_PENDING 2 +#define WM_NEGATIVE_X 4 +#define WM_NEGATIVE_Y 8 +#define WM_UPDATE_SIZE_HINTS 0x10 +#define WM_SYNC_PENDING 0x20 +#define WM_VROOT_OFFSET_STALE 0x40 +#define WM_ABOUT_TO_MAP 0x100 +#define WM_MOVE_PENDING 0x200 +#define WM_COLORMAPS_EXPLICIT 0x400 +#define WM_ADDED_TOPLEVEL_COLORMAP 0x800 +#define WM_WIDTH_NOT_RESIZABLE 0x1000 +#define WM_HEIGHT_NOT_RESIZABLE 0x2000 + +/* + * This is a list of all of the toplevels that have been mapped so far. It is + * used by the menu code to inval windows that were damaged by menus, and will + * eventually also be used to keep track of floating windows. + */ + +TkMacWindowList *tkMacWindowListPtr = NULL; + +/* + * The variable below is used to enable or disable tracing in this + * module. If tracing is enabled, then information is printed on + * standard output about interesting interactions with the window + * manager. + */ + +static int wmTracing = 0; + +/* + * The following structure is the official type record for geometry + * management of top-level windows. + */ + +static void TopLevelReqProc _ANSI_ARGS_((ClientData dummy, + Tk_Window tkwin)); + +static Tk_GeomMgr wmMgrType = { + "wm", /* name */ + TopLevelReqProc, /* requestProc */ + (Tk_GeomLostSlaveProc *) NULL, /* lostSlaveProc */ +}; + +/* + * Hash table for Mac Window -> TkWindow mapping. + */ + +static Tcl_HashTable windowTable; +static int windowHashInit = false; + +void MacMoveWindow(WindowRef window, int x, int y); + +/* + * Forward declarations for procedures defined in this file: + */ + +static int HaveAppearance _ANSI_ARGS_((void)); +static void InitialWindowBounds _ANSI_ARGS_((TkWindow *winPtr, + Rect *geometry)); +static int ParseGeometry _ANSI_ARGS_((Tcl_Interp *interp, + char *string, TkWindow *winPtr)); +static void TopLevelEventProc _ANSI_ARGS_((ClientData clientData, + XEvent *eventPtr)); +static void TopLevelReqProc _ANSI_ARGS_((ClientData dummy, + Tk_Window tkwin)); +static void UpdateGeometryInfo _ANSI_ARGS_(( + ClientData clientData)); +static void UpdateSizeHints _ANSI_ARGS_((TkWindow *winPtr)); +static void UpdateVRootGeometry _ANSI_ARGS_((WmInfo *wmPtr)); + +/* + *-------------------------------------------------------------- + * + * TkWmNewWindow -- + * + * This procedure is invoked whenever a new top-level + * window is created. Its job is to initialize the WmInfo + * structure for the window. + * + * Results: + * None. + * + * Side effects: + * A WmInfo structure gets allocated and initialized. + * + *-------------------------------------------------------------- + */ + +void +TkWmNewWindow( + TkWindow *winPtr) /* Newly-created top-level window. */ +{ + register WmInfo *wmPtr; + + wmPtr = (WmInfo *) ckalloc(sizeof(WmInfo)); + wmPtr->winPtr = winPtr; + wmPtr->reparent = None; + wmPtr->titleUid = NULL; + wmPtr->iconName = NULL; + wmPtr->master = None; + wmPtr->hints.flags = InputHint | StateHint; + wmPtr->hints.input = True; + wmPtr->hints.initial_state = NormalState; + wmPtr->hints.icon_pixmap = None; + wmPtr->hints.icon_window = None; + wmPtr->hints.icon_x = wmPtr->hints.icon_y = 0; + wmPtr->hints.icon_mask = None; + wmPtr->hints.window_group = None; + wmPtr->leaderName = NULL; + wmPtr->masterWindowName = NULL; + wmPtr->icon = NULL; + wmPtr->iconFor = NULL; + wmPtr->sizeHintsFlags = 0; + wmPtr->minWidth = wmPtr->minHeight = 1; + + /* + * Default the maximum dimensions to the size of the display, minus + * a guess about how space is needed for window manager decorations. + */ + + wmPtr->maxWidth = DisplayWidth(winPtr->display, winPtr->screenNum) - 15; + wmPtr->maxHeight = DisplayHeight(winPtr->display, winPtr->screenNum) - 30; + wmPtr->gridWin = NULL; + wmPtr->widthInc = wmPtr->heightInc = 1; + wmPtr->minAspect.x = wmPtr->minAspect.y = 1; + wmPtr->maxAspect.x = wmPtr->maxAspect.y = 1; + wmPtr->reqGridWidth = wmPtr->reqGridHeight = -1; + wmPtr->gravity = NorthWestGravity; + wmPtr->width = -1; + wmPtr->height = -1; + wmPtr->x = winPtr->changes.x; + wmPtr->y = winPtr->changes.y; + wmPtr->parentWidth = winPtr->changes.width + + 2*winPtr->changes.border_width; + wmPtr->parentHeight = winPtr->changes.height + + 2*winPtr->changes.border_width; + wmPtr->xInParent = 0; + wmPtr->yInParent = 0; + wmPtr->cmapList = NULL; + wmPtr->cmapCount = 0; + wmPtr->configWidth = -1; + wmPtr->configHeight = -1; + wmPtr->vRoot = None; + wmPtr->protPtr = NULL; + wmPtr->cmdArgv = NULL; + wmPtr->clientMachine = NULL; + wmPtr->flags = WM_NEVER_MAPPED; + wmPtr->style = zoomDocProc; + wmPtr->scrollWinPtr = NULL; + winPtr->wmInfoPtr = wmPtr; + + UpdateVRootGeometry(wmPtr); + + /* + * Tk must monitor structure events for top-level windows, in order + * to detect size and position changes caused by window managers. + */ + + Tk_CreateEventHandler((Tk_Window) winPtr, StructureNotifyMask, + TopLevelEventProc, (ClientData) winPtr); + + /* + * Arrange for geometry requests to be reflected from the window + * to the window manager. + */ + + Tk_ManageGeometry((Tk_Window) winPtr, &wmMgrType, (ClientData) 0); +} + +/* + *-------------------------------------------------------------- + * + * TkWmMapWindow -- + * + * This procedure is invoked to map a top-level window. This + * module gets a chance to update all window-manager-related + * information in properties before the window manager sees + * the map event and checks the properties. It also gets to + * decide whether or not to even map the window after all. + * + * Results: + * None. + * + * Side effects: + * Properties of winPtr may get updated to provide up-to-date + * information to the window manager. The window may also get + * mapped, but it may not be if this procedure decides that + * isn't appropriate (e.g. because the window is withdrawn). + * + *-------------------------------------------------------------- + */ + +void +TkWmMapWindow( + TkWindow *winPtr) /* Top-level window that's about to + * be mapped. */ +{ + register WmInfo *wmPtr = winPtr->wmInfoPtr; + Point where = {0, 0}; + int xOffset, yOffset; + int firstMap = false; + MacDrawable *macWin; + + if (wmPtr->flags & WM_NEVER_MAPPED) { + wmPtr->flags &= ~WM_NEVER_MAPPED; + firstMap = true; + + /* + * Create the underlying Mac window for this Tk window. + */ + macWin = (MacDrawable *) winPtr->window; + if (!TkMacHostToplevelExists(winPtr)) { + TkMacMakeRealWindowExist(winPtr); + } + + /* + * Generate configure event when we first map the window. + */ + LocalToGlobal(&where); + TkMacWindowOffset((WindowRef) TkMacGetDrawablePort((Drawable) macWin), + &xOffset, &yOffset); + where.h -= xOffset; + where.v -= yOffset; + TkGenWMConfigureEvent((Tk_Window) winPtr, + where.h, where.v, -1, -1, TK_LOCATION_CHANGED); + + /* + * This is the first time this window has ever been mapped. + * Store all the window-manager-related information for the + * window. + */ + + if (wmPtr->titleUid == NULL) { + wmPtr->titleUid = winPtr->nameUid; + } + + if (!Tk_IsEmbedded(winPtr)) { + TkSetWMName(winPtr, wmPtr->titleUid); + } + + TkWmSetClass(winPtr); + + if (wmPtr->iconName != NULL) { + XSetIconName(winPtr->display, winPtr->window, wmPtr->iconName); + } + + wmPtr->flags |= WM_UPDATE_SIZE_HINTS; + } + if (wmPtr->hints.initial_state == WithdrawnState) { + return; + } + + /* + * TODO: we need to display a window if it's iconic on creation. + */ + + if (wmPtr->hints.initial_state == IconicState) { + return; + } + + /* + * Update geometry information. + */ + wmPtr->flags |= WM_ABOUT_TO_MAP; + if (wmPtr->flags & WM_UPDATE_PENDING) { + Tk_CancelIdleCall(UpdateGeometryInfo, (ClientData) winPtr); + } + UpdateGeometryInfo((ClientData) winPtr); + wmPtr->flags &= ~WM_ABOUT_TO_MAP; + + /* + * Map the window. + */ + + XMapWindow(winPtr->display, winPtr->window); + + /* + * Now that the window is visable we can determine the offset + * from the window's content orgin to the window's decorative + * orgin (structure orgin). + */ + TkMacWindowOffset((WindowRef) TkMacGetDrawablePort(Tk_WindowId(winPtr)), + &wmPtr->xInParent, &wmPtr->yInParent); +} + +/* + *-------------------------------------------------------------- + * + * TkWmUnmapWindow -- + * + * This procedure is invoked to unmap a top-level window. + * On the Macintosh all we do is call XUnmapWindow. + * + * Results: + * None. + * + * Side effects: + * Unmaps the window. + * + *-------------------------------------------------------------- + */ + +void +TkWmUnmapWindow( + TkWindow *winPtr) /* Top-level window that's about to + * be mapped. */ +{ + XUnmapWindow(winPtr->display, winPtr->window); +} + +/* + *-------------------------------------------------------------- + * + * TkWmDeadWindow -- + * + * This procedure is invoked when a top-level window is + * about to be deleted. It cleans up the wm-related data + * structures for the window. + * + * Results: + * None. + * + * Side effects: + * The WmInfo structure for winPtr gets freed up. + * + *-------------------------------------------------------------- + */ + +void +TkWmDeadWindow(winPtr) + TkWindow *winPtr; /* Top-level window that's being deleted. */ +{ + register WmInfo *wmPtr = winPtr->wmInfoPtr; + WmInfo *wmPtr2; + + if (wmPtr == NULL) { + return; + } + if (wmPtr->hints.flags & IconPixmapHint) { + Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_pixmap); + } + if (wmPtr->hints.flags & IconMaskHint) { + Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_mask); + } + if (wmPtr->leaderName != NULL) { + ckfree(wmPtr->leaderName); + } + if (wmPtr->masterWindowName != NULL) { + ckfree(wmPtr->masterWindowName); + } + if (wmPtr->icon != NULL) { + wmPtr2 = ((TkWindow *) wmPtr->icon)->wmInfoPtr; + wmPtr2->iconFor = NULL; + } + if (wmPtr->iconFor != NULL) { + wmPtr2 = ((TkWindow *) wmPtr->iconFor)->wmInfoPtr; + wmPtr2->icon = NULL; + wmPtr2->hints.flags &= ~IconWindowHint; + } + while (wmPtr->protPtr != NULL) { + ProtocolHandler *protPtr; + + protPtr = wmPtr->protPtr; + wmPtr->protPtr = protPtr->nextPtr; + Tcl_EventuallyFree((ClientData) protPtr, TCL_DYNAMIC); + } + if (wmPtr->cmdArgv != NULL) { + ckfree((char *) wmPtr->cmdArgv); + } + if (wmPtr->clientMachine != NULL) { + ckfree((char *) wmPtr->clientMachine); + } + if (wmPtr->flags & WM_UPDATE_PENDING) { + Tk_CancelIdleCall(UpdateGeometryInfo, (ClientData) winPtr); + } + ckfree((char *) wmPtr); + winPtr->wmInfoPtr = NULL; +} + +/* + *-------------------------------------------------------------- + * + * TkWmSetClass -- + * + * This procedure is invoked whenever a top-level window's + * class is changed. If the window has been mapped then this + * procedure updates the window manager property for the + * class. If the window hasn't been mapped, the update is + * deferred until just before the first mapping. + * + * Results: + * None. + * + * Side effects: + * A window property may get updated. + * + *-------------------------------------------------------------- + */ + +void +TkWmSetClass( + TkWindow *winPtr) /* Newly-created top-level window. */ +{ + return; +} + +/* + *---------------------------------------------------------------------- + * + * Tk_WmCmd -- + * + * This procedure is invoked to process the "wm" Tcl command. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Tk_WmCmd( + ClientData clientData, /* Main window associated with + * interpreter. */ + Tcl_Interp *interp, /* Current interpreter. */ + int argc, /* Number of arguments. */ + char **argv) /* Argument strings. */ +{ + Tk_Window tkwin = (Tk_Window) clientData; + TkWindow *winPtr; + register WmInfo *wmPtr; + int c; + size_t length; + + if (argc < 2) { + wrongNumArgs: + Tcl_AppendResult(interp, "wrong # args: should be \"", + argv[0], " option window ?arg ...?\"", (char *) NULL); + return TCL_ERROR; + } + c = argv[1][0]; + length = strlen(argv[1]); + if ((c == 't') && (strncmp(argv[1], "tracing", length) == 0) + && (length >= 3)) { + if ((argc != 2) && (argc != 3)) { + Tcl_AppendResult(interp, "wrong # arguments: must be \"", + argv[0], " tracing ?boolean?\"", (char *) NULL); + return TCL_ERROR; + } + if (argc == 2) { + interp->result = (wmTracing) ? "on" : "off"; + return TCL_OK; + } + return Tcl_GetBoolean(interp, argv[2], &wmTracing); + } + + if (argc < 3) { + goto wrongNumArgs; + } + winPtr = (TkWindow *) Tk_NameToWindow(interp, argv[2], tkwin); + if (winPtr == NULL) { + return TCL_ERROR; + } + if (!(winPtr->flags & TK_TOP_LEVEL)) { + Tcl_AppendResult(interp, "window \"", winPtr->pathName, + "\" isn't a top-level window", (char *) NULL); + return TCL_ERROR; + } + wmPtr = winPtr->wmInfoPtr; + if ((c == 'a') && (strncmp(argv[1], "aspect", length) == 0)) { + int numer1, denom1, numer2, denom2; + + if ((argc != 3) && (argc != 7)) { + Tcl_AppendResult(interp, "wrong # arguments: must be \"", + argv[0], " aspect window ?minNumer minDenom ", + "maxNumer maxDenom?\"", (char *) NULL); + return TCL_ERROR; + } + if (argc == 3) { + if (wmPtr->sizeHintsFlags & PAspect) { + sprintf(interp->result, "%d %d %d %d", wmPtr->minAspect.x, + wmPtr->minAspect.y, wmPtr->maxAspect.x, + wmPtr->maxAspect.y); + } + return TCL_OK; + } + if (*argv[3] == '\0') { + wmPtr->sizeHintsFlags &= ~PAspect; + } else { + if ((Tcl_GetInt(interp, argv[3], &numer1) != TCL_OK) + || (Tcl_GetInt(interp, argv[4], &denom1) != TCL_OK) + || (Tcl_GetInt(interp, argv[5], &numer2) != TCL_OK) + || (Tcl_GetInt(interp, argv[6], &denom2) != TCL_OK)) { + return TCL_ERROR; + } + if ((numer1 <= 0) || (denom1 <= 0) || (numer2 <= 0) || + (denom2 <= 0)) { + interp->result = "aspect number can't be <= 0"; + return TCL_ERROR; + } + wmPtr->minAspect.x = numer1; + wmPtr->minAspect.y = denom1; + wmPtr->maxAspect.x = numer2; + wmPtr->maxAspect.y = denom2; + wmPtr->sizeHintsFlags |= PAspect; + } + wmPtr->flags |= WM_UPDATE_SIZE_HINTS; + goto updateGeom; + } else if ((c == 'c') && (strncmp(argv[1], "client", length) == 0) + && (length >= 2)) { + if ((argc != 3) && (argc != 4)) { + Tcl_AppendResult(interp, "wrong # arguments: must be \"", + argv[0], " client window ?name?\"", + (char *) NULL); + return TCL_ERROR; + } + if (argc == 3) { + if (wmPtr->clientMachine != NULL) { + interp->result = wmPtr->clientMachine; + } + return TCL_OK; + } + if (argv[3][0] == 0) { + if (wmPtr->clientMachine != NULL) { + ckfree((char *) wmPtr->clientMachine); + wmPtr->clientMachine = NULL; + } + return TCL_OK; + } + if (wmPtr->clientMachine != NULL) { + ckfree((char *) wmPtr->clientMachine); + } + wmPtr->clientMachine = (char *) + ckalloc((unsigned) (strlen(argv[3]) + 1)); + strcpy(wmPtr->clientMachine, argv[3]); + } else if ((c == 'c') && (strncmp(argv[1], "colormapwindows", length) == 0) + && (length >= 3)) { + TkWindow **cmapList; + TkWindow *winPtr2; + int i, windowArgc, gotToplevel; + char **windowArgv; + + if ((argc != 3) && (argc != 4)) { + Tcl_AppendResult(interp, "wrong # arguments: must be \"", + argv[0], " colormapwindows window ?windowList?\"", + (char *) NULL); + return TCL_ERROR; + } + if (argc == 3) { + Tk_MakeWindowExist((Tk_Window) winPtr); + for (i = 0; i < wmPtr->cmapCount; i++) { + if ((i == (wmPtr->cmapCount-1)) + && (wmPtr->flags & WM_ADDED_TOPLEVEL_COLORMAP)) { + break; + } + Tcl_AppendElement(interp, wmPtr->cmapList[i]->pathName); + } + return TCL_OK; + } + if (Tcl_SplitList(interp, argv[3], &windowArgc, &windowArgv) + != TCL_OK) { + return TCL_ERROR; + } + cmapList = (TkWindow **) ckalloc((unsigned) + ((windowArgc+1)*sizeof(TkWindow*))); + for (i = 0; i < windowArgc; i++) { + winPtr2 = (TkWindow *) Tk_NameToWindow(interp, windowArgv[i], + tkwin); + if (winPtr2 == NULL) { + ckfree((char *) cmapList); + ckfree((char *) windowArgv); + return TCL_ERROR; + } + if (winPtr2 == winPtr) { + gotToplevel = 1; + } + if (winPtr2->window == None) { + Tk_MakeWindowExist((Tk_Window) winPtr2); + } + cmapList[i] = winPtr2; + } + if (!gotToplevel) { + wmPtr->flags |= WM_ADDED_TOPLEVEL_COLORMAP; + cmapList[windowArgc] = winPtr; + windowArgc++; + } else { + wmPtr->flags &= ~WM_ADDED_TOPLEVEL_COLORMAP; + } + wmPtr->flags |= WM_COLORMAPS_EXPLICIT; + if (wmPtr->cmapList != NULL) { + ckfree((char *)wmPtr->cmapList); + } + wmPtr->cmapList = cmapList; + wmPtr->cmapCount = windowArgc; + ckfree((char *) windowArgv); + + /* + * On the Macintosh all of this is just an excercise + * in compatability as we don't support colormaps. If + * we did they would be installed here. + */ + + return TCL_OK; + } else if ((c == 'c') && (strncmp(argv[1], "command", length) == 0) + && (length >= 3)) { + int cmdArgc; + char **cmdArgv; + + if ((argc != 3) && (argc != 4)) { + Tcl_AppendResult(interp, "wrong # arguments: must be \"", + argv[0], " command window ?value?\"", + (char *) NULL); + return TCL_ERROR; + } + if (argc == 3) { + if (wmPtr->cmdArgv != NULL) { + interp->result = Tcl_Merge(wmPtr->cmdArgc, wmPtr->cmdArgv); + interp->freeProc = (Tcl_FreeProc *) free; + } + return TCL_OK; + } + if (argv[3][0] == 0) { + if (wmPtr->cmdArgv != NULL) { + ckfree((char *) wmPtr->cmdArgv); + wmPtr->cmdArgv = NULL; + } + return TCL_OK; + } + if (Tcl_SplitList(interp, argv[3], &cmdArgc, &cmdArgv) != TCL_OK) { + return TCL_ERROR; + } + if (wmPtr->cmdArgv != NULL) { + ckfree((char *) wmPtr->cmdArgv); + } + wmPtr->cmdArgc = cmdArgc; + wmPtr->cmdArgv = cmdArgv; + } else if ((c == 'd') && (strncmp(argv[1], "deiconify", length) == 0)) { + if (argc != 3) { + Tcl_AppendResult(interp, "wrong # arguments: must be \"", + argv[0], " deiconify window\"", (char *) NULL); + return TCL_ERROR; + } + if (wmPtr->iconFor != NULL) { + Tcl_AppendResult(interp, "can't deiconify ", argv[2], + ": it is an icon for ", winPtr->pathName, (char *) NULL); + return TCL_ERROR; + } + if (winPtr->flags & TK_EMBEDDED) { + Tcl_AppendResult(interp, "can't deiconify ", winPtr->pathName, + ": it is an embedded window", (char *) NULL); + return TCL_ERROR; + } + + /* + * TODO: may not want to call this function - look at Map events gened. + */ + + TkpWmSetState(winPtr, NormalState); + } else if ((c == 'f') && (strncmp(argv[1], "focusmodel", length) == 0) + && (length >= 2)) { + if ((argc != 3) && (argc != 4)) { + Tcl_AppendResult(interp, "wrong # arguments: must be \"", + argv[0], " focusmodel window ?active|passive?\"", + (char *) NULL); + return TCL_ERROR; + } + if (argc == 3) { + interp->result = wmPtr->hints.input ? "passive" : "active"; + return TCL_OK; + } + c = argv[3][0]; + length = strlen(argv[3]); + if ((c == 'a') && (strncmp(argv[3], "active", length) == 0)) { + wmPtr->hints.input = False; + } else if ((c == 'p') && (strncmp(argv[3], "passive", length) == 0)) { + wmPtr->hints.input = True; + } else { + Tcl_AppendResult(interp, "bad argument \"", argv[3], + "\": must be active or passive", (char *) NULL); + return TCL_ERROR; + } + } else if ((c == 'f') && (strncmp(argv[1], "frame", length) == 0) + && (length >= 2)) { + Window window; + + if (argc != 3) { + Tcl_AppendResult(interp, "wrong # arguments: must be \"", + argv[0], " frame window\"", (char *) NULL); + return TCL_ERROR; + } + window = wmPtr->reparent; + if (window == None) { + window = Tk_WindowId((Tk_Window) winPtr); + } + sprintf(interp->result, "0x%x", (unsigned int) window); + } else if ((c == 'g') && (strncmp(argv[1], "geometry", length) == 0) + && (length >= 2)) { + char xSign, ySign; + int width, height; + + if ((argc != 3) && (argc != 4)) { + Tcl_AppendResult(interp, "wrong # arguments: must be \"", + argv[0], " geometry window ?newGeometry?\"", + (char *) NULL); + return TCL_ERROR; + } + if (argc == 3) { + xSign = (wmPtr->flags & WM_NEGATIVE_X) ? '-' : '+'; + ySign = (wmPtr->flags & WM_NEGATIVE_Y) ? '-' : '+'; + if (wmPtr->gridWin != NULL) { + width = wmPtr->reqGridWidth + (winPtr->changes.width + - winPtr->reqWidth)/wmPtr->widthInc; + height = wmPtr->reqGridHeight + (winPtr->changes.height + - winPtr->reqHeight)/wmPtr->heightInc; + } else { + width = winPtr->changes.width; + height = winPtr->changes.height; + } + sprintf(interp->result, "%dx%d%c%d%c%d", width, height, + xSign, wmPtr->x, ySign, wmPtr->y); + return TCL_OK; + } + if (*argv[3] == '\0') { + wmPtr->width = -1; + wmPtr->height = -1; + goto updateGeom; + } + return ParseGeometry(interp, argv[3], winPtr); + } else if ((c == 'g') && (strncmp(argv[1], "grid", length) == 0) + && (length >= 3)) { + int reqWidth, reqHeight, widthInc, heightInc; + + if ((argc != 3) && (argc != 7)) { + Tcl_AppendResult(interp, "wrong # arguments: must be \"", + argv[0], " grid window ?baseWidth baseHeight ", + "widthInc heightInc?\"", (char *) NULL); + return TCL_ERROR; + } + if (argc == 3) { + if (wmPtr->sizeHintsFlags & PBaseSize) { + sprintf(interp->result, "%d %d %d %d", wmPtr->reqGridWidth, + wmPtr->reqGridHeight, wmPtr->widthInc, + wmPtr->heightInc); + } + return TCL_OK; + } + if (*argv[3] == '\0') { + /* + * Turn off gridding and reset the width and height + * to make sense as ungridded numbers. + */ + + wmPtr->sizeHintsFlags &= ~(PBaseSize|PResizeInc); + if (wmPtr->width != -1) { + wmPtr->width = winPtr->reqWidth + (wmPtr->width + - wmPtr->reqGridWidth)*wmPtr->widthInc; + wmPtr->height = winPtr->reqHeight + (wmPtr->height + - wmPtr->reqGridHeight)*wmPtr->heightInc; + } + wmPtr->widthInc = 1; + wmPtr->heightInc = 1; + } else { + if ((Tcl_GetInt(interp, argv[3], &reqWidth) != TCL_OK) + || (Tcl_GetInt(interp, argv[4], &reqHeight) != TCL_OK) + || (Tcl_GetInt(interp, argv[5], &widthInc) != TCL_OK) + || (Tcl_GetInt(interp, argv[6], &heightInc) != TCL_OK)) { + return TCL_ERROR; + } + if (reqWidth < 0) { + interp->result = "baseWidth can't be < 0"; + return TCL_ERROR; + } + if (reqHeight < 0) { + interp->result = "baseHeight can't be < 0"; + return TCL_ERROR; + } + if (widthInc < 0) { + interp->result = "widthInc can't be < 0"; + return TCL_ERROR; + } + if (heightInc < 0) { + interp->result = "heightInc can't be < 0"; + return TCL_ERROR; + } + Tk_SetGrid((Tk_Window) winPtr, reqWidth, reqHeight, widthInc, + heightInc); + } + wmPtr->flags |= WM_UPDATE_SIZE_HINTS; + goto updateGeom; + } else if ((c == 'g') && (strncmp(argv[1], "group", length) == 0) + && (length >= 3)) { + Tk_Window tkwin2; + + if ((argc != 3) && (argc != 4)) { + Tcl_AppendResult(interp, "wrong # arguments: must be \"", + argv[0], " group window ?pathName?\"", + (char *) NULL); + return TCL_ERROR; + } + if (argc == 3) { + if (wmPtr->hints.flags & WindowGroupHint) { + interp->result = wmPtr->leaderName; + } + return TCL_OK; + } + if (*argv[3] == '\0') { + wmPtr->hints.flags &= ~WindowGroupHint; + if (wmPtr->leaderName != NULL) { + ckfree(wmPtr->leaderName); + } + wmPtr->leaderName = NULL; + } else { + tkwin2 = Tk_NameToWindow(interp, argv[3], tkwin); + if (tkwin2 == NULL) { + return TCL_ERROR; + } + Tk_MakeWindowExist(tkwin2); + wmPtr->hints.window_group = Tk_WindowId(tkwin2); + wmPtr->hints.flags |= WindowGroupHint; + wmPtr->leaderName = ckalloc((unsigned) (strlen(argv[3])+1)); + strcpy(wmPtr->leaderName, argv[3]); + } + } else if ((c == 'i') && (strncmp(argv[1], "iconbitmap", length) == 0) + && (length >= 5)) { + Pixmap pixmap; + + if ((argc != 3) && (argc != 4)) { + Tcl_AppendResult(interp, "wrong # arguments: must be \"", + argv[0], " iconbitmap window ?bitmap?\"", + (char *) NULL); + return TCL_ERROR; + } + if (argc == 3) { + if (wmPtr->hints.flags & IconPixmapHint) { + interp->result = Tk_NameOfBitmap(winPtr->display, + wmPtr->hints.icon_pixmap); + } + return TCL_OK; + } + if (*argv[3] == '\0') { + if (wmPtr->hints.icon_pixmap != None) { + Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_pixmap); + } + wmPtr->hints.flags &= ~IconPixmapHint; + } else { + pixmap = Tk_GetBitmap(interp, (Tk_Window) winPtr, + Tk_GetUid(argv[3])); + if (pixmap == None) { + return TCL_ERROR; + } + wmPtr->hints.icon_pixmap = pixmap; + wmPtr->hints.flags |= IconPixmapHint; + } + } else if ((c == 'i') && (strncmp(argv[1], "iconify", length) == 0) + && (length >= 5)) { + if (argc != 3) { + Tcl_AppendResult(interp, "wrong # arguments: must be \"", + argv[0], " iconify window\"", (char *) NULL); + return TCL_ERROR; + } + if (Tk_Attributes((Tk_Window) winPtr)->override_redirect) { + Tcl_AppendResult(interp, "can't iconify \"", winPtr->pathName, + "\": override-redirect flag is set", (char *) NULL); + return TCL_ERROR; + } + if (wmPtr->master != None) { + Tcl_AppendResult(interp, "can't iconify \"", winPtr->pathName, + "\": it is a transient", (char *) NULL); + return TCL_ERROR; + } + if (wmPtr->iconFor != NULL) { + Tcl_AppendResult(interp, "can't iconify ", argv[2], + ": it is an icon for ", Tk_PathName(wmPtr->iconFor), + (char *) NULL); + return TCL_ERROR; + } + if (winPtr->flags & TK_EMBEDDED) { + Tcl_AppendResult(interp, "can't iconify ", winPtr->pathName, + ": it is an embedded window", (char *) NULL); + return TCL_ERROR; + } + TkpWmSetState(winPtr, IconicState); + } else if ((c == 'i') && (strncmp(argv[1], "iconmask", length) == 0) + && (length >= 5)) { + Pixmap pixmap; + + if ((argc != 3) && (argc != 4)) { + Tcl_AppendResult(interp, "wrong # arguments: must be \"", + argv[0], " iconmask window ?bitmap?\"", + (char *) NULL); + return TCL_ERROR; + } + if (argc == 3) { + if (wmPtr->hints.flags & IconMaskHint) { + interp->result = Tk_NameOfBitmap(winPtr->display, + wmPtr->hints.icon_mask); + } + return TCL_OK; + } + if (*argv[3] == '\0') { + if (wmPtr->hints.icon_mask != None) { + Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_mask); + } + wmPtr->hints.flags &= ~IconMaskHint; + } else { + pixmap = Tk_GetBitmap(interp, tkwin, Tk_GetUid(argv[3])); + if (pixmap == None) { + return TCL_ERROR; + } + wmPtr->hints.icon_mask = pixmap; + wmPtr->hints.flags |= IconMaskHint; + } + } else if ((c == 'i') && (strncmp(argv[1], "iconname", length) == 0) + && (length >= 5)) { + if (argc > 4) { + Tcl_AppendResult(interp, "wrong # arguments: must be \"", + argv[0], " iconname window ?newName?\"", (char *) NULL); + return TCL_ERROR; + } + if (argc == 3) { + interp->result = (wmPtr->iconName != NULL) ? wmPtr->iconName : ""; + return TCL_OK; + } else { + wmPtr->iconName = Tk_GetUid(argv[3]); + if (!(wmPtr->flags & WM_NEVER_MAPPED)) { + XSetIconName(winPtr->display, winPtr->window, wmPtr->iconName); + } + } + } else if ((c == 'i') && (strncmp(argv[1], "iconposition", length) == 0) + && (length >= 5)) { + int x, y; + + if ((argc != 3) && (argc != 5)) { + Tcl_AppendResult(interp, "wrong # arguments: must be \"", + argv[0], " iconposition window ?x y?\"", + (char *) NULL); + return TCL_ERROR; + } + if (argc == 3) { + if (wmPtr->hints.flags & IconPositionHint) { + sprintf(interp->result, "%d %d", wmPtr->hints.icon_x, + wmPtr->hints.icon_y); + } + return TCL_OK; + } + if (*argv[3] == '\0') { + wmPtr->hints.flags &= ~IconPositionHint; + } else { + if ((Tcl_GetInt(interp, argv[3], &x) != TCL_OK) + || (Tcl_GetInt(interp, argv[4], &y) != TCL_OK)){ + return TCL_ERROR; + } + wmPtr->hints.icon_x = x; + wmPtr->hints.icon_y = y; + wmPtr->hints.flags |= IconPositionHint; + } + } else if ((c == 'i') && (strncmp(argv[1], "iconwindow", length) == 0) + && (length >= 5)) { + Tk_Window tkwin2; + WmInfo *wmPtr2; + + if ((argc != 3) && (argc != 4)) { + Tcl_AppendResult(interp, "wrong # arguments: must be \"", + argv[0], " iconwindow window ?pathName?\"", + (char *) NULL); + return TCL_ERROR; + } + if (argc == 3) { + if (wmPtr->icon != NULL) { + interp->result = Tk_PathName(wmPtr->icon); + } + return TCL_OK; + } + if (*argv[3] == '\0') { + wmPtr->hints.flags &= ~IconWindowHint; + if (wmPtr->icon != NULL) { + wmPtr2 = ((TkWindow *) wmPtr->icon)->wmInfoPtr; + wmPtr2->iconFor = NULL; + wmPtr2->hints.initial_state = WithdrawnState; + } + wmPtr->icon = NULL; + } else { + tkwin2 = Tk_NameToWindow(interp, argv[3], tkwin); + if (tkwin2 == NULL) { + return TCL_ERROR; + } + if (!Tk_IsTopLevel(tkwin2)) { + Tcl_AppendResult(interp, "can't use ", argv[3], + " as icon window: not at top level", (char *) NULL); + return TCL_ERROR; + } + wmPtr2 = ((TkWindow *) tkwin2)->wmInfoPtr; + if (wmPtr2->iconFor != NULL) { + Tcl_AppendResult(interp, argv[3], " is already an icon for ", + Tk_PathName(wmPtr2->iconFor), (char *) NULL); + return TCL_ERROR; + } + if (wmPtr->icon != NULL) { + WmInfo *wmPtr3 = ((TkWindow *) wmPtr->icon)->wmInfoPtr; + wmPtr3->iconFor = NULL; + } + Tk_MakeWindowExist(tkwin2); + wmPtr->hints.icon_window = Tk_WindowId(tkwin2); + wmPtr->hints.flags |= IconWindowHint; + wmPtr->icon = tkwin2; + wmPtr2->iconFor = (Tk_Window) winPtr; + if (!(wmPtr2->flags & WM_NEVER_MAPPED)) { + /* + * Don't have iconwindows on the Mac. We just withdraw. + */ + + Tk_UnmapWindow(tkwin2); + } + } + } else if ((c == 'm') && (strncmp(argv[1], "maxsize", length) == 0) + && (length >= 2)) { + int width, height; + if ((argc != 3) && (argc != 5)) { + Tcl_AppendResult(interp, "wrong # arguments: must be \"", + argv[0], " maxsize window ?width height?\"", (char *) NULL); + return TCL_ERROR; + } + if (argc == 3) { + sprintf(interp->result, "%d %d", wmPtr->maxWidth, + wmPtr->maxHeight); + return TCL_OK; + } + if ((Tcl_GetInt(interp, argv[3], &width) != TCL_OK) + || (Tcl_GetInt(interp, argv[4], &height) != TCL_OK)) { + return TCL_ERROR; + } + wmPtr->maxWidth = width; + wmPtr->maxHeight = height; + wmPtr->flags |= WM_UPDATE_SIZE_HINTS; + goto updateGeom; + } else if ((c == 'm') && (strncmp(argv[1], "minsize", length) == 0) + && (length >= 2)) { + int width, height; + if ((argc != 3) && (argc != 5)) { + Tcl_AppendResult(interp, "wrong # arguments: must be \"", + argv[0], " minsize window ?width height?\"", (char *) NULL); + return TCL_ERROR; + } + if (argc == 3) { + sprintf(interp->result, "%d %d", wmPtr->minWidth, + wmPtr->minHeight); + return TCL_OK; + } + if ((Tcl_GetInt(interp, argv[3], &width) != TCL_OK) + || (Tcl_GetInt(interp, argv[4], &height) != TCL_OK)) { + return TCL_ERROR; + } + wmPtr->minWidth = width; + wmPtr->minHeight = height; + wmPtr->flags |= WM_UPDATE_SIZE_HINTS; + goto updateGeom; + } else if ((c == 'o') + && (strncmp(argv[1], "overrideredirect", length) == 0)) { + int boolean; + XSetWindowAttributes atts; + + if ((argc != 3) && (argc != 4)) { + Tcl_AppendResult(interp, "wrong # arguments: must be \"", + argv[0], " overrideredirect window ?boolean?\"", + (char *) NULL); + return TCL_ERROR; + } + if (argc == 3) { + if (Tk_Attributes((Tk_Window) winPtr)->override_redirect) { + interp->result = "1"; + } else { + interp->result = "0"; + } + return TCL_OK; + } + if (Tcl_GetBoolean(interp, argv[3], &boolean) != TCL_OK) { + return TCL_ERROR; + } + atts.override_redirect = (boolean) ? True : False; + Tk_ChangeWindowAttributes((Tk_Window) winPtr, CWOverrideRedirect, + &atts); + wmPtr->style = (boolean) ? plainDBox : documentProc; + } else if ((c == 'p') && (strncmp(argv[1], "positionfrom", length) == 0) + && (length >= 2)) { + if ((argc != 3) && (argc != 4)) { + Tcl_AppendResult(interp, "wrong # arguments: must be \"", + argv[0], " positionfrom window ?user/program?\"", + (char *) NULL); + return TCL_ERROR; + } + if (argc == 3) { + if (wmPtr->sizeHintsFlags & USPosition) { + interp->result = "user"; + } else if (wmPtr->sizeHintsFlags & PPosition) { + interp->result = "program"; + } + return TCL_OK; + } + if (*argv[3] == '\0') { + wmPtr->sizeHintsFlags &= ~(USPosition|PPosition); + } else { + c = argv[3][0]; + length = strlen(argv[3]); + if ((c == 'u') && (strncmp(argv[3], "user", length) == 0)) { + wmPtr->sizeHintsFlags &= ~PPosition; + wmPtr->sizeHintsFlags |= USPosition; + } else if ((c == 'p') && + (strncmp(argv[3], "program", length) == 0)) { + wmPtr->sizeHintsFlags &= ~USPosition; + wmPtr->sizeHintsFlags |= PPosition; + } else { + Tcl_AppendResult(interp, "bad argument \"", argv[3], + "\": must be program or user", (char *) NULL); + return TCL_ERROR; + } + } + wmPtr->flags |= WM_UPDATE_SIZE_HINTS; + goto updateGeom; + } else if ((c == 'p') && (strncmp(argv[1], "protocol", length) == 0) + && (length >= 2)) { + register ProtocolHandler *protPtr, *prevPtr; + Atom protocol; + int cmdLength; + + if ((argc < 3) || (argc > 5)) { + Tcl_AppendResult(interp, "wrong # arguments: must be \"", + argv[0], " protocol window ?name? ?command?\"", + (char *) NULL); + return TCL_ERROR; + } + if (argc == 3) { + /* + * Return a list of all defined protocols for the window. + */ + for (protPtr = wmPtr->protPtr; protPtr != NULL; + protPtr = protPtr->nextPtr) { + Tcl_AppendElement(interp, + Tk_GetAtomName((Tk_Window) winPtr, protPtr->protocol)); + } + return TCL_OK; + } + protocol = Tk_InternAtom((Tk_Window) winPtr, argv[3]); + if (argc == 4) { + /* + * Return the command to handle a given protocol. + */ + for (protPtr = wmPtr->protPtr; protPtr != NULL; + protPtr = protPtr->nextPtr) { + if (protPtr->protocol == protocol) { + interp->result = protPtr->command; + return TCL_OK; + } + } + return TCL_OK; + } + + /* + * Delete any current protocol handler, then create a new + * one with the specified command, unless the command is + * empty. + */ + + for (protPtr = wmPtr->protPtr, prevPtr = NULL; protPtr != NULL; + prevPtr = protPtr, protPtr = protPtr->nextPtr) { + if (protPtr->protocol == protocol) { + if (prevPtr == NULL) { + wmPtr->protPtr = protPtr->nextPtr; + } else { + prevPtr->nextPtr = protPtr->nextPtr; + } + Tcl_EventuallyFree((ClientData) protPtr, TCL_DYNAMIC); + break; + } + } + cmdLength = strlen(argv[4]); + if (cmdLength > 0) { + protPtr = (ProtocolHandler *) ckalloc(HANDLER_SIZE(cmdLength)); + protPtr->protocol = protocol; + protPtr->nextPtr = wmPtr->protPtr; + wmPtr->protPtr = protPtr; + protPtr->interp = interp; + strcpy(protPtr->command, argv[4]); + } + } else if ((c == 'r') && (strncmp(argv[1], "resizable", length) == 0)) { + int width, height; + + if ((argc != 3) && (argc != 5)) { + Tcl_AppendResult(interp, "wrong # arguments: must be \"", + argv[0], " resizable window ?width height?\"", + (char *) NULL); + return TCL_ERROR; + } + if (argc == 3) { + sprintf(interp->result, "%d %d", + (wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) ? 0 : 1, + (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE) ? 0 : 1); + return TCL_OK; + } + if ((Tcl_GetBoolean(interp, argv[3], &width) != TCL_OK) + || (Tcl_GetBoolean(interp, argv[4], &height) != TCL_OK)) { + return TCL_ERROR; + } + if (width) { + wmPtr->flags &= ~WM_WIDTH_NOT_RESIZABLE; + } else { + wmPtr->flags |= WM_WIDTH_NOT_RESIZABLE; + } + if (height) { + wmPtr->flags &= ~WM_HEIGHT_NOT_RESIZABLE; + } else { + wmPtr->flags |= WM_HEIGHT_NOT_RESIZABLE; + } + wmPtr->flags |= WM_UPDATE_SIZE_HINTS; + if (wmPtr->scrollWinPtr != NULL) { + TkScrollbarEventuallyRedraw( + (TkScrollbar *) wmPtr->scrollWinPtr->instanceData); + } + goto updateGeom; + } else if ((c == 's') && (strncmp(argv[1], "sizefrom", length) == 0) + && (length >= 2)) { + if ((argc != 3) && (argc != 4)) { + Tcl_AppendResult(interp, "wrong # arguments: must be \"", + argv[0], " sizefrom window ?user|program?\"", + (char *) NULL); + return TCL_ERROR; + } + if (argc == 3) { + if (wmPtr->sizeHintsFlags & USSize) { + interp->result = "user"; + } else if (wmPtr->sizeHintsFlags & PSize) { + interp->result = "program"; + } + return TCL_OK; + } + if (*argv[3] == '\0') { + wmPtr->sizeHintsFlags &= ~(USSize|PSize); + } else { + c = argv[3][0]; + length = strlen(argv[3]); + if ((c == 'u') && (strncmp(argv[3], "user", length) == 0)) { + wmPtr->sizeHintsFlags &= ~PSize; + wmPtr->sizeHintsFlags |= USSize; + } else if ((c == 'p') + && (strncmp(argv[3], "program", length) == 0)) { + wmPtr->sizeHintsFlags &= ~USSize; + wmPtr->sizeHintsFlags |= PSize; + } else { + Tcl_AppendResult(interp, "bad argument \"", argv[3], + "\": must be program or user", (char *) NULL); + return TCL_ERROR; + } + } + wmPtr->flags |= WM_UPDATE_SIZE_HINTS; + goto updateGeom; + } else if ((c == 's') && (strncmp(argv[1], "state", length) == 0) + && (length >= 2)) { + if (argc != 3) { + Tcl_AppendResult(interp, "wrong # arguments: must be \"", + argv[0], " state window\"", (char *) NULL); + return TCL_ERROR; + } + if (wmPtr->iconFor != NULL) { + interp->result = "icon"; + } else { + switch (wmPtr->hints.initial_state) { + case NormalState: + interp->result = "normal"; + break; + case IconicState: + interp->result = "iconic"; + break; + case WithdrawnState: + interp->result = "withdrawn"; + break; + case ZoomState: + interp->result = "zoomed"; + break; + } + } + } else if ((c == 't') && (strncmp(argv[1], "title", length) == 0) + && (length >= 2)) { + if (argc > 4) { + Tcl_AppendResult(interp, "wrong # arguments: must be \"", + argv[0], " title window ?newTitle?\"", (char *) NULL); + return TCL_ERROR; + } + if (argc == 3) { + interp->result = (wmPtr->titleUid != NULL) ? wmPtr->titleUid + : winPtr->nameUid; + return TCL_OK; + } else { + wmPtr->titleUid = Tk_GetUid(argv[3]); + if (!(wmPtr->flags & WM_NEVER_MAPPED) && !Tk_IsEmbedded(winPtr)) { + TkSetWMName(winPtr, wmPtr->titleUid); + } + } + } else if ((c == 't') && (strncmp(argv[1], "transient", length) == 0) + && (length >= 3)) { + Tk_Window master; + + if ((argc != 3) && (argc != 4)) { + Tcl_AppendResult(interp, "wrong # arguments: must be \"", + argv[0], " transient window ?master?\"", (char *) NULL); + return TCL_ERROR; + } + if (argc == 3) { + if (wmPtr->master != None) { + interp->result = wmPtr->masterWindowName; + } + return TCL_OK; + } + if (argv[3][0] == '\0') { + wmPtr->master = None; + if (wmPtr->masterWindowName != NULL) { + ckfree(wmPtr->masterWindowName); + } + wmPtr->masterWindowName = NULL; + wmPtr->style = documentProc; + } else { + master = Tk_NameToWindow(interp, argv[3], tkwin); + if (master == NULL) { + return TCL_ERROR; + } + Tk_MakeWindowExist(master); + wmPtr->master = Tk_WindowId(master); + wmPtr->masterWindowName = ckalloc((unsigned) (strlen(argv[3])+1)); + strcpy(wmPtr->masterWindowName, argv[3]); + wmPtr->style = plainDBox; + } + } else if ((c == 'w') && (strncmp(argv[1], "withdraw", length) == 0)) { + if (argc != 3) { + Tcl_AppendResult(interp, "wrong # arguments: must be \"", + argv[0], " withdraw window\"", (char *) NULL); + return TCL_ERROR; + } + if (wmPtr->iconFor != NULL) { + Tcl_AppendResult(interp, "can't withdraw ", argv[2], + ": it is an icon for ", Tk_PathName(wmPtr->iconFor), + (char *) NULL); + return TCL_ERROR; + } + TkpWmSetState(winPtr, WithdrawnState); + } else { + Tcl_AppendResult(interp, "unknown or ambiguous option \"", argv[1], + "\": must be aspect, client, command, deiconify, ", + "focusmodel, frame, geometry, grid, group, iconbitmap, ", + "iconify, iconmask, iconname, iconposition, ", + "iconwindow, maxsize, minsize, overrideredirect, ", + "positionfrom, protocol, resizable, sizefrom, state, title, ", + "transient, or withdraw", + (char *) NULL); + return TCL_ERROR; + } + return TCL_OK; + + updateGeom: + if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) { + Tk_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr); + wmPtr->flags |= WM_UPDATE_PENDING; + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * Tk_SetGrid -- + * + * This procedure is invoked by a widget when it wishes to set a grid + * coordinate system that controls the size of a top-level window. + * It provides a C interface equivalent to the "wm grid" command and + * is usually asscoiated with the -setgrid option. + * + * Results: + * None. + * + * Side effects: + * Grid-related information will be passed to the window manager, so + * that the top-level window associated with tkwin will resize on + * even grid units. If some other window already controls gridding + * for the top-level window then this procedure call has no effect. + * + *---------------------------------------------------------------------- + */ + +void +Tk_SetGrid( + Tk_Window tkwin, /* Token for window. New window mgr info + * will be posted for the top-level window + * associated with this window. */ + int reqWidth, /* Width (in grid units) corresponding to + * the requested geometry for tkwin. */ + int reqHeight, /* Height (in grid units) corresponding to + * the requested geometry for tkwin. */ + int widthInc, int heightInc)/* Pixel increments corresponding to a + * change of one grid unit. */ +{ + TkWindow *winPtr = (TkWindow *) tkwin; + register WmInfo *wmPtr; + + /* + * Find the top-level window for tkwin, plus the window manager + * information. + */ + + while (!(winPtr->flags & TK_TOP_LEVEL)) { + winPtr = winPtr->parentPtr; + } + wmPtr = winPtr->wmInfoPtr; + + if ((wmPtr->gridWin != NULL) && (wmPtr->gridWin != tkwin)) { + return; + } + + if ((wmPtr->reqGridWidth == reqWidth) + && (wmPtr->reqGridHeight == reqHeight) + && (wmPtr->widthInc == widthInc) + && (wmPtr->heightInc == heightInc) + && ((wmPtr->sizeHintsFlags & (PBaseSize|PResizeInc)) + == PBaseSize|PResizeInc)) { + return; + } + + /* + * If gridding was previously off, then forget about any window + * size requests made by the user or via "wm geometry": these are + * in pixel units and there's no easy way to translate them to + * grid units since the new requested size of the top-level window in + * pixels may not yet have been registered yet (it may filter up + * the hierarchy in DoWhenIdle handlers). However, if the window + * has never been mapped yet then just leave the window size alone: + * assume that it is intended to be in grid units but just happened + * to have been specified before this procedure was called. + */ + + if ((wmPtr->gridWin == NULL) && !(wmPtr->flags & WM_NEVER_MAPPED)) { + wmPtr->width = -1; + wmPtr->height = -1; + } + + /* + * Set the new gridding information, and start the process of passing + * all of this information to the window manager. + */ + + wmPtr->gridWin = tkwin; + wmPtr->reqGridWidth = reqWidth; + wmPtr->reqGridHeight = reqHeight; + wmPtr->widthInc = widthInc; + wmPtr->heightInc = heightInc; + wmPtr->sizeHintsFlags |= PBaseSize|PResizeInc; + wmPtr->flags |= WM_UPDATE_SIZE_HINTS; + if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) { + Tk_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr); + wmPtr->flags |= WM_UPDATE_PENDING; + } +} + +/* + *---------------------------------------------------------------------- + * + * Tk_UnsetGrid -- + * + * This procedure cancels the effect of a previous call + * to Tk_SetGrid. + * + * Results: + * None. + * + * Side effects: + * If tkwin currently controls gridding for its top-level window, + * gridding is cancelled for that top-level window; if some other + * window controls gridding then this procedure has no effect. + * + *---------------------------------------------------------------------- + */ + +void +Tk_UnsetGrid( + Tk_Window tkwin) /* Token for window that is currently + * controlling gridding. */ +{ + TkWindow *winPtr = (TkWindow *) tkwin; + register WmInfo *wmPtr; + + /* + * Find the top-level window for tkwin, plus the window manager + * information. + */ + + while (!(winPtr->flags & TK_TOP_LEVEL)) { + winPtr = winPtr->parentPtr; + } + wmPtr = winPtr->wmInfoPtr; + if (tkwin != wmPtr->gridWin) { + return; + } + + wmPtr->gridWin = NULL; + wmPtr->sizeHintsFlags &= ~(PBaseSize|PResizeInc); + if (wmPtr->width != -1) { + wmPtr->width = winPtr->reqWidth + (wmPtr->width + - wmPtr->reqGridWidth)*wmPtr->widthInc; + wmPtr->height = winPtr->reqHeight + (wmPtr->height + - wmPtr->reqGridHeight)*wmPtr->heightInc; + } + wmPtr->widthInc = 1; + wmPtr->heightInc = 1; + + wmPtr->flags |= WM_UPDATE_SIZE_HINTS; + if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) { + Tk_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr); + wmPtr->flags |= WM_UPDATE_PENDING; + } +} + +/* + *---------------------------------------------------------------------- + * + * TopLevelEventProc -- + * + * This procedure is invoked when a top-level (or other externally- + * managed window) is restructured in any way. + * + * Results: + * None. + * + * Side effects: + * Tk's internal data structures for the window get modified to + * reflect the structural change. + * + *---------------------------------------------------------------------- + */ + +static void +TopLevelEventProc( + ClientData clientData, /* Window for which event occurred. */ + XEvent *eventPtr) /* Event that just happened. */ +{ + register TkWindow *winPtr = (TkWindow *) clientData; + + winPtr->wmInfoPtr->flags |= WM_VROOT_OFFSET_STALE; + if (eventPtr->type == DestroyNotify) { + Tk_ErrorHandler handler; + + if (!(winPtr->flags & TK_ALREADY_DEAD)) { + /* + * A top-level window was deleted externally (e.g., by the window + * manager). This is probably not a good thing, but cleanup as + * best we can. The error handler is needed because + * Tk_DestroyWindow will try to destroy the window, but of course + * it's already gone. + */ + + handler = Tk_CreateErrorHandler(winPtr->display, -1, -1, -1, + (Tk_ErrorProc *) NULL, (ClientData) NULL); + Tk_DestroyWindow((Tk_Window) winPtr); + Tk_DeleteErrorHandler(handler); + } + if (wmTracing) { + printf("TopLevelEventProc: %s deleted\n", winPtr->pathName); + } + } else if (eventPtr->type == ReparentNotify) { + panic("recieved unwanted reparent event"); + } +} + +/* + *---------------------------------------------------------------------- + * + * TopLevelReqProc -- + * + * This procedure is invoked by the geometry manager whenever + * the requested size for a top-level window is changed. + * + * Results: + * None. + * + * Side effects: + * Arrange for the window to be resized to satisfy the request + * (this happens as a when-idle action). + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +static void +TopLevelReqProc( + ClientData dummy, /* Not used. */ + Tk_Window tkwin) /* Information about window. */ +{ + TkWindow *winPtr = (TkWindow *) tkwin; + WmInfo *wmPtr; + + wmPtr = winPtr->wmInfoPtr; + wmPtr->flags |= WM_UPDATE_SIZE_HINTS; + if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) { + Tk_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr); + wmPtr->flags |= WM_UPDATE_PENDING; + } +} + +/* + *---------------------------------------------------------------------- + * + * UpdateGeometryInfo -- + * + * This procedure is invoked when a top-level window is first + * mapped, and also as a when-idle procedure, to bring the + * geometry and/or position of a top-level window back into + * line with what has been requested by the user and/or widgets. + * This procedure doesn't return until the window manager has + * responded to the geometry change. + * + * Results: + * None. + * + * Side effects: + * The window's size and location may change, unless the WM prevents + * that from happening. + * + *---------------------------------------------------------------------- + */ + +static void +UpdateGeometryInfo( + ClientData clientData) /* Pointer to the window's record. */ +{ + register TkWindow *winPtr = (TkWindow *) clientData; + register WmInfo *wmPtr = winPtr->wmInfoPtr; + int x, y, width, height; + unsigned long serial; + + wmPtr->flags &= ~WM_UPDATE_PENDING; + + /* + * Compute the new size for the top-level window. See the + * user documentation for details on this, but the size + * requested depends on (a) the size requested internally + * by the window's widgets, (b) the size requested by the + * user in a "wm geometry" command or via wm-based interactive + * resizing (if any), and (c) whether or not the window is + * gridded. Don't permit sizes <= 0 because this upsets + * the X server. + */ + + if (wmPtr->width == -1) { + width = winPtr->reqWidth; + } else if (wmPtr->gridWin != NULL) { + width = winPtr->reqWidth + + (wmPtr->width - wmPtr->reqGridWidth)*wmPtr->widthInc; + } else { + width = wmPtr->width; + } + if (width <= 0) { + width = 1; + } + if (wmPtr->height == -1) { + height = winPtr->reqHeight; + } else if (wmPtr->gridWin != NULL) { + height = winPtr->reqHeight + + (wmPtr->height - wmPtr->reqGridHeight)*wmPtr->heightInc; + } else { + height = wmPtr->height; + } + if (height <= 0) { + height = 1; + } + + /* + * Compute the new position for the upper-left pixel of the window's + * decorative frame. This is tricky, because we need to include the + * border widths supplied by a reparented parent in this calculation, + * but can't use the parent's current overall size since that may + * change as a result of this code. + */ + + if (wmPtr->flags & WM_NEGATIVE_X) { + x = wmPtr->vRootWidth - wmPtr->x + - (width + (wmPtr->parentWidth - winPtr->changes.width)); + } else { + x = wmPtr->x; + } + if (wmPtr->flags & WM_NEGATIVE_Y) { + y = wmPtr->vRootHeight - wmPtr->y + - (height + (wmPtr->parentHeight - winPtr->changes.height)); + } else { + y = wmPtr->y; + } + + /* + * If the window's size is going to change and the window is + * supposed to not be resizable by the user, then we have to + * update the size hints. There may also be a size-hint-update + * request pending from somewhere else, too. + */ + + if (((width != winPtr->changes.width) + || (height != winPtr->changes.height)) + && (wmPtr->gridWin == NULL) + && ((wmPtr->sizeHintsFlags & (PMinSize|PMaxSize)) == 0)) { + wmPtr->flags |= WM_UPDATE_SIZE_HINTS; + } + if (wmPtr->flags & WM_UPDATE_SIZE_HINTS) { + UpdateSizeHints(winPtr); + } + + /* + * Reconfigure the window if it isn't already configured correctly. + * A few tricky points: + * + * 1. If the window is embedded and the container is also in this + * process, don't actually reconfigure the window; just pass the + * desired size on to the container. Also, zero out any position + * information, since embedded windows are not allowed to move. + * 2. Sometimes the window manager will give us a different size + * than we asked for (e.g. mwm has a minimum size for windows), so + * base the size check on what we *asked for* last time, not what we + * got. + * 3. Don't move window unless a new position has been requested for + * it. This is because of "features" in some window managers (e.g. + * twm, as of 4/24/91) where they don't interpret coordinates + * according to ICCCM. Moving a window to its current location may + * cause it to shift position on the screen. + */ + + if (Tk_IsEmbedded(winPtr)) { + TkWindow *contWinPtr; + + contWinPtr = TkpGetOtherWindow(winPtr); + + /* + * NOTE: Here we should handle out of process embedding. + */ + + if (contWinPtr != NULL) { + /* + * This window is embedded and the container is also in this + * process, so we don't need to do anything special about the + * geometry, except to make sure that the desired size is known + * by the container. Also, zero out any position information, + * since embedded windows are not allowed to move. + */ + + wmPtr->x = wmPtr->y = 0; + wmPtr->flags &= ~(WM_NEGATIVE_X|WM_NEGATIVE_Y); + Tk_GeometryRequest((Tk_Window) contWinPtr, width, height); + } + return; + } + serial = NextRequest(winPtr->display); + if (wmPtr->flags & WM_MOVE_PENDING) { + wmPtr->configWidth = width; + wmPtr->configHeight = height; + if (wmTracing) { + printf( + "UpdateGeometryInfo moving to %d %d, resizing to %d x %d,\n", + x, y, width, height); + } + Tk_MoveResizeWindow((Tk_Window) winPtr, x, y, (unsigned) width, + (unsigned) height); + } else if ((width != wmPtr->configWidth) + || (height != wmPtr->configHeight)) { + wmPtr->configWidth = width; + wmPtr->configHeight = height; + if (wmTracing) { + printf("UpdateGeometryInfo resizing to %d x %d\n", width, height); + } + Tk_ResizeWindow((Tk_Window) winPtr, (unsigned) width, + (unsigned) height); + } else { + return; + } +} + +/* + *-------------------------------------------------------------- + * + * UpdateSizeHints -- + * + * This procedure is called to update the window manager's + * size hints information from the information in a WmInfo + * structure. + * + * Results: + * None. + * + * Side effects: + * Properties get changed for winPtr. + * + *-------------------------------------------------------------- + */ + +static void +UpdateSizeHints( + TkWindow *winPtr) +{ + register WmInfo *wmPtr = winPtr->wmInfoPtr; + XSizeHints *hintsPtr; + + wmPtr->flags &= ~WM_UPDATE_SIZE_HINTS; + + hintsPtr = XAllocSizeHints(); + if (hintsPtr == NULL) { + return; + } + + /* + * Compute the pixel-based sizes for the various fields in the + * size hints structure, based on the grid-based sizes in + * our structure. + */ + + if (wmPtr->gridWin != NULL) { + hintsPtr->base_width = winPtr->reqWidth + - (wmPtr->reqGridWidth * wmPtr->widthInc); + if (hintsPtr->base_width < 0) { + hintsPtr->base_width = 0; + } + hintsPtr->base_height = winPtr->reqHeight + - (wmPtr->reqGridHeight * wmPtr->heightInc); + if (hintsPtr->base_height < 0) { + hintsPtr->base_height = 0; + } + hintsPtr->min_width = hintsPtr->base_width + + (wmPtr->minWidth * wmPtr->widthInc); + hintsPtr->min_height = hintsPtr->base_height + + (wmPtr->minHeight * wmPtr->heightInc); + hintsPtr->max_width = hintsPtr->base_width + + (wmPtr->maxWidth * wmPtr->widthInc); + hintsPtr->max_height = hintsPtr->base_height + + (wmPtr->maxHeight * wmPtr->heightInc); + } else { + hintsPtr->min_width = wmPtr->minWidth; + hintsPtr->min_height = wmPtr->minHeight; + hintsPtr->max_width = wmPtr->maxWidth; + hintsPtr->max_height = wmPtr->maxHeight; + hintsPtr->base_width = 0; + hintsPtr->base_height = 0; + } + hintsPtr->width_inc = wmPtr->widthInc; + hintsPtr->height_inc = wmPtr->heightInc; + hintsPtr->min_aspect.x = wmPtr->minAspect.x; + hintsPtr->min_aspect.y = wmPtr->minAspect.y; + hintsPtr->max_aspect.x = wmPtr->maxAspect.x; + hintsPtr->max_aspect.y = wmPtr->maxAspect.y; + hintsPtr->win_gravity = wmPtr->gravity; + hintsPtr->flags = wmPtr->sizeHintsFlags | PMinSize | PMaxSize; + + /* + * If the window isn't supposed to be resizable, then set the + * minimum and maximum dimensions to be the same. + */ + + if (wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) { + if (wmPtr->width >= 0) { + hintsPtr->min_width = wmPtr->width; + } else { + hintsPtr->min_width = winPtr->reqWidth; + } + hintsPtr->max_width = hintsPtr->min_width; + } + if (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE) { + if (wmPtr->height >= 0) { + hintsPtr->min_height = wmPtr->height; + } else { + hintsPtr->min_height = winPtr->reqHeight; + } + hintsPtr->max_height = hintsPtr->min_height; + } + + XSetWMNormalHints(winPtr->display, winPtr->window, hintsPtr); + + XFree((char *) hintsPtr); +} + +/* + *-------------------------------------------------------------- + * + * ParseGeometry -- + * + * This procedure parses a geometry string and updates + * information used to control the geometry of a top-level + * window. + * + * Results: + * A standard Tcl return value, plus an error message in + * interp->result if an error occurs. + * + * Side effects: + * The size and/or location of winPtr may change. + * + *-------------------------------------------------------------- + */ + +static int +ParseGeometry( + Tcl_Interp *interp, /* Used for error reporting. */ + char *string, /* String containing new geometry. Has the + * standard form "=wxh+x+y". */ + TkWindow *winPtr) /* Pointer to top-level window whose + * geometry is to be changed. */ +{ + register WmInfo *wmPtr = winPtr->wmInfoPtr; + int x, y, width, height, flags; + char *end; + register char *p = string; + + /* + * The leading "=" is optional. + */ + + if (*p == '=') { + p++; + } + + /* + * Parse the width and height, if they are present. Don't + * actually update any of the fields of wmPtr until we've + * successfully parsed the entire geometry string. + */ + + width = wmPtr->width; + height = wmPtr->height; + x = wmPtr->x; + y = wmPtr->y; + flags = wmPtr->flags; + if (isdigit(UCHAR(*p))) { + width = strtoul(p, &end, 10); + p = end; + if (*p != 'x') { + goto error; + } + p++; + if (!isdigit(UCHAR(*p))) { + goto error; + } + height = strtoul(p, &end, 10); + p = end; + } + + /* + * Parse the X and Y coordinates, if they are present. + */ + + if (*p != '\0') { + flags &= ~(WM_NEGATIVE_X | WM_NEGATIVE_Y); + if (*p == '-') { + flags |= WM_NEGATIVE_X; + } else if (*p != '+') { + goto error; + } + x = strtol(p+1, &end, 10); + p = end; + if (*p == '-') { + flags |= WM_NEGATIVE_Y; + } else if (*p != '+') { + goto error; + } + y = strtol(p+1, &end, 10); + if (*end != '\0') { + goto error; + } + + /* + * Assume that the geometry information came from the user, + * unless an explicit source has been specified. Otherwise + * most window managers assume that the size hints were + * program-specified and they ignore them. + */ + + if ((wmPtr->sizeHintsFlags & (USPosition|PPosition)) == 0) { + wmPtr->sizeHintsFlags |= USPosition; + flags |= WM_UPDATE_SIZE_HINTS; + } + } + + /* + * Everything was parsed OK. Update the fields of *wmPtr and + * arrange for the appropriate information to be percolated out + * to the window manager at the next idle moment. + */ + + wmPtr->width = width; + wmPtr->height = height; + if ((x != wmPtr->x) || (y != wmPtr->y) + || ((flags & (WM_NEGATIVE_X|WM_NEGATIVE_Y)) + != (wmPtr->flags & (WM_NEGATIVE_X|WM_NEGATIVE_Y)))) { + wmPtr->x = x; + wmPtr->y = y; + flags |= WM_MOVE_PENDING; + } + wmPtr->flags = flags; + + if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) { + Tk_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr); + wmPtr->flags |= WM_UPDATE_PENDING; + } + return TCL_OK; + + error: + Tcl_AppendResult(interp, "bad geometry specifier \"", + string, "\"", (char *) NULL); + return TCL_ERROR; +} + +/* + *---------------------------------------------------------------------- + * + * Tk_GetRootCoords -- + * + * Given a token for a window, this procedure traces through the + * window's lineage to find the (virtual) root-window coordinates + * corresponding to point (0,0) in the window. + * + * Results: + * The locations pointed to by xPtr and yPtr are filled in with + * the root coordinates of the (0,0) point in tkwin. If a virtual + * root window is in effect for the window, then the coordinates + * in the virtual root are returned. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +Tk_GetRootCoords( + Tk_Window tkwin, /* Token for window. */ + int *xPtr, /* Where to store x-displacement of (0,0). */ + int *yPtr) /* Where to store y-displacement of (0,0). */ +{ + int x, y; + register TkWindow *winPtr = (TkWindow *) tkwin; + + /* + * Search back through this window's parents all the way to a + * top-level window, combining the offsets of each window within + * its parent. + */ + + x = y = 0; + while (1) { + x += winPtr->changes.x + winPtr->changes.border_width; + y += winPtr->changes.y + winPtr->changes.border_width; + if (winPtr->flags & TK_TOP_LEVEL) { + if (!(Tk_IsEmbedded(winPtr))) { + x += winPtr->wmInfoPtr->xInParent; + y += winPtr->wmInfoPtr->yInParent; + break; + } else { + TkWindow *otherPtr; + + otherPtr = TkpGetOtherWindow(winPtr); + if (otherPtr != NULL) { + /* + * The container window is in the same application. + * Query its coordinates. + */ + winPtr = otherPtr; + + /* + * Remember to offset by the container window here, + * since at the end of this if branch, we will + * pop out to the container's parent... + */ + + x += winPtr->changes.x + winPtr->changes.border_width; + y += winPtr->changes.y + winPtr->changes.border_width; + + } else { + + /* + * NOTE: Here we should handle + * out of process embedding. + */ + + break; + } + } + } + winPtr = winPtr->parentPtr; + } + *xPtr = x; + *yPtr = y; +} + +/* + *---------------------------------------------------------------------- + * + * Tk_CoordsToWindow -- + * + * This is a Macintosh specific implementation of this function. + * Given the root coordinates of a point, this procedure returns + * the token for the top-most window covering that point, if + * there exists such a window in this application. + * + * Results: + * The return result is either a token for the window corresponding + * to rootX and rootY, or else NULL to indicate that there is no such + * window. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +Tk_Window +Tk_CoordsToWindow( + int rootX, int rootY, /* Coordinates of point in root window. If + * a virtual-root window manager is in use, + * these coordinates refer to the virtual + * root, not the real root. */ + Tk_Window tkwin) /* Token for any window in application; + * used to identify the display. */ +{ + WindowPtr whichWin; + Point where; + Window rootChild; + register TkWindow *winPtr, *childPtr; + TkWindow *nextPtr; /* Coordinates of highest child found so + * far that contains point. */ + int x, y; /* Coordinates in winPtr. */ + int tmpx, tmpy, bd; + + /* + * Step 1: find the top-level window that contains the desired point. + */ + + where.h = rootX; + where.v = rootY; + FindWindow(where, &whichWin); + if (whichWin == NULL) { + return NULL; + } + rootChild = TkMacGetXWindow(whichWin); + winPtr = (TkWindow *) Tk_IdToWindow(tkDisplayList->display, rootChild); + if (winPtr == NULL) { + return NULL; + } + + /* + * Step 2: work down through the hierarchy underneath this window. + * At each level, scan through all the children to find the highest + * one in the stacking order that contains the point. Then repeat + * the whole process on that child. + */ + + x = rootX - winPtr->wmInfoPtr->xInParent; + y = rootY - winPtr->wmInfoPtr->yInParent; + while (1) { + x -= winPtr->changes.x; + y -= winPtr->changes.y; + nextPtr = NULL; + + /* + * Container windows cannot have children. So if it is a container, + * look there, otherwise inspect the children. + */ + + if (Tk_IsContainer(winPtr)) { + childPtr = TkpGetOtherWindow(winPtr); + if (childPtr != NULL) { + if (Tk_IsMapped(childPtr)) { + tmpx = x - childPtr->changes.x; + tmpy = y - childPtr->changes.y; + bd = childPtr->changes.border_width; + + if ((tmpx >= -bd) && (tmpy >= -bd) + && (tmpx < (childPtr->changes.width + bd)) + && (tmpy < (childPtr->changes.height + bd))) { + nextPtr = childPtr; + } + } + } + + + /* + * NOTE: Here we should handle out of process embedding. + */ + + } else { + for (childPtr = winPtr->childList; childPtr != NULL; + childPtr = childPtr->nextPtr) { + if (!Tk_IsMapped(childPtr) || + (childPtr->flags & TK_TOP_LEVEL)) { + continue; + } + tmpx = x - childPtr->changes.x; + tmpy = y - childPtr->changes.y; + bd = childPtr->changes.border_width; + if ((tmpx >= -bd) && (tmpy >= -bd) + && (tmpx < (childPtr->changes.width + bd)) + && (tmpy < (childPtr->changes.height + bd))) { + nextPtr = childPtr; + } + } + } + if (nextPtr == NULL) { + break; + } + winPtr = nextPtr; + } + return (Tk_Window) winPtr; +} + +/* + *---------------------------------------------------------------------- + * + * Tk_TopCoordsToWindow -- + * + * Given a Tk Window, and coordinates of a point relative to that window + * this procedure returns the top-most child of the window (excluding + * toplevels) covering that point, if there exists such a window in this + * application. + * It also sets newX, and newY to the coords of the point relative to the + * window returned. + * + * Results: + * The return result is either a token for the window corresponding + * to rootX and rootY, or else NULL to indicate that there is no such + * window. newX and newY are also set to the coords of the point relative + * to the returned window. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +Tk_Window +Tk_TopCoordsToWindow( + Tk_Window tkwin, /* Token for a Tk Window which defines the; + * coordinates for rootX & rootY */ + int rootX, int rootY, /* Coordinates of a point in tkWin. */ + int *newX, int *newY) /* Coordinates of point in the upperMost child of + * tkWin containing (rootX,rootY) */ +{ + register TkWindow *winPtr, *childPtr; + TkWindow *nextPtr; /* Coordinates of highest child found so + * far that contains point. */ + int x, y; /* Coordinates in winPtr. */ + Window *children; /* Children of winPtr, or NULL. */ + + winPtr = (TkWindow *) tkwin; + x = rootX; + y = rootY; + while (1) { + nextPtr = NULL; + children = NULL; + + /* + * Container windows cannot have children. So if it is a container, + * look there, otherwise inspect the children. + */ + + if (Tk_IsContainer(winPtr)) { + childPtr = TkpGetOtherWindow(winPtr); + if (childPtr != NULL) { + if (Tk_IsMapped(childPtr) && + (x > childPtr->changes.x && + x < childPtr->changes.x + + childPtr->changes.width) && + (y > childPtr->changes.y && + y < childPtr->changes.y + + childPtr->changes.height)) { + nextPtr = childPtr; + } + } + + /* + * NOTE: Here we should handle out of process embedding. + */ + + } else { + + for (childPtr = winPtr->childList; childPtr != NULL; + childPtr = childPtr->nextPtr) { + if (!Tk_IsMapped(childPtr) || + (childPtr->flags & TK_TOP_LEVEL)) { + continue; + } + if (x < childPtr->changes.x || y < childPtr->changes.y) { + continue; + } + if (x > childPtr->changes.x + childPtr->changes.width || + y > childPtr->changes.y + childPtr->changes.height) { + continue; + } + nextPtr = childPtr; + } + } + if (nextPtr == NULL) { + break; + } + winPtr = nextPtr; + x -= winPtr->changes.x; + y -= winPtr->changes.y; + } + *newX = x; + *newY = y; + return (Tk_Window) winPtr; +} + +/* + *---------------------------------------------------------------------- + * + * UpdateVRootGeometry -- + * + * This procedure is called to update all the virtual root + * geometry information in wmPtr. + * + * Results: + * None. + * + * Side effects: + * The vRootX, vRootY, vRootWidth, and vRootHeight fields in + * wmPtr are filled with the most up-to-date information. + * + *---------------------------------------------------------------------- + */ + +static void +UpdateVRootGeometry( + WmInfo *wmPtr) /* Window manager information to be + * updated. The wmPtr->vRoot field must + * be valid. */ +{ + TkWindow *winPtr = wmPtr->winPtr; + unsigned int bd, dummy; + Window dummy2; + Status status; + Tk_ErrorHandler handler; + + /* + * If this isn't a virtual-root window manager, just return information + * about the screen. + */ + + wmPtr->flags &= ~WM_VROOT_OFFSET_STALE; + if (wmPtr->vRoot == None) { + noVRoot: + wmPtr->vRootX = wmPtr->vRootY = 0; + wmPtr->vRootWidth = DisplayWidth(winPtr->display, winPtr->screenNum); + wmPtr->vRootHeight = DisplayHeight(winPtr->display, winPtr->screenNum); + return; + } + + /* + * Refresh the virtual root information if it's out of date. + */ + + handler = Tk_CreateErrorHandler(winPtr->display, -1, -1, -1, + (Tk_ErrorProc *) NULL, (ClientData) NULL); + status = XGetGeometry(winPtr->display, wmPtr->vRoot, + &dummy2, &wmPtr->vRootX, &wmPtr->vRootY, + &wmPtr->vRootWidth, &wmPtr->vRootHeight, &bd, &dummy); + if (wmTracing) { + printf("UpdateVRootGeometry: x = %d, y = %d, width = %d, ", + wmPtr->vRootX, wmPtr->vRootY, wmPtr->vRootWidth); + printf("height = %d, status = %d\n", wmPtr->vRootHeight, status); + } + Tk_DeleteErrorHandler(handler); + if (status == 0) { + /* + * The virtual root is gone! Pretend that it never existed. + */ + + wmPtr->vRoot = None; + goto noVRoot; + } +} + +/* + *---------------------------------------------------------------------- + * + * Tk_GetVRootGeometry -- + * + * This procedure returns information about the virtual root + * window corresponding to a particular Tk window. + * + * Results: + * The values at xPtr, yPtr, widthPtr, and heightPtr are set + * with the offset and dimensions of the root window corresponding + * to tkwin. If tkwin is being managed by a virtual root window + * manager these values correspond to the virtual root window being + * used for tkwin; otherwise the offsets will be 0 and the + * dimensions will be those of the screen. + * + * Side effects: + * Vroot window information is refreshed if it is out of date. + * + *---------------------------------------------------------------------- + */ + +void +Tk_GetVRootGeometry( + Tk_Window tkwin, /* Window whose virtual root is to be + * queried. */ + int *xPtr, int *yPtr, /* Store x and y offsets of virtual root + * here. */ + int *widthPtr, /* Store dimensions of virtual root here. */ + int *heightPtr) +{ + WmInfo *wmPtr; + TkWindow *winPtr = (TkWindow *) tkwin; + + /* + * Find the top-level window for tkwin, and locate the window manager + * information for that window. + */ + + while (!(winPtr->flags & TK_TOP_LEVEL)) { + winPtr = winPtr->parentPtr; + } + wmPtr = winPtr->wmInfoPtr; + + /* + * Make sure that the geometry information is up-to-date, then copy + * it out to the caller. + */ + + if (wmPtr->flags & WM_VROOT_OFFSET_STALE) { + UpdateVRootGeometry(wmPtr); + } + *xPtr = wmPtr->vRootX; + *yPtr = wmPtr->vRootY; + *widthPtr = wmPtr->vRootWidth; + *heightPtr = wmPtr->vRootHeight; +} + +/* + *---------------------------------------------------------------------- + * + * Tk_MoveToplevelWindow -- + * + * This procedure is called instead of Tk_MoveWindow to adjust + * the x-y location of a top-level window. It delays the actual + * move to a later time and keeps window-manager information + * up-to-date with the move + * + * Results: + * None. + * + * Side effects: + * The window is eventually moved so that its upper-left corner + * (actually, the upper-left corner of the window's decorative + * frame, if there is one) is at (x,y). + * + *---------------------------------------------------------------------- + */ + +void +Tk_MoveToplevelWindow( + Tk_Window tkwin, /* Window to move. */ + int x, int y) /* New location for window (within + * parent). */ +{ + TkWindow *winPtr = (TkWindow *) tkwin; + register WmInfo *wmPtr = winPtr->wmInfoPtr; + + if (!(winPtr->flags & TK_TOP_LEVEL)) { + panic("Tk_MoveToplevelWindow called with non-toplevel window"); + } + wmPtr->x = x; + wmPtr->y = y; + wmPtr->flags |= WM_MOVE_PENDING; + wmPtr->flags &= ~(WM_NEGATIVE_X|WM_NEGATIVE_Y); + if ((wmPtr->sizeHintsFlags & (USPosition|PPosition)) == 0) { + wmPtr->sizeHintsFlags |= USPosition; + wmPtr->flags |= WM_UPDATE_SIZE_HINTS; + } + + /* + * If the window has already been mapped, must bring its geometry + * up-to-date immediately, otherwise an event might arrive from the + * server that would overwrite wmPtr->x and wmPtr->y and lose the + * new position. + */ + + if (!(wmPtr->flags & WM_NEVER_MAPPED)) { + if (wmPtr->flags & WM_UPDATE_PENDING) { + Tk_CancelIdleCall(UpdateGeometryInfo, (ClientData) winPtr); + } + UpdateGeometryInfo((ClientData) winPtr); + } +} + +/* + *---------------------------------------------------------------------- + * + * TkWmProtocolEventProc -- + * + * This procedure is called by the Tk_HandleEvent whenever a + * ClientMessage event arrives whose type is "WM_PROTOCOLS". + * This procedure handles the message from the window manager + * in an appropriate fashion. + * + * Results: + * None. + * + * Side effects: + * Depends on what sort of handler, if any, was set up for the + * protocol. + * + *---------------------------------------------------------------------- + */ + +void +TkWmProtocolEventProc( + TkWindow *winPtr, /* Window to which the event was sent. */ + XEvent *eventPtr) /* X event. */ +{ + WmInfo *wmPtr; + register ProtocolHandler *protPtr; + Tcl_Interp *interp; + Atom protocol; + int result; + + wmPtr = winPtr->wmInfoPtr; + if (wmPtr == NULL) { + return; + } + protocol = (Atom) eventPtr->xclient.data.l[0]; + for (protPtr = wmPtr->protPtr; protPtr != NULL; + protPtr = protPtr->nextPtr) { + if (protocol == protPtr->protocol) { + Tcl_Preserve((ClientData) protPtr); + interp = protPtr->interp; + Tcl_Preserve((ClientData) interp); + result = Tcl_GlobalEval(interp, protPtr->command); + if (result != TCL_OK) { + Tcl_AddErrorInfo(interp, "\n (command for \""); + Tcl_AddErrorInfo(interp, + Tk_GetAtomName((Tk_Window) winPtr, protocol)); + Tcl_AddErrorInfo(interp, "\" window manager protocol)"); + Tk_BackgroundError(interp); + } + Tcl_Release((ClientData) interp); + Tcl_Release((ClientData) protPtr); + return; + } + } + + /* + * No handler was present for this protocol. If this is a + * WM_DELETE_WINDOW message then just destroy the window. + */ + + if (protocol == Tk_InternAtom((Tk_Window) winPtr, "WM_DELETE_WINDOW")) { + Tk_DestroyWindow((Tk_Window) winPtr); + } +} + +/* + *---------------------------------------------------------------------- + * + * TkWmRestackToplevel -- + * + * This procedure restacks a top-level window. + * + * Results: + * None. + * + * Side effects: + * WinPtr gets restacked as specified by aboveBelow and otherPtr. + * This procedure doesn't return until the restack has taken + * effect and the ConfigureNotify event for it has been received. + * + *---------------------------------------------------------------------- + */ + +void +TkWmRestackToplevel( + TkWindow *winPtr, /* Window to restack. */ + int aboveBelow, /* Gives relative position for restacking; + * must be Above or Below. */ + TkWindow *otherPtr) /* Window relative to which to restack; + * if NULL, then winPtr gets restacked + * above or below *all* siblings. */ +{ + WmInfo *wmPtr; + WindowPeek macWindow, otherMacWindow, frontWindow; + + wmPtr = winPtr->wmInfoPtr; + + /* + * Get the mac window. Make sure it exists & is mapped. + */ + + if (winPtr->window == None) { + Tk_MakeWindowExist((Tk_Window) winPtr); + } + if (winPtr->wmInfoPtr->flags & WM_NEVER_MAPPED) { + + /* + * Can't set stacking order properly until the window is on the + * screen (mapping it may give it a reparent window), so make sure + * it's on the screen. + */ + + TkWmMapWindow(winPtr); + } + macWindow = (WindowPeek) TkMacGetDrawablePort(winPtr->window); + + /* + * Get the window in which a raise or lower is in relation to. + */ + if (otherPtr != NULL) { + if (otherPtr->window == None) { + Tk_MakeWindowExist((Tk_Window) otherPtr); + } + if (otherPtr->wmInfoPtr->flags & WM_NEVER_MAPPED) { + TkWmMapWindow(otherPtr); + } + otherMacWindow = (WindowPeek) TkMacGetDrawablePort(otherPtr->window); + } else { + otherMacWindow = NULL; + } + + frontWindow = (WindowPeek) FrontWindow(); + if (aboveBelow == Above) { + if (macWindow == frontWindow) { + /* + * Do nothing - it's already at the top. + */ + } else if (otherMacWindow == frontWindow || otherMacWindow == NULL) { + /* + * Raise the window to the top. If the window is visable then + * we also make it the active window. + */ + + if (wmPtr->hints.initial_state == WithdrawnState) { + BringToFront((WindowPtr) macWindow); + } else { + SelectWindow((WindowPtr) macWindow); + } + } else { + /* + * Find the window to be above. (Front window will actually be the + * window to be behind.) Front window is NULL if no other windows. + */ + while (frontWindow != NULL && + frontWindow->nextWindow != otherMacWindow) { + frontWindow = frontWindow->nextWindow; + } + if (frontWindow != NULL) { + SendBehind((WindowPtr) macWindow, (WindowPtr) frontWindow); + } + } + } else { + /* + * Send behind. If it was in front find another window to make active. + */ + if (macWindow == frontWindow) { + if (macWindow->nextWindow != NULL) { + SelectWindow((WindowPtr) macWindow->nextWindow); + } + } + SendBehind((WindowPtr) macWindow, (WindowPtr) otherMacWindow); + } +} + +/* + *---------------------------------------------------------------------- + * + * TkWmAddToColormapWindows -- + * + * This procedure is called to add a given window to the + * WM_COLORMAP_WINDOWS property for its top-level, if it + * isn't already there. It is invoked by the Tk code that + * creates a new colormap, in order to make sure that colormap + * information is propagated to the window manager by default. + * + * Results: + * None. + * + * Side effects: + * WinPtr's window gets added to the WM_COLORMAP_WINDOWS + * property of its nearest top-level ancestor, unless the + * colormaps have been set explicitly with the + * "wm colormapwindows" command. + * + *---------------------------------------------------------------------- + */ + +void +TkWmAddToColormapWindows( + TkWindow *winPtr) /* Window with a non-default colormap. + * Should not be a top-level window. */ +{ + TkWindow *topPtr; + TkWindow **oldPtr, **newPtr; + int count, i; + + if (winPtr->window == None) { + return; + } + + for (topPtr = winPtr->parentPtr; ; topPtr = topPtr->parentPtr) { + if (topPtr == NULL) { + /* + * Window is being deleted. Skip the whole operation. + */ + + return; + } + if (topPtr->flags & TK_TOP_LEVEL) { + break; + } + } + if (topPtr->wmInfoPtr->flags & WM_COLORMAPS_EXPLICIT) { + return; + } + + /* + * Make sure that the window isn't already in the list. + */ + + count = topPtr->wmInfoPtr->cmapCount; + oldPtr = topPtr->wmInfoPtr->cmapList; + + for (i = 0; i < count; i++) { + if (oldPtr[i] == winPtr) { + return; + } + } + + /* + * Make a new bigger array and use it to reset the property. + * Automatically add the toplevel itself as the last element + * of the list. + */ + + newPtr = (TkWindow **) ckalloc((unsigned) ((count+2)*sizeof(TkWindow*))); + if (count > 0) { + memcpy(newPtr, oldPtr, count * sizeof(TkWindow*)); + } + if (count == 0) { + count++; + } + newPtr[count-1] = winPtr; + newPtr[count] = topPtr; + if (oldPtr != NULL) { + ckfree((char *) oldPtr); + } + + topPtr->wmInfoPtr->cmapList = newPtr; + topPtr->wmInfoPtr->cmapCount = count+1; + + /* + * On the Macintosh all of this is just an excercise + * in compatability as we don't support colormaps. If + * we did they would be installed here. + */ +} + +/* + *---------------------------------------------------------------------- + * + * TkWmRemoveFromColormapWindows -- + * + * This procedure is called to remove a given window from the + * WM_COLORMAP_WINDOWS property for its top-level. It is invoked + * when windows are deleted. + * + * Results: + * None. + * + * Side effects: + * WinPtr's window gets removed from the WM_COLORMAP_WINDOWS + * property of its nearest top-level ancestor, unless the + * top-level itself is being deleted too. + * + *---------------------------------------------------------------------- + */ + +void +TkWmRemoveFromColormapWindows( + TkWindow *winPtr) /* Window that may be present in + * WM_COLORMAP_WINDOWS property for its + * top-level. Should not be a top-level + * window. */ +{ + TkWindow *topPtr; + TkWindow **oldPtr; + int count, i, j; + + for (topPtr = winPtr->parentPtr; ; topPtr = topPtr->parentPtr) { + if (topPtr == NULL) { + /* + * Ancestors have been deleted, so skip the whole operation. + * Seems like this can't ever happen? + */ + + return; + } + if (topPtr->flags & TK_TOP_LEVEL) { + break; + } + } + if (topPtr->flags & TK_ALREADY_DEAD) { + /* + * Top-level is being deleted, so there's no need to cleanup + * the WM_COLORMAP_WINDOWS property. + */ + + return; + } + + /* + * Find the window and slide the following ones down to cover + * it up. + */ + + count = topPtr->wmInfoPtr->cmapCount; + oldPtr = topPtr->wmInfoPtr->cmapList; + for (i = 0; i < count; i++) { + if (oldPtr[i] == winPtr) { + for (j = i ; j < count-1; j++) { + oldPtr[j] = oldPtr[j+1]; + } + topPtr->wmInfoPtr->cmapCount = count - 1; + break; + } + } +} + +/* + *---------------------------------------------------------------------- + * + * TkGetPointerCoords -- + * + * Fetch the position of the mouse pointer. + * + * Results: + * *xPtr and *yPtr are filled in with the (virtual) root coordinates + * of the mouse pointer for tkwin's display. If the pointer isn't + * on tkwin's screen, then -1 values are returned for both + * coordinates. The argument tkwin must be a toplevel window. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +TkGetPointerCoords( + Tk_Window tkwin, /* Toplevel window that identifies screen + * on which lookup is to be done. */ + int *xPtr, int *yPtr) /* Store pointer coordinates here. */ +{ + Point where; + + GetMouse(&where); + LocalToGlobal(&where); + *xPtr = where.h; + *yPtr = where.v; +} + +/* + *---------------------------------------------------------------------- + * + * InitialWindowBounds -- + * + * This function calculates the initial bounds for a new Mac + * toplevel window. Unless the geometry is specified by the user + * this code will auto place the windows in a cascade diagonially + * across the main monitor of the Mac. + * + * Results: + * The bounds are returned in geometry. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static void +InitialWindowBounds( + TkWindow *winPtr, /* Window to get initial bounds for. */ + Rect *geometry) /* On return the initial bounds. */ +{ + int x, y; + static int defaultX = 5; + static int defaultY = 45; + + if (!(winPtr->wmInfoPtr->sizeHintsFlags & (USPosition | PPosition))) { + /* + * We will override the program & hopefully place the + * window in a "better" location. + */ + + if (((tcl_macQdPtr->screenBits.bounds.right - defaultX) < 30) || + ((tcl_macQdPtr->screenBits.bounds.bottom - defaultY) < 30)) { + defaultX = 5; + defaultY = 45; + } + x = defaultX; + y = defaultY; + defaultX += 20; + defaultY += 20; + } else { + x = winPtr->wmInfoPtr->x; + y = winPtr->wmInfoPtr->y; + } + + geometry->left = x; + geometry->top = y; + geometry->right = x + winPtr->changes.width; + geometry->bottom = y + winPtr->changes.height; +} + +/* + *---------------------------------------------------------------------- + * + * TkMacResizable -- + * + * This function determines if the passed in window is part of + * a toplevel window that is resizable. If the window is + * resizable in the x, y or both directions, true is returned. + * + * Results: + * True if resizable, false otherwise. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +TkMacResizable( + TkWindow *winPtr) /* Tk window or NULL. */ +{ + WmInfo *wmPtr; + + if (winPtr == NULL) { + return false; + } + while (winPtr->wmInfoPtr == NULL) { + winPtr = winPtr->parentPtr; + } + + wmPtr = winPtr->wmInfoPtr; + if ((wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) && + (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE)) { + return false; + } else { + return true; + } +} + +/* + *---------------------------------------------------------------------- + * + * TkMacGrowToplevel -- + * + * The function is invoked when the user clicks in the grow region + * of a Tk window. The function will handle the dragging + * procedure and not return until completed. Finally, the function + * may place information Tk's event queue is the window was resized. + * + * Results: + * True if events were placed on event queue, false otherwise. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +TkMacGrowToplevel( + WindowPtr whichWindow, + Point start) +{ + Point where = start; + + GlobalToLocal(&where); + if (where.h > (whichWindow->portRect.right - 16) && + where.v > (whichWindow->portRect.bottom - 16)) { + + Window window; + TkWindow *winPtr; + WmInfo *wmPtr; + Rect bounds; + long growResult; + + window = TkMacGetXWindow(whichWindow); + winPtr = (TkWindow *) Tk_IdToWindow(tkDisplayList->display, window); + wmPtr = winPtr->wmInfoPtr; + + /* TODO: handle grid size options. */ + if ((wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) && + (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE)) { + return false; + } + if (wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) { + bounds.left = bounds.right = winPtr->changes.width; + } else { + bounds.left = (wmPtr->minWidth < 64) ? 64 : wmPtr->minWidth; + bounds.right = (wmPtr->maxWidth < 64) ? 64 : wmPtr->maxWidth; + } + if (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE) { + bounds.top = bounds.bottom = winPtr->changes.height; + } else { + bounds.top = (wmPtr->minHeight < 64) ? 64 : wmPtr->minHeight; + bounds.bottom = (wmPtr->maxHeight < 64) ? 64 : wmPtr->maxHeight; + } + + growResult = GrowWindow(whichWindow, start, &bounds); + + if (growResult != 0) { + SizeWindow(whichWindow, + LoWord(growResult), HiWord(growResult), true); + SetPort(whichWindow); + InvalRect(&whichWindow->portRect); /* TODO: may not be needed */ + TkMacInvalClipRgns(winPtr); + TkGenWMConfigureEvent((Tk_Window) winPtr, -1, -1, + (int) LoWord(growResult), (int) HiWord(growResult), + TK_SIZE_CHANGED); + return true; + } + return false; + } + return false; +} + +/* + *---------------------------------------------------------------------- + * + * TkSetWMName -- + * + * Set the title for a toplevel window. If the window is embedded, + * do not change the window title. + * + * Results: + * None. + * + * Side effects: + * The title of the window is changed. + * + *---------------------------------------------------------------------- + */ + +void +TkSetWMName( + TkWindow *winPtr, + Tk_Uid titleUid) +{ + Str255 pTitle; + GWorldPtr macWin; + + if (Tk_IsEmbedded(winPtr)) { + return; + } + + macWin = TkMacGetDrawablePort(winPtr->window); + + strcpy((char *) pTitle + 1, titleUid); + pTitle[0] = strlen(titleUid); + SetWTitle((WindowPtr) macWin, pTitle); +} + +void +TkGenWMDestroyEvent( + Tk_Window tkwin) +{ + XEvent event; + + event.xany.serial = Tk_Display(tkwin)->request; + event.xany.send_event = False; + event.xany.display = Tk_Display(tkwin); + + event.xclient.window = Tk_WindowId(tkwin); + event.xclient.type = ClientMessage; + event.xclient.message_type = Tk_InternAtom(tkwin, "WM_PROTOCOLS"); + event.xclient.format = 32; + event.xclient.data.l[0] = Tk_InternAtom(tkwin, "WM_DELETE_WINDOW"); + Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); +} + +/* + *---------------------------------------------------------------------- + * + * TkGenWMConfigureEvent -- + * + * Generate a ConfigureNotify event for Tk. Depending on the + * value of flag the values of width/height, x/y, or both may + * be changed. + * + * Results: + * None. + * + * Side effects: + * A ConfigureNotify event is sent to Tk. + * + *---------------------------------------------------------------------- + */ + +void +TkGenWMConfigureEvent( + Tk_Window tkwin, + int x, + int y, + int width, + int height, + int flags) +{ + XEvent event; + WmInfo *wmPtr; + TkWindow *winPtr = (TkWindow *) tkwin; + + if (tkwin == NULL) { + return; + } + + event.type = ConfigureNotify; + event.xconfigure.serial = Tk_Display(tkwin)->request; + event.xconfigure.send_event = False; + event.xconfigure.display = Tk_Display(tkwin); + event.xconfigure.event = Tk_WindowId(tkwin); + event.xconfigure.window = Tk_WindowId(tkwin); + event.xconfigure.border_width = winPtr->changes.border_width; + event.xconfigure.override_redirect = winPtr->atts.override_redirect; + if (winPtr->changes.stack_mode == Above) { + event.xconfigure.above = winPtr->changes.sibling; + } else { + event.xconfigure.above = None; + } + + if (flags & TK_LOCATION_CHANGED) { + event.xconfigure.x = x; + event.xconfigure.y = y; + } else { + event.xconfigure.x = Tk_X(tkwin); + event.xconfigure.y = Tk_Y(tkwin); + x = Tk_X(tkwin); + y = Tk_Y(tkwin); + } + if (flags & TK_SIZE_CHANGED) { + event.xconfigure.width = width; + event.xconfigure.height = height; + } else { + event.xconfigure.width = Tk_Width(tkwin); + event.xconfigure.height = Tk_Height(tkwin); + width = Tk_Width(tkwin); + height = Tk_Height(tkwin); + } + + Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); + + /* + * Update window manager information. + */ + if (Tk_IsTopLevel(winPtr)) { + wmPtr = winPtr->wmInfoPtr; + if (flags & TK_LOCATION_CHANGED) { + wmPtr->x = x; + wmPtr->y = y; + wmPtr->flags &= ~(WM_NEGATIVE_X | WM_NEGATIVE_Y); + } + if ((flags & TK_SIZE_CHANGED) && + ((width != Tk_Width(tkwin)) || (height != Tk_Height(tkwin)))) { + if ((wmPtr->width == -1) && (width == winPtr->reqWidth)) { + /* + * Don't set external width, since the user didn't change it + * from what the widgets asked for. + */ + } else { + if (wmPtr->gridWin != NULL) { + wmPtr->width = wmPtr->reqGridWidth + + (width - winPtr->reqWidth)/wmPtr->widthInc; + if (wmPtr->width < 0) { + wmPtr->width = 0; + } + } else { + wmPtr->width = width; + } + } + if ((wmPtr->height == -1) && (height == winPtr->reqHeight)) { + /* + * Don't set external height, since the user didn't change it + * from what the widgets asked for. + */ + } else { + if (wmPtr->gridWin != NULL) { + wmPtr->height = wmPtr->reqGridHeight + + (height - winPtr->reqHeight)/wmPtr->heightInc; + if (wmPtr->height < 0) { + wmPtr->height = 0; + } + } else { + wmPtr->height = height; + } + } + wmPtr->configWidth = width; + wmPtr->configHeight = height; + } + } + + /* + * Now set up the changes structure. Under X we wait for the + * ConfigureNotify to set these values. On the Mac we know imediatly that + * this is what we want - so we just set them. However, we need to + * make sure the windows clipping region is marked invalid so the + * change is visable to the subwindow. + */ + winPtr->changes.x = x; + winPtr->changes.y = y; + winPtr->changes.width = width; + winPtr->changes.height = height; + TkMacInvalClipRgns(winPtr); +} + +/* + *---------------------------------------------------------------------- + * + * TkGetTransientMaster -- + * + * If the passed window has the TRANSIENT_FOR property set this + * will return the master window. Otherwise it will return None. + * + * Results: + * The master window or None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +Window +TkGetTransientMaster( + TkWindow *winPtr) +{ + if (winPtr->wmInfoPtr != NULL) { + return winPtr->wmInfoPtr->master; + } + return None; +} + +/* + *---------------------------------------------------------------------- + * + * TkMacGetXWindow -- + * + * Returns the X window Id associated with the given WindowRef. + * + * Results: + * The window id is returned. None is returned if not a Tk window. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +Window +TkMacGetXWindow( + WindowRef macWinPtr) +{ + register Tcl_HashEntry *hPtr; + + if ((macWinPtr == NULL) || !windowHashInit) { + return None; + } + hPtr = Tcl_FindHashEntry(&windowTable, (char *) macWinPtr); + if (hPtr == NULL) { + return None; + } + return (Window) Tcl_GetHashValue(hPtr); +} + +/* + *---------------------------------------------------------------------- + * + * TkMacZoomToplevel -- + * + * The function is invoked when the user clicks in the zoom region + * of a Tk window. The function will handle the mouse tracking + * for the interaction. If the window is to be zoomed the window + * size is changed and events are generated to let Tk know what + * happened. + * + * Results: + * True if events were placed on event queue, false otherwise. + * + * Side effects: + * The window may be resized & events placed on Tk's queue. + * + *---------------------------------------------------------------------- + */ + +int +TkMacZoomToplevel( + WindowPtr whichWindow, /* The Macintosh window to zoom. */ + Point where, /* The current mouse position. */ + short zoomPart) /* Either inZoomIn or inZoomOut */ +{ + Window window; + Tk_Window tkwin; + Point location = {0, 0}; + int xOffset, yOffset; + WmInfo *wmPtr; + + SetPort(whichWindow); + if (!TrackBox(whichWindow, where, zoomPart)) { + return false; + } + + /* + * We should now zoom the window (as long as it's one of ours). We + * also need to generate an event to let Tk know that the window size + * has changed. + */ + window = TkMacGetXWindow(whichWindow); + tkwin = Tk_IdToWindow(tkDisplayList->display, window); + if (tkwin == NULL) { + return false; + } + + /* + * The following block of code works around a bug in the window + * definition for Apple's floating windows. The zoom behavior is + * broken - we must manually set the standard state (by default + * it's something like 1x1) and we must swap the zoomPart manually + * otherwise we always get the same zoomPart and nothing happens. + */ + wmPtr = ((TkWindow *) tkwin)->wmInfoPtr; + if (wmPtr->style >= floatProc && wmPtr->style <= floatSideZoomGrowProc) { + if (zoomPart == inZoomIn) { + Rect zoomRect = tcl_macQdPtr->screenBits.bounds; + InsetRect(&zoomRect, 60, 60); + SetWindowStandardState(whichWindow, &zoomRect); + zoomPart = inZoomOut; + } else { + zoomPart = inZoomIn; + } + } + + ZoomWindow(whichWindow, zoomPart, false); + InvalRect(&whichWindow->portRect); + TkMacInvalClipRgns((TkWindow *) tkwin); + + LocalToGlobal(&location); + TkMacWindowOffset(whichWindow, &xOffset, &yOffset); + location.h -= xOffset; + location.v -= yOffset; + TkGenWMConfigureEvent(tkwin, location.h, location.v, + whichWindow->portRect.right - whichWindow->portRect.left, + whichWindow->portRect.bottom - whichWindow->portRect.top, + TK_BOTH_CHANGED); + return true; +} + +/* + *---------------------------------------------------------------------- + * + * TkUnsupported1Cmd -- + * + * This procedure is invoked to process the "unsupported1" Tcl + * command. This command allows you to set the style of decoration + * for a Macintosh window. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * Changes the style of a new Mac window. + * + *---------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +TkUnsupported1Cmd( + ClientData clientData, /* Main window associated with + * interpreter. */ + Tcl_Interp *interp, /* Current interpreter. */ + int argc, /* Number of arguments. */ + char **argv) /* Argument strings. */ +{ + Tk_Window tkwin = (Tk_Window) clientData; + TkWindow *winPtr; + register WmInfo *wmPtr; + int c; + size_t length; + + if (argc < 3) { + wrongNumArgs: + Tcl_AppendResult(interp, "wrong # args: should be \"", + argv[0], " option window ?arg ...?\"", (char *) NULL); + return TCL_ERROR; + } + + winPtr = (TkWindow *) Tk_NameToWindow(interp, argv[2], tkwin); + if (winPtr == NULL) { + return TCL_ERROR; + } + if (!(winPtr->flags & TK_TOP_LEVEL)) { + Tcl_AppendResult(interp, "window \"", winPtr->pathName, + "\" isn't a top-level window", (char *) NULL); + return TCL_ERROR; + } + wmPtr = winPtr->wmInfoPtr; + c = argv[1][0]; + length = strlen(argv[1]); + if ((c == 's') && (strncmp(argv[1], "style", length) == 0)) { + if ((argc != 3) && (argc != 4)) { + Tcl_AppendResult(interp, "wrong # arguments: must be \"", + argv[0], " style window ?windowStyle?\"", + (char *) NULL); + return TCL_ERROR; + } + if (argc == 3) { + switch (wmPtr->style) { + case noGrowDocProc: + case documentProc: + interp->result = "documentProc"; + break; + case dBoxProc: + interp->result = "dBoxProc"; + break; + case plainDBox: + interp->result = "plainDBox"; + break; + case altDBoxProc: + interp->result = "altDBoxProc"; + break; + case movableDBoxProc: + interp->result = "movableDBoxProc"; + break; + case zoomDocProc: + case zoomNoGrow: + interp->result = "zoomDocProc"; + break; + case rDocProc: + interp->result = "rDocProc"; + break; + case floatProc: + case floatGrowProc: + interp->result = "floatProc"; + break; + case floatZoomProc: + case floatZoomGrowProc: + interp->result = "floatZoomProc"; + break; + case floatSideProc: + case floatSideGrowProc: + interp->result = "floatSideProc"; + break; + case floatSideZoomProc: + case floatSideZoomGrowProc: + interp->result = "floatSideZoomProc"; + break; + default: + panic("invalid style"); + } + return TCL_OK; + } + if (strcmp(argv[3], "documentProc") == 0) { + wmPtr->style = documentProc; + } else if (strcmp(argv[3], "noGrowDocProc") == 0) { + wmPtr->style = documentProc; + } else if (strcmp(argv[3], "dBoxProc") == 0) { + wmPtr->style = dBoxProc; + } else if (strcmp(argv[3], "plainDBox") == 0) { + wmPtr->style = plainDBox; + } else if (strcmp(argv[3], "altDBoxProc") == 0) { + wmPtr->style = altDBoxProc; + } else if (strcmp(argv[3], "movableDBoxProc") == 0) { + wmPtr->style = movableDBoxProc; + } else if (strcmp(argv[3], "zoomDocProc") == 0) { + wmPtr->style = zoomDocProc; + } else if (strcmp(argv[3], "zoomNoGrow") == 0) { + wmPtr->style = zoomNoGrow; + } else if (strcmp(argv[3], "rDocProc") == 0) { + wmPtr->style = rDocProc; + } else if (strcmp(argv[3], "floatProc") == 0) { + wmPtr->style = floatGrowProc; + } else if (strcmp(argv[3], "floatGrowProc") == 0) { + wmPtr->style = floatGrowProc; + } else if (strcmp(argv[3], "floatZoomProc") == 0) { + wmPtr->style = floatZoomGrowProc; + } else if (strcmp(argv[3], "floatZoomGrowProc") == 0) { + wmPtr->style = floatZoomGrowProc; + } else if (strcmp(argv[3], "floatSideProc") == 0) { + wmPtr->style = floatSideGrowProc; + } else if (strcmp(argv[3], "floatSideGrowProc") == 0) { + wmPtr->style = floatSideGrowProc; + } else if (strcmp(argv[3], "floatSideZoomProc") == 0) { + wmPtr->style = floatSideZoomGrowProc; + } else if (strcmp(argv[3], "floatSideZoomGrowProc") == 0) { + wmPtr->style = floatSideZoomGrowProc; + } else { + Tcl_AppendResult(interp, "bad style: should be documentProc, ", + "dBoxProc, plainDBox, altDBoxProc, movableDBoxProc, ", + "zoomDocProc, rDocProc, floatProc, floatZoomProc, ", + "floatSideProc, or floatSideZoomProc", + (char *) NULL); + return TCL_ERROR; + } + } else { + Tcl_AppendResult(interp, "unknown or ambiguous option \"", argv[1], + "\": must be style", + (char *) NULL); + return TCL_ERROR; + } + + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * TkpMakeMenuWindow -- + * + * Configure the window to be either a undecorated pull-down + * (or pop-up) menu, or as a toplevel floating menu (palette). + * + * Results: + * None. + * + * Side effects: + * Changes the style bit used to create a new Mac toplevel. + * + *---------------------------------------------------------------------- + */ + +void +TkpMakeMenuWindow( + Tk_Window tkwin, /* New window. */ + int transient) /* 1 means menu is only posted briefly as + * a popup or pulldown or cascade. 0 means + * menu is always visible, e.g. as a + * floating menu. */ +{ + if (transient) { + ((TkWindow *) tkwin)->wmInfoPtr->style = plainDBox; + } else { + ((TkWindow *) tkwin)->wmInfoPtr->style = floatProc; + ((TkWindow *) tkwin)->wmInfoPtr->flags |= WM_WIDTH_NOT_RESIZABLE; + ((TkWindow *) tkwin)->wmInfoPtr->flags |= WM_HEIGHT_NOT_RESIZABLE; + } +} + +/* + *---------------------------------------------------------------------- + * + * TkMacMakeRealWindowExist -- + * + * This function finally creates the real Macintosh window that + * the Mac actually understands. + * + * Results: + * None. + * + * Side effects: + * A new Macintosh toplevel is created. + * + *---------------------------------------------------------------------- + */ + +void +TkMacMakeRealWindowExist( + TkWindow *winPtr) /* Tk window. */ +{ + WmInfo *wmPtr = winPtr->wmInfoPtr; + WindowRef newWindow = NULL; + MacDrawable *macWin; + Rect geometry; + Tcl_HashEntry *valueHashPtr; + int new; + TkMacWindowList *listPtr; + + if (TkMacHostToplevelExists(winPtr)) { + return; + } + + macWin = (MacDrawable *) winPtr->window; + + /* + * If this is embedded, make sure its container's toplevel exists, + * then return... + */ + + if (Tk_IsEmbedded(winPtr)) { + TkWindow *contWinPtr; + + contWinPtr = TkpGetOtherWindow(winPtr); + if (contWinPtr != NULL) { + TkMacMakeRealWindowExist(contWinPtr->privatePtr->toplevel->winPtr); + macWin->flags |= TK_HOST_EXISTS; + return; + } else { + panic("TkMacMakeRealWindowExist could not find container"); + } + + /* + * NOTE: Here we should handle out of process embedding. + */ + + } + + InitialWindowBounds(winPtr, &geometry); + + newWindow = NewCWindow(NULL, &geometry, "\ptemp", false, + (short) wmPtr->style, (WindowRef) -1, true, 0); + if (newWindow == NULL) { + panic("couldn't allocate new Mac window"); + } + + /* + * Add this window to the list of toplevel windows. + */ + + listPtr = (TkMacWindowList *) ckalloc(sizeof(TkMacWindowList)); + listPtr->nextPtr = tkMacWindowListPtr; + listPtr->winPtr = winPtr; + tkMacWindowListPtr = listPtr; + + macWin->portPtr = (GWorldPtr) newWindow; + MacMoveWindow(newWindow, (int) geometry.left, (int) geometry.top); + SetPort((GrafPtr) newWindow); + + if (!windowHashInit) { + Tcl_InitHashTable(&windowTable, TCL_ONE_WORD_KEYS); + windowHashInit = true; + } + valueHashPtr = Tcl_CreateHashEntry(&windowTable, + (char *) newWindow, &new); + if (!new) { + panic("same macintosh window allocated twice!"); + } + Tcl_SetHashValue(valueHashPtr, macWin); + + macWin->flags |= TK_HOST_EXISTS; +} + +/* + *---------------------------------------------------------------------- + * + * TkMacRegisterOffScreenWindow -- + * + * This function adds the passed in Off Screen Port to the + * hash table that maps Mac windows to root X windows. + * + * Results: + * None. + * + * Side effects: + * An entry is added to the windowTable hash table. + * + *---------------------------------------------------------------------- + */ + +void +TkMacRegisterOffScreenWindow( + Window window, /* Window structure. */ + GWorldPtr portPtr) /* Pointer to a Mac GWorld. */ +{ + WindowRef newWindow = NULL; + MacDrawable *macWin; + Tcl_HashEntry *valueHashPtr; + int new; + + macWin = (MacDrawable *) window; + if (!windowHashInit) { + Tcl_InitHashTable(&windowTable, TCL_ONE_WORD_KEYS); + windowHashInit = true; + } + valueHashPtr = Tcl_CreateHashEntry(&windowTable, + (char *) portPtr, &new); + if (!new) { + panic("same macintosh window allocated twice!"); + } + Tcl_SetHashValue(valueHashPtr, macWin); +} + +/* + *---------------------------------------------------------------------- + * + * TkMacUnregisterMacWindow -- + * + * Given a macintosh port window, this function removes the + * association between this window and the root X window that + * Tk cares about. + * + * Results: + * None. + * + * Side effects: + * An entry is removed from the windowTable hash table. + * + *---------------------------------------------------------------------- + */ + +void +TkMacUnregisterMacWindow( + GWorldPtr portPtr) /* Pointer to a Mac GWorld. */ +{ + if (!windowHashInit) { + panic("TkMacUnregisterMacWindow: unmapping before inited");; + } + Tcl_DeleteHashEntry(Tcl_FindHashEntry(&windowTable, + (char *) portPtr)); +} + +/* + *---------------------------------------------------------------------- + * + * TkMacSetScrollbarGrow -- + * + * Sets a flag for a toplevel window indicating that the passed + * Tk scrollbar window will display the grow region for the + * toplevel window. + * + * Results: + * None. + * + * Side effects: + * A flag is set int windows toplevel parent. + * + *---------------------------------------------------------------------- + */ + +void +TkMacSetScrollbarGrow( + TkWindow *winPtr, /* Tk scrollbar window. */ + int flag) /* Boolean value true or false. */ +{ + if (flag) { + winPtr->privatePtr->toplevel->flags |= TK_SCROLLBAR_GROW; + winPtr->privatePtr->toplevel->winPtr->wmInfoPtr->scrollWinPtr = winPtr; + } else if (winPtr->privatePtr->toplevel->winPtr->wmInfoPtr->scrollWinPtr + == winPtr) { + winPtr->privatePtr->toplevel->flags &= ~TK_SCROLLBAR_GROW; + winPtr->privatePtr->toplevel->winPtr->wmInfoPtr->scrollWinPtr = NULL; + } +} + +/* + *---------------------------------------------------------------------- + * + * TkMacGetScrollbarGrowWindow -- + * + * Tests to see if a given window's toplevel window contains a + * scrollbar that will draw the GrowIcon for the window. + * + * Results: + * Boolean value. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +TkWindow * +TkMacGetScrollbarGrowWindow( + TkWindow *winPtr) /* Tk window. */ +{ + TkWindow *scrollWinPtr; + + if (winPtr == NULL) { + return NULL; + } + scrollWinPtr = + winPtr->privatePtr->toplevel->winPtr->wmInfoPtr->scrollWinPtr; + if (winPtr != NULL) { + /* + * We need to confirm the window exists. + */ + if ((Tk_Window) scrollWinPtr != + Tk_IdToWindow(winPtr->display, winPtr->window)) { + scrollWinPtr = NULL; + } + } + return scrollWinPtr; +} + +/* + *---------------------------------------------------------------------- + * + * TkWmFocusToplevel -- + * + * This is a utility procedure invoked by focus-management code. It + * exists because of the extra wrapper windows that exist under + * Unix; its job is to map from wrapper windows to the + * corresponding toplevel windows. On PCs and Macs there are no + * wrapper windows so no mapping is necessary; this procedure just + * determines whether a window is a toplevel or not. + * + * Results: + * If winPtr is a toplevel window, returns the pointer to the + * window; otherwise returns NULL. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +TkWindow * +TkWmFocusToplevel( + TkWindow *winPtr) /* Window that received a focus-related + * event. */ +{ + if (!(winPtr->flags & TK_TOP_LEVEL)) { + return NULL; + } + return winPtr; +} + +/* + *---------------------------------------------------------------------- + * + * TkpGetWrapperWindow -- + * + * This is a utility procedure invoked by focus-management code. It + * maps to the wrapper for a top-level, which is just the same + * as the top-level on Macs and PCs. + * + * Results: + * If winPtr is a toplevel window, returns the pointer to the + * window; otherwise returns NULL. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +TkWindow * +TkpGetWrapperWindow( + TkWindow *winPtr) /* Window that received a focus-related + * event. */ +{ + if (!(winPtr->flags & TK_TOP_LEVEL)) { + return NULL; + } + return winPtr; +} + +/* + *---------------------------------------------------------------------- + * + * TkpWmSetState -- + * + * Sets the window manager state for the wrapper window of a + * given toplevel window. + * + * Results: + * None. + * + * Side effects: + * May maximize, minimize, restore, or withdraw a window. + * + *---------------------------------------------------------------------- + */ + +void +TkpWmSetState(winPtr, state) + TkWindow *winPtr; /* Toplevel window to operate on. */ + int state; /* One of IconicState, ZoomState, NormalState, + * or WithdrawnState. */ +{ + WmInfo *wmPtr = winPtr->wmInfoPtr; + GWorldPtr macWin; + + wmPtr->hints.initial_state = state; + if (wmPtr->flags & WM_NEVER_MAPPED) { + return; + } + + macWin = TkMacGetDrawablePort(winPtr->window); + + if (state == WithdrawnState) { + Tk_UnmapWindow((Tk_Window) winPtr); + } else if (state == IconicState) { + Tk_UnmapWindow((Tk_Window) winPtr); +#ifdef HAVE_APPEARANCE + if (HaveAppearance()) { + /* + * The window always gets unmapped. However, if we can show the + * icon version of the window (collapsed) we make the window visable + * and then collapse it. + * + * TODO: This approach causes flashing! + */ + + if (IsWindowCollapsable((WindowRef) macWin)) { + ShowWindow((WindowRef) macWin); + CollapseWindow((WindowPtr) macWin, true); + } + } +#endif + } else if (state == NormalState) { + Tk_MapWindow((Tk_Window) winPtr); +#ifdef HAVE_APPEARANCE + if (HaveAppearance()) { + CollapseWindow((WindowPtr) macWin, false); + } +#endif + } else if (state == ZoomState) { + /* TODO: need to support zoomed windows */ + } +} +/* + *---------------------------------------------------------------------- + * + * HaveAppearance -- + * + * Determine if the appearance manager is available on this Mac. + * We cache the result so future calls are fast. + * + * Results: + * True if the appearance manager is present, false otherwise. + * + * Side effects: + * Calls Gestalt to query system values. + * + *---------------------------------------------------------------------- + */ + +static int +HaveAppearance() +{ + static initialized = false; + static int haveAppearance = false; + long response = 0; + OSErr err = noErr; + +#ifdef HAVE_APPEARANCE + if (!initialized) { + err = Gestalt(gestaltAppearanceAttr, &response); + if (err == noErr) { + haveAppearance = true; + } + } +#endif + + return haveAppearance; +} diff --git a/mac/tkMacXCursors.r b/mac/tkMacXCursors.r new file mode 100644 index 0000000..29ddc3e --- /dev/null +++ b/mac/tkMacXCursors.r @@ -0,0 +1,961 @@ +/* + * tkMacXCursors.r -- + * + * This file defines a set of Macintosh cursor resources that + * emulate the X cursor set. All of these cursors were + * constructed and donated by Grant Neufeld. (gneufeld@ccs.carleton.ca) + * + * + * Copyright (c) 1995-1996 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) tkMacXCursors.r 1.4 96/01/11 13:18:22 + */ + +/* + * All of the X cursors are defined as 'CURS' resources. However, a + * subset of the X cursors are also defined as 'crsr' resources. Tk + * will attempt to first use the color cursors ('crsr') if it doesn't + * exist it will attempt to use the black & white cursor ('CURS'). + */ + +data 'CURS' (3000, "X_cursor") { + $"E007 F00F F81F 7C3E 3E7C 1FF8 0FF0 07E0" + $"07E0 0FF0 1FF8 3E7C 7C3E F81F F00F E007" + $"0000 6006 700E 381C 1C38 0E70 07E0 03C0" + $"03C0 07E0 0E70 1C38 381C 700E 6006 0000" + $"0007 0007" +}; + +data 'CURS' (3001, "arrow") { + $"0000 0006 001E 007C 01FC 07F8 00F8 01F0" + $"03B0 0720 0E20 1C00 3800 7000 2000 0000" + $"0007 001F 007F 01FE 07FE 1FFC 7FFC 03F8" + $"07F8 0FF0 1F70 3E60 7C60 F840 7040 2000" + $"0001 000E" +}; + +data 'CURS' (3002, "based_arrow_down") { + $"0000 0000 0000 1FE0 0000 1FE0 0300 0300" + $"0300 0B40 0780 0300 0000 0000 0000 0000" + $"0000 0000 0000 1FE0 0000 1FE0 0780 0780" + $"3FF0 1FE0 0FC0 0780 0300 0000 0000 0000" + $"000B 0006" +}; + +data 'CURS' (3003, "based_arrow_up") { + $"0000 0000 0000 0000 0300 0780 0B40 0300" + $"0300 0300 1FE0 0000 1FE0 0000 0000 0000" + $"0000 0000 0000 0300 0780 0FC0 1FE0 3FF0" + $"0780 0780 1FE0 0000 1FE0 0000 0000 0000" + $"0004 0006" +}; + +data 'CURS' (3004, "boat") { + $"0000 0000 0000 0000 0100 03C0 8460 FFFF" + $"0018 0020 0040 FFC0 0000 0000 0000 0000" + $"0000 0000 0000 0000 0100 03C0 87E0 FFFF" + $"FFF8 FFE0 FFC0 FFC0 0000 0000 0000 0000" + $"0007 000F" +}; + +data 'CURS' (3005, "bogosity") { + $"0000 711C 1110 1110 1110 7FFC 5114 5114" + $"5114 5114 7FFC 1110 1110 1110 711C 0000" + $"0000 0000 0000 0000 0000 7FFC 7FFC 7FFC" + $"7FFC 7FFC 7FFC 0000 0000 0000 0000 0000" + $"0001 0007" +}; + +data 'CURS' (3006, "bottom_left_corner") { + $"0000 0000 0000 0000 C000 C020 C840 C880" + $"C900 CA00 CC00 CFC0 C000 C000 FFF0 FFF0" + $"0000 0000 0000 0000 0000 0020 0840 0880" + $"0900 0A00 0C00 0FC0 0000 0000 0000 0000" + $"000F 0000" +}; + +data 'CURS' (3007, "bottom_right_corner") { + $"0000 0000 0000 0000 0003 0403 0213 0113" + $"0093 0053 0033 03F3 0003 0003 0FFF 0FFF" + $"0000 0000 0000 0000 0000 0400 0210 0110" + $"0090 0050 0030 03F0 0000 0000 0000 0000" + $"000F 000F" +}; + +data 'CURS' (3008, "bottom_side") { + $"0000 0000 0100 0100 0100 0100 0100 1110" + $"0920 0540 0380 0100 0000 7FFC 7FFC 0000" + $"0000 0000 0100 0100 0100 0100 0100 1110" + $"0920 0540 0380 0100 0000 0000 0000 0000" + $"000B 0007" +}; + +data 'CURS' (3009, "bottom_tee") { + $"0000 0000 0000 0180 0180 0180 0180 0180" + $"0180 0180 7FFE 7FFE 0000 0000 0000 0000" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"000B 0007" +}; + +data 'CURS' (3010, "box_spiral") { + $"FFFE 8000 BFFE A002 AFFA A80A ABEA AA2A" + $"AAAA ABAA A82A AFEA A00A BFFA 8002 FFFE" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0008 0008" +}; + +data 'CURS' (3011, "center_ptr") { + $"0000 0300 0300 0780 0780 0FC0 0FC0 1FE0" + $"1FE0 3330 2310 0300 0300 0300 0300 0000" + $"0300 0780 0780 0FC0 0FC0 1FE0 1FE0 3FF0" + $"3FF0 7FF8 77B8 6798 0780 0780 0780 0780" + $"0001 0006" +}; + +data 'CURS' (3012, "circle") { + $"0000 03C0 0FF0 1FF8 3C3C 381C 700E 700E" + $"700E 700E 381C 3C3C 1FF8 0FF0 03C0 0000" + $"03C0 0FF0 1FF8 3FFC 7FFE 7C3E F81F F81F" + $"F81F F81F 7C3E 7FFE 3FFC 1FF8 0FF0 03C0" + $"0007 0007" +}; + +data 'CURS' (3013, "clock") { + $"1FF8 33CC 6466 4992 4F12 4422 63C6 3FFC" + $"2994 2994 2994 2BD4 6996 781E 7FFE 7FFE" + $"1FF8 3FFC 7FFE 7FFE 7FFE 7FFE 7FFE 3FFC" + $"3FFC 3FFC 3FFC 3FFC 7FFE 7FFE 7FFE 7FFE" + $"0004 0008" +}; + +data 'CURS' (3014, "coffee_mug") { + $"03F8 0C06 1001 1C07 33F9 7001 D001 9001" + $"960D DA55 7A55 36ED 10A1 1001 0802 07FC" + $"03F8 0FFE 1FFF 1FFF 3FFF 7FFF FFFF FFFF" + $"FFFF FFFF 7FFF 3FFF 1FFF 1FFF 0FFE 07FC" + $"0004 0003" +}; + +data 'CURS' (3015, "cross") { + $"0280 0280 0280 0280 0280 0280 FEFE 0000" + $"FEFE 0280 0280 0280 0280 0280 0280 0000" + $"0380 0380 0380 0380 0380 0380 FFFE FFFE" + $"FFFE 0380 0380 0380 0380 0380 0380 0000" + $"0007 0007" +}; + +data 'CURS' (3016, "cross_reverse") { + $"4284 A28A 5294 2AA8 16D0 0AA0 FD7E 0280" + $"FD7E 0AA0 16D0 2AA8 5294 A28A 4284 0000" + $"4384 E38E 739C 3BB8 1FF0 0FE0 FFFE FFFE" + $"FFFE 0FE0 1FF0 3BB8 739C E38E 4384 0000" + $"0007 0007" +}; + +data 'CURS' (3017, "crosshair") { + $"0100 0100 0100 0100 0100 0100 0100 FEFE" + $"0100 0100 0100 0100 0100 0100 0100 0000" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0007 0007" +}; + +data 'CURS' (3018, "diamond_cross") { + $"0280 06C0 0AA0 1290 2288 4284 FEFE 0000" + $"FEFE 4284 2288 1290 0AA0 06C0 0280 0000" + $"0280 06C0 0EE0 1EF0 3EF8 7EFC FEFE 0000" + $"FEFE 7EFC 3EF8 1EF0 0EE0 06C0 0280 0000" + $"0007 0007" +}; + +data 'CURS' (3019, "dot") { + $"0000 0000 0780 1FE0 1FE0 3FF0 3FF0 3FF0" + $"3FF0 1FE0 1FE0 0780 0000 0000 0000 0000" + $"0000 0780 1FE0 3FF0 3FF0 7FF8 7FF8 7FF8" + $"7FF8 3FF0 3FF0 1FE0 0780 0000 0000 0000" + $"0006 0006" +}; + +data 'CURS' (3020, "dotbox") { + $"0000 0000 3FFC 2004 2004 2004 2004 2184" + $"2184 2004 2004 2004 2004 3FFC 0000 0000" + $"0000 0000 3FFC 3FFC 300C 300C 318C 33CC" + $"33CC 318C 300C 300C 3FFC 3FFC 0000 0000" + $"0007 0007" +}; + +data 'CURS' (3021, "double_arrow") { + $"0000 0180 03C0 07E0 0DB0 1998 0180 0180" + $"0180 0180 1998 0DB0 07E0 03C0 0180 0000" + $"0180 03C0 07E0 0FF0 1FF8 3FFC 3BDC 03C0" + $"03C0 3BDC 3FFC 1FF8 0FF0 07E0 03C0 0180" + $"0007 0007" +}; + +data 'CURS' (3022, "draft_large") { + $"0000 0002 000C 003C 00F8 03F8 0FF0 00F0" + $"0160 0260 0440 0840 1000 2000 4000 0000" + $"0003 000F 003E 00FE 03FC 0FFC 3FF8 FFF8" + $"03F0 07F0 0EE0 1CE0 38C0 70C0 E080 4080" + $"0001 000E" +}; + +data 'CURS' (3023, "draft_small") { + $"0000 0002 000C 003C 00F8 03F8 0070 00B0" + $"0120 0220 0400 0800 1000 2000 4000 0000" + $"0003 000F 003E 00FE 03FC 0FFC 3FF8 01F8" + $"03F0 0770 0E60 1C60 3840 7040 E000 4000" + $"0001 000E" +}; + +data 'CURS' (3024, "draped_box") { + $"0000 0000 3FFC 2244 2664 2C34 381C 2184" + $"2184 381C 2C34 2664 2244 3FFC 0000 0000" + $"0000 0000 3FFC 3E7C 3E7C 3C3C 399C 23C4" + $"23C4 399C 3C3C 3E7C 3E7C 3FFC 0000 0000" + $"0007 0007" +}; + +data 'CURS' (3025, "exchange") { + $"0000 47C0 6FE0 7C30 4810 4C00 7E00 0000" + $"0000 00FC 0064 1024 187C 0FEC 07C4 0000" + $"C7C0 EFE0 FFF0 FFF8 FC38 FE10 FF00 FF80" + $"03FE 01FE 10FE 387E 3FFE 1FFE 0FEE 07C6" + $"0007 0007" +}; + +data 'CURS' (3026, "fleur") { + $"0000 0180 03C0 07E0 0180 1188 318C 7FFE" + $"7FFE 318C 1188 0180 07E0 03C0 0180 0000" + $"0180 03C0 07E0 0FF0 17E8 3BDC 7FFE FFFF" + $"FFFF 7FFE 3BDC 17E8 0FF0 07E0 03C0 0180" + $"0007 0007" +}; + +data 'CURS' (3027, "gobbler") { + $"0000 0078 0070 4036 4FB0 7FF0 7E30 7C30" + $"3038 00F0 0FE0 0400 0400 0400 0F00 0000" + $"00FC 00FC E0FF FFFF FFFF FFF8 FFF8 FFF8" + $"FFFC 7FFC 3FF8 1FF0 0E00 1F80 1F80 1F80" + $"0003 000E" +}; + +data 'CURS' (3028, "gumby") { + $"3F00 10C0 C820 EAA0 C820 CBA0 F838 383E" + $"0826 0826 092E 0926 0920 1110 2108 3EF8" + $"3F00 1FC0 CFE0 EFE0 CFE0 CFE0 FFF8 3FFE" + $"0FE6 0FE6 0FEE 0FE6 0FE0 1FF0 3FF8 3EF8" + $"0000 0002" +}; + +data 'CURS' (3029, "hand1") { + $"000C 003C 00F0 01E0 03C0 07E0 0FF0 2FE0" + $"7FF0 5FF0 07E0 07C0 4A00 6200 3400 1800" + $"000C 003C 00F0 01E0 03C0 07E0 0FF0 2FE0" + $"7FF0 7FF0 7FE0 7FC0 7E00 7E00 3C00 1800" + $"0000 000D" +}; + +data 'CURS' (3030, "hand2") { + $"0000 3FC0 4020 3F10 0808 0708 0808 0714" + $"0822 0641 0182 0124 0088 0050 0020 0000" + $"0000 3FC0 7FE0 3FF0 0FF8 07F8 0FF8 07FC" + $"0FFE 07FF 01FE 01FC 00F8 0070 0020 0000" + $"0002 0001" +}; + +data 'CURS' (3031, "heart") { + $"0000 3EF8 638C C106 8002 8002 8002 8002" + $"C006 600C 3018 1830 0C60 06C0 0380 0000" + $"0000 3EF8 7FFC FFFE FFFE FFFE FFFE FFFE" + $"FFFE 7FFC 3FF8 1FF0 0FE0 07C0 0380 0000" + $"0003 0007" +}; + +data 'CURS' (3032, "icon") { + $"FFFF D555 AAAB D555 A00B D005 A00B D005" + $"A00B D005 A00B D005 AAAB D555 AAAB FFFF" + $"FFFF FFFF FFFF FFFF F00F F00F F00F F00F" + $"F00F F00F F00F F00F FFFF FFFF FFFF FFFF" + $"0007 0007" +}; + +data 'CURS' (3033, "iron_cross") { + $"0000 3FFC 1FF8 4FF2 67E6 73CE 799E 7FFE" + $"7FFE 799E 73CE 67E6 4FF2 1FF8 3FFC 0000" + $"7FFE 7FFE FFFF FFFF FFFF FFFF FFFF FFFF" + $"FFFF FFFF FFFF FFFF FFFF FFFF 7FFE 7FFE" + $"0007 0006" +}; + +data 'CURS' (3034, "left_ptr") { + $"0000 0800 0C00 0E00 0F00 0F80 0FC0 0FE0" + $"0FF0 0F80 0D80 08C0 00C0 0060 0060 0000" + $"1800 1C00 1E00 1F00 1F80 1FC0 1FE0 1FF0" + $"1FF8 1FFC 1FC0 1DE0 19E0 10F0 00F0 0070" + $"0001 0004" +}; + +data 'CURS' (3035, "left_side") { + $"0000 6000 6000 6080 6100 6200 6400 6FFC" + $"6400 6200 6100 6080 6000 6000 0000 0000" + $"0000 0000 0000 0080 0100 0200 0400 0FFC" + $"0400 0200 0100 0080 0000 0000 0000 0000" + $"0007 0004" +}; + +data 'CURS' (3036, "left_tee") { + $"0000 0C00 0C00 0C00 0C00 0C00 0C00 0FF8" + $"0FF8 0C00 0C00 0C00 0C00 0C00 0C00 0000" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0007 0004" +}; + +data 'CURS' (3037, "leftbutton") { + $"8002 7FFC 7FFC 4444 4554 4554 4554 4554" + $"4444 7FFC 7FFC 7FFC 7FFC 7FFC 7FFC 8002" + $"FFFE FFFE FFFE FFFE FFFE FFFE FFFE FFFE" + $"FFFE FFFE FFFE FFFE FFFE FFFE FFFE FFFE" + $"0004 0003" +}; + +data 'CURS' (3038, "ll_angle") { + $"0000 0000 0000 0C00 0C00 0C00 0C00 0C00" + $"0C00 0C00 0FF8 0FF8 0000 0000 0000 0000" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"000B 0004" +}; + +data 'CURS' (3039, "lr_angle") { + $"0000 0000 0000 0030 0030 0030 0030 0030" + $"0030 0030 1FF0 1FF0 0000 0000 0000 0000" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"000B 000B" +}; + +data 'CURS' (3040, "man") { + $"0380 1EF0 0280 8100 4387 244B 1D70 0540" + $"0440 0280 0440 0920 1290 1450 783C F83F" + $"0380 1FF0 0380 8100 4387 27CB 1FF0 07C0" + $"07C0 0380 07C0 0FE0 1EF0 1C70 783C F83F" + $"0001 0007" +}; + +data 'CURS' (3041, "middlebutton") { + $"8002 7FFC 7FFC 4444 5454 5454 5454 5454" + $"4444 7FFC 7FFC 7FFC 7FFC 7FFC 7FFC 8002" + $"FFFE FFFE FFFE FFFE FFFE FFFE FFFE FFFE" + $"FFFE FFFE FFFE FFFE FFFE FFFE FFFE FFFE" + $"0004 0007" +}; + +data 'CURS' (3042, "mouse") { + $"0600 0100 0180 0FF0 1008 17E8 1428 1428" + $"17E8 1008 1008 1008 1008 1008 1008 0FF0" + $"0600 0100 0180 0FF0 1FF8 1FF8 1FF8 1FF8" + $"1FF8 1FF8 1FF8 1FF8 1FF8 1FF8 1FF8 0FF0" + $"0000 0000" +}; + +data 'CURS' (3043, "pencil") { + $"0000 00F0 0088 0108 0190 0270 0220 0440" + $"0440 0880 0880 1100 1E00 1C00 1800 1000" + $"0000 00F0 00F8 01F8 01F0 03F0 03E0 07C0" + $"07C0 0F80 0F80 1F00 1E00 1C00 1800 1000" + $"000F 0003" +}; + +data 'CURS' (3044, "pirate") { + $"03C0 07E0 0FF0 1998 1998 0FF0 07E0 03C0" + $"43C2 43C3 2184 1C38 03C0 0FF1 781F 4002" + $"07E0 0FF0 1FF8 3FFC 3FFC 1FF8 0FF0 47E2" + $"E7E7 E7E7 7FFF 3FFC 1FF9 7FFF FFFF F81F" + $"000A 0007" +}; + +data 'CURS' (3045, "plus") { + $"0000 0000 0000 0180 0180 0180 0180 1FF8" + $"1FF8 0180 0180 0180 0180 0000 0000 0000" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0007 0007" +}; + +data 'CURS' (3046, "question_arrow") { + $"07C0 0FE0 1C70 1830 1C30 0C70 00E0 03C0" + $"0380 0280 0280 0EE0 06C0 0380 0100 0000" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 3FF8 1FF0 0FE0 07C0 0380 0100" + $"000E 0007" +}; + +data 'CURS' (3047, "right_ptr") { + $"0000 0010 0030 0070 00F0 01F0 03F0 07F0" + $"0FF0 01F0 01B0 0310 0300 0600 0600 0000" + $"0018 0038 0078 00F8 01F8 03F8 07F8 0FF8" + $"1FF8 3FF8 03F8 07B8 0798 0F08 0F00 0E00" + $"0001 000B" +}; + +data 'CURS' (3048, "right_side") { + $"0000 0000 0006 0006 0106 0086 0046 0026" + $"3FF6 0026 0046 0086 0106 0006 0006 0000" + $"0000 0000 0000 0000 0100 0080 0040 0020" + $"3FF0 0020 0040 0080 0100 0000 0000 0000" + $"0008 000B" +}; + +data 'CURS' (3049, "right_tee") { + $"0000 0030 0030 0030 0030 0030 0030 1FF0" + $"1FF0 0030 0030 0030 0030 0030 0030 0000" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0007 000A" +}; + +data 'CURS' (3050, "rightbutton") { + $"8002 7FFC 7FFC 4444 5544 5544 5544 5544" + $"4444 7FFC 7FFC 7FFC 7FFC 7FFC 7FFC 8002" + $"FFFE FFFE FFFE FFFE FFFE FFFE FFFE FFFE" + $"FFFE FFFE FFFE FFFE FFFE FFFE FFFE FFFE" + $"0004 0003" +}; + +data 'CURS' (3051, "rtl_logo") { + $"0000 7FFE 4022 4022 4022 7FE2 4422 4422" + $"4422 4422 47FE 4402 4402 4402 7FFE 0000" + $"0000 7FFE 7FFE 6076 7FF6 7FF6 7C36 6C36" + $"6C36 6C3E 6FFE 6FFE 6E06 7FFE 7FFE 0000" + $"0007 0007" +}; + +data 'CURS' (3052, "sailboat") { + $"0000 0040 0040 0160 0160 0360 0370 0770" + $"0770 0F78 0F78 1F78 1F7C 3E38 0000 0000" + $"0040 00E0 01E0 03F0 03F0 07F0 07F8 0FF8" + $"0FF8 1FFC 1FFC 3FFC 3FFE 7F7C 7E38 0000" + $"000C 0008" +}; + +data 'CURS' (3053, "sb_down_arrow") { + $"0280 0280 0280 0280 0280 0280 0280 0280" + $"0280 0280 0280 0FE0 07C0 0380 0100 0000" + $"0380 0380 0380 0380 0380 0380 0380 0380" + $"0380 0380 0380 1FF0 0FE0 07C0 0380 0100" + $"000E 0007" +}; + +data 'CURS' (3054, "sb_h_double_arrow") { + $"0000 0000 0000 0000 0810 1818 3FFC 781E" + $"3FFC 1818 0810 0000 0000 0000 0000 0000" + $"0000 0000 0000 0810 1818 381C 7FFE FFFF" + $"7FFE 381C 1818 0810 0000 0000 0000 0000" + $"0007 0007" +}; + +data 'CURS' (3055, "sb_left_arrow") { + $"0000 0000 0000 0000 0800 1800 3FFF 7800" + $"3FFF 1800 0800 0000 0000 0000 0000 0000" + $"0000 0000 0000 0800 1800 3800 7FFF FFFF" + $"7FFF 3800 1800 0800 0000 0000 0000 0000" + $"0007 0001" +}; + +data 'CURS' (3056, "sb_right_arrow") { + $"0000 0000 0000 0000 0000 0010 0018 FFFC" + $"001E FFFC 0018 0010 0000 0000 0000 0000" + $"0000 0000 0000 0000 0010 0018 001C FFFE" + $"FFFF FFFE 001C 0018 0010 0000 0000 0000" + $"0008 000E" +}; + +data 'CURS' (3057, "sb_up_arrow") { + $"0000 0080 01C0 03E0 07F0 0140 0140 0140" + $"0140 0140 0140 0140 0140 0140 0140 0140" + $"0080 01C0 03E0 07F0 0FF8 01C0 01C0 01C0" + $"01C0 01C0 01C0 01C0 01C0 01C0 01C0 01C0" + $"0001 0008" +}; + +data 'CURS' (3058, "sb_v_double_arrow") { + $"0000 0100 0380 07C0 0FE0 0280 0280 0280" + $"0280 0280 0280 0FE0 07C0 0380 0100 0000" + $"0100 0380 07C0 0FE0 1FF0 0380 0380 0380" + $"0380 0380 0380 1FF0 0FE0 07C0 0380 0100" + $"0007 0007" +}; + +data 'CURS' (3059, "shuttle") { + $"0020 0070 00F8 01DE 05DE 09DE 11DE 11DE" + $"11DE 11DE 31DE 71DE FDDE 1888 0078 0030" + $"0020 0070 00F8 01FE 07FE 0FFE 1FFE 1FFE" + $"1FFE 1FFE 3FFE 7FFE FFFE 18F8 0078 0030" + $"0000 000A" +}; + +data 'CURS' (3060, "sizing") { + $"0000 7F80 4000 4000 4000 47E0 4420 4422" + $"4422 0422 07E2 0012 000A 0006 01FE 0000" + $"FFC0 FFC0 FFC0 E000 EFF0 EFF0 EC37 EC37" + $"EC37 EC37 0FF7 0FFF 001F 03FF 03FF 03FF" + $"000E 000E" +}; + +data 'CURS' (3061, "spider") { + $"2010 1020 1020 0840 0840 8787 6798 1FE0" + $"1FE0 6798 8787 0840 0840 1020 1020 2010" + $"7038 3870 3870 1CE0 9FE7 EFDF FFFF 7FF8" + $"7FF8 FFFF EFDF 9FE7 1CE0 3870 3870 7038" + $"0007 0007" +}; + +data 'CURS' (3062, "spraycan") { + $"0018 0040 0D18 1E40 1A18 3F00 2100 3900" + $"2900 3900 2900 3900 3900 2100 2100 3F00" + $"0000 0000 0C00 1E00 1E00 3F00 3F00 3F00" + $"3F00 3F00 3F00 3F00 3F00 3F00 3F00 3F00" + $"0002 0007" +}; + +data 'CURS' (3063, "star") { + $"0100 0280 0280 0280 0440 0440 0440 3938" + $"C006 3838 0920 1290 2448 2828 3018 2008" + $"0100 0380 0380 0380 07C0 07C0 07C0 3FF8" + $"FFFE 3FF8 0FE0 1EF0 3C78 3838 3018 2008" + $"0007 0007" +}; + +data 'CURS' (3064, "target") { + $"0000 0380 0FE0 1C70 3018 600C C106 C286" + $"C106 600C 3018 1C70 0FE0 0380 0000 0000" + $"0000 0380 0FE0 1FF0 3C78 701C E38E E38E" + $"E38E 701C 3C78 1FF0 0FE0 0380 0000 0000" + $"0007 0007" +}; + +data 'CURS' (3065, "tcross") { + $"0100 0100 0100 0100 0100 0100 0100 FFFE" + $"0100 0100 0100 0100 0100 0100 0100 0000" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0007 0007" +}; + +data 'CURS' (3066, "top_left_arrow") { + $"0000 6000 7800 3E00 3F80 1FE0 1E00 0D00" + $"0C80 0440 0420 0010 0008 0004 0000 0000" + $"E000 F800 FE00 7F80 7FE0 3FF8 3FFE 1F80" + $"1FC0 0EE0 0E70 0638 061C 020E 0204 0000" + $"0001 0001" +}; + +data 'CURS' (3067, "top_left_corner") { + $"FFF0 FFF0 C000 C000 CFC0 CC00 CA00 C900" + $"C880 C840 C020 C000 0000 0000 0000 0000" + $"0000 0000 0000 0000 0FC0 0C00 0A00 0900" + $"0880 0840 0020 0000 0000 0000 0000 0000" + $"0000 0000" +}; + +data 'CURS' (3068, "top_right_corner") { + $"0FFF 0FFF 0003 0003 03F3 0033 0053 0093" + $"0113 0213 0403 0003 0000 0000 0000 0000" + $"0000 0000 0000 0000 03F0 0030 0050 0090" + $"0110 0210 0400 0000 0000 0000 0000 0000" + $"0000 000F" +}; + +data 'CURS' (3069, "top_side") { + $"0000 7FFC 7FFC 0000 0100 0380 0540 0920" + $"1110 0100 0100 0100 0100 0100 0000 0000" + $"0000 0000 0000 0000 0100 0380 0540 0920" + $"1110 0100 0100 0100 0100 0100 0000 0000" + $"0004 0007" +}; + +data 'CURS' (3070, "top_tee") { + $"0000 0000 0000 0000 7FFE 7FFE 0180 0180" + $"0180 0180 0180 0180 0180 0000 0000 0000" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0004 0007" +}; + +data 'CURS' (3071, "trek") { + $"0100 0000 0380 07C0 0FE0 0EE0 0FE0 07C0" + $"0380 0100 0BA0 0D60 0920 0820 0820 0000" + $"0000 0380 07C0 0FE0 1FF0 1FF0 1FF0 0FE0" + $"07C0 0BA0 1FF0 1FF0 1FF0 1D70 1C70 0820" + $"0000 0007" +}; + +data 'CURS' (3072, "ul_angle") { + $"0000 0000 0000 0FF8 0FF8 0C00 0C00 0C00" + $"0C00 0C00 0C00 0C00 0000 0000 0000 0000" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0003 0004" +}; + +data 'CURS' (3073, "umbrella") { + $"0000 0890 0228 49A6 27C8 1930 610C 0100" + $"0100 0100 0100 0100 0140 0140 0080 0000" + $"0000 0FF0 1FF8 7FFE 7FFC FFFE FBBE E38E" + $"0380 0380 0380 03C0 03E0 03E0 01C0 0080" + $"0004 0007" +}; + +data 'CURS' (3074, "ur_angle") { + $"0000 0000 0000 0000 1FF0 1FF0 0030 0030" + $"0030 0030 0030 0030 0030 0000 0000 0000" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0004 000B" +}; + +data 'CURS' (3075, "watch") { + $"07E0 07E0 07E0 07E0 0810 1088 1088 108C" + $"138C 1008 1008 0810 07E0 07E0 07E0 07E0" + $"07E0 07E0 07E0 07E0 0FF0 1FF8 1FF8 1FFC" + $"1FFC 1FF8 1FF8 0FF0 07E0 07E0 07E0 07E0" + $"0008 000D" +}; + +data 'CURS' (3076, "xterm") { + $"0C60 0280 0100 0100 0100 0100 0100 0100" + $"0100 0100 0100 0100 0100 0100 0280 0C60" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"000B 0007" +}; + +/* + * The following are color versions of some of the + * cursors defined above. The color cursors will be + * used if the exist in preference to the black & white + * cursors. + */ + +data 'crsr' (3004, "boat", purgeable) { + $"8001 0000 0060 0000 0092 0000 0000 0000" + $"0000 0000 0000 0000 0000 0000 0100 03C0" + $"8460 FFFF 0018 0020 0040 FFC0 0000 0000" + $"0000 0000 0000 0000 0000 0000 0100 03C0" + $"87E0 FFFF FFF8 FFE0 FFC0 FFC0 0000 0000" + $"0000 0000 0007 000F 0000 0000 0000 0000" + $"0000 0000 8008 0000 0000 0010 0010 0000" + $"0000 0000 0000 0048 0000 0048 0000 0000" + $"0004 0001 0004 0000 0000 0000 0112 0000" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 000F 0000 0000 0000 00FF FF00" + $"0000 F000 0F32 25F0 0000 6FFF FFFF FFFF" + $"FFFF 2222 2222 221F F000 2222 2222 21F0" + $"0000 3333 3333 4F00 0000 FFFF FFFF FF00" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 0000 0000 0007 0000 FFFF FFFF" + $"FFFF 0001 BBBB BBBB BBBB 0002 EEEE EEEE" + $"EEEE 0003 DDDD DDDD DDDD 0004 CCCC CCCC" + $"CCCC 0005 4444 4444 4444 0006 1111 1111" + $"1111 000F 0000 0000 0000" +}; + +data 'crsr' (3013, "clock") { + $"8001 0000 0060 0000 0092 0000 0000 0000" + $"0000 0000 1FF8 33CC 6466 4992 4F12 4422" + $"63C6 3FFC 2994 2994 2994 2BD4 6996 781E" + $"7FFE 7FFE 1FF8 3FFC 7FFE 7FFE 7FFE 7FFE" + $"7FFE 3FFC 3FFC 3FFC 3FFC 3FFC 7FFE 7FFE" + $"7FFE 7FFE 0004 0008 0000 0000 0000 0000" + $"0000 0000 8008 0000 0000 0010 0010 0000" + $"0000 0000 0000 0048 0000 0048 0000 0000" + $"0004 0001 0004 0000 0000 0000 0112 0000" + $"0000 000F FFFF FFFF F000 00F6 05FF FF50" + $"6F00 0F60 5F00 56F5 06F0 0F00 F021 F30F" + $"00F0 0F00 F6F1 000F 00F0 0F00 5F00 00F5" + $"00F0 0F60 05FF FF50 06F0 00FF FFFF FFFF" + $"FF00 00F0 F001 100F 0F00 00F0 F001 100F" + $"0F00 00F0 F021 120F 0F00 00F0 F01F F10F" + $"0F00 0FF0 F021 120F 0FF0 0FF4 F500 005F" + $"4FF0 0FFF FFFF FFFF FFF0 0FFF FFFF FFFF" + $"FFF0 0000 0000 0000 0007 0000 FFFF FFFF" + $"FFFF 0001 4444 4444 4444 0002 AAAA AAAA" + $"AAAA 0003 EEEE EEEE EEEE 0004 5555 5555" + $"5555 0005 DDDD DDDD DDDD 0006 7777 7777" + $"7777 000F 0000 0000 0000" +}; + +data 'crsr' (3014, "coffee_mug") { + $"8001 0000 0060 0000 0092 0000 0000 0000" + $"0000 0000 03F8 0C06 1001 1C07 33F9 7001" + $"D001 9001 960D DA55 7A55 36ED 10A1 1001" + $"0802 07FC 03F8 0FFE 1FFF 1FFF 3FFF 7FFF" + $"FFFF FFFF FFFF FFFF 7FFF 3FFF 1FFF 1FFF" + $"0FFE 07FC 0004 0003 0000 0000 0000 0000" + $"0000 0000 8008 0000 0000 0010 0010 0000" + $"0000 0000 0000 0048 0000 0048 0000 0000" + $"0004 0001 0004 0000 0000 0000 0112 0000" + $"0000 0000 00FF FFFF F000 0000 FF42 2222" + $"4FF0 000F 4221 1111 224F 000F FF11 1111" + $"1FFF 00FF 24FF FFFF F42F 0F5F 2222 2222" + $"222F F52F 2222 2222 222F F40F 2222 2222" + $"222F F40F 4FF2 2224 FF2F F52F F2F2 2F2F" + $"2F2F 0F5F F2F2 535F 2F2F 00FF 4FF2 F3F4" + $"FF2F 000F 2222 F2F2 222F 000F 4222 2222" + $"224F 0000 F422 2222 24F0 0000 0FFF FFFF" + $"FF00 0000 0000 0000 0006 0000 FFFF FFFF" + $"FFFF 0001 CCCC 9999 6666 0002 CCCC CCCC" + $"FFFF 0003 3333 3333 6666 0004 9999 9999" + $"FFFF 0005 6666 6666 CCCC 000F 0000 0000" + $"0000" +}; + +data 'crsr' (3027, "gobbler") { + $"8001 0000 0060 0000 0092 0000 0000 0000" + $"0000 0000 0000 0078 0070 4036 4FB0 7FF0" + $"7E30 7C30 3038 00F0 0FE0 0400 0400 0400" + $"0F00 0000 00FC 00FC E0FF FFFF FFFF FFF8" + $"FFF8 FFF8 FFFC 7FFC 3FF8 1FF0 0E00 1F80" + $"1F80 1F80 0003 000E 0000 0000 0000 0000" + $"0000 0000 8008 0000 0000 0010 0010 0000" + $"0000 0000 0000 0048 0000 0048 0000 0000" + $"0004 0001 0004 0000 0000 0000 0112 0000" + $"0000 0000 0000 0000 0000 0000 0000 0222" + $"2000 0000 0000 0111 0000 0300 0000 0011" + $"0220 0100 1616 1011 0000 0361 6111 1111" + $"0000 0111 1114 4415 0000 0311 1144 4451" + $"0000 0011 4444 4415 1000 0004 4444 5151" + $"0000 0000 1515 1510 0000 0000 0200 0000" + $"0000 0000 0300 0000 0000 0000 0200 0000" + $"0000 0000 2323 0000 0000 0000 0000 0000" + $"0000 0000 0000 0000 0006 0000 FFFF FFFF" + $"FFFF 0001 CCCC 9999 6666 0002 DDDD 0000" + $"0000 0003 FFFF 6666 3333 0004 CCCC CCCC" + $"CCCC 0005 8888 8888 8888 0006 FFFF CCCC" + $"9999" +}; + +data 'crsr' (3028, "gumby") { + $"8001 0000 0060 0000 0092 0000 0000 0000" + $"0000 0000 3F00 10C0 C820 EAA0 C820 CBA0" + $"F838 383E 0826 0826 092E 0926 0920 1110" + $"2108 3EF8 3F00 1FC0 CFE0 EFE0 CFE0 CFE0" + $"FFF8 3FFE 0FE6 0FE6 0FEE 0FE6 0FE0 1FF0" + $"3FF8 3EF8 0000 0002 0000 0000 0000 0000" + $"0000 0000 8008 0000 0000 0010 0010 0000" + $"0000 0000 0000 0048 0000 0048 0000 0000" + $"0004 0001 0004 0000 0000 0000 0112 0000" + $"0000 00FF FFFF 0000 0000 000F 1212 FF00" + $"0000 FF00 F131 31F0 0000 FFF0 F3F3 F3F0" + $"0000 FF00 F131 31F0 0000 FF00 F2FF F2F0" + $"0000 4FFF F121 21FF F000 00FF F212 12FF" + $"FF40 0000 F121 21F0 0FF0 0000 F212 12F0" + $"0FF0 0000 F12F 21F0 FFF0 0000 F21F 12F0" + $"0FF0 0000 F12F 21F0 0000 000F 121F 121F" + $"0000 00F1 212F 2121 F000 00FF FFF0 FFFF" + $"F000 0000 0000 0000 0005 0000 FFFF FFFF" + $"FFFF 0001 0000 BBBB 0000 0002 CCCC CCCC" + $"CCCC 0003 AAAA AAAA AAAA 0004 4444 4444" + $"4444 000F 0000 0000 0000" +}; + +data 'crsr' (3031, "heart") { + $"8001 0000 0060 0000 0092 0000 0000 0000" + $"0000 0000 0000 3EF8 638C C106 8002 8002" + $"8002 8002 C006 600C 3018 1830 0C60 06C0" + $"0380 0000 0000 3EF8 7FFC FFFE FFFE FFFE" + $"FFFE FFFE FFFE 7FFC 3FF8 1FF0 0FE0 07C0" + $"0380 0000 0003 0007 0000 0000 0000 0000" + $"0000 0000 8004 0000 0000 0010 0010 0000" + $"0000 0000 0000 0048 0000 0048 0000 0000" + $"0002 0001 0002 0000 0000 0000 00D2 0000" + $"0000 0000 0000 0FFC FFC0 3AAB AA70 E99B" + $"999C E665 A65C E999 999C E666 665C E999" + $"999C D666 665C 3599 9970 0D66 65C0 0359" + $"9700 00D6 5C00 0035 7000 000F C000 0000" + $"0000 0000 0000 0000 0003 0000 FFFF FFFF" + $"FFFF 0001 DDDD 0000 0000 0002 FFFF 6666" + $"CCCC 0003 0000 0000 0000" +}; + +data 'crsr' (3042, "mouse", purgeable) { + $"8001 0000 0060 0000 0092 0000 0000 0000" + $"0000 0000 BE00 0100 0180 0FF0 1008 17E8" + $"1428 1428 17E8 1008 1008 1008 1008 1008" + $"1008 0FF0 FE00 0100 0180 0FF0 1FF8 1FF8" + $"1FF8 1FF8 1FF8 1FF8 1FF8 1FF8 1FF8 1FF8" + $"1FF8 0FF0 0001 0007 0000 0000 0000 0000" + $"0000 0000 8008 0000 0000 0010 0010 0000" + $"0000 0000 0000 0048 0000 0048 0000 0000" + $"0004 0001 0004 0000 0000 0000 0112 0000" + $"0000 1379 4AF0 0000 0000 0000 000F 0000" + $"0000 0000 000F F000 0000 0000 FFFF FFFF" + $"0000 000F 2111 1112 F000 000F 3655 5563" + $"F000 000F 3513 1351 F000 000F 3533 3351" + $"F000 000F 3655 5561 F000 000F 3311 1111" + $"F000 000F 3333 3333 F000 000F 3333 3333" + $"F000 000F 2222 2222 F000 000F 8888 8888" + $"F000 000F 7888 8887 F000 0000 FFFF FFFF" + $"0000 0000 0000 0000 000B 0000 FFFF FFFF" + $"FFFF 0001 EEEE EEEE EEEE 0002 CCCC CCCC" + $"CCCC 0003 DDDD DDDD DDDD 0004 4444 4444" + $"4444 0005 2222 2222 2222 0006 5555 5555" + $"5555 0007 AAAA AAAA AAAA 0008 BBBB BBBB" + $"BBBB 0009 7777 7777 7777 000A 1111 1111" + $"1111 000F 0000 0000 0000" +}; + +data 'crsr' (3043, "pencil", purgeable) { + $"8001 0000 0060 0000 0092 0000 0000 0000" + $"0000 0000 0000 00F0 0088 0108 0190 0270" + $"0220 0440 0440 0880 0880 1100 1E00 1C00" + $"1800 1000 0000 00F0 00F8 01F8 01F0 03F0" + $"03E0 07C0 07C0 0F80 0F80 1F00 1E00 1C00" + $"1800 1000 000F 0003 0000 0000 0000 0000" + $"0000 0000 8008 0000 0000 0010 0010 0000" + $"0000 0000 0000 0048 0000 0048 0000 0000" + $"0004 0001 0004 0000 0000 0000 0112 0000" + $"0000 0000 0000 0000 0000 0000 0000 FFFF" + $"0000 0000 0000 F404 F000 0000 000F 4042" + $"F000 0000 000F F42F 0000 0000 00F5 3FFF" + $"0000 0000 00F3 52F0 0000 0000 0F35 1F00" + $"0000 0000 0F53 2F00 0000 0000 F532 F000" + $"0000 0000 F312 F000 0000 000F 352F 0000" + $"0000 000F FFF0 0000 0000 000F FF00 0000" + $"0000 000F F000 0000 0000 000F 0000 0000" + $"0000 0000 0000 0000 0006 0000 FFFF FFFF" + $"FFFF 0001 CCCC CCCC CCCC 0002 8888 8888" + $"8888 0003 FFFF FFFF 0000 0004 DDDD 0000" + $"0000 0005 FFFF 6666 3333 000F 0000 0000" + $"0000" +}; + +data 'crsr' (3059, "shuttle") { + $"8001 0000 0060 0000 0092 0000 0000 0000" + $"0000 0000 0020 0070 00F8 01DE 05DE 09DE" + $"11DE 11DE 11DE 11DE 31DE 71DE FDDE 1888" + $"0078 0030 0020 0070 00F8 01FE 07FE 0FFE" + $"1FFE 1FFE 1FFE 1FFE 3FFE 7FFE FFFE 18F8" + $"0078 0030 0000 000A 0000 0000 0000 0000" + $"0000 0000 8008 0000 0000 0010 0010 0000" + $"0000 0000 0000 0048 0000 0048 0000 0000" + $"0004 0001 0004 0000 0000 0000 0112 0000" + $"0000 0000 0000 00F0 0000 0000 0000 0F3F" + $"0000 0000 0000 F343 F000 0000 000F 3404" + $"3FF0 0000 0F4F 3404 3FF0 0000 F55F 3404" + $"3FF0 000F 505F 3404 3FF0 000F 005F 3404" + $"3FF0 000F 005F 3404 3FF0 000F 005F 3404" + $"3FF0 00F3 005F 3404 3FF0 0F33 505F 3404" + $"3FF0 FFF3 3F4F 3404 3FF0 000F F000 1222" + $"1000 0000 0000 0111 1000 0000 0000 0011" + $"0000 0000 0000 0000 0006 0000 FFFF FFFF" + $"FFFF 0001 FFFF 6666 3333 0002 DDDD 0000" + $"0000 0003 4444 4444 4444 0004 8888 8888" + $"8888 0005 DDDD DDDD DDDD 000F 0000 0000" + $"0000" +}; + +data 'crsr' (3062, "spraycan") { + $"8001 0000 0060 0000 0092 0000 0000 0000" + $"0000 0000 0018 0040 0D18 1E40 1A18 3F00" + $"2100 3900 2900 3900 2900 3900 3900 2100" + $"2100 3F00 0000 0000 0C00 1E00 1E00 3F00" + $"3F00 3F00 3F00 3F00 3F00 3F00 3F00 3F00" + $"3F00 3F00 0002 0007 0000 0000 0000 0000" + $"0000 0000 8008 0000 0000 0010 0010 0000" + $"0000 0000 0000 0048 0000 0048 0000 0000" + $"0004 0001 0004 0000 0000 0000 0112 0000" + $"0000 0000 0000 0005 2000 0000 0000 0460" + $"0000 0000 FF1F 6005 2000 000F 33F0 0460" + $"0000 000F 10F0 0005 2000 00FF FFFF 0000" + $"0000 00F8 170F 0000 0000 00F5 F70F 0000" + $"0000 00FA F70F 0000 0000 00F9 F70F 0000" + $"0000 00FA F70F 0000 0000 00F9 F70F 0000" + $"0000 00F5 F70F 0000 0000 00F8 170F 0000" + $"0000 00F8 170F 0000 0000 00FF FFFF 0000" + $"0000 0000 0000 0000 000B 0000 FFFF FFFF" + $"FFFF 0001 AAAA AAAA AAAA 0002 7777 7777" + $"7777 0003 5555 5555 5555 0004 2222 2222" + $"2222 0005 4444 4444 4444 0006 BBBB BBBB" + $"BBBB 0007 DDDD DDDD DDDD 0008 EEEE EEEE" + $"EEEE 0009 6666 6666 CCCC 000A CCCC CCCC" + $"FFFF 000F 0000 0000 0000" +}; + +data 'crsr' (3063, "star") { + $"8001 0000 0060 0000 0092 0000 0000 0000" + $"0000 0000 0100 0280 0280 0280 0440 0440" + $"0440 3938 C006 3838 0920 1290 2448 2828" + $"3018 2008 0100 0380 0380 0380 07C0 07C0" + $"07C0 3FF8 FFFE 3FF8 0FE0 1EF0 3C78 3838" + $"3018 2008 0007 0007 0000 0000 0000 0000" + $"0000 0000 8004 0000 0000 0010 0010 0000" + $"0000 0000 0000 0048 0000 0048 0000 0000" + $"0002 0001 0002 0000 0000 0000 00D2 0000" + $"0000 0003 0000 000D C000 000D C000 000D" + $"C000 0035 7000 0035 7000 0035 7000 0FD7" + $"5FC0 F555 557C 0FD5 5FC0 00D7 5C00 035C" + $"D700 0D70 35C0 0DC0 0DC0 0F00 03C0 0C00" + $"00C0 0000 0000 0000 0002 0000 FFFF FFFF" + $"FFFF 0001 FFFF FFFF 0000 0003 0000 0000" + $"0000" +}; + +data 'crsr' (3071, "trek") { + $"8001 0000 0060 0000 0092 0000 0000 0000" + $"0000 0000 0100 0000 0380 07C0 0FE0 0EE0" + $"0FE0 07C0 0380 0100 0BA0 0D60 0920 0820" + $"0820 0000 0000 0380 07C0 0FE0 1FF0 1FF0" + $"1FF0 0FE0 07C0 0BA0 1FF0 1FF0 1FF0 1D70" + $"1C70 0820 0000 0007 0000 0000 0000 0000" + $"0000 0000 8008 0000 0000 0010 0010 0000" + $"0000 0000 0000 0048 0000 0048 0000 0000" + $"0004 0001 0004 0000 0000 0000 0112 0000" + $"0000 0000 0005 0000 0000 0000 0005 0000" + $"0000 0000 00FF F000 0000 0000 0F31 3F00" + $"0000 0000 F322 23F0 0000 0000 F110 11F0" + $"0000 0000 F311 13F0 0000 0000 0F31 3F00" + $"0000 0000 00FF F000 0000 0000 000F 0000" + $"0000 0000 F0FF F0F0 0000 0000 FF0F 0FF0" + $"0000 0000 400F 0040 0000 0000 4000 0040" + $"0000 0000 4000 0040 0000 0000 0000 0000" + $"0000 0000 0000 0000 0006 0000 FFFF FFFF" + $"FFFF 0001 EEEE EEEE EEEE 0002 9999 9999" + $"FFFF 0003 DDDD DDDD DDDD 0004 3333 3333" + $"6666 0005 DDDD 0000 0000 000F 0000 0000" + $"0000" +}; + +data 'crsr' (3075, "watch", purgeable) { + $"8001 0000 0060 0000 0092 0000 0000 0000" + $"0000 0000 07E0 07E0 07E0 07E0 0810 1088" + $"1088 108C 138C 1008 1008 0810 07E0 07E0" + $"07E0 07E0 07E0 07E0 07E0 07E0 0FF0 1FF8" + $"1FF8 1FF8 1FF8 1FF8 1FF8 0FF0 07E0 07E0" + $"07E0 07E0 0008 000D 0000 0000 0000 0000" + $"0000 0000 8008 0000 0000 0010 0010 0000" + $"0000 0000 0000 0048 0000 0048 0000 0000" + $"0004 0001 0004 0000 0000 0000 0112 0000" + $"0000 0000 0FFF FFF0 0000 0000 0FFF FFF0" + $"0000 0000 0FFF FFF0 0000 0000 0FFF FFF0" + $"0000 0000 F020 202F 0000 000F 0222 F221" + $"F000 000F 2222 F123 F000 000F 0222 F121" + $"FF00 000F 22FF F123 FF00 000F 0222 2221" + $"F000 000F 2222 2213 F000 0000 F131 313F" + $"0000 0000 0FFF FFF0 0000 0000 0FFF FFF0" + $"0000 0000 0FFF FFF0 0000 0000 0FFF FFF0" + $"0000 0000 0000 0000 0004 0000 FFFF FFFF" + $"FFFF 0001 CCCC CCCC CCCC 0002 EEEE EEEE" + $"EEEE 0003 BBBB BBBB BBBB 000F 0000 0000" + $"0000" +}; + diff --git a/mac/tkMacXStubs.c b/mac/tkMacXStubs.c new file mode 100644 index 0000000..f1042c2 --- /dev/null +++ b/mac/tkMacXStubs.c @@ -0,0 +1,709 @@ +/* + * tkMacXStubs.c -- + * + * This file contains most of the X calls called by Tk. Many of + * these calls are just stubs and either don't make sense on the + * Macintosh or thier implamentation just doesn't do anything. Other + * calls will eventually be moved into other files. + * + * Copyright (c) 1995-1997 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) tkMacXStubs.c 1.87 97/11/20 18:35:29 + */ + +#include "tkInt.h" +#include <X.h> +#include <Xlib.h> +#include <stdio.h> +#include <tcl.h> + +#include <Xatom.h> + +#include <Windows.h> +#include <Fonts.h> +#include <QDOffscreen.h> +#include <ToolUtils.h> +#include <Sound.h> +#include "tkMacInt.h" + +/* + * Because this file is still under major development Debugger statements are + * used through out this file. The define TCL_DEBUG will decide whether + * the debugger statements actually call the debugger or not. + */ + +#ifndef TCL_DEBUG +# define Debugger() +#endif + +#define ROOT_ID 10 + +/* + * Declarations of static variables used in this file. + */ + +static TkDisplay *gMacDisplay = NULL; /* Macintosh display. */ +static char *macScreenName = "Macintosh:0"; + /* Default name of macintosh display. */ + +/* + * Forward declarations of procedures used in this file. + */ + +static XID MacXIdAlloc _ANSI_ARGS_((Display *display)); +static int DefaultErrorHandler _ANSI_ARGS_((Display* display, + XErrorEvent* err_evt)); + +/* + * Other declrations + */ + +int TkMacXDestroyImage _ANSI_ARGS_((XImage *image)); +unsigned long TkMacXGetPixel _ANSI_ARGS_((XImage *image, int x, int y)); +int TkMacXPutPixel _ANSI_ARGS_((XImage *image, int x, int y, + unsigned long pixel)); +XImage *TkMacXSubImage _ANSI_ARGS_((XImage *image, int x, int y, + unsigned int width, unsigned int height)); +int TkMacXAddPixel _ANSI_ARGS_((XImage *image, long value)); +int _XInitImageFuncPtrs _ANSI_ARGS_((XImage *image)); + +/* + *---------------------------------------------------------------------- + * + * TkpOpenDisplay -- + * + * Create the Display structure and fill it with device + * specific information. + * + * Results: + * Returns a Display structure on success or NULL on failure. + * + * Side effects: + * Allocates a new Display structure. + * + *---------------------------------------------------------------------- + */ + +TkDisplay * +TkpOpenDisplay( + char *display_name) +{ + Display *display; + Screen *screen; + GDHandle graphicsDevice; + + if (gMacDisplay != NULL) { + if (strcmp(gMacDisplay->display->display_name, display_name) == 0) { + return gMacDisplay; + } else { + return NULL; + } + } + + graphicsDevice = GetMainDevice(); + display = (Display *) ckalloc(sizeof(Display)); + display->resource_alloc = MacXIdAlloc; + screen = (Screen *) ckalloc(sizeof(Screen) * 2); + display->default_screen = 0; + display->request = 0; + display->nscreens = 1; + display->screens = screen; + display->display_name = macScreenName; + display->qlen = 0; + + screen->root = ROOT_ID; + screen->display = display; + screen->root_depth = (*(*graphicsDevice)->gdPMap)->cmpSize * + (*(*graphicsDevice)->gdPMap)->cmpCount; + screen->height = (*graphicsDevice)->gdRect.bottom - + (*graphicsDevice)->gdRect.top; + screen->width = (*graphicsDevice)->gdRect.right - + (*graphicsDevice)->gdRect.left; + + screen->mwidth = (screen->width * 254 + 360) / 720; + screen->mheight = (screen->height * 254 + 360) / 720; + screen->black_pixel = 0x00000000; + screen->white_pixel = 0x00FFFFFF; + screen->root_visual = (Visual *) ckalloc(sizeof(Visual)); + screen->root_visual->visualid = 0; + screen->root_visual->class = TrueColor; + screen->root_visual->red_mask = 0x00FF0000; + screen->root_visual->green_mask = 0x0000FF00; + screen->root_visual->blue_mask = 0x000000FF; + screen->root_visual->bits_per_rgb = 24; + screen->root_visual->map_entries = 2 ^ 8; + + gMacDisplay = (TkDisplay *) ckalloc(sizeof(TkDisplay)); + gMacDisplay->display = display; + return gMacDisplay; +} + +/* + *---------------------------------------------------------------------- + * + * TkpCloseDisplay -- + * + * Deallocates a display structure created by TkpOpenDisplay. + * + * Results: + * None. + * + * Side effects: + * Frees memory. + * + *---------------------------------------------------------------------- + */ + +void +TkpCloseDisplay( + TkDisplay *displayPtr) +{ + Display *display = displayPtr->display; + if (gMacDisplay != displayPtr) { + panic("TkpCloseDisplay: tried to call TkpCloseDisplay on bad display"); + } + + /* + * Make sure that the local scrap is transfered to the global + * scrap if needed. + */ + + TkSuspendClipboard(); + + gMacDisplay = NULL; + if (display->screens != (Screen *) NULL) { + if (display->screens->root_visual != (Visual *) NULL) { + ckfree((char *) display->screens->root_visual); + } + ckfree((char *) display->screens); + } + ckfree((char *) display); + ckfree((char *) displayPtr); +} + +/* + *---------------------------------------------------------------------- + * + * MacXIdAlloc -- + * + * This procedure is invoked by Xlib as the resource allocator + * for a display. + * + * Results: + * The return value is an X resource identifier that isn't currently + * in use. + * + * Side effects: + * The identifier is removed from the stack of free identifiers, + * if it was previously on the stack. + * + *---------------------------------------------------------------------- + */ + +static XID +MacXIdAlloc( + Display *display) /* Display for which to allocate. */ +{ + static long int cur_id = 100; + /* + * Some special XIds are reserved + * - this is why we start at 100 + */ + + return ++cur_id; +} + +/* + *---------------------------------------------------------------------- + * + * TkpWindowWasRecentlyDeleted -- + * + * Tries to determine whether the given window was recently deleted. + * Called from the generic code error handler to attempt to deal with + * async BadWindow errors under some circumstances. + * + * Results: + * Always 0, we do not keep this information on the Mac, so we do not + * know whether the window was destroyed. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +TkpWindowWasRecentlyDeleted( + Window win, + TkDisplay *dispPtr) +{ + return 0; +} + +/* + *---------------------------------------------------------------------- + * + * DefaultErrorHandler -- + * + * This procedure is the default X error handler. Tk uses it's + * own error handler so this call should never be called. + * + * Results: + * None. + * + * Side effects: + * This function will call panic and exit. + * + *---------------------------------------------------------------------- + */ + +static int +DefaultErrorHandler( + Display* display, + XErrorEvent* err_evt) +{ + /* + * This call should never be called. Tk replaces + * it with its own error handler. + */ + panic("Warning hit bogus error handler!"); + return 0; +} + + +char * +XGetAtomName( + Display * display, + Atom atom) +{ + display->request++; + return NULL; +} + +int +_XInitImageFuncPtrs(XImage *image) +{ + return 0; +} + +XErrorHandler +XSetErrorHandler( + XErrorHandler handler) +{ + return DefaultErrorHandler; +} + +Window +XRootWindow(Display *display, int screen_number) +{ + display->request++; + return ROOT_ID; +} + +XImage * +XGetImage(display, d, x, y, width, height, plane_mask, format) + Display *display; + Drawable d; + int x; + int y; + unsigned int width; + unsigned int height; + unsigned long plane_mask; + int format; +{ + Debugger(); + return NULL; +} + +int +XGetGeometry(display, d, root_return, x_return, y_return, width_return, + height_return, border_width_return, depth_return) + Display* display; + Drawable d; + Window* root_return; + int* x_return; + int* y_return; + unsigned int* width_return; + unsigned int* height_return; + unsigned int* border_width_return; + unsigned int* depth_return; +{ + /* Used in tkCanvPs.c & wm code */ + Debugger(); + return 0; +} + +void +XChangeProperty( + Display* display, + Window w, + Atom property, + Atom type, + int format, + int mode, + _Xconst unsigned char* data, + int nelements) +{ + Debugger(); +} + +void +XSelectInput( + Display* display, + Window w, + long event_mask) +{ + Debugger(); +} + +void +XBell( + Display* display, + int percent) +{ + SysBeep(percent); +} + +void +XSetWMNormalHints( + Display* display, + Window w, + XSizeHints* hints) +{ + /* + * Do nothing. Shouldn't even be called. + */ +} + +XSizeHints * +XAllocSizeHints() +{ + /* + * Always return NULL. Tk code checks to see if NULL + * is returned & does nothing if it is. + */ + + return NULL; +} + +XImage * +XCreateImage( + Display* display, + Visual* visual, + unsigned int depth, + int format, + int offset, + char* data, + unsigned int width, + unsigned int height, + int bitmap_pad, + int bytes_per_line) +{ + XImage *ximage; + + display->request++; + ximage = (XImage *) ckalloc(sizeof(XImage)); + + ximage->height = height; + ximage->width = width; + ximage->depth = depth; + ximage->xoffset = offset; + ximage->format = format; + ximage->data = data; + ximage->bitmap_pad = bitmap_pad; + if (bytes_per_line == 0) { + ximage->bytes_per_line = width * 4; /* assuming 32 bits per pixel */ + } else { + ximage->bytes_per_line = bytes_per_line; + } + + if (format == ZPixmap) { + ximage->bits_per_pixel = 32; + ximage->bitmap_unit = 32; + } else { + ximage->bits_per_pixel = 1; + ximage->bitmap_unit = 8; + } + ximage->byte_order = LSBFirst; + ximage->bitmap_bit_order = LSBFirst; + ximage->red_mask = 0x00FF0000; + ximage->green_mask = 0x0000FF00; + ximage->blue_mask = 0x000000FF; + + ximage->f.destroy_image = TkMacXDestroyImage; + ximage->f.get_pixel = TkMacXGetPixel; + ximage->f.put_pixel = TkMacXPutPixel; + ximage->f.sub_image = TkMacXSubImage; + ximage->f.add_pixel = TkMacXAddPixel; + + return ximage; +} + +GContext +XGContextFromGC( + GC gc) +{ + /* TODO - currently a no-op */ + return 0; +} + +Status +XSendEvent( + Display* display, + Window w, + Bool propagate, + long event_mask, + XEvent* event_send) +{ + Debugger(); + return 0; +} + +int +XGetWindowProperty( + Display *display, + Window w, + Atom property, + long long_offset, + long long_length, + Bool delete, + Atom req_type, + Atom *actual_type_return, + int *actual_format_return, + unsigned long *nitems_return, + unsigned long *bytes_after_return, + unsigned char ** prop_return) +{ + display->request++; + *actual_type_return = None; + *actual_format_return = *bytes_after_return = 0; + *nitems_return = 0; + return 0; +} + +void +XRefreshKeyboardMapping() +{ + /* used by tkXEvent.c */ + Debugger(); +} + +void +XSetIconName( + Display* display, + Window w, + const char *icon_name) +{ + /* + * This is a no-op, no icon name for Macs. + */ + display->request++; +} + +void +XForceScreenSaver( + Display* display, + int mode) +{ + /* + * This function is just a no-op. It is defined to + * reset the screen saver. However, there is no real + * way to do this on a Mac. Let me know if there is! + */ + display->request++; +} + +/* + *---------------------------------------------------------------------- + * + * TkGetServerInfo -- + * + * Given a window, this procedure returns information about + * the window server for that window. This procedure provides + * the guts of the "winfo server" command. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +TkGetServerInfo( + Tcl_Interp *interp, /* The server information is returned in + * this interpreter's result. */ + Tk_Window tkwin) /* Token for window; this selects a + * particular display and server. */ +{ + char buffer[50], buffer2[50]; + + sprintf(buffer, "X%dR%d ", ProtocolVersion(Tk_Display(tkwin)), + ProtocolRevision(Tk_Display(tkwin))); + sprintf(buffer2, " %d", VendorRelease(Tk_Display(tkwin))); + Tcl_AppendResult(interp, buffer, ServerVendor(Tk_Display(tkwin)), + buffer2, (char *) NULL); +} +/* + * Image stuff + */ + +int +TkMacXDestroyImage( + XImage *image) +{ + Debugger(); + return 0; +} + +unsigned long +TkMacXGetPixel( + XImage *image, + int x, + int y) +{ + Debugger(); + return 0; +} + +int +TkMacXPutPixel( + XImage *image, + int x, + int y, + unsigned long pixel) +{ + /* Debugger(); */ + return 0; +} + +XImage * +TkMacXSubImage( + XImage *image, + int x, + int y, + unsigned int width, + unsigned int height) +{ + Debugger(); + return NULL; +} + +int +TkMacXAddPixel( + XImage *image, + long value) +{ + Debugger(); + return 0; +} + +/* + *---------------------------------------------------------------------- + * + * XChangeWindowAttributes, XSetWindowBackground, + * XSetWindowBackgroundPixmap, XSetWindowBorder, XSetWindowBorderPixmap, + * XSetWindowBorderWidth, XSetWindowColormap + * + * These functions are all no-ops. They all have equivilent + * Tk calls that should always be used instead. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +XChangeWindowAttributes( + Display* display, + Window w, + unsigned long value_mask, + XSetWindowAttributes* attributes) +{ +} + +void +XSetWindowBackground( + Display *display, + Window window, + unsigned long value) +{ +} + +void +XSetWindowBackgroundPixmap( + Display* display, + Window w, + Pixmap background_pixmap) +{ +} + +void +XSetWindowBorder( + Display* display, + Window w, + unsigned long border_pixel) +{ +} + +void +XSetWindowBorderPixmap( + Display* display, + Window w, + Pixmap border_pixmap) +{ +} + +void +XSetWindowBorderWidth( + Display* display, + Window w, + unsigned int width) +{ +} + +void +XSetWindowColormap( + Display* display, + Window w, + Colormap colormap) +{ + Debugger(); +} + +/* + *---------------------------------------------------------------------- + * + * TkGetDefaultScreenName -- + * + * Returns the name of the screen that Tk should use during + * initialization. + * + * Results: + * Returns a statically allocated string. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +char * +TkGetDefaultScreenName( + Tcl_Interp *interp, /* Not used. */ + char *screenName) /* If NULL, use default string. */ +{ + if ((screenName == NULL) || (screenName[0] == '\0')) { + screenName = macScreenName; + } + return screenName; +} |