2007-09-29 08:39:35 +00:00
|
|
|
#include <Carbon/Carbon.h>
|
|
|
|
|
|
|
|
#include <fitz.h>
|
|
|
|
#include <mupdf.h>
|
|
|
|
#include "pdfapp.h"
|
|
|
|
|
|
|
|
#define gDefaultFilename "/Users/giles/projects/ghostscript/tiger.pdf"
|
|
|
|
|
|
|
|
#define kViewClassID CFSTR("com.artofcode.ghostpdf.View")
|
|
|
|
#define kViewPrivate 'MU_v'
|
|
|
|
|
|
|
|
/* the pdfapp abstraction currently uses magic callbacks, so we have
|
|
|
|
to use a a global state for our own data, or subclass pdfapp_t and
|
|
|
|
do a lot of casting */
|
|
|
|
|
|
|
|
/* pdfapp callbacks - error handling */
|
|
|
|
void winwarn(pdfapp_t *pdf, char *msg)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "ghostpdf warning: %s\n", msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
void winerror(pdfapp_t *pdf, char *msg)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "ghostpdf error: %s\n", msg);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* pdfapp callbacks - drawing */
|
|
|
|
|
|
|
|
void wintitle(pdfapp_t *pdf, char *title)
|
|
|
|
{
|
|
|
|
/* set new document title */
|
|
|
|
}
|
|
|
|
|
|
|
|
void winresize(pdfapp_t *pdf, int w, int h)
|
|
|
|
{
|
|
|
|
/* pdfapp as been asked to shrinkwrap the document image;
|
|
|
|
we're called to actually apply the new window size. */
|
|
|
|
}
|
|
|
|
|
|
|
|
void winconvert(pdfapp_t *pdf, fz_pixmap *image)
|
|
|
|
{
|
|
|
|
/* notification that page drawing is complete */
|
|
|
|
/* do nothing */
|
|
|
|
}
|
|
|
|
|
|
|
|
void winrepaint(pdfapp_t *pdf)
|
|
|
|
{
|
|
|
|
/* image needs repainting */
|
|
|
|
HIViewSetNeedsDisplay((HIViewRef)pdf->userdata, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
char* winpassword(pdfapp_t *pdf, char *filename)
|
|
|
|
{
|
|
|
|
/* prompt user for document password */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void winopenuri(pdfapp_t *pdf, char *s)
|
|
|
|
{
|
|
|
|
/* user clicked on an external uri */
|
|
|
|
/* todo: launch browser and/or open a new window if it's a PDF */
|
|
|
|
}
|
|
|
|
|
|
|
|
void wincursor(pdfapp_t *pdf, int curs)
|
|
|
|
{
|
|
|
|
/* cursor status change notification */
|
|
|
|
}
|
|
|
|
|
|
|
|
void windocopy(pdfapp_t *pdf)
|
|
|
|
{
|
|
|
|
/* user selected some text; copy it to the clipboard */
|
|
|
|
}
|
|
|
|
|
|
|
|
static OSStatus
|
|
|
|
view_construct(EventRef inEvent)
|
|
|
|
{
|
|
|
|
OSStatus err;
|
|
|
|
pdfapp_t *pdf;
|
|
|
|
|
|
|
|
pdf = (pdfapp_t *)malloc(sizeof(pdfapp_t));
|
|
|
|
require_action(pdf != NULL, CantMalloc, err = memFullErr);
|
2007-10-19 23:05:02 +00:00
|
|
|
|
2007-09-29 08:39:35 +00:00
|
|
|
pdfapp_init(pdf);
|
|
|
|
|
|
|
|
err = GetEventParameter(inEvent, kEventParamHIObjectInstance,
|
|
|
|
typeHIObjectRef, NULL, sizeof(HIObjectRef), NULL,
|
|
|
|
(HIObjectRef *)&pdf->userdata);
|
|
|
|
require_noerr(err, ParameterMissing);
|
|
|
|
err = SetEventParameter(inEvent, kEventParamHIObjectInstance,
|
|
|
|
typeVoidPtr, sizeof(pdfapp_t *), &pdf);
|
|
|
|
|
|
|
|
ParameterMissing:
|
|
|
|
if (err != noErr)
|
|
|
|
free(pdf);
|
|
|
|
|
|
|
|
CantMalloc:
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static OSStatus
|
|
|
|
view_destruct(EventRef inEvent, pdfapp_t *pdf)
|
|
|
|
{
|
|
|
|
pdfapp_close(pdf);
|
|
|
|
free(pdf);
|
|
|
|
return noErr;
|
|
|
|
}
|
|
|
|
|
|
|
|
static OSStatus
|
|
|
|
view_initialize(EventHandlerCallRef inCallRef, EventRef inEvent,
|
|
|
|
pdfapp_t *pdf)
|
|
|
|
{
|
|
|
|
OSStatus err;
|
|
|
|
HIRect bounds;
|
|
|
|
HIViewRef view = (HIViewRef)pdf->userdata;
|
2007-10-19 23:05:02 +00:00
|
|
|
|
2007-09-29 08:39:35 +00:00
|
|
|
err = CallNextEventHandler(inCallRef, inEvent);
|
|
|
|
require_noerr(err, TroubleInSuperClass);
|
|
|
|
|
|
|
|
HIViewGetBounds (view, &bounds);
|
|
|
|
pdf->scrw = bounds.size.width;
|
|
|
|
pdf->scrh = bounds.size.height;
|
2007-10-19 23:05:02 +00:00
|
|
|
|
2007-09-29 08:39:35 +00:00
|
|
|
pdfapp_open(pdf, gDefaultFilename);
|
2007-10-19 23:05:02 +00:00
|
|
|
|
2007-09-29 08:39:35 +00:00
|
|
|
TroubleInSuperClass:
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
cgcontext_set_rgba(CGContextRef ctx, unsigned int rgba)
|
|
|
|
{
|
|
|
|
const double norm = 1.0 / 255;
|
|
|
|
CGContextSetRGBFillColor(ctx,
|
|
|
|
((rgba >> 24) & 0xff) * norm,
|
|
|
|
((rgba >> 16) & 0xff) * norm,
|
|
|
|
((rgba >> 8) & 0xff) * norm,
|
|
|
|
(rgba & 0xff) * norm);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
draw_rect(CGContextRef ctx, double x0, double y0, double x1, double y1,
|
|
|
|
unsigned int rgba)
|
|
|
|
{
|
|
|
|
HIRect rect;
|
|
|
|
|
|
|
|
cgcontext_set_rgba(ctx, rgba);
|
|
|
|
rect.origin.x = x0;
|
|
|
|
rect.origin.y = y0;
|
|
|
|
rect.size.width = x1 - x0;
|
|
|
|
rect.size.height = y1 - y0;
|
|
|
|
CGContextFillRect(ctx, rect);
|
|
|
|
}
|
|
|
|
|
|
|
|
static OSStatus
|
|
|
|
view_draw(EventRef inEvent, pdfapp_t *pdf)
|
|
|
|
{
|
|
|
|
OSStatus err;
|
|
|
|
CGContextRef gc;
|
|
|
|
CGDataProviderRef provider;
|
|
|
|
CGImageRef image;
|
|
|
|
CGColorSpaceRef colorspace;
|
|
|
|
CGRect rect;
|
|
|
|
|
|
|
|
err = GetEventParameter(inEvent, kEventParamCGContextRef, typeCGContextRef,
|
|
|
|
NULL, sizeof(CGContextRef), NULL, &gc);
|
|
|
|
require_noerr(err, cleanup);
|
|
|
|
|
|
|
|
colorspace = CGColorSpaceCreateDeviceRGB();
|
|
|
|
provider = CGDataProviderCreateWithData(NULL, pdf->image->samples,
|
|
|
|
pdf->image->w * pdf->image->h * 4,
|
|
|
|
NULL);
|
|
|
|
image = CGImageCreate(pdf->image->w, pdf->image->h,
|
|
|
|
8, 32, pdf->image->w * 4,
|
|
|
|
colorspace, kCGImageAlphaNoneSkipFirst, provider,
|
|
|
|
NULL, 0, kCGRenderingIntentDefault);
|
|
|
|
|
|
|
|
rect.origin.x = 0;
|
|
|
|
rect.origin.y = 0;
|
|
|
|
rect.size.width = pdf->image->w;
|
|
|
|
rect.size.height = pdf->image->h;
|
|
|
|
HIViewDrawCGImage(gc, &rect, image);
|
|
|
|
|
|
|
|
CGColorSpaceRelease(colorspace);
|
|
|
|
CGDataProviderRelease(provider);
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static OSStatus
|
|
|
|
view_get_data(EventRef inEvent, pdfapp_t *pdf)
|
|
|
|
{
|
|
|
|
OSStatus err;
|
|
|
|
OSType tag;
|
|
|
|
Ptr ptr;
|
|
|
|
Size outSize;
|
|
|
|
|
|
|
|
/* Probably could use a bit more error checking here, for type
|
|
|
|
and size match. Also, just returning a viewctx seems a
|
|
|
|
little hacky. */
|
|
|
|
err = GetEventParameter(inEvent, kEventParamControlDataTag, typeEnumeration,
|
|
|
|
NULL, sizeof(OSType), NULL, &tag);
|
|
|
|
require_noerr(err, ParameterMissing);
|
|
|
|
|
|
|
|
err = GetEventParameter(inEvent, kEventParamControlDataBuffer, typePtr,
|
|
|
|
NULL, sizeof(Ptr), NULL, &ptr);
|
|
|
|
|
|
|
|
if (tag == kViewPrivate) {
|
|
|
|
*((pdfapp_t **)ptr) = pdf;
|
|
|
|
outSize = sizeof(pdfapp_t *);
|
|
|
|
} else
|
|
|
|
err = errDataNotSupported;
|
|
|
|
|
|
|
|
if (err == noErr)
|
|
|
|
err = SetEventParameter(inEvent, kEventParamControlDataBufferSize, typeLongInteger,
|
|
|
|
sizeof(Size), &outSize);
|
|
|
|
|
|
|
|
ParameterMissing:
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static OSStatus
|
|
|
|
view_set_data(EventRef inEvent, pdfapp_t *pdf)
|
|
|
|
{
|
|
|
|
OSStatus err;
|
|
|
|
Ptr ptr;
|
|
|
|
OSType tag;
|
|
|
|
|
|
|
|
err = GetEventParameter(inEvent, kEventParamControlDataTag, typeEnumeration,
|
|
|
|
NULL, sizeof(OSType), NULL, &tag);
|
|
|
|
require_noerr(err, ParameterMissing);
|
|
|
|
|
|
|
|
err = GetEventParameter(inEvent, kEventParamControlDataBuffer, typePtr,
|
|
|
|
NULL, sizeof(Ptr), NULL, &ptr);
|
|
|
|
require_noerr(err, ParameterMissing);
|
|
|
|
|
|
|
|
/* we think we don't use this */
|
|
|
|
err = errDataNotSupported;
|
|
|
|
|
|
|
|
ParameterMissing:
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static OSStatus
|
|
|
|
view_hittest(EventRef inEvent, pdfapp_t *pdf)
|
|
|
|
{
|
|
|
|
OSStatus err;
|
|
|
|
HIPoint where;
|
|
|
|
HIRect bounds;
|
|
|
|
ControlPartCode part;
|
|
|
|
|
|
|
|
err = GetEventParameter(inEvent, kEventParamMouseLocation, typeHIPoint,
|
|
|
|
NULL, sizeof(HIPoint), NULL, &where);
|
|
|
|
require_noerr(err, ParameterMissing);
|
|
|
|
|
|
|
|
err = HIViewGetBounds(pdf->userdata, &bounds);
|
|
|
|
require_noerr(err, ParameterMissing);
|
|
|
|
|
|
|
|
if (CGRectContainsPoint(bounds, where))
|
|
|
|
part = 1;
|
|
|
|
else
|
|
|
|
part = kControlNoPart;
|
|
|
|
err = SetEventParameter(inEvent, kEventParamControlPart,
|
|
|
|
typeControlPartCode, sizeof(ControlPartCode),
|
|
|
|
&part);
|
|
|
|
printf("hittest %g, %g!\n", where.x, where.y);
|
|
|
|
|
|
|
|
ParameterMissing:
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pascal OSStatus
|
|
|
|
view_handler(EventHandlerCallRef inCallRef,
|
|
|
|
EventRef inEvent,
|
|
|
|
void* inUserData )
|
|
|
|
{
|
|
|
|
OSStatus err = eventNotHandledErr;
|
|
|
|
UInt32 eventClass = GetEventClass(inEvent);
|
|
|
|
UInt32 eventKind = GetEventKind(inEvent);
|
|
|
|
pdfapp_t *pdf = (pdfapp_t *)inUserData;
|
|
|
|
|
|
|
|
switch (eventClass) {
|
|
|
|
case kEventClassHIObject:
|
|
|
|
switch (eventKind) {
|
|
|
|
case kEventHIObjectConstruct:
|
|
|
|
err = view_construct(inEvent);
|
|
|
|
break;
|
|
|
|
case kEventHIObjectInitialize:
|
|
|
|
err = view_initialize(inCallRef, inEvent, pdf);
|
|
|
|
break;
|
|
|
|
case kEventHIObjectDestruct:
|
|
|
|
err = view_destruct(inEvent, pdf);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case kEventClassControl:
|
|
|
|
switch (eventKind) {
|
|
|
|
case kEventControlInitialize:
|
|
|
|
err = noErr;
|
|
|
|
break;
|
|
|
|
case kEventControlDraw:
|
|
|
|
err = view_draw(inEvent, pdf);
|
|
|
|
break;
|
|
|
|
case kEventControlGetData:
|
|
|
|
err = view_get_data(inEvent, pdf);
|
|
|
|
break;
|
|
|
|
case kEventControlSetData:
|
|
|
|
err = view_set_data(inEvent, pdf);
|
|
|
|
break;
|
|
|
|
case kEventControlHitTest:
|
|
|
|
err = view_hittest(inEvent, pdf);
|
|
|
|
break;
|
|
|
|
/*...*/
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
OSStatus
|
|
|
|
view_register(void)
|
|
|
|
{
|
|
|
|
OSStatus err = noErr;
|
|
|
|
static HIObjectClassRef view_ClassRef = NULL;
|
|
|
|
|
|
|
|
if (view_ClassRef == NULL) {
|
|
|
|
EventTypeSpec eventList[] = {
|
|
|
|
{ kEventClassHIObject, kEventHIObjectConstruct },
|
|
|
|
{ kEventClassHIObject, kEventHIObjectInitialize },
|
|
|
|
{ kEventClassHIObject, kEventHIObjectDestruct },
|
|
|
|
|
|
|
|
{ kEventClassControl, kEventControlActivate },
|
|
|
|
{ kEventClassControl, kEventControlDeactivate },
|
|
|
|
{ kEventClassControl, kEventControlDraw },
|
|
|
|
{ kEventClassControl, kEventControlHiliteChanged },
|
|
|
|
{ kEventClassControl, kEventControlHitTest },
|
|
|
|
{ kEventClassControl, kEventControlInitialize },
|
|
|
|
{ kEventClassControl, kEventControlGetData },
|
|
|
|
{ kEventClassControl, kEventControlSetData },
|
|
|
|
};
|
|
|
|
err = HIObjectRegisterSubclass(kViewClassID,
|
|
|
|
kHIViewClassID,
|
|
|
|
NULL,
|
|
|
|
view_handler,
|
|
|
|
GetEventTypeCount(eventList),
|
|
|
|
eventList,
|
|
|
|
NULL,
|
|
|
|
&view_ClassRef);
|
|
|
|
}
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
OSStatus view_create(
|
|
|
|
WindowRef inWindow,
|
|
|
|
const HIRect* inBounds,
|
|
|
|
HIViewRef* outView)
|
|
|
|
{
|
|
|
|
OSStatus err;
|
|
|
|
EventRef event;
|
|
|
|
|
|
|
|
err = view_register();
|
|
|
|
require_noerr(err, CantRegister);
|
|
|
|
|
|
|
|
err = CreateEvent(NULL, kEventClassHIObject, kEventHIObjectInitialize,
|
|
|
|
GetCurrentEventTime(), 0, &event);
|
|
|
|
require_noerr(err, CantCreateEvent);
|
|
|
|
|
|
|
|
if (inBounds != NULL) {
|
|
|
|
err = SetEventParameter(event, 'Boun', typeHIRect, sizeof(HIRect),
|
|
|
|
inBounds);
|
|
|
|
require_noerr(err, CantSetParameter);
|
|
|
|
}
|
|
|
|
|
|
|
|
err = HIObjectCreate(kViewClassID, event, (HIObjectRef*)outView);
|
|
|
|
require_noerr(err, CantCreate);
|
|
|
|
|
|
|
|
if (inWindow != NULL) {
|
|
|
|
HIViewRef root;
|
|
|
|
err = GetRootControl(inWindow, &root);
|
|
|
|
require_noerr(err, CantGetRootView);
|
|
|
|
err = HIViewAddSubview(root, *outView);
|
|
|
|
}
|
|
|
|
CantCreate:
|
|
|
|
CantGetRootView:
|
|
|
|
CantSetParameter:
|
|
|
|
CantCreateEvent:
|
|
|
|
ReleaseEvent(event);
|
|
|
|
CantRegister:
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
IBNibRef nibRef;
|
|
|
|
OSStatus err;
|
|
|
|
WindowRef window;
|
|
|
|
|
|
|
|
pdfapp_t pdf;
|
2007-10-19 23:05:02 +00:00
|
|
|
|
2007-09-29 08:39:35 +00:00
|
|
|
fz_cpudetect();
|
|
|
|
fz_accelerate();
|
|
|
|
|
|
|
|
err = view_register();
|
|
|
|
require_noerr(err, CantRegisterView);
|
|
|
|
|
|
|
|
err = CreateNibReference(CFSTR("main"), &nibRef);
|
|
|
|
printf("err = %d\n", (int)err);
|
|
|
|
require_noerr(err, CantGetNibRef);
|
|
|
|
|
|
|
|
err = SetMenuBarFromNib(nibRef, CFSTR("MenuBar"));
|
|
|
|
require_noerr(err, CantSetMenuBar);
|
2007-10-19 23:05:02 +00:00
|
|
|
|
2007-09-29 08:39:35 +00:00
|
|
|
err = CreateWindowFromNib(nibRef, CFSTR("MainWindow"), &window);
|
|
|
|
require_noerr(err, CantCreateWindow);
|
|
|
|
|
|
|
|
//openpdf(window, gDefaultFilename);
|
|
|
|
|
|
|
|
DisposeNibReference(nibRef);
|
|
|
|
|
|
|
|
pdfapp_init(&pdf);
|
|
|
|
pdfapp_open(&pdf, gDefaultFilename);
|
2007-10-19 23:05:02 +00:00
|
|
|
|
2007-09-29 08:39:35 +00:00
|
|
|
ShowWindow(window);
|
|
|
|
RunApplicationEventLoop();
|
|
|
|
|
|
|
|
pdfapp_close(&pdf);
|
|
|
|
|
|
|
|
CantGetNibRef:
|
|
|
|
CantSetMenuBar:
|
|
|
|
CantCreateWindow:
|
|
|
|
CantRegisterView:
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|