diff --git a/LaunchAPPL/Client/Serial.cc b/LaunchAPPL/Client/Serial.cc
index 22c5c0656e..c705b16b13 100644
--- a/LaunchAPPL/Client/Serial.cc
+++ b/LaunchAPPL/Client/Serial.cc
@@ -149,7 +149,7 @@ bool SerialLauncher::Go(int timeout)
read(&tmp, 4);
tmp = ntohl(tmp);
- return false;
+ return true;
}
diff --git a/LaunchAPPL/Server/CMakeLists.txt b/LaunchAPPL/Server/CMakeLists.txt
index 6203a0fd2a..aa6236b4f8 100644
--- a/LaunchAPPL/Server/CMakeLists.txt
+++ b/LaunchAPPL/Server/CMakeLists.txt
@@ -1,6 +1,8 @@
-add_application(LaunchAPPLServer CONSOLE
- main.cc
+add_application(LaunchAPPLServer
+ LaunchAPPLServer.r
+ LaunchAPPLServer.cc
MacSerialStream.h
MacSerialStream.cc)
target_link_libraries(LaunchAPPLServer LaunchAPPLCommon)
+set_target_properties(LaunchAPPLServer PROPERTIES LINK_FLAGS "-Wl,-gc-sections")
diff --git a/LaunchAPPL/Server/LaunchAPPLServer.cc b/LaunchAPPL/Server/LaunchAPPLServer.cc
new file mode 100644
index 0000000000..378b80077c
--- /dev/null
+++ b/LaunchAPPL/Server/LaunchAPPLServer.cc
@@ -0,0 +1,408 @@
+/*
+ Copyright 2018 Wolfgang Thaller.
+
+ This file is part of Retro68.
+
+ Retro68 is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Retro68 is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Retro68. If not, see .
+*/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+#include "MacSerialStream.h"
+#include
+#include
+#include
+#include
+
+#include
+
+enum
+{
+ kMenuApple = 128,
+ kMenuFile,
+ kMenuEdit
+};
+
+enum
+{
+ kItemAbout = 1,
+
+ kItemQuit = 1
+};
+
+
+void ShowAboutBox()
+{
+ WindowRef w = GetNewWindow(128, NULL, (WindowPtr) -1);
+#if !TARGET_API_MAC_CARBON
+ MacMoveWindow(w,
+ qd.screenBits.bounds.right/2 - w->portRect.right/2,
+ qd.screenBits.bounds.bottom/2 - w->portRect.bottom/2,
+ false);
+#endif
+ ShowWindow(w);
+#if TARGET_API_MAC_CARBON
+ SetPortWindowPort(w);
+#else
+ SetPort(w);
+#endif
+
+ Handle h = GetResource('TEXT', 128);
+ HLock(h);
+#if TARGET_API_MAC_CARBON
+ Rect r;
+ GetWindowPortBounds(w,&r);
+#else
+ Rect r = w->portRect;
+#endif
+ InsetRect(&r, 10,10);
+ TETextBox(*h, GetHandleSize(h), &r, teJustLeft);
+
+ ReleaseResource(h);
+ while(!Button())
+ ;
+ while(Button())
+ ;
+ FlushEvents(everyEvent, 0);
+ DisposeWindow(w);
+}
+
+void UpdateMenus()
+{
+ MenuRef m = GetMenu(kMenuFile);
+ WindowRef w = FrontWindow();
+
+#if TARGET_API_MAC_CARBON
+ #define EnableItem EnableMenuItem
+ #define DisableItem DisableMenuItem
+#endif
+
+ m = GetMenu(kMenuEdit);
+ if(w && GetWindowKind(w) < 0)
+ {
+ // Desk accessory in front: Enable edit menu items
+ EnableItem(m,1);
+ EnableItem(m,3);
+ EnableItem(m,4);
+ EnableItem(m,5);
+ EnableItem(m,6);
+ }
+ else
+ {
+ // Application window or nothing in front, disable edit menu
+ DisableItem(m,1);
+ DisableItem(m,3);
+ DisableItem(m,4);
+ DisableItem(m,5);
+ DisableItem(m,6);
+ }
+}
+
+void DoMenuCommand(long menuCommand)
+{
+ Str255 str;
+ WindowRef w;
+ short menuID = menuCommand >> 16;
+ short menuItem = menuCommand & 0xFFFF;
+ if(menuID == kMenuApple)
+ {
+ if(menuItem == kItemAbout)
+ ShowAboutBox();
+#if !TARGET_API_MAC_CARBON
+ else
+ {
+ GetMenuItemText(GetMenu(128), menuItem, str);
+ OpenDeskAcc(str);
+ }
+#endif
+ }
+ else if(menuID == kMenuFile)
+ {
+ switch(menuItem)
+ {
+ case kItemQuit:
+ ExitToShell();
+ break;
+ }
+ }
+ else if(menuID == kMenuEdit)
+ {
+#if !TARGET_API_MAC_CARBON
+ if(!SystemEdit(menuItem - 1))
+#endif
+ {
+ // edit command not handled by desk accessory
+ }
+ }
+
+ HiliteMenu(0);
+}
+
+
+WindowPtr statusWindow;
+Str255 statusString = "\p";
+int progressDone, progressTotal = 0;
+
+void DoUpdate(WindowRef w)
+{
+ if(w != statusWindow)
+ return;
+
+#if TARGET_API_MAC_CARBON
+ SetPortWindowPort(w);
+#else
+ SetPort(w);
+#endif
+ BeginUpdate(w);
+ EraseRect(&w->portRect);
+
+ MoveTo(10,20);
+ DrawString(statusString);
+
+ Rect r;
+
+ if(progressTotal)
+ {
+ SetRect(&r, 10, 40, w->portRect.right-10, 60);
+ FrameRect(&r);
+ SetRect(&r, 10, 40, 10 + (w->portRect.right-20) * progressDone / progressTotal, 60);
+ PaintRect(&r);
+ }
+
+ EndUpdate(w);
+}
+
+enum class AppStatus
+{
+ ready = 1,
+ downloading = 2,
+ running = 3,
+ uploading = 4
+};
+
+void SetStatus(AppStatus stat, int done = 0, int total = 0)
+{
+ GetIndString(statusString,128,(short)stat);
+
+ progressTotal = total;
+ progressDone = done;
+ SetPort(statusWindow);
+ InvalRect(&statusWindow->portRect);
+}
+
+class Listener : public StreamListener
+{
+ uint32_t dataSize, rsrcSize;
+ uint32_t remainingSize;
+ short refNum;
+public:
+ enum class State
+ {
+ size,
+ data,
+ rsrc,
+ launch,
+ stop
+ };
+ State state = State::size;
+
+
+ size_t onReceive(const uint8_t* p, size_t n)
+ {
+ switch(state)
+ {
+ case State::size:
+ {
+ if(n < 8)
+ return 0;
+ dataSize = *(const uint32_t*)p;
+ rsrcSize = *(const uint32_t*)(p+4);
+
+ SetStatus(AppStatus::downloading, 0, dataSize + rsrcSize);
+ printf("Data Size: %u / %u\n", dataSize, rsrcSize);
+
+ FSDelete("\pRetro68App", 0);
+ Create("\pRetro68App", 0, '????', 'APPL');
+ OpenDF("\pRetro68App", 0, &refNum);
+ state = State::data;
+ remainingSize = dataSize;
+ return 8;
+ }
+
+ case State::data:
+ {
+ long count = n < remainingSize ? n : remainingSize;
+
+ FSWrite(refNum, &count, p);
+ remainingSize -= count;
+
+ SetStatus(AppStatus::downloading, dataSize - remainingSize, dataSize + rsrcSize);
+
+ if(remainingSize)
+ return count;
+
+ FSClose(refNum);
+ OpenRF("\pRetro68App", 0, &refNum);
+ state = State::rsrc;
+ remainingSize = rsrcSize;
+
+
+ return count;
+ }
+
+ case State::rsrc:
+ {
+ long count = n < remainingSize ? n : remainingSize;
+
+ FSWrite(refNum, &count, p);
+ remainingSize -= count;
+
+ SetStatus(AppStatus::downloading, dataSize + rsrcSize - remainingSize, dataSize + rsrcSize);
+
+ if(remainingSize)
+ return count;
+
+ FSClose(refNum);
+
+ SetStatus(AppStatus::running);
+
+ state = State::launch;
+ return count;
+ }
+ }
+ }
+};
+
+int main()
+{
+#if !TARGET_API_MAC_CARBON
+ InitGraf(&qd.thePort);
+ InitFonts();
+ InitWindows();
+ InitMenus();
+ TEInit();
+ InitDialogs(NULL);
+#endif
+
+ SetMenuBar(GetNewMBar(128));
+ AppendResMenu(GetMenu(128), 'DRVR');
+ DrawMenuBar();
+
+ InitCursor();
+
+ statusWindow = GetNewWindow(129, NULL, (WindowPtr) -1);
+ SetStatus(AppStatus::ready);
+ MacSerialStream stream;
+
+//#define SIMULATE_ERRORS
+#ifdef SIMULATE_ERRORS
+ UnreliableStream uStream(stream);
+ ReliableStream rStream(uStream);
+#else
+ ReliableStream rStream(stream);
+#endif
+
+ Listener listener;
+ rStream.setListener(&listener);
+
+
+ for(;;)
+ {
+ EventRecord e;
+ WindowRef win;
+
+#if 0 && !TARGET_API_MAC_CARBON
+ SystemTask();
+ if(GetNextEvent(everyEvent, &e))
+#else
+ // actually, we should be using WaitNextEvent
+ // on everything starting from System 7
+ if(WaitNextEvent(everyEvent, &e, 10, NULL))
+#endif
+ {
+ switch(e.what)
+ {
+ case keyDown:
+ if(e.modifiers & cmdKey)
+ {
+ UpdateMenus();
+ DoMenuCommand(MenuKey(e.message & charCodeMask));
+ }
+ break;
+ case mouseDown:
+ switch(FindWindow(e.where, &win))
+ {
+ case inGoAway:
+ if(TrackGoAway(win, e.where))
+ DisposeWindow(win);
+ break;
+ case inDrag:
+ DragWindow(win, e.where, &qd.screenBits.bounds);
+ break;
+ case inMenuBar:
+ UpdateMenus();
+ DoMenuCommand( MenuSelect(e.where) );
+ break;
+ case inContent:
+ SelectWindow(win);
+ break;
+#if !TARGET_API_MAC_CARBON
+ case inSysWindow:
+ SystemClick(&e, win);
+ break;
+#endif
+ }
+ break;
+ case updateEvt:
+ DoUpdate((WindowRef)e.message);
+ break;
+ }
+ }
+
+ stream.idle();
+
+ if(listener.state == Listener::State::launch)
+ {
+ stream.close();
+ {
+ LaunchParamBlockRec lpb;
+ memset(&lpb, 0, sizeof(lpb));
+
+ lpb.reserved1 = (unsigned long) "\pRetro68App";
+ lpb.reserved2 = 0;
+ lpb.launchBlockID = extendedBlock;
+ lpb.launchEPBLength = 6;
+ lpb.launchFileFlags = 0;
+ lpb.launchControlFlags = 0xC000;
+
+ printf("Launching...\n");
+ OSErr err = LaunchApplication(&lpb);
+ listener.state = Listener::State::size;
+ uint32_t zero = 0;
+ stream.write(&zero, 4);
+ stream.flushWrite();
+ }
+ }
+ }
+ return 0;
+}
diff --git a/LaunchAPPL/Server/LaunchAPPLServer.r b/LaunchAPPL/Server/LaunchAPPLServer.r
new file mode 100644
index 0000000000..ac138c794b
--- /dev/null
+++ b/LaunchAPPL/Server/LaunchAPPLServer.r
@@ -0,0 +1,113 @@
+/*
+ Copyright 2018 Wolfgang Thaller.
+
+ This file is part of Retro68.
+
+ Retro68 is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Retro68 is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Retro68. If not, see .
+*/
+
+#include "Processes.r"
+#include "Menus.r"
+#include "Windows.r"
+#include "MacTypes.r"
+
+resource 'MENU' (128) {
+ 128, textMenuProc;
+ allEnabled, enabled;
+ apple;
+ {
+ "About LaunchAPPLServer...", noIcon, noKey, noMark, plain;
+ "-", noIcon, noKey, noMark, plain;
+ }
+};
+
+resource 'MENU' (129) {
+ 129, textMenuProc;
+ allEnabled, enabled;
+ "File";
+ {
+ "Quit", noIcon, "Q", noMark, plain;
+ }
+};
+
+resource 'MENU' (130) {
+ 130, textMenuProc;
+ 0, enabled;
+ "Edit";
+ {
+ "Undo", noIcon, "Z", noMark, plain;
+ "-", noIcon, noKey, noMark, plain;
+ "Cut", noIcon, "X", noMark, plain;
+ "Copy", noIcon, "C", noMark, plain;
+ "Paste", noIcon, "V", noMark, plain;
+ "Clear", noIcon, noKey, noMark, plain;
+ }
+};
+
+resource 'MBAR' (128) {
+ { 128, 129, 130 };
+};
+
+data 'TEXT' (128) {
+ "About LaunchAPPLShell\r\r"
+ "Listens on the modem port for an application sent by Retro68's LaunchAPPL tool."
+};
+
+resource 'WIND' (128, "About") {
+ {0, 0, 150, 320}, altDBoxProc;
+ invisible;
+ noGoAway;
+ 0, "";
+ noAutoCenter;
+};
+
+resource 'WIND' (129, "Main") {
+ {30, 10, 200, 400}, noGrowDocProc;
+ visible;
+ noGoAway;
+ 0, "Retro68 Application Launching Server";
+ centerMainScreen;
+};
+
+resource 'STR#' (128) {
+ {
+ "Ready.";
+ "Downloading Application...";
+ "Running Application...";
+ "Sending Results...";
+ }
+};
+
+
+
+resource 'SIZE' (-1) {
+ dontSaveScreen,
+ acceptSuspendResumeEvents,
+ enableOptionSwitch,
+ canBackground,
+ multiFinderAware,
+ backgroundAndForeground,
+ dontGetFrontClicks,
+ ignoreChildDiedEvents,
+ is32BitCompatible,
+ reserved,
+ reserved,
+ reserved,
+ reserved,
+ reserved,
+ reserved,
+ reserved,
+ 256 * 1024,
+ 256 * 1024
+};
diff --git a/LaunchAPPL/Server/main.cc b/LaunchAPPL/Server/main.cc
deleted file mode 100644
index d5e28ff3cc..0000000000
--- a/LaunchAPPL/Server/main.cc
+++ /dev/null
@@ -1,157 +0,0 @@
-
-#include
-#include
-#include
-
-#include "MacSerialStream.h"
-#include
-#include
-
-#include
-
-
-/*
-class DumpToConsole : public StreamListener
-{
-public:
- size_t onReceive(const uint8_t* p, size_t n)
- {
- for(int i = 0; i < n; i++)
- putchar(p[i]);
- return n;
- }
-};*/
-
-class Listener : public StreamListener
-{
- uint32_t size;
- short refNum;
-public:
- enum class State
- {
- dataSize,
- data,
- rsrcSize,
- rsrc,
- launch,
- stop
- };
- State state = State::dataSize;
-
-
- size_t onReceive(const uint8_t* p, size_t n)
- {
- switch(state)
- {
- case State::dataSize:
- {
- if(n < 4)
- return 0;
- size = *(const uint32_t*)p;
-
- printf("Data Size: %u\n", size);
-
- FSDelete("\pRetro68App", 0);
- Create("\pRetro68App", 0, '????', 'APPL');
- OpenDF("\pRetro68App", 0, &refNum);
- state = State::data;
- return 4 + onReceive(p+4, n-4);
- }
-
- case State::data:
- {
- long count = n < size ? n : size;
-
- FSWrite(refNum, &count, p);
- if(count < size)
- return count;
- FSClose(refNum);
- state = State::rsrcSize;
- return count;
- }
-
- case State::rsrcSize:
- {
- if(n < 4)
- return 0;
- size = *(const uint32_t*)p;
-
- printf("Rsrc Size: %u\n", size);
-
- OpenRF("\pRetro68App", 0, &refNum);
- state = State::rsrc;
- return 4;
- }
-
- case State::rsrc:
- {
- long count = n < size ? n : size;
-
- FSWrite(refNum, &count, p);
- if(count < size)
- {
- size -= count;
- return count;
- }
- FSClose(refNum);
-
-
- state = State::launch;
- return count;
- }
- }
- }
-};
-
-int main()
-{
- OSErr err;
- short outRefNum, inRefNum;
-
- printf("Hello.\n");
-
- {
- MacSerialStream stream;
-
-//#define SIMULATE_ERRORS
-#ifdef SIMULATE_ERRORS
- UnreliableStream uStream(stream);
- ReliableStream rStream(uStream);
-#else
- ReliableStream rStream(stream);
-#endif
-
- Listener listener;
- rStream.setListener(&listener);
-
- while(!Button())
- {
- stream.idle();
-
- if(listener.state == Listener::State::launch)
- {
- stream.close();
- {
- LaunchParamBlockRec lpb;
- memset(&lpb, 0, sizeof(lpb));
-
- lpb.reserved1 = (unsigned long) "\pRetro68App";
- lpb.reserved2 = 0;
- lpb.launchBlockID = extendedBlock;
- lpb.launchEPBLength = 6;
- lpb.launchFileFlags = 0;
- lpb.launchControlFlags = 0xC000;
-
- printf("Launching...\n");
- OSErr err = LaunchApplication(&lpb);
- printf("Still here after launch (err = %d). Press Enter to exit.\n", (int)err);
- getchar();
- return 0;
- }
- }
- }
- }
-
- return 0;
-}
-