More migration.
This commit is contained in:
parent
705f81d7e4
commit
f95b9c1204
|
@ -0,0 +1,84 @@
|
|||
// 4 december 2014
|
||||
#import <stdlib.h>
|
||||
#import "uipriv_darwin.h"
|
||||
|
||||
NSMutableArray *allocations;
|
||||
|
||||
void initAlloc(void)
|
||||
{
|
||||
allocations = [NSMutableArray new];
|
||||
}
|
||||
|
||||
#define UINT8(p) ((uint8_t *) (p))
|
||||
#define PVOID(p) ((void *) (p))
|
||||
#define EXTRA (sizeof (size_t) + sizeof (const char **))
|
||||
#define DATA(p) PVOID(UINT8(p) + EXTRA)
|
||||
#define BASE(p) PVOID(UINT8(p) - EXTRA)
|
||||
#define SIZE(p) ((size_t *) (p))
|
||||
#define CCHAR(p) ((const char **) (p))
|
||||
#define TYPE(p) CCHAR(UINT8(p) + sizeof (size_t))
|
||||
|
||||
void uninitAlloc(void)
|
||||
{
|
||||
if ([allocations count] == 0) {
|
||||
[allocations release];
|
||||
return;
|
||||
}
|
||||
fprintf(stderr, "[libui] leaked allocations:\n");
|
||||
[allocations enumerateObjectsUsingBlock:^(id obj, NSUInteger index, BOOL *stop) {
|
||||
NSValue *v;
|
||||
void *ptr;
|
||||
|
||||
v = (NSValue *) obj;
|
||||
ptr = [v pointerValue];
|
||||
fprintf(stderr, "[libui] %p %s\n", ptr, *TYPE(ptr));
|
||||
}];
|
||||
complain("either you left something around or there's a bug in libui");
|
||||
}
|
||||
|
||||
void *uiAlloc(size_t size, const char *type)
|
||||
{
|
||||
void *out;
|
||||
|
||||
out = malloc(EXTRA + size);
|
||||
if (out == NULL) {
|
||||
fprintf(stderr, "memory exhausted in uiAlloc()\n");
|
||||
abort();
|
||||
}
|
||||
memset(DATA(out), 0, size);
|
||||
*SIZE(out) = size;
|
||||
*TYPE(out) = type;
|
||||
[allocations addObject:[NSValue valueWithPointer:out]];
|
||||
return DATA(out);
|
||||
}
|
||||
|
||||
void *uiRealloc(void *p, size_t new, const char *type)
|
||||
{
|
||||
void *out;
|
||||
size_t *s;
|
||||
|
||||
if (p == NULL)
|
||||
return uiAlloc(new, type);
|
||||
p = BASE(p);
|
||||
out = realloc(p, EXTRA + new);
|
||||
if (out == NULL) {
|
||||
fprintf(stderr, "memory exhausted in uiRealloc()\n");
|
||||
abort();
|
||||
}
|
||||
s = SIZE(out);
|
||||
if (new <= *s)
|
||||
memset(((uint8_t *) DATA(out)) + *s, 0, new - *s);
|
||||
*s = new;
|
||||
[allocations removeObject:[NSValue valueWithPointer:p]];
|
||||
[allocations addObject:[NSValue valueWithPointer:out]];
|
||||
return DATA(out);
|
||||
}
|
||||
|
||||
void uiFree(void *p)
|
||||
{
|
||||
if (p == NULL)
|
||||
complain("attempt to uiFree(NULL); there's a bug somewhere");
|
||||
p = BASE(p);
|
||||
free(p);
|
||||
[allocations removeObject:[NSValue valueWithPointer:p]];
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
// 6 april 2015
|
||||
#import "uipriv_darwin.h"
|
||||
|
||||
static BOOL canQuit = NO;
|
||||
|
||||
@implementation applicationClass
|
||||
|
||||
// hey look! we're overriding terminate:!
|
||||
// we're going to make sure we can go back to main() whether Cocoa likes it or not!
|
||||
// and just how are we going to do that, hm?
|
||||
// (note: this is called after applicationShouldTerminate:)
|
||||
- (void)terminate:(id)sender
|
||||
{
|
||||
// yes that's right folks: DO ABSOLUTELY NOTHING.
|
||||
// the magic is [NSApp run] will just... stop.
|
||||
|
||||
// well let's not do nothing; let's actually quit our graceful way
|
||||
NSEvent *e;
|
||||
|
||||
// for debugging
|
||||
NSLog(@"in terminate:");
|
||||
|
||||
if (!canQuit)
|
||||
complain("call to [NSApp terminate:] when not ready to terminate");
|
||||
|
||||
[realNSApp() stop:realNSApp()];
|
||||
// stop: won't register until another event has passed; let's synthesize one
|
||||
e = [NSEvent otherEventWithType:NSApplicationDefined
|
||||
location:NSZeroPoint
|
||||
modifierFlags:0
|
||||
timestamp:[[NSProcessInfo processInfo] systemUptime]
|
||||
windowNumber:0
|
||||
context:[NSGraphicsContext currentContext]
|
||||
subtype:0
|
||||
data1:0
|
||||
data2:0];
|
||||
[realNSApp() postEvent:e atStart:NO]; // let pending events take priority (this is what PostQuitMessage() on Windows does so we have to do it here too for parity; thanks to mikeash in irc.freenode.net/#macdev for confirming that this parameter should indeed be NO)
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation appDelegate
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[self.menuManager release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)app
|
||||
{
|
||||
// for debugging
|
||||
NSLog(@"in applicationShouldTerminate:");
|
||||
if (shouldQuit()) {
|
||||
canQuit = YES;
|
||||
// this will call terminate:, which is the same as uiQuit()
|
||||
return NSTerminateNow;
|
||||
}
|
||||
return NSTerminateCancel;
|
||||
}
|
||||
|
||||
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)app
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
uiInitOptions options;
|
||||
|
||||
const char *uiInit(uiInitOptions *o)
|
||||
{
|
||||
options = *o;
|
||||
[applicationClass sharedApplication];
|
||||
// don't check for a NO return; something (launch services?) causes running from application bundles to always return NO when asking to change activation policy, even if the change is to the same activation policy!
|
||||
// see https://github.com/andlabs/ui/issues/6
|
||||
[realNSApp() setActivationPolicy:NSApplicationActivationPolicyRegular];
|
||||
[realNSApp() setDelegate:[appDelegate new]];
|
||||
|
||||
initAlloc();
|
||||
|
||||
// always do this so we always have an application menu
|
||||
appDelegate().menuManager = [menuManager new];
|
||||
[realNSApp() setMainMenu:[appDelegate().menuManager makeMenubar]];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void uiUninit(void)
|
||||
{
|
||||
uninitMenus();
|
||||
// TODO free application delegate
|
||||
// TODO free NSApplication resources (main menu, etc.)
|
||||
uninitAlloc();
|
||||
}
|
||||
|
||||
void uiFreeInitError(const char *err)
|
||||
{
|
||||
}
|
||||
|
||||
void uiMain(void)
|
||||
{
|
||||
[realNSApp() run];
|
||||
}
|
||||
|
||||
void uiQuit(void)
|
||||
{
|
||||
canQuit = YES;
|
||||
[realNSApp() terminate:realNSApp()];
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
// 26 june 2015
|
||||
#import "uipriv_darwin.h"
|
||||
|
||||
char *uiOpenFile(void)
|
||||
{
|
||||
// TODO
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *uiSaveFile(void)
|
||||
{
|
||||
// TODO
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void uiMsgBox(const char *title, const char *description)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
void uiMsgBoxError(const char *title, const char *description)
|
||||
{
|
||||
// TODO
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
// 10 april 2015
|
||||
#import "uipriv_darwin.h"
|
||||
|
||||
char *uiDarwinNSStringToText(NSString *s)
|
||||
{
|
||||
char *out;
|
||||
|
||||
out = strdup([s UTF8String]);
|
||||
if (out == NULL) {
|
||||
fprintf(stderr, "memory exhausted in uiDarwinNSStringToText()\n");
|
||||
abort();
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void uiFreeText(char *s)
|
||||
{
|
||||
free(s);
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
// 7 april 2015
|
||||
#import "uipriv_darwin.h"
|
||||
|
||||
// also fine for NSCells and NSTexts (NSTextViews)
|
||||
void setStandardControlFont(NSControl *control)
|
||||
{
|
||||
[control setFont:[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]]];
|
||||
}
|
||||
|
||||
void disableAutocorrect(NSTextView *tv)
|
||||
{
|
||||
[tv setEnabledTextCheckingTypes:0];
|
||||
[tv setAutomaticDashSubstitutionEnabled:NO];
|
||||
// don't worry about automatic data detection; it won't change stringValue (thanks pretty_function in irc.freenode.net/#macdev)
|
||||
[tv setAutomaticSpellingCorrectionEnabled:NO];
|
||||
[tv setAutomaticTextReplacementEnabled:NO];
|
||||
[tv setAutomaticQuoteSubstitutionEnabled:NO];
|
||||
[tv setAutomaticLinkDetectionEnabled:NO];
|
||||
[tv setSmartInsertDeleteEnabled:NO];
|
||||
}
|
||||
|
||||
void complain(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
fprintf(stderr, "[libui] ");
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(ap);
|
||||
abort();
|
||||
}
|
||||
|
||||
// These are based on measurements from Interface Builder.
|
||||
// These seem to be based on Auto Layout constants, but I don't see an API that exposes these...
|
||||
// This one is 8 for most pairs of controls that I've tried; the only difference is between two pushbuttons, where it's 12...
|
||||
#define macXPadding 8
|
||||
// Likewise, this one appears to be 12 for pairs of push buttons...
|
||||
#define macYPadding 8
|
||||
|
||||
uiSizing *uiDarwinNewSizing(void)
|
||||
{
|
||||
uiSizing *d;
|
||||
|
||||
d = uiNew(uiSizing);
|
||||
d->XPadding = macXPadding;
|
||||
d->YPadding = macYPadding;
|
||||
d->Sys = uiNew(uiSizingSys);
|
||||
return d;
|
||||
}
|
||||
|
||||
void uiFreeSizing(uiSizing *d)
|
||||
{
|
||||
uiFree(d->Sys);
|
||||
uiFree(d);
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
// 29 may 2015
|
||||
#include "ui.h"
|
||||
|
||||
static uintmax_t type_uiMenu = 0;
|
||||
static uintmax_t type_uiMenuItem = 0;
|
||||
|
||||
uintmax_t uiTypeMenu(void)
|
||||
{
|
||||
if (type_uiMenu == 0)
|
||||
type_uiMenu = uiRegisterType("uiMenu", 0, 0);
|
||||
return type_uiMenu;
|
||||
}
|
||||
|
||||
uintmax_t uiTypeMenuItem(void)
|
||||
{
|
||||
if (type_uiMenuItem == 0)
|
||||
type_uiMenuItem = uiRegisterType("uiMenuItem", 0, 0);
|
||||
return type_uiMenuItem;
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
// 5 may 2015
|
||||
#include <string.h>
|
||||
#include "ui.h"
|
||||
#include "uipriv.h"
|
||||
|
||||
struct ptrArray *newPtrArray(void)
|
||||
{
|
||||
return uiNew(struct ptrArray);
|
||||
}
|
||||
|
||||
void ptrArrayDestroy(struct ptrArray *p)
|
||||
{
|
||||
if (p->len != 0)
|
||||
complain("attempt to destroy ptrarray %p while it still has pointers inside", p);
|
||||
if (p->ptrs != NULL) // array was created but nothing was ever put inside
|
||||
uiFree(p->ptrs);
|
||||
uiFree(p);
|
||||
}
|
||||
|
||||
#define grow 32
|
||||
|
||||
void ptrArrayAppend(struct ptrArray *p, void *d)
|
||||
{
|
||||
ptrArrayInsertAt(p, p->len, d);
|
||||
}
|
||||
|
||||
void ptrArrayInsertAt(struct ptrArray *p, uintmax_t i, void *d)
|
||||
{
|
||||
if (i > p->len)
|
||||
complain("index out of range in ptrArrayInsertAt()");
|
||||
if (p->len >= p->cap) {
|
||||
p->cap += grow;
|
||||
p->ptrs = (void **) uiRealloc(p->ptrs, p->cap * sizeof (void *), "void *[]");
|
||||
}
|
||||
// thanks to ValleyBell
|
||||
memmove(&(p->ptrs[i + 1]), &(p->ptrs[i]), (p->len - i) * sizeof (void *));
|
||||
p->ptrs[i] = d;
|
||||
p->len++;
|
||||
}
|
||||
|
||||
void ptrArrayDelete(struct ptrArray *p, uintmax_t i)
|
||||
{
|
||||
if (i >= p->len)
|
||||
complain("index out of range in ptrArrayRemove()");
|
||||
// thanks to ValleyBell
|
||||
memmove(&(p->ptrs[i]), &(p->ptrs[i + 1]), (p->len - i - 1) * sizeof (void *));
|
||||
p->ptrs[p->len - 1] = NULL;
|
||||
p->len--;
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
// 9 may 2015
|
||||
#include "ui.h"
|
||||
#include "uipriv.h"
|
||||
|
||||
static int defaultOnShouldQuit(void *data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int (*onShouldQuit)(void *) = defaultOnShouldQuit;
|
||||
static void *onShouldQuitData;
|
||||
|
||||
void uiOnShouldQuit(int (*f)(void *), void *data)
|
||||
{
|
||||
onShouldQuit = f;
|
||||
onShouldQuitData = data;
|
||||
}
|
||||
|
||||
int shouldQuit(void)
|
||||
{
|
||||
return (*onShouldQuit)(onShouldQuitData);
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
// 17 may 2015
|
||||
#include "ui.h"
|
||||
#include "uipriv.h"
|
||||
|
||||
struct typeinfo {
|
||||
const char *name;
|
||||
uintmax_t parent;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
static struct ptrArray *types = NULL;
|
||||
|
||||
uintmax_t uiRegisterType(const char *name, uintmax_t parent, size_t size)
|
||||
{
|
||||
struct typeinfo *ti;
|
||||
|
||||
if (types == NULL) {
|
||||
types = newPtrArray();
|
||||
// reserve ID 0
|
||||
ptrArrayAppend(types, NULL);
|
||||
}
|
||||
// TODO prevent our size from being smaller than our parent's
|
||||
ti = uiNew(struct typeinfo);
|
||||
ti->name = name;
|
||||
ti->parent = parent;
|
||||
ti->size = size;
|
||||
ptrArrayAppend(types, ti);
|
||||
return types->len - 1;
|
||||
}
|
||||
|
||||
void *uiIsA(void *p, uintmax_t id, int fail)
|
||||
{
|
||||
uiTyped *t;
|
||||
struct typeinfo *ti, *ti2;
|
||||
uintmax_t compareTo;
|
||||
|
||||
if (id == 0 || id >= types->len)
|
||||
complain("invalid type ID given to uiIsA()");
|
||||
t = (uiTyped *) p;
|
||||
compareTo = t->Type;
|
||||
if (compareTo == 0)
|
||||
complain("object %p has no type in uiIsA()", t);
|
||||
for (;;) {
|
||||
if (compareTo >= types->len)
|
||||
complain("invalid type ID in uiIsA()", t);
|
||||
if (compareTo == id)
|
||||
return t;
|
||||
ti = ptrArrayIndex(types, struct typeinfo *, compareTo);
|
||||
if (ti->parent == 0)
|
||||
break;
|
||||
compareTo = ti->parent;
|
||||
}
|
||||
if (fail) {
|
||||
ti = ptrArrayIndex(types, struct typeinfo *, id);
|
||||
ti2 = ptrArrayIndex(types, struct typeinfo *, t->Type);
|
||||
complain("object %p not a %s in uiIsA() (is a %s)", t, ti->name, ti2->name);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void uninitTypes(void)
|
||||
{
|
||||
struct typeinfo *ti;
|
||||
|
||||
if (types == NULL) // never initialized; do nothing
|
||||
return;
|
||||
// the first entry is NULL; get rid of it directly
|
||||
ptrArrayDelete(types, 0);
|
||||
while (types->len != 0) {
|
||||
ti = ptrArrayIndex(types, struct typeinfo *, 0);
|
||||
ptrArrayDelete(types, 0);
|
||||
uiFree(ti);
|
||||
}
|
||||
ptrArrayDestroy(types);
|
||||
}
|
||||
|
||||
uiTyped *newTyped(uintmax_t type)
|
||||
{
|
||||
struct typeinfo *ti;
|
||||
uiTyped *instance;
|
||||
|
||||
if (type == 0 || type >= types->len)
|
||||
complain("invalid type ID given to newTyped()");
|
||||
ti = ptrArrayIndex(types, struct typeinfo *, type);
|
||||
instance = (uiTyped *) uiAlloc(ti->size, ti->name);
|
||||
instance->Type = type;
|
||||
return instance;
|
||||
}
|
Loading…
Reference in New Issue