!makefile lcc windows/Makefile.lcc
!makefile gtk unix/Makefile.gtk
!makefile mpw mac/Makefile.mpw
+!makefile osx macosx/Makefile
# Source directories.
!srcdir charset/
!srcdir windows/
!srcdir unix/
!srcdir mac/
+!srcdir macosx/
# Help text added to the top of each Makefile, with /D converted
# into -D as appropriate for the particular Makefile.
install-strip:
$(MAKE) install INSTALL_PROGRAM="$(INSTALL_PROGRAM) -s"
!end
+!begin osx
+CFLAGS += -DMACOSX
+!end
# ------------------------------------------------------------
# Definitions of object groups. A group name, followed by an =,
+ winutils wincfg
# Same thing on Unix.
-UXTERM = TERMINAL gtkwin gtkdlg gtkcols gtkpanel gtkcfg uxcfg uxucs uxprint
- + xkeysym timing
+UXTERM = TERMINAL uxcfg uxucs uxprint timing
+GTKTERM = UXTERM gtkwin gtkcfg gtkdlg gtkcols gtkpanel xkeysym
+OSXTERM = UXTERM osxwin osxdlg osxctrls
# Non-SSH back ends (putty, puttytel, plink).
NONSSH = telnet raw rlogin ldisc pinger
MISC = timing misc version settings tree234 proxy
WINMISC = MISC winstore winnet cmdline windefs winmisc pproxy wintime
UXMISC = MISC uxstore uxsel uxnet cmdline uxmisc uxproxy time
+OSXMISC = MISC uxstore uxsel osxsel uxnet uxmisc uxproxy time
MACMISC = MISC macstore macnet mtcpnet otnet macmisc macabout pproxy
# Character set library, for use in pterm.
+ sshpubk sshaes sshsh512 import winutils puttygen.res tree234
+ notiming LIBS wintime
-pterm : [X] UXTERM uxmisc misc ldisc settings uxpty uxsel BE_NONE uxstore
+pterm : [X] GTKTERM uxmisc misc ldisc settings uxpty uxsel BE_NONE uxstore
+ uxsignal CHARSET cmdline uxpterm version time
-putty : [X] UXTERM uxmisc misc ldisc settings uxsel BE_ALL uxstore
+putty : [X] GTKTERM uxmisc misc ldisc settings uxsel BE_ALL uxstore
+ uxsignal CHARSET uxputty NONSSH UXSSH UXMISC ux_x11
-puttytel : [X] UXTERM uxmisc misc ldisc settings uxsel BE_NOSSH
+puttytel : [X] GTKTERM uxmisc misc ldisc settings uxsel BE_NOSSH
+ uxstore uxsignal CHARSET uxputty NONSSH UXMISC
plink : [U] uxplink uxcons NONSSH UXSSH BE_ALL logging UXMISC uxsignal ux_x11
PuTTYgen : [M] macpgen sshrsag sshdssg sshprime sshdes sshbn sshmd5 version
+ sshrand macnoise sshsha macstore misc sshrsa sshdss macmisc sshpubk
+ sshaes sshsh512 import macpgen.rsrc macpgkey macabout
+
+PuTTY : [MX] osxmain OSXTERM OSXMISC CHARSET BE_ALL NONSSH UXSSH
+ + ux_x11 uxpty uxsignal testback
--- /dev/null
+# Makefile for putty under Mac OS X.
+#
+# This file was created by `mkfiles.pl' from the `Recipe' file.
+# DO NOT EDIT THIS FILE DIRECTLY; edit Recipe or mkfiles.pl instead.
+#
+# Extra options you can set:
+#
+# - VER=-DSNAPSHOT=1999-01-25
+# Generates executables whose About box report them as being a
+# development snapshot.
+#
+# - VER=-DRELEASE=0.43
+# Generates executables whose About box report them as being a
+# release version.
+#
+# - COMPAT=-DAUTO_WINSOCK
+# Causes PuTTY to assume that <windows.h> includes its own WinSock
+# header file, so that it won't try to include <winsock.h>.
+#
+# - COMPAT=-DWINSOCK_TWO
+# Causes the PuTTY utilities to include <winsock2.h> instead of
+# <winsock.h>, except Plink which _needs_ WinSock 2 so it already
+# does this.
+#
+# - COMPAT=-DNO_SECURITY
+# Disables Pageant's use of <aclapi.h>, which is not available
+# with some development environments (such as older versions of
+# the Cygwin/mingw GNU toolchain). This means that Pageant
+# won't care about the local user ID of processes accessing it; a
+# version of Pageant built with this option will therefore refuse
+# to run under NT-series OSes on security grounds (although it
+# will run fine on Win95-series OSes where there is no access
+# control anyway).
+#
+# - COMPAT=-DNO_MULTIMON
+# Disables PuTTY's use of <multimon.h>, which is not available
+# with some development environments. This means that PuTTY's
+# full-screen mode (configurable to work on Alt-Enter) will
+# not behave usefully in a multi-monitor environment.
+#
+# Note that this definition is always enabled in the Cygwin
+# build, since at the time of writing this <multimon.h> is
+# known not to be available in Cygwin.
+#
+# - COMPAT=-DNO_IPV6
+# Disables PuTTY's ability to make IPv6 connections, enabling
+# it to compile under development environments which do not
+# support IPv6 in their header files.
+#
+# - COMPAT=-DMSVC4
+# - RCFL=-DMSVC4
+# Makes a couple of minor changes so that PuTTY compiles using
+# MSVC 4. You will also need /DNO_SECURITY and /DNO_MULTIMON.
+#
+# - RCFL=-DASCIICTLS
+# Uses ASCII rather than Unicode to specify the tab control in
+# the resource file. Probably most useful when compiling with
+# Cygnus/mingw32, whose resource compiler may have less of a
+# problem with it.
+#
+# - XFLAGS=-DTELNET_DEFAULT
+# Causes PuTTY to default to the Telnet protocol (in the absence
+# of Default Settings and so on to the contrary). Normally PuTTY
+# will default to SSH.
+#
+# - XFLAGS=-DDEBUG
+# Causes PuTTY to enable internal debugging.
+#
+# - XFLAGS=-DMALLOC_LOG
+# Causes PuTTY to emit a file called putty_mem.log, logging every
+# memory allocation and free, so you can track memory leaks.
+#
+# - XFLAGS=-DMINEFIELD
+# Causes PuTTY to use a custom memory allocator, similar in
+# concept to Electric Fence, in place of regular malloc(). Wastes
+# huge amounts of RAM, but should cause heap-corruption bugs to
+# show up as GPFs at the point of failure rather than appearing
+# later on as second-level damage.
+#
+CC = $(TOOLPATH)gcc
+
+CFLAGS = -O2 -Wall -Werror -g -I.././ -I../charset/ -I../windows/ -I../unix/ \
+ -I../mac/ -I../macosx/
+MLDFLAGS = -framework Cocoa
+ULDFLAGS =
+all: PuTTY plink pscp psftp puttygen
+CFLAGS += -DMACOSX
+
+PuTTY.app:
+ mkdir -p $@
+PuTTY.app/Contents: PuTTY.app
+ mkdir -p $@
+PuTTY.app/Contents/MacOS: PuTTY.app/Contents
+ mkdir -p $@
+PuTTY: PuTTY.app/Contents/MacOS/PuTTY $(PuTTY_extra)
+
+PuTTY.app/Contents/MacOS/PuTTY: PuTTY.app/Contents/MacOS be_all.o config.o \
+ cproxy.o dialog.o fromucs.o ldisc.o ldiscucs.o localenc.o \
+ logging.o macenc.o mimeenc.o minibidi.o misc.o osxctrls.o \
+ osxdlg.o osxmain.o osxsel.o osxwin.o pinger.o portfwd.o \
+ proxy.o raw.o rlogin.o sbcs.o sbcsdat.o settings.o slookup.o \
+ ssh.o sshaes.o sshblowf.o sshbn.o sshcrc.o sshcrcda.o \
+ sshdes.o sshdh.o sshdss.o sshmd5.o sshpubk.o sshrand.o \
+ sshrsa.o sshsh512.o sshsha.o sshzlib.o telnet.o terminal.o \
+ testback.o time.o timing.o toucs.o tree234.o utf8.o ux_x11.o \
+ uxagentc.o uxcfg.o uxmisc.o uxnet.o uxnoise.o uxprint.o \
+ uxproxy.o uxpty.o uxsel.o uxsignal.o uxstore.o uxucs.o \
+ version.o wcwidth.o wildcard.o x11fwd.o xenc.o
+ $(CC) $(MLDFLAGS) -o $@ be_all.o config.o cproxy.o dialog.o \
+ fromucs.o ldisc.o ldiscucs.o localenc.o logging.o macenc.o \
+ mimeenc.o minibidi.o misc.o osxctrls.o osxdlg.o osxmain.o \
+ osxsel.o osxwin.o pinger.o portfwd.o proxy.o raw.o rlogin.o \
+ sbcs.o sbcsdat.o settings.o slookup.o ssh.o sshaes.o \
+ sshblowf.o sshbn.o sshcrc.o sshcrcda.o sshdes.o sshdh.o \
+ sshdss.o sshmd5.o sshpubk.o sshrand.o sshrsa.o sshsh512.o \
+ sshsha.o sshzlib.o telnet.o terminal.o testback.o time.o \
+ timing.o toucs.o tree234.o utf8.o ux_x11.o uxagentc.o \
+ uxcfg.o uxmisc.o uxnet.o uxnoise.o uxprint.o uxproxy.o \
+ uxpty.o uxsel.o uxsignal.o uxstore.o uxucs.o version.o \
+ wcwidth.o wildcard.o x11fwd.o xenc.o
+
+plink: be_all.o cmdline.o cproxy.o ldisc.o logging.o misc.o pinger.o \
+ portfwd.o proxy.o raw.o rlogin.o settings.o ssh.o sshaes.o \
+ sshblowf.o sshbn.o sshcrc.o sshcrcda.o sshdes.o sshdh.o \
+ sshdss.o sshmd5.o sshpubk.o sshrand.o sshrsa.o sshsh512.o \
+ sshsha.o sshzlib.o telnet.o time.o timing.o tree234.o \
+ ux_x11.o uxagentc.o uxcons.o uxmisc.o uxnet.o uxnoise.o \
+ uxplink.o uxproxy.o uxsel.o uxsignal.o uxstore.o version.o \
+ wildcard.o x11fwd.o
+ $(CC) $(ULDFLAGS) -o $@ be_all.o cmdline.o cproxy.o ldisc.o \
+ logging.o misc.o pinger.o portfwd.o proxy.o raw.o rlogin.o \
+ settings.o ssh.o sshaes.o sshblowf.o sshbn.o sshcrc.o \
+ sshcrcda.o sshdes.o sshdh.o sshdss.o sshmd5.o sshpubk.o \
+ sshrand.o sshrsa.o sshsh512.o sshsha.o sshzlib.o telnet.o \
+ time.o timing.o tree234.o ux_x11.o uxagentc.o uxcons.o \
+ uxmisc.o uxnet.o uxnoise.o uxplink.o uxproxy.o uxsel.o \
+ uxsignal.o uxstore.o version.o wildcard.o x11fwd.o
+
+pscp: be_none.o cmdline.o cproxy.o int64.o logging.o misc.o pinger.o \
+ portfwd.o proxy.o pscp.o settings.o sftp.o ssh.o sshaes.o \
+ sshblowf.o sshbn.o sshcrc.o sshcrcda.o sshdes.o sshdh.o \
+ sshdss.o sshmd5.o sshpubk.o sshrand.o sshrsa.o sshsh512.o \
+ sshsha.o sshzlib.o time.o timing.o tree234.o uxagentc.o \
+ uxcons.o uxmisc.o uxnet.o uxnoise.o uxproxy.o uxsel.o \
+ uxsftp.o uxstore.o version.o wildcard.o x11fwd.o
+ $(CC) $(ULDFLAGS) -o $@ be_none.o cmdline.o cproxy.o int64.o \
+ logging.o misc.o pinger.o portfwd.o proxy.o pscp.o \
+ settings.o sftp.o ssh.o sshaes.o sshblowf.o sshbn.o sshcrc.o \
+ sshcrcda.o sshdes.o sshdh.o sshdss.o sshmd5.o sshpubk.o \
+ sshrand.o sshrsa.o sshsh512.o sshsha.o sshzlib.o time.o \
+ timing.o tree234.o uxagentc.o uxcons.o uxmisc.o uxnet.o \
+ uxnoise.o uxproxy.o uxsel.o uxsftp.o uxstore.o version.o \
+ wildcard.o x11fwd.o
+
+psftp: be_none.o cmdline.o cproxy.o int64.o logging.o misc.o pinger.o \
+ portfwd.o proxy.o psftp.o settings.o sftp.o ssh.o sshaes.o \
+ sshblowf.o sshbn.o sshcrc.o sshcrcda.o sshdes.o sshdh.o \
+ sshdss.o sshmd5.o sshpubk.o sshrand.o sshrsa.o sshsh512.o \
+ sshsha.o sshzlib.o time.o timing.o tree234.o uxagentc.o \
+ uxcons.o uxmisc.o uxnet.o uxnoise.o uxproxy.o uxsel.o \
+ uxsftp.o uxstore.o version.o wildcard.o x11fwd.o
+ $(CC) $(ULDFLAGS) -o $@ be_none.o cmdline.o cproxy.o int64.o \
+ logging.o misc.o pinger.o portfwd.o proxy.o psftp.o \
+ settings.o sftp.o ssh.o sshaes.o sshblowf.o sshbn.o sshcrc.o \
+ sshcrcda.o sshdes.o sshdh.o sshdss.o sshmd5.o sshpubk.o \
+ sshrand.o sshrsa.o sshsh512.o sshsha.o sshzlib.o time.o \
+ timing.o tree234.o uxagentc.o uxcons.o uxmisc.o uxnet.o \
+ uxnoise.o uxproxy.o uxsel.o uxsftp.o uxstore.o version.o \
+ wildcard.o x11fwd.o
+
+puttygen: cmdgen.o import.o misc.o notiming.o sshaes.o sshbn.o sshdes.o \
+ sshdss.o sshdssg.o sshmd5.o sshprime.o sshpubk.o sshrand.o \
+ sshrsa.o sshrsag.o sshsh512.o sshsha.o time.o tree234.o \
+ uxcons.o uxgen.o uxmisc.o uxnoise.o uxstore.o version.o
+ $(CC) $(ULDFLAGS) -o $@ cmdgen.o import.o misc.o notiming.o sshaes.o \
+ sshbn.o sshdes.o sshdss.o sshdssg.o sshmd5.o sshprime.o \
+ sshpubk.o sshrand.o sshrsa.o sshrsag.o sshsh512.o sshsha.o \
+ time.o tree234.o uxcons.o uxgen.o uxmisc.o uxnoise.o \
+ uxstore.o version.o
+
+be_all.o: ../be_all.c ../putty.h ../puttyps.h ../network.h ../misc.h \
+ ../windows/winstuff.h ../mac/macstuff.h ../macosx/osx.h \
+ ../unix/unix.h ../puttymem.h ../tree234.h \
+ ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+be_none.o: ../be_none.c ../putty.h ../puttyps.h ../network.h ../misc.h \
+ ../windows/winstuff.h ../mac/macstuff.h ../macosx/osx.h \
+ ../unix/unix.h ../puttymem.h ../tree234.h \
+ ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+be_nossh.o: ../be_nossh.c ../putty.h ../puttyps.h ../network.h ../misc.h \
+ ../windows/winstuff.h ../mac/macstuff.h ../macosx/osx.h \
+ ../unix/unix.h ../puttymem.h ../tree234.h \
+ ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+cmdgen.o: ../cmdgen.c ../putty.h ../ssh.h ../puttyps.h ../network.h \
+ ../misc.h ../puttymem.h ../int64.h ../windows/winstuff.h \
+ ../mac/macstuff.h ../macosx/osx.h ../unix/unix.h \
+ ../tree234.h ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+cmdline.o: ../cmdline.c ../putty.h ../puttyps.h ../network.h ../misc.h \
+ ../windows/winstuff.h ../mac/macstuff.h ../macosx/osx.h \
+ ../unix/unix.h ../puttymem.h ../tree234.h \
+ ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+config.o: ../config.c ../putty.h ../dialog.h ../storage.h ../puttyps.h \
+ ../network.h ../misc.h ../windows/winstuff.h \
+ ../mac/macstuff.h ../macosx/osx.h ../unix/unix.h \
+ ../puttymem.h ../tree234.h ../windows/winhelp.h \
+ ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+cproxy.o: ../cproxy.c ../putty.h ../ssh.h ../network.h ../proxy.h \
+ ../puttyps.h ../misc.h ../puttymem.h ../int64.h \
+ ../windows/winstuff.h ../mac/macstuff.h ../macosx/osx.h \
+ ../unix/unix.h ../tree234.h ../windows/winhelp.h \
+ ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+dialog.o: ../dialog.c ../putty.h ../dialog.h ../puttyps.h ../network.h \
+ ../misc.h ../windows/winstuff.h ../mac/macstuff.h \
+ ../macosx/osx.h ../unix/unix.h ../puttymem.h ../tree234.h \
+ ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+fromucs.o: ../charset/fromucs.c ../charset/charset.h ../charset/internal.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+gtkcfg.o: ../unix/gtkcfg.c ../putty.h ../dialog.h ../storage.h ../puttyps.h \
+ ../network.h ../misc.h ../windows/winstuff.h \
+ ../mac/macstuff.h ../macosx/osx.h ../unix/unix.h \
+ ../puttymem.h ../tree234.h ../windows/winhelp.h \
+ ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+gtkcols.o: ../unix/gtkcols.c ../unix/gtkcols.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+gtkdlg.o: ../unix/gtkdlg.c ../unix/gtkcols.h ../unix/gtkpanel.h ../putty.h \
+ ../storage.h ../dialog.h ../tree234.h ../puttyps.h \
+ ../network.h ../misc.h ../windows/winstuff.h \
+ ../mac/macstuff.h ../macosx/osx.h ../unix/unix.h \
+ ../puttymem.h ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+gtkpanel.o: ../unix/gtkpanel.c ../unix/gtkpanel.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+gtkwin.o: ../unix/gtkwin.c ../putty.h ../terminal.h ../puttyps.h \
+ ../network.h ../misc.h ../tree234.h ../windows/winstuff.h \
+ ../mac/macstuff.h ../macosx/osx.h ../unix/unix.h \
+ ../puttymem.h ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+import.o: ../import.c ../putty.h ../ssh.h ../misc.h ../puttyps.h \
+ ../network.h ../puttymem.h ../int64.h ../windows/winstuff.h \
+ ../mac/macstuff.h ../macosx/osx.h ../unix/unix.h \
+ ../tree234.h ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+int64.o: ../int64.c ../int64.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+ldisc.o: ../ldisc.c ../putty.h ../terminal.h ../ldisc.h ../puttyps.h \
+ ../network.h ../misc.h ../tree234.h ../windows/winstuff.h \
+ ../mac/macstuff.h ../macosx/osx.h ../unix/unix.h \
+ ../puttymem.h ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+ldiscucs.o: ../ldiscucs.c ../putty.h ../terminal.h ../ldisc.h ../puttyps.h \
+ ../network.h ../misc.h ../tree234.h ../windows/winstuff.h \
+ ../mac/macstuff.h ../macosx/osx.h ../unix/unix.h \
+ ../puttymem.h ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+localenc.o: ../charset/localenc.c ../charset/charset.h ../charset/internal.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+logging.o: ../logging.c ../putty.h ../puttyps.h ../network.h ../misc.h \
+ ../windows/winstuff.h ../mac/macstuff.h ../macosx/osx.h \
+ ../unix/unix.h ../puttymem.h ../tree234.h \
+ ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+mac.o: ../mac/mac.c ../mac/macresid.h ../putty.h ../ssh.h ../terminal.h \
+ ../mac/mac.h ../puttyps.h ../network.h ../misc.h \
+ ../puttymem.h ../int64.h ../tree234.h ../charset/charset.h \
+ ../windows/winstuff.h ../mac/macstuff.h ../macosx/osx.h \
+ ../unix/unix.h ../windows/winhelp.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+macabout.o: ../mac/macabout.c ../putty.h ../mac/mac.h ../mac/macresid.h \
+ ../puttyps.h ../network.h ../misc.h ../charset/charset.h \
+ ../tree234.h ../windows/winstuff.h ../mac/macstuff.h \
+ ../macosx/osx.h ../unix/unix.h ../puttymem.h \
+ ../windows/winhelp.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+macctrls.o: ../mac/macctrls.c ../putty.h ../mac/mac.h ../mac/macresid.h \
+ ../dialog.h ../tree234.h ../puttyps.h ../network.h ../misc.h \
+ ../charset/charset.h ../windows/winstuff.h ../mac/macstuff.h \
+ ../macosx/osx.h ../unix/unix.h ../puttymem.h \
+ ../windows/winhelp.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+macdlg.o: ../mac/macdlg.c ../putty.h ../dialog.h ../mac/mac.h \
+ ../mac/macresid.h ../storage.h ../puttyps.h ../network.h \
+ ../misc.h ../charset/charset.h ../tree234.h \
+ ../windows/winstuff.h ../mac/macstuff.h ../macosx/osx.h \
+ ../unix/unix.h ../puttymem.h ../windows/winhelp.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+macenc.o: ../charset/macenc.c ../charset/charset.h ../charset/internal.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+macevlog.o: ../mac/macevlog.c ../putty.h ../mac/mac.h ../mac/macresid.h \
+ ../terminal.h ../puttyps.h ../network.h ../misc.h \
+ ../charset/charset.h ../tree234.h ../windows/winstuff.h \
+ ../mac/macstuff.h ../macosx/osx.h ../unix/unix.h \
+ ../puttymem.h ../windows/winhelp.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+macmisc.o: ../mac/macmisc.c ../putty.h ../mac/mac.h ../ssh.h ../puttyps.h \
+ ../network.h ../misc.h ../charset/charset.h ../tree234.h \
+ ../puttymem.h ../int64.h ../windows/winstuff.h \
+ ../mac/macstuff.h ../macosx/osx.h ../unix/unix.h \
+ ../windows/winhelp.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+macnet.o: ../mac/macnet.c ../putty.h ../network.h ../mac/mac.h ../ssh.h \
+ ../puttyps.h ../misc.h ../charset/charset.h ../tree234.h \
+ ../puttymem.h ../int64.h ../windows/winstuff.h \
+ ../mac/macstuff.h ../macosx/osx.h ../unix/unix.h \
+ ../windows/winhelp.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+macnoise.o: ../mac/macnoise.c ../putty.h ../ssh.h ../storage.h ../puttyps.h \
+ ../network.h ../misc.h ../puttymem.h ../int64.h \
+ ../windows/winstuff.h ../mac/macstuff.h ../macosx/osx.h \
+ ../unix/unix.h ../tree234.h ../windows/winhelp.h \
+ ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+macpgen.o: ../mac/macpgen.c ../mac/macpgrid.h ../putty.h ../ssh.h \
+ ../mac/mac.h ../puttyps.h ../network.h ../misc.h \
+ ../puttymem.h ../int64.h ../charset/charset.h ../tree234.h \
+ ../windows/winstuff.h ../mac/macstuff.h ../macosx/osx.h \
+ ../unix/unix.h ../windows/winhelp.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+macpgkey.o: ../mac/macpgkey.c ../putty.h ../mac/mac.h ../mac/macpgrid.h \
+ ../ssh.h ../puttyps.h ../network.h ../misc.h \
+ ../charset/charset.h ../tree234.h ../puttymem.h ../int64.h \
+ ../windows/winstuff.h ../mac/macstuff.h ../macosx/osx.h \
+ ../unix/unix.h ../windows/winhelp.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+macstore.o: ../mac/macstore.c ../putty.h ../storage.h ../mac/mac.h \
+ ../mac/macresid.h ../puttyps.h ../network.h ../misc.h \
+ ../charset/charset.h ../tree234.h ../windows/winstuff.h \
+ ../mac/macstuff.h ../macosx/osx.h ../unix/unix.h \
+ ../puttymem.h ../windows/winhelp.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+macterm.o: ../mac/macterm.c ../mac/macresid.h ../putty.h \
+ ../charset/charset.h ../mac/mac.h ../terminal.h ../puttyps.h \
+ ../network.h ../misc.h ../tree234.h ../windows/winstuff.h \
+ ../mac/macstuff.h ../macosx/osx.h ../unix/unix.h \
+ ../puttymem.h ../windows/winhelp.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+macucs.o: ../mac/macucs.c ../putty.h ../terminal.h ../misc.h ../mac/mac.h \
+ ../puttyps.h ../network.h ../tree234.h ../puttymem.h \
+ ../charset/charset.h ../windows/winstuff.h ../mac/macstuff.h \
+ ../macosx/osx.h ../unix/unix.h ../windows/winhelp.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+mimeenc.o: ../charset/mimeenc.c ../charset/charset.h ../charset/internal.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+minibidi.o: ../minibidi.c ../misc.h ../puttymem.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+misc.o: ../misc.c ../putty.h ../puttyps.h ../network.h ../misc.h \
+ ../windows/winstuff.h ../mac/macstuff.h ../macosx/osx.h \
+ ../unix/unix.h ../puttymem.h ../tree234.h \
+ ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+mtcpnet.o: ../mac/mtcpnet.c ../putty.h ../network.h ../mac/mac.h \
+ ../puttyps.h ../misc.h ../charset/charset.h ../tree234.h \
+ ../windows/winstuff.h ../mac/macstuff.h ../macosx/osx.h \
+ ../unix/unix.h ../puttymem.h ../windows/winhelp.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+nocproxy.o: ../nocproxy.c ../putty.h ../network.h ../proxy.h ../puttyps.h \
+ ../misc.h ../windows/winstuff.h ../mac/macstuff.h \
+ ../macosx/osx.h ../unix/unix.h ../puttymem.h ../tree234.h \
+ ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+notiming.o: ../notiming.c ../putty.h ../puttyps.h ../network.h ../misc.h \
+ ../windows/winstuff.h ../mac/macstuff.h ../macosx/osx.h \
+ ../unix/unix.h ../puttymem.h ../tree234.h \
+ ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+osxctrls.o: ../macosx/osxctrls.m ../putty.h ../dialog.h ../macosx/osxclass.h \
+ ../tree234.h ../puttyps.h ../network.h ../misc.h \
+ ../windows/winstuff.h ../mac/macstuff.h ../macosx/osx.h \
+ ../unix/unix.h ../puttymem.h ../windows/winhelp.h \
+ ../charset/charset.h
+ $(CC) -x objective-c $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+osxdlg.o: ../macosx/osxdlg.m ../putty.h ../storage.h ../dialog.h \
+ ../macosx/osxclass.h ../puttyps.h ../network.h ../misc.h \
+ ../windows/winstuff.h ../mac/macstuff.h ../macosx/osx.h \
+ ../unix/unix.h ../puttymem.h ../tree234.h \
+ ../windows/winhelp.h ../charset/charset.h
+ $(CC) -x objective-c $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+osxmain.o: ../macosx/osxmain.m ../putty.h ../macosx/osxclass.h ../puttyps.h \
+ ../network.h ../misc.h ../windows/winstuff.h \
+ ../mac/macstuff.h ../macosx/osx.h ../unix/unix.h \
+ ../puttymem.h ../tree234.h ../windows/winhelp.h \
+ ../charset/charset.h
+ $(CC) -x objective-c $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+osxsel.o: ../macosx/osxsel.m ../putty.h ../macosx/osxclass.h ../puttyps.h \
+ ../network.h ../misc.h ../windows/winstuff.h \
+ ../mac/macstuff.h ../macosx/osx.h ../unix/unix.h \
+ ../puttymem.h ../tree234.h ../windows/winhelp.h \
+ ../charset/charset.h
+ $(CC) -x objective-c $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+osxwin.o: ../macosx/osxwin.m ../putty.h ../terminal.h ../macosx/osxclass.h \
+ ../puttyps.h ../network.h ../misc.h ../tree234.h \
+ ../windows/winstuff.h ../mac/macstuff.h ../macosx/osx.h \
+ ../unix/unix.h ../puttymem.h ../windows/winhelp.h \
+ ../charset/charset.h
+ $(CC) -x objective-c $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+otnet.o: ../mac/otnet.c ../putty.h ../network.h ../mac/mac.h ../puttyps.h \
+ ../misc.h ../charset/charset.h ../tree234.h \
+ ../windows/winstuff.h ../mac/macstuff.h ../macosx/osx.h \
+ ../unix/unix.h ../puttymem.h ../windows/winhelp.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+pinger.o: ../pinger.c ../putty.h ../puttyps.h ../network.h ../misc.h \
+ ../windows/winstuff.h ../mac/macstuff.h ../macosx/osx.h \
+ ../unix/unix.h ../puttymem.h ../tree234.h \
+ ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+portfwd.o: ../portfwd.c ../putty.h ../ssh.h ../puttyps.h ../network.h \
+ ../misc.h ../puttymem.h ../int64.h ../windows/winstuff.h \
+ ../mac/macstuff.h ../macosx/osx.h ../unix/unix.h \
+ ../tree234.h ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+pproxy.o: ../pproxy.c ../putty.h ../network.h ../proxy.h ../puttyps.h \
+ ../misc.h ../windows/winstuff.h ../mac/macstuff.h \
+ ../macosx/osx.h ../unix/unix.h ../puttymem.h ../tree234.h \
+ ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+proxy.o: ../proxy.c ../putty.h ../network.h ../proxy.h ../puttyps.h \
+ ../misc.h ../windows/winstuff.h ../mac/macstuff.h \
+ ../macosx/osx.h ../unix/unix.h ../puttymem.h ../tree234.h \
+ ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+pscp.o: ../pscp.c ../putty.h ../psftp.h ../ssh.h ../sftp.h ../storage.h \
+ ../puttyps.h ../network.h ../misc.h ../puttymem.h ../int64.h \
+ ../windows/winstuff.h ../mac/macstuff.h ../macosx/osx.h \
+ ../unix/unix.h ../tree234.h ../windows/winhelp.h \
+ ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+psftp.o: ../psftp.c ../putty.h ../psftp.h ../storage.h ../ssh.h ../sftp.h \
+ ../int64.h ../puttyps.h ../network.h ../misc.h ../puttymem.h \
+ ../windows/winstuff.h ../mac/macstuff.h ../macosx/osx.h \
+ ../unix/unix.h ../tree234.h ../windows/winhelp.h \
+ ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+raw.o: ../raw.c ../putty.h ../puttyps.h ../network.h ../misc.h \
+ ../windows/winstuff.h ../mac/macstuff.h ../macosx/osx.h \
+ ../unix/unix.h ../puttymem.h ../tree234.h \
+ ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+rlogin.o: ../rlogin.c ../putty.h ../puttyps.h ../network.h ../misc.h \
+ ../windows/winstuff.h ../mac/macstuff.h ../macosx/osx.h \
+ ../unix/unix.h ../puttymem.h ../tree234.h \
+ ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+sbcs.o: ../charset/sbcs.c ../charset/charset.h ../charset/internal.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+sbcsdat.o: ../charset/sbcsdat.c ../charset/charset.h ../charset/internal.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+settings.o: ../settings.c ../putty.h ../storage.h ../puttyps.h ../network.h \
+ ../misc.h ../windows/winstuff.h ../mac/macstuff.h \
+ ../macosx/osx.h ../unix/unix.h ../puttymem.h ../tree234.h \
+ ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+sftp.o: ../sftp.c ../misc.h ../int64.h ../tree234.h ../sftp.h ../puttymem.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+sizetip.o: ../windows/sizetip.c ../putty.h ../puttyps.h ../network.h \
+ ../misc.h ../windows/winstuff.h ../mac/macstuff.h \
+ ../macosx/osx.h ../unix/unix.h ../puttymem.h ../tree234.h \
+ ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+slookup.o: ../charset/slookup.c ../charset/charset.h ../charset/internal.h \
+ ../charset/enum.c ../charset/sbcsdat.c ../charset/utf8.c
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+ssh.o: ../ssh.c ../putty.h ../tree234.h ../ssh.h ../puttyps.h ../network.h \
+ ../misc.h ../puttymem.h ../int64.h ../windows/winstuff.h \
+ ../mac/macstuff.h ../macosx/osx.h ../unix/unix.h \
+ ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+sshaes.o: ../sshaes.c ../ssh.h ../puttymem.h ../network.h ../int64.h \
+ ../misc.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+sshblowf.o: ../sshblowf.c ../ssh.h ../puttymem.h ../network.h ../int64.h \
+ ../misc.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+sshbn.o: ../sshbn.c ../misc.h ../ssh.h ../puttymem.h ../network.h ../int64.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+sshcrc.o: ../sshcrc.c ../ssh.h ../puttymem.h ../network.h ../int64.h \
+ ../misc.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+sshcrcda.o: ../sshcrcda.c ../misc.h ../ssh.h ../puttymem.h ../network.h \
+ ../int64.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+sshdes.o: ../sshdes.c ../ssh.h ../puttymem.h ../network.h ../int64.h \
+ ../misc.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+sshdh.o: ../sshdh.c ../ssh.h ../puttymem.h ../network.h ../int64.h ../misc.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+sshdss.o: ../sshdss.c ../ssh.h ../misc.h ../puttymem.h ../network.h \
+ ../int64.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+sshdssg.o: ../sshdssg.c ../misc.h ../ssh.h ../puttymem.h ../network.h \
+ ../int64.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+sshmd5.o: ../sshmd5.c ../ssh.h ../puttymem.h ../network.h ../int64.h \
+ ../misc.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+sshprime.o: ../sshprime.c ../ssh.h ../puttymem.h ../network.h ../int64.h \
+ ../misc.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+sshpubk.o: ../sshpubk.c ../putty.h ../ssh.h ../misc.h ../puttyps.h \
+ ../network.h ../puttymem.h ../int64.h ../windows/winstuff.h \
+ ../mac/macstuff.h ../macosx/osx.h ../unix/unix.h \
+ ../tree234.h ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+sshrand.o: ../sshrand.c ../putty.h ../ssh.h ../puttyps.h ../network.h \
+ ../misc.h ../puttymem.h ../int64.h ../windows/winstuff.h \
+ ../mac/macstuff.h ../macosx/osx.h ../unix/unix.h \
+ ../tree234.h ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+sshrsa.o: ../sshrsa.c ../ssh.h ../misc.h ../puttymem.h ../network.h \
+ ../int64.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+sshrsag.o: ../sshrsag.c ../ssh.h ../puttymem.h ../network.h ../int64.h \
+ ../misc.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+sshsh512.o: ../sshsh512.c ../ssh.h ../puttymem.h ../network.h ../int64.h \
+ ../misc.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+sshsha.o: ../sshsha.c ../ssh.h ../puttymem.h ../network.h ../int64.h \
+ ../misc.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+sshzlib.o: ../sshzlib.c ../ssh.h ../puttymem.h ../network.h ../int64.h \
+ ../misc.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+stricmp.o: ../mac/stricmp.c ../putty.h ../puttyps.h ../network.h ../misc.h \
+ ../windows/winstuff.h ../mac/macstuff.h ../macosx/osx.h \
+ ../unix/unix.h ../puttymem.h ../tree234.h \
+ ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+telnet.o: ../telnet.c ../putty.h ../puttyps.h ../network.h ../misc.h \
+ ../windows/winstuff.h ../mac/macstuff.h ../macosx/osx.h \
+ ../unix/unix.h ../puttymem.h ../tree234.h \
+ ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+terminal.o: ../terminal.c ../putty.h ../terminal.h ../puttyps.h ../network.h \
+ ../misc.h ../tree234.h ../windows/winstuff.h \
+ ../mac/macstuff.h ../macosx/osx.h ../unix/unix.h \
+ ../puttymem.h ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+testback.o: ../testback.c ../putty.h ../puttyps.h ../network.h ../misc.h \
+ ../windows/winstuff.h ../mac/macstuff.h ../macosx/osx.h \
+ ../unix/unix.h ../puttymem.h ../tree234.h \
+ ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+time.o: ../time.c
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+timing.o: ../timing.c ../putty.h ../tree234.h ../puttyps.h ../network.h \
+ ../misc.h ../windows/winstuff.h ../mac/macstuff.h \
+ ../macosx/osx.h ../unix/unix.h ../puttymem.h \
+ ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+toucs.o: ../charset/toucs.c ../charset/charset.h ../charset/internal.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+tree234.o: ../tree234.c ../puttymem.h ../tree234.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+utf8.o: ../charset/utf8.c ../charset/charset.h ../charset/internal.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+ux_x11.o: ../unix/ux_x11.c ../putty.h ../ssh.h ../puttyps.h ../network.h \
+ ../misc.h ../puttymem.h ../int64.h ../windows/winstuff.h \
+ ../mac/macstuff.h ../macosx/osx.h ../unix/unix.h \
+ ../tree234.h ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+uxagentc.o: ../unix/uxagentc.c ../putty.h ../misc.h ../tree234.h \
+ ../puttymem.h ../puttyps.h ../network.h \
+ ../windows/winstuff.h ../mac/macstuff.h ../macosx/osx.h \
+ ../unix/unix.h ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+uxcfg.o: ../unix/uxcfg.c ../putty.h ../dialog.h ../storage.h ../puttyps.h \
+ ../network.h ../misc.h ../windows/winstuff.h \
+ ../mac/macstuff.h ../macosx/osx.h ../unix/unix.h \
+ ../puttymem.h ../tree234.h ../windows/winhelp.h \
+ ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+uxcons.o: ../unix/uxcons.c ../putty.h ../storage.h ../ssh.h ../puttyps.h \
+ ../network.h ../misc.h ../puttymem.h ../int64.h \
+ ../windows/winstuff.h ../mac/macstuff.h ../macosx/osx.h \
+ ../unix/unix.h ../tree234.h ../windows/winhelp.h \
+ ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+uxgen.o: ../unix/uxgen.c ../putty.h ../puttyps.h ../network.h ../misc.h \
+ ../windows/winstuff.h ../mac/macstuff.h ../macosx/osx.h \
+ ../unix/unix.h ../puttymem.h ../tree234.h \
+ ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+uxmisc.o: ../unix/uxmisc.c ../putty.h ../puttyps.h ../network.h ../misc.h \
+ ../windows/winstuff.h ../mac/macstuff.h ../macosx/osx.h \
+ ../unix/unix.h ../puttymem.h ../tree234.h \
+ ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+uxnet.o: ../unix/uxnet.c ../putty.h ../network.h ../tree234.h ../puttyps.h \
+ ../misc.h ../windows/winstuff.h ../mac/macstuff.h \
+ ../macosx/osx.h ../unix/unix.h ../puttymem.h \
+ ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+uxnoise.o: ../unix/uxnoise.c ../putty.h ../ssh.h ../storage.h ../puttyps.h \
+ ../network.h ../misc.h ../puttymem.h ../int64.h \
+ ../windows/winstuff.h ../mac/macstuff.h ../macosx/osx.h \
+ ../unix/unix.h ../tree234.h ../windows/winhelp.h \
+ ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+uxplink.o: ../unix/uxplink.c ../putty.h ../storage.h ../tree234.h \
+ ../puttyps.h ../network.h ../misc.h ../windows/winstuff.h \
+ ../mac/macstuff.h ../macosx/osx.h ../unix/unix.h \
+ ../puttymem.h ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+uxprint.o: ../unix/uxprint.c ../putty.h ../puttyps.h ../network.h ../misc.h \
+ ../windows/winstuff.h ../mac/macstuff.h ../macosx/osx.h \
+ ../unix/unix.h ../puttymem.h ../tree234.h \
+ ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+uxproxy.o: ../unix/uxproxy.c ../tree234.h ../putty.h ../network.h ../proxy.h \
+ ../puttyps.h ../misc.h ../windows/winstuff.h \
+ ../mac/macstuff.h ../macosx/osx.h ../unix/unix.h \
+ ../puttymem.h ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+uxpterm.o: ../unix/uxpterm.c ../putty.h ../puttyps.h ../network.h ../misc.h \
+ ../windows/winstuff.h ../mac/macstuff.h ../macosx/osx.h \
+ ../unix/unix.h ../puttymem.h ../tree234.h \
+ ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+uxpty.o: ../unix/uxpty.c ../putty.h ../tree234.h ../puttyps.h ../network.h \
+ ../misc.h ../windows/winstuff.h ../mac/macstuff.h \
+ ../macosx/osx.h ../unix/unix.h ../puttymem.h \
+ ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+uxputty.o: ../unix/uxputty.c ../putty.h ../storage.h ../puttyps.h \
+ ../network.h ../misc.h ../windows/winstuff.h \
+ ../mac/macstuff.h ../macosx/osx.h ../unix/unix.h \
+ ../puttymem.h ../tree234.h ../windows/winhelp.h \
+ ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+uxsel.o: ../unix/uxsel.c ../putty.h ../tree234.h ../puttyps.h ../network.h \
+ ../misc.h ../windows/winstuff.h ../mac/macstuff.h \
+ ../macosx/osx.h ../unix/unix.h ../puttymem.h \
+ ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+uxsftp.o: ../unix/uxsftp.c ../putty.h ../psftp.h ../puttyps.h ../network.h \
+ ../misc.h ../windows/winstuff.h ../mac/macstuff.h \
+ ../macosx/osx.h ../unix/unix.h ../puttymem.h ../tree234.h \
+ ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+uxsignal.o: ../unix/uxsignal.c
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+uxstore.o: ../unix/uxstore.c ../putty.h ../storage.h ../tree234.h \
+ ../puttyps.h ../network.h ../misc.h ../windows/winstuff.h \
+ ../mac/macstuff.h ../macosx/osx.h ../unix/unix.h \
+ ../puttymem.h ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+uxucs.o: ../unix/uxucs.c ../putty.h ../charset/charset.h ../terminal.h \
+ ../misc.h ../puttyps.h ../network.h ../tree234.h \
+ ../puttymem.h ../windows/winstuff.h ../mac/macstuff.h \
+ ../macosx/osx.h ../unix/unix.h ../windows/winhelp.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+version.o: ../version.c
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+vsnprint.o: ../mac/vsnprint.c ../putty.h ../puttyps.h ../network.h ../misc.h \
+ ../windows/winstuff.h ../mac/macstuff.h ../macosx/osx.h \
+ ../unix/unix.h ../puttymem.h ../tree234.h \
+ ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+wcwidth.o: ../wcwidth.c ../putty.h ../puttyps.h ../network.h ../misc.h \
+ ../windows/winstuff.h ../mac/macstuff.h ../macosx/osx.h \
+ ../unix/unix.h ../puttymem.h ../tree234.h \
+ ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+wildcard.o: ../wildcard.c ../putty.h ../puttyps.h ../network.h ../misc.h \
+ ../windows/winstuff.h ../mac/macstuff.h ../macosx/osx.h \
+ ../unix/unix.h ../puttymem.h ../tree234.h \
+ ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+wincfg.o: ../windows/wincfg.c ../putty.h ../dialog.h ../storage.h \
+ ../puttyps.h ../network.h ../misc.h ../windows/winstuff.h \
+ ../mac/macstuff.h ../macosx/osx.h ../unix/unix.h \
+ ../puttymem.h ../tree234.h ../windows/winhelp.h \
+ ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+wincons.o: ../windows/wincons.c ../putty.h ../storage.h ../ssh.h \
+ ../puttyps.h ../network.h ../misc.h ../puttymem.h ../int64.h \
+ ../windows/winstuff.h ../mac/macstuff.h ../macosx/osx.h \
+ ../unix/unix.h ../tree234.h ../windows/winhelp.h \
+ ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+winctrls.o: ../windows/winctrls.c ../putty.h ../misc.h ../dialog.h \
+ ../puttyps.h ../network.h ../puttymem.h \
+ ../windows/winstuff.h ../mac/macstuff.h ../macosx/osx.h \
+ ../unix/unix.h ../tree234.h ../windows/winhelp.h \
+ ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+windefs.o: ../windows/windefs.c ../putty.h ../puttyps.h ../network.h \
+ ../misc.h ../windows/winstuff.h ../mac/macstuff.h \
+ ../macosx/osx.h ../unix/unix.h ../puttymem.h ../tree234.h \
+ ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+windlg.o: ../windows/windlg.c ../putty.h ../ssh.h ../windows/win_res.h \
+ ../storage.h ../dialog.h ../puttyps.h ../network.h ../misc.h \
+ ../puttymem.h ../int64.h ../windows/winstuff.h \
+ ../mac/macstuff.h ../macosx/osx.h ../unix/unix.h \
+ ../tree234.h ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+window.o: ../windows/window.c ../putty.h ../terminal.h ../storage.h \
+ ../windows/win_res.h ../puttyps.h ../network.h ../misc.h \
+ ../tree234.h ../windows/winstuff.h ../mac/macstuff.h \
+ ../macosx/osx.h ../unix/unix.h ../puttymem.h \
+ ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+winmisc.o: ../windows/winmisc.c ../putty.h ../puttyps.h ../network.h \
+ ../misc.h ../windows/winstuff.h ../mac/macstuff.h \
+ ../macosx/osx.h ../unix/unix.h ../puttymem.h ../tree234.h \
+ ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+winnet.o: ../windows/winnet.c ../putty.h ../network.h ../tree234.h \
+ ../puttyps.h ../misc.h ../windows/winstuff.h \
+ ../mac/macstuff.h ../macosx/osx.h ../unix/unix.h \
+ ../puttymem.h ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+winnoise.o: ../windows/winnoise.c ../putty.h ../ssh.h ../storage.h \
+ ../puttyps.h ../network.h ../misc.h ../puttymem.h ../int64.h \
+ ../windows/winstuff.h ../mac/macstuff.h ../macosx/osx.h \
+ ../unix/unix.h ../tree234.h ../windows/winhelp.h \
+ ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+winpgen.o: ../windows/winpgen.c ../putty.h ../ssh.h ../puttyps.h \
+ ../network.h ../misc.h ../puttymem.h ../int64.h \
+ ../windows/winstuff.h ../mac/macstuff.h ../macosx/osx.h \
+ ../unix/unix.h ../tree234.h ../windows/winhelp.h \
+ ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+winpgnt.o: ../windows/winpgnt.c ../putty.h ../ssh.h ../misc.h ../tree234.h \
+ ../puttyps.h ../network.h ../puttymem.h ../int64.h \
+ ../windows/winstuff.h ../mac/macstuff.h ../macosx/osx.h \
+ ../unix/unix.h ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+winpgntc.o: ../windows/winpgntc.c ../putty.h ../puttyps.h ../network.h \
+ ../misc.h ../windows/winstuff.h ../mac/macstuff.h \
+ ../macosx/osx.h ../unix/unix.h ../puttymem.h ../tree234.h \
+ ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+winplink.o: ../windows/winplink.c ../putty.h ../storage.h ../tree234.h \
+ ../puttyps.h ../network.h ../misc.h ../windows/winstuff.h \
+ ../mac/macstuff.h ../macosx/osx.h ../unix/unix.h \
+ ../puttymem.h ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+winprint.o: ../windows/winprint.c ../putty.h ../puttyps.h ../network.h \
+ ../misc.h ../windows/winstuff.h ../mac/macstuff.h \
+ ../macosx/osx.h ../unix/unix.h ../puttymem.h ../tree234.h \
+ ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+winsftp.o: ../windows/winsftp.c ../putty.h ../psftp.h ../puttyps.h \
+ ../network.h ../misc.h ../windows/winstuff.h \
+ ../mac/macstuff.h ../macosx/osx.h ../unix/unix.h \
+ ../puttymem.h ../tree234.h ../windows/winhelp.h \
+ ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+winstore.o: ../windows/winstore.c ../putty.h ../storage.h ../puttyps.h \
+ ../network.h ../misc.h ../windows/winstuff.h \
+ ../mac/macstuff.h ../macosx/osx.h ../unix/unix.h \
+ ../puttymem.h ../tree234.h ../windows/winhelp.h \
+ ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+wintime.o: ../windows/wintime.c ../putty.h ../puttyps.h ../network.h \
+ ../misc.h ../windows/winstuff.h ../mac/macstuff.h \
+ ../macosx/osx.h ../unix/unix.h ../puttymem.h ../tree234.h \
+ ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+winucs.o: ../windows/winucs.c ../putty.h ../terminal.h ../misc.h \
+ ../puttyps.h ../network.h ../tree234.h ../puttymem.h \
+ ../windows/winstuff.h ../mac/macstuff.h ../macosx/osx.h \
+ ../unix/unix.h ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+winutils.o: ../windows/winutils.c ../misc.h ../puttymem.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+x11fwd.o: ../x11fwd.c ../putty.h ../ssh.h ../tree234.h ../puttyps.h \
+ ../network.h ../misc.h ../puttymem.h ../int64.h \
+ ../windows/winstuff.h ../mac/macstuff.h ../macosx/osx.h \
+ ../unix/unix.h ../windows/winhelp.h ../charset/charset.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+xenc.o: ../charset/xenc.c ../charset/charset.h ../charset/internal.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+xkeysym.o: ../unix/xkeysym.c ../misc.h ../puttymem.h
+ $(CC) $(COMPAT) $(FWHACK) $(XFLAGS) $(CFLAGS) -c $<
+
+clean:
+ rm -f *.o *.dmg
+ rm -rf *.app
--- /dev/null
+This directory contains a Mac OS X port of PuTTY/pterm, running as a
+native Aqua GUI application.
+
+THIS PORT IS CURRENTLY UNFINISHED AND EXPERIMENTAL. You are welcome
+to use it, but don't be surprised at unexpected behaviour. I'm not
+kidding.
+
+In particular, I have not yet decided where OS X PuTTY should store
+its configuration data. Options include storing it in ~/.putty to be
+compatible with Unix PuTTY, storing it wherever is compatible with
+Mac Classic PuTTY, storing it in a natively OS X location, or
+sorting out the `config-locations' wishlist item and doing all
+three. Therefore, if you start using this port and create a whole
+load of saved sessions, you should not be surprised if a future
+version of the port decides to look somewhere completely different
+for the data and therefore loses them all. If that happens, don't
+say you weren't warned!
+
+Even more importantly, the alert box that confirms host keys is not
+yet implemented, and the application will bomb out and exit if it
+should be needed. This means you cannot make an SSH connection to a
+new host using the GUI PuTTY in this port: you must first run
+`plink' (which should be exactly identical to the version in the
+Unix port) and tell it to confirm the host key.
+
+Other ways in which the port is currently unfinished include:
+
+ - terminal display is horribly slow
+
+ - fatal errors are currently output via printf, which is obviously
+ wrong for a GUI application
+
+ - fonts aren't configurable
+
+ - several features are unimplemented in the terminal display:
+ underlining, non-solid-block cursors, double-width and
+ double-height line attributes, bold as font rather than as
+ colour, wide (CJK) characters, combining characters.
+
+ - there's no scrollbar
+
+ - terminal window resizing isn't implemented yet
+
+ - proper window placement (cascading down and right from the
+ starting position, plus remembering previous window positions per
+ the Apple HIG) is not implemented
+
+ - close-on-exit isn't implemented
+
+ - warn-on-close isn't implemented
+
+ - SessionWindow's dealloc method does nothing yet, so leaks memory
+
+ - use of Alt+numberpad to enter arbitrary numeric character codes
+ is not yet supported
+
+ - cut and paste isn't supported
+
+ - there's no Meta key yet. (I think it will have to be Command
+ rather than Option since the latter is necessary to send some
+ characters, including the rather important # on Apple UK
+ keyboards; but trapping Command-<key> and sending it to the
+ window rather than the application menu requires me to make a
+ positive effort of some sort and I haven't got round to it yet.)
+
+ - there's no specials menu
+
+ - currently no support for server-side window management requests
+ (i.e. escape sequences to minimise or maximise the window,
+ request or change its position and size, change its title etc)
+
+ - window title is currently fixed
+
+ - no Event Log
+
+ - no mid-session Change Settings
+
+ - no icon (surprisingly important in an OS X app!)
--- /dev/null
+#ifndef PUTTY_OSX_H
+#define PUTTY_OSX_H
+
+/*
+ * Cocoa defines `FontSpec' itself, so we must change its name.
+ * (Arrgh.)
+ */
+#define FontSpec FontSpec_OSX_Proof
+
+/*
+ * Define the various compatibility symbols to make uxpty.c compile
+ * correctly on OS X.
+ */
+#define BSD_PTYS
+#define OMIT_UTMP
+#define HAVE_NO_SETRESUID
+#define NOT_X_WINDOWS
+
+/*
+ * OS X is largely just Unix, so we can include most of this
+ * unchanged.
+ */
+#include "unix.h"
+
+/*
+ * Functions exported by osxsel.m. (Both of these functions are
+ * expected to be called in the _main_ thread: the select subthread
+ * is an implementation detail of osxsel.m and ideally should not
+ * be visible at all outside it.)
+ */
+void osxsel_init(void); /* call this to kick things off */
+void osxsel_process_results(void); /* call this on receipt of a netevent */
+
+#endif
--- /dev/null
+/*
+ * Header file for the Objective-C parts of Mac OS X PuTTY. This
+ * file contains the class definitions, which would cause compile
+ * failures in the pure C modules if they appeared in osx.h.
+ */
+
+#ifndef PUTTY_OSXCLASS_H
+#define PUTTY_OSXCLASS_H
+
+#include "putty.h"
+
+/*
+ * The application controller class, defined in osxmain.m.
+ */
+@interface AppController : NSObject
+{
+ NSTimer *timer;
+}
+- (void)newSessionConfig:(id)sender;
+- (void)newTerminal:(id)sender;
+- (void)newSessionWithConfig:(id)cfg;
+- (void)setTimer:(long)next;
+@end
+extern AppController *controller;
+
+/*
+ * The SessionWindow class, defined in osxwin.m.
+ */
+
+@class SessionWindow;
+@class TerminalView;
+
+@interface SessionWindow : NSWindow
+{
+ Terminal *term;
+ TerminalView *termview;
+ struct unicode_data ucsdata;
+ void *logctx;
+ Config cfg;
+ void *ldisc;
+ Backend *back;
+ void *backhandle;
+}
+- (id)initWithConfig:(Config)cfg;
+- (void)drawStartFinish:(BOOL)start;
+- (void)setColour:(int)n r:(float)r g:(float)g b:(float)b;
+- (Config *)cfg;
+- (void)doText:(wchar_t *)text len:(int)len x:(int)x y:(int)y
+ attr:(unsigned long)attr lattr:(int)lattr;
+- (int)fromBackend:(const char *)data len:(int)len isStderr:(int)is_stderr;
+@end
+
+/*
+ * The ConfigWindow class, defined in osxdlg.m.
+ */
+
+@class ConfigWindow;
+
+@interface ConfigWindow : NSWindow
+{
+ NSOutlineView *treeview;
+ struct controlbox *ctrlbox;
+ struct sesslist sl;
+ void *dv;
+ Config cfg;
+}
+- (id)initWithConfig:(Config)cfg;
+@end
+
+/*
+ * Functions exported by osxctrls.m. (They have to go in this
+ * header file and not osx.h, because some of them have Cocoa class
+ * types in their prototypes.)
+ */
+#define HSPACING 12 /* needed in osxdlg.m and osxctrls.m */
+#define VSPACING 8
+
+void *fe_dlg_init(void *data, NSWindow *window, NSObject *target, SEL action);
+void fe_dlg_free(void *dv);
+void create_ctrls(void *dv, NSView *parent, struct controlset *s,
+ int *minw, int *minh);
+int place_ctrls(void *dv, struct controlset *s, int leftx, int topy,
+ int width); /* returns height used */
+void select_panel(void *dv, struct controlbox *b, const char *name);
+
+#endif /* PUTTY_OSXCLASS_H */
--- /dev/null
+/*
+ * osxctrls.m: OS X implementation of the dialog.h interface.
+ */
+
+#import <Cocoa/Cocoa.h>
+#include "putty.h"
+#include "dialog.h"
+#include "osxclass.h"
+#include "tree234.h"
+
+/*
+ * Still to be implemented:
+ *
+ * - file selectors (NSOpenPanel / NSSavePanel)
+ *
+ * - font selectors
+ * - colour selectors
+ * * both of these have a conceptual oddity in Cocoa that
+ * you're only supposed to have one per application. But I
+ * currently expect to be able to have multiple PuTTY config
+ * boxes on screen at once; what happens if you trigger the
+ * font selector in each one at the same time?
+ * * if it comes to that, the _font_ selector can probably be
+ * managed by other means: nobody is forcing me to implement
+ * a font selector using a `Change...' button. The portable
+ * dialog interface gives me the flexibility to do this how I
+ * want.
+ * * The colour selector interface, in its present form, is
+ * more interesting and _if_ a radical change of plan is
+ * required then it may stretch across the interface into the
+ * portable side.
+ * * Before I do anything rash I should start by looking at the
+ * Mac Classic port and see how it's done there, on the basis
+ * that Apple seem reasonably unlikely to have invented this
+ * crazy restriction specifically for OS X.
+ *
+ * - focus management
+ * * I tried using makeFirstResponder to give keyboard focus,
+ * but it appeared not to work. Try again, and work out how
+ * it should be done.
+ * * also look into tab order. Currently pressing Tab suggests
+ * that only edit boxes and list boxes can get the keyboard
+ * focus, and that buttons (in all their forms) are unable to
+ * be driven by the keyboard. Find out for sure.
+ *
+ * - dlg_error_msg
+ * * this may run into the usual aggro with modal dialog boxes.
+ */
+
+/*
+ * For Cocoa control layout, I need a two-stage process. In stage
+ * one, I allocate all the controls and measure their natural
+ * sizes, which allows me to compute the _minimum_ width and height
+ * of a given section of dialog. Then, in stage two, I lay out the
+ * dialog box as a whole, decide how much each section of the box
+ * needs to receive, and assign it its final size.
+ */
+
+/*
+ * As yet unsolved issues [FIXME]:
+ *
+ * - Sometimes the height returned from create_ctrls and the
+ * height returned from place_ctrls differ. Find out why. It may
+ * be harmless (e.g. results of NSTextView being odd), but I
+ * want to know.
+ *
+ * - NSTextViews are indented a bit. It'd be nice to put their
+ * left margin at the same place as everything else's.
+ *
+ * - I don't yet know whether we even _can_ support tab order or
+ * keyboard shortcuts. If we can't, then fair enough, we can't.
+ * But if we can, we should.
+ *
+ * - I would _really_ like to know of a better way to correct
+ * NSButton's stupid size estimates than by subclassing it and
+ * overriding sizeToFit with hard-wired sensible values!
+ *
+ * - Speaking of stupid size estimates, the amount by which I'm
+ * adjusting a titled NSBox (currently equal to the point size
+ * of its title font) looks as if it isn't _quite_ enough.
+ * Figure out what the real amount should be and use it.
+ *
+ * - I don't understand why there's always a scrollbar displayed
+ * in each list box. I thought I told it to autohide scrollers?
+ *
+ * - Why do I have to fudge list box heights by adding one? (Might
+ * it be to do with the missing header view?)
+ */
+
+/*
+ * Subclass of NSButton which corrects the fact that the normal
+ * one's sizeToFit method persistently returns 32 as its height,
+ * which is simply a lie. I have yet to work out a better
+ * alternative than hard-coding the real heights.
+ */
+@interface MyButton : NSButton
+{
+ int minht;
+}
+@end
+@implementation MyButton
+- (id)initWithFrame:(NSRect)r
+{
+ self = [super initWithFrame:r];
+ minht = 25;
+ return self;
+}
+- (void)setButtonType:(NSButtonType)t
+{
+ if (t == NSRadioButton || t == NSSwitchButton)
+ minht = 18;
+ else
+ minht = 25;
+ [super setButtonType:t];
+}
+- (void)sizeToFit
+{
+ NSRect r;
+ [super sizeToFit];
+ r = [self frame];
+ r.size.height = minht;
+ [self setFrame:r];
+}
+@end
+
+/*
+ * Class used as the data source for NSTableViews.
+ */
+@interface MyTableSource : NSObject
+{
+ tree234 *tree;
+}
+- (id)init;
+- (void)add:(const char *)str withId:(int)id;
+- (int)getid:(int)index;
+- (void)swap:(int)index1 with:(int)index2;
+- (void)removestr:(int)index;
+- (void)clear;
+@end
+@implementation MyTableSource
+- (id)init
+{
+ self = [super init];
+ tree = newtree234(NULL);
+ return self;
+}
+- (void)dealloc
+{
+ char *p;
+ while ((p = delpos234(tree, 0)) != NULL)
+ sfree(p);
+ freetree234(tree);
+ [super dealloc];
+}
+- (void)add:(const char *)str withId:(int)id
+{
+ addpos234(tree, dupprintf("%d\t%s", id, str), count234(tree));
+}
+- (int)getid:(int)index
+{
+ char *p = index234(tree, index);
+ return atoi(p);
+}
+- (void)removestr:(int)index
+{
+ char *p = delpos234(tree, index);
+ sfree(p);
+}
+- (void)swap:(int)index1 with:(int)index2
+{
+ char *p1, *p2;
+
+ if (index1 > index2) {
+ int t = index1; index1 = index2; index2 = t;
+ }
+
+ /* delete later one first so it doesn't affect index of earlier one */
+ p2 = delpos234(tree, index2);
+ p1 = delpos234(tree, index1);
+
+ /* now insert earlier one before later one for the inverse reason */
+ addpos234(tree, p2, index1);
+ addpos234(tree, p1, index2);
+}
+- (void)clear
+{
+ char *p;
+ while ((p = delpos234(tree, 0)) != NULL)
+ sfree(p);
+}
+- (int)numberOfRowsInTableView:(NSTableView *)aTableView
+{
+ return count234(tree);
+}
+- (id)tableView:(NSTableView *)aTableView
+ objectValueForTableColumn:(NSTableColumn *)aTableColumn
+ row:(int)rowIndex
+{
+ int j = [[aTableColumn identifier] intValue];
+ char *p = index234(tree, rowIndex);
+
+ while (j >= 0) {
+ p += strcspn(p, "\t");
+ if (*p) p++;
+ j--;
+ }
+
+ return [NSString stringWithCString:p length:strcspn(p, "\t")];
+}
+@end
+
+/*
+ * Object to receive messages from various control classes.
+ */
+@class Receiver;
+
+struct fe_dlg {
+ NSWindow *window;
+ NSObject *target;
+ SEL action;
+ tree234 *byctrl;
+ tree234 *bywidget;
+ tree234 *boxes;
+ void *data; /* passed to portable side */
+ Receiver *rec;
+};
+
+@interface Receiver : NSObject
+{
+ struct fe_dlg *d;
+}
+- (id)initWithStruct:(struct fe_dlg *)aStruct;
+@end
+
+struct fe_ctrl {
+ union control *ctrl;
+ NSButton *button, *button2;
+ NSTextField *label, *editbox;
+ NSComboBox *combobox;
+ NSButton **radiobuttons;
+ NSTextView *textview;
+ NSPopUpButton *popupbutton;
+ NSTableView *tableview;
+ NSScrollView *scrollview;
+ int nradiobuttons;
+ void *privdata;
+ int privdata_needs_free;
+};
+
+static int fe_ctrl_cmp_by_ctrl(void *av, void *bv)
+{
+ struct fe_ctrl *a = (struct fe_ctrl *)av;
+ struct fe_ctrl *b = (struct fe_ctrl *)bv;
+
+ if (a->ctrl < b->ctrl)
+ return -1;
+ if (a->ctrl > b->ctrl)
+ return +1;
+ return 0;
+}
+
+static int fe_ctrl_find_by_ctrl(void *av, void *bv)
+{
+ union control *a = (union control *)av;
+ struct fe_ctrl *b = (struct fe_ctrl *)bv;
+
+ if (a < b->ctrl)
+ return -1;
+ if (a > b->ctrl)
+ return +1;
+ return 0;
+}
+
+struct fe_box {
+ struct controlset *s;
+ id box;
+};
+
+static int fe_boxcmp(void *av, void *bv)
+{
+ struct fe_box *a = (struct fe_box *)av;
+ struct fe_box *b = (struct fe_box *)bv;
+
+ if (a->s < b->s)
+ return -1;
+ if (a->s > b->s)
+ return +1;
+ return 0;
+}
+
+static int fe_boxfind(void *av, void *bv)
+{
+ struct controlset *a = (struct controlset *)av;
+ struct fe_box *b = (struct fe_box *)bv;
+
+ if (a < b->s)
+ return -1;
+ if (a > b->s)
+ return +1;
+ return 0;
+}
+
+struct fe_backwards { /* map Cocoa widgets back to fe_ctrls */
+ id widget;
+ struct fe_ctrl *c;
+};
+
+static int fe_backwards_cmp_by_widget(void *av, void *bv)
+{
+ struct fe_backwards *a = (struct fe_backwards *)av;
+ struct fe_backwards *b = (struct fe_backwards *)bv;
+
+ if (a->widget < b->widget)
+ return -1;
+ if (a->widget > b->widget)
+ return +1;
+ return 0;
+}
+
+static int fe_backwards_find_by_widget(void *av, void *bv)
+{
+ id a = (id)av;
+ struct fe_backwards *b = (struct fe_backwards *)bv;
+
+ if (a < b->widget)
+ return -1;
+ if (a > b->widget)
+ return +1;
+ return 0;
+}
+
+static struct fe_ctrl *fe_ctrl_new(union control *ctrl)
+{
+ struct fe_ctrl *c;
+
+ c = snew(struct fe_ctrl);
+ c->ctrl = ctrl;
+
+ c->button = c->button2 = nil;
+ c->label = nil;
+ c->editbox = nil;
+ c->combobox = nil;
+ c->textview = nil;
+ c->popupbutton = nil;
+ c->tableview = nil;
+ c->scrollview = nil;
+ c->radiobuttons = NULL;
+ c->nradiobuttons = 0;
+ c->privdata = NULL;
+ c->privdata_needs_free = FALSE;
+
+ return c;
+}
+
+static void fe_ctrl_free(struct fe_ctrl *c)
+{
+ if (c->privdata_needs_free)
+ sfree(c->privdata);
+ sfree(c->radiobuttons);
+ sfree(c);
+}
+
+static struct fe_ctrl *fe_ctrl_byctrl(struct fe_dlg *d, union control *ctrl)
+{
+ return find234(d->byctrl, ctrl, fe_ctrl_find_by_ctrl);
+}
+
+static void add_box(struct fe_dlg *d, struct controlset *s, id box)
+{
+ struct fe_box *b = snew(struct fe_box);
+ b->box = box;
+ b->s = s;
+ add234(d->boxes, b);
+}
+
+static id find_box(struct fe_dlg *d, struct controlset *s)
+{
+ struct fe_box *b = find234(d->boxes, s, fe_boxfind);
+ return b ? b->box : NULL;
+}
+
+static void add_widget(struct fe_dlg *d, struct fe_ctrl *c, id widget)
+{
+ struct fe_backwards *b = snew(struct fe_backwards);
+ b->widget = widget;
+ b->c = c;
+ add234(d->bywidget, b);
+}
+
+static struct fe_ctrl *find_widget(struct fe_dlg *d, id widget)
+{
+ struct fe_backwards *b = find234(d->bywidget, widget,
+ fe_backwards_find_by_widget);
+ return b ? b->c : NULL;
+}
+
+void *fe_dlg_init(void *data, NSWindow *window, NSObject *target, SEL action)
+{
+ struct fe_dlg *d;
+
+ d = snew(struct fe_dlg);
+ d->window = window;
+ d->target = target;
+ d->action = action;
+ d->byctrl = newtree234(fe_ctrl_cmp_by_ctrl);
+ d->bywidget = newtree234(fe_backwards_cmp_by_widget);
+ d->boxes = newtree234(fe_boxcmp);
+ d->data = data;
+ d->rec = [[Receiver alloc] initWithStruct:d];
+
+ return d;
+}
+
+void fe_dlg_free(void *dv)
+{
+ struct fe_dlg *d = (struct fe_dlg *)dv;
+ struct fe_ctrl *c;
+ struct fe_box *b;
+
+ while ( (c = delpos234(d->byctrl, 0)) != NULL )
+ fe_ctrl_free(c);
+ freetree234(d->byctrl);
+
+ while ( (c = delpos234(d->bywidget, 0)) != NULL )
+ sfree(c);
+ freetree234(d->bywidget);
+
+ while ( (b = delpos234(d->boxes, 0)) != NULL )
+ sfree(b);
+ freetree234(d->boxes);
+
+ [d->rec release];
+
+ sfree(d);
+}
+
+@implementation Receiver
+- (id)initWithStruct:(struct fe_dlg *)aStruct
+{
+ self = [super init];
+ d = aStruct;
+ return self;
+}
+- (void)buttonPushed:(id)sender
+{
+ struct fe_ctrl *c = find_widget(d, sender);
+
+ assert(c && c->ctrl->generic.type == CTRL_BUTTON);
+ c->ctrl->generic.handler(c->ctrl, d, d->data, EVENT_ACTION);
+}
+- (void)checkboxChanged:(id)sender
+{
+ struct fe_ctrl *c = find_widget(d, sender);
+
+ assert(c && c->ctrl->generic.type == CTRL_CHECKBOX);
+ c->ctrl->generic.handler(c->ctrl, d, d->data, EVENT_VALCHANGE);
+}
+- (void)radioChanged:(id)sender
+{
+ struct fe_ctrl *c = find_widget(d, sender);
+ int j;
+
+ assert(c && c->radiobuttons);
+ for (j = 0; j < c->nradiobuttons; j++)
+ if (sender != c->radiobuttons[j])
+ [c->radiobuttons[j] setState:NSOffState];
+ c->ctrl->generic.handler(c->ctrl, d, d->data, EVENT_VALCHANGE);
+}
+- (void)popupMenuSelected:(id)sender
+{
+ struct fe_ctrl *c = find_widget(d, sender);
+ c->ctrl->generic.handler(c->ctrl, d, d->data, EVENT_VALCHANGE);
+}
+- (void)controlTextDidChange:(NSNotification *)notification
+{
+ id widget = [notification object];
+ struct fe_ctrl *c = find_widget(d, widget);
+ assert(c && c->ctrl->generic.type == CTRL_EDITBOX);
+ c->ctrl->generic.handler(c->ctrl, d, d->data, EVENT_VALCHANGE);
+}
+- (void)controlTextDidEndEditing:(NSNotification *)notification
+{
+ id widget = [notification object];
+ struct fe_ctrl *c = find_widget(d, widget);
+ assert(c && c->ctrl->generic.type == CTRL_EDITBOX);
+ c->ctrl->generic.handler(c->ctrl, d, d->data, EVENT_REFRESH);
+}
+- (void)tableViewSelectionDidChange:(NSNotification *)notification
+{
+ id widget = [notification object];
+ struct fe_ctrl *c = find_widget(d, widget);
+ assert(c && c->ctrl->generic.type == CTRL_LISTBOX);
+ c->ctrl->generic.handler(c->ctrl, d, d->data, EVENT_SELCHANGE);
+}
+- (BOOL)tableView:(NSTableView *)aTableView
+ shouldEditTableColumn:(NSTableColumn *)aTableColumn
+ row:(int)rowIndex
+{
+ return NO; /* no editing permitted */
+}
+- (void)listDoubleClicked:(id)sender
+{
+ struct fe_ctrl *c = find_widget(d, sender);
+ assert(c && c->ctrl->generic.type == CTRL_LISTBOX);
+ c->ctrl->generic.handler(c->ctrl, d, d->data, EVENT_ACTION);
+}
+- (void)dragListButton:(id)sender
+{
+ struct fe_ctrl *c = find_widget(d, sender);
+ int direction, row, nrows;
+ assert(c && c->ctrl->generic.type == CTRL_LISTBOX &&
+ c->ctrl->listbox.draglist);
+
+ if (sender == c->button)
+ direction = -1; /* up */
+ else
+ direction = +1; /* down */
+
+ row = [c->tableview selectedRow];
+ nrows = [c->tableview numberOfRows];
+
+ if (row + direction < 0 || row + direction >= nrows) {
+ NSBeep();
+ return;
+ }
+
+ [[c->tableview dataSource] swap:row with:row+direction];
+ [c->tableview reloadData];
+ [c->tableview selectRow:row+direction byExtendingSelection:NO];
+
+ c->ctrl->generic.handler(c->ctrl, d, d->data, EVENT_VALCHANGE);
+}
+@end
+
+void create_ctrls(void *dv, NSView *parent, struct controlset *s,
+ int *minw, int *minh)
+{
+ struct fe_dlg *d = (struct fe_dlg *)dv;
+ int ccw[100]; /* cumulative column widths */
+ int cypos[100];
+ int ncols;
+ int wmin = 0, hmin = 0;
+ int i, j, cw, ch;
+ NSRect rect;
+ NSFont *textviewfont = nil;
+ int boxh = 0, boxw = 0;
+
+ if (!s->boxname && s->boxtitle) {
+ /* This controlset is a panel title. */
+
+ NSTextField *tf;
+
+ tf = [[NSTextField alloc] initWithFrame:NSMakeRect(0,0,1,1)];
+ [tf setEditable:NO];
+ [tf setSelectable:NO];
+ [tf setBordered:NO];
+ [tf setDrawsBackground:NO];
+ [tf setStringValue:[NSString stringWithCString:s->boxtitle]];
+ [tf sizeToFit];
+ rect = [tf frame];
+ [parent addSubview:tf];
+
+ /*
+ * I'm going to store this NSTextField in the boxes tree,
+ * because I really can't face having a special tree234
+ * mapping controlsets to panel titles.
+ */
+ add_box(d, s, tf);
+
+ *minw = rect.size.width;
+ *minh = rect.size.height;
+
+ return;
+ }
+
+ if (*s->boxname) {
+ /*
+ * Create an NSBox to contain this subset of controls.
+ */
+ NSBox *box;
+ NSRect tmprect;
+
+ box = [[NSBox alloc] initWithFrame:NSMakeRect(0,0,1,1)];
+ if (s->boxtitle)
+ [box setTitle:[NSString stringWithCString:s->boxtitle]];
+ else
+ [box setTitlePosition:NSNoTitle];
+ add_box(d, s, box);
+ tmprect = [box frame];
+ [box setContentViewMargins:NSMakeSize(20,20)];
+ [box setFrameFromContentFrame:NSMakeRect(100,100,100,100)];
+ rect = [box frame];
+ [box setFrame:tmprect];
+ boxh = (int)(rect.size.height - 100);
+ boxw = (int)(rect.size.width - 100);
+ [parent addSubview:box];
+
+ if (s->boxtitle)
+ boxh += [[box titleFont] pointSize];
+
+ /*
+ * All subsequent controls will be placed within this box.
+ */
+ parent = box;
+ }
+
+ ncols = 1;
+ ccw[0] = 0;
+ ccw[1] = 100;
+ cypos[0] = 0;
+
+ /*
+ * Now iterate through the controls themselves, create them,
+ * and add their width and height to the overall width/height
+ * calculation.
+ */
+ for (i = 0; i < s->ncontrols; i++) {
+ union control *ctrl = s->ctrls[i];
+ struct fe_ctrl *c;
+ int colstart = COLUMN_START(ctrl->generic.column);
+ int colspan = COLUMN_SPAN(ctrl->generic.column);
+ int colend = colstart + colspan;
+ int ytop, wthis;
+
+ switch (ctrl->generic.type) {
+ case CTRL_COLUMNS:
+ for (j = 1; j < ncols; j++)
+ if (cypos[0] < cypos[j])
+ cypos[0] = cypos[j];
+
+ assert(ctrl->columns.ncols < lenof(ccw));
+
+ ccw[0] = 0;
+ for (j = 0; j < ctrl->columns.ncols; j++) {
+ ccw[j+1] = ccw[j] + (ctrl->columns.percentages ?
+ ctrl->columns.percentages[j] : 100);
+ cypos[j] = cypos[0];
+ }
+
+ ncols = ctrl->columns.ncols;
+
+ continue; /* no actual control created */
+ case CTRL_TABDELAY:
+ /*
+ * I'm currently uncertain that we can implement tab
+ * order in OS X.
+ */
+ continue; /* no actual control created */
+ }
+
+ c = fe_ctrl_new(ctrl);
+ add234(d->byctrl, c);
+
+ cw = ch = 0;
+
+ switch (ctrl->generic.type) {
+ case CTRL_BUTTON:
+ case CTRL_CHECKBOX:
+ {
+ NSButton *b;
+
+ b = [[MyButton alloc] initWithFrame:NSMakeRect(0, 0, 1, 1)];
+ [b setBezelStyle:NSRoundedBezelStyle];
+ if (ctrl->generic.type == CTRL_CHECKBOX)
+ [b setButtonType:NSSwitchButton];
+ [b setTitle:[NSString stringWithCString:ctrl->generic.label]];
+ if (ctrl->button.isdefault)
+ [b setKeyEquivalent:@"\r"];
+ else if (ctrl->button.iscancel)
+ [b setKeyEquivalent:@"\033"];
+ [b sizeToFit];
+ rect = [b frame];
+
+ [parent addSubview:b];
+
+ [b setTarget:d->rec];
+ if (ctrl->generic.type == CTRL_CHECKBOX)
+ [b setAction:@selector(checkboxChanged:)];
+ else
+ [b setAction:@selector(buttonPushed:)];
+ add_widget(d, c, b);
+
+ c->button = b;
+
+ cw = rect.size.width;
+ ch = rect.size.height;
+ }
+ break;
+ case CTRL_EDITBOX:
+ {
+ int editp = ctrl->editbox.percentwidth;
+ int labelp = editp == 100 ? 100 : 100 - editp;
+ NSTextField *tf;
+ NSComboBox *cb;
+
+ tf = [[NSTextField alloc] initWithFrame:NSMakeRect(0,0,1,1)];
+ [tf setEditable:NO];
+ [tf setSelectable:NO];
+ [tf setBordered:NO];
+ [tf setDrawsBackground:NO];
+ [tf setStringValue:[NSString
+ stringWithCString:ctrl->generic.label]];
+ [tf sizeToFit];
+ rect = [tf frame];
+ [parent addSubview:tf];
+ c->label = tf;
+
+ cw = rect.size.width * 100 / labelp;
+ ch = rect.size.height;
+
+ if (ctrl->editbox.has_list) {
+ cb = [[NSComboBox alloc]
+ initWithFrame:NSMakeRect(0,0,1,1)];
+ [cb setStringValue:@"x"];
+ [cb sizeToFit];
+ rect = [cb frame];
+ [parent addSubview:cb];
+ c->combobox = cb;
+ } else {
+ if (ctrl->editbox.password)
+ tf = [NSSecureTextField alloc];
+ else
+ tf = [NSTextField alloc];
+
+ tf = [tf initWithFrame:NSMakeRect(0,0,1,1)];
+ [tf setEditable:YES];
+ [tf setSelectable:YES];
+ [tf setBordered:YES];
+ [tf setStringValue:@"x"];
+ [tf sizeToFit];
+ rect = [tf frame];
+ [parent addSubview:tf];
+ c->editbox = tf;
+
+ [tf setDelegate:d->rec];
+ add_widget(d, c, tf);
+ }
+
+ if (editp == 100) {
+ /* the edit box and its label are vertically separated */
+ ch += VSPACING + rect.size.height;
+ } else {
+ /* the edit box and its label are horizontally separated */
+ if (ch < rect.size.height)
+ ch = rect.size.height;
+ }
+
+ if (cw < rect.size.width * 100 / editp)
+ cw = rect.size.width * 100 / editp;
+ }
+ break;
+ case CTRL_TEXT:
+ {
+ NSTextView *tv;
+ int testwid;
+
+ if (!textviewfont) {
+ NSTextField *tf;
+ tf = [[NSTextField alloc] init];
+ textviewfont = [tf font];
+ [tf release];
+ }
+
+ testwid = (ccw[colend] - ccw[colstart]) * 3;
+
+ tv = [[NSTextView alloc]
+ initWithFrame:NSMakeRect(0,0,testwid,1)];
+ [tv setEditable:NO];
+ [tv setSelectable:NO];
+ //[tv setBordered:NO];
+ [tv setDrawsBackground:NO];
+ [tv setFont:textviewfont];
+ [tv setString:
+ [NSString stringWithCString:ctrl->generic.label]];
+ rect = [tv frame];
+ [tv sizeToFit];
+ [parent addSubview:tv];
+ c->textview = tv;
+
+ cw = rect.size.width;
+ ch = rect.size.height;
+ }
+ break;
+ case CTRL_RADIO:
+ {
+ NSTextField *tf;
+ int j;
+
+ if (ctrl->generic.label) {
+ tf = [[NSTextField alloc]
+ initWithFrame:NSMakeRect(0,0,1,1)];
+ [tf setEditable:NO];
+ [tf setSelectable:NO];
+ [tf setBordered:NO];
+ [tf setDrawsBackground:NO];
+ [tf setStringValue:
+ [NSString stringWithCString:ctrl->generic.label]];
+ [tf sizeToFit];
+ rect = [tf frame];
+ [parent addSubview:tf];
+ c->label = tf;
+
+ cw = rect.size.width;
+ ch = rect.size.height;
+ } else {
+ cw = 0;
+ ch = -VSPACING; /* compensate for next advance */
+ }
+
+ c->nradiobuttons = ctrl->radio.nbuttons;
+ c->radiobuttons = snewn(ctrl->radio.nbuttons, NSButton *);
+
+ for (j = 0; j < ctrl->radio.nbuttons; j++) {
+ NSButton *b;
+ int ncols;
+
+ b = [[MyButton alloc] initWithFrame:NSMakeRect(0,0,1,1)];
+ [b setBezelStyle:NSRoundedBezelStyle];
+ [b setButtonType:NSRadioButton];
+ [b setTitle:[NSString
+ stringWithCString:ctrl->radio.buttons[j]]];
+ [b sizeToFit];
+ rect = [b frame];
+ [parent addSubview:b];
+
+ c->radiobuttons[j] = b;
+
+ [b setTarget:d->rec];
+ [b setAction:@selector(radioChanged:)];
+ add_widget(d, c, b);
+
+ /*
+ * Add to the height every time we place a
+ * button in column 0.
+ */
+ if (j % ctrl->radio.ncolumns == 0) {
+ ch += rect.size.height + VSPACING;
+ }
+
+ /*
+ * Add to the width by working out how many
+ * columns this button spans.
+ */
+ if (j == ctrl->radio.nbuttons - 1)
+ ncols = (ctrl->radio.ncolumns -
+ (j % ctrl->radio.ncolumns));
+ else
+ ncols = 1;
+
+ if (cw < rect.size.width * ctrl->radio.ncolumns / ncols)
+ cw = rect.size.width * ctrl->radio.ncolumns / ncols;
+ }
+ }
+ break;
+ case CTRL_FILESELECT:
+ case CTRL_FONTSELECT:
+ {
+ NSTextField *tf;
+ NSButton *b;
+ int kh;
+
+ tf = [[NSTextField alloc] initWithFrame:NSMakeRect(0,0,1,1)];
+ [tf setEditable:NO];
+ [tf setSelectable:NO];
+ [tf setBordered:NO];
+ [tf setDrawsBackground:NO];
+ [tf setStringValue:[NSString
+ stringWithCString:ctrl->generic.label]];
+ [tf sizeToFit];
+ rect = [tf frame];
+ [parent addSubview:tf];
+ c->label = tf;
+
+ cw = rect.size.width;
+ ch = rect.size.height;
+
+ tf = [NSTextField alloc];
+ tf = [tf initWithFrame:NSMakeRect(0,0,1,1)];
+ if (ctrl->generic.type == CTRL_FILESELECT) {
+ [tf setEditable:YES];
+ [tf setSelectable:YES];
+ [tf setBordered:YES];
+ } else {
+ [tf setEditable:NO];
+ [tf setSelectable:NO];
+ [tf setBordered:NO];
+ [tf setDrawsBackground:NO];
+ }
+ [tf setStringValue:@"x"];
+ [tf sizeToFit];
+ rect = [tf frame];
+ [parent addSubview:tf];
+ c->editbox = tf;
+
+ kh = rect.size.height;
+ if (cw < rect.size.width * 4 / 3)
+ cw = rect.size.width * 4 / 3;
+
+ b = [[MyButton alloc] initWithFrame:NSMakeRect(0, 0, 1, 1)];
+ [b setBezelStyle:NSRoundedBezelStyle];
+ if (ctrl->generic.type == CTRL_FILESELECT)
+ [b setTitle:@"Browse..."];
+ else
+ [b setTitle:@"Change..."];
+ // [b setKeyEquivalent:somethingorother];
+ // [b setTarget:somethingorother];
+ // [b setAction:somethingorother];
+ [b sizeToFit];
+ rect = [b frame];
+ [parent addSubview:b];
+
+ c->button = b;
+
+ if (kh < rect.size.height)
+ kh = rect.size.height;
+ ch += VSPACING + kh;
+ if (cw < rect.size.width * 4)
+ cw = rect.size.width * 4;
+ }
+ break;
+ case CTRL_LISTBOX:
+ {
+ int listp = ctrl->listbox.percentwidth;
+ int labelp = listp == 100 ? 100 : 100 - listp;
+ NSTextField *tf;
+ NSPopUpButton *pb;
+ NSTableView *tv;
+ NSScrollView *sv;
+
+ if (ctrl->generic.label) {
+ tf = [[NSTextField alloc]
+ initWithFrame:NSMakeRect(0,0,1,1)];
+ [tf setEditable:NO];
+ [tf setSelectable:NO];
+ [tf setBordered:NO];
+ [tf setDrawsBackground:NO];
+ [tf setStringValue:
+ [NSString stringWithCString:ctrl->generic.label]];
+ [tf sizeToFit];
+ rect = [tf frame];
+ [parent addSubview:tf];
+ c->label = tf;
+
+ cw = rect.size.width;
+ ch = rect.size.height;
+ } else {
+ cw = 0;
+ ch = -VSPACING; /* compensate for next advance */
+ }
+
+ if (ctrl->listbox.height == 0) {
+ pb = [[NSPopUpButton alloc]
+ initWithFrame:NSMakeRect(0,0,1,1)];
+ [pb sizeToFit];
+ rect = [pb frame];
+ [parent addSubview:pb];
+ c->popupbutton = pb;
+
+ [pb setTarget:d->rec];
+ [pb setAction:@selector(popupMenuSelected:)];
+ add_widget(d, c, pb);
+ } else {
+ assert(listp == 100);
+ if (ctrl->listbox.draglist) {
+ int bi;
+
+ listp = 75;
+
+ for (bi = 0; bi < 2; bi++) {
+ NSButton *b;
+ b = [[MyButton alloc]
+ initWithFrame:NSMakeRect(0, 0, 1, 1)];
+ [b setBezelStyle:NSRoundedBezelStyle];
+ if (bi == 0)
+ [b setTitle:@"Up"];
+ else
+ [b setTitle:@"Down"];
+ [b sizeToFit];
+ rect = [b frame];
+ [parent addSubview:b];
+
+ if (bi == 0)
+ c->button = b;
+ else
+ c->button2 = b;
+
+ [b setTarget:d->rec];
+ [b setAction:@selector(dragListButton:)];
+ add_widget(d, c, b);
+
+ if (cw < rect.size.width * 4)
+ cw = rect.size.width * 4;
+ }
+ }
+
+ sv = [[NSScrollView alloc] initWithFrame:
+ NSMakeRect(20,20,10,10)];
+ [sv setBorderType:NSLineBorder];
+ tv = [[NSTableView alloc] initWithFrame:[sv frame]];
+ [[tv headerView] setFrame:NSMakeRect(0,0,0,0)];
+ [sv setDocumentView:tv];
+ [parent addSubview:sv];
+ [sv setHasVerticalScroller:YES];
+ [sv setAutohidesScrollers:YES];
+ [tv setAllowsColumnReordering:NO];
+ [tv setAllowsColumnResizing:NO];
+ [tv setAllowsMultipleSelection:ctrl->listbox.multisel];
+ [tv setAllowsEmptySelection:YES];
+ [tv setAllowsColumnSelection:YES];
+ [tv setDataSource:[[MyTableSource alloc] init]];
+ rect = [tv frame];
+ /*
+ * For some reason this consistently comes out
+ * one short. Add one.
+ */
+ rect.size.height = (ctrl->listbox.height+1)*[tv rowHeight];
+ [sv setFrame:rect];
+ c->tableview = tv;
+ c->scrollview = sv;
+
+ [tv setDelegate:d->rec];
+ [tv setTarget:d->rec];
+ [tv setDoubleAction:@selector(listDoubleClicked:)];
+ add_widget(d, c, tv);
+ }
+
+ if (c->tableview) {
+ int ncols, *percentages;
+ int hundred = 100;
+
+ if (ctrl->listbox.ncols) {
+ ncols = ctrl->listbox.ncols;
+ percentages = ctrl->listbox.percentages;
+ } else {
+ ncols = 1;
+ percentages = &hundred;
+ }
+
+ for (j = 0; j < ncols; j++) {
+ NSTableColumn *col;
+
+ col = [[NSTableColumn alloc] initWithIdentifier:
+ [NSNumber numberWithInt:j]];
+ [c->tableview addTableColumn:col];
+ }
+ }
+
+ if (labelp == 100) {
+ /* the list and its label are vertically separated */
+ ch += VSPACING + rect.size.height;
+ } else {
+ /* the list and its label are horizontally separated */
+ if (ch < rect.size.height)
+ ch = rect.size.height;
+ }
+
+ if (cw < rect.size.width * 100 / listp)
+ cw = rect.size.width * 100 / listp;
+ }
+ break;
+ }
+
+ /*
+ * Update the width and height data for the control we've
+ * just created.
+ */
+ ytop = 0;
+
+ for (j = colstart; j < colend; j++) {
+ if (ytop < cypos[j])
+ ytop = cypos[j];
+ }
+
+ for (j = colstart; j < colend; j++)
+ cypos[j] = ytop + ch + VSPACING;
+
+ if (hmin < ytop + ch)
+ hmin = ytop + ch;
+
+ wthis = (cw + HSPACING) * 100 / (ccw[colend] - ccw[colstart]);
+ wthis -= HSPACING;
+
+ if (wmin < wthis)
+ wmin = wthis;
+ }
+
+ if (*s->boxname) {
+ /*
+ * Add a bit to the width and height for the box.
+ */
+ wmin += boxw;
+ hmin += boxh;
+ }
+
+ //printf("For controlset %s/%s, returning w=%d h=%d\n",
+ // s->pathname, s->boxname, wmin, hmin);
+ *minw = wmin;
+ *minh = hmin;
+}
+
+int place_ctrls(void *dv, struct controlset *s, int leftx, int topy,
+ int width)
+{
+ struct fe_dlg *d = (struct fe_dlg *)dv;
+ int ccw[100]; /* cumulative column widths */
+ int cypos[100];
+ int ncols;
+ int i, j, ret;
+ int boxh = 0, boxw = 0;
+
+ if (!s->boxname && s->boxtitle) {
+ /* Size and place the panel title. */
+
+ NSTextField *tf = find_box(d, s);
+ NSRect rect;
+
+ rect = [tf frame];
+ [tf setFrame:NSMakeRect(leftx, topy-rect.size.height,
+ width, rect.size.height)];
+ return rect.size.height;
+ }
+
+ if (*s->boxname) {
+ NSRect rect, tmprect;
+ NSBox *box = find_box(d, s);
+
+ assert(box != NULL);
+ tmprect = [box frame];
+ [box setFrameFromContentFrame:NSMakeRect(100,100,100,100)];
+ rect = [box frame];
+ [box setFrame:tmprect];
+ boxw = rect.size.width - 100;
+ boxh = rect.size.height - 100;
+ if (s->boxtitle)
+ boxh += [[box titleFont] pointSize];
+ topy -= boxh;
+ width -= boxw;
+ }
+
+ ncols = 1;
+ ccw[0] = 0;
+ ccw[1] = 100;
+ cypos[0] = topy;
+ ret = 0;
+
+ /*
+ * Now iterate through the controls themselves, placing them
+ * appropriately.
+ */
+ for (i = 0; i < s->ncontrols; i++) {
+ union control *ctrl = s->ctrls[i];
+ struct fe_ctrl *c;
+ int colstart = COLUMN_START(ctrl->generic.column);
+ int colspan = COLUMN_SPAN(ctrl->generic.column);
+ int colend = colstart + colspan;
+ int xthis, ythis, wthis, ch;
+ NSRect rect;
+
+ switch (ctrl->generic.type) {
+ case CTRL_COLUMNS:
+ for (j = 1; j < ncols; j++)
+ if (cypos[0] > cypos[j])
+ cypos[0] = cypos[j];
+
+ assert(ctrl->columns.ncols < lenof(ccw));
+
+ ccw[0] = 0;
+ for (j = 0; j < ctrl->columns.ncols; j++) {
+ ccw[j+1] = ccw[j] + (ctrl->columns.percentages ?
+ ctrl->columns.percentages[j] : 100);
+ cypos[j] = cypos[0];
+ }
+
+ ncols = ctrl->columns.ncols;
+
+ continue; /* no actual control created */
+ case CTRL_TABDELAY:
+ continue; /* nothing to do here, move along */
+ }
+
+ c = fe_ctrl_byctrl(d, ctrl);
+
+ ch = 0;
+ ythis = topy;
+
+ for (j = colstart; j < colend; j++) {
+ if (ythis > cypos[j])
+ ythis = cypos[j];
+ }
+
+ xthis = (width + HSPACING) * ccw[colstart] / 100;
+ wthis = (width + HSPACING) * ccw[colend] / 100 - HSPACING - xthis;
+ xthis += leftx;
+
+ switch (ctrl->generic.type) {
+ case CTRL_BUTTON:
+ case CTRL_CHECKBOX:
+ rect = [c->button frame];
+ [c->button setFrame:NSMakeRect(xthis,ythis-rect.size.height,wthis,
+ rect.size.height)];
+ ch = rect.size.height;
+ break;
+ case CTRL_EDITBOX:
+ {
+ int editp = ctrl->editbox.percentwidth;
+ int labelp = editp == 100 ? 100 : 100 - editp;
+ int lheight, theight, rheight, ynext, editw;
+ NSControl *edit = (c->editbox ? c->editbox : c->combobox);
+
+ rect = [c->label frame];
+ lheight = rect.size.height;
+ rect = [edit frame];
+ theight = rect.size.height;
+
+ if (editp == 100)
+ rheight = lheight;
+ else
+ rheight = (lheight < theight ? theight : lheight);
+
+ [c->label setFrame:
+ NSMakeRect(xthis, ythis-(rheight+lheight)/2,
+ (wthis + HSPACING) * labelp / 100 - HSPACING,
+ lheight)];
+ if (editp == 100) {
+ ynext = ythis - rheight - VSPACING;
+ rheight = theight;
+ } else {
+ ynext = ythis;
+ }
+
+ editw = (wthis + HSPACING) * editp / 100 - HSPACING;
+
+ [edit setFrame:
+ NSMakeRect(xthis+wthis-editw, ynext-(rheight+theight)/2,
+ editw, theight)];
+
+ ch = (ythis - ynext) + theight;
+ }
+ break;
+ case CTRL_TEXT:
+ [c->textview setFrame:NSMakeRect(xthis, 0, wthis, 1)];
+ [c->textview sizeToFit];
+ rect = [c->textview frame];
+ [c->textview setFrame:NSMakeRect(xthis, ythis-rect.size.height,
+ wthis, rect.size.height)];
+ ch = rect.size.height;
+ break;
+ case CTRL_RADIO:
+ {
+ int j, ynext;
+
+ if (c->label) {
+ rect = [c->label frame];
+ [c->label setFrame:NSMakeRect(xthis,ythis-rect.size.height,
+ wthis,rect.size.height)];
+ ynext = ythis - rect.size.height - VSPACING;
+ } else
+ ynext = ythis;
+
+ for (j = 0; j < ctrl->radio.nbuttons; j++) {
+ int col = j % ctrl->radio.ncolumns;
+ int ncols;
+ int lx,rx;
+
+ if (j == ctrl->radio.nbuttons - 1)
+ ncols = ctrl->radio.ncolumns - col;
+ else
+ ncols = 1;
+
+ lx = (wthis + HSPACING) * col / ctrl->radio.ncolumns;
+ rx = ((wthis + HSPACING) *
+ (col+ncols) / ctrl->radio.ncolumns) - HSPACING;
+
+ /*
+ * Set the frame size.
+ */
+ rect = [c->radiobuttons[j] frame];
+ [c->radiobuttons[j] setFrame:
+ NSMakeRect(lx+xthis, ynext-rect.size.height,
+ rx-lx, rect.size.height)];
+
+ /*
+ * Advance to next line if we're in the last
+ * column.
+ */
+ if (col + ncols == ctrl->radio.ncolumns)
+ ynext -= rect.size.height + VSPACING;
+ }
+ ch = (ythis - ynext) - VSPACING;
+ }
+ break;
+ case CTRL_FILESELECT:
+ case CTRL_FONTSELECT:
+ {
+ int ynext, eh, bh, th, mx;
+
+ rect = [c->label frame];
+ [c->label setFrame:NSMakeRect(xthis,ythis-rect.size.height,
+ wthis,rect.size.height)];
+ ynext = ythis - rect.size.height - VSPACING;
+
+ rect = [c->editbox frame];
+ eh = rect.size.height;
+ rect = [c->button frame];
+ bh = rect.size.height;
+ th = (eh > bh ? eh : bh);
+
+ mx = (wthis + HSPACING) * 3 / 4 - HSPACING;
+
+ [c->editbox setFrame:
+ NSMakeRect(xthis, ynext-(th+eh)/2, mx, eh)];
+ [c->button setFrame:
+ NSMakeRect(xthis+mx+HSPACING, ynext-(th+bh)/2,
+ wthis-mx-HSPACING, bh)];
+
+ ch = (ythis - ynext) + th + VSPACING;
+ }
+ break;
+ case CTRL_LISTBOX:
+ {
+ int listp = ctrl->listbox.percentwidth;
+ int labelp = listp == 100 ? 100 : 100 - listp;
+ int lheight, theight, rheight, ynext, listw, xlist;
+ NSControl *list = (c->scrollview ? (id)c->scrollview :
+ (id)c->popupbutton);
+
+ if (ctrl->listbox.draglist) {
+ assert(listp == 100);
+ listp = 75;
+ }
+
+ rect = [list frame];
+ theight = rect.size.height;
+
+ if (c->label) {
+ rect = [c->label frame];
+ lheight = rect.size.height;
+
+ if (labelp == 100)
+ rheight = lheight;
+ else
+ rheight = (lheight < theight ? theight : lheight);
+
+ [c->label setFrame:
+ NSMakeRect(xthis, ythis-(rheight+lheight)/2,
+ (wthis + HSPACING) * labelp / 100 - HSPACING,
+ lheight)];
+ if (labelp == 100) {
+ ynext = ythis - rheight - VSPACING;
+ rheight = theight;
+ } else {
+ ynext = ythis;
+ }
+ } else {
+ ynext = ythis;
+ rheight = theight;
+ }
+
+ listw = (wthis + HSPACING) * listp / 100 - HSPACING;
+
+ if (labelp == 100)
+ xlist = xthis;
+ else
+ xlist = xthis+wthis-listw;
+
+ [list setFrame: NSMakeRect(xlist, ynext-(rheight+theight)/2,
+ listw, theight)];
+
+ /*
+ * Size the columns for the table view.
+ */
+ if (c->tableview) {
+ int ncols, *percentages;
+ int hundred = 100;
+ int cpercent = 0, cpixels = 0;
+ NSArray *cols;
+
+ if (ctrl->listbox.ncols) {
+ ncols = ctrl->listbox.ncols;
+ percentages = ctrl->listbox.percentages;
+ } else {
+ ncols = 1;
+ percentages = &hundred;
+ }
+
+ cols = [c->tableview tableColumns];
+
+ for (j = 0; j < ncols; j++) {
+ NSTableColumn *col = [cols objectAtIndex:j];
+ int newcpixels;
+
+ cpercent += percentages[j];
+ newcpixels = listw * cpercent / 100;
+ [col setWidth:newcpixels-cpixels];
+ cpixels = newcpixels;
+ }
+ }
+
+ ch = (ythis - ynext) + theight;
+
+ if (c->button) {
+ int b2height, centre;
+ int bx, bw;
+
+ /*
+ * Place the Up and Down buttons for a drag list.
+ */
+ assert(c->button2);
+
+ rect = [c->button frame];
+ b2height = VSPACING + 2 * rect.size.height;
+
+ centre = ynext - rheight/2;
+
+ bx = (wthis + HSPACING) * 3 / 4;
+ bw = wthis - bx;
+ bx += leftx;
+
+ [c->button setFrame:
+ NSMakeRect(bx, centre+b2height/2-rect.size.height,
+ bw, rect.size.height)];
+ [c->button2 setFrame:
+ NSMakeRect(bx, centre-b2height/2,
+ bw, rect.size.height)];
+ }
+ }
+ break;
+ }
+
+ for (j = colstart; j < colend; j++)
+ cypos[j] = ythis - ch - VSPACING;
+ if (ret < topy - (ythis - ch))
+ ret = topy - (ythis - ch);
+ }
+
+ if (*s->boxname) {
+ NSBox *box = find_box(d, s);
+ assert(box != NULL);
+ [box sizeToFit];
+
+ if (s->boxtitle) {
+ NSRect rect = [box frame];
+ rect.size.height += [[box titleFont] pointSize];
+ [box setFrame:rect];
+ }
+
+ ret += boxh;
+ }
+
+ //printf("For controlset %s/%s, returning ret=%d\n",
+ // s->pathname, s->boxname, ret);
+ return ret;
+}
+
+void select_panel(void *dv, struct controlbox *b, const char *name)
+{
+ struct fe_dlg *d = (struct fe_dlg *)dv;
+ int i, j, hidden;
+ struct controlset *s;
+ union control *ctrl;
+ struct fe_ctrl *c;
+ NSBox *box;
+
+ for (i = 0; i < b->nctrlsets; i++) {
+ s = b->ctrlsets[i];
+
+ if (*s->pathname) {
+ hidden = !strcmp(s->pathname, name) ? NO : YES;
+
+ if ((box = find_box(d, s)) != NULL) {
+ [box setHidden:hidden];
+ } else {
+ for (j = 0; j < s->ncontrols; j++) {
+ ctrl = s->ctrls[j];
+ c = fe_ctrl_byctrl(d, ctrl);
+
+ if (!c)
+ continue;
+
+ if (c->label)
+ [c->label setHidden:hidden];
+ if (c->button)
+ [c->button setHidden:hidden];
+ if (c->button2)
+ [c->button2 setHidden:hidden];
+ if (c->editbox)
+ [c->editbox setHidden:hidden];
+ if (c->combobox)
+ [c->combobox setHidden:hidden];
+ if (c->textview)
+ [c->textview setHidden:hidden];
+ if (c->tableview)
+ [c->tableview setHidden:hidden];
+ if (c->scrollview)
+ [c->scrollview setHidden:hidden];
+ if (c->popupbutton)
+ [c->popupbutton setHidden:hidden];
+ if (c->radiobuttons) {
+ int j;
+ for (j = 0; j < c->nradiobuttons; j++)
+ [c->radiobuttons[j] setHidden:hidden];
+ }
+ break;
+ }
+ }
+ }
+ }
+}
+
+void dlg_radiobutton_set(union control *ctrl, void *dv, int whichbutton)
+{
+ struct fe_dlg *d = (struct fe_dlg *)dv;
+ struct fe_ctrl *c = fe_ctrl_byctrl(d, ctrl);
+ int j;
+
+ assert(c->radiobuttons);
+ for (j = 0; j < c->nradiobuttons; j++)
+ [c->radiobuttons[j] setState:
+ (j == whichbutton ? NSOnState : NSOffState)];
+}
+
+int dlg_radiobutton_get(union control *ctrl, void *dv)
+{
+ struct fe_dlg *d = (struct fe_dlg *)dv;
+ struct fe_ctrl *c = fe_ctrl_byctrl(d, ctrl);
+ int j;
+
+ assert(c->radiobuttons);
+ for (j = 0; j < c->nradiobuttons; j++)
+ if ([c->radiobuttons[j] state] == NSOnState)
+ return j;
+
+ return 0; /* should never reach here */
+}
+
+void dlg_checkbox_set(union control *ctrl, void *dv, int checked)
+{
+ struct fe_dlg *d = (struct fe_dlg *)dv;
+ struct fe_ctrl *c = fe_ctrl_byctrl(d, ctrl);
+
+ assert(c->button);
+ [c->button setState:(checked ? NSOnState : NSOffState)];
+}
+
+int dlg_checkbox_get(union control *ctrl, void *dv)
+{
+ struct fe_dlg *d = (struct fe_dlg *)dv;
+ struct fe_ctrl *c = fe_ctrl_byctrl(d, ctrl);
+
+ assert(c->button);
+ return ([c->button state] == NSOnState);
+}
+
+void dlg_editbox_set(union control *ctrl, void *dv, char const *text)
+{
+ struct fe_dlg *d = (struct fe_dlg *)dv;
+ struct fe_ctrl *c = fe_ctrl_byctrl(d, ctrl);
+
+ if (c->editbox) {
+ [c->editbox setStringValue:[NSString stringWithCString:text]];
+ } else {
+ assert(c->combobox);
+ [c->combobox setStringValue:[NSString stringWithCString:text]];
+ }
+}
+
+void dlg_editbox_get(union control *ctrl, void *dv, char *buffer, int length)
+{
+ struct fe_dlg *d = (struct fe_dlg *)dv;
+ struct fe_ctrl *c = fe_ctrl_byctrl(d, ctrl);
+ NSString *str;
+
+ if (c->editbox) {
+ str = [c->editbox stringValue];
+ } else {
+ assert(c->combobox);
+ str = [c->combobox stringValue];
+ }
+ if (!str)
+ str = @"";
+
+ /* The length parameter to this method doesn't include a trailing NUL */
+ [str getCString:buffer maxLength:length-1];
+}
+
+void dlg_listbox_clear(union control *ctrl, void *dv)
+{
+ struct fe_dlg *d = (struct fe_dlg *)dv;
+ struct fe_ctrl *c = fe_ctrl_byctrl(d, ctrl);
+
+ if (c->tableview) {
+ [[c->tableview dataSource] clear];
+ [c->tableview reloadData];
+ } else {
+ [c->popupbutton removeAllItems];
+ }
+}
+
+void dlg_listbox_del(union control *ctrl, void *dv, int index)
+{
+ struct fe_dlg *d = (struct fe_dlg *)dv;
+ struct fe_ctrl *c = fe_ctrl_byctrl(d, ctrl);
+
+ if (c->tableview) {
+ [[c->tableview dataSource] removestr:index];
+ [c->tableview reloadData];
+ } else {
+ [c->popupbutton removeItemAtIndex:index];
+ }
+}
+
+void dlg_listbox_addwithid(union control *ctrl, void *dv,
+ char const *text, int id)
+{
+ struct fe_dlg *d = (struct fe_dlg *)dv;
+ struct fe_ctrl *c = fe_ctrl_byctrl(d, ctrl);
+
+ if (c->tableview) {
+ [[c->tableview dataSource] add:text withId:id];
+ [c->tableview reloadData];
+ } else {
+ [c->popupbutton addItemWithTitle:[NSString stringWithCString:text]];
+ [[c->popupbutton lastItem] setTag:id];
+ }
+}
+
+void dlg_listbox_add(union control *ctrl, void *dv, char const *text)
+{
+ dlg_listbox_addwithid(ctrl, dv, text, -1);
+}
+
+int dlg_listbox_getid(union control *ctrl, void *dv, int index)
+{
+ struct fe_dlg *d = (struct fe_dlg *)dv;
+ struct fe_ctrl *c = fe_ctrl_byctrl(d, ctrl);
+
+ if (c->tableview) {
+ return [[c->tableview dataSource] getid:index];
+ } else {
+ return [[c->popupbutton itemAtIndex:index] tag];
+ }
+}
+
+int dlg_listbox_index(union control *ctrl, void *dv)
+{
+ struct fe_dlg *d = (struct fe_dlg *)dv;
+ struct fe_ctrl *c = fe_ctrl_byctrl(d, ctrl);
+
+ if (c->tableview) {
+ return [c->tableview selectedRow];
+ } else {
+ return [c->popupbutton indexOfSelectedItem];
+ }
+}
+
+int dlg_listbox_issel(union control *ctrl, void *dv, int index)
+{
+ struct fe_dlg *d = (struct fe_dlg *)dv;
+ struct fe_ctrl *c = fe_ctrl_byctrl(d, ctrl);
+
+ if (c->tableview) {
+ return [c->tableview isRowSelected:index];
+ } else {
+ return [c->popupbutton indexOfSelectedItem] == index;
+ }
+}
+
+void dlg_listbox_select(union control *ctrl, void *dv, int index)
+{
+ struct fe_dlg *d = (struct fe_dlg *)dv;
+ struct fe_ctrl *c = fe_ctrl_byctrl(d, ctrl);
+
+ if (c->tableview) {
+ [c->tableview selectRow:index byExtendingSelection:NO];
+ } else {
+ [c->popupbutton selectItemAtIndex:index];
+ }
+}
+
+void dlg_text_set(union control *ctrl, void *dv, char const *text)
+{
+ struct fe_dlg *d = (struct fe_dlg *)dv;
+ struct fe_ctrl *c = fe_ctrl_byctrl(d, ctrl);
+
+ assert(c->textview);
+ [c->textview setString:[NSString stringWithCString:text]];
+}
+
+void dlg_filesel_set(union control *ctrl, void *dv, Filename fn)
+{
+ /* FIXME */
+}
+
+void dlg_filesel_get(union control *ctrl, void *dv, Filename *fn)
+{
+ /* FIXME */
+}
+
+void dlg_fontsel_set(union control *ctrl, void *dv, FontSpec fn)
+{
+ /* FIXME */
+}
+
+void dlg_fontsel_get(union control *ctrl, void *dv, FontSpec *fn)
+{
+ /* FIXME */
+}
+
+void dlg_update_start(union control *ctrl, void *dv)
+{
+ /* FIXME */
+}
+
+void dlg_update_done(union control *ctrl, void *dv)
+{
+ /* FIXME */
+}
+
+void dlg_set_focus(union control *ctrl, void *dv)
+{
+ /* FIXME */
+}
+
+union control *dlg_last_focused(union control *ctrl, void *dv)
+{
+ return NULL; /* FIXME */
+}
+
+void dlg_beep(void *dv)
+{
+ NSBeep();
+}
+
+void dlg_error_msg(void *dv, char *msg)
+{
+ /* FIXME */
+}
+
+void dlg_end(void *dv, int value)
+{
+ struct fe_dlg *d = (struct fe_dlg *)dv;
+ [d->target performSelector:d->action
+ withObject:[NSNumber numberWithInt:value]];
+}
+
+void dlg_coloursel_start(union control *ctrl, void *dv,
+ int r, int g, int b)
+{
+ /* FIXME */
+}
+
+int dlg_coloursel_results(union control *ctrl, void *dv,
+ int *r, int *g, int *b)
+{
+ return 0; /* FIXME */
+}
+
+void dlg_refresh(union control *ctrl, void *dv)
+{
+ struct fe_dlg *d = (struct fe_dlg *)dv;
+ struct fe_ctrl *c;
+
+ if (ctrl) {
+ if (ctrl->generic.handler != NULL)
+ ctrl->generic.handler(ctrl, d, d->data, EVENT_REFRESH);
+ } else {
+ int i;
+
+ for (i = 0; (c = index234(d->byctrl, i)) != NULL; i++) {
+ assert(c->ctrl != NULL);
+ if (c->ctrl->generic.handler != NULL)
+ c->ctrl->generic.handler(c->ctrl, d,
+ d->data, EVENT_REFRESH);
+ }
+ }
+}
+
+void *dlg_get_privdata(union control *ctrl, void *dv)
+{
+ struct fe_dlg *d = (struct fe_dlg *)dv;
+ struct fe_ctrl *c = fe_ctrl_byctrl(d, ctrl);
+ return c->privdata;
+}
+
+void dlg_set_privdata(union control *ctrl, void *dv, void *ptr)
+{
+ struct fe_dlg *d = (struct fe_dlg *)dv;
+ struct fe_ctrl *c = fe_ctrl_byctrl(d, ctrl);
+ c->privdata = ptr;
+ c->privdata_needs_free = FALSE;
+}
+
+void *dlg_alloc_privdata(union control *ctrl, void *dv, size_t size)
+{
+ struct fe_dlg *d = (struct fe_dlg *)dv;
+ struct fe_ctrl *c = fe_ctrl_byctrl(d, ctrl);
+ /*
+ * This is an internal allocation routine, so it's allowed to
+ * use smalloc directly.
+ */
+ c->privdata = smalloc(size);
+ c->privdata_needs_free = TRUE;
+ return c->privdata;
+}
--- /dev/null
+/*
+ * osxdlg.m: various PuTTY dialog boxes for OS X.
+ */
+
+#import <Cocoa/Cocoa.h>
+#include "putty.h"
+#include "storage.h"
+#include "dialog.h"
+#include "osxclass.h"
+
+/*
+ * The `ConfigWindow' class is used to start up a new PuTTY
+ * session.
+ */
+
+@class ConfigTree;
+@interface ConfigTree : NSObject
+{
+ NSString **paths;
+ int *levels;
+ int nitems, itemsize;
+}
+- (void)addPath:(char *)path;
+@end
+
+@implementation ConfigTree
+- (id)init
+{
+ self = [super init];
+ paths = NULL;
+ levels = NULL;
+ nitems = itemsize = 0;
+ return self;
+}
+- (void)addPath:(char *)path
+{
+ if (nitems >= itemsize) {
+ itemsize += 32;
+ paths = sresize(paths, itemsize, NSString *);
+ levels = sresize(levels, itemsize, int);
+ }
+ paths[nitems] = [[NSString stringWithCString:path] retain];
+ levels[nitems] = ctrl_path_elements(path) - 1;
+ nitems++;
+}
+- (void)dealloc
+{
+ int i;
+
+ for (i = 0; i < nitems; i++)
+ [paths[i] release];
+
+ sfree(paths);
+ sfree(levels);
+
+ [super dealloc];
+}
+- (id)iterateChildren:(int)index ofItem:(id)item count:(int *)count
+{
+ int i, plevel;
+
+ if (item) {
+ for (i = 0; i < nitems; i++)
+ if (paths[i] == item)
+ break;
+ assert(i < nitems);
+ plevel = levels[i];
+ i++;
+ } else {
+ i = 0;
+ plevel = -1;
+ }
+
+ if (count)
+ *count = 0;
+
+ while (index > 0) {
+ if (i >= nitems || levels[i] != plevel+1)
+ return nil;
+ if (count)
+ (*count)++;
+ do {
+ i++;
+ } while (i < nitems && levels[i] > plevel+1);
+ index--;
+ }
+
+ return paths[i];
+}
+- (id)outlineView:(NSOutlineView *)outlineView child:(int)index ofItem:(id)item
+{
+ return [self iterateChildren:index ofItem:item count:NULL];
+}
+- (int)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item
+{
+ int count = 0;
+ /* pass nitems+1 to ensure we run off the end */
+ [self iterateChildren:nitems+1 ofItem:item count:&count];
+ return count;
+}
+- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item
+{
+ return [self outlineView:outlineView numberOfChildrenOfItem:item] > 0;
+}
+- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
+{
+ /*
+ * Trim off all path elements except the last one.
+ */
+ NSArray *components = [item componentsSeparatedByString:@"/"];
+ return [components objectAtIndex:[components count]-1];
+}
+@end
+
+@implementation ConfigWindow
+- (id)initWithConfig:(Config)aCfg
+{
+ NSScrollView *scrollview;
+ NSTableColumn *col;
+ ConfigTree *treedata;
+ int by = 0, mby = 0;
+ int wmin = 0;
+ int hmin = 0;
+ int panelht = 0;
+
+ get_sesslist(&sl, TRUE);
+
+ ctrlbox = ctrl_new_box();
+ setup_config_box(ctrlbox, &sl, FALSE /*midsession*/, aCfg.protocol,
+ 0 /* protcfginfo */);
+ unix_setup_config_box(ctrlbox, FALSE /*midsession*/);
+
+ cfg = aCfg; /* structure copy */
+
+ self = [super initWithContentRect:NSMakeRect(0,0,300,300)
+ styleMask:(NSTitledWindowMask | NSMiniaturizableWindowMask |
+ NSClosableWindowMask)
+ backing:NSBackingStoreBuffered
+ defer:YES];
+ [self setTitle:@"PuTTY Configuration"];
+
+ [self setIgnoresMouseEvents:NO];
+
+ dv = fe_dlg_init(&cfg, self, self, @selector(configBoxFinished:));
+
+ scrollview = [[NSScrollView alloc] initWithFrame:NSMakeRect(20,20,10,10)];
+ treeview = [[NSOutlineView alloc] initWithFrame:[scrollview frame]];
+ [scrollview setBorderType:NSLineBorder];
+ [scrollview setDocumentView:treeview];
+ [[self contentView] addSubview:scrollview];
+ [scrollview setHasVerticalScroller:YES];
+ [scrollview setAutohidesScrollers:YES];
+ /* FIXME: the below is untested. Test it then remove this notice. */
+ [treeview setAllowsColumnReordering:NO];
+ [treeview setAllowsColumnResizing:NO];
+ [treeview setAllowsMultipleSelection:NO];
+ [treeview setAllowsEmptySelection:NO];
+ [treeview setAllowsColumnSelection:YES];
+
+ treedata = [[[ConfigTree alloc] init] retain];
+
+ col = [[NSTableColumn alloc] initWithIdentifier:nil];
+ [treeview addTableColumn:col];
+ [treeview setOutlineTableColumn:col];
+
+ [[treeview headerView] setFrame:NSMakeRect(0,0,0,0)];
+
+ /*
+ * Create the controls.
+ */
+ {
+ int i;
+ char *path = NULL;
+
+ for (i = 0; i < ctrlbox->nctrlsets; i++) {
+ struct controlset *s = ctrlbox->ctrlsets[i];
+ int mw, mh;
+
+ if (!*s->pathname) {
+
+ create_ctrls(dv, [self contentView], s, &mw, &mh);
+
+ by += 20 + mh;
+
+ if (wmin < mw + 40)
+ wmin = mw + 40;
+ } else {
+ int j = path ? ctrl_path_compare(s->pathname, path) : 0;
+
+ if (j != INT_MAX) { /* add to treeview, start new panel */
+ char *c;
+
+ /*
+ * We expect never to find an implicit path
+ * component. For example, we expect never to
+ * see A/B/C followed by A/D/E, because that
+ * would _implicitly_ create A/D. All our path
+ * prefixes are expected to contain actual
+ * controls and be selectable in the treeview;
+ * so we would expect to see A/D _explicitly_
+ * before encountering A/D/E.
+ */
+ assert(j == ctrl_path_elements(s->pathname) - 1);
+
+ c = strrchr(s->pathname, '/');
+ if (!c)
+ c = s->pathname;
+ else
+ c++;
+
+ [treedata addPath:s->pathname];
+ path = s->pathname;
+
+ panelht = 0;
+ }
+
+ create_ctrls(dv, [self contentView], s, &mw, &mh);
+ if (wmin < mw + 3*20+150)
+ wmin = mw + 3*20+150;
+ panelht += mh + 20;
+ if (hmin < panelht - 20)
+ hmin = panelht - 20;
+ }
+ }
+ }
+
+ {
+ int i;
+ NSRect r;
+
+ [treeview setDataSource:treedata];
+ for (i = [treeview numberOfRows]; i-- ;)
+ [treeview expandItem:[treeview itemAtRow:i] expandChildren:YES];
+
+ [treeview sizeToFit];
+ r = [treeview frame];
+ if (hmin < r.size.height)
+ hmin = r.size.height;
+ }
+
+ [self setContentSize:NSMakeSize(wmin, hmin+60+by)];
+ [scrollview setFrame:NSMakeRect(20, 40+by, 150, hmin)];
+ [treeview setDelegate:self];
+ mby = by;
+
+ /*
+ * Now place the controls.
+ */
+ {
+ int i;
+ char *path = NULL;
+ panelht = 0;
+
+ for (i = 0; i < ctrlbox->nctrlsets; i++) {
+ struct controlset *s = ctrlbox->ctrlsets[i];
+
+ if (!*s->pathname) {
+ by -= VSPACING + place_ctrls(dv, s, 20, by, wmin-40);
+ } else {
+ if (!path || strcmp(s->pathname, path))
+ panelht = 0;
+
+ panelht += VSPACING + place_ctrls(dv, s, 2*20+150,
+ 40+mby+hmin-panelht,
+ wmin - (3*20+150));
+
+ path = s->pathname;
+ }
+ }
+ }
+
+ select_panel(dv, ctrlbox, [[treeview itemAtRow:0] cString]);
+
+ [treeview reloadData];
+
+ dlg_refresh(NULL, dv);
+
+ [self center]; /* :-) */
+
+ return self;
+}
+- (void)configBoxFinished:(id)object
+{
+ int ret = [object intValue]; /* it'll be an NSNumber */
+ if (ret) {
+ [controller performSelectorOnMainThread:
+ @selector(newSessionWithConfig:)
+ withObject:[NSData dataWithBytes:&cfg length:sizeof(cfg)]
+ waitUntilDone:NO];
+ }
+ [self close];
+}
+- (void)outlineViewSelectionDidChange:(NSNotification *)notification
+{
+ const char *path = [[treeview itemAtRow:[treeview selectedRow]] cString];
+ select_panel(dv, ctrlbox, path);
+}
+- (BOOL)outlineView:(NSOutlineView *)outlineView
+ shouldEditTableColumn:(NSTableColumn *)tableColumn item:(id)item
+{
+ return NO; /* no editing! */
+}
+@end
+
+/* ----------------------------------------------------------------------
+ * Various special-purpose dialog boxes.
+ */
+
+int askappend(void *frontend, Filename filename)
+{
+ return 0; /* FIXME */
+}
+
+void askalg(void *frontend, const char *algtype, const char *algname)
+{
+ fatalbox("Cipher algorithm dialog box not supported yet");
+ return; /* FIXME */
+}
+
+void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
+ char *keystr, char *fingerprint)
+{
+ int ret;
+
+ /*
+ * Verify the key.
+ */
+ ret = verify_host_key(host, port, keytype, keystr);
+
+ if (ret == 0)
+ return;
+
+ /*
+ * FIXME FIXME FIXME. I currently lack any sensible means of
+ * asking the user for a verification non-application-modally,
+ * _or_ any means of closing just this connection if the answer
+ * is no (the Unix and Windows ports just exit() in this
+ * situation since they're one-connection-per-process).
+ *
+ * What I need to do is to make this function optionally-
+ * asynchronous, much like the interface to agent_query(). It
+ * can either run modally and return a result directly, _or_ it
+ * can kick off a non-modal dialog, return a `please wait'
+ * status, and the dialog can call the backend back when the
+ * result comes in. Also, in either case, the aye/nay result
+ * wants to be passed to the backend so that it can tear down
+ * the connection if the answer was nay.
+ *
+ * For the moment, I simply bomb out if we have an unrecognised
+ * host key. This makes this port safe but not very useful: you
+ * can only use it at all if you already have a host key cache
+ * set up by running the Unix port.
+ */
+ fatalbox("Host key dialog box not supported yet");
+}
+
+void old_keyfile_warning(void)
+{
+ /*
+ * This should never happen on OS X. We hope.
+ */
+}
+
+void about_box(void *window)
+{
+ /* FIXME */
+}
--- /dev/null
+/*
+ * osxmain.m: main-program file of Mac OS X PuTTY.
+ */
+
+#import <Cocoa/Cocoa.h>
+
+#define PUTTY_DO_GLOBALS /* actually _define_ globals */
+
+#include "putty.h"
+#include "osxclass.h"
+
+/* ----------------------------------------------------------------------
+ * Global variables.
+ */
+
+AppController *controller;
+
+/* ----------------------------------------------------------------------
+ * Miscellaneous elements of the interface to the cross-platform
+ * and Unix PuTTY code.
+ */
+
+const char platform_x11_best_transport[] = "unix";
+
+char *platform_get_x_display(void) {
+ return NULL;
+}
+
+FontSpec platform_default_fontspec(const char *name)
+{
+ FontSpec ret;
+ /* FIXME */
+ return ret;
+}
+
+Filename platform_default_filename(const char *name)
+{
+ Filename ret;
+ if (!strcmp(name, "LogFileName"))
+ strcpy(ret.path, "putty.log");
+ else
+ *ret.path = '\0';
+ return ret;
+}
+
+char *platform_default_s(const char *name)
+{
+ return NULL;
+}
+
+int platform_default_i(const char *name, int def)
+{
+ if (!strcmp(name, "CloseOnExit"))
+ return 2; /* maps to FORCE_ON after painful rearrangement :-( */
+ return def;
+}
+
+char *x_get_default(const char *key)
+{
+ return NULL; /* this is a stub */
+}
+
+void modalfatalbox(char *p, ...)
+{
+ /* FIXME: proper OS X GUI stuff */
+ va_list ap;
+ fprintf(stderr, "FATAL ERROR: ");
+ va_start(ap, p);
+ vfprintf(stderr, p, ap);
+ va_end(ap);
+ fputc('\n', stderr);
+ exit(1);
+}
+
+void fatalbox(char *p, ...)
+{
+ /* FIXME: proper OS X GUI stuff */
+ va_list ap;
+ fprintf(stderr, "FATAL ERROR: ");
+ va_start(ap, p);
+ vfprintf(stderr, p, ap);
+ va_end(ap);
+ fputc('\n', stderr);
+ exit(1);
+}
+
+void cmdline_error(char *p, ...)
+{
+ va_list ap;
+ fprintf(stderr, "%s: ", appname);
+ va_start(ap, p);
+ vfprintf(stderr, p, ap);
+ va_end(ap);
+ fputc('\n', stderr);
+ exit(1);
+}
+
+/*
+ * Clean up and exit.
+ */
+void cleanup_exit(int code)
+{
+ /*
+ * Clean up.
+ */
+ sk_cleanup();
+ random_save_seed();
+ exit(code);
+}
+
+/* ----------------------------------------------------------------------
+ * Tiny extension to NSMenuItem which carries a payload of a `void
+ * *', allowing several menu items to invoke the same message but
+ * pass different data through it.
+ */
+@interface DataMenuItem : NSMenuItem
+{
+ void *payload;
+}
+- (void)setPayload:(void *)d;
+- (void *)getPayload;
+@end
+@implementation DataMenuItem
+- (void)setPayload:(void *)d
+{
+ payload = d;
+}
+- (void *)getPayload
+{
+ return payload;
+}
+@end
+
+/* ----------------------------------------------------------------------
+ * Utility routines for constructing OS X menus.
+ */
+
+NSMenu *newmenu(const char *title)
+{
+ return [[[NSMenu allocWithZone:[NSMenu menuZone]]
+ initWithTitle:[NSString stringWithCString:title]]
+ autorelease];
+}
+
+NSMenu *newsubmenu(NSMenu *parent, const char *title)
+{
+ NSMenuItem *item;
+ NSMenu *child;
+
+ item = [[[NSMenuItem allocWithZone:[NSMenu menuZone]]
+ initWithTitle:[NSString stringWithCString:title]
+ action:NULL
+ keyEquivalent:@""]
+ autorelease];
+ child = newmenu(title);
+ [item setEnabled:YES];
+ [item setSubmenu:child];
+ [parent addItem:item];
+ return child;
+}
+
+id initnewitem(NSMenuItem *item, NSMenu *parent, const char *title,
+ const char *key, id target, SEL action)
+{
+ unsigned mask = NSCommandKeyMask;
+
+ if (key[strcspn(key, "-")]) {
+ while (*key && *key != '-') {
+ int c = tolower((unsigned char)*key);
+ if (c == 's') {
+ mask |= NSShiftKeyMask;
+ } else if (c == 'o' || c == 'a') {
+ mask |= NSAlternateKeyMask;
+ }
+ key++;
+ }
+ if (*key)
+ key++;
+ }
+
+ item = [[item initWithTitle:[NSString stringWithCString:title]
+ action:NULL
+ keyEquivalent:[NSString stringWithCString:key]]
+ autorelease];
+
+ if (*key)
+ [item setKeyEquivalentModifierMask: mask];
+
+ [item setEnabled:YES];
+ [item setTarget:target];
+ [item setAction:action];
+
+ [parent addItem:item];
+
+ return item;
+}
+
+NSMenuItem *newitem(NSMenu *parent, char *title, char *key,
+ id target, SEL action)
+{
+ return initnewitem([NSMenuItem allocWithZone:[NSMenu menuZone]],
+ parent, title, key, target, action);
+}
+
+/* ----------------------------------------------------------------------
+ * AppController: the object which receives the messages from all
+ * menu selections that aren't standard OS X functions.
+ */
+@implementation AppController
+
+- (id)init
+{
+ self = [super init];
+ timer = NULL;
+ return self;
+}
+
+- (void)newTerminal:(id)sender
+{
+ id win;
+ Config cfg;
+
+ do_defaults(NULL, &cfg);
+
+ cfg.protocol = -1; /* PROT_TERMINAL */
+
+ win = [[SessionWindow alloc] initWithConfig:cfg];
+ [win makeKeyAndOrderFront:self];
+}
+
+- (void)newSessionConfig:(id)sender
+{
+ id win;
+ Config cfg;
+
+ do_defaults(NULL, &cfg);
+
+ win = [[ConfigWindow alloc] initWithConfig:cfg];
+ [win makeKeyAndOrderFront:self];
+}
+
+- (void)newSessionWithConfig:(id)vdata
+{
+ id win;
+ Config cfg;
+ NSData *data = (NSData *)vdata;
+
+ assert([data length] == sizeof(cfg));
+ [data getBytes:&cfg];
+
+ win = [[SessionWindow alloc] initWithConfig:cfg];
+ [win makeKeyAndOrderFront:self];
+}
+
+- (NSMenu *)applicationDockMenu:(NSApplication *)sender
+{
+ NSMenu *menu = newmenu("Dock Menu");
+ /*
+ * FIXME: Add some useful things to this, probably including
+ * the saved session list.
+ */
+ return menu;
+}
+
+- (void)timerFired:(id)sender
+{
+ long now, next;
+
+ assert(sender == timer);
+
+ /* `sender' is the timer itself, so its userInfo is an NSNumber. */
+ now = [(NSNumber *)[sender userInfo] longValue];
+
+ [sender invalidate];
+
+ timer = NULL;
+
+ if (run_timers(now, &next))
+ [self setTimer:next];
+}
+
+- (void)setTimer:(long)next
+{
+ long interval = next - GETTICKCOUNT();
+ float finterval;
+
+ if (interval <= 0)
+ interval = 1; /* just in case */
+
+ finterval = interval / (float)TICKSPERSEC;
+
+ if (timer) {
+ [timer invalidate];
+ }
+
+ timer = [NSTimer scheduledTimerWithTimeInterval:finterval
+ target:self selector:@selector(timerFired:)
+ userInfo:[NSNumber numberWithLong:next] repeats:NO];
+}
+
+@end
+
+void timer_change_notify(long next)
+{
+ [controller setTimer:next];
+}
+
+/* ----------------------------------------------------------------------
+ * Annoyingly, it looks as if I have to actually subclass
+ * NSApplication if I want to catch NSApplicationDefined events. So
+ * here goes.
+ */
+@interface MyApplication : NSApplication
+{
+}
+@end
+@implementation MyApplication
+- (void)sendEvent:(NSEvent *)ev
+{
+ if ([ev type] == NSApplicationDefined)
+ osxsel_process_results();
+
+ [super sendEvent:ev];
+}
+@end
+
+/* ----------------------------------------------------------------------
+ * Main program. Constructs the menus and runs the application.
+ */
+int main(int argc, char **argv)
+{
+ NSAutoreleasePool *pool;
+ NSMenu *menu;
+ NSMenuItem *item;
+ NSImage *icon;
+
+ pool = [[NSAutoreleasePool alloc] init];
+
+ icon = [NSImage imageNamed:@"NSApplicationIcon"];
+ [MyApplication sharedApplication];
+ [NSApp setApplicationIconImage:icon];
+
+ controller = [[[AppController alloc] init] autorelease];
+ [NSApp setDelegate:controller];
+
+ [NSApp setMainMenu: newmenu("Main Menu")];
+
+ menu = newsubmenu([NSApp mainMenu], "Apple Menu");
+ [NSApp setServicesMenu:newsubmenu(menu, "Services")];
+ [menu addItem:[NSMenuItem separatorItem]];
+ item = newitem(menu, "Hide PuTTY", "h", NSApp, @selector(hide:));
+ item = newitem(menu, "Hide Others", "o-h", NSApp, @selector(hideOtherApplications:));
+ item = newitem(menu, "Show All", "", NSApp, @selector(unhideAllApplications:));
+ [menu addItem:[NSMenuItem separatorItem]];
+ item = newitem(menu, "Quit", "q", NSApp, @selector(terminate:));
+ [NSApp setAppleMenu: menu];
+
+ menu = newsubmenu([NSApp mainMenu], "File");
+ item = newitem(menu, "New", "n", NULL, @selector(newSessionConfig:));
+ item = newitem(menu, "New Terminal", "t", NULL, @selector(newTerminal:));
+ item = newitem(menu, "Close", "w", NULL, @selector(performClose:));
+
+ menu = newsubmenu([NSApp mainMenu], "Window");
+ [NSApp setWindowsMenu: menu];
+ item = newitem(menu, "Minimise Window", "m", NULL, @selector(performMiniaturize:));
+
+// menu = newsubmenu([NSApp mainMenu], "Help");
+// item = newitem(menu, "PuTTY Help", "?", NSApp, @selector(showHelp:));
+
+ /*
+ * Start up the sub-thread doing select().
+ */
+ osxsel_init();
+
+ /*
+ * Start up networking.
+ */
+ sk_init();
+
+ /*
+ * FIXME: To make initial debugging more convenient I'm going
+ * to start by opening a session window unconditionally. This
+ * will probably change later on.
+ */
+ [controller newSessionConfig:nil];
+
+ [NSApp run];
+ [pool release];
+
+ return 0;
+}
--- /dev/null
+/*
+ * osxsel.m: OS X implementation of the front end interface to uxsel.
+ */
+
+#import <Cocoa/Cocoa.h>
+#include <unistd.h>
+#include "putty.h"
+#include "osxclass.h"
+
+/*
+ * The unofficial Cocoa FAQ at
+ *
+ * http://www.alastairs-place.net/cocoa/faq.txt
+ *
+ * says that Cocoa has the native ability to be given an fd and
+ * tell you when it becomes readable, but cannot tell you when it
+ * becomes _writable_. This is unacceptable to PuTTY, which depends
+ * for correct functioning on being told both. Therefore, I can't
+ * use the Cocoa native mechanism.
+ *
+ * Instead, I'm going to resort to threads. I start a second thread
+ * whose job is to do selects. At the termination of every select,
+ * it posts a Cocoa event into the main thread's event queue, so
+ * that the main thread gets select results interleaved with other
+ * GUI operations. Communication from the main thread _to_ the
+ * select thread is performed by writing to a pipe whose other end
+ * is one of the file descriptors being selected on. (This is the
+ * only sensible way, because we have to be able to interrupt a
+ * select in order to provide a new fd list.)
+ */
+
+/*
+ * In more detail, the select thread must:
+ *
+ * - start off by listening to _just_ the pipe, waiting to be told
+ * to begin a select.
+ *
+ * - when it receives the `start' command, it should read the
+ * shared uxsel data (which is protected by a mutex), set up its
+ * select, and begin it.
+ *
+ * - when the select terminates, it should write the results
+ * (perhaps minus the inter-thread pipe if it's there) into
+ * shared memory and dispatch a GUI event to let the main thread
+ * know.
+ *
+ * - the main thread will then think about it, do some processing,
+ * and _then_ send a command saying `now restart select'. Before
+ * sending that command it might easily have tinkered with the
+ * uxsel structures, which is why it waited before sending it.
+ *
+ * - EOF on the inter-thread pipe, of course, means the process
+ * has finished completely, so the select thread terminates.
+ *
+ * - The main thread may wish to adjust the uxsel settings in the
+ * middle of a select. In this situation it first writes the new
+ * data to the shared memory area, then notifies the select
+ * thread by writing to the inter-thread pipe.
+ *
+ * So the upshot is that the sequence of operations performed in
+ * the select thread must be:
+ *
+ * - read a byte from the pipe (which may block)
+ *
+ * - read the shared uxsel data and perform a select
+ *
+ * - notify the main thread of interesting select results (if any)
+ *
+ * - loop round again from the top.
+ *
+ * This is sufficient. Notifying the select thread asynchronously
+ * by writing to the pipe will cause its select to terminate and
+ * another to begin immediately without blocking. If the select
+ * thread's select terminates due to network data, its subsequent
+ * pipe read will block until the main thread is ready to let it
+ * loose again.
+ */
+
+static int osxsel_pipe[2];
+
+static NSLock *osxsel_inlock;
+static fd_set osxsel_rfds_in;
+static fd_set osxsel_wfds_in;
+static fd_set osxsel_xfds_in;
+static int osxsel_inmax;
+
+static NSLock *osxsel_outlock;
+static fd_set osxsel_rfds_out;
+static fd_set osxsel_wfds_out;
+static fd_set osxsel_xfds_out;
+static int osxsel_outmax;
+
+static int inhibit_start_select;
+
+/*
+ * NSThread requires an object method as its thread procedure, so
+ * here I define a trivial holding class.
+ */
+@class OSXSel;
+@interface OSXSel : NSObject
+{
+}
+- (void)runThread:(id)arg;
+@end
+@implementation OSXSel
+- (void)runThread:(id)arg
+{
+ char c;
+ fd_set r, w, x;
+ int n, ret;
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ while (1) {
+ /*
+ * Read one byte from the pipe.
+ */
+ ret = read(osxsel_pipe[0], &c, 1);
+
+ if (ret <= 0)
+ return; /* terminate the thread */
+
+ /*
+ * Now set up the select data.
+ */
+ [osxsel_inlock lock];
+ memcpy(&r, &osxsel_rfds_in, sizeof(fd_set));
+ memcpy(&w, &osxsel_wfds_in, sizeof(fd_set));
+ memcpy(&x, &osxsel_xfds_in, sizeof(fd_set));
+ n = osxsel_inmax;
+ [osxsel_inlock unlock];
+ FD_SET(osxsel_pipe[0], &r);
+ if (n < osxsel_pipe[0]+1)
+ n = osxsel_pipe[0]+1;
+
+ /*
+ * Perform the select.
+ */
+ ret = select(n, &r, &w, &x, NULL);
+
+ /*
+ * Detect the one special case in which the only
+ * interesting fd was the inter-thread pipe. In that
+ * situation only we are interested - the main thread will
+ * not be!
+ */
+ if (ret == 1 && FD_ISSET(osxsel_pipe[0], &r))
+ continue; /* just loop round again */
+
+ /*
+ * Write the select results to shared data.
+ *
+ * I _think_ we don't need this data to be lock-protected:
+ * it won't be read by the main thread until after we send
+ * a message indicating that we've finished writing it, and
+ * we won't start another select (hence potentially writing
+ * it again) until the main thread notifies us in return.
+ *
+ * However, I'm scared of multithreading and not totally
+ * convinced of my reasoning, so I'm going to lock it
+ * anyway.
+ */
+ [osxsel_outlock lock];
+ memcpy(&osxsel_rfds_out, &r, sizeof(fd_set));
+ memcpy(&osxsel_wfds_out, &w, sizeof(fd_set));
+ memcpy(&osxsel_xfds_out, &x, sizeof(fd_set));
+ osxsel_outmax = n;
+ [osxsel_outlock unlock];
+
+ /*
+ * Post a message to the main thread's message queue
+ * telling it that select data is available.
+ */
+ [NSApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined
+ location:NSMakePoint(0,0)
+ modifierFlags:0
+ timestamp:0
+ windowNumber:0
+ context:nil
+ subtype:0
+ data1:0
+ data2:0]
+ atStart:NO];
+ }
+
+ [pool release];
+}
+@end
+
+void osxsel_init(void)
+{
+ uxsel_init();
+
+ if (pipe(osxsel_pipe) < 0) {
+ fatalbox("Unable to set up inter-thread pipe for select");
+ }
+ [NSThread detachNewThreadSelector:@selector(runThread:)
+ toTarget:[[[OSXSel alloc] init] retain] withObject:nil];
+ /*
+ * Also initialise (i.e. clear) the input fd_sets. Need not
+ * start a select just yet - the select thread will block until
+ * we have at least one fd for it!
+ */
+ FD_ZERO(&osxsel_rfds_in);
+ FD_ZERO(&osxsel_wfds_in);
+ FD_ZERO(&osxsel_xfds_in);
+ osxsel_inmax = 0;
+ /*
+ * Initialise the mutex locks used to protect the data passed
+ * between threads.
+ */
+ osxsel_inlock = [[[NSLock alloc] init] retain];
+ osxsel_outlock = [[[NSLock alloc] init] retain];
+}
+
+static void osxsel_start_select(void)
+{
+ char c = 'g'; /* for `Go!' :-) but it's never used */
+
+ if (!inhibit_start_select)
+ write(osxsel_pipe[1], &c, 1);
+}
+
+int uxsel_input_add(int fd, int rwx)
+{
+ /*
+ * Add the new fd to the appropriate input fd_sets, then write
+ * to the inter-thread pipe.
+ */
+ [osxsel_inlock lock];
+ if (rwx & 1)
+ FD_SET(fd, &osxsel_rfds_in);
+ else
+ FD_CLR(fd, &osxsel_rfds_in);
+ if (rwx & 2)
+ FD_SET(fd, &osxsel_wfds_in);
+ else
+ FD_CLR(fd, &osxsel_wfds_in);
+ if (rwx & 4)
+ FD_SET(fd, &osxsel_xfds_in);
+ else
+ FD_CLR(fd, &osxsel_xfds_in);
+ if (osxsel_inmax < fd+1)
+ osxsel_inmax = fd+1;
+ [osxsel_inlock unlock];
+ osxsel_start_select();
+
+ /*
+ * We must return an `id' which will be passed back to us at
+ * the time of uxsel_input_remove. Since we have no need to
+ * store ids in that sense, we might as well go with the fd
+ * itself.
+ */
+ return fd;
+}
+
+void uxsel_input_remove(int id)
+{
+ /*
+ * Remove the fd from all the input fd_sets. In this
+ * implementation, the simplest way to do that is to call
+ * uxsel_input_add with rwx==0!
+ */
+ uxsel_input_add(id, 0);
+}
+
+/*
+ * Function called in the main thread to process results. It will
+ * have to read the output fd_sets, go through them, call back to
+ * uxsel with the results, and then write to the inter-thread pipe.
+ *
+ * This function will have to be called from an event handler in
+ * osxmain.m, which will therefore necessarily contain a small part
+ * of this mechanism (along with calling osxsel_init).
+ */
+void osxsel_process_results(void)
+{
+ int i;
+
+ /*
+ * We must write to the pipe to start a fresh select _even if_
+ * there were no changes. So for efficiency, we set a flag here
+ * which inhibits uxsel_input_{add,remove} from writing to the
+ * pipe; then once we finish processing, we clear the flag
+ * again and write a single byte ourselves. It's cleaner,
+ * because it wakes up the select thread fewer times.
+ */
+ inhibit_start_select = TRUE;
+
+ [osxsel_outlock lock];
+
+ for (i = 0; i < osxsel_outmax; i++) {
+ if (FD_ISSET(i, &osxsel_xfds_out))
+ select_result(i, 4);
+ }
+ for (i = 0; i < osxsel_outmax; i++) {
+ if (FD_ISSET(i, &osxsel_rfds_out))
+ select_result(i, 1);
+ }
+ for (i = 0; i < osxsel_outmax; i++) {
+ if (FD_ISSET(i, &osxsel_wfds_out))
+ select_result(i, 2);
+ }
+
+ [osxsel_outlock unlock];
+
+ inhibit_start_select = FALSE;
+ osxsel_start_select();
+}
--- /dev/null
+/*
+ * osxwin.m: code to manage a session window in Mac OS X PuTTY.
+ */
+
+#import <Cocoa/Cocoa.h>
+#include "putty.h"
+#include "terminal.h"
+#include "osxclass.h"
+
+/* Colours come in two flavours: configurable, and xterm-extended. */
+#define NCFGCOLOURS (lenof(((Config *)0)->colours))
+#define NEXTCOLOURS 240 /* 216 colour-cube plus 24 shades of grey */
+#define NALLCOLOURS (NCFGCOLOURS + NEXTCOLOURS)
+
+/*
+ * The key component of the per-session data is the SessionWindow
+ * class. A pointer to this is used as the frontend handle, to be
+ * passed to all the platform-independent subsystems that require
+ * one.
+ */
+
+@interface TerminalView : NSImageView
+{
+ NSFont *font;
+ NSImage *image;
+ Terminal *term;
+ Config cfg;
+ NSColor *colours[NALLCOLOURS];
+ float fw, fasc, fdesc, fh;
+}
+- (void)drawStartFinish:(BOOL)start;
+- (void)setColour:(int)n r:(float)r g:(float)g b:(float)b;
+- (void)doText:(wchar_t *)text len:(int)len x:(int)x y:(int)y
+ attr:(unsigned long)attr lattr:(int)lattr;
+@end
+
+@implementation TerminalView
+- (BOOL)isFlipped
+{
+ return YES;
+}
+- (id)initWithTerminal:(Terminal *)aTerm config:(Config)aCfg
+{
+ float w, h;
+
+ self = [self initWithFrame:NSMakeRect(0,0,100,100)];
+
+ term = aTerm;
+ cfg = aCfg;
+
+ /*
+ * Initialise the fonts we're going to use.
+ *
+ * FIXME: for the moment I'm sticking with exactly one default font.
+ */
+ font = [NSFont userFixedPitchFontOfSize:0];
+
+ /*
+ * Now determine the size of the primary font.
+ *
+ * FIXME: If we have multiple fonts, we may need to set fasc
+ * and fdesc to the _maximum_ asc and desc out of all the
+ * fonts, _before_ adding them together to get fh.
+ */
+ fw = [font widthOfString:@"A"];
+ fasc = [font ascender];
+ fdesc = -[font descender];
+ fh = fasc + fdesc;
+ fh = (int)fh + (fh > (int)fh); /* round up, ickily */
+
+ /*
+ * Use this to figure out the size of the terminal view.
+ */
+ w = fw * term->cols;
+ h = fh * term->rows;
+
+ /*
+ * And set our size and subimage.
+ */
+ image = [[NSImage alloc] initWithSize:NSMakeSize(w,h)];
+ [image setFlipped:YES];
+ [self setImage:image];
+ [self setFrame:NSMakeRect(0,0,w,h)];
+
+ term_invalidate(term);
+
+ return self;
+}
+- (void)drawStartFinish:(BOOL)start
+{
+ if (start)
+ [image lockFocus];
+ else
+ [image unlockFocus];
+}
+- (void)doText:(wchar_t *)text len:(int)len x:(int)x y:(int)y
+ attr:(unsigned long)attr lattr:(int)lattr
+{
+ int nfg, nbg, rlen, widefactor;
+ float ox, oy, tw, th;
+ NSDictionary *attrdict;
+
+ /* FIXME: TATTR_COMBINING */
+
+ nfg = ((attr & ATTR_FGMASK) >> ATTR_FGSHIFT);
+ nbg = ((attr & ATTR_BGMASK) >> ATTR_BGSHIFT);
+ if (attr & ATTR_REVERSE) {
+ int t = nfg;
+ nfg = nbg;
+ nbg = t;
+ }
+ if (cfg.bold_colour && (attr & ATTR_BOLD)) {
+ if (nfg < 16) nfg |= 8;
+ else if (nfg >= 256) nfg |= 1;
+ }
+ if (cfg.bold_colour && (attr & ATTR_BLINK)) {
+ if (nbg < 16) nbg |= 8;
+ else if (nbg >= 256) nbg |= 1;
+ }
+ if (attr & TATTR_ACTCURS) {
+ nfg = 260;
+ nbg = 261;
+ }
+
+ if (attr & ATTR_WIDE) {
+ widefactor = 2;
+ /* FIXME: what do we actually have to do about wide characters? */
+ } else {
+ widefactor = 1;
+ }
+
+ /* FIXME: ATTR_BOLD without cfg.bold_colour */
+
+ if ((lattr & LATTR_MODE) != LATTR_NORM) {
+ x *= 2;
+ if (x >= term->cols)
+ return;
+ if (x + len*2*widefactor > term->cols)
+ len = (term->cols-x)/2/widefactor;/* trim to LH half */
+ rlen = len * 2;
+ } else
+ rlen = len;
+
+ /* FIXME: how do we actually implement double-{width,height} lattrs? */
+
+ ox = x * fw;
+ oy = y * fh;
+ tw = rlen * widefactor * fw;
+ th = fh;
+
+ /*
+ * Set the clipping rectangle.
+ */
+ [[NSGraphicsContext currentContext] saveGraphicsState];
+ [NSBezierPath clipRect:NSMakeRect(ox, oy, tw, th)];
+
+ attrdict = [NSDictionary dictionaryWithObjectsAndKeys:
+ colours[nfg], NSForegroundColorAttributeName,
+ colours[nbg], NSBackgroundColorAttributeName,
+ font, NSFontAttributeName, nil];
+
+ /*
+ * Create an NSString and draw it.
+ *
+ * Annoyingly, although our input is wchar_t which is four
+ * bytes wide on OS X and terminal.c supports 32-bit Unicode,
+ * we must convert into the two-byte type `unichar' to store in
+ * NSString, so we lose display capability for extra-BMP stuff
+ * at this point.
+ */
+ {
+ NSString *string;
+ unichar *utext;
+ int i;
+
+ utext = snewn(len, unichar);
+ for (i = 0; i < len; i++)
+ utext[i] = (text[i] >= 0x10000 ? 0xFFFD : text[i]);
+
+ string = [NSString stringWithCharacters:utext length:len];
+ [string drawAtPoint:NSMakePoint(ox, oy) withAttributes:attrdict];
+
+ sfree(utext);
+ }
+
+ /*
+ * Restore the graphics state from before the clipRect: call.
+ */
+ [[NSGraphicsContext currentContext] restoreGraphicsState];
+
+ /*
+ * And flag this area as needing display.
+ */
+ [self setNeedsDisplayInRect:NSMakeRect(ox, oy, tw, th)];
+}
+
+- (void)setColour:(int)n r:(float)r g:(float)g b:(float)b
+{
+ assert(n >= 0 && n < lenof(colours));
+ colours[n] = [[NSColor colorWithDeviceRed:r green:g blue:b alpha:1.0]
+ retain];
+}
+@end
+
+@implementation SessionWindow
+- (id)initWithConfig:(Config)aCfg
+{
+ NSRect rect = { {0,0}, {0,0} };
+
+ cfg = aCfg; /* structure copy */
+
+ init_ucs(&ucsdata, cfg.line_codepage, cfg.utf8_override,
+ CS_UTF8, cfg.vtmode);
+ term = term_init(&cfg, &ucsdata, self);
+ logctx = log_init(self, &cfg);
+ term_provide_logctx(term, logctx);
+ term_size(term, cfg.height, cfg.width, cfg.savelines);
+
+ termview = [[[TerminalView alloc] initWithTerminal:term config:cfg]
+ autorelease];
+
+ /*
+ * Now work out the size of the window.
+ */
+ rect = [termview frame];
+ rect.origin = NSMakePoint(0,0);
+ rect.size.width += 2 * cfg.window_border;
+ rect.size.height += 2 * cfg.window_border;
+
+ /*
+ * Set up a backend.
+ */
+ {
+ int i;
+ back = &pty_backend;
+ for (i = 0; backends[i].backend != NULL; i++)
+ if (backends[i].protocol == cfg.protocol) {
+ back = backends[i].backend;
+ break;
+ }
+ }
+
+ {
+ const char *error;
+ char *realhost = NULL;
+ error = back->init(self, &backhandle, &cfg, cfg.host, cfg.port,
+ &realhost, cfg.tcp_nodelay, cfg.tcp_keepalives);
+ if (error) {
+ fatalbox("%s\n", error); /* FIXME: connection_fatal at worst */
+ }
+
+ if (realhost)
+ sfree(realhost); /* FIXME: do something with this */
+ }
+
+ /*
+ * Create a line discipline. (This must be done after creating
+ * the terminal _and_ the backend, since it needs to be passed
+ * pointers to both.)
+ */
+ ldisc = ldisc_create(&cfg, term, back, backhandle, self);
+
+ /*
+ * FIXME: Set up a scrollbar.
+ */
+
+ self = [super initWithContentRect:rect
+ styleMask:(NSTitledWindowMask | NSMiniaturizableWindowMask |
+ NSClosableWindowMask)
+ backing:NSBackingStoreBuffered
+ defer:YES];
+ [self setTitle:@"PuTTY"];
+
+ [self setIgnoresMouseEvents:NO];
+
+ /*
+ * Put the terminal view in the window.
+ */
+ rect = [termview frame];
+ rect.origin = NSMakePoint(cfg.window_border, cfg.window_border);
+ [termview setFrame:rect];
+ [[self contentView] addSubview:termview];
+
+ /*
+ * Set up the colour palette.
+ */
+ palette_reset(self);
+
+ /*
+ * FIXME: Only the _first_ document window should be centred.
+ * The subsequent ones should appear down and to the right of
+ * it, probably using the cascade function provided by Cocoa.
+ * Also we're apparently required by the HIG to remember and
+ * reuse previous positions of windows, although I'm not sure
+ * how that works if the user opens more than one of the same
+ * session type.
+ */
+ [self center]; /* :-) */
+
+ return self;
+}
+
+- (void)dealloc
+{
+ /*
+ * FIXME: Here we must deallocate all sorts of stuff: the
+ * terminal, the backend, the ldisc, the logctx, you name it.
+ * Do so.
+ */
+ [super dealloc];
+}
+
+- (void)drawStartFinish:(BOOL)start
+{
+ [termview drawStartFinish:start];
+}
+
+- (void)setColour:(int)n r:(float)r g:(float)g b:(float)b
+{
+ [termview setColour:n r:r g:g b:b];
+}
+
+- (void)doText:(wchar_t *)text len:(int)len x:(int)x y:(int)y
+ attr:(unsigned long)attr lattr:(int)lattr
+{
+ /* Pass this straight on to the TerminalView. */
+ [termview doText:text len:len x:x y:y attr:attr lattr:lattr];
+}
+
+- (Config *)cfg
+{
+ return &cfg;
+}
+
+- (void)keyDown:(NSEvent *)ev
+{
+ NSString *s = [ev characters];
+ int i;
+ int n = [s length], c = [s characterAtIndex:0], m = [ev modifierFlags];
+ int cm = [[ev charactersIgnoringModifiers] characterAtIndex:0];
+ wchar_t output[32];
+ char coutput[32];
+ int use_coutput = FALSE, special = FALSE, start, end;
+
+printf("n=%d c=U+%04x cm=U+%04x m=%08x\n", n, c, cm, m);
+
+ /*
+ * FIXME: Alt+numberpad codes.
+ */
+
+ /*
+ * Shift and Ctrl with PageUp/PageDown for scrollback.
+ */
+ if (n == 1 && c == NSPageUpFunctionKey && (m & NSShiftKeyMask)) {
+ term_scroll(term, 0, -term->rows/2);
+ return;
+ }
+ if (n == 1 && c == NSPageUpFunctionKey && (m & NSControlKeyMask)) {
+ term_scroll(term, 0, -1);
+ return;
+ }
+ if (n == 1 && c == NSPageDownFunctionKey && (m & NSShiftKeyMask)) {
+ term_scroll(term, 0, +term->rows/2);
+ return;
+ }
+ if (n == 1 && c == NSPageDownFunctionKey && (m & NSControlKeyMask)) {
+ term_scroll(term, 0, +1);
+ return;
+ }
+
+ /*
+ * FIXME: Shift-Ins for paste? Or is that not Maccy enough?
+ */
+
+ /*
+ * FIXME: Alt (Option? Command?) prefix in general.
+ *
+ * (Note that Alt-Shift-thing will work just by looking at
+ * charactersIgnoringModifiers; but Alt-Ctrl-thing will need
+ * processing properly, and Alt-as-in-Option won't happen at
+ * all. Hmmm.)
+ *
+ * (Note also that we need to be able to override menu key
+ * equivalents before this is particularly useful.)
+ */
+ start = 1;
+ end = start;
+
+ /*
+ * Ctrl-` is the same as Ctrl-\, unless we already have a
+ * better idea.
+ */
+ if ((m & NSControlKeyMask) && n == 1 && cm == '`' && c == '`') {
+ output[1] = '\x1c';
+ end = 2;
+ }
+
+ /* We handle Return ourselves, because it needs to be flagged as
+ * special to ldisc. */
+ if (n == 1 && c == '\015') {
+ coutput[1] = '\015';
+ use_coutput = TRUE;
+ end = 2;
+ special = TRUE;
+ }
+
+ /* Control-Shift-Space is 160 (ISO8859 nonbreaking space) */
+ if (n == 1 && (m & NSControlKeyMask) && (m & NSShiftKeyMask) &&
+ cm == ' ') {
+ output[1] = '\240';
+ end = 2;
+ }
+
+ /* Control-2, Control-Space and Control-@ are all NUL. */
+ if ((m & NSControlKeyMask) && n == 1 &&
+ (cm == '2' || cm == '@' || cm == ' ') && c == cm) {
+ output[1] = '\0';
+ end = 2;
+ }
+
+ /* We don't let MacOS tell us what Backspace is! We know better. */
+ if (cm == 0x7F && !(m & NSShiftKeyMask)) {
+ coutput[1] = cfg.bksp_is_delete ? '\x7F' : '\x08';
+ end = 2;
+ use_coutput = special = TRUE;
+ }
+ /* For Shift Backspace, do opposite of what is configured. */
+ if (cm == 0x7F && (m & NSShiftKeyMask)) {
+ coutput[1] = cfg.bksp_is_delete ? '\x08' : '\x7F';
+ end = 2;
+ use_coutput = special = TRUE;
+ }
+
+ /* Shift-Tab is ESC [ Z. Oddly, this combination generates ^Y by
+ * default on MacOS! */
+ if (cm == 0x19 && (m & NSShiftKeyMask) && !(m & NSControlKeyMask)) {
+ end = 1;
+ output[end++] = '\033';
+ output[end++] = '[';
+ output[end++] = 'Z';
+ }
+
+ /*
+ * NetHack keypad mode.
+ */
+ if (cfg.nethack_keypad && (m & NSNumericPadKeyMask)) {
+ wchar_t *keys = NULL;
+ switch (cm) {
+ case '1': keys = L"bB"; break;
+ case '2': keys = L"jJ"; break;
+ case '3': keys = L"nN"; break;
+ case '4': keys = L"hH"; break;
+ case '5': keys = L".."; break;
+ case '6': keys = L"lL"; break;
+ case '7': keys = L"yY"; break;
+ case '8': keys = L"kK"; break;
+ case '9': keys = L"uU"; break;
+ }
+ if (keys) {
+ end = 2;
+ if (m & NSShiftKeyMask)
+ output[1] = keys[1];
+ else
+ output[1] = keys[0];
+ goto done;
+ }
+ }
+
+ /*
+ * Application keypad mode.
+ */
+ if (term->app_keypad_keys && !cfg.no_applic_k &&
+ (m & NSNumericPadKeyMask)) {
+ int xkey = 0;
+ switch (cm) {
+ case NSClearLineFunctionKey: xkey = 'P'; break;
+ case '=': xkey = 'Q'; break;
+ case '/': xkey = 'R'; break;
+ case '*': xkey = 'S'; break;
+ /*
+ * FIXME: keypad - and + need to be mapped to ESC O l
+ * and ESC O k, or ESC O l and ESC O m, depending on
+ * xterm function key mode, and I can't remember which
+ * goes where.
+ */
+ case '\003': xkey = 'M'; break;
+ case '0': xkey = 'p'; break;
+ case '1': xkey = 'q'; break;
+ case '2': xkey = 'r'; break;
+ case '3': xkey = 's'; break;
+ case '4': xkey = 't'; break;
+ case '5': xkey = 'u'; break;
+ case '6': xkey = 'v'; break;
+ case '7': xkey = 'w'; break;
+ case '8': xkey = 'x'; break;
+ case '9': xkey = 'y'; break;
+ case '.': xkey = 'n'; break;
+ }
+ if (xkey) {
+ if (term->vt52_mode) {
+ if (xkey >= 'P' && xkey <= 'S') {
+ output[end++] = '\033';
+ output[end++] = xkey;
+ } else {
+ output[end++] = '\033';
+ output[end++] = '?';
+ output[end++] = xkey;
+ }
+ } else {
+ output[end++] = '\033';
+ output[end++] = 'O';
+ output[end++] = xkey;
+ }
+ goto done;
+ }
+ }
+
+ /*
+ * Next, all the keys that do tilde codes. (ESC '[' nn '~',
+ * for integer decimal nn.)
+ *
+ * We also deal with the weird ones here. Linux VCs replace F1
+ * to F5 by ESC [ [ A to ESC [ [ E. rxvt doesn't do _that_, but
+ * does replace Home and End (1~ and 4~) by ESC [ H and ESC O w
+ * respectively.
+ */
+ {
+ int code = 0;
+ switch (cm) {
+ case NSF1FunctionKey:
+ code = (m & NSShiftKeyMask ? 23 : 11);
+ break;
+ case NSF2FunctionKey:
+ code = (m & NSShiftKeyMask ? 24 : 12);
+ break;
+ case NSF3FunctionKey:
+ code = (m & NSShiftKeyMask ? 25 : 13);
+ break;
+ case NSF4FunctionKey:
+ code = (m & NSShiftKeyMask ? 26 : 14);
+ break;
+ case NSF5FunctionKey:
+ code = (m & NSShiftKeyMask ? 28 : 15);
+ break;
+ case NSF6FunctionKey:
+ code = (m & NSShiftKeyMask ? 29 : 17);
+ break;
+ case NSF7FunctionKey:
+ code = (m & NSShiftKeyMask ? 31 : 18);
+ break;
+ case NSF8FunctionKey:
+ code = (m & NSShiftKeyMask ? 32 : 19);
+ break;
+ case NSF9FunctionKey:
+ code = (m & NSShiftKeyMask ? 33 : 20);
+ break;
+ case NSF10FunctionKey:
+ code = (m & NSShiftKeyMask ? 34 : 21);
+ break;
+ case NSF11FunctionKey:
+ code = 23;
+ break;
+ case NSF12FunctionKey:
+ code = 24;
+ break;
+ case NSF13FunctionKey:
+ code = 25;
+ break;
+ case NSF14FunctionKey:
+ code = 26;
+ break;
+ case NSF15FunctionKey:
+ code = 28;
+ break;
+ case NSF16FunctionKey:
+ code = 29;
+ break;
+ case NSF17FunctionKey:
+ code = 31;
+ break;
+ case NSF18FunctionKey:
+ code = 32;
+ break;
+ case NSF19FunctionKey:
+ code = 33;
+ break;
+ case NSF20FunctionKey:
+ code = 34;
+ break;
+ }
+ if (!(m & NSControlKeyMask)) switch (cm) {
+ case NSHomeFunctionKey:
+ code = 1;
+ break;
+#ifdef FIXME
+ case GDK_Insert: case GDK_KP_Insert:
+ code = 2;
+ break;
+#endif
+ case NSDeleteFunctionKey:
+ code = 3;
+ break;
+ case NSEndFunctionKey:
+ code = 4;
+ break;
+ case NSPageUpFunctionKey:
+ code = 5;
+ break;
+ case NSPageDownFunctionKey:
+ code = 6;
+ break;
+ }
+ /* Reorder edit keys to physical order */
+ if (cfg.funky_type == FUNKY_VT400 && code <= 6)
+ code = "\0\2\1\4\5\3\6"[code];
+
+ if (term->vt52_mode && code > 0 && code <= 6) {
+ output[end++] = '\033';
+ output[end++] = " HLMEIG"[code];
+ goto done;
+ }
+
+ if (cfg.funky_type == FUNKY_SCO && /* SCO function keys */
+ code >= 11 && code <= 34) {
+ char codes[] = "MNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@[\\]^_`{";
+ int index = 0;
+ switch (cm) {
+ case NSF1FunctionKey: index = 0; break;
+ case NSF2FunctionKey: index = 1; break;
+ case NSF3FunctionKey: index = 2; break;
+ case NSF4FunctionKey: index = 3; break;
+ case NSF5FunctionKey: index = 4; break;
+ case NSF6FunctionKey: index = 5; break;
+ case NSF7FunctionKey: index = 6; break;
+ case NSF8FunctionKey: index = 7; break;
+ case NSF9FunctionKey: index = 8; break;
+ case NSF10FunctionKey: index = 9; break;
+ case NSF11FunctionKey: index = 10; break;
+ case NSF12FunctionKey: index = 11; break;
+ }
+ if (m & NSShiftKeyMask) index += 12;
+ if (m & NSControlKeyMask) index += 24;
+ output[end++] = '\033';
+ output[end++] = '[';
+ output[end++] = codes[index];
+ goto done;
+ }
+ if (cfg.funky_type == FUNKY_SCO && /* SCO small keypad */
+ code >= 1 && code <= 6) {
+ char codes[] = "HL.FIG";
+ if (code == 3) {
+ output[1] = '\x7F';
+ end = 2;
+ } else {
+ output[end++] = '\033';
+ output[end++] = '[';
+ output[end++] = codes[code-1];
+ }
+ goto done;
+ }
+ if ((term->vt52_mode || cfg.funky_type == FUNKY_VT100P) &&
+ code >= 11 && code <= 24) {
+ int offt = 0;
+ if (code > 15)
+ offt++;
+ if (code > 21)
+ offt++;
+ if (term->vt52_mode) {
+ output[end++] = '\033';
+ output[end++] = code + 'P' - 11 - offt;
+ } else {
+ output[end++] = '\033';
+ output[end++] = 'O';
+ output[end++] = code + 'P' - 11 - offt;
+ }
+ goto done;
+ }
+ if (cfg.funky_type == FUNKY_LINUX && code >= 11 && code <= 15) {
+ output[end++] = '\033';
+ output[end++] = '[';
+ output[end++] = '[';
+ output[end++] = code + 'A' - 11;
+ goto done;
+ }
+ if (cfg.funky_type == FUNKY_XTERM && code >= 11 && code <= 14) {
+ if (term->vt52_mode) {
+ output[end++] = '\033';
+ output[end++] = code + 'P' - 11;
+ } else {
+ output[end++] = '\033';
+ output[end++] = 'O';
+ output[end++] = code + 'P' - 11;
+ }
+ goto done;
+ }
+ if (cfg.rxvt_homeend && (code == 1 || code == 4)) {
+ if (code == 1) {
+ output[end++] = '\033';
+ output[end++] = '[';
+ output[end++] = 'H';
+ } else {
+ output[end++] = '\033';
+ output[end++] = 'O';
+ output[end++] = 'w';
+ }
+ goto done;
+ }
+ if (code) {
+ char buf[20];
+ sprintf(buf, "\x1B[%d~", code);
+ for (i = 0; buf[i]; i++)
+ output[end++] = buf[i];
+ goto done;
+ }
+ }
+
+ /*
+ * Cursor keys. (This includes the numberpad cursor keys,
+ * if we haven't already done them due to app keypad mode.)
+ */
+ {
+ int xkey = 0;
+ switch (cm) {
+ case NSUpArrowFunctionKey: xkey = 'A'; break;
+ case NSDownArrowFunctionKey: xkey = 'B'; break;
+ case NSRightArrowFunctionKey: xkey = 'C'; break;
+ case NSLeftArrowFunctionKey: xkey = 'D'; break;
+ }
+ if (xkey) {
+ /*
+ * The arrow keys normally do ESC [ A and so on. In
+ * app cursor keys mode they do ESC O A instead.
+ * Ctrl toggles the two modes.
+ */
+ if (term->vt52_mode) {
+ output[end++] = '\033';
+ output[end++] = xkey;
+ } else if (!term->app_cursor_keys ^ !(m & NSControlKeyMask)) {
+ output[end++] = '\033';
+ output[end++] = 'O';
+ output[end++] = xkey;
+ } else {
+ output[end++] = '\033';
+ output[end++] = '[';
+ output[end++] = xkey;
+ }
+ goto done;
+ }
+ }
+
+ done:
+
+ /*
+ * Failing everything else, send the exact Unicode we got from
+ * OS X.
+ */
+ if (end == start) {
+ if (n > lenof(output)-start)
+ n = lenof(output)-start; /* _shouldn't_ happen! */
+ for (i = 0; i < n; i++) {
+ output[i+start] = [s characterAtIndex:i];
+ }
+ end = n+start;
+ }
+
+ if (use_coutput) {
+ assert(special);
+ assert(end < lenof(coutput));
+ coutput[end] = '\0';
+ ldisc_send(ldisc, coutput+start, -2, TRUE);
+ } else {
+ luni_send(ldisc, output+start, end-start, TRUE);
+ }
+}
+
+- (int)fromBackend:(const char *)data len:(int)len isStderr:(int)is_stderr
+{
+ return term_data(term, is_stderr, data, len);
+}
+
+@end
+
+int from_backend(void *frontend, int is_stderr, const char *data, int len)
+{
+ SessionWindow *win = (SessionWindow *)frontend;
+ return [win fromBackend:data len:len isStderr:is_stderr];
+}
+
+void frontend_keypress(void *handle)
+{
+ /* FIXME */
+}
+
+void connection_fatal(void *frontend, char *p, ...)
+{
+ //SessionWindow *win = (SessionWindow *)frontend;
+ /* FIXME: proper OS X GUI stuff */
+ va_list ap;
+ fprintf(stderr, "FATAL ERROR: ");
+ va_start(ap, p);
+ vfprintf(stderr, p, ap);
+ va_end(ap);
+ fputc('\n', stderr);
+ exit(1);
+}
+
+void notify_remote_exit(void *frontend)
+{
+ //SessionWindow *win = (SessionWindow *)frontend;
+ /* FIXME */
+}
+
+void ldisc_update(void *frontend, int echo, int edit)
+{
+ //SessionWindow *win = (SessionWindow *)frontend;
+ /*
+ * In a GUI front end, this need do nothing.
+ */
+}
+
+void update_specials_menu(void *frontend)
+{
+ //SessionWindow *win = (SessionWindow *)frontend;
+ /* FIXME */
+}
+
+/*
+ * This is still called when mode==BELL_VISUAL, even though the
+ * visual bell is handled entirely within terminal.c, because we
+ * may want to perform additional actions on any kind of bell (for
+ * example, taskbar flashing in Windows).
+ */
+void beep(void *frontend, int mode)
+{
+ //SessionWindow *win = (SessionWindow *)frontend;
+ if (mode != BELL_VISUAL)
+ NSBeep();
+}
+
+int char_width(Context ctx, int uc)
+{
+ /*
+ * Under X, any fixed-width font really _is_ fixed-width.
+ * Double-width characters will be dealt with using a separate
+ * font. For the moment we can simply return 1.
+ */
+ return 1;
+}
+
+void palette_set(void *frontend, int n, int r, int g, int b)
+{
+ SessionWindow *win = (SessionWindow *)frontend;
+
+ if (n >= 16)
+ n += 256 - 16;
+ if (n > NALLCOLOURS)
+ return;
+ [win setColour:n r:r/255.0 g:g/255.0 b:b/255.0];
+
+ /*
+ * FIXME: do we need an OS X equivalent of set_window_background?
+ */
+}
+
+void palette_reset(void *frontend)
+{
+ SessionWindow *win = (SessionWindow *)frontend;
+ Config *cfg = [win cfg];
+
+ /* This maps colour indices in cfg to those used in colours[]. */
+ static const int ww[] = {
+ 256, 257, 258, 259, 260, 261,
+ 0, 8, 1, 9, 2, 10, 3, 11,
+ 4, 12, 5, 13, 6, 14, 7, 15
+ };
+
+ int i;
+
+ for (i = 0; i < NCFGCOLOURS; i++) {
+ [win setColour:ww[i] r:cfg->colours[i][0]/255.0
+ g:cfg->colours[i][1]/255.0 b:cfg->colours[i][2]/255.0];
+ }
+
+ for (i = 0; i < NEXTCOLOURS; i++) {
+ if (i < 216) {
+ int r = i / 36, g = (i / 6) % 6, b = i % 6;
+ [win setColour:i+16 r:r/5.0 g:g/5.0 b:b/5.0];
+ } else {
+ int shade = i - 216;
+ float fshade = (shade + 1) / (float)(NEXTCOLOURS - 216 + 1);
+ [win setColour:i+16 r:fshade g:fshade b:fshade];
+ }
+ }
+
+ /*
+ * FIXME: do we need an OS X equivalent of set_window_background?
+ */
+}
+
+Context get_ctx(void *frontend)
+{
+ SessionWindow *win = (SessionWindow *)frontend;
+
+ /*
+ * Lock the drawing focus on the image inside the TerminalView.
+ */
+ [win drawStartFinish:YES];
+
+ [[NSGraphicsContext currentContext] setShouldAntialias:YES];
+
+ /*
+ * Cocoa drawing functions don't take a graphics context: that
+ * parameter is implicit. Therefore, we'll use the frontend
+ * handle itself as the context, on the grounds that it's as
+ * good a thing to use as any.
+ */
+ return frontend;
+}
+
+void free_ctx(Context ctx)
+{
+ SessionWindow *win = (SessionWindow *)ctx;
+
+ [win drawStartFinish:NO];
+}
+
+void do_text(Context ctx, int x, int y, wchar_t *text, int len,
+ unsigned long attr, int lattr)
+{
+ SessionWindow *win = (SessionWindow *)ctx;
+
+ [win doText:text len:len x:x y:y attr:attr lattr:lattr];
+}
+
+void do_cursor(Context ctx, int x, int y, wchar_t *text, int len,
+ unsigned long attr, int lattr)
+{
+ SessionWindow *win = (SessionWindow *)ctx;
+ Config *cfg = [win cfg];
+ int active, passive;
+
+ if (attr & TATTR_PASCURS) {
+ attr &= ~TATTR_PASCURS;
+ passive = 1;
+ } else
+ passive = 0;
+ if ((attr & TATTR_ACTCURS) && cfg->cursor_type != 0) {
+ attr &= ~TATTR_ACTCURS;
+ active = 1;
+ } else
+ active = 0;
+
+ [win doText:text len:len x:x y:y attr:attr lattr:lattr];
+
+ /*
+ * FIXME: now draw the various cursor types (both passive and
+ * active underlines and vertical lines, plus passive blocks).
+ */
+}
+
+/*
+ * Minimise or restore the window in response to a server-side
+ * request.
+ */
+void set_iconic(void *frontend, int iconic)
+{
+ //SessionWindow *win = (SessionWindow *)frontend;
+ /* FIXME */
+}
+
+/*
+ * Move the window in response to a server-side request.
+ */
+void move_window(void *frontend, int x, int y)
+{
+ //SessionWindow *win = (SessionWindow *)frontend;
+ /* FIXME */
+}
+
+/*
+ * Move the window to the top or bottom of the z-order in response
+ * to a server-side request.
+ */
+void set_zorder(void *frontend, int top)
+{
+ //SessionWindow *win = (SessionWindow *)frontend;
+ /* FIXME */
+}
+
+/*
+ * Refresh the window in response to a server-side request.
+ */
+void refresh_window(void *frontend)
+{
+ //SessionWindow *win = (SessionWindow *)frontend;
+ /* FIXME */
+}
+
+/*
+ * Maximise or restore the window in response to a server-side
+ * request.
+ */
+void set_zoomed(void *frontend, int zoomed)
+{
+ //SessionWindow *win = (SessionWindow *)frontend;
+ /* FIXME */
+}
+
+/*
+ * Report whether the window is iconic, for terminal reports.
+ */
+int is_iconic(void *frontend)
+{
+ //SessionWindow *win = (SessionWindow *)frontend;
+ return NO; /* FIXME */
+}
+
+/*
+ * Report the window's position, for terminal reports.
+ */
+void get_window_pos(void *frontend, int *x, int *y)
+{
+ //SessionWindow *win = (SessionWindow *)frontend;
+ /* FIXME */
+}
+
+/*
+ * Report the window's pixel size, for terminal reports.
+ */
+void get_window_pixels(void *frontend, int *x, int *y)
+{
+ //SessionWindow *win = (SessionWindow *)frontend;
+ /* FIXME */
+}
+
+/*
+ * Return the window or icon title.
+ */
+char *get_window_title(void *frontend, int icon)
+{
+ //SessionWindow *win = (SessionWindow *)frontend;
+ return NULL; /* FIXME */
+}
+
+void set_title(void *frontend, char *title)
+{
+ //SessionWindow *win = (SessionWindow *)frontend;
+ /* FIXME */
+}
+
+void set_icon(void *frontend, char *title)
+{
+ //SessionWindow *win = (SessionWindow *)frontend;
+ /* FIXME */
+}
+
+void set_sbar(void *frontend, int total, int start, int page)
+{
+ //SessionWindow *win = (SessionWindow *)frontend;
+ /* FIXME */
+}
+
+void get_clip(void *frontend, wchar_t ** p, int *len)
+{
+ //SessionWindow *win = (SessionWindow *)frontend;
+ /* FIXME */
+}
+
+void write_clip(void *frontend, wchar_t * data, int len, int must_deselect)
+{
+ //SessionWindow *win = (SessionWindow *)frontend;
+ /* FIXME */
+}
+
+void request_paste(void *frontend)
+{
+ //SessionWindow *win = (SessionWindow *)frontend;
+ /* FIXME */
+}
+
+void set_raw_mouse_mode(void *frontend, int activate)
+{
+ //SessionWindow *win = (SessionWindow *)frontend;
+ /* FIXME */
+}
+
+void request_resize(void *frontend, int w, int h)
+{
+ //SessionWindow *win = (SessionWindow *)frontend;
+ /* FIXME */
+}
+
+void sys_cursor(void *frontend, int x, int y)
+{
+ //SessionWindow *win = (SessionWindow *)frontend;
+ /*
+ * This is probably meaningless under OS X. FIXME: find out for
+ * sure.
+ */
+}
+
+void logevent(void *frontend, const char *string)
+{
+ //SessionWindow *win = (SessionWindow *)frontend;
+ /* FIXME */
+printf("logevent: %s\n", string);
+}
+
+int font_dimension(void *frontend, int which)/* 0 for width, 1 for height */
+{
+ //SessionWindow *win = (SessionWindow *)frontend;
+ return 1; /* FIXME */
+}
+
+void set_busy_status(void *frontend, int status)
+{
+ /*
+ * We need do nothing here: the OS X `application is busy'
+ * beachball pointer appears _automatically_ when the
+ * application isn't responding to GUI messages.
+ */
+}
if ($groups{$i}) {
foreach $j (@{$groups{$i}}) { unshift @objs, $j; }
} elsif (($i eq "[G]" or $i eq "[C]" or $i eq "[M]" or
- $i eq "[X]" or $i eq "[U]") and defined $prog) {
- $type = substr($i,1,1);
+ $i eq "[X]" or $i eq "[U]" or $i eq "[MX]") and defined $prog) {
+ $type = substr($i,1,(length $i)-2);
} else {
push @$listref, $i;
}
sort @{$programs{$i}};
$programs{$i} = [@list];
foreach $j (@list) {
- # Dependencies for "x" start with "x.c".
+ # Dependencies for "x" start with "x.c" or "x.m" (depending on
+ # which one exists).
# Dependencies for "x.res" start with "x.rc".
# Dependencies for "x.rsrc" start with "x.r".
# Both types of file are pushed on the list of files to scan.
$file = "$1.r";
$depends{$j} = [$file];
push @scanlist, $file;
- } elsif ($j =~ /\.lib$/) {
- # libraries don't have dependencies
- } else {
+ } elsif ($j !~ /\./) {
$file = "$j.c";
+ $file = "$j.m" unless &findfile($file);
$depends{$j} = [$file];
push @scanlist, $file;
}
# Returns true if the argument is a known makefile type. Otherwise,
# prints a warning and returns false;
if (grep { $type eq $_ }
- ("vc","vcproj","cygwin","borland","lcc","gtk","mpw")) {
+ ("vc","vcproj","cygwin","borland","lcc","gtk","mpw","osx")) {
return 1;
}
warn "$.:unknown makefile type '$type'\n";
sub findfile {
my ($name) = @_;
- my $dir, $i, $outdir = "";
+ my $dir;
+ my $i;
+ my $outdir = undef;
unless (defined $findfilecache{$name}) {
$i = 0;
foreach $dir (@srcdirs) {
$outdir=~s/^\.\///;
}
die "multiple instances of source file $name\n" if $i > 1;
- $findfilecache{$name} = $outdir . $name;
+ $findfilecache{$name} = (defined $outdir ? $outdir . $name : undef);
}
return $findfilecache{$name};
}
} elsif ($i =~ /^(.*)\.lib/) {
$y = $1;
($x = $ltmpl) =~ s/X/$y/;
- } else {
+ } elsif ($i !~ /\./) {
($x = $otmpl) =~ s/X/$i/;
}
push @ret, $x if $x ne "";
return join " ", @ret;
}
+sub special {
+ my ($prog, $suffix) = @_;
+ my @ret;
+ my ($i, $x, $y);
+ @ret = ();
+ foreach $i (@{$programs{$prog}}) {
+ if (substr($i, (length $i) - (length $suffix)) eq $suffix) {
+ push @ret, $i;
+ }
+ }
+ return (scalar @ret) ? (join " ", @ret) : undef;
+}
+
sub splitline {
my ($line, $width, $splitchar) = @_;
my ($result, $len);
@ret = ();
foreach $n (@prognames) {
($prog, $type) = split ",", $n;
- push @ret, $n if index($types, $type) >= 0;
+ push @ret, $n if index(":$types:", ":$type:") >= 0;
}
return @ret;
}
@ret = ();
foreach $n (@prognames) {
($prog, $type) = split ",", $n;
- push @ret, $prog if index($types, $type) >= 0;
+ push @ret, $prog if index(":$types:", ":$type:") >= 0;
}
return @ret;
}
my ($types,$suffix) = @_;
# assume that all UNIX programs have a man page
- if($suffix eq "1" && $types =~ /X/) {
+ if($suffix eq "1" && $types =~ /:X:/) {
return map("$_.1", &progrealnames($types));
}
return ();
"\n".
".SUFFIXES:\n".
"\n";
- print &splitline("all:" . join "", map { " $_.exe" } &progrealnames("GC"));
+ print &splitline("all:" . join "", map { " $_.exe" } &progrealnames("G:C"));
print "\n\n";
- foreach $p (&prognames("GC")) {
+ foreach $p (&prognames("G:C")) {
($prog, $type) = split ",", $p;
$objstr = &objects($p, "X.o", "X.res.o", undef);
print &splitline($prog . ".exe: " . $objstr), "\n";
&splitline("\tbrcc32 \$(RCFL) -i \$(BCB)\\include -r".
" -DNO_WINRESRC_H -DWIN32 -D_WIN32 -DWINVER=0x0401 \$*.rc",69)."\n".
"\n";
- print &splitline("all:" . join "", map { " $_.exe" } &progrealnames("GC"));
+ print &splitline("all:" . join "", map { " $_.exe" } &progrealnames("G:C"));
print "\n\n";
- foreach $p (&prognames("GC")) {
+ foreach $p (&prognames("G:C")) {
($prog, $type) = split ",", $p;
$objstr = &objects($p, "X.obj", "X.res", undef);
print &splitline("$prog.exe: " . $objstr . " $prog.rsp"), "\n";
my $ap = ($type eq "G") ? "-aa" : "-ap";
print "\tilink32 $ap -Gn -L\$(BCB)\\lib \@$prog.rsp\n\n";
}
- foreach $p (&prognames("GC")) {
+ foreach $p (&prognames("G:C")) {
($prog, $type) = split ",", $p;
print $prog, ".rsp: \$(MAKEFILE)\n";
$objstr = &objects($p, "X.obj", undef, undef);
"LFLAGS = /incremental:no /fixed\n".
"\n".
"\n";
- print &splitline("all:" . join "", map { " $_.exe" } &progrealnames("GC"));
+ print &splitline("all:" . join "", map { " $_.exe" } &progrealnames("G:C"));
print "\n\n";
- foreach $p (&prognames("GC")) {
+ foreach $p (&prognames("G:C")) {
($prog, $type) = split ",", $p;
$objstr = &objects($p, "X.obj", "X.res", undef);
print &splitline("$prog.exe: " . $objstr . " $prog.rsp"), "\n";
print "\tlink \$(LFLAGS) -out:$prog.exe -map:$prog.map \@$prog.rsp\n\n";
}
- foreach $p (&prognames("GC")) {
+ foreach $p (&prognames("G:C")) {
($prog, $type) = split ",", $p;
print $prog, ".rsp: \$(MAKEFILE)\n";
$objstr = &objects($p, "X.obj", "X.res", "X.lib");
%all_object_deps = map {$_->{obj} => $_->{deps}} @deps;
# Create the project files
# Get names of all Windows projects (GUI and console)
- my @prognames = &prognames("GC");
+ my @prognames = &prognames("G:C");
foreach $progname (@prognames) {
create_project(\%all_object_deps, $progname);
}
".SUFFIXES:\n".
"\n".
"\n";
- print &splitline("all:" . join "", map { " $_" } &progrealnames("XU"));
+ print &splitline("all:" . join "", map { " $_" } &progrealnames("X:U"));
print "\n\n";
- foreach $p (&prognames("XU")) {
+ foreach $p (&prognames("X:U")) {
($prog, $type) = split ",", $p;
$objstr = &objects($p, "X.o", undef, undef);
print &splitline($prog . ": " . $objstr), "\n";
print "\n";
print $makefile_extra{'gtk'};
print "\nclean:\n".
- "\trm -f *.o". (join "", map { " $_" } &progrealnames("XU")) . "\n";
+ "\trm -f *.o". (join "", map { " $_" } &progrealnames("X:U")) . "\n";
select STDOUT; close OUT;
}
"\n".
"# Get include directory for resource compiler\n".
"\n";
- print &splitline("all:" . join "", map { " $_.exe" } &progrealnames("GC"));
+ print &splitline("all:" . join "", map { " $_.exe" } &progrealnames("G:C"));
print "\n\n";
- foreach $p (&prognames("GC")) {
+ foreach $p (&prognames("G:C")) {
($prog, $type) = split ",", $p;
$objstr = &objects($p, "X.obj", "X.res", undef);
print &splitline("$prog.exe: " . $objstr ), "\n";
select STDOUT; close OUT;
}
+
+if (defined $makefiles{'osx'}) {
+ $dirpfx = &dirpfx($makefiles{'osx'}, "/");
+
+ ##-- Mac OS X makefile
+ open OUT, ">$makefiles{'osx'}"; select OUT;
+ print
+ "# Makefile for $project_name under Mac OS X.\n".
+ "#\n# This file was created by `mkfiles.pl' from the `Recipe' file.\n".
+ "# DO NOT EDIT THIS FILE DIRECTLY; edit Recipe or mkfiles.pl instead.\n";
+ # gcc command line option is -D not /D
+ ($_ = $help) =~ s/=\/D/=-D/gs;
+ print $_;
+ print
+ "CC = \$(TOOLPATH)gcc\n".
+ "\n".
+ &splitline("CFLAGS = -O2 -Wall -Werror -g " .
+ (join " ", map {"-I$dirpfx$_"} @srcdirs))."\n".
+ "MLDFLAGS = -framework Cocoa\n".
+ "ULDFLAGS =\n".
+ &splitline("all:" . join "", map { " $_" } &progrealnames("MX:U")) .
+ "\n" .
+ $makefile_extra{'osx'} .
+ "\n";
+ foreach $p (&prognames("MX")) {
+ ($prog, $type) = split ",", $p;
+ $objstr = &objects($p, "X.o", undef, undef);
+ $icon = &special($p, ".icns");
+ $infoplist = &special($p, "info.plist");
+ print "${prog}.app:\n\tmkdir -p \$\@\n";
+ print "${prog}.app/Contents: ${prog}.app\n\tmkdir -p \$\@\n";
+ print "${prog}.app/Contents/MacOS: ${prog}.app/Contents\n\tmkdir -p \$\@\n";
+ $targets = "${prog}.app/Contents/MacOS/$prog";
+ if (defined $icon) {
+ print "${prog}.app/Contents/Resources: ${prog}.app/Contents\n\tmkdir -p \$\@\n";
+ print "${prog}.app/Contents/Resources/${prog}.icns: ${prog}.app/Contents/Resources $icon\n\tcp $icon \$\@\n";
+ $targets .= " ${prog}.app/Contents/Resources/${prog}.icns";
+ }
+ if (defined $infoplist) {
+ print "${prog}.app/Contents/Info.plist: ${prog}.app/Contents/Resources $infoplist\n\tcp $infoplist \$\@\n";
+ $targets .= " ${prog}.app/Contents/Info.plist";
+ }
+ $targets .= " \$(${prog}_extra)";
+ print &splitline("${prog}: $targets", 69) . "\n\n";
+ print &splitline("${prog}.app/Contents/MacOS/$prog: ".
+ "${prog}.app/Contents/MacOS " . $objstr), "\n";
+ $libstr = &objects($p, undef, undef, "-lX");
+ print &splitline("\t\$(CC)" . $mw . " \$(MLDFLAGS) -o \$@ " .
+ $objstr . " $libstr", 69), "\n\n";
+ }
+ foreach $p (&prognames("U")) {
+ ($prog, $type) = split ",", $p;
+ $objstr = &objects($p, "X.o", undef, undef);
+ print &splitline($prog . ": " . $objstr), "\n";
+ $libstr = &objects($p, undef, undef, "-lX");
+ print &splitline("\t\$(CC)" . $mw . " \$(ULDFLAGS) -o \$@ " .
+ $objstr . " $libstr", 69), "\n\n";
+ }
+ foreach $d (&deps("X.o", undef, $dirpfx, "/")) {
+ print &splitline(sprintf("%s: %s", $d->{obj}, join " ", @{$d->{deps}})),
+ "\n";
+ $firstdep = $d->{deps}->[0];
+ if ($firstdep =~ /\.c$/) {
+ print "\t\$(CC) \$(COMPAT) \$(FWHACK) \$(XFLAGS) \$(CFLAGS) -c \$<\n";
+ } elsif ($firstdep =~ /\.m$/) {
+ print "\t\$(CC) -x objective-c \$(COMPAT) \$(FWHACK) \$(XFLAGS) \$(CFLAGS) -c \$<\n";
+ }
+ }
+ print "\nclean:\n".
+ "\trm -f *.o *.dmg\n".
+ "\trm -rf *.app\n";
+ select STDOUT; close OUT;
+}
#include "macstuff.h"
+#elif defined(MACOSX)
+
+#include "osx.h"
+
#else
#include "unix.h"