#include "x3.h" #include "x3common.h" /* Globals for managing sync */ #define VERBOSE #define kX3ViewClassID CFSTR("com.levien.x3.X3View") #define kX3ViewPrivate 'X3_v' /* Some utility-type functions. */ UInt32 x3mkmultichar(const char *s) { int len = strlen(s); int i; UInt32 result = 0; for (i = 0; i < (len > 4 ? 4 : len); i++) result = (result << 8) + (unsigned char)s[i]; for (; i < 4; i++) result = (result << 8) + ' '; return result; } char *x3multicharstr(UInt32 mc, char buf[5]) { int i, len; for (i = 0; i < 4; i++) if (((mc >> (8 * i)) & 0xff) != ' ') break; len = 4 - i; for (i = 0; i < len; i++) buf[i] = (mc >> (24 - 8 * i)) & 0xff; buf[len] = 0; return buf; } void x3widget_init(x3widget *w, const x3type *type) { w->type = type; w->name = NULL; w->parent = NULL; w->var = x3carbonnone; w->u.window = NULL; w->n_children = 0; w->children = NULL; } static x3widget *x3widget_new_container(x3widget *parent, char *name, const x3type *type) { x3widget *result = (x3widget *)malloc(sizeof(x3widget)); x3widget_init(result, type); result->name = name ? strdup(name) : NULL; x3add(parent, result); x3qsizereq(result); return result; } static x3widget *x3widget_new_hiview(x3widget *parent, char *name, const x3type *type, HIViewRef hiview) { x3widget *result = (x3widget *)malloc(sizeof(x3widget)); x3widget_init(result, type); result->name = name ? strdup(name) : NULL; result->var = x3carbonhiview; result->u.hiview = hiview; x3add(parent, result); x3qsizereq(result); return result; } static x3widget *x3widget_new_menu(x3widget *parent, const x3type *type, MenuRef menu) { x3widget *result = (x3widget *)malloc(sizeof(x3widget)); x3widget_init(result, type); result->var = x3carbonmenu; result->u.menu = menu; x3add(parent, result); return result; } static x3widget *x3widget_new_menuitem(x3widget *parent, const x3type *type, int index) { x3widget *result = (x3widget *)malloc(sizeof(x3widget)); x3widget_init(result, type); x3add(parent, result); result->var = x3carbonmenuitem; result->u.menuitem = index; return result; } void x3init(int *pargc, char ***pargv) { ProcessSerialNumber psn; /* Most apps get this done from loading the menu bar from the NIB. Prior to 10.3, there was an undocumented call. This one is official for 10.3 and later. */ GetCurrentProcess(&psn); TransformProcessType(&psn, kProcessTransformToForegroundApplication); SetFrontProcess(&psn); x3initqs(); } void x3main(void) { x3sync(); RunApplicationEventLoop(); } void x3_window_show(x3widget *mainwin) { ControlRef root; #if 0 TransitionWindow(mainwin->u.window, kWindowZoomTransitionEffect, kWindowShowTransitionAction, NULL); #endif #if 0 CreateRootControl(mainwin->u.window, &root); #endif //RepositionWindow(mainwin->u.window, NULL, kWindowCascadeOnMainScreen); ShowWindow(mainwin->u.window); SelectWindow(mainwin->u.window); } static WindowRef x3window_of(x3widget *w) { while (w->parent) w = w->parent; return w->var == x3carbonwindow ? w->u.window : NULL; } typedef struct { x3widget base; x3window_callback callback; void *callback_data; } x3widget_window; pascal OSStatus x3carbonWindowEventHandler(EventHandlerCallRef cr, EventRef inEvent, void *data) { x3widget_window *z = (x3widget_window *)data; OSStatus result = noErr; UInt32 eclass = GetEventClass(inEvent); UInt32 ekind = GetEventKind(inEvent); char multicharbuf[5]; if (eclass == kEventClassCommand && ekind == kEventCommandProcess) { HICommand command; int status; GetEventParameter(inEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommand), NULL, &command); status = z->callback(&z->base, z->callback_data, x3multicharstr(command.commandID, multicharbuf), "command", NULL, NULL); if (status == 1) result = eventNotHandledErr; } else if (eclass = kEventClassWindow && ekind == kEventWindowBoundsChanged) { /* todo: only queue size request when size changes, not just pos */ x3qsizereq(&z->base); x3sync(); } else { printf("My handler is getting called %s %d!\n", x3multicharstr(eclass, multicharbuf), GetEventKind(inEvent)); } result = eventNotHandledErr; return result; } void x3window_sizereq(x3widget *w) { } void x3window_sizealloc(x3widget *w, x3rect *r) { int i; Rect bounds; x3rect child_r; GetWindowBounds(w->u.window, kWindowContentRgn, &bounds); child_r.x0 = 0; child_r.x1 = bounds.right - bounds.left; child_r.y0 = 0; child_r.y1 = bounds.bottom - bounds.top; printf("x3window_sizealloc (%d, %d) - (%d, %d)\n", bounds.left, bounds.top, bounds.right, bounds.bottom); for (i = 0; i < w->n_children; i++) { x3widget *child = w->children[i]; if (child->type->sizealloc) child->type->sizealloc(child, &child_r); child->flags &= ~x3flag_needsizealloc; } } x3type x3windowtype = { x3window_sizereq, x3window_sizealloc, x3add_default }; x3widget *x3window(x3windowflags flags, char *label, x3window_callback callback, void *data) { WindowRef window; Rect bounds = { 100, 100, 400, 600 }; EventHandlerRef handlerRef; WindowAttributes attrs = kWindowCompositingAttribute | kWindowLiveResizeAttribute | kWindowInWindowMenuAttribute | kWindowFrameworkScaledAttribute | kWindowStandardHandlerAttribute; EventTypeSpec windowEvents[] = { { kEventClassCommand, kEventCommandProcess }, //{ kEventClassCommand, kEventCommandUpdateStatus }, //{ kEventClassMouse, kEventMouseDown }, //{ kEventClassWindow, kEventWindowClose }, //{ kEventClassWindow, kEventWindowGetIdealSize }, { kEventClassWindow, kEventWindowBoundsChanged }, //{ kEventClassWindow, kEventWindowGetClickActivation }, //{ kEventClassWindow, kEventWindowContextualMenuSelect } }; CFStringRef cflabel = CFStringCreateWithCString(NULL, label, kCFStringEncodingUTF8); x3widget *result = (x3widget *)malloc(sizeof(x3widget_window)); if (flags & x3window_main) attrs |= kWindowStandardDocumentAttributes; OSStatus err = CreateNewWindow(kDocumentWindowClass, attrs, &bounds, &window); SetWindowTitleWithCFString(window, cflabel); CFRelease(cflabel); x3widget_init(result, &x3windowtype); result->var = x3carbonwindow; result->u.window = window; ((x3widget_window *)result)->callback = callback; ((x3widget_window *)result)->callback_data = data; InstallWindowEventHandler(window, NewEventHandlerUPP(x3carbonWindowEventHandler), sizeof(windowEvents)/sizeof(EventTypeSpec), windowEvents, result, &handlerRef); x3qshow(result); return result; } x3type x3menutype = { NULL, NULL, x3add_default }; x3widget *x3menu(x3widget *parent, char *name) { static int id = 1; /* Note: menu id should probably be kept per-window */ MenuRef menu; CFStringRef cflabel = CFStringCreateWithCString(NULL, name, kCFStringEncodingUTF8); CreateNewMenu(id++, 0, &menu); SetMenuTitleWithCFString(menu, cflabel); CFRelease(cflabel); InsertMenu(menu, 0); return x3widget_new_menu(parent, &x3menutype, menu); } int x3parseshortcut(const char *shortcut, UInt16 *pkey, UInt8 *pmods) { UInt16 key; UInt8 mods = kMenuNoCommandModifier; int i = 0; while (shortcut[i] == '<') { if (!strncmp(shortcut + i, "", 5)) { mods &= ~kMenuNoCommandModifier; i += 5; } else if (!strncmp(shortcut + i, "", 7)) { mods |= kMenuShiftModifier; i += 7; } else if (!strncmp(shortcut + i, "