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; -} -