From e188eef51c92a6ea6819396585f86288b66728ed Mon Sep 17 00:00:00 2001 From: Charles Lehner Date: Thu, 24 Jul 2014 00:44:47 -0400 Subject: [PATCH] Initial commit --- .gitignore | 2 ++ Browsy.make | 1 + README.md | 23 +++++++++++++++++++++++ page.html | 1 + src/Browsy.h | 1 + src/Browsy.r | 1 + src/Browsy.rsrc.bin | Bin 0 -> 13184 bytes src/main.c | 1 + src/menus.c | 1 + src/uri.c | 1 + src/uri.h | 1 + src/utils.c | 1 + src/window.c | 1 + src/window.h | 1 + 14 files changed, 36 insertions(+) create mode 100644 .gitignore create mode 100755 Browsy.make create mode 100644 README.md create mode 100755 page.html create mode 100755 src/Browsy.h create mode 100755 src/Browsy.r create mode 100644 src/Browsy.rsrc.bin create mode 100755 src/main.c create mode 100755 src/menus.c create mode 100755 src/uri.c create mode 100755 src/uri.h create mode 100755 src/utils.c create mode 100755 src/window.c create mode 100755 src/window.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..21867bf --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +Browsy +Browsy.NJ diff --git a/Browsy.make b/Browsy.make new file mode 100755 index 0000000..fb13313 --- /dev/null +++ b/Browsy.make @@ -0,0 +1 @@ +# File: Browsy.make # Target: Browsy # Created: Saturday, July 7, 2012 01:10:12 AM MAKEFILE = Browsy.make ¥MondoBuild¥ = {MAKEFILE} # Make blank to avoid rebuilds when makefile is modified SrcDir = :src: ObjDir = :build: Includes = ¶ -i :src: ¶ -i :include: Sym-68K = -sym off COptions = {Includes} {Sym-68K} -model near -includes unix ### Source Files ### SrcFiles = ¶ "{SrcDir}Browsy.r" ¶ "{SrcDir}main.c" ¶ "{SrcDir}menus.c" ¶ "{SrcDir}window.c" ¶ "{SrcDir}utils.c" ¶ "{SrcDir}uri.c" ### Object Files ### ObjFiles-68K = ¶ "{ObjDir}main.c.o" ¶ "{ObjDir}menus.c.o" ¶ "{ObjDir}window.c.o" ¶ "{ObjDir}utils.c.o" ¶ "{ObjDir}uri.c.o" ### Libraries ### LibFiles-68K = "{Libraries}MathLib.o" ¶ "{CLibraries}StdCLib.o" ¶ "{Libraries}MacRuntime.o" ¶ "{Libraries}IntEnv.o" ¶ "{Libraries}ToolLibs.o" ¶ "{Libraries}Interface.o" ¶ #"{SharedLibraries}MenusLib" ¶ :lib:tidy.o ### Default Rules ### .c.o Ä .c {¥MondoBuild¥} {C} {depDir}{default}.c -o {targDir}{default}.c.o {COptions} ### Build Rules ### Browsy ÄÄ {ObjFiles-68K} {LibFiles-68K} {¥MondoBuild¥} ILink ¶ -o {Targ} ¶ #-weaklib MenusLib ¶ {LibFiles-68K} ¶ {ObjFiles-68K} ¶ {Sym-68K} ¶ -mf -d ¶ -t 'APPL' ¶ -c 'WWW6' ¶ -model near ¶ -state rewrite ¶ -compact -pad 0 If "{Sym-68K}" =~ /-sym Å[nNuU]Å/ ILinkToSYM {Targ}.NJ -mf -sym 3.2 -c 'sade' End Browsy ÄÄ "{SrcDir}Browsy.rsrc" {¥MondoBuild¥} Rez "{SrcDir}Browsy.r" -o {Targ} {Includes} -append ### Required Dependencies ### "{ObjDir}main.c.o" Ä "{SrcDir}main.c" "{ObjDir}menus.c.o" Ä "{SrcDir}menus.c" "{ObjDir}window.c.o" Ä "{SrcDir}window.c" "{ObjDir}utils.c.o" Ä "{SrcDir}utils.c" "{ObjDir}uri.c.o" Ä "{SrcDir}uri.c" ### Optional Dependencies ### ### Build this target to generate "include file" dependencies. ### Dependencies Ä $OutOfDate MakeDepend ¶ -append {MAKEFILE} ¶ -ignore "{CIncludes}" ¶ -ignore "{RIncludes}" ¶ -objdir "{ObjDir}" ¶ -objext .o ¶ {Includes} ¶ {SrcFiles} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..24504c3 --- /dev/null +++ b/README.md @@ -0,0 +1,23 @@ +# Browsy + +A browser for System 6. + +Currently this is mostly a UI concept, that can read local text files, manage +history, and allow the user to push buttons. + +Build using MPW. + +## TODO + +- Implement scrolling +- Fetch pages over HTTP +- Parse HTML and maybe CSS +- Render pages +- Move build system to the [MPW Emulator](https://github.com/ksherlock/mpw) + (maybe) + +Parsing and rendering code could be taken from another browser project such as netsurf or Dillo. + +Network connectivity could be implemented using GUSI, which provides a UNIX-like +API, or by handling the Macintosh TCP stuff directly, which might allow for more +control over responsiveness. diff --git a/page.html b/page.html new file mode 100755 index 0000000..b1d3091 --- /dev/null +++ b/page.html @@ -0,0 +1 @@ + Cool Page Outside paragraph
After Line break
It is Bold, Italic, Underline

In paragraph

Second paragraph

Paragraph without closing tag

Another paragraph without closing tag

First Heading

Another paragraph

Second Heading

Meow paragraph

Unordered list

Ordered list

  1. List item 1
  2. List item 2

Definition list

Term 1
Definition 1
Term 2
Definition 3

Fourth heading

Link to Home Page

Fifth heading

Form

Plain input: Input text:
Password:
Checkboxes:
Meow
Pizza
Select ice cream flavor: Scoops:
1
2
3
Todo: multi select
Textarea:

Submit button:
Reset button:

HTML entities

&amp: "&"
&nbsp: " "

More Stuff

Preformatted text
Address
\ No newline at end of file diff --git a/src/Browsy.h b/src/Browsy.h new file mode 100755 index 0000000..d630426 --- /dev/null +++ b/src/Browsy.h @@ -0,0 +1 @@ +const short defaultALRT = 129; Boolean HasColorQD; Boolean Sys7; Boolean HasWNE; typedef struct HistoryItem { char *title; char *address; struct HistoryItem *prev; struct HistoryItem *next; } HistoryItem; // utils typedef short SICN[16]; typedef SICN **SICNHand; void PlotSICN(Rect *theRect, SICNHand theSICN, long theIndex); Boolean WNE(EventMask eventMask, EventRecord *theEvent, UInt32 sleep, RgnHandle mouseRgn); char *GetFilePathName(int vRefNum, Str255 fName); int GetFilePathVolRef(char *pathFileName); StringPtr GetFilePathFileName(char *pathFileName); char *url_encode(char *str); char *url_decode(char *str); char *url_sanitize(char *str); //void PlotSICN(Rect *theRect, Handle theSICN, long theIndex); void CtoP(char *cstr, unsigned char *pstr); \ No newline at end of file diff --git a/src/Browsy.r b/src/Browsy.r new file mode 100755 index 0000000..1ff47f1 --- /dev/null +++ b/src/Browsy.r @@ -0,0 +1 @@ +include "Browsy.rsrc"; \ No newline at end of file diff --git a/src/Browsy.rsrc.bin b/src/Browsy.rsrc.bin new file mode 100644 index 0000000000000000000000000000000000000000..a3c8da17cc1f44c087f849f09e9b2474869846bc GIT binary patch literal 13184 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 OF|`|G;=zByAO8b59qzIK literal 0 HcmV?d00001 diff --git a/src/main.c b/src/main.c new file mode 100755 index 0000000..064a208 --- /dev/null +++ b/src/main.c @@ -0,0 +1 @@ +#include #include #include #include #include #include #include #include "Browsy.h" #include "window.h" void Initialize(); void MainLoop(); void CheckEnvironment(); void DoIdle(); void Terminate(); void HandleEvent(EventRecord *event); void HandleUpdateEvt(EventRecord *event); void HandleKeyDown(EventRecord *event, WindowPtr topWin); void HandleMouseDown(EventRecord *event, WindowPtr topWin); void HandleActivate(EventRecord *event); void InitAppleEvents(); //void HandleNullEvent(EventRecord *event); QDGlobals qd; void main() { Initialize(); // todo: open specified files // else open empty window PageWindowNavigateHome(NewPageWindow()); MainLoop(); Terminate(); } void Initialize() { InitGraf(&qd.thePort); InitFonts(); InitWindows(); InitMenus(); TEInit(); InitDialogs(nil); InitCursor(); CheckEnvironment(); SetupMenus(); InitAppleEvents(); InitPageWindows(); } void CheckEnvironment() { SysEnvRec sEnv; OSErr oe; oe = SysEnvirons(1,&sEnv); Sys7 = sEnv.systemVersion >= 0x0700; HasColorQD = sEnv.hasColorQD; HasWNE = (NGetTrapAddress(_WaitNextEvent, ToolTrap) != NGetTrapAddress(_Unimplemented, ToolTrap)); } void MainLoop() { EventRecord event; Boolean ok; while (true) { ok = WNE(everyEvent, &event, 10L, nil); if (ok) { HandleEvent(&event); } else { // idle } DoIdle(); } } void DoIdle() { PageWindow *topPWin = GetPageWindow(FrontWindow()); if (topPWin) { PageWindowIdle(topPWin); } } void Terminate() { ExitToShell(); } void HandleEvent(EventRecord *event) { WindowPtr topWin = FrontWindow(); switch (event->what) { case mouseDown: HandleMouseDown(event, topWin); break; case keyDown: case autoKey: HandleKeyDown(event, topWin); break; case updateEvt: HandleUpdateEvt(event); break; case diskEvt: //HandleDiskEvt(event); break; case activateEvt: HandleActivate(event); break; case mouseMovedMessage: //HandleMouseMoved(event); break; case mouseUp: //HandleMouseUp(event); break; case nullEvent: //HandleNullEvent(event); break; } } void HandleMouseDown(EventRecord *event, WindowPtr topWin) { WindowPtr win; PageWindow* pWin; short windowCode = FindWindow(event->where, &win); Rect oldPort; switch (windowCode) { case inMenuBar: //AdjustMenus(); HandleMenu(MenuSelect(event->where)); break; case inSysWindow: SystemClick(event, win); break; case inDrag: DragWindow(win, event->where, &qd.screenBits.bounds); break; case inZoomIn: case inZoomOut: if (TrackBox(win, event->where, windowCode)) { SetPort(win); oldPort = win->portRect; EraseRect(&win->portRect); ZoomWindow(win, windowCode, false); //AdjustScrollBars(win, true); //DrawPage(win); InvalRect(&win->portRect); pWin = GetPageWindow(win); if (pWin) { PageWindowResized(pWin, oldPort); } } break; case inGrow: { long size; Rect r = qd.screenBits.bounds; //GrafPtr oldPort = 0; //GetPort(&oldPort); r.top = 100; r.left = 150; r.bottom -= (GetMBarHeight()<<1); r.right -= 20; //SetRect(&r, MaxWindowWidth+SBarSize-1, 64, //MaxWindowWidth+SBarSize-1, gMaxHeight); if (win != topWin) { SelectWindow(win); } oldPort = win->portRect; size = GrowWindow(win, event->where, &r); SizeWindow(win, LoWord(size), HiWord(size), true); pWin = GetPageWindow(win); if (pWin) { PageWindowResized(pWin, oldPort); } //DrawPage(win); SetPort(win); InvalRect(&win->portRect); //SetPort(oldPort); } break; case inContent: if (win != topWin) { SelectWindow(win); // todo: draw } else { pWin = GetPageWindow(win); if (pWin) { PageWindowMouseDown(pWin, event->where, event->modifiers); } } break; case inGoAway: if (TrackGoAway(win, event->where)) { if (event->modifiers & optionKey) { CloseAll(); } else { pWin = GetPageWindow(win); ClosePageWindow(pWin); } } break; } } void HandleKeyDown(EventRecord *event, WindowPtr topWin) { PageWindow *pWin; char theChar = (char)(event->message & charCodeMask); if (event->modifiers & cmdKey) { HandleMenu(MenuKey(theChar)); } else { pWin = GetPageWindow(topWin); PageWindowKeyDown(pWin, theChar); } } void HandleUpdateEvt(EventRecord *event) { WindowPtr win = (WindowPtr)(event->message); PageWindow *pWin = GetPageWindow(win); BeginUpdate(win); if (pWin) { UpdatePageWindow(pWin); } EndUpdate(win); } void HandleActivate(EventRecord *event) { WindowPtr win = (WindowPtr) event->message; PageWindow *pWin = GetPageWindow(win); if (!pWin) return; if (event->modifiers & activeFlag) { PageWindowActivate(pWin); } else { PageWindowDeactivate(pWin); } } /*void HandleNullEvent(EventRecord *event) { WindowPtr win = (WindowPtr) event->message; PageWindow *pWin = GetPageWindow(win); if (!pWin) return; PageWindowNullEvent(pWin, event); }*/ Boolean GotRequiredParams(AppleEvent *event) { DescType returnedType; Size actualSize; OSErr err; err = AEGetAttributePtr (event, keyMissedKeywordAttr, typeWildCard, &returnedType, NULL, 0, &actualSize); return err == errAEDescNotFound; } /* CAppleEvent::GotRequiredParams */ void HandleOpenAE(AppleEvent *event, AppleEvent *reply, long refCon) { #pragma unused(reply, refCon) Handle docList = NULL; long i, itemCount; FSRef myFSRef; AEDescList theList; OSErr oe; //PageWindow *pwin = GetPageWindow(FrontWindow()); if ((oe = AEGetParamDesc( event, keyDirectObject, typeAEList, &theList)) != noErr) { //DebugStr("\pAEGetParamDesc"); return; } /*if (!GotRequiredParams(event)) { //DebugStr("\pGotRequiredParams"); return; }*/ if ((oe = AECountItems( &theList, &itemCount)) != noErr) { //DebugStr("\pAECountItems"); return; } for (i = 1; i <= itemCount; i++) { //oe = AEGetNthPtr( &theList, i, typeFSRef, &aeKeyword, &actualType, //(Ptr) &myFSRef, sizeof( FSRef), &actualSize); oe = AEGetNthPtr( &theList, i, typeFSRef, NULL, NULL, &myFSRef, sizeof(FSRef), NULL); if (oe == noErr) { NewPageWindow(); //OpenEditWindow(&myFSS); } } AEDisposeDesc(&theList); // event was handled successfully } pascal OSErr HandleAppleEvent(AppleEvent *event,AppleEvent *reply, long refCon) { #pragma unused(reply, refCon) DescType actualType; Size actualSize; DescType eventClass, eventID; OSErr oe; if ((oe = AEGetAttributePtr( (AppleEvent*) event, keyEventClassAttr, typeType, &actualType, (Ptr) &eventClass, sizeof(eventClass), &actualSize)) != noErr) return oe; if ((oe = AEGetAttributePtr( (AppleEvent*) event, keyEventIDAttr, typeType, &actualType, (Ptr) &eventID, sizeof(eventID), &actualSize)) != noErr) return oe; if (eventClass == kCoreEventClass) { switch (eventID) { case kAEOpenApplication: if (GotRequiredParams(event)) { } break; case kAEOpenDocuments: //HandleOpenEvent(event); break; case kAEPrintDocuments: break; case kAEQuitApplication: if (GotRequiredParams(event)) { Terminate(); } break; } } return noErr; } void InitAppleEvents() { if (Sys7) { AEInstallEventHandler(typeWildCard, typeWildCard, (AEEventHandlerUPP) NewAEEventHandlerProc((ProcPtr) HandleAppleEvent), 0, FALSE); AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments, NewAEEventHandlerUPP(HandleOpenAE), 0, FALSE); //(EventHandlerProcPtr) AppleEventHandler, 0, FALSE); } } \ No newline at end of file diff --git a/src/menus.c b/src/menus.c new file mode 100755 index 0000000..ccc03dd --- /dev/null +++ b/src/menus.c @@ -0,0 +1 @@ +#include #include #include #include #include #include #include #include #include #include "Browsy.h" #include "window.h" static void ShowAbout(); const short defaultMenubar = 128; const short aboutDialog = 128; enum {appleMenu=128, fileMenu, editMenu, navigateMenu, historyMenu}; enum { fileNewItem=1, fileOpenItem, fileOpenURLItem, fileCloseItem=5, fileSaveAsItem, filePageSetupItem=8, filePrintItem, fileQuitItem=11, editUndoItem=1, editCutItem=3, editCopyItem, editPasteItem, editClearItem, editSelectAllItem=8, navigateBackItem=1, navigateForwardItem, navigateHomeItem, navigateStopItem=5, navigateReloadItem }; QDGlobals qd; void SetupMenus() { MenuHandle menu; Handle menubar = GetNewMBar(defaultMenubar); SetMenuBar(menubar); menu = GetMenuHandle(appleMenu); AppendResMenu(menu, 'DRVR'); DrawMenuBar(); } void HandleMenu(long menuAction) { short menu = HiWord(menuAction); short item = LoWord(menuAction); MenuHandle mh = GetMenuHandle(menu); WindowPtr topWin = FrontWindow(); PageWindow* pWin = GetPageWindow(topWin); WindowPeek peek; Str255 name; GrafPtr savePort = 0; if (menuAction <= 0) { return; } switch(menu) { case appleMenu: if (item == 1) { ShowAbout(); } else { GetPort(&savePort); GetMenuItemText(mh, item, name); OpenDeskAcc(name); SetPort(savePort); } break; case fileMenu: switch(item) { case fileNewItem: pWin = NewPageWindow(); break; case fileQuitItem: // todo: wait for mactcp and name resolver Terminate(); break; case fileOpenItem: PageWindowOpenFile(pWin); break; case fileOpenURLItem: if (!pWin) { pWin = NewPageWindow(); } PageWindowFocusTE(pWin, pWin->addressBarTE); TESetSelect(0, (*pWin->addressBarTE)->teLength, pWin->addressBarTE); break; case fileCloseItem: peek = (WindowPeek)topWin; if (peek->windowKind < 0) { CloseDeskAcc(peek->windowKind); } else if (peek->goAwayFlag) { if (pWin) { ClosePageWindow(pWin); } } break; case fileSaveAsItem: PageWindowSaveAs(pWin); break; case filePageSetupItem: SysBeep(5); break; case filePrintItem: SysBeep(5); break; } break; case editMenu: { TEHandle te; Boolean inPage; // give to desk accessories first if (SystemEdit(item-1)) { break; } if (!pWin) { break; } te = pWin->focusTE; inPage = te == pWin->contentTE; switch (item) { case editUndoItem: // todo break; case editCutItem: if (te && !inPage) { TECut(te); if (!inPage) { ZeroScrap(); TEToScrap(); } } else { SysBeep(5); } break; case editCopyItem: if (te) { TECopy(te); if (!inPage) { ZeroScrap(); TEToScrap(); } } break; case editPasteItem: if (te && !inPage) { TEFromScrap(); TEPaste(te); } else { SysBeep(5); } break; case editClearItem: if (te && !inPage) { TEDelete(te); } else { SysBeep(5); } break; case editSelectAllItem: if (te) { TESetSelect(0, (*te)->teLength, te); } break; } break; } case navigateMenu: switch(item) { case navigateBackItem: //PageWindowNavigateBack(pWin); PageWindowNavigateHistory(pWin, -1); break; case navigateForwardItem: //PageWindowNavigateForward(pWin); PageWindowNavigateHistory(pWin, 1); break; case navigateHomeItem: PageWindowNavigateHome(pWin); break; case navigateStopItem: //PageWindowStop(pWin); break; case navigateReloadItem: PageWindowNavigateHistory(pWin, 0); //PageWindowReload(pWin); break; } break; } HiliteMenu(0); } // Browser6 static pascal Boolean aboutFilter( DialogPtr theDialog, EventRecord *theEvent, short *itemHit) { if (theDialog) { switch (theEvent->what) { case mouseDown: if (itemHit) { *itemHit=1; } return 1; } } return 0; } static void ShowAbout() { DialogPtr dlg = GetNewDialog(aboutDialog, nil, (WindowPtr)-1L); short item; ModalDialog(aboutFilter, &item); DisposeDialog(dlg); } \ No newline at end of file diff --git a/src/uri.c b/src/uri.c new file mode 100755 index 0000000..64b07da --- /dev/null +++ b/src/uri.c @@ -0,0 +1 @@ +#include #include #include #include #include #include "Browsy.h" #include "uri.h" char *GuessContentType(char *path) { char *extension = strrchr(path, '.'); if (!extension) return "text/plain"; if (!strcmp(extension, "html") || !strcmp(extension, "htm")) return "text/html"; return "text/plain"; } URIResponse *NewResponse() { return (URIResponse *)calloc(1, sizeof(URIResponse)); /*URIResponse *resp; resp = (URIResponse *)malloc(sizeof(URIResponse)); memset(resp, 0, sizeof(URIResponse); resp->headers = NULL; resp->length = 0; resp->contentHandle = NULL; resp->contentType = NULL; return resp;*/ } void DisposeResponse(URIResponse *resp) { if (resp->contentHandle) DisposeHandle(resp->contentHandle); if (resp->contentType) free(resp->contentType); DisposeHeaders(resp->headers); free(resp); } void DisposeHeaders(HTTPHeader *header) { if (!header) return; free(header->name); free(header->value); DisposeHeaders(header->next); } void DisposeRequest(URIRequest *req) { DisposeHeaders(req->headers); if (req->data) DisposeHandle(req->data); if (req->uri) free(req->uri); if (req->response) DisposeResponse(req->response); free(req); }; void RequestURI( char *uri, void (*callback)(struct URIRequest *req), void *refCon) { URIRequest *req; URIResponse *resp; char scheme[8]; // uri scheme short i; short len = strlen(uri)+1; char *path; // part of the uri after the scheme: req = (URIRequest *)malloc(sizeof(URIRequest)); if (!req) { ErrorAlert("Unable to create URI request."); return; } req->refCon = refCon; req->callback = callback; req->uri = (char *)malloc(sizeof(char)*len); strncpy(req->uri, uri, len); // get scheme/protocol // and make it lowercase for (i=0; ilength = bytes; resp->contentHandle = fileContents; resp->contentType = GuessContentType(filePath); req->state = stateComplete; req->response = resp; callback(req); //TESetText(*fileContents, bytes, pWin->contentTE); //HLock(fileContents); //(*pWin->contentTE)->hText = fileContents; //TECalText(pWin->contentTE); //InvalRect(&(*pWin->contentTE)->viewRect); //HUnlock(fileContents); } if (refNum) FSClose(refNum); //if (fileContents) DisposeHandle(fileContents); free(filePath); } else if (strcmp(scheme, "http")==0) { Handle errorText = NewHandle(25); strcpy(*errorText, "http not yet implemented!"); //char *path; //PageWindowSetStatus(pWin, "http not yet implemented!"); resp = NewResponse(); resp->contentHandle = errorText; resp->length = 25; resp->contentType = "text/plain"; req->state = stateComplete; req->response = resp; callback(req); } else if (strcmp(scheme, "about")==0) { Handle text; Str255 puri; CtoP(uri, puri); text = GetNamedResource('TEXT', puri); resp = NewResponse(); if (text == NULL) { resp->contentHandle = NULL; resp->length = 0; } else { resp->contentHandle = text; resp->length = GetHandleSize(text); } resp->contentType = "text/plain"; req->state = stateComplete; req->response = resp; callback(req); } else { Handle errorText = NewHandle(19); strcpy(*errorText, "Unknown URI scheme."); //char *path; //PageWindowSetStatus(pWin, "http not yet implemented!"); resp = NewResponse(); resp->contentHandle = errorText; resp->length = 19; resp->contentType = "text/plain"; req->state = stateComplete; req->response = resp; callback(req); //PageWindowSetStatus(pWin, "Unknown URI scheme."); } } \ No newline at end of file diff --git a/src/uri.h b/src/uri.h new file mode 100755 index 0000000..ddf7055 --- /dev/null +++ b/src/uri.h @@ -0,0 +1 @@ +enum { stateResolving, stateConnecting, stateLoading, stateComplete }; enum { methodGET, methodPOST }; /* enum { err } */ typedef struct HTTPHeader { char *name; char *value; struct HTTPHeader *next; } HTTPHeader; typedef struct { short status; long length; char *contentType; HTTPHeader *headers; Handle contentHandle; } URIResponse; typedef struct URIRequest { char method; char *uri; HTTPHeader *headers; // list of headers Handle data; // POST data void (*callback)(struct URIRequest*); // called on data recieve and done void *refCon; // User/app reference data int state; URIResponse *response; } URIRequest; URIResponse *NewResponse(); void DisposeResponse(URIResponse *resp); void DisposeHeaders(HTTPHeader *header); void DisposeRequest(URIRequest *req); void RequestURI(char *uri, void (*callback)(URIRequest *req), void *refCon); \ No newline at end of file diff --git a/src/utils.c b/src/utils.c new file mode 100755 index 0000000..e2e66b9 --- /dev/null +++ b/src/utils.c @@ -0,0 +1 @@ +#include #include #include "Browsy.h" // wait/get next event Boolean WNE(EventMask eventMask, EventRecord *theEvent, UInt32 sleep, RgnHandle mouseRgn) { if (HasWNE) { return WaitNextEvent(eventMask, theEvent, sleep, mouseRgn); } else { // Single Finder, System 6 or less // Give time to desk accessories SystemTask(); return GetNextEvent(eventMask, theEvent); } } // GetFilePathName and GetFilePathVolRef are from MacTech: // www.mactech.com/articles/mactech/Vol.07/07.09/FilePath/ char *GetFilePathName(vRefNum, fName) int vRefNum; /* File's vol/dir ref */ Str255 fName; /* (pascal string) */ { WDPBRec wDir; /* Working directory */ HVolumeParam wVol; /* Working HFS param blk */ DirInfo wCInfo; /* Working cat info blk */ long wDirID; /* Working dir number */ Str255 wName; /* Working directory name*/ char *wPtr; /* Working string pointer*/ long wLength; /* Working string length */ char *pathFileName;/* Working file path name*/ short i; wDir.ioNamePtr = 0L; /* Init working directory*/ wDir.ioVRefNum = vRefNum; wDir.ioWDIndex = 0; wDir.ioWDProcID = 0; wDir.ioWDVRefNum = vRefNum; (void) PBGetWDInfo(&wDir,FALSE); /* Get the directory ref */ vRefNum = wDir.ioWDVRefNum;/* Save working vol ref #*/ wDirID = wDir.ioWDDirID; /* Save working dir ref #*/ wVol.ioNamePtr = (StringPtr)&wName;/* Init vol block*/ wVol.ioVRefNum = vRefNum; wVol.ioVolIndex = 0; wLength = 0L; /* Set path length to zip*/ pathFileName = NewPtr(0L); /* Set null file's path */ if (!PBHGetVInfo(&((HParamBlockRec)wVol),FALSE) &&/* Got vol info? */ pathFileName) { /* Got file path pointer?*/ if (wVol.ioVSigWord == 0x4244) {/* Check if it HFS */ wCInfo.ioNamePtr = (StringPtr)&wName;/* Init it */ wCInfo.ioVRefNum = vRefNum; wCInfo.ioFDirIndex = -1; wCInfo.ioDrParID = wDirID; wCInfo.ioDrDirID = wDirID; while (wCInfo.ioDrParID != 1){/* Do full path */ wCInfo.ioDrDirID = wCInfo.ioDrParID;/*Move up dir*/ if (PBGetCatInfo(&(CInfoPBRec)wCInfo,FALSE))/* Get dir info */ break; /* Break-out if failed!! */ wLength += wName[0] + 1L;/* Set string length */ wPtr = NewPtr(wLength + 1L);/* Alloc new str */ if (!wPtr) { /* Didn't get str ptr? */ if (pathFileName) /* Check if got memory */ DisposePtr(pathFileName);/* Release it */ pathFileName = 0L; /* Invalidate str pointer*/ break; /* Break-out if failed!! */ } /* Shuffle file path down*/ BlockMove(pathFileName,wPtr + wName[0] + 1, wLength - (long)(wName[0])); DisposePtr(pathFileName);/* Release old one */ *(wPtr + wName[0]) = ':';/* Add dir delimeter */ BlockMove(&wName[1],pathFileName = wPtr, (long)(wName[0])); } } else { /* Oops, get vol info */ wLength = wName[0] + 1L; /* Set string length */ wPtr = NewPtr(wLength + 1L);/* Alloc new string */ if (wPtr) { /* Got string pointer? */ *(wPtr + wName[0]) = ':';/* Tack on dir delimeter*/ BlockMove(&wName[1],pathFileName = wPtr, (long)(wName[0])); } } if (pathFileName) /* Check if got da string*/ pathFileName[wLength] = 0;/* Set end-of-string */ } // append filename //strncpy(pathFileName + wLength, fName+1, fName[0]); wPtr = NewPtr(wLength + fName[0]); BlockMove(pathFileName, wPtr, wLength); DisposePtr(pathFileName); BlockMove(&fName[1], (pathFileName = wPtr) + wLength, (long)(fName[0])); wLength += fName[0]; pathFileName[wLength] = 0; // convert path to unix-style for (i=1; i> 4), *pbuf++ = to_hex(*pstr & 15); pstr++; } *pbuf = '\0'; return buf; } /* Returns a url-decoded version of str */ /* IMPORTANT: be sure to free() the returned string after use */ char *url_decode(char *str) { char *pstr = str, *buf = (char*)malloc(strlen(str) + 1), *pbuf = buf; while (*pstr) { if (*pstr == '%') { if (pstr[1] && pstr[2]) { *pbuf++ = from_hex(pstr[1]) << 4 | from_hex(pstr[2]); pstr += 2; } //} else if (*pstr == '+') { //*pbuf++ = ' '; } else { *pbuf++ = *pstr; } pstr++; } *pbuf = '\0'; return buf; } /* Make sure a str is url-encoded */ /* IMPORTANT: be sure to free() the returned string after use */ char *url_sanitize(char *str) { char *pstr = str, *buf = (char*)malloc(strlen(str) * 3 + 1), *pbuf = buf; while (*pstr) { if (isalnum(*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' || *pstr == '~' || *pstr == ':' || *pstr == '/' || *pstr == '?' || *pstr == '&' || *pstr == '=' || *pstr == '%' || *pstr == ';') *pbuf++ = *pstr; //else if (*pstr == ' ') //*pbuf++ = '+'; else *pbuf++ = '%', *pbuf++ = to_hex(*pstr >> 4), *pbuf++ = to_hex(*pstr & 15); pstr++; } *pbuf = '\0'; return buf; } // from Apple Technical Note TN1019, // with modifications for changing the source mode (removed) void PlotSICN(Rect *theRect, SICNHand theSICN, long theIndex/*, short srcMode*/) { char state; /* saves original flags of 'SICN' handle */ BitMap srcBits; /* built up around 'SICN' data so we can CopyBits */ short srcMode = srcCopy; //if (!srcMode) srcMode = srcCopy; /* check the index for a valid value */ if ((GetHandleSize((Handle)theSICN) / sizeof(SICN)) > theIndex) { /* store the resource's current locked/unlocked condition */ state = HGetState((Handle)theSICN); /* lock the resource so it won't move during the CopyBits call */ HLock((Handle)theSICN); /* set up the small icon's bitmap */ srcBits.baseAddr = (Ptr) (*theSICN)[theIndex]; srcBits.rowBytes = 2; SetRect(&srcBits.bounds, 0, 0, 16, 16); /* draw the small icon in the current grafport */ CopyBits(&srcBits,&(*qd.thePort).portBits, &srcBits.bounds,theRect,srcMode,nil); /* restore the resource's locked/unlocked condition */ HSetState((Handle) theSICN, state); } } void CtoP(char *cstr, unsigned char *pstr) { short len = strlen(cstr); strncpy(pstr+1, cstr, len); pstr[0] = len; } \ No newline at end of file diff --git a/src/window.c b/src/window.c new file mode 100755 index 0000000..1d25902 --- /dev/null +++ b/src/window.c @@ -0,0 +1 @@ +#include #include #include #include #include #include #include #include #include #include "Browsy.h" #include "window.h" #include "uri.h" const short toolbarHeight = 28; const short statusBarHeight = 15; const short defaultWindow = 128; const short handCursor = 128; const short toolbarButtonsWidth = 84; const short navBtn = 1; const short toolbarIconsSICN = 128; const short toolbarIconsDisabledSICN = 129; const short navMenuPopupIds = 1000; enum {iconBack, iconForward, iconHome, iconStop}; /*static Rect toolbarRects[] = {toolbarRectBack, toolbarRectForward, toolbarRectHome, toolbarRectStop};*/ // these don't seem to be including properly from ControlDefinitions.h enum { //inLabel = kControlLabelPart, //inMenu = kControlMenuPart, //inTriangle = kControlTrianglePart, inButton = 10, inCheckBox = 11, inUpButton = 20, inDownButton = 21, inPageUp = 22, inPageDown = 23, inThumb = 129 }; Rect toolbarButtonsRect = {4, 4, toolbarHeight, toolbarButtonsWidth + 4}; Rect toolbarRectBack = {5, 5, 21, 21}; // top left bottom right Rect toolbarRectForward = {5, 25, 21, 41}; Rect toolbarRectHome = {5, 45, 21, 61}; Rect toolbarRectStop = {5, 65, 21, 81}; static pascal void ScrollAction(ControlHandle control, short part); void Scroll(PageWindow *pWin, int h, int v); //void PageWindowAdjustScrollBars(PageWindow *pWin); void FrameAddressBar(PageWindow *pWin); void PageWindowDrawGrowIcon(PageWindow *pWin); void ErrorAlert(char *text); HistoryItem *HistoryItemNewNext(HistoryItem *base); void DrawToolbarButtons(PageWindow *pWin); void HandleNavButtonClick(PageWindow *pWin, Point where); void RecievePageData(URIRequest* req); void PopupNavMenu(PageWindow *pWin, Rect *buttonRect); void DebugSave(long bytes, Ptr buffer); void InitPageWindows() { // left top right bottom //SetRect(&toolbarButtonsRect, 4, 4, toolbarButtonsWidth + 4, toolbarHeight); //(SICNHand) GetResource('SICN', mySICN); } PageWindow* GetPageWindow(WindowPtr win) { WindowPeek peek = (WindowPeek) win; if (!win) return nil; if (peek->windowKind >= userKind) { return (PageWindow*) GetWRefCon(win); } return nil; } void ClosePageWindow(PageWindow *pWin) { HistoryItem *history = pWin->history, *curr, *next; TEDispose(pWin->addressBarTE); TEDispose(pWin->contentTE); TEDispose(pWin->statusTE); DisposeWindow(pWin->window); // Dispose window history. if (history) { for (curr = history->next; curr; curr = next) { next = curr->next; if (curr->address) free(curr->address); if (curr->title) free(curr->title); free(curr); } for (curr = history; curr; curr = next) { next = curr->prev; if (curr->address) free(curr->address); if (curr->title) free(curr->title); free(curr); } } free(pWin); } void CloseAll() { WindowPeek win = (WindowPeek) FrontWindow(); PageWindow* pWin; while (win) { pWin = GetPageWindow((WindowPtr)&win); if (pWin) { ClosePageWindow(pWin); } win = win->nextWindow; } } PageWindow* NewPageWindow() { //Str255 name = "\pUntitled"; PageWindow* pWin = (PageWindow*) malloc(sizeof(PageWindow)); WindowPtr window = GetNewWindow(defaultWindow, nil, (WindowPtr)-1L); TEHandle addressBarTE, contentTE, statusTE; Rect destRect, viewRect, scrollRect, pr; //ControlHandle vScrollBar; SetPort(window); pr = window->portRect; //PageWindowDrawGrowIcon(pWin); // Address bar destRect.top = viewRect.top = 7; destRect.left = viewRect.left = 7 + toolbarButtonsWidth; destRect.bottom = viewRect.bottom = 21; destRect.right = 1000; viewRect.right = pr.right - pr.left - 7; addressBarTE = TENew(&destRect, &viewRect); //(*addressBarTE)->txFont = 0; //(*addressBarTE)->txFace = 0; (*addressBarTE)->txSize = 10; (*addressBarTE)->lineHeight = 13; (*addressBarTE)->fontAscent = 10; TESetText("http://", 7, addressBarTE); pWin->addressBarTE = addressBarTE; //TEActivate(addressBarTE); //InvalRect(&viewRect); // Content TE destRect.top = viewRect.top = pr.top + toolbarHeight; destRect.left = viewRect.left = 0; //destRect.bottom = viewRect.bottom = 30; viewRect.bottom = pr.bottom - statusBarHeight; destRect.bottom = 1000; // page length? destRect.right = viewRect.right = pr.right - 15; contentTE = TEStyleNew(&destRect, &viewRect); pWin->contentTE = contentTE; //TESetText("meow", 4, contentTE); //TEActivate(contentTE); // Status bar TE //destRect.left = viewRect.left = 2; destRect.left = 2; viewRect.left = 0; //destRect.top = viewRect.top = pr.bottom - statusBarHeight + 4; destRect.top = pr.bottom - statusBarHeight + 2; viewRect.top = destRect.top - 1; //destRect.bottom = viewRect.bottom = destRect.top + 12; //destRect.bottom = viewRect.top + 12; //viewRect.bottom = pr.bottom; //statusTEPtr->destRect.right = pr.right - 16; //statusTEPtr->viewRect.right = pr.right; destRect.bottom = viewRect.top + 12; viewRect.bottom = pr.bottom; //viewRect.right = destRect.right = pr.right - 16; //destRect.right = pr.right - 16; //viewRect.right = pr.right; statusTE = TENew(&destRect, &viewRect); (*statusTE)->txSize = 9; (*statusTE)->lineHeight = 12; (*statusTE)->fontAscent = 9; (*statusTE)->crOnly = -1; //TESetText("Statusy", 7, statusTE); //InvalRect(&viewRect); pWin->statusTE = statusTE; //PageWindowSetStatus(pWin, "Statusy the status is good because it is a good status and here it is."); // Scrollbar scrollRect.left = pr.right - 15; scrollRect.top = pr.top - 1; scrollRect.right = pr.right + 1; scrollRect.bottom = viewRect.bottom; pWin->vScrollBar = NewControl(window, &scrollRect, "\p", true, 0, 0, scrollRect.bottom - scrollRect.top, 16, 1L); //pWin->vScrollBar = vScrollBar; //PageWindowAdjustScrollBars(pWin); /*pWin->toolbarBackBtn = NewControl(window, &toolbarRectBack, "\p", true, 0, 0, 0, pushButProc, navBtn);*/ SetWRefCon(window, (long) pWin); //SetWTitle(window, name); pWin->window = window; pWin->location = ""; pWin->focusTE = NULL; pWin->history = NULL; FrameAddressBar(pWin); PageWindowAdjustScrollBars(pWin); DrawToolbarButtons(pWin); return pWin; } void DrawToolbarButtons(PageWindow *pWin) { SICNHand iconsActive = (SICNHand) GetResource('SICN', toolbarIconsSICN); SICNHand iconsDisabled = (SICNHand) GetResource('SICN', toolbarIconsDisabledSICN); HistoryItem *history = pWin->history; SetPort(pWin->window); //EraseRect(&toolbarButtonsRect); PlotSICN(&toolbarRectBack, history && history->prev ? iconsActive : iconsDisabled, iconBack); PlotSICN(&toolbarRectForward, history && history->next ? iconsActive : iconsDisabled, iconForward); PlotSICN(&toolbarRectHome, iconsActive, iconHome); PlotSICN(&toolbarRectStop, /*todo: is loading */ 0 ? iconsActive : iconsDisabled, iconStop); } void UpdatePageWindow(PageWindow *pWin) { WindowPtr win = pWin->window; Rect pr = win->portRect; Rect updateRect = ((*(win->visRgn))->rgnBBox); SetPort(win); //EraseRect(&updateRect); PageWindowDrawGrowIcon(pWin); if (RectInRgn(&(*(pWin->statusTE))->viewRect, win->visRgn)) { EraseRect(&(*(pWin->statusTE))->viewRect); } //(*(pWin->addressBarTE))->viewRect.right = pr.right - pr.left - 7; TEUpdate(&updateRect, pWin->addressBarTE); TEUpdate(&updateRect, pWin->contentTE); TEUpdate(&updateRect, pWin->statusTE); FrameAddressBar(pWin); UpdateControls(win, win->visRgn); if (RectInRgn(&toolbarButtonsRect, win->visRgn)) { DrawToolbarButtons(pWin); } //DrawToolbarButtons(pWin); //DrawDocument(pWin->document); } void PageWindowActivate(PageWindow *pWin) { WindowPtr win = pWin->window; ControlHandle ch; //SetPort(win); PageWindowDrawGrowIcon(pWin); if (pWin->focusTE) { TEActivate(pWin->focusTE); } //FrameAddressBar(pWin); //HiliteControl(pWin->vScrollBar, 0); for (ch = (ControlHandle) ((WindowPeek)(win))->controlList; ch != nil; ch = (*ch)->nextControl) { ShowControl(ch); } } void PageWindowDeactivate(PageWindow *pWin) { WindowPtr win = pWin->window; ControlHandle ch; //SetPort(win); //PageWindowDrawGrowIcon(pWin); if (pWin->focusTE) { TEDeactivate(pWin->focusTE); } //HiliteControl(pWin->vScrollBar, 255); //HideControl(pWin->vScrollBar); ch = (ControlHandle) ((WindowPeek)(win))->controlList; while (ch != nil) { HideControl(ch); ch = (*ch)->nextControl; } PageWindowDrawGrowIcon(pWin); } void PageWindowIdle(PageWindow *pWin) { WindowPtr win = pWin->window; //ControlHandle ch; Point mouse; Cursor *cursor; if (pWin->focusTE && (pWin->focusTE != pWin->contentTE)) { TEIdle(pWin->focusTE); } //SetPort(win); GetMouse(&mouse); SetPort(win); //if (FindControl(mouse, win, &ch)) if (PtInRect(mouse, &(*(pWin->addressBarTE))->viewRect)) { cursor = *GetCursor(iBeamCursor); } else if (PtInRect(mouse, &(*(pWin->contentTE))->viewRect)) { cursor = *GetCursor(iBeamCursor); } else { //PageWindowKeyDown(pWin, 'a'); // if (mouse is over ) cursor = handCursor; cursor = &qd.arrow; } SetCursor(cursor); } void PageWindowAdjustScrollBars(PageWindow *pWin) { short h; Rect pr = pWin->window->portRect; MoveControl(pWin->vScrollBar, pr.right - 15, -1 + toolbarHeight); SizeControl(pWin->vScrollBar, 16, (pr.bottom - pr.top) - 13 - toolbarHeight); h = TEGetHeight((*pWin->contentTE)->nLines, 1, pWin->contentTE); //SetCtlMax(pWin->vScrollBar, h); (*pWin->vScrollBar)->contrlMax = h; } void PageWindowResized(PageWindow *pWin, Rect oldPort) { Rect pr = pWin->window->portRect, r; TEPtr addressBarTEPtr = *(pWin->addressBarTE); TEPtr contentTEPtr = *(pWin->contentTE); TEPtr statusTEPtr = *(pWin->statusTE); addressBarTEPtr->viewRect.right = pr.right - pr.left - 7; contentTEPtr->viewRect.bottom = pr.bottom /*- pr.top*/ - statusBarHeight; contentTEPtr->viewRect.right = pr.right - 15; //statusTEPtr->viewRect.top = statusTEPtr->destRect.top = pr.bottom - statusBarHeight + 4; statusTEPtr->destRect.top = pr.bottom - statusBarHeight + 2; statusTEPtr->viewRect.top = statusTEPtr->destRect.top - 1; //statusTEPtr->viewRect.bottom = statusTEPtr->destRect.bottom = statusTEPtr->viewRect.top + 12; statusTEPtr->destRect.bottom = statusTEPtr->viewRect.top + 12; statusTEPtr->viewRect.bottom = pr.bottom; statusTEPtr->viewRect.right = statusTEPtr->destRect.right = pr.right - 15; //EraseRect(&statusTEPtr->viewRect); //InvalRect(&statusTEPtr->viewRect); PageWindowAdjustScrollBars(pWin); //PageWindowSetStatus(pWin, "asdfgasdfasdfy"); r.left = (pr.right < oldPort.right ? pr.right : oldPort.right) - 8; r.right = pr.right; r.top = 0; r.bottom = toolbarHeight; EraseRect(&r); InvalRect(&r); //SetPort(pWin->window); } void PageWindowFocusTE(PageWindow *pWin, TEHandle te) { if (te != pWin->focusTE) { if (pWin->focusTE) { TEDeactivate(pWin->focusTE); } if (te) { TEActivate(te); } pWin->focusTE = te; } } void PageWindowMouseDown(PageWindow *pWin, Point where, int modifiers) { TEHandle te = NULL; ControlHandle ch; unsigned short part; int oldValue, delta; GlobalToLocal(&where); SetPort(pWin->window); part = (short)FindControl(where, pWin->window, &ch); if (!part) { if (PtInRect(where, &toolbarButtonsRect)) { HandleNavButtonClick(pWin, where); } else if (PtInRect(where, &((*(te = pWin->addressBarTE))->viewRect))) { // click in address bar //te = pWin->addressBarTE; PageWindowFocusTE(pWin, te); TEClick(where, (modifiers & shiftKey) != 0, te); } else if (PtInRect(where, &((*(te = pWin->contentTE))->viewRect))) { // click in page context text //te = pWin->contentTE; PageWindowFocusTE(pWin, te); TEClick(where, (modifiers & shiftKey) != 0, te); // hide insertion point if ((*te)->selStart == (*te)->selEnd) { TEDeactivate(te); pWin->focusTE = NULL; } } } else { switch(part) { // Form element case inButton: //if (TrackControl(ch, where, 0)) { //if (where.top < toolbarHeight) { break; case inCheckBox: break; // Scroll bar case inThumb: oldValue = GetControlValue(ch); if (TrackControl(ch, where, 0)) { delta = oldValue - GetControlValue(ch); if (delta) { if (ch == pWin->vScrollBar) { Scroll(pWin, 0, delta); } else { Scroll(pWin, delta, 0); } } } break; case inUpButton: case inDownButton: case inPageUp: case inPageDown: TrackControl(ch, where, ScrollAction); break; } } } static pascal void ScrollAction(ControlHandle control, short part) { #pragma unused(part, pWin) WindowPtr win = (*control)->contrlOwner; PageWindow *pWin = GetPageWindow(win); short delta, page, ex; Boolean isH; Rect r = (*control)->contrlRect; Rect wr = (*(pWin->contentTE))->viewRect; //pWin->window->portRect static unsigned long lastTicks; if (TickCount()-lastTicks < 4) return; else lastTicks = TickCount(); isH = r.right-r.left > r.bottom-r.top; //page = (isH ? RoundDiv(r.right-r.left, win->hPitch) //: RoundDiv(r.bottom-r.top, win->vPitch))-1; page = isH ? wr.right-wr.left : wr.bottom-wr.top; switch(part) { case inUpButton: delta = -16; break; case inDownButton: delta = 16; break; case inPageUp: delta = -page; break; case inPageDown: delta = page; break; } //SetCtlValue(control, (ex = GetCtlValue(control)) + delta); ex = (*control)->contrlValue; (*control)->contrlValue = ex + delta; //if (ex -= GetCtlValue(control)) { Draw1Control(control); if (ex -= (*control)->contrlValue) { if (isH) Scroll(pWin, ex, 0); else Scroll(pWin, 0, ex); //PageWindowUpdate(pWin); } } void Scroll(PageWindow *pWin, int h, int v) { //RgnHandle updateRgn; //updateRgn = NewRgn(); TEPinScroll(h, v, pWin->contentTE); //ScrollRect(pWin->window->portRect, updateRgn); //InvalRgn(updateRgn); //DisposeRgn(updateRgn); } void HandleNavButtonClick(PageWindow *pWin, /*ControlHandle ch, */Point where) { Rect *r;// = (*ch)->contrlRect; Boolean hit = false; int i = 0; EventRecord evt; RgnHandle mouseRgn = NewRgn(); Boolean btnHasMenu; /*short i; for (i=0; *i; i++) { if (PtInRect(where, toolbarRects[i])) { r = toolbarRects[i]; } }*/ if (PtInRect(where, &toolbarRectBack)) { if (!pWin->history->prev) return; r = &toolbarRectBack; } else if (PtInRect(where, &toolbarRectForward)) { if (!pWin->history->next) return; r = &toolbarRectForward; } else if (PtInRect(where, &toolbarRectHome)) { r = &toolbarRectHome; } else if (PtInRect(where, &toolbarRectStop)) { if (1/*todo: is not loading*/) return; r = &toolbarRectStop; } RectRgn(mouseRgn, r); //if (GetControlReference(ch) != navBtn) return; //if (!TrackControl(ch, where, nil)) return; //if (ch == pWin->toolbarBackBtn) { btnHasMenu = (r == &toolbarRectBack || r == &toolbarRectForward); do { GetMouse(&where); if (PtInRect(where, r)) { if (!hit) { hit = true; InvertRect(r); } if (btnHasMenu && (i > 8)) { PopupNavMenu(pWin, r); InvertRect(r); return; } } else { if (btnHasMenu) { PopupNavMenu(pWin, r); InvertRect(r); return; } if (hit) { hit = false; InvertRect(r); } } WNE(mUpMask | app4Mask, &evt, 10L, mouseRgn); i++; } while (Button()); if (hit) { InvertRect(r); if (r == &toolbarRectBack) { PageWindowNavigateHistory(pWin, -1); } else if (r == &toolbarRectForward) { PageWindowNavigateHistory(pWin, 1); } else if (r == &toolbarRectHome) { PageWindowNavigateHome(pWin); } else if (r == &toolbarRectForward) { //StopLoading(pWin); } else { ErrorAlert("Unknown button pressed."); } } } /* I couldn't get AppendMenuItemText to work in 68k. This version takes a c string instead of pascal string.*/ void MyAppendMenuItemText(MenuHandle menuH, char *itemText) { /*Str255 ptext; CtoP(itemText, ptext); AppendMenu(menuH, ptext);*/ static const char *metaChars = ";^!menuData; short menuTitleLength = menuData[0]; Ptr menuItemData = menuData + menuTitleLength + 1; //Handle menuDataH = RecoverHandle(menuData); short menuItems = CountMItems(menuH)+1; short i = 0; Str255 sanitizedText; char replacedChars[255]; short itemLength = strlen(itemText); memset(replacedChars, 0, 255); memcpy(sanitizedText+1, itemText, itemLength); sanitizedText[0] = itemLength; //CtoP(itemText, sanitizedText); // Strip out metacharacters while (itemText[i] && ((i += strcspn(itemText+i, metaChars)+1)) && ihistory; //Str255 menuItemData; char *menuText; //short len; short choice; Point pt; while (curr = (back ? curr->prev : curr->next), curr) { menuText = curr->title ? curr->title : curr->address; MyAppendMenuItemText(menuH, menuText); } //PageWindowSaveAs(pWin, 256, (Ptr)(*menuH)->menuData); SetPt(&pt, buttonRect->left, buttonRect->bottom); LocalToGlobal(&pt); InsertMenu(menuH, -1); choice = PopUpMenuSelect(menuH, pt.v, pt.h, 0) & 0xffff; if (choice) { PageWindowNavigateHistory(pWin, back ? -choice : choice); } DeleteMenu(navMenuPopupIds + back); SetPort(pWin->window); } void PageWindowNavigate(PageWindow *pWin, char *location) { short len = strlen(location)+1; char *newLocation = (char *)malloc(sizeof(char)*len); HistoryItem *historyItem; newLocation = url_sanitize(location); len = strlen(newLocation); TESetText(newLocation, len, pWin->addressBarTE); InvalRect(&(*pWin->addressBarTE)->viewRect); // don't put a new history item for the same address if (strncmp(newLocation, pWin->history->address, len+1) != 0) { historyItem = HistoryItemNewNext(pWin->history); historyItem->address = newLocation; //historyItem->title = "Title"; pWin->history = historyItem; //PageWindowSetStatus(pWin, pWin->location); } // redraw buttons InvalRect(&toolbarButtonsRect); RequestURI(newLocation, RecievePageData, pWin); //ErrorAlert("requesting uri."); } void RecievePageData(URIRequest* req) { PageWindow *pWin = (PageWindow *)req->refCon; URIResponse *resp = req->response; //if (startedLoading) { pWin->location = pWin->history->address; //} //ErrorAlert("recieved page data."); TESetText(*resp->contentHandle, resp->length, pWin->contentTE); PageWindowAdjustScrollBars(pWin); InvalRect(&(*pWin->contentTE)->viewRect); } // delete items after given item, and replace with new one. HistoryItem *HistoryItemNewNext(HistoryItem *base) { HistoryItem *curr, *next, *newNext; newNext = (HistoryItem *)malloc(sizeof(HistoryItem)); if (!newNext) { ErrorAlert("Unable to create history item."); return NULL; } newNext->address = NULL; newNext->title = NULL; newNext->prev = base; newNext->next = NULL; if (base != NULL) { for (curr = base->next; curr; curr = next) { next = curr->next; if (curr->address) free(curr->address); if (curr->title) free(curr->title); free(curr); } base->next = newNext; } return newNext; } void PageWindowKeyDown(PageWindow *pWin, char theChar) { char *location; if (pWin->focusTE == pWin->contentTE) { } else if (pWin->focusTE == pWin->addressBarTE) { if (theChar == '\n') { if ((*pWin->addressBarTE)->teLength == 0 && pWin->history) { // Put back current address location = pWin->history->address; TESetText(location, strlen(location), pWin->addressBarTE); InvalRect(&(*pWin->addressBarTE)->viewRect); } else { location = (char *) malloc((*(pWin->addressBarTE))->teLength); strcpy(location, *(TEGetText(pWin->addressBarTE))); location[(*(pWin->addressBarTE))->teLength] = 0; PageWindowNavigate(pWin, location); free(location); } } else { TEKey(theChar, pWin->addressBarTE); //FrameAddressBar(pWin); } } else if (pWin->focusTE) { if (theChar == '\n') { // todo: find and submit form } else { TEKey(theChar, pWin->focusTE); } } } void FrameAddressBar(PageWindow *pWin) { Rect frame = (*(pWin->addressBarTE))->viewRect; frame.left -= 3; frame.top -= 3; frame.right += 3; frame.bottom += 2; SetPort(pWin->window); FrameRect(&frame); } void PageWindowSetStatus(PageWindow *pWin, char *status) { //(*pWin->statusTE)->hText = &status; //TECalText(pWin->statusTE); TESetText(status, strlen(status), pWin->statusTE); InvalRect(&(*pWin->statusTE)->viewRect); } void PageWindowDrawGrowIcon(PageWindow *pWin) { Rect r = pWin->window->portRect; RgnHandle oldClip = pWin->window->clipRgn; SetPort(pWin->window); r.top = toolbarHeight - 1; pWin->window->clipRgn = NewRgn(); ClipRect(&r); DrawGrowIcon(pWin->window); DisposeRgn(pWin->window->clipRgn); pWin->window->clipRgn = oldClip; // Draw toolbar line MoveTo(0, toolbarHeight - 1); Line(r.right - r.left, 0); } void PageWindowOpenFile(PageWindow *pWin) { short modifiers = 0; // todo SFTypeList tl; short numTypes; SFReply reply; char *pathName; char *encodedPathName; char uri[256] = "file:///"; Point where; Rect *rp = &qd.screenBits.bounds; where.h = (rp->right - rp->left) - 348; where.v = (rp->bottom - rp->top) - 136; where.h >>= 1; where.v >>= 2; if (modifiers & optionKey) numTypes = -1; else { numTypes = 2; tl[0] = 'TEXT'; tl[1] = 'HTML'; } SFGetFile(where, "\pOpen...", NULL, numTypes, tl, nil, &reply); if (reply.good) { //char blah[255]; short len; if (!pWin) { pWin = NewPageWindow(); } pathName = GetFilePathName(reply.vRefNum, reply.fName); len = strlen(pathName); //sprintf(blah, "pathName (%u): %s", len, pathName); //ErrorAlert(blah); if (strlen(pathName) != len) { ErrorAlert("Length of pathname changed. 1"); len = strlen(pathName); } pathName[len] = 0; if (strlen(pathName) != len) { ErrorAlert("Length of pathname changed. 2"); len = strlen(pathName); } //sprintf(blah, "pathName (%u)", strlen(pathName)); //ErrorAlert(blah); //pathName[len] = 0; encodedPathName = url_encode(pathName); if (strlen(pathName) != len) { ErrorAlert("Length of pathname changed. 3"); // 1 len = strlen(pathName); } strcat(uri, encodedPathName); if (strlen(pathName) != len) { ErrorAlert("Length of pathname changed. 4"); } //sprintf(blah, "pathName (%u): %s", strlen(pathName), pathName); //ErrorAlert(blah); free(encodedPathName); DisposePtr(pathName); PageWindowNavigate(pWin, uri); } } void PageWindowSaveAs(PageWindow *pWin) { short refNum; OSErr oe; SFReply reply; StringPtr fileName; Point where; Rect *rp = &qd.screenBits.bounds; //Str255 loc = "\pabcdefghijklmnopqrstuvwxyz"; long bytes = 5; Ptr buffer; where.h = (rp->right - rp->left) - 348; where.v = (rp->bottom - rp->top) - 136; where.h >>= 1; where.v >>= 2; //GetFilename(pWin, fileName); //BlockMove(pWin->location, loc+1, strlen(pWin->location)); //loc[0] = strlen(pWin->location)+1; //ParamText("\pLocation:",loc,"\p","\p"); //StopAlert(129, NULL); fileName = GetFilePathFileName(pWin->location); //PageWindowSetStatus(pWin, fileName); SFPutFile(where, "\pSave As...", fileName, NULL, &reply); if (!reply.good) { return; } //oe = SFPutOpen(reply.fName, reply.vRefNum, 'WWW6', 'TEXT', &refNum, NULL, NULL); oe = Create(reply.fName, reply.vRefNum, 'WWW6', 'TEXT'); /*if (oe != noErr) { ParamText("\pUnable to save file.","\p","\p","\p"); StopAlert(129, NULL); //PageWindowSetStatus(pWin, errStr); return; }*/ oe = FSOpen(reply.fName, reply.vRefNum, &refNum); if (oe != noErr) { ParamText("\pUnable to save file.","\p","\p","\p"); StopAlert(129, NULL); //PageWindowSetStatus(pWin, errStr); return; } oe = SetFPos(refNum, fsFromStart, 0); if (oe != noErr) { ParamText("\pUnable to save file!","\p","\p","\p"); StopAlert(129, NULL); return; } // todo buffer = "abcde"; oe = FSWrite(refNum, &bytes, buffer); if (oe != noErr) { ParamText("\pUnable to write file.","\p","\p","\p"); StopAlert(129, NULL); return; } FSClose(refNum); } void ErrorAlert(char *text) { Str255 errStr; short len = strlen(text); strncpy(errStr+1, text, len); //BlockMove(text, errStr+1, len); errStr[0] = len; ParamText(errStr, "\p", "\p", "\p"); StopAlert(129, NULL); } void PageWindowNavigateHome(PageWindow *pWin) { //char *home = "http://192.168.1.128/stuff/election/2011candidates.html"; char *home = "file:///Macintosh HD/Documents/Browsy/page.html"; //"http://www.lehnerstudios.com/newsite/"; // GetPrefStr(prefHomePage, home); PageWindowNavigate(pWin, home); } void PageWindowNavigateHistory(PageWindow *pWin, short amount) { HistoryItem *curr = pWin->history; short i = 1; // amount=0 for refresh if (curr == NULL) { i = 0; } else if (amount < 0) { // Back for (i=0; i>amount && curr->prev; i--) { curr = curr->prev; } pWin->history = curr; } else if (amount > 0) { // Forward for (i=0; inext; i++) { curr = curr->next; } pWin->history = curr; } if (i == 0) { SysBeep(5); } else { PageWindowNavigate(pWin, curr->address); } } void DebugSave(long bytes, Ptr buffer) { short refNum; OSErr oe; SFReply reply; Point where; Rect *rp = &qd.screenBits.bounds; //Str255 loc = "\pabcdefghijklmnopqrstuvwxyz"; where.h = (rp->right - rp->left) - 348; where.v = (rp->bottom - rp->top) - 136; where.h >>= 1; where.v >>= 2; SFPutFile(where, "\pSave As...", "\pdebug", NULL, &reply); if (!reply.good) { return; } //oe = SFPutOpen(reply.fName, reply.vRefNum, 'WWW6', 'TEXT', &refNum, NULL, NULL); oe = Create(reply.fName, reply.vRefNum, 'WWW6', 'TEXT'); /*if (oe != noErr) { ParamText("\pUnable to save file.","\p","\p","\p"); StopAlert(129, NULL); return; }*/ oe = FSOpen(reply.fName, reply.vRefNum, &refNum); if (oe != noErr) { ParamText("\pUnable to save file.","\p","\p","\p"); StopAlert(129, NULL); return; } oe = SetFPos(refNum, fsFromStart, 0); if (oe != noErr) { ParamText("\pUnable to save file!","\p","\p","\p"); StopAlert(129, NULL); return; } oe = FSWrite(refNum, &bytes, buffer); if (oe != noErr) { ParamText("\pUnable to write file.","\p","\p","\p"); StopAlert(129, NULL); return; } FSClose(refNum); } \ No newline at end of file diff --git a/src/window.h b/src/window.h new file mode 100755 index 0000000..3d1a6c5 --- /dev/null +++ b/src/window.h @@ -0,0 +1 @@ + typedef struct { WindowPtr window; char *location; TEHandle addressBarTE; TEHandle contentTE; TEHandle focusTE; // whichever TE has focus TEHandle statusTE; // text in status bar HistoryItem *history; ControlHandle vScrollBar; ControlHandle toolbarBackBtn; } PageWindow; PageWindow* NewPageWindow(); PageWindow* GetPageWindow(WindowPtr win); void InitPageWindows(); void ClosePageWindow(PageWindow *pWin); void PageWindowNavigates(PageWindow *pWin, char *location); void UpdatePageWindow(PageWindow *pWin); void PageWindowActivate(PageWindow *pWin); void PageWindowDeactivate(PageWindow *pWin); void PageWindowAdjustScrollBars(PageWindow *pWin); void PageWindowResized(PageWindow *pWin, Rect oldPort); void CloseAll(); void PageWindowIdle(PageWindow *pWin); void PageWindowMouseDown(PageWindow* pWin, Point where, int modifiers); void PageWindowFocusTE(PageWindow *pWin, TEHandle te); void PageWindowKeyDown(PageWindow *pWin, char theChar); void PageWindowSetStatus(PageWindow *pWin, char *status); void PageWindowSaveAs(PageWindow *pWin); void PageWindowOpenFile(PageWindow *pWin); void PageWindowNavigateHistory(PageWindow *pWin, short amount); void PageWindowNavigateHome(PageWindow *pWin); \ No newline at end of file