NeXT App-Wrapper Description
This is my description of how the NeXT App-Wrapper system worked
and what made it good.
From jeske@... Thu Oct 1 11:39:29 1998
Message-ID: <19981001113929.J13461@home.chat.net>
Date: Thu, 1 Oct 1998 11:39:29 -0700
From: David Jeske
To: laventor@....
Subject: Re: making KDE's packages install like NeXT programs/libraries
References: <19980929210825.48599@hope>
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
X-Mailer: Mutt 0.92.1
In-Reply-To: <19980929210825.48599@hope>; from laventor@pcsystems.net on Tue, Sep 29, 1998 at 09:08:25PM +0000
Status: RO
Content-Length: 6868
Hello,
On Tue, Sep 29, 1998 at 09:08:25PM +0000, laventor@pcsystems.net wrote:
> After reading your suggestion on KDE's wishlist mentioning NeXT's
> app wrappers, bundles, and frameworks I was fascinated by the
> idea... I've tried to find information specifying exactly how this
> works, but I've had no luck. I assume this is because NeXT isn't
> being sold any more (or so I've heard).
It's more likely because it just worked well enough that most people
didn't need to know all the details.
> I would appreciate any information you could give me on this,
> especially regarding the installation of shared libraries (how does
> NeXT handle it if you move the directory a program is installed in,
> for example?) and headers, but, again, I'd prefer to know as much as
> I can about the subject so anything would help. I'd especially
> appreciate it if you could point me to some URLs with detailed
> information on the app wrappers, bundles, and frameworks.
** App-wrappers
When next started (2.0 and earlier) there were no app-wrappers. They
jammed everything into one executable file. However, the executables
were getting bloated, and they wanted to easily support
internationalization, and complex files included within the
app. Instead of doing some resource format where they create a
filesystem in the app, they decided to just use the filesystem for
what it's good for.
If I remember correctly it was version 2.1 when they created the
app-wrapper concept. A simple next app-wrapper looks like this inside:
Foo.app/Foo <- executable
/English.lproj/Foo.nib <- English version of the UI
/English.lproj/two.tiff <- language dependent icon
/French.lproj/Foo.nib <- French version of the UI
/French.lproj/two.tiff <- language dependent icon
one.tiff <- language independent icon
The executable itself contains information about:
The app's icon (i.e. to be shown in the fileviewer, etc)
The filetypes this app can open
Icons for those filetypes
Executable code for the platforms supported by this build (i.e.
they have a concept called 'FAT' binaries, where an executable
could contain binary code for multiple platforms)
The files inside the app-wrapper (for the most part) should not be
modified during the running of the program. All configuration data was
stored in an API called "next defaults". This assured that you could
just "copy" an app from one machine to another and it would work. No
fancy installation process required.
* NIB files
A ".nib" file is another famous next concept, a formization of the 'UI
resource' concept. NIB stands for 'next interface builder'. It's a
file of archived objects and archived object connections which make up
the UI. Next's interface builder is still years ahead of most UI
builders, and part of that lies in the fact that it actually archives
objects into the NIB files, instead of generating code which is
compiled into the app.
** Location Independence
An app on nextstep can be launched from anywhere on the system. It
will find all it's datafiles (which are in the app-wrapper) relative
to the path of the executable.
Next had a concept of "standard app paths". If your app was in one of
the standard app paths, (by default /NextApps, /LocalApps, ~/Apps)
then it would be automatically found and it's filetypes would be
registered. It would also have it's filetypes registered if the user
had it in his Doc (i.e. an app launcher). If neither of these were
true, the app could still be launched, but it's filetypes would not be
registered. For example, if I put an imageviewer in ~/temp_stuff, and
I tried to open a GIF file, the system wouldn't know about that
imageviewer being able to open my GIF file.
** Bundles not shlibs
Apps which needed to load code would load it in the form of
"Bundles". A bundle was just like an app-wrapper, in that it could
contain NIB interfaces in any number of languages, and other
datatfiles. However, it could not be 'launched' but instead would be
loaded as a plug-in for another app. For example, screensaver modules
were stored in bundle-wrappers. You could just generically name your
plug-in ".bundle", or you could name it more descriptively, like
".backmod" for BackSpace (the name of the screensaver app) Module.
There was a standard convention for 'installing' these modules so they
could be automatically found, just like the 'standard app paths'
above. There was a 'standard library paths' which by default was
/NextLibrary, /LocalLibrary, ~/Library. Within one of the *Library
directories are other directories which delimit between files for
different purposes. For example "~/Library/Bookshelves" was where the
Librarian.app would store it's bookshelves (lists of documentation
orginazed together to be searched), and ~/Library/BackSpace was where
you would install those screensaver modules for them to be
automatically seen. Likewise, if there was GIMP for nextstep, there
would be something like ~/Library/GIMP where you would put your
gimp-plugins to be automatically registered. If the admin wanted to
install a set of gimp plug-ins to be accessable to all, he would put
them in /LocalLibrary/GIMP.
Shlibs on nextstep are really only the system libs which are shipped
by Next. There were people who would build legacy UNIX shlibs, but
nobody did this for the nice GUI stuff, they would use bundles instead.
However, in the most recent versions (4.1/4.2) they have come up with
a concept for libs and headers as well. They call it
'frameworks'. They place all the libs and headers required for a
framework inside a '.framework' wrapper. That framework can be in any
of the standard directories for frameworks. (I don't remember the
specifics, but it's something like *Library/Developer/Frameworks,
where *Library means any of the standard library paths).
In a practical sense it works like this: If you have some code that
needs the "FooBar" framework, as long as it is in one of the Framework
paths, the builder will automagically find it. If it's not already
there, the user merely needs to download and copy "FooBar.framework"
into ~/Library/Developer/Frameworks. The project builder automagically
will tell gcc what it's "include paths" should be, and the linker what
it's "lib paths" should be based on where it finds the frameworks it
needs.
** To the end user
When an end user was browsing around the filesystem, he never saw that
apps were actually directory. When you clicked on a ".app" it was just
an atomic item which you could double click to launch, or drag to your
"app launcher".
Expert users could do "File->Open As Folder" to get inside the
app-wrapper itself.
Take a look at this URL for some screen shots:
http://www3.pair.com/mccarthy/nextstep/
--
David Jeske (N9LCA) + http://www.chat.net/~jeske/ + jeske@...
From jeske@... Mon Oct 5 21:21:28 1998
Message-ID: <19981005212127.F22462@home.chat.net>
Date: Mon, 5 Oct 1998 21:21:28 -0700
From: David Jeske
To: laventor@pcsystems.net
Subject: Re: a thank you, and a few more questions
References: <19980929210825.48599@hope> <19981001113929.J13461@home.chat.net> <19981006033748.12726@hope>
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
X-Mailer: Mutt 0.92.1
In-Reply-To: <19981006033748.12726@hope>; from laventor@pcsystems.net on Tue, Oct 06, 1998 at 03:37:48AM +0000
Status: RO
Content-Length: 8156
On Tue, Oct 06, 1998 at 03:37:48AM +0000, laventor@pcsystems.net wrote:
> On Thu, Oct 01, 1998 at 11:39:29AM -0700, David Jeske wrote:
> > The files inside the app-wrapper (for the most part) should not be
> > modified during the running of the program. All configuration data was
> > stored in an API called "next defaults". This assured that you could
> > just "copy" an app from one machine to another and it would work. No
> > fancy installation process required.
>
> How and where was this configuration data stored? I'd also appreciate it if
> you could explain the general idea of NeXT defaults or point me to something
> that'd contain a explanation...
The application didn't know 'where' it was stored, it was stored
through a standard API. That was the power of the thing. For example,
the application didn't know how many 'levels' of configuration data
there were (i.e. next had 'system wide' and 'per user' but it also
could be 'system wide', 'group wide' and 'per user' and the
applications would work, in fact, they could change it _today_ and old
apps would still work).
Next's implementation of nextdefaults stored per-user config
information inside a ~/.NextDefaults directory in their home
directory. However, applications _never_ touched these files directly.
> > * NIB files
> >
> > A ".nib" file is another famous next concept, a formization of the 'UI
> > resource' concept. NIB stands for 'next interface builder'. It's a
> > file of archived objects and archived object connections which make up
> > the UI. Next's interface builder is still years ahead of most UI
> > builders, and part of that lies in the fact that it actually archives
> > objects into the NIB files, instead of generating code which is
> > compiled into the app.
>
> I don't understand this very well at all. I know how generating the
> code and linking with a library could create a interface, but I
> don't know what you mean by "archiving objects."
To create a NIB files, the Next IB (Interface Builder) program would
actually build a LIVE interface, with LIVE objects. Then, it just
asked those objects to 'archive themselves to a file'. All the objects
in the interface, and their connections, would store themselves in the
file. When the application 'loaded' the interface, it would ask the
objects to 'unarchive' out of the file.
This way, you could have three files, all with the same UI, but
customized for different languages. The application would figure out
what language it was supposed to run in, and then unarchive the
appropriate file.
If you did this with compiling, you would have to generate code and
compile into the program different versions of the UI init code for
each language.
> > Next had a concept of "standard app paths". If your app was in one of
> > the standard app paths, (by default /NextApps, /LocalApps, ~/Apps)
> > then it would be automatically found and it's filetypes would be
> > registered. It would also have it's filetypes registered if the user
> > had it in his Doc (i.e. an app launcher). If neither of these were
> > true, the app could still be launched, but it's filetypes would not be
> > registered. For example, if I put an imageviewer in ~/temp_stuff, and
> > I tried to open a GIF file, the system wouldn't know about that
> > imageviewer being able to open my GIF file.
>
> If you had more than one program installed that could open a particular file
> type, how did NeXT go about deciding which one to launch?
The user could specify one as preferred. If you brought up the 'Tools
Inspector' within the Workspace Manager/File Viewer (i.e. the main
desktop app), it would show you all the apps which were installed and
capable of opening the currently selected file. If you wanted to just
'one time' launch in one of those apps, you would just double click on
that app's icon in the Inspector. If you wanted to set that app as the
default handler for a particular type, you would click on it in the
Inspector, and then click the "set as default" button in the
inspector.
Or you could Alt-drag the datafile onto the icon for the app you
wanted it to launch in.
> I read through the URL you mentioned (Introduction to NeXTStep) and
> one thing wasn't very clear to me. Could you explain to me how
> Services worked? I don't understand how a program knows what
> function to perform when you select a service (I assume it has
> something to do with context), and I can't figure out how programs
> could be integrated to that degree (e.g. how does any program that
> uses e-mail know to use the new program I installed; this wouldn't
> be hard if there was some standard variable that (for instance)
> contained the path to the program, but surely not every popular
> program type (e.g. e-mail programs) had such a standard
> variable...).
There were no paths involved with services. I do think services could
be much better than it currently is on Next. However, what they have
is pretty powerful.
Basically, apps export 'services' they can perform to the world. Along
with a 'service name', they say what 'pasteboard type' that service
needs to be valid.
So an email program might export "send as email" as a service, and it
might say that it'll accept 'any' pasteboard type. So when you select
an item and it ends up on the pasteboard, the user can goto
"Services->Mail.app->Send As Email" and it'll grab that selection and
throw it to the email program.
Other popular ones were "OmniWeb->Open URL" and "Webster->Define in
Webster".
--------
It would have been much nicer if two more concepts were integrated,
that is "suites" of services. It would have been nice if there an
'email' suite of services which any email program could adhere to,
then the user could choose which email program he wanted to use to
service the 'email service requests'. This would have given the
functionality you speak of above where everyone would know how to use
the program you installed and chose to be your default email
program. It's not very hard, but services was invented quite early in
the nextstep world.
It also would have been nicer if services receivers had a bit more to
say about whether or not a piece of data on the pasteboard was going
to be valid. For example, it would be nice if an email program could
recognize something as "user@host" to know it's a valid email
address. Or if a web browser could look and see "http://www.foo.com"
and know that it's a valid URL. Apple did something like this with
"Apple DataDetectors" and I hope they will reinvent that in MacOS X
under nextstep.
> Thank you for your time, and describing things in such detail. My
> reason for wanting to know these things is I'd like to at least try
> altering the source code for standard UNIX programs and making them
> install like NeXT did... I realise it would be hard, but it would
> make administering a system set up like that somewhat easier
> (deleting a program is as easy as deleting a directory versus having
> to make it into a package, then use a package manager to remove it;
> if the config files were grouped by the programs they belong to
> (rather than being sprayed all over /etc) it'd make it easier to
> find the one you needed to edit, etc). I wish someone had made a
> distribution like this...
I agree... I've been pushing people on the KDE and Gnome lists to
follow these kinds of standards for a while... I think I've got the
beginning of a critical mass on the Gnome list.
The most important things to implement to make this work right are:
1) relative paths for datafiles... create some sharedlibrary function
to let an app get it's install location, then it should use relative
paths to get to it's datafiles
2) no data inside the wrapper is mutable
3) store configuration data in an API which has NO absolute file locations
4) have the application passively export it's capabilities (i.e. it's
icon, filetypes it can handle, icons for those filetypes, services, etc)
Don't follow the unix model where to install an app you have to hack
configuration files in several different apps.
--
David Jeske (N9LCA) + http://www.chat.net/~jeske/ + jeske@...