mirror of
https://github.com/autc04/Retro68.git
synced 2024-12-27 23:31:44 +00:00
LaunchAPPL/Serial: start a nice GUI for the server
This commit is contained in:
parent
e2967f3bb9
commit
fc9f941891
@ -149,7 +149,7 @@ bool SerialLauncher::Go(int timeout)
|
||||
read(&tmp, 4);
|
||||
tmp = ntohl(tmp);
|
||||
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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")
|
||||
|
408
LaunchAPPL/Server/LaunchAPPLServer.cc
Normal file
408
LaunchAPPL/Server/LaunchAPPLServer.cc
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <Quickdraw.h>
|
||||
#include <Windows.h>
|
||||
#include <Menus.h>
|
||||
#include <Fonts.h>
|
||||
#include <Resources.h>
|
||||
#include <TextEdit.h>
|
||||
#include <TextUtils.h>
|
||||
#include <Dialogs.h>
|
||||
#include <Devices.h>
|
||||
|
||||
|
||||
#include "MacSerialStream.h"
|
||||
#include <ReliableStream.h>
|
||||
#include <Processes.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <UnreliableStream.h>
|
||||
|
||||
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;
|
||||
}
|
113
LaunchAPPL/Server/LaunchAPPLServer.r
Normal file
113
LaunchAPPL/Server/LaunchAPPLServer.r
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
||||
};
|
@ -1,157 +0,0 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <Events.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "MacSerialStream.h"
|
||||
#include <ReliableStream.h>
|
||||
#include <Processes.h>
|
||||
|
||||
#include <UnreliableStream.h>
|
||||
|
||||
|
||||
/*
|
||||
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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user