The R Project SVN R

Rev

Rev 44003 | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 44003 Rev 45017
Line 47... Line 47...
47
 *  Initialise the base_object and set the list to be empty.
47
 *  Initialise the base_object and set the list to be empty.
48
 */
48
 */
49
PROTECTED
49
PROTECTED
50
void init_objects(void)
50
void init_objects(void)
51
{
51
{
52
	if (base_object)
52
    if (base_object)
53
		return;
53
	return;
54
 
54
 
55
	base_object = create(objinfo);
55
    base_object = create(objinfo);
56
 
56
 
57
	if (! base_object)
57
    if (! base_object)
58
		apperror("Out of memory (init_objects)!");
58
	apperror("Out of memory (init_objects)!");
59
 
59
 
60
	base_object->kind = BaseObject;
60
    base_object->kind = BaseObject;
61
	base_object->next = base_object->prev = base_object;
61
    base_object->next = base_object->prev = base_object;
62
	base_object->parent = base_object->child = NULL;
62
    base_object->parent = base_object->child = NULL;
63
}
63
}
64
 
64
 
65
static void add_object(object obj, object parent)
65
static void add_object(object obj, object parent)
66
{
66
{
67
	/* All objects have a parent. */
67
    /* All objects have a parent. */
68
	if (! parent)
68
    if (! parent)
69
		parent = base_object;
69
	parent = base_object;
70
 
70
 
71
	if (parent->child)
71
    if (parent->child)
72
	{	/* add to end of child circularly linked list */
72
    {	/* add to end of child circularly linked list */
73
		obj->prev = parent->child->prev;
73
	obj->prev = parent->child->prev;
74
		obj->next = parent->child;
74
	obj->next = parent->child;
75
		obj->prev->next = obj;
75
	obj->prev->next = obj;
76
		obj->next->prev = obj;
76
	obj->next->prev = obj;
77
	} else {
77
    } else {
78
		/* create new child list */
78
	/* create new child list */
79
		obj->next = obj->prev = obj;
79
	obj->next = obj->prev = obj;
80
		parent->child = obj;
80
	parent->child = obj;
81
	}
81
    }
82
	obj->parent = parent;
82
    obj->parent = parent;
83
 
83
 
84
#if DEBUG
84
#if DEBUG
85
	print_object_list();
85
    print_object_list();
86
#endif
86
#endif
87
}
87
}
88
 
88
 
89
static void remove_object(object obj)
89
static void remove_object(object obj)
90
{
90
{
91
	if ((obj->next) && (obj->next != obj)) {
91
    if ((obj->next) && (obj->next != obj)) {
92
		obj->prev->next = obj->next;
92
	obj->prev->next = obj->next;
93
		obj->next->prev = obj->prev;
93
	obj->next->prev = obj->prev;
94
	} else {
94
    } else {
95
		obj->next = obj->prev = NULL;
95
	obj->next = obj->prev = NULL;
96
	}
96
    }
97
 
97
 
98
	if (obj->parent)
98
    if (obj->parent)
99
		if (obj->parent->child == obj)
99
	if (obj->parent->child == obj)
100
			obj->parent->child = obj->next;
100
	    obj->parent->child = obj->next;
101
}
101
}
102
 
102
 
103
/*
103
/*
104
 *  Bring an object to the front of its sibling list.
104
 *  Bring an object to the front of its sibling list.
105
 *  Useful for keeping track of which window is up front.
105
 *  Useful for keeping track of which window is up front.
106
 */
106
 */
107
PROTECTED
107
PROTECTED
108
void move_to_front(object obj)
108
void move_to_front(object obj)
109
{
109
{
110
	object parent = obj->parent;
110
    object parent = obj->parent;
111
	remove_object(obj);	 /* Remove it so as to reorder list. */
111
    remove_object(obj);	 /* Remove it so as to reorder list. */
112
	add_object(obj, parent); /* Add to end of list. */
112
    add_object(obj, parent); /* Add to end of list. */
113
	parent->child = obj;	 /* Move to front. */
113
    parent->child = obj;	 /* Move to front. */
114
}
114
}
115
 
115
 
116
/*
116
/*
117
 *  Call a function on all objects in a sibling list.
117
 *  Call a function on all objects in a sibling list.
118
 *  Only applies up to the end of the list, i.e. up to and
118
 *  Only applies up to the end of the list, i.e. up to and
119
 *  including the last element in the circular list.
119
 *  including the last element in the circular list.
120
 *  Used to disable or enable windows when modal windows are used.
120
 *  Used to disable or enable windows when modal windows are used.
121
 */
121
 */
122
void apply_to_list(object first, actionfn fn)
122
void apply_to_list(object first, actionfn fn)
123
{
123
{
124
	object start = first->parent->child;
124
    object start = first->parent->child;
125
	object obj = first;
125
    object obj = first;
126
 
126
 
127
	do {
127
    do {
128
		fn(obj);
128
	fn(obj);
129
		obj = obj->next;
129
	obj = obj->next;
130
	} while (obj != start);
130
    } while (obj != start);
131
}
131
}
132
 
132
 
133
/*
133
/*
134
 *  When objects are deleted using del() they are added to
134
 *  When objects are deleted using del() they are added to
135
 *  the end of a circular list, which is traversed at the end
135
 *  the end of a circular list, which is traversed at the end
Line 137... Line 137...
137
 *  the objects in that list. The del_base object is at
137
 *  the objects in that list. The del_base object is at
138
 *  the head of this list and is the first object to be
138
 *  the head of this list and is the first object to be
139
 *  deleted.
139
 *  deleted.
140
 */
140
 */
141
 
141
 
142
	typedef struct delnode delnode;
142
typedef struct delnode delnode;
143
	struct delnode {
143
struct delnode {
144
		object    obj;	/* object to be deleted */
144
    object    obj;	/* object to be deleted */
145
		delnode * next;	/* next object in the list */
145
    delnode * next;	/* next object in the list */
146
		delnode * prev; /* previous object in the list */
146
    delnode * prev; /* previous object in the list */
147
	};
147
};
148
 
148
 
149
	static delnode * del_base = NULL;
149
static delnode * del_base = NULL;
150
 
150
 
151
/*
151
/*
152
 *  Reduce the reference count of an object:
152
 *  Reduce the reference count of an object:
153
 *  A by-product of this might be that the object is added
153
 *  A by-product of this might be that the object is added
154
 *  to the list of objects to be deleted. If the refcount
154
 *  to the list of objects to be deleted. If the refcount
Line 159... Line 159...
159
 *  any circumstances (e.g. default fonts and cursors).
159
 *  any circumstances (e.g. default fonts and cursors).
160
 */
160
 */
161
PROTECTED
161
PROTECTED
162
void decrease_refcount(object obj)
162
void decrease_refcount(object obj)
163
{
163
{
164
	delnode *new_node;
164
    delnode *new_node;
165
 
165
 
166
	if (! obj)
166
    if (! obj)
167
		return;
167
	return;
168
	if (obj->refcount <= 0)
168
    if (obj->refcount <= 0)
169
		return;	/* cannot delete this object */
169
	return;	/* cannot delete this object */
170
	obj->refcount--;
170
    obj->refcount--;
171
	if (obj->refcount != 0)
171
    if (obj->refcount != 0)
172
		return;	/* don't delete this object */
172
	return;	/* don't delete this object */
173
 
173
 
174
	/* the refcount must now be zero, so add to list */
174
    /* the refcount must now be zero, so add to list */
175
	new_node = create(delnode);
175
    new_node = create(delnode);
176
	new_node->obj = obj;
176
    new_node->obj = obj;
177
	if (del_base) {
177
    if (del_base) {
178
		/* add to end of circular list */
178
	/* add to end of circular list */
179
		new_node->prev = del_base->prev;
179
	new_node->prev = del_base->prev;
180
		new_node->next = del_base;
180
	new_node->next = del_base;
181
		new_node->prev->next = new_node;
181
	new_node->prev->next = new_node;
182
		new_node->next->prev = new_node;
182
	new_node->next->prev = new_node;
183
	}
183
    }
184
	else {
184
    else {
185
		/* create new circular list */
185
	/* create new circular list */
186
		new_node->next = new_node->prev = new_node;
186
	new_node->next = new_node->prev = new_node;
187
		del_base = new_node;
187
	del_base = new_node;
188
	}
188
    }
189
}
189
}
190
 
190
 
191
/*
191
/*
192
 *  Increase the reference count of an object.
192
 *  Increase the reference count of an object.
193
 *  Avoids increases a negative number (they're special).
193
 *  Avoids increases a negative number (they're special).
194
 */
194
 */
195
PROTECTED
195
PROTECTED
196
void increase_refcount(object obj)
196
void increase_refcount(object obj)
197
{
197
{
198
	if (obj && (obj->refcount >= 0))
198
    if (obj && (obj->refcount >= 0))
199
		obj->refcount ++;
199
	obj->refcount ++;
200
}
200
}
201
 
201
 
202
/*
202
/*
203
 *  Protect an object from being deleted. This function is
203
 *  Protect an object from being deleted. This function is
204
 *  used to protect default fonts and cursors from deletion.
204
 *  used to protect default fonts and cursors from deletion.
Line 206... Line 206...
206
 *  special value -1.
206
 *  special value -1.
207
 */
207
 */
208
PROTECTED
208
PROTECTED
209
void protect_object(object obj)
209
void protect_object(object obj)
210
{
210
{
211
	if (obj)
211
    if (obj)
212
		obj->refcount = -1;
212
	obj->refcount = -1;
213
}
213
}
214
 
214
 
215
/*
215
/*
216
 *  Remove a delnode from the deletion list.
216
 *  Remove a delnode from the deletion list.
217
 *  Fix del_base to point correctly.
217
 *  Fix del_base to point correctly.
218
 */
218
 */
219
static void remove_delnode(delnode *n)
219
static void remove_delnode(delnode *n)
220
{
220
{
221
	/* remove and destroy this node */
221
    /* remove and destroy this node */
222
	n->prev->next = n->next;
222
    n->prev->next = n->next;
223
	n->next->prev = n->prev;
223
    n->next->prev = n->prev;
224
	if (n == n->next) /* nothing in list */
224
    if (n == n->next) /* nothing in list */
225
		del_base = NULL;
225
	del_base = NULL;
226
	else if (n == del_base)	/* move head */
226
    else if (n == del_base)	/* move head */
227
		del_base = n->next;
227
	del_base = n->next;
228
	discard(n);
228
    discard(n);
229
}
229
}
230
 
230
 
231
/*
231
/*
232
 *  Remove all copies of an object from the deletion list
232
 *  Remove all copies of an object from the deletion list
233
 *  after that object has been deleted.
233
 *  after that object has been deleted.
234
 *  This occurs as a by-product of object deletion, and
234
 *  This occurs as a by-product of object deletion, and
235
 *  ensures that an object cannot be deleted twice.
235
 *  ensures that an object cannot be deleted twice.
236
 */
236
 */
237
static void remove_deleted_object(object obj)
237
static void remove_deleted_object(object obj)
238
{
238
{
239
	delnode *last;
239
    delnode *last;
240
	delnode *next;
240
    delnode *next;
241
	delnode *n;
241
    delnode *n;
242
 
242
 
243
	if (! del_base)
243
    if (! del_base)
244
		return;
244
	return;
245
	next = del_base;
245
    next = del_base;
246
	last = del_base->prev;
246
    last = del_base->prev;
247
	do {
247
    do {
248
		n = next;
248
	n = next;
249
		next = n->next;
249
	next = n->next;
250
		if (n->obj == obj) {
250
	if (n->obj == obj) {
251
			/* remove and destroy this node */
251
	    /* remove and destroy this node */
252
			remove_delnode(n);
252
	    remove_delnode(n);
253
		}
253
	}
254
	} while (n != last);
254
    } while (n != last);
255
}
255
}
256
 
256
 
257
/*
257
/*
258
 *  Traverse the deletion list and delete every object found there.
258
 *  Traverse the deletion list and delete every object found there.
259
 *  This function repeatedly deletes del_base until that value is null.
259
 *  This function repeatedly deletes del_base until that value is null.
Line 261... Line 261...
261
 */
261
 */
262
static void del_object(object obj);	/* declaration */
262
static void del_object(object obj);	/* declaration */
263
PROTECTED
263
PROTECTED
264
void deletion_traversal(void)
264
void deletion_traversal(void)
265
{
265
{
266
	static int level = 0;
266
    static int level = 0;
267
	object obj;
267
    object obj;
268
 
268
 
269
	level++;
269
    level++;
270
	if (level == 1) {
270
    if (level == 1) {
271
		while (del_base) {
271
	while (del_base) {
272
			obj = del_base->obj;
272
	    obj = del_base->obj;
273
			if (obj) {
273
	    if (obj) {
274
				if (obj->refcount == 0)
274
		if (obj->refcount == 0)
275
					del_object(obj);
275
		    del_object(obj);
276
				else
276
		else
277
					remove_deleted_object(obj);
277
		    remove_deleted_object(obj);
278
			}
278
	    }
279
		}
-
 
280
	}
279
	}
-
 
280
    }
281
	level--;
281
    level--;
282
}
282
}
283
 
283
 
284
/*
284
/*
285
 *  Keep application global variables up-to-date.
285
 *  Keep application global variables up-to-date.
286
 */
286
 */
287
static void update_app_globals(object obj)
287
static void update_app_globals(object obj)
288
{
288
{
289
	if (obj->drawstate == current)
289
    if (obj->drawstate == current)
290
		current = & app_drawstate;
290
	current = & app_drawstate;
291
	if (obj == current->dest)
291
    if (obj == current->dest)
292
		current->dest = NULL;
292
	current->dest = NULL;
293
	if (obj == current_window)
293
    if (obj == current_window)
294
		current_window = NULL;
294
	current_window = NULL;
295
	if (obj == current_menubar)
295
    if (obj == current_menubar)
296
		current_menubar = NULL;
296
	current_menubar = NULL;
297
	if (obj == current_menu)
297
    if (obj == current_menu)
298
		current_menu = NULL;
298
	current_menu = NULL;
299
	if (obj == current->crsr)
299
    if (obj == current->crsr)
300
		current->crsr = ArrowCursor;
300
	current->crsr = ArrowCursor;
301
	if (obj == current->fnt)
301
    if (obj == current->fnt)
302
		current->fnt = SystemFont;
302
	current->fnt = SystemFont;
303
}
303
}
304
 
304
 
305
/*
305
/*
306
 *  Object deletion functions:
306
 *  Object deletion functions:
307
 *
307
 *
Line 314... Line 314...
314
 *    releasing the memory used by the object from the heap.
314
 *    releasing the memory used by the object from the heap.
315
 */
315
 */
316
static void free_private(object obj)
316
static void free_private(object obj)
317
{
317
{
318
#if DEBUG
318
#if DEBUG
319
	print_object_list();
319
    print_object_list();
320
#endif
320
#endif
321
	/* Remove from object hierachy. */
321
    /* Remove from object hierachy. */
322
	remove_object(obj);
322
    remove_object(obj);
323
	/* Call user destructor first. */
323
    /* Call user destructor first. */
324
	if ((obj->call) && (obj->call->die))
324
    if ((obj->call) && (obj->call->die))
325
		obj->call->die(obj);
325
	obj->call->die(obj);
326
	/* Fix application variables. */
326
    /* Fix application variables. */
327
	update_app_globals(obj);
327
    update_app_globals(obj);
328
	/* Free drawing context. */
328
    /* Free drawing context. */
329
	del_context(obj);
329
    del_context(obj);
330
	/* Then call private destructor. */
330
    /* Then call private destructor. */
331
	if (obj->die)
331
    if (obj->die)
332
		obj->die(obj);
332
	obj->die(obj);
333
	/* Remove object from deletion list. */
333
    /* Remove object from deletion list. */
334
	remove_deleted_object(obj);
334
    remove_deleted_object(obj);
335
}
335
}
336
 
336
 
337
static void free_object(object obj)
337
static void free_object(object obj)
338
{
338
{
339
	free_private(obj);
339
    free_private(obj);
340
 
340
 
341
	/* Free any extra internal info. */
341
    /* Free any extra internal info. */
342
	if (obj->drawstate)
342
    if (obj->drawstate)
343
		discard(obj->drawstate);
343
	discard(obj->drawstate);
344
	if (obj->text)
344
    if (obj->text)
345
		discard(obj->text);
345
	discard(obj->text);
346
	if (obj->call)
346
    if (obj->call)
347
		discard(obj->call);
347
	discard(obj->call);
348
	discard(obj);
348
    discard(obj);
349
}
349
}
350
 
350
 
351
/*
351
/*
352
 *  Private recursive object destructor. Deletes child objects
352
 *  Private recursive object destructor. Deletes child objects
353
 *  first and then the top-most object specified.
353
 *  first and then the top-most object specified.
354
 *  This function is called during the deletion_traversal function,
354
 *  This function is called during the deletion_traversal function,
355
 *  which is called at the end of each doevent call.
355
 *  which is called at the end of each doevent call.
356
 */
356
 */
357
static void del_object(object obj)
357
static void del_object(object obj)
358
{
358
{
359
	while (obj->child)
359
    while (obj->child)
360
		del_object(obj->child);
360
	del_object(obj->child);
361
	free_object(obj);
361
    free_object(obj);
362
}
362
}
363
 
363
 
364
/*
364
/*
365
 *  Quick destruction function when terminating application.
365
 *  Quick destruction function when terminating application.
366
 *  Make Windows happy by releasing memory which it otherwise
366
 *  Make Windows happy by releasing memory which it otherwise
Line 369... Line 369...
369
 *  del_object or free_object). This works fine, and avoids
369
 *  del_object or free_object). This works fine, and avoids
370
 *  problems when calling exitapp() in callbacks.
370
 *  problems when calling exitapp() in callbacks.
371
 */
371
 */
372
static void free_memory(object obj)
372
static void free_memory(object obj)
373
{
373
{
374
	if (obj->kind == WindowObject)
374
    if (obj->kind == WindowObject)
375
		hide(obj);
375
	hide(obj);
376
	while(obj->child)
376
    while(obj->child)
377
		free_memory(obj->child);
377
	free_memory(obj->child);
378
	free_private(obj);
378
    free_private(obj);
379
}
379
}
380
 
380
 
381
PROTECTED
381
PROTECTED
382
void finish_objects(void)
382
void finish_objects(void)
383
{
383
{
384
	free_memory(base_object);
384
    free_memory(base_object);
385
	base_object = NULL;
385
    base_object = NULL;
386
}
386
}
387
 
387
 
388
/*
388
/*
389
 *  Create and return a new object with a refcount of 1.
389
 *  Create and return a new object with a refcount of 1.
390
 *  The object is Transparent and may have some other
390
 *  The object is Transparent and may have some other
391
 *  structures associated with it (depending on its kind).
391
 *  structures associated with it (depending on its kind).
392
 */
392
 */
393
PROTECTED
393
PROTECTED
394
object new_object(int kind, HANDLE handle, object parent)
394
object new_object(int kind, HANDLE handle, object parent)
395
{
395
{
396
	object obj;
396
    object obj;
397
 
397
 
398
	/* create the object */
398
    /* create the object */
399
	obj = create(objinfo);
399
    obj = create(objinfo);
400
	if (! obj)
400
    if (! obj)
401
		return NULL;
401
	return NULL;
402
        obj->menubar = obj->popup = obj->toolbar = NULL;
402
    obj->menubar = obj->popup = obj->toolbar = NULL;
403
        obj->status[0] = '\0';
403
    obj->status[0] = '\0';
404
	if (kind & ControlObject)
404
    if (kind & ControlObject)
405
	{
405
    {
406
		obj->call = create(callinfo);
406
	obj->call = create(callinfo);
407
		if (! obj->call) {
407
	if (! obj->call) {
408
			discard(obj);
408
	    discard(obj);
409
			return NULL;
409
	    return NULL;
410
		}
410
	}
411
	}
411
    }
412
 
412
 
413
	obj->refcount = 1;
413
    obj->refcount = 1;
414
	obj->kind = kind;
414
    obj->kind = kind;
415
	obj->handle = handle;
415
    obj->handle = handle;
416
	obj->bg = Transparent;
416
    obj->bg = Transparent;
417
 
417
 
418
	add_object(obj, parent);
418
    add_object(obj, parent);
419
 
419
 
420
	return obj;
420
    return obj;
421
}
421
}
422
 
422
 
423
/*
423
/*
424
 *  Return the object if it matches the spec.
424
 *  Return the object if it matches the spec.
425
 */
425
 */
426
static object match_object(object obj, HANDLE handle, int id, int key)
426
static object match_object(object obj, HANDLE handle, int id, int key)
427
{
427
{
428
	if ((handle != 0) && (obj->handle == handle))
428
    if ((handle != 0) && (obj->handle == handle))
429
		return obj;
429
	return obj;
430
	if ((id != 0) && (obj->id == id))
430
    if ((id != 0) && (obj->id == id))
431
		return obj;
431
	return obj;
432
	if ((key != 0) && (obj->key == key)
432
    if ((key != 0) && (obj->key == key)
433
		&& (obj->kind == MenuitemObject))
433
	&& (obj->kind == MenuitemObject))
434
		return obj;
434
	return obj;
435
	return NULL;
435
    return NULL;
436
}
436
}
437
 
437
 
438
/*
438
/*
439
 *  Perform the multi-child tree traversal.
439
 *  Perform the multi-child tree traversal.
440
 */
440
 */
441
object tree_search(object top, HANDLE handle, int id, int key)
441
object tree_search(object top, HANDLE handle, int id, int key)
442
{
442
{
443
	object obj, first_object, found = NULL;
443
    object obj, first_object, found = NULL;
444
 
444
 
445
	if ((! top) || (! top->child))
445
    if ((! top) || (! top->child))
446
		return NULL;
446
	return NULL;
447
 
447
 
448
	first_object = top->child;
448
    first_object = top->child;
449
	obj = first_object;
449
    obj = first_object;
450
 
450
 
451
	while (obj != top)
451
    while (obj != top)
452
	{
452
    {
453
		found = match_object(obj, handle, id, key);
453
	found = match_object(obj, handle, id, key);
454
		if (found)
454
	if (found)
455
			break;
455
	    break;
456
 
456
 
457
		if (obj->child)
457
	if (obj->child)
458
		{	/* object has children - descend tree */
458
	{	/* object has children - descend tree */
459
			first_object = obj->child;
459
	    first_object = obj->child;
460
			obj = first_object;
460
	    obj = first_object;
461
			continue;
461
	    continue;
462
		}
462
	}
463
		else
463
	else
464
		{	/* object is childless - go to next object */
464
	{	/* object is childless - go to next object */
465
			obj = obj->next;
465
	    obj = obj->next;
466
		}
466
	}
467
 
467
 
468
		while (obj == first_object)
468
	while (obj == first_object)
469
		{	/* back at first object in sibling list */
469
	{	/* back at first object in sibling list */
470
			/* climb the tree */
470
	    /* climb the tree */
471
			obj = obj->parent;
471
	    obj = obj->parent;
472
			if (obj == top)
472
	    if (obj == top)
473
				break;
473
		break;
474
			if (obj->parent) {
474
	    if (obj->parent) {
475
				first_object = obj->parent->child;
475
		first_object = obj->parent->child;
476
				obj = obj->next;
476
		obj = obj->next;
477
			}
477
	    }
478
			else
478
	    else
479
				break;
479
		break;
480
		}
-
 
481
	}
480
	}
-
 
481
    }
482
 
482
 
483
	return found;
483
    return found;
484
}
484
}
485
 
485
 
486
PROTECTED
486
PROTECTED
487
object find_object(HANDLE handle, int id, int key)
487
object find_object(HANDLE handle, int id, int key)
488
{
488
{
489
	return tree_search(base_object, handle, id, key);
489
    return tree_search(base_object, handle, id, key);
490
}
490
}
491
 
491
 
492
/*
492
/*
493
 *  Write the tree structure to disk to examine it.
493
 *  Write the tree structure to disk to examine it.
494
 */
494
 */
495
#if DEBUG
495
#if DEBUG
496
static void print_drawstate(FILE *f, drawstate d, object obj)
496
static void print_drawstate(FILE *f, drawstate d, object obj)
497
{
497
{
498
	fprintf(f, "%lu: [", ((unsigned long)d));
498
    fprintf(f, "%lu: [", ((unsigned long)d));
499
	if (!d)
499
    if (!d)
500
		return;
500
	return;
501
	fprintf(f, "drawto=%s", (! d->drawing) ? "null" :
501
    fprintf(f, "drawto=%s", (! d->drawing) ? "null" :
502
		(d->drawing == obj) ? "this" : "??");
502
	    (d->drawing == obj) ? "this" : "??");
503
	fprintf(f, ", 0x%8.8lX", (unsigned long)d->rgb);
503
    fprintf(f, ", 0x%8.8lX", (unsigned long)d->rgb);
504
	fprintf(f, ", %s", getname(d->font));
504
    fprintf(f, ", %s", getname(d->font));
505
	fprintf(f, ", %s", getname(d->cursor));
505
    fprintf(f, ", %s", getname(d->cursor));
506
	fprintf(f, ", (%d,%d)", d->point.x, d->point.y);
506
    fprintf(f, ", (%d,%d)", d->point.x, d->point.y);
507
	fprintf(f, ", width=%d", d->linewidth);
507
    fprintf(f, ", width=%d", d->linewidth);
508
	fprintf(f, "]");
508
    fprintf(f, "]");
509
}
509
}
510
 
510
 
511
static void print_objects(FILE *f, object obj, int indent)
511
static void print_objects(FILE *f, object obj, int indent)
512
{
512
{
513
	object child;
513
    object child;
514
	char *s;
514
    char *s;
515
	int i;
515
    int i;
516
 
516
 
517
	for (i=0; i<indent; i++)
517
    for (i=0; i<indent; i++)
518
		fprintf(f, " ");
518
	fprintf(f, " ");
519
	if (! obj) {
519
    if (! obj) {
520
		fprintf(f, "Null Object\n");
520
	fprintf(f, "Null Object\n");
521
		return;
521
	return;
522
	}
522
    }
523
	switch(obj->kind) {
523
    switch(obj->kind) {
524
	case BaseObject:	s = "BaseObject"; break;
524
    case BaseObject:	s = "BaseObject"; break;
525
	case ControlObject:	s = "ControlObject"; break;
525
    case ControlObject:	s = "ControlObject"; break;
526
	case WindowObject:	s = "WindowObject"; break;
526
    case WindowObject:	s = "WindowObject"; break;
527
	case BitmapObject:	s = "BitmapObject"; break;
527
    case BitmapObject:	s = "BitmapObject"; break;
528
	case CursorObject:	s = "CursorObject"; break;
528
    case CursorObject:	s = "CursorObject"; break;
529
	case FontObject:	s = "FontObject"; break;
529
    case FontObject:	s = "FontObject"; break;
530
	case UserObject:	s = "UserObject"; break;
530
    case UserObject:	s = "UserObject"; break;
531
	case LabelObject:	s = "LabelObject"; break;
531
    case LabelObject:	s = "LabelObject"; break;
532
	case ButtonObject:	s = "ButtonObject"; break;
532
    case ButtonObject:	s = "ButtonObject"; break;
533
	case CheckboxObject:	s = "CheckboxObject"; break;
533
    case CheckboxObject:	s = "CheckboxObject"; break;
534
	case RadioObject:	s = "RadioObject"; break;
534
    case RadioObject:	s = "RadioObject"; break;
535
	case ScrollbarObject:	s = "ScrollbarObject"; break;
535
    case ScrollbarObject:	s = "ScrollbarObject"; break;
536
	case FieldObject:	s = "FieldObject"; break;
536
    case FieldObject:	s = "FieldObject"; break;
537
	case TextboxObject:	s = "TextboxObject"; break;
537
    case TextboxObject:	s = "TextboxObject"; break;
538
	case ListboxObject:	s = "ListboxObject"; break;
538
    case ListboxObject:	s = "ListboxObject"; break;
539
	case ProgressbarObject:	s = "ProgressbarObject"; break;
539
    case ProgressbarObject:	s = "ProgressbarObject"; break;
540
	case MultilistObject:	s = "MultilistObject"; break;
540
    case MultilistObject:	s = "MultilistObject"; break;
541
	case DroplistObject:	s = "DroplistObject"; break;
541
    case DroplistObject:	s = "DroplistObject"; break;
542
	case DropfieldObject:	s = "DropfieldObject"; break;
542
    case DropfieldObject:	s = "DropfieldObject"; break;
543
	case MenubarObject:	s = "MenubarObject"; break;
543
    case MenubarObject:	s = "MenubarObject"; break;
544
	case MenuObject:	s = "MenuObject"; break;
544
    case MenuObject:	s = "MenuObject"; break;
545
	case MenuitemObject:	s = "MenuitemObject"; break;
545
    case MenuitemObject:	s = "MenuitemObject"; break;
546
	default: s = "Unknown Object???"; break;
546
    default: s = "Unknown Object???"; break;
547
	}
547
    }
548
	fprintf(f, "%s", s);
548
    fprintf(f, "%s", s);
549
	if (obj->text)
549
    if (obj->text)
550
		fprintf(f, ", text: \"%s\"", obj->text);
550
	fprintf(f, ", text: \"%s\"", obj->text);
551
	/*
551
    /*
552
	if (! obj->child)
552
      if (! obj->child)
553
		fprintf(f, ", child: null");
553
      fprintf(f, ", child: null");
554
	*/
554
    */
555
	if (! obj->handle)
555
    if (! obj->handle)
556
		fprintf(f, ", handle: null");
556
	fprintf(f, ", handle: null");
557
	if (obj->drawstate) {
557
    if (obj->drawstate) {
558
		fprintf(f, ", drawstate ");
558
	fprintf(f, ", drawstate ");
559
		print_drawstate(f, obj->drawstate, obj);
559
	print_drawstate(f, obj->drawstate, obj);
560
	}
560
    }
561
	fprintf(f, "\n");
561
    fprintf(f, "\n");
562
 
562
 
563
	indent += 2;
563
    indent += 2;
564
	child = obj->child;
564
    child = obj->child;
565
	while (child) {
565
    while (child) {
566
		print_objects(f, child, indent); /* recursive */
566
	print_objects(f, child, indent); /* recursive */
567
		child = child->next;
567
	child = child->next;
568
		if (child == obj->child) /* if back at start of list */
568
	if (child == obj->child) /* if back at start of list */
569
			break;
569
	    break;
570
	}
570
    }
571
	fflush(f);
571
    fflush(f);
572
}
572
}
573
 
573
 
574
PROTECTED
574
PROTECTED
575
void print_object_list(void)
575
void print_object_list(void)
576
{
576
{
577
	static int start_again = 1;
577
    static int start_again = 1;
578
	char *mode = "at"; /* to ensure text mode */
578
    char *mode = "at"; /* to ensure text mode */
579
	FILE *f;
579
    FILE *f;
580
 
580
 
581
	if (! app_initialised)
581
    if (! app_initialised)
582
		return;
582
	return;
583
	if (start_again) {
583
    if (start_again) {
584
		mode = "w";
584
	mode = "w";
585
		start_again = 0;
585
	start_again = 0;
586
	}
586
    }
587
	f = fopen("obj-list.txt", mode);
587
    f = fopen("obj-list.txt", mode);
588
 
588
 
589
	if (current) {
589
    if (current) {
590
		fprintf(f, "current drawstate ");
590
	fprintf(f, "current drawstate ");
591
		print_drawstate(f, current, NULL);
591
	print_drawstate(f, current, NULL);
592
		fprintf(f, "\n");
-
 
593
	}
-
 
594
	fprintf(f, "global drawstate ");
-
 
595
	print_drawstate(f, & app_drawstate, NULL);
-
 
596
	fprintf(f, "\n");
592
	fprintf(f, "\n");
-
 
593
    }
-
 
594
    fprintf(f, "global drawstate ");
-
 
595
    print_drawstate(f, & app_drawstate, NULL);
-
 
596
    fprintf(f, "\n");
597
 
597
 
598
	print_objects(f, base_object, 0);
598
    print_objects(f, base_object, 0);
599
	fprintf(f, "------------\n");
599
    fprintf(f, "------------\n");
600
	fclose(f);
600
    fclose(f);
601
}
601
}
602
#endif
602
#endif
603
 
603
 
604
void remove_menu_item(object obj)
604
void remove_menu_item(object obj)
605
{
605
{
606
	/* Must call private destructor first! */
606
    /* Must call private destructor first! */
607
	if (obj->die) obj->die(obj);
607
    if (obj->die) obj->die(obj);
608
	remove_object(obj);
608
    remove_object(obj);
609
	remove_deleted_object(obj);
609
    remove_deleted_object(obj);
610
}
610
}