summaryrefslogtreecommitdiff
path: root/plot/osx/acoccoa.h
blob: ba88cd4e67f1c13a41eab4876a5f9e2bc69b8fc2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402

#ifndef ACOCCOA_H

/* OS X Coccoa support code for Argyll. */
/* In some places we really prefer not to have OS X code */
/* in separate .m files, so we'll do it all from C. */

#include <Carbon/Carbon.h>

#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
# include <objc/runtime.h>
# include <objc/message.h>
#else
# include <objc/objc-runtime.h>

/* Objective-C runtime compatibility functions for < 10.5 */

/* Create a class definition, but don't register it */
Class CreateClassDefinition(const char *name, const char *superclassName) {
	struct objc_class *meta_class;
	struct objc_class *super_class;
	struct objc_class *new_class;
	struct objc_class *root_class;

	// Ensure that the superclass exists and that someone
	// hasn't already implemented a class with the same name
	//
	super_class = (struct objc_class *)objc_lookUpClass(superclassName);
	if (super_class == nil) {
		printf("failed to lookup '%s'\n",superclassName);
		return Nil;
	}

	if (objc_lookUpClass(name) != nil) {
		return Nil;
	}

	// Find the root class
	root_class = super_class;
	while(root_class->super_class != nil)
		root_class = root_class->super_class;

	// Allocate space for the class and its metaclass
	if ((new_class = calloc(2, sizeof(struct objc_class))) == NULL) {
		return Nil;
	}
	meta_class = &new_class[1];

	// setup class
	new_class->isa = meta_class;
	new_class->info = CLS_CLASS;
	meta_class->info = CLS_META;

	// Create a copy of the class name.
	// For efficiency, we have the metaclass and the class itself
	// to share this copy of the name, but this is not a requirement
	// imposed by the runtime.
	if ((new_class->name = strdup(name)) == NULL) {
		free(new_class);
	}
	meta_class->name = new_class->name;

	// Allocate empty method lists.
	// We can add methods later.
	if ((new_class->methodLists = calloc( 1, sizeof(struct objc_method_list *))) == NULL) {
		free((void *)new_class->name);
		free(new_class);
		return Nil;
	}
	*new_class->methodLists = (struct objc_method_list *) -1;
	if ((meta_class->methodLists = calloc(1, sizeof(struct objc_method_list *))) == NULL) {
		free(new_class->methodLists);
		free((void *)new_class->name);
		free(new_class);
		return Nil;
	}
	*meta_class->methodLists = (struct objc_method_list *) -1;

	// Connect the class definition to the class hierarchy:
	// Connect the class to the superclass.
	// Connect the metaclass to the metaclass of the superclass.
	// Connect the metaclass of the metaclass to the metaclass of the root class.
	new_class->super_class = super_class;
	meta_class->super_class = super_class->isa;
	meta_class->isa = (void *)root_class->isa;

	// Set the sizes of the class and the metaclass.
	new_class->instance_size = super_class->instance_size;
	meta_class->instance_size = meta_class->super_class->instance_size;

	return new_class;
}

/* Add an array of methods. Null terminated by name array */
/* We assume that the class is being created, and that there are */
/* no existing methods. */
BOOL registerDynamicMethods(Class cls, const char *mnames[], IMP mimps[], const char *mtypes[]) {
	int i, nmeth;
	struct objc_method_list *methodList;
   
	/* Count the number of methods */
	for (nmeth = 0; mnames[nmeth] != NULL && mnames[nmeth][0] != '\000'; nmeth++)
		;

	/* Allocate an array */
	methodList = malloc(sizeof(struct objc_method_list) + (nmeth-1) * sizeof(struct objc_method));
       
	methodList->method_count = nmeth;
	for (i = 0; i < nmeth; i++) {
		// Get or register the selector for the method name
		SEL methodSEL = SELUID(mnames[i]);
	
		// Registering the method seems to register the selector
		if (ISSELECTOR(methodSEL) == NO) {
			methodSEL = sel_registerName(mnames[i]);
		}
  	 
		// Fill out the method list
		methodList->method_list[i].method_name = methodSEL;
		methodList->method_list[i].method_imp = mimps[i];
		methodList->method_list[i].method_types = strdup(mtypes[i]);
	}
	
	// Register our methods
	class_addMethods((Class)cls, methodList);

	return YES;
}

/* Add an array of instance variables. Null terminated by name array */
/* We assume that the class is being created, and that there are */
/* no existing methods. */
BOOL registerDynamicVariables(Class cls, const char *names[], size_t sizes[], const char *types[]) {
	int i, nvar = 1;
	int vsize;
	struct objc_ivar *ivarp;

	/* Count the number of variables */
	for (nvar = 0; names[nvar] != NULL && names[nvar][0] != '\000'; nvar++)
		;

	vsize = sizeof(struct objc_ivar_list) + (nvar - 1) * sizeof(struct objc_ivar);
	cls->ivars = calloc(vsize, 1);
	cls->ivars->ivar_count = nvar;

	for (i = 0; i < nvar; i++) {
		int abytes;
		ivarp = &cls->ivars->ivar_list[i];
	
		/* Set the variable information */
		ivarp->ivar_name = strdup(names[i]);
		ivarp->ivar_type = strdup(types[i]);
	
		/* Align the offset for this variable to it's size, limiting to 64 bits */
		if ((abytes = sizes[i]) > 8)
			abytes = 8;
		cls->instance_size = (cls->instance_size + abytes-1) & ~(abytes-1);
		ivarp->ivar_offset = (int)cls->instance_size;
		cls->instance_size += sizes[i];
	}

    return YES;
}

#endif /* __MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 */

extern id NSApp;

/* Create a class */
BOOL registerClass(
const char *name,			/* Name of class being created */
const char *supername,		/* Name of superclass */
const char *methnames[],	/* List of method names, empty string terminated */
IMP methimps[],				/* Method implementations */
const char *methsigs[],			/* Method signatures */
const char *varnames[],		/* List of variable names, empty string terminated */
size_t varsizes[],			/* Variable size in bytes */
const char *varsigs[]		/* Variable signatures */
) {
	int i;
	Class nclass;

#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
	nclass = objc_allocateClassPair((Class)objc_getClass(supername), name, 0);
	if (nclass == Nil) {
		return NO;
	}

	for (i = 0; methnames[i] != NULL && methnames[i][0] != '\000'; i++) {
		class_addMethod(nclass, sel_getUid(methnames[i]), methimps[i], methsigs[i]);
	}

	// Should check return value is YES
	for (i = 0; varnames[i] != NULL && varnames[i][0] != '\000'; i++) {
		int asize;
		while( (1 << asize) < varsizes[i] && asize < 8)
			asize++;
		class_addIvar(nclass, varnames[i],  varsizes[i], asize, varsigs[i]); 
	}

	// Must be called after adding instance variable
	objc_registerClassPair(nclass);
#else
	/* Use compat.h functions to do the dirty work */
	// Should check the return value!
	if ((nclass = CreateClassDefinition(name, supername)) == Nil) {
		return NO;
	}

	registerDynamicMethods(nclass, methnames, methimps, methsigs);

	registerDynamicVariables(nclass, varnames, varsizes, varsigs);

	// Register the class with the runtime.
	objc_addClass(nclass);
#endif
	return YES;
}

/* ------------------------------------------------ */
/* One of the primary disadvantages of coding Coccoa in C */
/* is the lack of compatible .h files. We have to make our own.. */

/* ------------------------------------------------ */

/* Foundation stuff */

#ifndef __OBJC__

#if !defined(FSTATIC_INLINE)
# if defined (__GNUC__) && (__GNUC__ == 4)
#  define FSTATIC_INLINE static __inline__ __attribute__((always_inline))
# else
#  define FSTATIC_INLINE static __inline__
# endif
#endif

#ifdef __LP64__
typedef double NSFloat;
#else
typedef float NSFloat;
#endif

typedef struct _NSPoint {
    NSFloat x;
    NSFloat y;
} NSPoint;

FSTATIC_INLINE NSPoint NSMakePoint(NSFloat x, NSFloat y) {
    NSPoint r;
    r.x = x;
    r.y = y;
    return r;
}

typedef struct _NSSize {
    NSFloat width;
    NSFloat height;
} NSSize;

FSTATIC_INLINE NSSize NSMakeSize(NSFloat w, NSFloat h) {
    NSSize r;
    r.width = w;
    r.height = h;
    return r;
}


typedef struct _NSRect {
    NSPoint origin;
    NSSize size;
} NSRect;

FSTATIC_INLINE NSRect NSMakeRect(NSFloat x, NSFloat y, NSFloat w, NSFloat h) {
    NSRect r;
    r.origin.x = x;
    r.origin.y = y;
    r.size.width = w;
    r.size.height = h;
    return r;
}

#endif /* !__OBJC__ */

/* ------------------------------------------------ */
/* Constats for NSString class */

/* 10.4 and latter */
typedef enum {
	NSStringDrawingUsesLineFragmentOrigin        = (1 << 0),
	NSStringDrawingUsesFontLeading               = (1 << 1),
	NSStringDrawingDisableScreenFontSubstitution = (1 << 2),
	NSStringDrawingUsesDeviceMetrics             = (1 << 3),
	NSStringDrawingOneShot                       = (1 << 4),
	NSStringDrawingTruncatesLastVisibleLine      = (1 << 5)
} NSStringDrawingOptions;

/* ------------------------------------------------ */
/* Constats for NSApplication class */

typedef enum {
	NSApplicationPresentationDefault                    = 0,
	NSApplicationPresentationAutoHideDock               = (1 <<  0),
	NSApplicationPresentationHideDock                   = (1 <<  1),
	NSApplicationPresentationAutoHideMenuBar            = (1 <<  2),
	NSApplicationPresentationHideMenuBar                = (1 <<  3),
	NSApplicationPresentationDisableAppleMenu           = (1 <<  4),
	NSApplicationPresentationDisableProcessSwitching    = (1 <<  5),
	NSApplicationPresentationDisableForceQuit           = (1 <<  6),
	NSApplicationPresentationDisableSessionTermination  = (1 <<  7),
	NSApplicationPresentationDisableHideApplication     = (1 <<  8),
	NSApplicationPresentationDisableMenuBarTransparency = (1 <<  9),
	NSApplicationPresentationFullScreen                 = (1 << 10),
	NSApplicationPresentationAutoHideToolbar            = (1 << 11)
} NSApplicationPresentationOptions;

typedef enum {
	NSTerminateCancel = 0,
	NSTerminateNow = 1,
	NSTerminateLater = 2
} NSApplicationTerminateReply;

/* ------------------------------------------------ */
/* Constats for NSWindow class */

enum {
    NSBorderlessWindowMask               = 0,
    NSTitledWindowMask                   = 1 << 0,
    NSClosableWindowMask                 = 1 << 1,
    NSMiniaturizableWindowMask           = 1 << 2,
    NSResizableWindowMask                = 1 << 3,
	NSTexturedBackgroundWindowMask       = 1 << 8
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
	,NSUnscaledWindowMask                = 1 << 11,
	 NSUnifiedTitleAndToolbarWindowMask  = 1 << 12
#endif
};

/* types of window backing store */
typedef enum {
    NSBackingStoreRetained       = 0,
    NSBackingStoreNonretained    = 1,
    NSBackingStoreBuffered       = 2
} NSBackingStoreType;


/* ------------------------------------------------ */
/* Convenience functions */

/* Transform process to interact with descktop */
void transProcess() {
	OSStatus stat;
	ProcessSerialNumber psn = { 0, 0 };

	if (GetCurrentProcess(&psn) != noErr) {
		/* Transform the process so that the desktop interacts with it properly. */
		/* We don't need resources or a bundle if we do this. */
		if (psn.lowLongOfPSN != 0 && (stat = TransformProcessType(&psn,
			               kProcessTransformToForegroundApplication)) != noErr)
			fprintf(stderr,"TransformProcess failed with code %d\n",stat);
	}
}

/* Send a message to the object */
#define sendMsg(oid, msg, ...) objc_msgSend(oid, sel_getUid(msg), ##__VA_ARGS__)

/* alloc and init a new object */
id newObject(const char *cname) {
	id rv;
	rv = objc_msgSend(objc_getClass(cname), sel_getUid("alloc"));
	rv = objc_msgSend(rv, sel_getUid("init"));
	return rv;
}
/* release an object */
void delObject(id oid) {
	objc_msgSend(oid, sel_getUid("release"));
}

/* dealloc super */
void delObjectSuper(id oid) {
	struct objc_super ss;
	ss.receiver = oid;
#ifdef __OBJC__
	ss.super_class = sendMsg(oid, "superclass");
#else
	ss.class = (Class)sendMsg(oid, "superclass");
#endif
	objc_msgSendSuper(&ss, sel_getUid("dealloc"));
}

/* Create an NSString from a C string */
id newNSString(const char *cstr) {
	id str;

	str = objc_msgSend(objc_getClass("NSString"), sel_getUid("alloc"));
	str = objc_msgSend(str, sel_getUid("initWithUTF8String:"), cstr);

	return str;
}

#define ACOCCOA_H
#endif /* ACOCCOA_H */