This is Info file pm.info, produced by Makeinfo version 1.68 from the input file bigpm.texi.  File: pm.info, Node: Mac/Apps/PBar, Next: Mac/AssistantFrames, Prev: Mac/Apps/MacPGP, Up: Module List An AppleEvent Module for Progress Bar 1.0.1 ******************************************* NAME ==== Mac::Apps::PBar - An AppleEvent Module for Progress Bar 1.0.1 SYNOPSIS ======== use Mac::Apps::PBar; $bar = Mac::Apps::PBar->new('FTP DOWNLOAD', '100, 50'); $bar->data({ Cap1=>'file: BigFile.tar.gz', Cap2=>'size: 1,230K', MinV=>'0', MaxV=>'1230', }); for(0..10) { $n = $_*123; $bar->data(Valu, $n); sleep(1); } sleep(5); $bar->close_window; DESCRIPTION =========== Progress Bar is a small AppleScriptable utility written by Gregory H. Dow. This module, `PBar.pm', generates Apple Event calls using AEBuild in place of AppleScript. Because the Apple Event Manager is not involved, Progress Bar updates more quickly. In most applications the time taken to up date the Progress Bar must be kept to a minimum. On this machine (68030 CPU) An `AppleScript' update to the progress bar takes about 0.72 seconds. Using `PBar.pm' the time is reduced to 0.10 seconds; a seven-fold improvement. Progress Bar 1.0.1 is found by a search for the creator type `PBar' and launched automatically. To minimise the time taken for the search, `Progress Bar 1.0.1' should be kept in the same volume as `PBar.pm'. CREATING A NEW PROGRESS BAR --------------------------- Progress Bar 1.0.1 is launced and a new Progress bar created by: $bar = Mac::Apps::PBar->new('NAME', 'xpos, ypos'); where the arguments to the new constructor have the following meanings: First argument is a string for the title bar of the Progress Bar window. Second argument is a string `'xpos, ypos'' defining the position of the top left-hand corner of the window in pixels. The pair of numbers and the comma should be enclosed in single quotes as shown. SENDING DATA ------------ Values are sent to the `Progress Bar' by the data sub-routine using the variable names in the `aete resource' for each of the `Progress Bar' properties. There are five property values for the `PBar' class. The syntax is: $bar->data('property', 'value') or $bar->data({'property', 'value', 'property', 'value'}) The second method is suggested. *Minimum value* `'MinV'' This is the value of the displayed parameter corresponding to the origin of the bar. Often it is zero, but may take other values (for instance a temperature bar in degrees Fahrenheit might start at 32). *Maximum value* `'MaxV'' This is the value corresponding to the full extent of the bar. It can take any value, such as the size of a file in KB, or 100 for a percentage variable. Bar increments are integers, hence discrimination is finer the larger the value of `MaxV'. *Current value* `'Valu'' This is the value which sets the progress bar to the position corresponding to the current value of the parameter displayed. The value must obviously lie somewhere between `MinV' and `MaxV'. *Upper caption* `'Cap1'' This string, immediately under the title bar, can be set to anything appropriate for the application. *Lower caption* `'Cap2'' The lower caption string can either be set to a constant value (e.g. `File size = 1234K') or up-dated with the bar. For instance it might be appropriate to set `'Cap2'' as follows: $n = $max_value - $current_value; $bar->data({Cap2=>"remaining $n"}); Note the double quotes so that the value of $n is interpolated. It should be remembered however that it will take twice as long to update both `Cap2' and `Valu' as just to update the bar `Valu' by itself. In applications where speed is of the essence, just the bar value `Valu' should be changed. SEE ALSO -------- The following documents, which are relevant to AEBuild, may be of interest: AEGizmos_1.4.1 Written by Jens Peter Alfke this gives a description of AEBuild on which the MacPerl AEBuildAppleEvent is based. Available from: ftp://dev.apple.com/ devworld/Tool_Chest/Interapplication_Communication/ AE_Tools_/AEGizmos_1.4.1 aete.convert A fascinating MacPerl script by David C. Schooley which extracts the aete resources from scriptable applications. It is an invaluable aid for the construction ofAEBuild events. Available from: ftp://ftp.ee.gatech.edu/ pub/mac/Widgets/ aete.converter_1.1.sea.hqx AE_Tracker This a small control panel which allows some or all AE Events to be tracked at various selectable levels of information. It is relatively difficult to decipher the output but AE_Tracker can be helpful. Available from: ftp://ftp.amug.org/ pub/amug/bbs-in-a-box/files/system7/a/ aetracker2.0.sit.hqx Inside Macintosh Chapter 6 "Resolving and Creating Object Specifier Records" . The summary can be obtained from: http://gemma.apple.com/ dev/techsupport/insidemac/IAC/ IAC-287.html Progress Bar 1.0.1 Obtainable from Info-Mac archives as: info-mac/dev/osa/progress-bar-1.0.1.hqx References are valid as of May 1997. AUTHORS ======= Chris Nandor `' http://pudge.net/ Alan Fry `' Copyright (c) 1998 Chris Nandor and Alan Fry. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. Please see the Perl Artistic License. HISTORY ======= Version 1.3, 3 January 1998 General cleanup. Now requires MacPerl 5.1.4r4. Version 1.2, 13 October 1997 Switched to Mac::Apps::Launch package. Version 1.1, 16 September 1997 Put in the hashref methods to change multiple data in one call.  File: pm.info, Node: Mac/AssistantFrames, Next: Mac/Comm/OT_PPP, Prev: Mac/Apps/PBar, Up: Module List GUI-Class to build an assistant-like line of frames resembles the standard OS assistants/wizards. ************************************************************************************************* NAME ==== Mac::AssistantFrames - GUI-Class to build an assistant-like line of frames resembles the standard OS assistants/wizards. SYNOPSIS ======== This uses a static predefined sequence. This is easy to set up and easy to process. use Mac::AssistantFrames; my $assist = Mac::AssistantFrames->new(); $assist->addToSequence(sub { $assist->startFrame("title", "description"); }); $assist->addToSequence(sub { $assist->yesnoFrame("title", "description"); }); $assist->addToSequence(sub { $assist->finishFrame("title", "description"); }); my $res = $assist->processSequence(); if (defined($res)) { print join(":", @$res); } This is for handcoded sequencing through dialogs - this allows a flexible sequence and shows some more of the methods. use Mac::AssistantFrames; my $assist = Mac::AssistantFrames->new(); while ($assist->running()) { my $last = $assist->getLastFrame(); if ($last eq "") { $assist->startFrame("title", "description"); } elsif ($last eq "") { $assist->constantFrame("dlg1", "title", "description", "value"); } elsif ($last eq "dlg1") { $assist->singleSelectionFrame("dlg2", "title", "description", ["v1", "v2", "v3"]); } elsif ($last eq "dlg2") { $assist->constantHiddenFrame("dlg3", "value"); } elsif ($last eq "dlg3") { $assist->finishFrame("title", "description"); } } if ($assist->getLastFrame eq "") { print $assist->joinedAnswersr(":"), "\n"; } else { print "aborted\n"; } DESCRIPTION =========== This Module implements simple assistant style frames for MacPerl. You can use it if you need to ask the user some questions in sequence to accomplish a task. This could be done with one dialogbox, too. But the assistant approach is often easier to understand, especially if the user doesn't know much about the subject at hand. This is the case most often with configuration of new software packages, where the user has to be given much more detailed descriptions of what to do as would fit on a simple dialog. The AssistantFrame allows backward navigation in case the user erred on some of his answers. It allows complete backwind of the frames (abortion of the process) and it has a uniform userinterface that resembles a lot the Mac-style assistants. CLASS METHODS ============= new() This constructor creates a new frame sequence object. Version() This method returns the version of the module. METHODS ======= running() This checks if the assistant object is in running state. If the "" frame is aborted, this is reset to 0. If the "" frame is accepted, this is reset to 0. backupOne() This method backs up one frame. This is internally used, you seldom have to invoke it yourself. continueOne(name, value) This method adds a successfull frame to the sequence. This is used internally, so you shouldn't need to call this yourself. abort([text]) This method stops the assistant. If "text" is given, it creates an alert dialog. If it is not given, the assistant is just canceled. This can be used to react on errors in a assistant processing. standardAction(name, dlg) This method is internally used to process the events from the dialog. Just ignore it. getLastFrame() This method returns the last frame the user completed. This is needed to allow backing up and sequencing correctly. If the sequence of frames is empty, it returns "". getLastFrameRaw() This method is used to get the last frame, as is getLastFrame. Only difference: getLastFrameRaw delivers the frame-name in "raw" format - names of hidden constant elements is bracketed in []. This function is used internally to distinguish frames from constants. getLastAnswer() This returns the last answer given. It is usefull to make frames dependend on older frames. getAnswers() This returns a reference to the array of the answer-strings. joinedAnswers(sep) This returns a string created by joining all answers together, separated by sep. getNumAnswers() This returns the number of accumulated answers. addToSequence(closure) This adds the closure to the sequence array of the assistant. The sequence array allows a simple processing of a static sequence of frames. processSequence() This processes the sequence array and returns a reference to the array of answers. FRAMES ====== startFrame(title, description) This frame has the special name "". It must be the first frame in the sequence and should give the user a short introduction into the task at hand. The user can only abort the sequence if he is at this frame and backs up, or by closing the window of the current frame (this can be done in any frame). The startframe produces the empty string as value. Any other frame can take over the rule of the startframe by giving it the name "". finishFrame(title, description) This frame has the special name "". It must be the last frame in the sequence and should give the user a description of the effect this whole sequence would have if completed. It produces the empty string as value. Any frame can take over the rule of the finish-frame by giving it the name "". constantFrame(dlg, title, description, value) This frame is just an informational Message that is associated with a constant value. It is often needed if you have to give more detailed descriptions. constantHiddenFrame(value) This frame is no frame - it is just a constant value that is spliced into the answer list. This might be needed by your application, if you want to construct a string out of the answer-list with join. If backed-up, this frame is ignored. textEntryFrame(dlg, title, description, value) This frame allows the entry of free text into a frame. This text is then delivered as answer. extendedTextEntryFrame(dlg, title, description, value, format, [pattern]) This is identical to textEntryFrame, except that it shows some additional description on the format of the text to be entered. An optional additional parameter gives you the possibility to give a regexp that must match with the entered string. numberEntryFrame(dlg, title, description, value) This is identical to textEntryFrame, but it expects you to enter a number and does check the syntax of your entry. Numbers are always delivered with a sign, even if that is "+". extendedNumberEntryFrame(dlg, title, description, value, format, from, to) This is identical to numberEntryFrame, except that you can give an additional parameter that gives a description about the number to be entered. Two more additional parameters make a range of numbers you are allowed to enter. yesnoFrame(dlg, title, description) This frame asks a simple yes-no question. This may be used for asking for optional parts of the assistant. It delivers a Y or a N as answer. radioFrame(dlg, title, description, values, labels [, offset]) This frame presents a selection using radio buttons. Only one value can be selected. This is usefull for small selections. The strings from labels are used for the frame, the strings from values are delivered in the answer. The offset is used for the positioning of the elements. singleSelectFrame(dlg, title, description, [val1, val2, val3]) This frame allows a single selection out of a list of values. This should be used if there are more than 5 values to choose from, or if the number of values is not known at compiletime. COPYRIGHT ========= Copyright 1998, Georg Bauer This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. AVAILABILITY ============ The latest version of this library is likely to be available from: http://www.westfalen.de/hugo/mac/ If there are problems with this library, just drop a note to: Georg_Bauer@muensterland.org =cut  File: pm.info, Node: Mac/Comm/OT_PPP, Next: Mac/FileSpec/Unixish, Prev: Mac/AssistantFrames, Up: Module List Interface to Open Transport PPP ******************************* NAME ==== Mac::Comm::OT_PPP - Interface to Open Transport PPP SYNOPSIS ======== use Mac::Comm::OT_PPP; $ppp = new Mac::Comm::OT_PPP; DESCRIPTION =========== This module allows you to do basic operations with OT/PPP, the PPP connection software from Apple Computer designed for use with their Open Transport networking architecture. For more information on Open Transport or OT/PPP, see the Open Transport web site. PPPconnect $ppp->PPPconnect(USER,PASS,ADRS); Connect to phone number ADRS as user USER with password PASS. PPPdisconnect $ppp->PPPdisconnect(); Disconnect. PPPstatus $hash = $ppp->PPPstatus(); foreach $key (keys %{$hash}) { print "$key: $$hash{$key}\n"; } Return status: RAsb State of connection RAsc Seconds connected RAsr Seconds remaining RAun User name RAsn Server name RAms Most recent message for connection RAbm Baud rate of connection RAbi Bytes in/received RAbo Bytes out/sent RAsp Connection type (?) PPPsavelog $ppp->PPPsavelog(FILE); Save log to file of filepath FILE. Operation can take a minute or two if the log is big, and might freeze up your computer while working. Be patient. VERSION NOTES ============= v.1.2 January 3, 1998 General cleanup. v.1.1 October 13, 1997 Took some code and threw it in a module. v.1.0 May 4, 1997 Took some code and threw it in a module. SEE ALSO ======== Open Transport Home Page http://tuvix.apple.com/dev/opentransport AUTHOR ====== Chris Nandor `' http://pudge.net/ Copyright (c) 1998 Chris Nandor. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. Please see the Perl Artistic License. VERSION ======= Version 1.20 (03 January 1998)  File: pm.info, Node: Mac/FileSpec/Unixish, Next: Mac/Glue, Prev: Mac/Comm/OT_PPP, Up: Module List Unixish-compatability in file specifications ******************************************** NAME ==== Mac::FileSpec::Unixish - Unixish-compatability in file specifications SYNOPSIS ======== use Mac::FileSpec::Unixish; # exports 'unixify' and 'nativize' @input = map( unixify($_), @ARGV); foreach $item (@input) { my $_native_item = nativize($item); next unless $item =~ m<([^/]+)$>s # assumes / is the path separator and -f $_native_item; printf("File %s is %d bytes long...\n", $1, -s _ ); open(IN, "<$_native_item") || die "Can't open $_native_item : $!\n"; print "First line: ", scalar(); close(IN); } DESCRIPTION =========== Mac::FileSpec::Unixish provides two functions, `nativize' and `unixify' (both of which are exported by default), that will allow you to denote and manipulate pathspecs in Unixish style, and let you convert these pathspecs to and from the native OS's format for conveying such things. It currently assumes that if you are not running under MacOS (as reported in $^O), you must be on a Unix box. If you want better, I suggest using File::Spec. (In essence, I wrote Mac::FileSpec::Unixish as a cheap hack to get around using File::Spec.) Using this library, you can, in your code, refer to files using a Unixish notation, a la: $foo = "../analyses/ziz.txt"; open(OUT, '>' . nativize($foo) ) || die "Couldn't open $foo \: $!"; Under Unix, `nativize($foo)' will be simply "../analyses/ziz.txt" (`nativize' and `unixify' are nearly no-ops under Unixes); but under MacOS it will be "::analyses:ziz.txt". Incidentally, `nativize(unixify($item))' is always eq $item, for all (defined, non-undef) values of $item, regardless of whether or not this is performed under MacOS. In other words, this: @items = map(unixify($_), @ARGV); foreach $one (@items) { print "$one => ", -s nativize($one), " bytes\n"; my $one_copy = $one; $one_copy =~ s/[^/]+$//s; print " in the directory $one_copy"; } will work equally well under MacOS as under Unix, regardless of the fact that items in @ARGV will be in "foo:bar:baz" format if run under MacOS, and "/foo/bar/baz" format if run under Unix. This portability is the entire point of this library. (This code will work even if run under MacOS and if @ARGV contains a pathspec like "Sean:reports:by week:5/5/98". `unixify' encodes those slashes (as "\e2f", if you're curious) so that they won't be misunderstood as path separators in the Unixish representation - see "GUTS", below, for the gory details.) This library also provides (but does not by default export) a function Mac::FileSpec::Unixish::under_macos(), which returns true if you're running under MacOS, and false otherwise. You can use that in cases like: my $home = Mac::FileSpec::Unixish::under_macos() ? '/Sean/' : '~/' ; PURPOSE ------- This library exists so that a careful programmer who knows what filespecs are legal and meaningful both under Mac and under Unix, can write code that manipulates files and filenawes, and have this code work equally well under MacOS and under Unix. That's all this library is for, and that's all it does. This library doesn't overload anything, so *don't* go thinking that you can go open(OUT, '>../foo/bar.txt"); under MacOS. Proper use of this library means that every time you pass a file specification to any file operation (from chdir to -s to opendir), you should pass the Unixish designation thru `nativize' - and every time you get a file spec from the OS (thru `@ARGV' or `StandardFile::GetFolder("Select a folder")' or whatever), that you pass it thru `unixify' to get the Unixish representation. `nativize' and `unixify' are the only two functions this module exports. This library doesn't try to interpret Unixish pathspecs with any semantics other than the above-described - to wit, "~"s in filespecs (as in `~/.plan' or `~luser/.plan') aren't expanded, since there is no equivalent meaning under MacOS. And if you say "/tmp/", you *will* get "tmp:" under MacOS - and this is probably not what you want. This (coupled with the fact that MacOS has nothing like "/", save as a notational (or notional) base for the mounted volumes) almost definitely means that *you don't want to use any absolute pathspecs like "/tmp/" or "/usr/home/luser" or "/Sean/System Folder", or pathspecs based on ~ or ~luser*. In other words, your pathspecs should either come from outside the program (as from %ENV, @ARGV, or things you devise based on them), or should be relative. You have been warned! GUTS ---- Here are some of the icky details of how this module works. "Unixish" path specification means pathspecs expressed with the meanings that Unix assigns to '/', '.', and '..' - with the additional bit of semantics that the escape character (ASCII 0x1B, a.k.a. `"\e"') and two hex ([a-fA-F0-9]) characters after it denote the one character with that hex code. In other words, it's just like URL-encoding, but with `ESC' instead of %. I included this quoting mechanism so it would be possible to denote, in Unixish notation, Mac filenames with "/"s in them. Example: "Foovol:stuff:05/98" -> "/Foovol/stuff/05\e2f98" But actual hardcoding of "\e2f" is unwise, since if you have: open(OUT, '>' . nativize("/Foovol/stuff/05\e2f98")); This will Do What You Want only if you're under MacOS, but under Unix it will instead try to write to `/Foovol/stuff/05/98'. As mentioned above, `nativize(unixify($item))' is always $item, for all values of $item, and regardless of whether or not this is performed under MacOS. But the inverse (i.e., whether `unixify(nativize($item))') is not necessarily true! In a rather dramatic case, `nativize("/")' happens to yield "" under MacOS, for many, many reasons. Other, more mundane cases include the fact that "../foo" and "./../foo" and, for that matter, ".././foo" are all synonyms for the same thing, and the (notational if not meaningful) distinction between them may be smashed - under MacOS, they'd all end up "::foo". A Note on Trailers ------------------ Note that when a trailing MacOS ":" means 'directory' (e.g., "Sean:reports:", it is represented as a trailing '/' in the Unixish representation, and vice versa. When I'm writing code, I always use a trailer (a trailing ":" or "/") when accessing a directory (as is `opendir(FOODIR, ":foo:bar:")' or `opendir(FOODIR, "./foo/bar/")' ). Now, this is generally unnecessary; `opendir(FOODIR, ":foo:bar:")' and `opendir(FOODIR, ":foo:bar:")' do the same thing, just as `opendir(FOODIR, "foo/bar/")' and `opendir(FOODIR, "foo/bar")' do the same thing on (absolutely all?) Unix boxes. However, when accessing the root drive of a MacOS volume, the "root" directory of a volume, like "foo", you should use the trailer - `opendir(FOODIR, "foo:")', not `opendir(FOODIR, "foo")'. It's odd to note that MacOS seems inconsistent about using the trailer. If you drop the Finder icon for the volume "foo" onto a droplet, it'll see "foo:" in @ARGV - with the trailer. But if you drop the Finder icon for the directory "foo:bar" (or any other non-volume-root directory I've tested this on) onto a droplet, it'll see "foo:bar" in @ARGV - no trailer. COPYRIGHT ========= Copyright 1998-2000, Sean M. Burke `sburke@cpan.org', all rights reserved. You may use and redistribute this library under the same terms as Perl itself. AUTHOR ====== Sean M. Burke `sburke@cpan.org'  File: pm.info, Node: Mac/Glue, Next: Mac/Macbinary, Prev: Mac/FileSpec/Unixish, Up: Module List Control Mac apps with Apple event terminology ********************************************* NAME ==== Mac::Glue - Control Mac apps with Apple event terminology SYNOPSIS ======== use Mac::Glue; my $glue = Mac::Glue->new('Finder'); $glue->open( $glue->prop('System Folder') ); # see rest of docs for lots more info DESCRIPTION =========== You should have the latest cpan-mac distribution: http://sourceforge.net/projects/cpan-mac/ For more information, support, CVS, etc.: http://sourceforge.net/projects/mac-glue/ Mac OS apps speak to each other with a *lingua franca* called *Apple events*. The most common way to do Apple events (aside from doaing them in a precompiled application with C, Pascal, etc.) is with AppleScript. Other languages can do Apple events too, like Frontier and even Python. But we like Perl. MacPerl has for a few years had an interface to Apple events, with the Mac::AppleEvents module, which is the basis for everything we'll do here. Mac::AppleEvents::Simple was made to simplify the process of doing Apple events in MacPerl, but even that can be too much trouble to use. One has to find out the class and event IDs, find out the keywords and data types for each parameter, etc. So the vision was born for a framework that wouldn't take much significant work. An application's AETE resource would provide the names to match to the cryptic four-character codes we had been using. Compare. Raw Mac::AppleEvents method use Mac::AppleEvents; $evt = AEBuildAppleEvent('aevt', 'odoc', typeApplSignature, 'MACS', kAutoGenerateReturnID, kAnyTransactionID, "'----': obj{want:type(prop), from:'null'()," . "form:prop, seld:type(macs)}" ) or die $^E; $rep = AESend($evt, kAEWaitReply) or die $^E; AEDisposeDesc($evt); AEDisposeDesc($rep); Easier Mac::AppleEvents::Simple method use Mac::AppleEvents::Simple; do_event(qw(aevt odoc MACS), "'----': obj{want:type(prop), from:'null'()," . "form:prop, seld:type(macs)}" ); Cool Mac::Glue method use Mac::Glue; my $glue = Mac::Glue->new('Finder'); $glue->open( $glue->prop('System Folder') ); The latter is much simpler to understand, to read, to write. It leverages the user's understanding of AppleScript. And it is just more natural. There are downsides. Mac::Glue is less powerful than the Mac::AppleEvents raw interfaces, because it offers less flexibility in how events are called. It is also slower to start a script, because the glue structures need to be loaded in. However, once a script has started, a difference in speed from the raw interfaces should be minimal (though not a lot of testing has been done on that). With the code above, on a PowerBook G3/292, running Mac OS 8.6: Benchmark: timing 100 iterations of glue, glue2, raw, simple... glue: 10 secs ( 9.98 usr 0.00 sys = 9.98 cpu) glue2: 8 secs ( 8.35 usr 0.00 sys = 8.35 cpu) raw: 8 secs ( 7.88 usr 0.00 sys = 7.88 cpu) simple: 7 secs ( 7.50 usr 0.00 sys = 7.50 cpu) The "glue2" entry is the same as "glue" entry, but it creates a glue object only once instead of each time through, cutting down on the overhead. It appears that Mac::Glue is a bit slower than the other methods, but not substantially, and it is cooler and easier. The one place where performance is the biggest problem is on initial execution of the program, but once it starts it is plenty fast. We'll work to cut down that start time, too. So, now that you are convinced this is cool, let's continue. Creating a Glue --------------- In order to script an application with Mac::Glue, a glue must be created first. For that, the application is dropped on the `gluemac' droplet. A distribution called Mac::AETE, created by David Schooley, is used to parse an application's AETE resource, and the glue is written out to a file using Storable, DB_File, and MLDBM. Glues are saved in $ENV{MACGLUEDIR} (which is defined when Mac::Glue is used if it is not defined already). By default, glues are stored in `:site_perl:Mac:Glue:glues:'. All glues have access to the global scripting additions and dialect information. Glues for these must be created as well, and are created with the `gluescriptadds' and `gluedialect' programs, which are similar to the `gluemac' program. They are saved in "$ENV{MACGLUEDIR}additions:" and "$ENV{MACGLUEDIR}dialects:". Along with the glue file is a POD file containing documentation for the glue, listing all the events (with parameters), classes (with properties), and enumerators, and descriptions of each. Using a Glue ------------ The first thing you do is call the module. use Mac::Glue; Then you create an object for your app by passing the new function the name of the glue (you may include or omit underscores in the name if you like). my $glue = Mac::Glue->new('My App'); # or My_App You can also pass in additional parameters for the type of target to use. For PPC ports, you can do this: my $glue = Mac::Glue->new('My App', ppc => 'My App Name', 'Server Name', 'Zone'); You may also specify a process serial number: my $glue = Mac::Glue->new('My App', psn => $psn); Note that `$psn' should be a regular long integer, and will be packed into a double long behind the scenes. If this confuses you, don't worry about it; the values returned from the Mac::Processes module are good to pass back in as `$psn'. You can also pass a path to an application: my $glue = Mac::Glue->new('My App', path => $path_to_file); New for Mac OS 9, you can send events over TCP/IP: my $glue = Mac::Glue->new('My App', eppc => 'My App Name', 'some.machine.com'); Once you have your glue set up, you start calling events, as they are documented in the POD file for the glue. The events can be called case-insensitively, with the exception of those that match the names of the special methods (see `"Special parameters and methods"' in this node). In that case, since the special methods are in all caps, the event methods can be called case-insensitively except for all caps. e.g., for an event named reply, it could be called with: $glue->Reply; $glue->reply; $glue->RePLY; However, it could not be called with `$glue->REPLY', since that is reserved. All applications respond to events differently. Something that works for one application might not work for another, so don't use any of these examples as a way you should script a specific application. They are just hyopthetical examples, for the most part. Events sometimes accept parameters, sometimes they don't. The primary parameter of most events is a special parameter called the *direct object* parameter. In your event call, pass the data for that parameter first: $glue->open($file); Other parameters must be named and must be provided as key-value pairs, with the key as the name of the parameter, and the value as the parameter's data: $glue->open($file, using => $myapp); Note that the direct object parameter is the only parameter that doesn't need a name in front of it, and must come first in the list if it is supplied at all. Mac::Glue will attempt to coerce passed data into the expected type. For example, if open expects an alias, the file specification in $file will be turned into an alias before being added to the event. You can override this behavior with the `param_type' function. If open expects an alias (`typeAlias'), but you want to pass text, you can do: $glue->open( param_type($path, typeChar) ); Each datum can be a simple scalar as above, an AEDesc object, an Mac::AEObjDesc object (returned by `obj', `prop', and event methods), an Mac::AEEnum object (returned by the enum function), or an array or hash reference, corresponding to AE lists and records. In this example, we nest them, with an arrayref as one of the values in the hashref, so the AE list is a datum for one of the keys in the AE record: $glue->make(new => 'window', with_properties => {name => "New Window", position => [100, 200]}); The words "name" and "position" will be changed into the proper corresponding AE IDs. And on return, record keys will be changed back from the AE IDs into the English words. Events return direct object parameters, turned into suitable data for use in the program. Aliases are resolved into file specifications, AE records and lists are turned into Perl hashes and arrays (recursively, for nested lists), etc. my @urls = $sherlock->search_internet('AltaVista', 'for' => 'Mac::Glue'); AE objects (which will be discussed later) are returned as `Mac::AEObjDesc' objects, so they may be used again by being passed back to another event. my $window_object = $glue->get( window => 1 ); $glue->save($window_object); This allows AppleScript-like loops: my @selection = $glue->get( $glue->prop(selection => of => window) ); my @owners; for my $item (@selection) { push @owners, $glue->get( $glue->obj(cell => 'Owners' => $item) ); } Some objects may allow an easy way to get a human-readable form, with the `as' parameter: my $item = $glue->get( file => 1, as => 'string' ); Errors are returned in the special variable $^E, which should be checked immediately after an event call. $glue->close(window => 1); if ($^E) { warn "Couldn't close window: $^E\n"; } Or, if a value is expected and none is returned: my $file = $glue->choose_file('Select a file, please.') or die "No file chosen: $^E"; Checking $^E only works if the error returned is an error number. If it isn't, the actual error is available from the reply event, which can be accessed by using the RETOBJ parameter (described below in `"Special parameters and methods"' in this node). You can also handle errors with the ERRORS handlers (also described below in `"Special parameters and methods"' in this node). Creating object specifier records --------------------------------- This is one of the more complex parts of Apple events, and it is only partially implemented (though full implementation is expected eventually, and most of it is implemented now). Object specifier records are created by the `obj' method, and have four components to them. class container form data The class and data are passed as key-value pairs, like in AE records or parameter lists. The form and the type of the data are determined by the glue data or a good guess. The container is determined by the order of the key-value pairs: each pair is contained by the pair or object that follows it. my $obj = $glue->obj(file => 'foo', folder => 'bar', disk => 'buz'); So you have three pairs. The key of each pair ("file", "folder", "disk") is the class. The value of each pair ("foo", "bar", "baz") is the data. Because the data are each text, the form defaults to formName, and the data type defaults to typeChar (TEXT). If the data is a number, then the form would be formAbsolutePosition, and the data type would be typeLongInteger. So that leaves only the container. Each pair is contained by the pair following it. The disk contains the folder, the folder contains the file. The disk has no container (its container is null). Easy, right? I hope so. That's the idea. But let's go back to the forms, since that is the only tough part left. The primary forms are types, names, unique IDs, absolute positions, relative positions, tests, and ranges. Normally, text data has form name and type TEXT. Integer data has absolute position form, and integer type. The `obj_form' function accepts three parameters, which allows you to set the form and data, or form, type, and data, in case you want to send data different from how Mac::Glue would guess. These two are the same, since in the second case, the other is assumed: use Mac::Glue ':glue'; $obj1 = $glue->obj(window => obj_form(formAbsolutePostion, typeLongInteger, 1)); $obj2 = $glue->obj(window => 1); Special constants are exported that specify relative positions and absolute positions. $first = $glue->obj(file => gFirst, property => 'Desktop'); $second = $glue->obj(file => gNext, $first); for ($first, $second) { print $glue->get($_, as => 'string'); } `of' and in are synonyms of property: $glue->obj(file => gFirst, property => 'Desktop'); $glue->obj(file => gFirst, of => 'Desktop'); $glue->obj(file => gFirst, in => 'Desktop'); The "as" parameter above has a form of type, such as: obj_form(formPropertyID, typeType, 'string'); Then "string" is turned into a four-character ID behind the scenes (in this case, it is "TEXT"). A special method called `prop' is for specifying properties. These are equivalent: $glue->obj(property => 'Desktop'); $glue->prop('Desktop'); Descriptor types for object specifier records --------------------------------------------- Property IDs Normally, the glue will know a property is expected and coerce whatever string you provide into its four-character ID. Sometimes `obj_form(formPropertyID, typeType, 'property_name')' may be appropriate. Name Just pass the data as text. If there is some ambiguity, you may explicitly use `obj_form(formName, typeChar, 'string')'. Unique IDs Could be anything. Absolute position As discussed above, if it is an index number, you can just pass the number, as in `window => 1', or you can explicitly mark it with `window => obj_form(formAbsolutePosition, typeLongInteger, 1)'. For other absolutes, you may use constants, such as `window => gLast'. Choices are `gFirst', `gMiddle', `gLast', `gAny', `gAll'. These are just shortcuts for explicit forms like `obj_form(formAbsolutePosition, typeAbsoluteOrdinal, kAEAll)'. Note that if there is a plural form of the class name, you may use it to mean the same thing as "class => gAll". These are all the same: $f->obj(files => of => 'System Folder'); $f->obj(files => gAll, of => 'System Folder'); $f->obj(file => gAll, of => 'System Folder'); Relative position Similar to absolute position, but an additional object must be specified, such as `file =' gNext, file => gMiddle>, which would return the file after the middle file. Available constants are `gNext' and `gPrevious'. The explicit form is `obj_form(formRelativePosition, typeEnumerated, kAENext)'. Ranges The range function accepts two arguments, the start and stop ranges. range(START, STOP) Each can be a number index, an absolute position constant, a string, or another data type passed with `obj_form'. Here are a few ways to specify files in the System Folder: $f->obj(files => range(1, 5), of => 'System Folder'); $f->obj(files => range(1, "System"), of => 'System Folder'); $f->obj(files => range("Finder", "System"), of => 'System Folder'); $f->obj(files => range(gFirst, "System"), of => 'System Folder'); Whose tests The `whose' function accepts either logical records or comparison records. # comparison record $f->obj(CLASS => whose(CLASS => VALUE, OPERATOR, VALUE)); $f->obj(CLASS => whose(PROPERTY, OPERATOR, VALUE)); PROPERTY and CLASS => VALUE work like prop() and obj(). The PROPERTY form is the same as `property => VALUE'. OPERATOR is contains, equals, `begins_with', `ends_with', `l_t', `l_e', `g_t', or `g_e'. VALUE is the value to compare to. # files whose name begins with "foo" $f->obj(files => whose(name => begins_with => 'foo')); # rows whose first cell equals "bar" $f->obj(rows => whose(cell => 1 => equals => 'bar')); Then there is the logical record type, for use when more than one comparison record is needed. # logical record $f->obj(CLASS => whose(OPERATOR, LIST)); OPERATOR is AND, `OR', or `NOT'. LIST is any number of other logical records or comparison records, contained in anonymous arrays. So you can join any number of records together: # words where it contains "e" and it begins with "p" and it does not end with "s" $aw->obj( words => whose(AND => [it => contains => 'e'], [it => begins_with => 'p'], [NOT => [it => ends_with => 's']] ), $text) Note how each logical record and comparison record following each logical operator is in an anonymous array. Also not how the special word "it" refers to the object being examined. There's one more record type that works similarly to the above object specifier records, but is not exactly the same thing. It's called an *insertion location record*, and is created like this: location(POSITION[, OBJECT]) POSITION is a string, and can be one of before, after, `beginning', or end. `front' is a synonym for `beginning', and back and `behind' are synonyms for after. OBJECT is the object to be positioned against, and will be the null object if not supplied. my $aw = new Mac::Glue 'AppleWorks'; my $text = $aw->prop(text_body => document => 1); $aw->activate; # note null object in location() $aw->make(new => 'document', at => location('front')); $aw->set($text, to => "foo bar buz baz."); $aw->move( $aw->obj(word => 4 => $text), to => location(after => $aw->obj(word => 2 => $text)) ); Special parameters and methods ------------------------------ Special parameters can be passed in the event which control certain aspects of the event call's behavior. They can be passed as parameters (affecting only the one event), or called as methods (which affect every call made from that object). They are all upper case. $glue->REPLY(1); # wait for reply on all events $glue->close(REPLY => 0); # don't wait for this one event REPLY Boolean, for whether or not to wait for a reply. Default is to wait. MODE Set other modes, such as `kAENeverInteract'. This value is OR'd together with the REPLY value. Default is `kAECanInteract | kAECanSwitchLayer'. SWITCH Switch to the application being called. Usually more efficient to use the activate event: $glue->activate; PRIORITY Set the event priority. Default is `kAENormalPriority'. TIMEOUT Number of seconds to wait before timing out. Default is a couple hundred thousand seconds or so. RETOBJ Boolean, for whether or not the event call will return the direct object data (the default), or a Mac::AppleEvents::Simple object, containing references to the actual event and reply, so you can do more advanced things with the data if you want to. ERRORS A subroutine reference that will handle any errors (that is, will be executed only if $^E is true) after the event is executed. Your handler will be passed 6 or more arguments: 0 The glue object 1 The event object (same object returned by RETOBJ) 2 The Glue's name 3 The event's name 4 The error message 5 The error number 6..n Any arguments passed to the event in the first place Example: sub error_handler { my($glue, $event, $gluename, $eventname, $errs, $errn, @args) = @_; my $args = join ', ', @args; die "$gluename->$eventname($args) event failed:\n$errs\n"; } $finder->open( $finder->obj( item => 'HD' ), # nothing named HD in Finder ERRORS => \&error_handler ); Result: # Finder->open(DOBJ, Mac::AEObjDesc=HASH(0xc4c0814)) event failed: No such object (OS error -1728) Editing a Glue -------------- There is an included droplet, `glueedit', for editing glues. Drop a created glue on the droplet, and it will make a text file on the Desktop. Edit it, and then drop the text file back on the droplet. Be careful; this obviously can be dangerous. If you break something, you can use `gluemac' to recreate the original glue, of course. Why would you edit a glue? Well, sometimes AETE resources are wrong. :) EXPORT ====== Mac::Glue has two export sets. `glue' exports the constants and functions beginning with "glue" listed in `"Creating Object Specifier Records"' in this node, as well as the functions `obj_form', enum, location, range, and `whose'. all exports everything from Mac::AppleEvents and Mac::AppleEvents::Simple, including all functions and constants. Nothing is exported by default. use Mac::Glue ':glue'; # good for most things use Mac::Glue ':all'; # for more advanced things TIPS ==== Hide background apps -------------------- use Mac::Glue; use Mac::Apps::Launch; $a = new Mac::Glue 'Acrobat Exchange'; $a->launch; Hide($a->{ID}); # now do your thing ... Scripting Addition Maintenance ------------------------------ If you have a lot of scripting additions, it can slow down Mac::Glue (on startup) and take up more RAM. Same thing goes for Mac OS in general; each installed additions takes up more RAM and has to be loaded into the system, taking up extra time. So only keep installed the ones you want installed. If you have a huge scripting addition and you only want to use a small part of its functionality, you could also edit the glue and strip out portions you don't want. This is not recommended for those who don't know precisely what they are doing, and the gains may be unnoticable anyway. GOTCHAS ======= * MAKE SURE `site_perl' COMES FIRST IN YOUR LIBRARY PREFERENCES. Thank you. :-) * Do NOT send an event to the MacPerl application itself and expect a reply. Instead, try `$macperlglue->REPLY(0)'. Similarly, do not drop MacPerl onto `gluemac'. Instead, you can make a copy of the MacPerl application, and drop that on `gluemac'. * You should have the latest cpan-mac distribution is installed. * You should delete old dialect glue files manually if running Mac OS 9. TODO / BUGS =========== * Specifying other attributes (transactions, etc.) * Add more coercions etc. to Mac::AppleEvents::Simple (feedback wanted on this, let me know what I missed) * Add comparison operators from glues * "tell" objects to do events * New AETE flags in Mac OS 8.5, Mac OS 9? Anything else new? Anything missing in backward compatibility to 7.5? * System of versioning (for glues and target apps) for distribution of modified glues * MacPerl (I think) needs a new idle function for waiting for replies * MacPerl hangs if it waits for a reply after sending an event to itself * Handlers? * Add dynamic fetching of glues? HISTORY ======= v1.00, Tuesday, September 12, 2000 Added error handling via ERRORS parameter / method. General cleanup, additional examples. v0.58, Tuesday, November 16, 1999 Change all of the classes to have `Mac::' at the beginning of them (except for ones that originate elsewhere, like `AEDesc', et al). Added `Mac::AEParamType' and `param_type'. If a parameter expects an AE object specifier record, and is not passed one, then it guesses the type and sets it to either `typeChar' or `typeInteger'. Made the conversion of keys into English names recursive with lists, in addition to records (i.e., lists can contain multiple records). v0.57, Tuesday, November 2, 1999 Added conversion of keys in returned records back into the "English" names. Records containing class parameter are coerced into descriptors of that class (i.e., `{name => 'foo', class => 'disk'}'). Added support for events over TCP/IP (Mac OS 9 required). Note: if Keychain Access is used in Mac OS 9, the login method may no longer be required for accessing of remote machines. Fixed bug in can method; also changed how can calls AUTOLOAD. Added code for experimental callback stuff, undocumented, subject to change, and probably does not even work. Changed `_get_name' to `_get_id', created new `_get_name'. Updated dialect creation code for Mac OS 9 (aeut is now stored in the `AppleScript' extension instead of a dialect file, but for Mac::Glue is still stored in the `dialects' folder. Instead of being called English, it will likely be called `AppleScript'. You should delete (or archive) old dialect glues manually. v0.56, Friday, September 10, 1999 If plural class is used (i.e., files for file), and the following value is not an `AE*' object, then it will become "every class". (Jeff Lowrey) Added more documentation about using `AEObjDesc' objects. (Jeff Lowrey) v0.55, Thursday, September 2, 1999 Added extra arguments to new to accept alternate targets. PPC ports, PSNs, and paths are explicitly accepted now. (Paths are first launched, then the PSN is found ... aliases won't work properly as paths.) Added login class method to tell MacPerl to try logging in with specified username and password. Requires `Login As' OSAX from the `GTQ Scripting Library'. v0.51, Wednesday, September 1, 1999 Changed ordering of search in `_find_event'. Fixed doc problems in Mac::AETE::Format::Glue: inheritance classes are named, and optional parameters are properly denoted. v0.50, 12 July 1999 Added g* constants in addition to glue* constants. Use whichever you like, but I will use g* for everything. If you don't want the g* constants, because they conflict with something, use the `:long' and `:longall' import tags instead of `:glue' and :all. Gone to beta! Woo! v0.31, 22 June 1999 Fixed bug that only found class names instead of class and property names in creation of object specifier records. Fixed bug which changed directories on initialization, and didn't change it back. Allow case-insensitive parameter names. v0.30, 16 June 1999 Changed function names: `glueInsertion' is now location, `glueRange' is now range. Added `whose' function. Added can method which correctly finds available events. Made special parameters, formerly with leading underscore and lowercase, to all uppercase with no underscore (i.e., `_retobj' is now RETOBJ). Added `of' and in as synonyms for property in `obj' method calls. Put `AEObjDesc' back in! Will use in the future, maybe, to use objects as targets for events. Return all descriptors from `obj' and `prop', and all objects returned from events, as `AEObjDesc' objects. Added `glueTrue' and `glueFalse' constants. Tried again to suppress warnings during initial scripting additions and dialect creation. Tons of internal cleaning up. v0.26, 07 June 1999 Made choice of serializer for glue more intelligent: FreezeThaw automatically picked for CFM68K, Storable for PPC. Updated Mac::AppleEvents and Mac::Memory, fixed more bugs and added constants. Fixed bug in AutoSplit. Added `glueInsertion', `glueRange', and `glueNull'. Completely removed `AEObjDesc' package, which existed to support destruction of descriptors. Use global hash now to keep track of descriptors to destroy (`Mac::AppleEvents::Simple' in this node). So all descriptors returned from `obj' and `prop' and others are `AEDesc' objects. Changed ordering of items in creating object specifiers in `_do_obj' to match AppleScript, so comparing to Capture AE output would be easier. Put `%AE_PUT' back in Mac::Glue and left `%AE_GET' in Mac::AppleEvents::Simple. Switched `DOBJ, {PARAM1 => DATA1}' to `DOBJ, PARAM1 => DATA1' in event calls. Always default to wait for reply and no timeout if unspecified by user. Return useful errors in $^E. Accept and return nested arrays/lists and hashes/records. Call events and pass classes / properties case-insensitively. Other miscellaneous changes. Some cleaning up. v0.25, 30 May 1999 Add serializer option. Updates to Mac::Memory and Mac::AppleEvents and Mac::AppleEvents::Simple. Added constants for absolute and relative positions. Added enum. Put o and p back as `obj' and `prop'. Other miscellaneous changes. Lots of cleaning up. v0.20, 22 May 1999 Complete rewrite. Too many changes to bother mentioning, because I am lazy. v0.09, 13 October 1998 Added ability to use properties. These are called with the p method: $obj->get($obj->p('label_index', item=>'HD')); which is equivalent to: $obj->get($obj->o(property=>'label_index', item=>'HD')); v0.08, 10 October 1998 Unreleased. Significant cleanup of module, in large part unfinished changes from last version. No longer doing error checking for whether lists are allowed or objects are allowed, because these are sometimes wrong or undetectable. Also, will not raise exception on a missing required parameter, but will warn if -w is on. `obj_form' is exported from the glue modules, and all of the functions and constant from `Mac::AppleEvents' can be imported from a glue module with the :all tag: use Mac::Glue::SomeApp qw(:all); v0.07, 30 September 1998 More documentation and bugfixes. Having serious problems with `AEObjDesc::DESTROY'. v0.06, 29 September 1998 Whole bunches of changes. Note that glues made under 0.05 no longer work. AUTHOR ====== Chris Nandor , http://pudge.net/ Copyright (c) 1998-2000 Chris Nandor. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the Artistic License, distributed with Perl. THANKS ====== Matthias Neeracher , David Schooley , Graham Barr , John W Baxter , Marion Delgado , Eric Dobbs , Josh Gemmell , Nathaniel Irons , Dave Johnson , Bart Lateur , Jefferson R. Lowrey , Mat Marcus , Larry Moore , Ricardo Muggli , Vincent Nonnenmacher , Henry Penninkilampi , Peter Prymmer , Ramesh R. , Axel Rose , Stephan Somogyi , Kevin Walker , Matthew Wickline . (If I left your name out, please remind me.) SEE ALSO ======== Mac::AppleEvents, Mac::AppleEvents::Simple, macperlcat, Inside Macintosh: Interapplication Communication. http://sourceforge.net/projects/mac-glue/ VERSION ======= v1.00, Tuesday, September 12, 2000