1 
2 #include "pointer.h"
3 #include "stipple.h"
4 #ifndef _xsound_h
5 #	include "xsound.h"
6 #endif
7 
8 #ifndef _game_h
9 #	include "game.h"
10 #endif
11 #ifndef _rgb_h
12 #	include "rgb.h"
13 #endif
14 
15 #include <stdarg.h>
16 
17 Display	*dpy;			// the display connection
18 int		scr;			// default screen of the display
19 Window	win;			// the output window
20 Window	new_root=0;	// a surrounding black window, when started with option -root (default)
21 Colormap	cmap;			// the colormap used for the window
22 Colormap	local_cmap;	// flag, if the colormap had to be created local
23 
24 static int	nbg_cols_all;
25 static int	bg_unused;
26 static int	nball_cols_to_alloc;
27 
28 Pixmap	pointer_pmap;		// Pixmap (wird vom PBall benutzt)
29 int		pointer_off_x, pointer_off_y;
30 
31 static Pixmap		stipple_pmap=0;
32 
33 // The stipple cache is used to store the 'textured' pixmap to
34 // reuse some on several output-operation.
35 #define STIPPLE_CACHE	10
36 static const int	stipple_sz=128;
37 static Pixmap		rand_stipple[STIPPLE_CACHE];
38 static long			rand_col[STIPPLE_CACHE];
39 
40 static unsigned long	start_seconds;
41 
42 static int	info_ch = 0;
43 
44 #ifdef STATISTICS
45 static	GC	gc_text;
46 static int	info_cw = 0;
47 
48 static XFontStruct *fs = 0;
49 static Font	info_font;
50 static unsigned long info_fg, info_bg;
51 static const int info_width = 16;
52 static int info_offset = 0;
53 
showinfo(StatType stat,const char * info)54 void showinfo( StatType stat, const char *info ) {
55 static info_toggle=0;
56 
57 	if (new_root) {
58 		int len = strlen(info);
59 		if (stat==OffsetInfo) {
60 			if (len) {
61 				info_toggle^=1;
62 				if (info_toggle) {
63 					XSetForeground( dpy, gc_text, info_bg );
64 					XSetBackground( dpy, gc_text, info_fg );
65 				}
66 			}
67 			else {
68 				info = "                  ";
69 				len = 20;
70 			}
71 		}
72 		XDrawImageString( dpy, new_root,
73 			gc_text,
74 			info_offset - (stat+1)*info_width*info_cw,
75 			DisplayHeight(dpy,scr)- 1,
76 			info, len);
77 
78 		if ((stat==OffsetInfo) && (info_toggle)) {
79 			XSetForeground( dpy, gc_text, info_fg );
80 			XSetBackground( dpy, gc_text, info_bg );
81 		}
82 	}
83 }
84 
85 #define	GRAPH_SIZE_X	50
86 #define	GRAPH_SIZE_Y	800
graphinfo(int value)87 void graphinfo( int value ) {
88 static int row=-1;
89 	if (row<0) {
90 		for (row=0;row<=GRAPH_SIZE_Y;row+=20) {
91 			for (int i=0;i<=100;i+=20) {
92 				XDrawPoint(dpy,new_root,gc_text,row,DisplayHeight(dpy,scr)-1-i );
93 			}
94 		}
95 		row=0;
96 	}
97 	if (value>120)	value=120;
98 
99 	XSetForeground( dpy, gc_text, info_bg );
100 	XDrawLine(dpy, new_root, gc_text,
101 		row, DisplayHeight(dpy,scr)-1,
102 		row, DisplayHeight(dpy,scr)-1-GRAPH_SIZE_X);
103 	XSetForeground( dpy, gc_text, info_fg );
104 	if (row%20==0) {
105 		for (int i=0;i<=100;i+=20) {
106 			XDrawPoint(dpy, new_root, gc_text, row, DisplayHeight(dpy,scr)-1-i );
107 		}
108 	}
109 	XDrawLine(dpy, new_root, gc_text,
110 		row, DisplayHeight(dpy,scr)-1-value+1,
111 		row, DisplayHeight(dpy,scr)-1-value-1);
112 	row++;
113 	if (row>GRAPH_SIZE_Y)	row=0;
114 	XDrawLine(dpy, new_root, gc_text,
115 		row, DisplayHeight(dpy,scr)-1,
116 		row, DisplayHeight(dpy,scr)-11);
117 }
118 #endif
119 
120 
InitTime()121 static void InitTime() {
122 struct timeval start;
123 
124 	X_GETTIMEOFDAY( &start );				// comes with X11R6 (see stdinc.h)
125 	start_seconds = start.tv_sec;
126 }
127 
GetCurrentTime()128 double GetCurrentTime() {
129 struct timeval	current;
130 
131 	X_GETTIMEOFDAY( &current );			// comes with X11R6 (see stdinc.h)
132 	return( ((double)(current.tv_sec-start_seconds))+(current.tv_usec/1000000.0) );
133 }
134 
135 
136 GC		gc_default;
137 
138 GC		gc_lay1;
139 GC		gc_lay2;
140 GC		gc_cursor;
141 
142 GC		gc_current;
143 
144 GC		gc_bxor;
145 GC		gc_bclear;
146 
147 GC		gc_ballwhite;
148 GC		gc_ball[MAX_BALL];
149 
150 
SetBgColor(ColorId col)151 void SetBgColor( ColorId col ) {
152 	gc_current = gc_default;
153 
154 //
155 // set the foreground pixel
156 //
157 	if (col&BG_MASK) {
158 		XSetForeground( dpy, gc_current, ball_pix[0]|bg_pix[col&COLOR_MASK] );
159 	}
160 	else if (col&STAT_MASK) {
161 		XSetForeground( dpy, gc_current, stat_pix[col&COLOR_MASK] );
162 	}
163 	else {
164 		XSetForeground( dpy, gc_current, ball_pix[col&COLOR_MASK] );
165 	}
166 
167 //
168 // set background (when in mixed mode)
169 //
170 	if (col&MIX_MASK) {
171 	//
172 	// set background color
173 	//
174 		if ((col>>COLOR_BITS)&BG_MASK) {
175 			XSetBackground( dpy, gc_current,
176 								ball_pix[0]|bg_pix[(col>>COLOR_BITS)&COLOR_MASK] );
177 		}
178 		else if ((col>>COLOR_BITS)&STAT_MASK) {
179 			XSetBackground(dpy,gc_current,stat_pix[(col>>COLOR_BITS)&COLOR_MASK]);
180 		}
181 		else {
182 			XSetBackground(dpy,gc_current,ball_pix[(col>>COLOR_BITS)&COLOR_MASK]);
183 		}
184 
185 	//
186 	// set (or create) background stipple
187 	//
188 		if (col&RAND_MASK) {
189 			int i;
190 			for (i=0;i<STIPPLE_CACHE;i++) {
191 				if (col==rand_col[i])	break;
192 				if (rand_col[i]==0)		break;
193 			}
194 			if (i==STIPPLE_CACHE) {
195 				XFreePixmap(dpy,rand_col[0]);			// drop first map
196 				for (i=0;i<STIPPLE_CACHE-1;i++) {	// shift other maps
197 					rand_col[i]     = rand_col[i+1];
198 					rand_stipple[i] = rand_stipple[i+1];
199 				}
200 				rand_col[i] = 0;							// mark last cache as unused
201 			}
202 
203 			if (!rand_col[i]) {
204 				// create a new map for the given color
205 				rand_col[i]    =col;
206 				rand_stipple[i]=XCreatePixmap(dpy,win,stipple_sz,stipple_sz,1);
207 
208 				GC	gc = XCreateGC( dpy, rand_stipple[i], 0, 0L );
209 				XSetFunction(dpy,gc,GXset);
210 				XFillRectangle(dpy,rand_stipple[i],gc,0,0,stipple_sz,stipple_sz);
211 				XSetFunction(dpy,gc,GXclear);
212 				for (int j=stipple_sz*stipple_sz/
213 								((int)((col&RAND_MASK)>>RAND_SHIFT)+1); j>0;j--) {
214 					XDrawPoint(dpy,rand_stipple[i],gc,rand()%stipple_sz,rand()%stipple_sz);
215 				}
216 				XFreeGC(dpy,gc);
217 			}
218 			XSetStipple( dpy, gc_current, rand_stipple[i] );
219 		}
220 		else {
221 			XSetStipple( dpy, gc_current, stipple_pmap );
222 		}
223 		XSetFillStyle( dpy, gc_current, FillOpaqueStippled );
224 	}
225 	else {
226 		XSetFillStyle( dpy, gc_current, FillSolid );
227 	}
228 }
229 
ParseColor(const char * name,XColor * col)230 int ParseColor( const char *name, XColor *col ) {
231 RGBColor	rgbcol;
232 
233 	if ( rgbcol.SetColor(name)==0 ) {
234 			col->red   = rgbcol.red   | (rgbcol.red  <<8);
235 			col->green = rgbcol.green | (rgbcol.green<<8);
236 			col->blue  = rgbcol.blue  | (rgbcol.blue <<8);
237 		//	printf("'%s': %04x/%04x/%04x\n",name,col->red,col->green,col->blue);
238 		 	return 0;
239 	}
240 	if (XParseColor(dpy,cmap,name,col))			return 0;
241 	else {
242 		fprintf(stderr,"failed to query RGB-values for '%s'\n",name );
243 		return -1;
244 	}
245 }
246 
StoreColor(unsigned pixel)247 int StoreColor( unsigned pixel ) {
248 			long	stat=-1;
249 unsigned long	bgc;
250 			int	nbgc;
251 unsigned long	shc;
252 			int	nshc;
253 unsigned long	cuc;
254 unsigned long	bc;
255 			int	nbc;
256 
257 		bgc = pixel&bg_mask;			// Hintergrund
258 		for (nbgc=(nbg_cols_all-1)-1;nbgc>=0;nbgc--) {// passenden Index suchen
259 			if (bg_pix[nbgc]==bgc)		break;
260 		}
261 		if ((bgc)&&nbgc>=nbg_cols) {
262 				stat = nbgc-nbg_cols;				// unbenutztes Pixel -> static
263 		}
264 
265 		shc = pixel&shade_mask;		// Schattierung
266 		for (nshc=0;nshc<nshade_cols;nshc++) {			// passenden Index suchen
267 			if (shade_pix[nshc]==shc)		break;
268 		}
269 		if ((shc)&&nshc>=nshade_cols) {
270 				printf( "not implemented: shaded %d free for static\n", pixel );
271 				return -1;		// unbenutztes Pixel
272 		}
273 
274 		cuc = pixel&cursor_mask;   // Cursor
275 
276 		bc  = pixel-bgc-shc-cuc;	// Ballfarbe
277 		for (nbc=0;nbc<nball_cols_to_alloc;nbc++) {		// passenden Index suchen
278 			if (ball_pix[nbc]==bc)		break;
279 		}
280 		if (nbc>=nball_cols_to_alloc)		return -1;
281 
282 		if (nbc>=nball_cols) {
283 			stat = nball_cols*bg_unused + (nbc-nball_cols)*(nbg_cols_all)
284 					+ ((nbgc>=0)?nbgc+1:0);
285 		}
286 		else {
287 			if (stat>=0)	stat+=(nbc*bg_unused);
288 		}
289 
290 XColor 	col;
291 
292 	if (cuc&&(stat<nstat_cols)) {
293 		ParseColor(cursor_col, &col );
294 	}
295 	else {
296 		if (stat>=0) {
297 			if (stat<nstat_cols) {
298 				ParseColor(stat_col[stat], &col );
299 				if (!shc) {
300 					DBG2( ShowColors, "Static %2ld at pixel %3d\n", stat, pixel );
301 					stat_pix[stat] = pixel;
302 				}
303 			}
304 			else return -1;
305 		}
306 		else if (nbc) {
307 				ParseColor(ball_col[nbc], &col );		// RGB-Werte lesen
308 		}
309 		else if (bgc) {
310 				ParseColor(bg_col[nbgc], &col );		// RGB-Werte lesen
311 		}
312 		else	ParseColor(ball_col[0], &col );
313 
314 		if (shc) {
315 			XColor	scol;
316 			ParseColor(shade_col[nshc], &scol );	// RGB-Werte lesen
317 
318 			col.red   = (col.red  *m[nshc] + scol.red  *d[nshc])/(m[nshc]+d[nshc]);
319 			col.green = (col.green*m[nshc] + scol.green*d[nshc])/(m[nshc]+d[nshc]);
320 			col.blue  = (col.blue *m[nshc] + scol.blue *d[nshc])/(m[nshc]+d[nshc]);
321 		}
322 	}
323 
324 	col.pixel = pixel;
325 	col.flags = DoRed|DoGreen|DoBlue;
326 	XStoreColor( dpy,cmap,&col);
327 	return 0;
328 }
329 
StoreColors()330 void StoreColors() {
331 	for (int i=0;i<256;i++)	StoreColor(i);
332 }
333 
GetBlackPixel()334 unsigned long GetBlackPixel() {
335 unsigned long erg=GetAllocatedPixel( "black" );
336 
337 	if (erg)		return erg;
338 	else			return BlackPixel(dpy,scr);
339 }
340 
AllocColors()341 void AllocColors() {
342 unsigned long plane_mask[8];
343 int	nplanes = 0;
344 int	n;
345 
346 	nball_cols_to_alloc = nball_cols;
347 //
348 // Ausrechnen, wieviele Planes ben�tigt werden
349 //
350 	n = nbg_cols;		// Planes f�r Hintergrund sammeln
351 	while( n )	{ nplanes++;	n>>=1; }
352 	nbg_cols_all = (1<<nplanes);
353 	bg_unused    = nbg_cols_all-1-nbg_cols;
354 	n = nshade_cols;
355 	while( n )	{ nplanes++;	n>>=1; }
356 	if (cursor_col)	nplanes++;
357 
358 //
359 // Anfordern der Farben
360 //
361 	DBG1( ShowColors, "Graphic: %d planes\n", nplanes );
362 	DBG1( ShowColors, "Graphic: %d ball colors\n", nball_cols );
363 	DBG1( ShowColors, "Graphic: %d static colors\n", nstat_cols );
364 	while (nstat_cols>nball_cols*bg_unused
365 							+(nball_cols_to_alloc-nball_cols)*(nbg_cols_all)) {
366 		nball_cols_to_alloc++;
367 	}
368 	DBG1( ShowColors, "Graphic: %d statics 'between planes'\n", nball_cols*bg_unused );
369 	DBG1( ShowColors, "Graphic: allocating %d ball colors\n", nball_cols_to_alloc );
370 
371 	cmap = DefaultColormap( dpy, scr );
372 	if (XAllocColorCells( dpy, cmap, False,
373 					plane_mask, nplanes, ball_pix, nball_cols_to_alloc )==0) {
374 		DBG0( UnixTrace,
375 						"Allocation of colors failed - creating local colormap.\n" );
376 		cmap= XCreateColormap(dpy,win,DefaultVisual(dpy,scr),AllocNone);
377 		if (XAllocColorCells( dpy, cmap, False,
378 					plane_mask, nplanes, ball_pix, nball_cols_to_alloc )==0) {
379 				fprintf(stderr, "not enough colors: " );
380 				fprintf(stderr, "I need %d colors + %d planes.\n",
381 							nball_cols_to_alloc, nplanes );
382 				exit(0);
383 		}
384 		if (new_root) {
385 				XSetWindowAttributes	attrib;
386 				attrib.colormap = cmap;
387 				XChangeWindowAttributes( dpy, new_root, CWColormap, &attrib );
388 				XSetWindowColormap( dpy, new_root, cmap );
389 		}
390 		else {
391 				XSetWindowAttributes	attrib;
392 				attrib.colormap = cmap;
393 				XChangeWindowAttributes( dpy, win, CWColormap, &attrib );
394 				XSetWindowColormap( dpy, win, cmap );
395 		}
396 		XSync(dpy,0);
397 	}
398 
399 //
400 // Verteilen der Planes auf die Farben
401 //
402 int c=0;
403 	for (n=0;n<nbg_cols+bg_unused;n++) {
404 		bg_pix[n] = 0;
405 		if ((n+1)&1)		bg_pix[n]+=plane_mask[c+0];
406 		if ((n+1)&2)		bg_pix[n]+=plane_mask[c+1];
407 		if ((n+1)&4)		bg_pix[n]+=plane_mask[c+2];
408 	}
409 	n=nbg_cols;
410 	bg_mask=0;
411 	while(n)		{ bg_mask+=plane_mask[c++];		n>>=1; }
412 
413 	for (n=0;n<nshade_cols;n++) {
414 		shade_pix[n] = 0;
415 		if ((n+1)&1)		shade_pix[n]+=plane_mask[c+0];
416 		if ((n+1)&2)		shade_pix[n]+=plane_mask[c+1];
417 		if ((n+1)&4)		shade_pix[n]+=plane_mask[c+2];
418 	}
419 	n=nshade_cols;
420 	shade_mask=0;
421 	while(n)		{ shade_mask+=plane_mask[c++];	n>>=1; }
422 
423 	if (cursor_col) {
424 		cursor_mask = plane_mask[c];
425 	}
426 
427 	ball_mask=0;
428 	for (n=0;n<nball_cols_to_alloc;n++) {
429 		ball_mask|=ball_pix[n];
430 	}
431 //
432 // Farben eintragen
433 //
434 	StoreColors();							// Farben in Tabelle eintragen
435 //
436 // GC's besetzen
437 //
438 unsigned long	value_mask;
439 XGCValues		values;
440 
441 	value_mask =	GCPlaneMask | GCForeground | GCBackground | GCFunction
442 					|	GCArcMode | GCStipple | GCFillStyle | GCGraphicsExposures;
443 	values.graphics_exposures = False;
444 	values.foreground = 0xffff;
445 	values.background = 0;
446 	values.function	= GXxor;
447 	values.arc_mode	= ArcChord;		// statt ArcPieSlice
448 	stipple_pmap      =
449 	values.stipple		= XCreateBitmapFromData( dpy, RootWindow( dpy, scr ),
450 									stipple_bits, stipple_width, stipple_height );
451 	values.fill_style	= FillSolid;
452 #ifdef STATISTICS
453 	values.font= info_font;
454 	if (values.font)	value_mask|=GCFont;
455 #endif
456 
457 	values.plane_mask  = bg_pix[0];
458 	gc_lay1 = XCreateGC( dpy, RootWindow( dpy, scr ), value_mask, &values );
459 	values.plane_mask  = shade_pix[0];
460 	gc_lay2 = XCreateGC( dpy, RootWindow( dpy, scr ), value_mask, &values );
461 
462 	values.plane_mask  = cursor_mask;
463 	gc_cursor = XCreateGC( dpy, RootWindow( dpy, scr ), value_mask, &values );
464 
465 //
466 // Default Graphic-Context erzeugen
467 //
468 	values.foreground = ball_pix[0];
469 	values.plane_mask = ball_mask | shade_pix[0];		// Arbeiten in lay2
470 	values.function   = GXxor;
471 	gc_bxor = XCreateGC( dpy, RootWindow( dpy, scr ), value_mask, &values );
472 	values.function   = GXclear;
473 	gc_bclear = XCreateGC( dpy, RootWindow( dpy, scr ), value_mask, &values );
474 
475 	values.plane_mask	= ball_mask|shade_mask|bg_mask|cursor_mask;
476 	values.function	= GXcopy;
477 	gc_default = XCreateGC( dpy, RootWindow( dpy, scr ), value_mask, &values );
478 
479 	values.plane_mask	= ball_mask;
480 	gc_ball[0] = XCreateGC( dpy, RootWindow( dpy, scr ), value_mask, &values );
481 //
482 // Kontext f�r den Text
483 //
484 #ifdef STATISTICS
485 	values.foreground = info_fg = ball_pix[0];
486 	values.background = info_bg = GetBlackPixel();
487 	values.plane_mask  = AllPlanes;
488 	gc_text    = XCreateGC( dpy, RootWindow( dpy, scr ), value_mask, &values );
489 
490 	info_offset = (DisplayWidth(dpy,scr)+max_x)/2;
491 #endif
492 //
493 // GC's f�r die Ballfarben
494 //
495 unsigned long white_pix=0;
496 
497 	values.fill_style = FillSolid;
498 	values.plane_mask = ball_mask;
499 	values.function	= GXxor;
500 	values.background = 0;
501 	if (deluxe) {
502 		white_pix = GetAllocatedPixel( "ivory" );
503 		if (!white_pix) {
504 			fprintf( stderr, "white color 'ivory' missing for ball-underground\n");
505 			exit(-1);
506 		}
507 		values.foreground = (white_pix^ball_pix[0]);
508 		gc_ballwhite=XCreateGC(dpy,RootWindow(dpy,scr),value_mask,&values);
509 	}
510 
511 
512 	for (int i=0;i<nball_ids;i++) {
513 		ColorId	col = ball_ids[i];
514 
515 		if (deluxe) values.foreground = white_pix^ball_pix[col&COLOR_MASK];
516 		else			values.foreground = ball_pix[0]^ball_pix[col&COLOR_MASK];
517 		if (col&MIX_MASK) {
518 			values.foreground = ball_pix[0]^ball_pix[(col>>COLOR_BITS)&COLOR_MASK];
519 			values.fill_style = FillOpaqueStippled;
520 		}
521 		else {
522 			values.fill_style = FillSolid;
523 		}
524 
525 		gc_ball[i]=XCreateGC( dpy, RootWindow( dpy, scr ), value_mask, &values );
526 	}
527 //
528 // Pixmaps erzeugen
529 //
530 	pointer_pmap = XCreatePixmapFromBitmapData(dpy,win,
531 			pointer_bits, pointer_width, pointer_height, cursor_mask, 0,
532 			DefaultDepth(dpy,scr) );
533 	pointer_off_x = pointer_x_hot;
534 	pointer_off_y = pointer_y_hot;
535 
536 #ifdef DEBUG
537 	if (debug&Sync) {
538 		XSynchronize(dpy,1);
539 	}
540 	if ((debug&ShowSubWindow)&&(!new_root)) {
541 		XSizeHints				hints;
542 
543 		hints.flags = PPosition | PSize | PAspect | PMinSize | PMaxSize;
544 		hints.x = (DisplayWidth(dpy,scr) -max_x)/2;
545 		hints.y = 0;
546 		hints.width  = hints.min_width  = hints.max_width  = max_x;
547 		hints.height = hints.min_height = hints.max_height = max_y;
548 		XSetWMNormalHints( dpy,win,&hints );
549 	}
550 #endif
551 
552 #ifdef DEBUG
553 	if (debug&ShowColors) {
554 Window	help;
555 const int lpixs_x = 16;
556 const int lpixs_y = 16;
557 const int d=16;
558 const int o=2;
559 
560 // To overcome a bug? in the fvwm window-manager, the server is now
561 // synchronized and a pause for a second is taken. I wonder what fvwm
562 // is doing in that second ...
563 
564 XSync(dpy,0);
565 printf( "wait a second, so that even the FVWM gets a change for not crashing\n" );
566 sleep(1);
567 
568 		help = CreateWindow("Noname",lpixs_x*(d+o)+1 ,lpixs_y*(d+o)+1);
569 
570 		for (int px=0;px<lpixs_x;px++) {
571 			for (int py=0;py<lpixs_y;py++) {
572 				if (!StoreColor(px+py*lpixs_x)) {
573 					XSetForeground(dpy,gc_default,px+py*lpixs_x);
574 					XFillRectangle(dpy,help,gc_default,1+px*(d+o),1+py*(d+o),d,d );
575 				}
576 			}
577 		}
578 	}
579 #endif
580 }
581 
582 
MapMainWindow()583 void MapMainWindow() {
584 XEvent	event;
585 
586 	XSetWindowBackground( dpy, win, ball_pix[0] );
587 	XMapRaised( dpy, win );
588 	if (new_root) {
589 		XSetWindowBackground( dpy, new_root, GetBlackPixel() );
590 		XMapRaised( dpy, new_root );
591 		if (!no_override)	XInstallColormap( dpy, cmap );
592 	}
593 	XWindowEvent( dpy, win, ExposureMask, &event );
594 	XSetInputFocus( dpy, win, RevertToNone, CurrentTime );
595 	XSync(dpy,0);
596 }
597 
598 
CreateWindow(const char * name,int width,int height)599 Window CreateWindow( const char *name, int width, int height )
600 {
601 Window	win;
602 XSetWindowAttributes	attrib;
603 XSizeHints				hints;
604 XEvent	event;
605 static	int	offx=10;
606 const	int frame = 7;
607 
608 	hints.flags = PPosition | PSize | PAspect | PMinSize | PMaxSize;
609 	hints.x = DisplayWidth(dpy,scr) -offx-width-frame;
610 	hints.y = DisplayHeight(dpy,scr)-height-2*frame,
611 	hints.width  = hints.min_width  = hints.max_width  = width;
612 	hints.height = hints.min_height = hints.max_height = height;
613 	offx+=width+2*frame;
614 
615 		win = XCreateSimpleWindow( dpy, RootWindow(dpy,scr),
616 					hints.x, hints.y, hints.width, hints.height,
617 					0, ball_pix[0], ball_pix[0] );
618 	attrib.colormap = cmap;
619 	XChangeWindowAttributes( dpy, win, CWColormap, &attrib );
620 
621 	XSetWMNormalHints( dpy,win,&hints );
622 
623 	XStoreName( dpy, win, name );
624 	XSelectInput( dpy,win,ExposureMask );
625 	XMapRaised( dpy, win );
626 	XWindowEvent( dpy, win, ExposureMask, &event );
627 printf( "window '%s' mapped and raised at (%d,%d) size: (%dx%d)\n", name, hints.x, hints.y, hints.width, hints.height );
628 	return win;
629 }
630 
InitGraphic(double x,double y)631 void InitGraphic( double x, double y )
632 {
633 XSetWindowAttributes	setwinattr;
634 
635 #if (SOUND_SUBSYSTEM)
636 	if (sound_request)		init_sound( "" );
637 #endif
638 
639 	dpy = XOpenDisplay( "" );
640 	if (!dpy) {
641 		fprintf( stderr, "can't open display\n" );
642 		exit(0);
643 	}
644 	scr = DefaultScreen(dpy);
645 
646 #ifdef STATISTICS
647 	fs=XLoadQueryFont(dpy,"5x8");
648 	if (!fs) {	fs=XLoadQueryFont(dpy,"6x10");
649 				if (!fs)	fs=XLoadQueryFont(dpy,"fixed");
650 	}
651 	if (fs) {
652 		info_font = fs->fid;
653 		info_cw   = XTextWidth(fs,"A",1);
654 		info_ch   = fs->ascent + fs->descent;
655 	}
656 #endif
657 
658 //
659 // Gr��e des Fensters bestimmen: Fenster zentrieren
660 //
661 int	dp_height = DisplayHeight(dpy,scr)-info_ch;
662 
663 	world_x = x;
664 	world_y = y;
665 	if ( size>0 ) {
666 		if (size>DisplayWidth(dpy,scr))		size = DisplayWidth(dpy,scr);
667 		max_x = size;
668 		max_y = (int)(size/world_x*world_y);
669 		if (max_y>dp_height) {
670 			max_y = dp_height;
671 			size = max_x = (int)(max_y/world_y*world_x);
672 		}
673 	}
674 	else if ( ((double)DisplayWidth(dpy,scr))/dp_height < world_x/world_y ) {
675 		max_x  = DisplayWidth(dpy,scr);
676 		max_y = (int)(max_x/world_x*world_y);
677 	}
678 	else {
679 		max_y = dp_height;
680 		max_x = (int)(max_y/world_y*world_x);
681 	}
682 
683 //
684 	if ( size<=0 ) {
685 		setwinattr.override_redirect = (no_override)?False:True;
686 		new_root = XCreateSimpleWindow( dpy, RootWindow( dpy, scr ),
687 					0, 0, DisplayWidth( dpy,scr ), DisplayHeight( dpy,scr ),
688 					0, WhitePixel( dpy,scr ), BlackPixel( dpy,scr ) );
689 		XChangeWindowAttributes( dpy, new_root, CWOverrideRedirect, &setwinattr );
690 
691 		win = XCreateSimpleWindow( dpy, new_root,
692 					(DisplayWidth( dpy,scr )-max_x)/2,
693 					(dp_height-max_y)/2,
694 					max_x, max_y, 0, BlackPixel( dpy,scr ),WhitePixel( dpy,scr ) );
695 		XSelectInput( dpy, new_root,	ColormapChangeMask|FocusChangeMask|KeyPressMask );
696 		XSelectInput( dpy, win, ExposureMask|KeyPressMask );
697 		setwinattr.backing_store = (0)?Always:NotUseful;
698 		setwinattr.bit_gravity   = ForgetGravity;;
699 		XChangeWindowAttributes(dpy,win,CWBitGravity|CWBackingStore,&setwinattr );
700 		w2n = (max_x-2)/world_x;
701 	}
702 	else {
703 		new_root = 0;
704 		win = XCreateSimpleWindow( dpy, RootWindow( dpy, scr ),
705 					0,0 , max_x, max_y, 2, 0,0 );
706 		XSelectInput( dpy, win, KeyPressMask|ExposureMask);
707 		setwinattr.backing_store = (0)?Always:NotUseful;
708 		setwinattr.bit_gravity   = ForgetGravity;;
709 		XChangeWindowAttributes(dpy,win,CWBitGravity|CWBackingStore,&setwinattr );
710 		w2n = (max_x-2)/world_x;
711 	}
712 
713 //
714 // BellPitch einstellen
715 //
716 	XStoreName( dpy, win, "flying" );
717 	InitTime();					// Initialisierung der Zeitmessung
718 }
719 
UnlockGraphic()720 void UnlockGraphic() {
721 	XUngrabServer(dpy);
722 	XSync(dpy,0);
723 	no_server_grabs+=100;
724 }
725 
CloseGraphic()726 void CloseGraphic()
727 {
728 int	i;
729 #ifdef STATISTICS
730 	if (fs)		XFreeFont(dpy,fs);
731 #endif
732 	for (i=0;i<STIPPLE_CACHE;i++) {
733 		if (rand_stipple[i])		XFreePixmap(dpy,rand_stipple[i]);
734 		rand_stipple[i]=0;
735 		rand_col[i]=0;
736 	}
737 
738 	XFreePixmap( dpy, pointer_pmap );
739 	XFreePixmap( dpy, stipple_pmap );
740 
741 	XFreeGC( dpy, gc_default );
742 
743 	XFreeGC( dpy, gc_lay1 );
744 	XFreeGC( dpy, gc_lay2 );
745 	XFreeGC( dpy, gc_cursor );
746 
747 	XFreeGC( dpy, gc_bxor );
748 	XFreeGC( dpy, gc_bclear );
749 
750 	if (deluxe)		XFreeGC( dpy, gc_ballwhite );
751 	for (i=0;i<nball_ids;i++) {
752 		XFreeGC( dpy, gc_ball[i] );
753 	}
754 
755 #ifdef STATISTICS
756 	XFreeGC( dpy, gc_text );
757 #endif
758 
759 	if (new_root) {
760 		XUninstallColormap( dpy, cmap );
761 	}
762 	if (cmap!=DefaultColormap( dpy, scr )) {
763 		XFreeColormap(dpy,cmap);
764 	}
765 
766 	end_sound();
767 	XSync( dpy, 0 );
768 	XCloseDisplay( dpy );
769 }
770 
771 
772 
773 
774 
GetKey()775 char	GetKey()
776 {
777 XEvent	event;
778 
779 	XSync( dpy, 0 );
780 	PBall::WaitForEvents();
781 
782 	while (XEventsQueued( dpy, QueuedAfterFlush )) {
783 		XNextEvent( dpy, &event );
784 		switch( event.xany.type ) {
785 		case KeyPress:
786 		{	char				buffer=0;
787 			XComposeStatus	compose;
788 			KeySym			keysym;
789 
790 			XLookupString( (XKeyEvent*)&event, &buffer, 1, &keysym, &compose );
791 			if (buffer!='\014') {
792 				if (isupper(buffer))		return tolower(buffer);
793 				return buffer;
794 			}
795 			// run straight down to the exposure event when ^L was pressed
796 		}
797 		case Expose:
798 		{
799 			while( XCheckMaskEvent( dpy, ExposureMask, &event ))
800 											;
801 			XClearWindow( dpy, win );
802 			g->ExposeRedraw();
803 			PBallTop::ForAll( &PBallTop::Redraw );
804 			break;
805 		}
806 		case ColormapNotify:
807 			while( XCheckMaskEvent( dpy, ColormapChangeMask, &event ));
808 			if (event.xcolormap.state!=ColormapInstalled && event.xcolormap.colormap==cmap) {
809 				printf( "### colormap was uninstalled by window manager\n" );
810 				if (no_server_grabs) {
811 					printf( "    please let me grab the server or try the option -no_override\n" );
812 					exit(0);
813 				}
814 				else {
815 					printf( "    I AM GRABBING THE SERVER NOW ...\n" );
816 				}
817 				XGrabServer(dpy);
818 				XInstallColormap(dpy,cmap);
819 				no_server_grabs-=100;
820 			}
821 			break;
822 		case FocusIn:
823 		//	printf( "focus: In\n" );
824 			break;
825 		case FocusOut:
826 		//	printf( "focus: Out\n" );
827 			break;
828 		default:
829 			break;
830 		}
831 	}
832 	return 0;
833 }
834 
835 
836 #define XPix(x)	((int)((x)*w2n))
837 #define YPix(y)	((int)((y)*w2n))
838 #define Pix(r)		((int)((r)*w2n))
839 
DrawLine(const Real & x1,const Real & y1,const Real & x2,const Real & y2)840 void DrawLine( const Real& x1, const Real& y1, const Real& x2, const Real& y2 ) {
841 int	px1 = XPix(x1);
842 int	py1 = YPix(y1);
843 int	px2 = XPix(x2);
844 int	py2 = YPix(y2);
845 	XDrawLine( dpy, win, gc_current, px1, py1, px2, py2 );
846 }
847 
848 
DrawArc(const Real & x,const Real & y,const Real & r,const Real & from,const Real & angle)849 void DrawArc( const Real& x, const Real& y, const Real& r, const Real& from, const Real& angle ) {
850 int	px  = XPix(x-r);
851 int	py  = YPix(y-r);
852 int	size= Pix(2.*r);
853 
854 	XDrawArc( dpy, win, gc_current,
855 				px, py, size, size,
856 				(int)(from*64.), (int)(angle*64.) );
857 }
858 
859 
DrawCircle(const Real & x,const Real & y,const Real & r)860 void DrawCircle( const Real& x, const Real& y, const Real& r ) {
861 int	px  = XPix(x-r);
862 int	py  = YPix(y-r);
863 int	size= Pix(2.*r);
864 
865 	XDrawArc( dpy, win, gc_current,
866 				px, py, size, size,
867 				0, (int)360*64 );
868 }
869 
870 
FillArc(const Real & x,const Real & y,const Real & r,const Real & from,const Real & angle)871 void FillArc( const Real& x, const Real& y, const Real& r, const Real& from, const Real& angle ) {
872 int	px  = XPix(x-r);
873 int	py  = YPix(y-r);
874 int	size= Pix(2.*r);
875 
876 	XFillArc( dpy, win, gc_current,
877 				px, py, size, size,
878 				(int)(from*64.), (int)(angle*64.) );
879 }
880 
FillCircle(const Real & x,const Real & y,const Real & r)881 void FillCircle( const Real& x, const Real& y, const Real& r ) {
882 int	px  = XPix(x-r);
883 int	py  = YPix(y-r);
884 int	size= Pix(2.*r);
885 
886 	XFillArc( dpy, win, gc_current,
887 				px, py, size, size,
888 				0, (int)360*64 );
889 }
890 
891 
FillRectangle(const Real & x,const Real & y,const Real & width,const Real & height)892 void FillRectangle( const Real& x, const Real& y, const Real& width, const Real& height ) {
893 int	px1 = XPix(x);
894 int	py1 = YPix(y);
895 int	px2 = XPix(x+width);
896 int	py2 = YPix(y+height);
897 	XFillRectangle( dpy, win, gc_current, px1, py1, px2-px1, py2-py1 );
898 }
899 
FillPoly(int n,...)900 void FillPoly( int n, ... ) {
901 va_list	argptr;
902 Vec2	*v;
903 int		i;
904 XPoint	buffer[10];
905 XPoint	*p;				// Zeiger auf Puffer, um gegebenenfalls mehr anzufordern
906 
907 	va_start(argptr,n);
908 
909 	if (sizeof(buffer)/sizeof(XPoint)<(unsigned)n)	p=new XPoint[n];
910 	else															p=buffer;
911 
912 	for (i=0;i<n;i++) {
913 		v =  va_arg(argptr,Vec2*);
914 		p[i].x = XPix(v->X());
915 		p[i].y = YPix(v->Y());
916 
917 	}
918 	XFillPolygon( dpy,win,gc_current,p,n,0,0);
919 
920 	if (p!=buffer)									delete p;
921 	va_end(argptr);
922 }
923 
FillPoly(int n,Vec2 v[])924 void FillPoly( int n, Vec2 v[] ) {
925 int		i;
926 XPoint	buffer[10];
927 XPoint	*p;
928 
929 	if (sizeof(buffer)/sizeof(XPoint)<(unsigned)n)	p=new XPoint[n];
930 	else															p=buffer;
931 
932 	for (i=0;i<n;i++) {
933 		p[i].x = XPix(v[i].X());
934 		p[i].y = YPix(v[i].Y());
935 	}
936 	XFillPolygon( dpy,win,gc_current,p,n,0,0);
937 
938 	if (p!=buffer)									delete p;
939 }
940 
941 
942