1 /***********************************************************/
2 /*                                                         */
3 /*  System dependent miscellaneous routines (unix, x11)    */
4 /*                                                         */
5 /***********************************************************/
6 
7 #include <apricot.h>
8 #include <sys/stat.h>
9 #include "unix/guts.h"
10 #include "Application.h"
11 #include "File.h"
12 #include "Icon.h"
13 #define XK_MISCELLANY
14 #include <X11/keysymdef.h>
15 
16 /* Miscellaneous system-dependent functions */
17 
18 #define X_COLOR_TO_RGB(xc)     (ARGB(((xc).red>>8),((xc).green>>8),((xc).blue>>8)))
19 #define RANGE(a)        { if ((a) < -16383) (a) = -16383; else if ((a) > 16383) a = 16383; }
20 #define RANGE2(a,b)     RANGE(a) RANGE(b)
21 
22 static XrmQuark
get_class_quark(const char * name)23 get_class_quark( const char *name)
24 {
25 	XrmQuark quark;
26 	char *s, *t;
27 
28 	t = s = prima_normalize_resource_string( duplicate_string( name), true);
29 	if ( t && *t == 'P' && strncmp( t, "Prima__", 7) == 0)
30 		s = t + 7;
31 	if ( s && *s == 'A' && strcmp( s, "Application") == 0)
32 		strcpy( s, "Prima"); /* we have enough space */
33 	quark = XrmStringToQuark( s);
34 	free( t);
35 	return quark;
36 }
37 
38 static XrmQuark
get_instance_quark(const char * name)39 get_instance_quark( const char *name)
40 {
41 	XrmQuark quark;
42 	char *s;
43 
44 	s = duplicate_string( name);
45 	quark = XrmStringToQuark( prima_normalize_resource_string( s, false));
46 	free( s);
47 	return quark;
48 }
49 
50 static Bool
update_quarks_cache(Handle self)51 update_quarks_cache( Handle self)
52 {
53 	PComponent me = PComponent( self);
54 	XrmQuark qClass, qInstance;
55 	int n;
56 	DEFXX;
57 	PDrawableSysData UU;
58 
59 	if (!XX)
60 		return false;
61 
62 	qClass = get_class_quark( self == application ? "Prima" : me-> self-> className);
63 	qInstance = get_instance_quark( me-> name ? me-> name : "noname");
64 
65 	free( XX-> q_class_name); XX-> q_class_name = NULL;
66 	free( XX-> q_instance_name); XX-> q_instance_name = NULL;
67 
68 	if ( me-> owner && me-> owner != self && PComponent(me-> owner)-> sysData && X(PComponent( me-> owner))-> q_class_name) {
69 		UU = X(PComponent( me-> owner));
70 		XX-> n_class_name = n = UU-> n_class_name + 1;
71 		if (( XX-> q_class_name = malloc( sizeof( XrmQuark) * (n + 3))))
72 			memcpy( XX-> q_class_name, UU-> q_class_name, sizeof( XrmQuark) * n);
73 		XX-> q_class_name[n-1] = qClass;
74 		XX-> n_instance_name = n = UU-> n_instance_name + 1;
75 		if (( XX-> q_instance_name = malloc( sizeof( XrmQuark) * (n + 3))))
76 			memcpy( XX-> q_instance_name, UU-> q_instance_name, sizeof( XrmQuark) * n);
77 		XX-> q_instance_name[n-1] = qInstance;
78 	} else {
79 		XX-> n_class_name = n = 1;
80 		if (( XX-> q_class_name = malloc( sizeof( XrmQuark) * (n + 3))))
81 			XX-> q_class_name[n-1] = qClass;
82 		XX-> n_instance_name = n = 1;
83 		if (( XX-> q_instance_name = malloc( sizeof( XrmQuark) * (n + 3))))
84 			XX-> q_instance_name[n-1] = qInstance;
85 	}
86 	return true;
87 }
88 
89 int
unix_rm_get_int(Handle self,XrmQuark class_detail,XrmQuark name_detail,int default_value)90 unix_rm_get_int( Handle self, XrmQuark class_detail, XrmQuark name_detail, int default_value)
91 {
92 	DEFXX;
93 	XrmRepresentation type;
94 	XrmValue value;
95 	long int r;
96 	char *end;
97 
98 	if ( XX && guts.db && XX-> q_class_name && XX-> q_instance_name) {
99 		XX-> q_class_name[XX-> n_class_name] = class_detail;
100 		XX-> q_class_name[XX-> n_class_name + 1] = 0;
101 		XX-> q_instance_name[XX-> n_instance_name] = name_detail;
102 		XX-> q_instance_name[XX-> n_instance_name + 1] = 0;
103 		if ( XrmQGetResource( guts.db,
104 									XX-> q_instance_name,
105 									XX-> q_class_name,
106 									&type, &value)) {
107 			if ( type == guts.qString) {
108 				r = strtol((char *)value. addr, &end, 0);
109 				if (*(value. addr) && !*end)
110 					return (int)r;
111 			}
112 		}
113 	}
114 	return default_value;
115 }
116 
117 Bool
apc_fetch_resource(const char * className,const char * name,const char * resClass,const char * res,Handle owner,int resType,void * result)118 apc_fetch_resource( const char *className, const char *name,
119 						const char *resClass, const char *res,
120 						Handle owner, int resType,
121 						void *result)
122 {
123 	PDrawableSysData XX;
124 	XrmQuark *classes, *instances, backup_classes[3], backup_instances[3];
125 	XrmRepresentation type;
126 	XrmValue value;
127 	int nc, ni;
128 	char *s;
129 	XColor clr;
130 
131 	if ( owner == NULL_HANDLE) {
132 		classes           = backup_classes;
133 		instances         = backup_instances;
134 		nc = ni = 0;
135 	} else {
136 		if (!update_quarks_cache( owner)) return false;
137 		XX                   = X(owner);
138 		if (!XX) return false;
139 		classes              = XX-> q_class_name;
140 		instances            = XX-> q_instance_name;
141 		if ( classes == NULL || instances == NULL) return false;
142 		nc                   = XX-> n_class_name;
143 		ni                   = XX-> n_instance_name;
144 	}
145 	classes[nc++]        = get_class_quark( className);
146 	instances[ni++]      = get_instance_quark( name);
147 	classes[nc++]        = get_class_quark( resClass);
148 	instances[ni++]      = get_instance_quark( res);
149 	classes[nc]          = 0;
150 	instances[ni]        = 0;
151 
152 	if (guts. debug & DEBUG_XRDB) {
153 		int i;
154 		_debug( "misc: inst: ");
155 		for ( i = 0; i < ni; i++) {
156 			_debug( "%s ", XrmQuarkToString( instances[i]));
157 		}
158 		_debug( "\nmisc: class: ");
159 		for ( i = 0; i < nc; i++) {
160 			_debug( "%s ", XrmQuarkToString( classes[i]));
161 		}
162 		_debug( "\n");
163 	}
164 
165 	if ( XrmQGetResource( guts.db,
166 				instances,
167 				classes,
168 				&type, &value)) {
169 		if ( type == guts.qString) {
170 			s = (char *)value.addr;
171 			Xdebug("found %s\n", s);
172 			switch ( resType) {
173 			case frString:
174 				*((char**)result) = duplicate_string( s);
175 				break;
176 			case frColor:
177 				if (!XParseColor( DISP, DefaultColormap( DISP, SCREEN), s, &clr))
178 					return false;
179 				*((Color*)result) = X_COLOR_TO_RGB(clr);
180 				Xdebug("color: %06x\n", *((Color*)result));
181 				break;
182 			case frFont:
183 				prima_font_pp2font( s, ( Font *) result);
184 #define DEBUG_FONT(font) font.height,font.width,font.size,font.name,font.encoding
185 				Xdebug("font: %d.[w=%d,s=%d].%s.%s\n", DEBUG_FONT((*(( Font *) result))));
186 				break;
187 			case frUnix_int:
188 				*((int*)result) = atoi( s);
189 				Xdebug("int: %d\n", *((int*)result));
190 				break;
191 			default:
192 				return false;
193 			}
194 			return true;
195 		}
196 	}
197 
198 	return false;
199 }
200 
201 Color
apc_lookup_color(const char * colorName)202 apc_lookup_color( const char * colorName)
203 {
204 	char buf[ 256];
205 	char *b;
206 	int len;
207 	XColor clr;
208 
209 	if ( DISP && XParseColor( DISP, DefaultColormap( DISP, SCREEN), colorName, &clr))
210 		return X_COLOR_TO_RGB(clr);
211 
212 #define xcmp( name, stlen, retval)  if (( len == stlen) && ( strcmp( name, buf) == 0)) return retval
213 
214 	strncpy( buf, colorName, 255);
215 	len = strlen( buf);
216 	for ( b = buf; *b; b++) *b = tolower(*b);
217 
218 	switch( buf[0]) {
219 	case 'a':
220 		xcmp( "aqua", 4, 0x00FFFF);
221 		xcmp( "azure", 5, ARGB(240,255,255));
222 		break;
223 	case 'b':
224 		xcmp( "black", 5, 0x000000);
225 		xcmp( "blanchedalmond", 14, ARGB( 255,235,205));
226 		xcmp( "blue", 4, 0x000080);
227 		xcmp( "brown", 5, 0x808000);
228 		xcmp( "beige", 5, ARGB(245,245,220));
229 		break;
230 	case 'c':
231 		xcmp( "cyan", 4, 0x008080);
232 		xcmp( "chocolate", 9, ARGB(210,105,30));
233 		break;
234 	case 'd':
235 		xcmp( "darkgray", 8, 0x404040);
236 		break;
237 	case 'e':
238 		break;
239 	case 'f':
240 		xcmp( "fuchsia", 7, 0xFF00FF);
241 		break;
242 	case 'g':
243 		xcmp( "green", 5, 0x008000);
244 		xcmp( "gray", 4, 0x808080);
245 		xcmp( "gray80", 6, ARGB(204,204,204));
246 		xcmp( "gold", 4, ARGB(255,215,0));
247 		break;
248 	case 'h':
249 		xcmp( "hotpink", 7, ARGB(255,105,180));
250 		break;
251 	case 'i':
252 		xcmp( "ivory", 5, ARGB(255,255,240));
253 		break;
254 	case 'j':
255 		break;
256 	case 'k':
257 		xcmp( "khaki", 5, ARGB(240,230,140));
258 		break;
259 	case 'l':
260 		xcmp( "lime", 4, 0x00FF00);
261 		xcmp( "lightgray", 9, 0xC0C0C0);
262 		xcmp( "lightblue", 9, 0x0000FF);
263 		xcmp( "lightgreen", 10, 0x00FF00);
264 		xcmp( "lightcyan", 9, 0x00FFFF);
265 		xcmp( "lightmagenta", 12, 0xFF00FF);
266 		xcmp( "lightred", 8, 0xFF0000);
267 		xcmp( "lemon", 5, ARGB(255,250,205));
268 		break;
269 	case 'm':
270 		xcmp( "maroon", 6, 0x800000);
271 		xcmp( "magenta", 7, 0x800080);
272 		break;
273 	case 'n':
274 		xcmp( "navy", 4, 0x000080);
275 		break;
276 	case 'o':
277 		xcmp( "olive", 5, 0x808000);
278 		xcmp( "orange", 6, ARGB(255,165,0));
279 		break;
280 	case 'p':
281 		xcmp( "purple", 6, 0x800080);
282 		xcmp( "peach", 5, ARGB(255,218,185));
283 		xcmp( "peru", 4, ARGB(205,133,63));
284 		xcmp( "pink", 4, ARGB(255,192,203));
285 		xcmp( "plum", 4, ARGB(221,160,221));
286 		break;
287 	case 'q':
288 		break;
289 	case 'r':
290 		xcmp( "red", 3, 0x800000);
291 		xcmp( "royalblue", 9, ARGB(65,105,225));
292 		break;
293 	case 's':
294 		xcmp( "silver", 6, 0xC0C0C0);
295 		xcmp( "sienna", 6, ARGB(160,82,45));
296 		break;
297 	case 't':
298 		xcmp( "teal", 4, 0x008080);
299 		xcmp( "turquoise", 9, ARGB(64,224,208));
300 		xcmp( "tan", 3, ARGB(210,180,140));
301 		xcmp( "tomato", 6, ARGB(255,99,71));
302 		break;
303 	case 'u':
304 		break;
305 	case 'w':
306 		xcmp( "white", 5, 0xFFFFFF);
307 		xcmp( "wheat", 5, ARGB(245,222,179));
308 		break;
309 	case 'v':
310 		xcmp( "violet", 6, ARGB(238,130,238));
311 		break;
312 	case 'x':
313 		break;
314 	case 'y':
315 		xcmp( "yellow", 6, 0xFFFF00);
316 		break;
317 	case 'z':
318 		break;
319 	}
320 
321 #undef xcmp
322 
323 	return clInvalid;
324 }
325 
326 /* Component-related functions */
327 
328 Bool
apc_component_create(Handle self)329 apc_component_create( Handle self)
330 {
331 	if ( !PComponent( self)-> sysData) {
332 		if ( !( PComponent( self)-> sysData = malloc( sizeof( UnixSysData))))
333 			return false;
334 		bzero( PComponent( self)-> sysData, sizeof( UnixSysData));
335 		((PUnixSysData)(PComponent(self)->sysData))->component. self = self;
336 	}
337 	return true;
338 }
339 
340 Bool
apc_component_destroy(Handle self)341 apc_component_destroy( Handle self)
342 {
343 	DEFXX;
344 	if ( XX-> q_instance_name) {
345 		free( XX-> q_instance_name);
346 		XX-> q_instance_name = NULL;
347 	}
348 	if ( XX-> q_class_name) {
349 		free( XX-> q_class_name);
350 		XX-> q_class_name = NULL;
351 	}
352 
353 	free( PComponent( self)-> sysData);
354 	PComponent( self)-> sysData = NULL;
355 	X_WINDOW = NULL_HANDLE;
356 	return true;
357 }
358 
359 Bool
apc_component_fullname_changed_notify(Handle self)360 apc_component_fullname_changed_notify( Handle self)
361 {
362 	Handle *list;
363 	PComponent me = PComponent( self);
364 	int i, n;
365 
366 	if ( self == NULL_HANDLE) return false;
367 	if (!update_quarks_cache( self)) return false;
368 
369 	if ( me-> components && (n = me-> components-> count) > 0) {
370 		if ( !( list = allocn( Handle, n))) return false;
371 		memcpy( list, me-> components-> items, sizeof( Handle) * n);
372 
373 		for ( i = 0; i < n; i++) {
374 			apc_component_fullname_changed_notify( list[i]);
375 		}
376 		free( list);
377 	}
378 
379 	return true;
380 }
381 
382 /* Cursor support */
383 
384 void
prima_no_cursor(Handle self)385 prima_no_cursor( Handle self)
386 {
387 	if ( self && guts.focused == self && X(self)
388 		&& !(XF_IN_PAINT(X(self)))
389 		&& X(self)-> flags. cursor_visible
390 		&& guts. cursor_save
391 		&& guts. cursor_shown)
392 	{
393 		DEFXX;
394 		int x, y, w, h;
395 
396 		h = XX-> cursor_size. y;
397 		y = XX-> size. y - (h + XX-> cursor_pos. y);
398 		x = XX-> cursor_pos. x;
399 		w = XX-> cursor_size. x;
400 
401 		prima_get_gc( XX);
402 		XChangeGC( DISP, XX-> gc, VIRGIN_GC_MASK, &guts. cursor_gcv);
403 		XCHECKPOINT;
404 		XCopyArea( DISP, guts. cursor_save, XX-> udrawable, XX-> gc,
405 					0, 0, w, h, x, y);
406 		XFlush(DISP);
407 		XCHECKPOINT;
408 		prima_release_gc( XX);
409 		guts. cursor_shown = false;
410 	}
411 }
412 
413 void
prima_update_cursor(Handle self)414 prima_update_cursor( Handle self)
415 {
416 	if (
417 		guts.focused == self
418 		&& !(XF_IN_PAINT(X(self)))
419 	) {
420 		DEFXX;
421 		int x, y, w, h;
422 
423 		h = XX-> cursor_size. y;
424 		y = XX-> size. y - (h + XX-> cursor_pos. y);
425 		x = XX-> cursor_pos. x;
426 		w = XX-> cursor_size. x;
427 
428 		if ( !guts. cursor_save || !guts. cursor_xor
429 			|| w > guts. cursor_pixmap_size. x
430 			|| h > guts. cursor_pixmap_size. y ||
431 			XX-> flags. layered != guts. cursor_layered
432 			)
433 		{
434 			if ( !guts. cursor_save) {
435 				guts. cursor_gcv. background = 0;
436 				guts. cursor_gcv. foreground = 0xffffffff;
437 			}
438 			if ( guts. cursor_save) {
439 				XFreePixmap( DISP, guts. cursor_save);
440 				guts. cursor_save = 0;
441 			}
442 			if ( guts. cursor_xor) {
443 				XFreePixmap( DISP, guts. cursor_xor);
444 				guts. cursor_xor = 0;
445 			}
446 			if ( guts. cursor_pixmap_size. x < w)
447 				guts. cursor_pixmap_size. x = w;
448 			if ( guts. cursor_pixmap_size. y < h)
449 				guts. cursor_pixmap_size. y = h;
450 			if ( guts. cursor_pixmap_size. x < 16)
451 				guts. cursor_pixmap_size. x = 16;
452 			if ( guts. cursor_pixmap_size. y < 64)
453 				guts. cursor_pixmap_size. y = 64;
454 			guts. cursor_save = XCreatePixmap( DISP, XX-> udrawable,
455 				guts. cursor_pixmap_size. x,
456 				guts. cursor_pixmap_size. y,
457 				XX-> visual-> depth);
458 			guts. cursor_xor  = XCreatePixmap( DISP, XX-> udrawable,
459 				guts. cursor_pixmap_size. x,
460 				guts. cursor_pixmap_size. y,
461 				XX-> visual-> depth);
462 			guts. cursor_layered = XX-> flags. layered;
463 		}
464 
465 		prima_get_gc( XX);
466 		XChangeGC( DISP, XX-> gc, VIRGIN_GC_MASK, &guts. cursor_gcv);
467 		XCopyArea( DISP, XX-> udrawable, guts. cursor_save, XX-> gc,
468 			x, y, w, h, 0, 0);
469 		XCopyArea( DISP, guts. cursor_save, guts. cursor_xor, XX-> gc,
470 			0, 0, w, h, 0, 0);
471 		XSetFunction( DISP, XX-> gc, GXxor);
472 		XFillRectangle( DISP, guts. cursor_xor, XX-> gc, 0, 0, w, h);
473 		prima_release_gc( XX);
474 		XCHECKPOINT;
475 
476 		if ( XX-> flags. cursor_visible) {
477 			guts. cursor_shown = false;
478 			prima_cursor_tick();
479 		} else {
480 			apc_timer_stop( CURSOR_TIMER);
481 		}
482 	}
483 }
484 
485 void
prima_cursor_tick(void)486 prima_cursor_tick( void)
487 {
488 	if (
489 		guts. focused &&
490 		X(guts. focused)-> flags. cursor_visible &&
491 		!(XF_IN_PAINT(X(guts. focused)))
492 	) {
493 		PDrawableSysData selfxx = X(guts. focused);
494 		Pixmap pixmap;
495 		int x, y, w, h;
496 
497 		if ( guts. cursor_shown) {
498 			guts. cursor_shown = false;
499 			apc_timer_set_timeout( CURSOR_TIMER, guts. invisible_timeout);
500 			pixmap = guts. cursor_save;
501 		} else {
502 			guts. cursor_shown = true;
503 			apc_timer_set_timeout( CURSOR_TIMER, guts. visible_timeout);
504 			pixmap = guts. cursor_xor;
505 		}
506 
507 		h = XX-> cursor_size. y;
508 		y = XX-> size. y - (h + XX-> cursor_pos. y);
509 		x = XX-> cursor_pos. x;
510 		w = XX-> cursor_size. x;
511 
512 		prima_get_gc( XX);
513 		XChangeGC( DISP, XX-> gc, VIRGIN_GC_MASK, &guts. cursor_gcv);
514 		XCHECKPOINT;
515 		XCopyArea( DISP, pixmap, XX-> udrawable, XX-> gc, 0, 0, w, h, x, y);
516 		XCHECKPOINT;
517 		prima_release_gc( XX);
518 		XFlush( DISP);
519 		XCHECKPOINT;
520 	} else {
521 		apc_timer_stop( CURSOR_TIMER);
522 		guts. cursor_shown = !guts. cursor_shown;
523 	}
524 }
525 
526 Bool
apc_cursor_set_pos(Handle self,int x,int y)527 apc_cursor_set_pos( Handle self, int x, int y)
528 {
529 	DEFXX;
530 	prima_no_cursor( self);
531 	RANGE2(x,y);
532 	XX-> cursor_pos. x = x;
533 	XX-> cursor_pos. y = y;
534 	prima_update_cursor( self);
535 	return true;
536 }
537 
538 Bool
apc_cursor_set_size(Handle self,int x,int y)539 apc_cursor_set_size( Handle self, int x, int y)
540 {
541 	DEFXX;
542 	prima_no_cursor( self);
543 	if ( x < 0) x = 1;
544 	if ( y < 0) y = 1;
545 	if ( x > 16383) x = 16383;
546 	if ( y > 16383) y = 16383;
547 	XX-> cursor_size. x = x;
548 	XX-> cursor_size. y = y;
549 	prima_update_cursor( self);
550 	return true;
551 }
552 
553 Bool
apc_cursor_set_visible(Handle self,Bool visible)554 apc_cursor_set_visible( Handle self, Bool visible)
555 {
556 	DEFXX;
557 	if ( XX-> flags. cursor_visible != visible) {
558 		prima_no_cursor( self);
559 		XX-> flags. cursor_visible = visible;
560 		prima_update_cursor( self);
561 	}
562 	return true;
563 }
564 
565 Point
apc_cursor_get_pos(Handle self)566 apc_cursor_get_pos( Handle self)
567 {
568 	return X(self)-> cursor_pos;
569 }
570 
571 Point
apc_cursor_get_size(Handle self)572 apc_cursor_get_size( Handle self)
573 {
574 	return X(self)-> cursor_size;
575 }
576 
577 Bool
apc_cursor_get_visible(Handle self)578 apc_cursor_get_visible( Handle self)
579 {
580 	return X(self)-> flags. cursor_visible;
581 }
582 
583 int
apc_pointer_get_state(Handle self)584 apc_pointer_get_state( Handle self)
585 {
586 	XWindow foo;
587 	int bar;
588 	unsigned mask;
589 	XQueryPointer( DISP, guts.root,  &foo, &foo, &bar, &bar, &bar, &bar, &mask);
590 	return
591 		(( mask & Button1Mask) ? mb1 : 0) |
592 		(( mask & Button2Mask) ? mb2 : 0) |
593 		(( mask & Button3Mask) ? mb3 : 0) |
594 		(( mask & Button4Mask) ? mb4 : 0) |
595 		(( mask & Button5Mask) ? mb5 : 0) |
596 		(( mask & Button6Mask) ? mb6 : 0) |
597 		(( mask & Button7Mask) ? mb7 : 0);
598 }
599 
600 int
apc_kbd_get_state(Handle self)601 apc_kbd_get_state( Handle self)
602 {
603 	XWindow foo;
604 	int bar;
605 	unsigned int mask;
606 	XQueryPointer( DISP, guts.root, &foo, &foo, &bar, &bar, &bar, &bar, &mask);
607 	return
608 		(( mask & ShiftMask)   ? kmShift : 0) |
609 		(( mask & ControlMask) ? kmCtrl  : 0) |
610 		(( mask & Mod1Mask)    ? kmAlt   : 0);
611 }
612 
613 static void
close_msgdlg(struct MsgDlg * md)614 close_msgdlg( struct MsgDlg * md)
615 {
616 	md-> active  = false;
617 	md-> pressed = false;
618 	if ( md-> grab)
619 		XUngrabPointer( DISP, CurrentTime);
620 	md-> grab    = false;
621 	XUnmapWindow( DISP, md-> w);
622 	XFlush( DISP);
623 	if ( md-> next == NULL) {
624 		XSetInputFocus( DISP, md-> focus, md-> focus_revertTo, CurrentTime);
625 		XCHECKPOINT;
626 	}
627 }
628 
629 void
prima_msgdlg_event(XEvent * ev,struct MsgDlg * md)630 prima_msgdlg_event( XEvent * ev, struct MsgDlg * md)
631 {
632 	XWindow w = ev-> xany. window;
633 	switch ( ev-> type) {
634 	case ConfigureNotify:
635 		md-> winSz. x = ev-> xconfigure. width;
636 		md-> winSz. y = ev-> xconfigure. height;
637 		break;
638 	case Expose:
639 		{
640 			int i, y = md-> textPos. y;
641 			int d = md-> pressed ? 2 : 0;
642 			XSetForeground( DISP, md-> gc, md-> bg. primary);
643 			if ( md-> bg. balance > 0) {
644 				Pixmap p = prima_get_hatch( &guts. ditherPatterns[ md-> bg. balance]);
645 				if ( p) {
646 					XSetStipple( DISP, md-> gc, p);
647 					XSetFillStyle( DISP, md-> gc, FillOpaqueStippled);
648 					XSetBackground( DISP, md-> gc, md-> bg. secondary);
649 				}
650 			}
651 			XFillRectangle( DISP, w, md-> gc, 0, 0, md-> winSz.x, md-> winSz.y);
652 			if ( md-> bg. balance > 0)
653 				XSetFillStyle( DISP, md-> gc, FillSolid);
654 			XSetForeground( DISP, md-> gc, md-> fg);
655 			for ( i = 0; i < md-> wrappedCount; i++) {
656 				if ( md-> wide)
657 					XDrawString16( DISP, w, md-> gc,
658 					( md-> winSz.x - md-> widths[i]) / 2, y,
659 						( XChar2b*) md-> wrapped[i], md-> lengths[i]);
660 				else
661 					XDrawString( DISP, w, md-> gc,
662 					( md-> winSz.x - md-> widths[i]) / 2, y,
663 						md-> wrapped[i], md-> lengths[i]);
664 				y += md-> font-> height + md-> font-> externalLeading;
665 			}
666 			XDrawRectangle( DISP, w, md-> gc,
667 				md-> btnPos.x-1, md-> btnPos.y-1, md-> btnSz.x+2, md-> btnSz.y+2);
668 			XDrawString( DISP, w, md-> gc,
669 				md-> btnPos.x + ( md-> btnSz.x - md-> OKwidth) / 2 + d,
670 				md-> btnPos.y + md-> font-> height + md-> font-> externalLeading +
671 				( md-> btnSz.y - md-> font-> height - md-> font-> externalLeading) / 2 - 2 + d,
672 				"OK", 2);
673 			XSetForeground( DISP, md-> gc,
674 				md-> pressed ? md-> d3d : md-> l3d);
675 			XDrawLine( DISP, w, md-> gc,
676 				md-> btnPos.x, md-> btnPos.y + md-> btnSz.y - 1,
677 				md-> btnPos.x, md-> btnPos. y);
678 			XDrawLine( DISP, w, md-> gc,
679 				md-> btnPos.x + 1, md-> btnPos. y,
680 				md-> btnPos.x + md-> btnSz.x - 1, md-> btnPos. y);
681 			XSetForeground( DISP, md-> gc,
682 				md-> pressed ? md-> l3d : md-> d3d);
683 			XDrawLine( DISP, w, md-> gc,
684 				md-> btnPos.x, md-> btnPos.y + md-> btnSz.y,
685 				md-> btnPos.x + md-> btnSz.x, md-> btnPos.y + md-> btnSz.y);
686 			XDrawLine( DISP, w, md-> gc,
687 				md-> btnPos.x + md-> btnSz.x, md-> btnPos.y + md-> btnSz.y - 1,
688 				md-> btnPos.x + md-> btnSz.x, md-> btnPos.y + 1);
689 		}
690 		break;
691 	case ButtonPress:
692 		if ( !md-> grab &&
693 			( ev-> xbutton. button == Button1) &&
694 			( ev-> xbutton. x >= md-> btnPos. x ) &&
695 			( ev-> xbutton. x < md-> btnPos. x + md-> btnSz.x) &&
696 			( ev-> xbutton. y >= md-> btnPos. y ) &&
697 			( ev-> xbutton. y < md-> btnPos. y + md-> btnSz.y)) {
698 			md-> pressed = true;
699 			md-> grab = true;
700 			XClearArea( DISP, w, md-> btnPos.x, md-> btnPos.y,
701 				md-> btnSz.x, md-> btnSz.y, true);
702 			XGrabPointer( DISP, w, false,
703 				ButtonReleaseMask | PointerMotionMask | ButtonMotionMask,
704 				GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
705 		}
706 		break;
707 	case MotionNotify:
708 		if ( md-> grab) {
709 			Bool np =
710 			(( ev-> xmotion. x >= md-> btnPos. x ) &&
711 				( ev-> xmotion. x < md-> btnPos. x + md-> btnSz.x) &&
712 				( ev-> xmotion. y >= md-> btnPos. y ) &&
713 				( ev-> xmotion. y < md-> btnPos. y + md-> btnSz.y));
714 			if ( np != md-> pressed) {
715 				md-> pressed = np;
716 				XClearArea( DISP, w, md-> btnPos.x, md-> btnPos.y,
717 					md-> btnSz.x, md-> btnSz.y, true);
718 			}
719 		}
720 		break;
721 	case KeyPress:
722 		{
723 			char str_buf[256];
724 			KeySym keysym;
725 			int str_len = XLookupString( &ev-> xkey, str_buf, 256, &keysym, NULL);
726 			if (
727 				( keysym == XK_Return) ||
728 				( keysym == XK_Escape) ||
729 				( keysym == XK_KP_Enter) ||
730 				( keysym == XK_KP_Space) ||
731 				(( str_len == 1) && ( str_buf[0] == ' '))
732 				)
733 				close_msgdlg( md);
734 		}
735 		break;
736 	case ButtonRelease:
737 		if ( md-> grab &&
738 			( ev-> xbutton. button == Button1)) {
739 			md-> grab = false;
740 			XUngrabPointer( DISP, CurrentTime);
741 			if ( md-> pressed) close_msgdlg( md);
742 		}
743 		break;
744 	case ClientMessage:
745 		if (( ev-> xclient. message_type == WM_PROTOCOLS) &&
746 			(( Atom) ev-> xclient. data. l[0] == WM_DELETE_WINDOW))
747 			close_msgdlg( md);
748 		break;
749 	}
750 }
751 
752 Bool
apc_show_message(const char * message,Bool utf8)753 apc_show_message( const char * message, Bool utf8)
754 {
755 	int * wrapped;
756 	Font f;
757 	Point appSz, appPos;
758 	Point textSz;
759 	Point winSz;
760 	TextWrapRec twr;
761 	int i;
762 	struct MsgDlg md, **storage;
763 	Bool ret = false;
764 	PList font_abc_unicode = NULL;
765 	PFontABC font_abc_ascii = NULL;
766 	XFontStruct *fs = NULL;
767 
768 	if ( !DISP) {
769 		warn( "%s", message);
770 		return true;
771 	}
772 
773 	if ( guts. grab_widget)
774 		apc_widget_set_capture( guts. grab_widget, 0, 0);
775 
776 	appSz = apc_application_get_size( NULL_HANDLE);
777 	appPos.x = 0;
778 	appPos.y = 0;
779 
780 	/* multi-monitor centering */
781 	{
782 		int i, nrects = 0;
783 		Box *best = NULL, *rects = apc_application_get_monitor_rects( application, &nrects);
784 		for ( i = 0; i < nrects; i++) {
785 				Box * curr = rects + i;
786 				if ( best == NULL || best-> x > curr->x || best->y > curr->y)
787 						best = curr;
788 		}
789 		if ( best ) {
790 			appPos.x = best->x;
791 			appPos.y = best->y;
792 			appSz.x  = best->width;
793 			appSz.y  = best->height;
794 		}
795 	}
796 
797 	/* acquiring message font and wrapping message text */
798 	{
799 		PCachedFont cf;
800 		int max;
801 
802 		apc_sys_get_msg_font( &f);
803 		f. pitch = fpDefault;
804 #define DEBUG_FONT(font) font.height,font.width,font.size,font.name,font.encoding
805 		prima_core_font_pick( NULL_HANDLE, &f, &f);
806 		cf = prima_find_known_font( &f, false, false);
807 		if ( !cf || !cf-> id) {
808 			warn( "%s", message);
809 			return false;
810 		}
811 		fs = XQueryFont( DISP, cf-> id);
812 		if (!fs) {
813 			warn( "%s", message);
814 			return false;
815 		}
816 
817 		twr. text      = ( char *) message;
818 		twr. utf8_text = utf8;
819 		twr. textLen   = strlen( message);
820 		twr. utf8_textLen = utf8 ? prima_utf8_length( message, -1) : twr. textLen;
821 		twr. width     = appSz. x * 2 / 3;
822 		twr. tabIndent = 3;
823 		twr. options   = twNewLineBreak | twWordBreak | twReturnLines;
824 		twr. ascii     = &font_abc_ascii;
825 		twr. unicode   = &font_abc_unicode;
826 		twr. count     = 0;
827 		guts. font_abc_nil_hack = fs;
828 		wrapped = CDrawable->do_text_wrap( NULL_HANDLE, &twr, NULL, NULL);
829 
830 		if ( font_abc_ascii) free( font_abc_ascii);
831 		if ( font_abc_unicode) {
832 			int i;
833 			for ( i = 0; i < font_abc_unicode-> count; i += 2)
834 				free(( void*) font_abc_unicode-> items[ i + 1]);
835 			plist_destroy( font_abc_unicode);
836 		}
837 
838 		md.wrappedCount = md.count = twr.count / 4;
839 		if ( !( md.widths  = malloc( md.count * sizeof(int))))
840 			goto EXIT;
841 		if ( !( md.lengths = malloc( md.count * sizeof(int))))
842 			goto EXIT;
843 		if ( !( md.wrapped = malloc( md.count * sizeof(char*))))
844 			goto EXIT;
845 		bzero(md.wrapped, md.count * sizeof(char*));
846 
847 		/* find text extensions */
848 		max = 0;
849 		for ( i = 0; i < md.count; i+=4) {
850 			md.lengths[i] = wrapped[i+3];
851 			if (utf8) {
852 				if (!(md.wrapped[i] = (char*)prima_alloc_utf8_to_wchar( message + wrapped[i], md.lengths[i])))
853 					goto EXIT;
854 				md.widths[i] = XTextWidth16( fs, (XChar2b*) md.wrapped[i], md.lengths[i]);
855 			} else {
856 				if (!(md.wrapped[i] = malloc( md.lengths[i] + 1)))
857 					goto EXIT;
858 				memcpy(md.wrapped[i], message + wrapped[i], md.lengths[i]);
859 				md.wrapped[i][md.lengths[i]] = 0;
860 				md. widths[i] = XTextWidth( fs, md.wrapped[i], md.lengths[i]);
861 			}
862 			if ( md. widths[i] > max) max = md. widths[i];
863 		}
864 		textSz. x = max;
865 		textSz. y = md.count * ( f. height + f. externalLeading);
866 
867 		md. font          = &f;
868 		md. fontId        = cf-> id;
869 		md. OKwidth       = XTextWidth( fs, "OK", 2);
870 		md. btnSz.x       = md. OKwidth + 2 + 10;
871 		if ( md. btnSz. x < 56) md. btnSz. x = 56;
872 		md. btnSz.y       = f. height + f. externalLeading + 2 + 12;
873 
874 		winSz. x = textSz. x + 4;
875 		if ( winSz. x < md. btnSz. x + 2) winSz. x = md. btnSz.x + 2;
876 		winSz. x += f. width * 4;
877 		winSz. y = textSz. y + 2 + 12 + md. btnSz. y + f. height;
878 		while ( winSz. y + 12 >= appSz.y) {
879 			winSz. y -= f. height + f. externalLeading;
880 			md. wrappedCount--;
881 		}
882 		md. btnPos. x = ( winSz. x - md. btnSz. x) / 2;
883 		md. btnPos. y = winSz. y - 2 - md. btnSz. y - f. height / 2;
884 		md. textPos. x = 2;
885 		md. textPos. y = f. height * 3 / 2 + 2;
886 		md. winSz = winSz;
887 	}
888 
889 	md. wide    = utf8;
890 	md. active  = true;
891 	md. next    = NULL;
892 	md. pressed = false;
893 	md. grab    = false;
894 	XGetInputFocus( DISP, &md. focus, &md. focus_revertTo);
895 	XCHECKPOINT;
896 	{
897 		char * prima = "Prima";
898 		XTextProperty p;
899 		XSizeHints xs;
900 		XSetWindowAttributes attrs;
901 		Atom net_data[2];
902 		attrs. event_mask = 0
903 			| KeyPressMask
904 			| ButtonPressMask
905 			| ButtonReleaseMask
906 			| ButtonMotionMask
907 			| PointerMotionMask
908 			| StructureNotifyMask
909 			| ExposureMask;
910 		attrs. override_redirect = false;
911 		attrs. do_not_propagate_mask = attrs. event_mask;
912 
913 		md. w = XCreateWindow( DISP, guts. root,
914 			appPos.x + ( appSz.x - winSz.x) / 2, appPos.y + ( appSz.y - winSz.y) / 2,
915 			winSz.x, winSz.y, 0, CopyFromParent, InputOutput,
916 			CopyFromParent, CWEventMask | CWOverrideRedirect, &attrs);
917 		XCHECKPOINT;
918 		if ( !md. w) goto EXIT;
919 		XSetWMProtocols( DISP, md. w, &WM_DELETE_WINDOW, 1);
920 		XCHECKPOINT;
921 		xs. flags = PMinSize | PMaxSize | USPosition;
922 		xs. min_width  = xs. max_width  = winSz.x;
923 		xs. min_height = xs. max_height = winSz. y;
924 		xs. x = appPos.x + ( appSz.x - winSz.x) / 2;
925 		xs. y = appPos.y + ( appSz.y - winSz.y) / 2;
926 		XSetWMNormalHints( DISP, md. w, &xs);
927 		if ( XStringListToTextProperty( &prima, 1, &p) != 0) {
928 			XSetWMIconName( DISP, md. w, &p);
929 			XSetWMName( DISP, md. w, &p);
930 			XFree( p. value);
931 		}
932 		net_data[0] = NET_WM_STATE_SKIP_TASKBAR;
933 		net_data[1] = NET_WM_STATE_MODAL;
934 		XChangeProperty( DISP, md. w, NET_WM_STATE, XA_ATOM, 32,
935 			PropModeReplace, ( unsigned char *) net_data, 2);
936 	}
937 
938 	storage = &guts. message_boxes;
939 	while ( *storage) storage = &((*storage)-> next);
940 	*storage = &md;
941 
942 	{
943 #define CLR(x) prima_allocate_color( NULL_HANDLE,prima_map_color(x,NULL),NULL)
944 		XGCValues gcv;
945 		gcv. font = md. fontId;
946 		md. gc = XCreateGC( DISP, md. w, GCFont, &gcv);
947 		md. fg  = CLR(clFore | wcDialog);
948 		prima_allocate_color( NULL_HANDLE, prima_map_color(clBack | wcDialog,NULL), &md. bg);
949 		md. l3d = CLR(clLight3DColor | wcDialog);
950 		md. d3d = CLR(clDark3DColor  | wcDialog);
951 #undef CLR
952 	}
953 
954 
955 	XMapWindow( DISP, md. w);
956 	XMoveResizeWindow( DISP, md. w,
957 		appPos.x + ( appSz.x - winSz.x) / 2, appPos.y + ( appSz.y - winSz.y) / 2, winSz.x, winSz.y);
958 	XNoOp( DISP);
959 	while ( md. active && !guts. applicationClose) {
960 		XFlush( DISP);
961 		prima_one_loop_round( WAIT_ALWAYS, false);
962 	}
963 
964 	XFreeGC( DISP, md. gc);
965 	XDestroyWindow( DISP, md. w);
966 	*storage = md. next;
967 	ret = true;
968 EXIT:
969 	XFreeFontInfo( NULL, fs, 1);
970 	if ( md.widths ) free( md.widths);
971 	if ( md.lengths) free( md.lengths);
972 	if ( md.wrapped ) {
973 		for ( i = 0; i < md.count; i++)
974 			free(md.wrapped[i]);
975 		free(md.wrapped);
976 	}
977 
978 	return ret;
979 }
980 
981 /* system metrics */
982 
983 Bool
apc_sys_get_insert_mode(void)984 apc_sys_get_insert_mode( void)
985 {
986 	return guts. insert;
987 }
988 
989 PFont
apc_sys_get_msg_font(PFont f)990 apc_sys_get_msg_font( PFont f)
991 {
992 	memcpy( f, &guts. default_msg_font, sizeof( Font));
993 	return f;
994 }
995 
996 PFont
apc_sys_get_caption_font(PFont f)997 apc_sys_get_caption_font( PFont f)
998 {
999 	memcpy( f, &guts. default_caption_font, sizeof( Font));
1000 	return f;
1001 }
1002 
1003 static int
is_composite_display(void)1004 is_composite_display(void)
1005 {
1006 	if ( guts. argb_visual. visual == NULL ) return false;
1007 
1008 #ifndef HAVE_X11_EXTENSIONS_XCOMPOSITE_H
1009 	return -1;
1010 #else
1011 	/* try to become a compmgr */
1012 	XCHECKPOINT;
1013 	guts. composite_error_triggered = false;
1014 	XCompositeRedirectSubwindows( DISP, guts.root, CompositeRedirectManual);
1015 	XCHECKPOINT;
1016 	XSync(DISP, false);
1017 	if ( guts. composite_error_triggered )
1018 		return true;
1019 	XCompositeUnredirectSubwindows( DISP, guts.root, CompositeRedirectManual);
1020 	XCHECKPOINT;
1021 	XSync(DISP, false);
1022 	if ( guts. composite_error_triggered )
1023 		return true;
1024 
1025 	return false;
1026 #endif
1027 }
1028 
1029 int
apc_sys_get_value(int v)1030 apc_sys_get_value( int v)  /* XXX one big XXX */
1031 {
1032 	switch ( v) {
1033 	case svYMenu: {
1034 		Font f;
1035 		apc_menu_default_font( &f);
1036 		return f. height + MENU_ITEM_GAP * 2;
1037 	}
1038 	case svYTitleBar: /* XXX */ return 20;
1039 	case svMousePresent:		return guts. mouse_buttons > 0;
1040 	case svMouseButtons:		return guts. mouse_buttons;
1041 	case svSubmenuDelay:  /* XXX ? */ return guts. menu_timeout;
1042 	case svFullDrag: /* XXX ? */ return false;
1043 	case svWheelPresent:		return guts.mouse_wheel_up || guts.mouse_wheel_down;
1044 	case svXIcon:
1045 	case svYIcon:
1046 	case svXSmallIcon:
1047 	case svYSmallIcon:
1048 		{
1049 			int ret[4], n;
1050 			XIconSize * sz = NULL;
1051 			if ( XGetIconSizes( DISP, guts.root, &sz, &n) && ( n > 0) && (sz != NULL)) {
1052 				ret[0] = sz-> max_width;
1053 				ret[1] = sz-> max_height;
1054 				ret[2] = sz-> min_width;
1055 				ret[3] = sz-> min_height;
1056 			} else {
1057 				ret[0] = ret[1] = 64;
1058 				ret[2] = ret[3] = 20;
1059 			}
1060 			if ( sz) XFree( sz);
1061 			return ret[v - svXIcon];
1062 		}
1063 		break;
1064 	case svXPointer:		return guts. cursor_width;
1065 	case svYPointer:		return guts. cursor_height;
1066 	case svXScrollbar:		return 19;
1067 	case svYScrollbar:		return 19;
1068 	case svXCursor:		return 1;
1069 	case svAutoScrollFirst:	return guts. scroll_first;
1070 	case svAutoScrollNext:	return guts. scroll_next;
1071 	case svXbsNone:		return 0;
1072 	case svYbsNone:		return 0;
1073 	case svXbsSizeable:		return 3; /* XXX */
1074 	case svYbsSizeable:		return 3; /* XXX */
1075 	case svXbsSingle:		return 1; /* XXX */
1076 	case svYbsSingle:		return 1; /* XXX */
1077 	case svXbsDialog:		return 2; /* XXX */
1078 	case svYbsDialog:		return 2; /* XXX */
1079 	case svShapeExtension:	return guts. shape_extension;
1080 	case svDblClickDelay:        return guts. double_click_time_frame;
1081 	case svColorPointer:         return
1082 #ifdef HAVE_X11_XCURSOR_XCURSOR_H
1083 		1
1084 #else
1085 		0
1086 #endif
1087 		;
1088 	case svCanUTF8_Input:        return 1;
1089 	case svCanUTF8_Output:       return 1;
1090 	case svCompositeDisplay:     return is_composite_display();
1091 	case svLayeredWidgets:       return guts. argb_visual. visual != NULL;
1092 	case svFixedPointerSize:     return
1093 #ifdef HAVE_X11_XCURSOR_XCURSOR_H
1094 		0
1095 #else
1096 		1
1097 #endif
1098 ;
1099 	case svMenuCheckSize   : return MENU_CHECK_XOFFSET;
1100 	case svFriBidi         : return use_fribidi;
1101 	case svAntialias       : return guts. argb_visual. visual != NULL;
1102 	default:
1103 		return -1;
1104 	}
1105 }
1106 
1107 Bool
apc_sys_set_insert_mode(Bool insMode)1108 apc_sys_set_insert_mode( Bool insMode)
1109 {
1110 	guts. insert = !!insMode;
1111 	return true;
1112 }
1113 
1114 /* etc */
1115 
1116 Bool
apc_beep(int style)1117 apc_beep( int style)
1118 {
1119 	/* XXX - mbError, mbQuestion, mbInformation, mbWarning */
1120 	if ( DISP)
1121 		XBell( DISP, 0);
1122 	return true;
1123 }
1124 
1125 Bool
apc_beep_tone(int freq,int duration)1126 apc_beep_tone( int freq, int duration)
1127 {
1128 	XKeyboardControl xkc;
1129 	XKeyboardState   xks;
1130 	struct timeval timeout;
1131 
1132 	if ( !DISP) return false;
1133 
1134 	XGetKeyboardControl( DISP, &xks);
1135 	xkc. bell_pitch    = freq;
1136 	xkc. bell_duration = duration;
1137 	XChangeKeyboardControl( DISP, KBBellPitch | KBBellDuration, &xkc);
1138 
1139 	XBell( DISP, 100);
1140 	XFlush( DISP);
1141 
1142 	xkc. bell_pitch    = xks. bell_pitch;
1143 	xkc. bell_duration = xks. bell_duration;
1144 	XChangeKeyboardControl( DISP, KBBellPitch | KBBellDuration, &xkc);
1145 
1146 	timeout. tv_sec  = duration / 1000;
1147 	timeout. tv_usec = 1000 * (duration % 1000);
1148 	select( 0, NULL, NULL, NULL, &timeout);
1149 
1150 	return true;
1151 }
1152 
1153 char *
apc_system_action(const char * s)1154 apc_system_action( const char *s)
1155 {
1156 	int l = strlen( s);
1157 	switch (*s) {
1158 	case 'b':
1159 		if ( l == 7 && strcmp( s, "browser") == 0)
1160 			return duplicate_string("netscape");
1161 		break;
1162 	case 'c':
1163 		if ( l == 19 && strcmp( s, "can.shape.extension") == 0 && guts.shape_extension)
1164 			return duplicate_string( "yes");
1165 		else if ( l == 26 && strcmp( s, "can.shared.image.extension") == 0 && guts.shared_image_extension)
1166 			return duplicate_string( "yes");
1167 		break;
1168 	case 'D':
1169 		if ( l == 7 && ( strcmp( s, "Display") == 0)) {
1170 			char * c = malloc(19);
1171 			if ( c) snprintf( c, 18, "0x%p", DISP);
1172 			return c;
1173 		}
1174 		break;
1175 	case 'g':
1176 		if ( l > 15 && strncmp( "get.frame.info ", s, 15) == 0) {
1177 			char *end;
1178 			XWindow w = strtoul( s + 15, &end, 0);
1179 			Handle self;
1180 			Rect r;
1181 			char buf[ 80];
1182 
1183 			if (*end == '\0' &&
1184 				( self = prima_xw2h( w)) &&
1185 				prima_get_frame_info( self, &r) &&
1186 				snprintf( buf, sizeof(buf), "%d %d %d %d", r.left, r.bottom, r.right, r.top) < sizeof(buf))
1187 				return duplicate_string( buf);
1188 			return duplicate_string("");
1189 		} else if ( strncmp( s, "gtk.OpenFile.", 13) == 0) {
1190 			s += 13;
1191 #ifdef WITH_GTK
1192 			if ( guts. use_gtk )
1193 				return prima_gtk_openfile(( char*) s);
1194 #endif
1195 			return NULL;
1196 		}
1197 		break;
1198 	case 'r':
1199 		if ( strncmp( s, "resolution", 10) == 0) {
1200 			int dx, dy;
1201 			int i = sscanf( s + 10, "%u %u", &dx, &dy);
1202 			if ( i != 2 || (dx < 1 || dy < 1)) {
1203 				warn("Bad resolution\n");
1204 				return 0;
1205 			}
1206 			guts. resolution. x = dx;
1207 			guts. resolution. y = dy;
1208 			return NULL;
1209 		}
1210 		break;
1211 	case 's':
1212 		if ( strcmp( "synchronize", s) == 0) {
1213 			XSynchronize( DISP, true);
1214 			return NULL;
1215 		}
1216 		if ( strncmp( "setfont ", s, 8) == 0) {
1217 			Handle self = NULL_HANDLE;
1218 			char font[1024];
1219 			XWindow win;
1220 			int i = sscanf( s + 8, "%lu %s", &win, font);
1221 			if ( i != 2 || !(self = prima_xw2h( win)))  {
1222 				warn( "Bad parameters to sysaction setfont");
1223 				return 0;
1224 			}
1225 			if ( !opt_InPaint) return 0;
1226 			XSetFont( DISP, X(self)-> gc, XLoadFont( DISP, font));
1227 			return NULL;
1228 		}
1229 		if ( strcmp( "shaper", s) == 0) {
1230 			char shaper[64] = "";
1231 #ifdef USE_XFT
1232 			if ( guts. use_xft ) strcat(shaper, "xft ");
1233 #endif
1234 #ifdef WITH_HARFBUZZ
1235 			if ( guts. use_harfbuzz ) strcat(shaper, "harfbuzz ");
1236 #endif
1237 			shaper[strlen(shaper)-1] = 0;
1238 			return duplicate_string(shaper);
1239 		}
1240 		break;
1241 	case 't':
1242 		if ( strncmp( "textout16 ", s, 10) == 0) {
1243 			Handle self = NULL_HANDLE;
1244 			unsigned char text[1024];
1245 			XWindow win;
1246 			int x, y, len;
1247 			int i = sscanf( s + 10, "%lu %d %d %s", &win, &x, &y, text);
1248 			if ( i != 4 || !(self = prima_xw2h( win)))  {
1249 				warn( "Bad parameters to sysaction textout16");
1250 				return 0;
1251 			}
1252 			if ( !opt_InPaint) return 0;
1253 			len = strlen((char*) text);
1254 			for ( i = 0; i < len; i++) if ( text[i]==255) text[i] = 0;
1255 			XDrawString16( DISP, win, X(self)-> gc, x, y, ( XChar2b *) text, len / 2);
1256 			return NULL;
1257 		}
1258 		break;
1259 	case 'u':
1260 		if ( strcmp( s, "unix_guts") == 0)
1261 			return (char*) &guts;
1262 		break;
1263 	case 'x':
1264 		if ( strncmp(s, "xquartz.", 8) == 0) {
1265 			s += 8;
1266 #ifdef WITH_COCOA
1267 			if ( guts. use_quartz )
1268 				return prima_cocoa_system_action(( char*) s);
1269 #endif
1270 			return NULL;
1271 		}
1272 		break;
1273 	case 'X':
1274 		if ( strcmp( s, "XOpenDisplay") == 0) {
1275 			char err_buf[512];
1276 			if ( DISP)
1277 				return duplicate_string( "X display already opened");
1278 			window_subsystem_set_option( "yes-x11", NULL);
1279 			if ( !window_subsystem_init( err_buf))
1280 				return duplicate_string( err_buf);
1281 			return NULL;
1282 		}
1283 		break;
1284 	}
1285 	warn("Unknown sysaction:%s", s);
1286 	return NULL;
1287 }
1288 
1289 Bool
apc_query_drives_map(const char * firstDrive,char * result,int len)1290 apc_query_drives_map( const char* firstDrive, char *result, int len)
1291 {
1292 	if ( !result || len <= 0) return true;
1293 	*result = 0;
1294 	return true;
1295 }
1296 
1297 int
apc_query_drive_type(const char * drive)1298 apc_query_drive_type( const char *drive)
1299 {
1300 	return dtNone;
1301 }
1302 
1303 char *
apc_get_user_name(void)1304 apc_get_user_name( void)
1305 {
1306 	char * c = getlogin();
1307 	return c ? c : "";
1308 }
1309 
1310 Bool
apc_dl_export(char * path)1311 apc_dl_export(char *path)
1312 {
1313 	/* XXX */
1314 	return true;
1315 }
1316 
1317 void
prima_rect_union(XRectangle * t,const XRectangle * s)1318 prima_rect_union( XRectangle *t, const XRectangle *s)
1319 {
1320 	XRectangle r;
1321 
1322 	if ( t-> x < s-> x) r. x = t-> x; else r. x = s-> x;
1323 	if ( t-> y < s-> y) r. y = t-> y; else r. y = s-> y;
1324 	if ( t-> x + t-> width > s-> x + s-> width)
1325 		r. width = t-> x + t-> width - r. x;
1326 	else
1327 		r. width = s-> x + s-> width - r. x;
1328 	if ( t-> y + t-> height > s-> y + s-> height)
1329 		r. height = t-> y + t-> height - r. y;
1330 	else
1331 		r. height = s-> y + s-> height - r. y;
1332 	*t = r;
1333 }
1334 
1335 void
prima_rect_intersect(XRectangle * t,const XRectangle * s)1336 prima_rect_intersect( XRectangle *t, const XRectangle *s)
1337 {
1338 	XRectangle r;
1339 	int w, h;
1340 
1341 	if ( t-> x > s-> x) r. x = t-> x; else r. x = s-> x;
1342 	if ( t-> y > s-> y) r. y = t-> y; else r. y = s-> y;
1343 	if ( t-> x + t-> width < s-> x + s-> width)
1344 		w = t-> x + (int)t-> width - r. x;
1345 	else
1346 		w = s-> x + (int)s-> width - r. x;
1347 	if ( t-> y + t-> height < s-> y + s-> height)
1348 		h = t-> y + (int)t-> height - r. y;
1349 	else
1350 		h = s-> y + (int)s-> height - r. y;
1351 	if ( w < 0 || h < 0) {
1352 		r. x = 0; r. y = 0; r. width = 0; r. height = 0;
1353 	} else {
1354 		r. width = w; r. height = h;
1355 	}
1356 	*t = r;
1357 }
1358 
1359 
1360 void
prima_utf8_to_wchar(const char * utf8,XChar2b * u16,int src_len_bytes,int target_len_xchars)1361 prima_utf8_to_wchar( const char * utf8, XChar2b * u16, int src_len_bytes, int target_len_xchars )
1362 {
1363 	STRLEN charlen;
1364 	while ( target_len_xchars--) {
1365 		register UV u = prima_utf8_uvchr(utf8, src_len_bytes, &charlen);
1366 		if ( u < 0x10000) {
1367 			u16-> byte1 = u >> 8;
1368 			u16-> byte2 = u & 0xff;
1369 		} else
1370 			u16-> byte1 = u16-> byte2 = 0xff;
1371 		u16++;
1372 		utf8 += charlen;
1373 		src_len_bytes -= charlen;
1374 		if ( src_len_bytes <= 0 || charlen == 0) break;
1375 	}
1376 }
1377 
1378 XChar2b *
prima_alloc_utf8_to_wchar(const char * utf8,int length_chars)1379 prima_alloc_utf8_to_wchar( const char * utf8, int length_chars)
1380 {
1381 	XChar2b * ret;
1382 	if ( length_chars < 0) length_chars = prima_utf8_length( utf8, -1) + 1;
1383 	if ( !( ret = malloc( length_chars * sizeof( XChar2b)))) return NULL;
1384 	prima_utf8_to_wchar( utf8, ret, strlen(utf8), length_chars);
1385 	return ret;
1386 }
1387 
1388 void
prima_wchar2char(char * dest,XChar2b * src,int lim)1389 prima_wchar2char( char * dest, XChar2b * src, int lim)
1390 {
1391 	if ( lim < 1) return;
1392 	while ( lim-- && src-> byte1 && src-> byte2) *(dest++) = (src++)-> byte2;
1393 	if ( lim < 0) dest--;
1394 	*dest = 0;
1395 }
1396 
1397 void
prima_char2wchar(XChar2b * dest,char * src,int lim)1398 prima_char2wchar( XChar2b * dest, char * src, int lim)
1399 {
1400 	int l = strlen( src) + 1;
1401 	if ( lim < 1) return;
1402 	if ( lim > l) lim = l;
1403 	src  += lim - 2;
1404 	dest += lim - 1;
1405 	dest-> byte1 = dest-> byte2 = 0;
1406 	dest--;
1407 	while ( lim--) {
1408 		dest-> byte2 = *(src--);
1409 		dest-> byte1 = 0;
1410 		dest--;
1411 	}
1412 }
1413 
1414 /* printer stubs */
1415 
apc_prn_create(Handle self)1416 Bool   apc_prn_create( Handle self) { return false; }
apc_prn_destroy(Handle self)1417 Bool   apc_prn_destroy( Handle self) { return true; }
apc_prn_select(Handle self,const char * printer)1418 Bool   apc_prn_select( Handle self, const char* printer) { return false; }
apc_prn_get_selected(Handle self)1419 char * apc_prn_get_selected( Handle self) { return NULL; }
apc_prn_get_size(Handle self)1420 Point  apc_prn_get_size( Handle self) { Point r = {0,0}; return r; }
apc_prn_get_resolution(Handle self)1421 Point  apc_prn_get_resolution( Handle self) { Point r = {0,0}; return r; }
apc_prn_get_default(Handle self)1422 char * apc_prn_get_default( Handle self) { return NULL; }
apc_prn_setup(Handle self)1423 Bool   apc_prn_setup( Handle self) { return false; }
apc_prn_begin_doc(Handle self,const char * docName)1424 Bool   apc_prn_begin_doc( Handle self, const char* docName) { return false; }
apc_prn_begin_paint_info(Handle self)1425 Bool   apc_prn_begin_paint_info( Handle self) { return false; }
apc_prn_end_doc(Handle self)1426 Bool   apc_prn_end_doc( Handle self) { return true; }
apc_prn_end_paint_info(Handle self)1427 Bool   apc_prn_end_paint_info( Handle self) { return true; }
apc_prn_new_page(Handle self)1428 Bool   apc_prn_new_page( Handle self) { return true; }
apc_prn_abort_doc(Handle self)1429 Bool   apc_prn_abort_doc( Handle self) { return true; }
apc_prn_get_handle(Handle self)1430 ApiHandle   apc_prn_get_handle( Handle self) { return ( ApiHandle) 0; }
apc_prn_set_option(Handle self,char * option,char * value)1431 Bool   apc_prn_set_option( Handle self, char * option, char * value) { return false; }
1432 
apc_prn_get_option(Handle self,char * option,char ** value)1433 Bool apc_prn_get_option( Handle self, char * option, char ** value)
1434 {
1435 	*value = NULL;
1436 	return false;
1437 }
1438 
apc_prn_enum_options(Handle self,int * count,char *** options)1439 Bool apc_prn_enum_options( Handle self, int * count, char *** options)
1440 {
1441 	*count = 0;
1442 	return false;
1443 }
1444 
1445 PrinterInfo *
apc_prn_enumerate(Handle self,int * count)1446 apc_prn_enumerate( Handle self, int * count)
1447 {
1448 	*count = 0;
1449 	return NULL;
1450 }
1451 
1452 char *
apc_last_error(void)1453 apc_last_error( void )
1454 {
1455 	return NULL;
1456 }
1457 
1458