1 #ifndef __global_h
2 #	include "global.H"
3 #endif
4 #ifndef __port_h
5 #	include "port.H"
6 #endif
7 #ifndef __color_h
8 #	include "color.H"
9 #endif
10 #ifndef __tile_h
11 #	include "tile.H"
12 #endif
13 #ifndef __board_h
14 #	include "board.H"
15 #endif
16 #ifndef __font_h
17 #	include "font.H"
18 #endif
19 #ifndef __game_h
20 #	include "game.H"
21 #endif
22 #ifndef __mem_image_h
23 #	include "mem_image.H"
24 #endif
25 #ifndef __color_mapper_h
26 #	include "color_mapper.H"
27 #endif
28 
29 #include <X11/Xutil.h>
30 #include <X11/cursorfont.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 
34 // #include <string.h>
35 // #include <sys/time.h>
36 #ifdef WIN32
37 // l�schen der schlechtesten Macros der Xlib
38 #	undef	Status
39 #	include "winsock.h"
40 #endif
41 #include <X11/Xos.h>
42 #ifndef X_GETTIMEOFDAY
43 	/* define X_GETTIMEOFDAY macro, a portable gettimeofday() */
44 	/* copied from Xos.h for pre-X11R6 releases               */
45 #	if defined(SVR4) || defined(VMS) || defined(WIN32)
46 #		define X_GETTIMEOFDAY(t) gettimeofday(t)
47 #	else
48 #		define X_GETTIMEOFDAY(t) gettimeofday(t, (struct timezone*)0)
49 #	endif
50 #endif
51 #ifndef FDS_TYPE
52 //
53 // The problem occured, that on HP-UX, the type used in the masks of the
54 // select() system call are not the usual 'fd_set'. Instead they are just
55 // integer pointers, which leads to an compile-error, when not casted.
56 // Therefore it actually will get casted by the following Macro FDS_TYPE,
57 // which should usually be defined to an empty string.
58 //
59 #	ifdef __hpux
60 #		define	FDS_TYPE	(int*)
61 #	else
62 #		define	FDS_TYPE
63 #	endif
64 #endif
65 
66 #include "stipple.h"
67 #include "rstipple.h"
68 
69 /* Field position */
70 #define	MFieldX(x)		((x)*sizex+offx+border)
71 #define	MFieldY(y)		((y)*sizey+offy+border)
72 
73 /* Score position */
74 #define	SCol(x)			((x)*bsizex+(dwidth)*sizex+2*border+offx)
75 #define	STop()			(border+offy)
76 #define	SRow(y)			(dheight*sizey+border-(y+1)*bsizey+offy)
77 
78 #define	FACTOR	(2)
79 #define	FlashSpeed	20
80 
81 #define	_TRACE_COLORS
82 
83 unsigned long current_time;
84 
get_current_time()85 static unsigned long get_current_time() {
86 unsigned long ret;
87 struct timeval	timeval;
88 static unsigned long start=0;
89 
90 	X_GETTIMEOFDAY( &timeval );
91 	if (!start)		start=timeval.tv_sec;
92 	ret = ((timeval.tv_sec-start) * 100) + timeval.tv_usec/10000;
93 	return( ret );
94 }
95 
96 
97 Port *Port::first = 0;
98 int  Port::color_id = 1;
99 int  Port::dwidth  = 8;
100 int  Port::dheight = 3;
101 int  Port::dsize   = 44;
102 int  Port::wsizex  = 100;
103 int  Port::wsizey  = 100;
104 int  Port::nplayers = 1;
105 Mode Port::def_mode = Smiley;
106 int  Port::def_size = 1;
107 MemImage *Port::gif = 0;
108 int  Port::remove_flag = 1;
109 int  Port::sync_flag = 0;
110 int  Port::resize_lock = 0;
111 static unsigned long next_sec;
112 
113 struct fd_set Port::readfds;
114 int Port::nfds = 0;
115 
116 #ifndef MaxBorder
117 #	define MaxBorder	(80)
118 #endif
119 
Port(char * disp_name,char * color)120 Port::Port( char *disp_name, char *color )
121 {
122 char	dsp_nam[30];
123 static int w=0;
124 int i;
125 
126 	wbsizex = (wsizex<wsizey)?wsizex:wsizey;
127 	wbsizey = (wsizey*dheight)/(dwidth*dheight);
128 	wborder = (wsizex+wsizey)/2;
129 	if (wborder>MaxBorder)	wborder=MaxBorder;
130 
131 	strcpy( dsp_nam, disp_name );
132 	if ((*disp_name)&&(!strchr(dsp_nam,':'))) {
133 		strcat( dsp_nam, ":0" );
134 	}
135 
136 // open connection to display and create a window
137 	display = XOpenDisplay( dsp_nam );
138 	if (!display) {
139 		fprintf(stderr,"\n" );
140 		fprintf( stderr, "*** can't open display '%s'.\n", dsp_nam );
141 		fprintf(stderr,"\n" );
142 		exit(-1);
143 	}
144 	screen = DefaultScreenOfDisplay( display );
145 	mapper = new ColorMapper(display);
146 	double_depth=(DefaultDepthOfScreen(screen)>8)?0:1;
147 //	XSynchronize(display,1);
148 
149 // Check for non-pseudocolor visual, since there are
150 // no planes available -> need for a stipple instead
151 	if (DefaultVisualOfScreen(screen)->c_class!=PseudoColor || def_mode==Photo) {
152 		light=mapper->alloc_named_color("white");
153 		fg   =mapper->alloc_named_color("grey30");
154 		bg   =mapper->alloc_named_color("grey60");
155 		dark =mapper->alloc_named_color("black");
156 
157 		stipple_pmap=XCreateBitmapFromData( display,RootWindowOfScreen( screen ),
158 							stipple_bits, stipple_width, stipple_height );
159 		rstipple_pmap=XCreateBitmapFromData( display,RootWindowOfScreen( screen ),
160 							rstipple_bits, rstipple_width, rstipple_height );
161 	}
162 	else {
163 		stipple_pmap = 0;
164 		rstipple_pmap = 0;
165 		light = 0;
166 		fg    = 2;
167 		bg    = 1;
168 		dark  = 3;
169 	}
170 	MInit(dsize);
171 	window = XCreateSimpleWindow( display, RootWindowOfScreen( screen ),
172 				0, 0, MWidth(), MHeight(),
173 				0, BlackPixelOfScreen(screen), WhitePixelOfScreen(screen) );
174 	XStoreName( display, window, color );
175 	XSelectInput( display, window, StructureNotifyMask|ExposureMask|ButtonPressMask );
176 
177 	normal_cursor = XCreateFontCursor( display, XC_top_left_arrow );
178 //	idle_cursor   = XCreateFontCursor( display, XC_dotbox );
179 	idle_cursor   = XCreateFontCursor( display, XC_circle );
180 
181 XSetWindowAttributes	attrib;
182 	attrib.bit_gravity = ForgetGravity;
183 	XChangeWindowAttributes(display,window,CWBitGravity,&attrib);
184 
185 XSizeHints	hints;
186 	hints.flags = USPosition | USSize | PAspect;
187 	hints.x = 100+(w%2)*(50+MWidth());
188 	hints.y = 100+(w/2)*(50+MHeight());
189 	hints.width  = MWidth();
190 	hints.height = MHeight();
191 	hints.min_aspect.x = hints.max_aspect.x = MWidth();
192 	hints.min_aspect.y = hints.max_aspect.y = MHeight();
193 #if (1)
194 	XSetNormalHints( display,window,&hints );
195 #endif
196 	w++;
197 
198 	this->width  = hints.width;
199 	this->height = hints.height;
200 
201 Atom atom = XInternAtom(display,"PmWindowType",True);
202 	if (atom) {
203 		char* win_type = "FGnormal";
204 		XTextProperty prop;
205 		XStringListToTextProperty (&win_type, 1, &prop);
206 		XSetTextProperty (display, window, &prop, atom);
207 		XFree((void*)prop.value);
208 	}
209 
210 //
211 // Reaktion auf Destroy Message anmelden
212 //
213 	WmProtocolsPropId    = XInternAtom(display,"WM_PROTOCOLS",False);
214 	WmDeleteWindowPropId = XInternAtom(display,"WM_DELETE_WINDOW",False);
215 	XSetWMProtocols( display, window, &WmDeleteWindowPropId, 1 );
216 
217 //
218 // Fileselector merken
219 //
220 	if (!nfds)		FD_ZERO( &readfds );
221 	FD_SET(  ConnectionNumber(display), &readfds  );
222 	if (nfds<=ConnectionNumber(display))		nfds = ConnectionNumber(display)+1;
223 
224 	mode=def_mode;
225 	if (mode==Photo) {
226 		ncols=gif->GetNCols();
227 		gif_cols=new unsigned long[ncols];
228 		for (i=0;i<ncols;i++) {
229 			XColor	def;
230 			gif->GetColor(i,&def.red,&def.green,&def.blue);
231 			gif_cols[i]=mapper->alloc_color(&def);
232 		}
233 	}
234 
235 	tile = new Tile*[board_p->ntiles];
236 	for (i=0;i<board_p->ntiles;i++)	tile[i]=0;
237 	blank = 0;
238 	empty = 0;
239 // initialize graphic context for drawing tiles
240 // on a pseudocolor display, only the lower 2 planes are to
241 // be drawn, the tile gets its color through overlay-planes.
242 	gc_tile = XCreateGC( display, RootWindowOfScreen(screen), 0L, NULL );
243 	if (stipple_pmap) {
244 		XSetStipple( display, gc_tile, rstipple_pmap );
245 		XSetFillStyle( display, gc_tile, FillStippled );
246 	}
247 	else {
248 		XSetPlaneMask( display, gc_tile, 0x3 );
249 	}
250 	gc_all = XCreateGC( display, RootWindowOfScreen(screen), 0L, NULL );
251 
252 // initialize tiles
253 	sizex=0;
254 	sizey=0;
255 	resize( hints.width, hints.height );
256 
257 // exchange colors of ports
258 	colors=0;
259 	color_name = new char[strlen(color)+1];
260 	strcpy( color_name, color );
261 	my_id = color_id;
262 
263 #ifdef TRACE_COLORS
264 printf( "new Port: %08lx\n", this );
265 #endif
266 	add_color( 0, "yellow" );
267 	if (first)	add_foreign_color( first, color_name );
268 	add_color( color_id, color_name );
269 
270 	if (stipple_pmap)	XSetWindowBackground( display, window, colors->pixel );
271 	else					XSetWindowBackground( display, window, colors->pixel+bg );
272 	XMapRaised( display, window );
273 
274 // connect to list of created displays
275 	next = first;
276 	first = this;
277 
278 	color_id++;
279 	lock_count = 0;
280 	lock_time  = 0;
281 	flash_time = 0;
282 	lock[0] = lock[1] = -1;
283 
284 	points     = 0;
285 	selections = 0;
286 	active     = (sync_flag)?0:1;
287 
288 #ifdef TRACE_COLORS
289 printf( "    Port  %08lx initialized\n", this );
290 #endif
291 }
292 
add_foreign_color(Port * current,char * color_name)293 void Port::add_foreign_color( Port *current, char *color_name ) {
294 	current->add_color( color_id, color_name );
295 	if (current->next)	add_foreign_color(current->next,color_name);
296 	add_color( current->my_id, current->color_name );
297 }
298 
299 
sub_color(int id)300 void Port::sub_color( int id ) {
301 Color	*current= colors;
302 Color *mark=0;
303 
304 //
305 // Id dekrementieren
306 //
307 	while(current) {
308 		if (current->color_id==id)		mark = current;
309 		if (current->color_id>id)		current->color_id--;
310 		current=current->next;
311 	}
312 //
313 // Farbe ausketten
314 //
315 	if (mark==colors) {
316 		colors = mark->next;
317 	}
318 	else {
319 		current = colors;
320 		while( current->next != mark )		current = current->next;
321 		current->next = mark->next;
322 	}
323 //
324 // Farbe loeschen
325 //
326 	mark->next    = 0;
327 	delete mark;
328 
329 //
330 // neue Fensterdimension:
331 //
332 	offx = (width-MWidth())/2;
333 	XClearArea(display,window,0,0,0,0,True);
334 }
335 
~Port()336 Port::~Port() {
337 
338 	activate_next_player();				// checks, if I was the active player ...
339 
340 	nplayers--;								// Zahl der Spieler
341 	board_p->color_removed(my_id);		// Farbe im Brett freigeben
342 	color_id--;								// Gesamtfarbenzaehler
343 //
344 // Farbe aus allen Ports austragen
345 //
346 Port	*current;
347 
348 	current=first;
349 	do {
350 		if (current->my_id>my_id)     current->my_id--;
351 		current = current->next;
352 	} while(current);
353 
354 //
355 // Port ausketten
356 //
357 	if (this==first) {
358 		first  = this->next;
359 	}
360 	else {
361 		current = first;
362 		while( current->next != this )		current = current->next;
363 		current->next = this->next;
364 	}
365 
366 //
367 // Farbumsetzungstabelle freigeben
368 //
369 	if (gif_cols)		delete gif_cols;
370 	if (gif&&!first)	{ delete gif;	gif=0; }
371 //
372 // Farbe aus den Ports austragen
373 //
374 	for (current=first;current;current=current->next)
375 											current->sub_color( my_id );
376 
377 	for (int i=0;i<board_p->ntiles;i++) {
378 		if (tile[i])		delete tile[i];
379 	}
380 	delete tile;
381 	if (blank)	delete blank;
382 	if (empty)	delete empty;
383 	delete colors;
384 	delete color_name;
385 	if (stipple_pmap) {
386 		XFreePixmap( display, stipple_pmap );
387 		XFreePixmap( display, rstipple_pmap );
388 	}
389 	XFreeGC( display, gc_all );
390 	XFreeGC( display, gc_tile );
391 	XFreeCursor( display, normal_cursor );
392 	XFreeCursor( display, idle_cursor );
393 
394 	delete mapper;
395 	XSync( display, 0 );
396 	XCloseDisplay( display );
397 }
398 
UpdateTime(const char * time_str)399 void Port::UpdateTime( const char *time_str ) {
400 	XStoreName( display, window, time_str );
401 }
402 
add_color(int color_id,char * color_name)403 void Port::add_color( int color_id, char *color_name )
404 {
405 Color *new_color;
406 
407 #ifdef TRACE_COLORS
408 printf( "%08lx: add %d = %s\n", this, color_id, color_name );
409 #endif
410 
411 	new_color = new Color( this, color_id, color_name );
412 #if(1)
413 	new_color->next = colors;
414 	colors = new_color;
415 #else
416 	new_color->next = 0;
417 	if (!colors)		colors = new_color;
418 	else {
419 		Color	*col = colors;
420 		while( col->next )	col=col->next;
421 		col->next=new_color;
422 	}
423 #endif
424 }
425 
426 
empty_queue()427 int Port::empty_queue() {
428 XEvent	event;
429 
430 	// XSync( display, 0 );
431 	while ( XEventsQueued( display, QueuedAfterFlush ) ) {
432 		XNextEvent( display, &event );
433 		switch( event.type ) {
434 		case ButtonPress:
435 		{
436 			switch(event.xbutton.button) {
437 			case 2:
438 				if (my_id==1)		return 1;
439 
440 			default:
441 			{	if (board_p->finished&&current_time>board_p->finished+5000)	return 1;
442 				int x = (event.xbutton.x-offx-border)/sizex;
443 				int y = (event.xbutton.y-offy-border)/sizey;
444 #if (0)
445 				printf("  press: (%d,%d)\n", x, y );
446 #endif
447 				selected(x,y);
448 			}
449 			}
450 			break;
451 		}
452 		case Expose:
453 		{
454 #if (0)
455 			printf("%d - Expose: (%d,%d) - (%d,%d)\n", my_id,
456 						event.xexpose.x, event.xexpose.y,
457 						event.xexpose.x + event.xexpose.width,
458 						event.xexpose.y + event.xexpose.height );
459 #endif
460 			redraw( event.xexpose.x, event.xexpose.y,
461 						event.xexpose.x + event.xexpose.width,
462 						event.xexpose.y + event.xexpose.height );
463 			break;
464 		}
465 		case ConfigureNotify:
466 #if (0)
467 			printf("%d - Configure: (%d,%d)\n", my_id,
468 						event.xconfigure.width, event.xconfigure.height );
469 #endif
470 			resize( event.xconfigure.width, event.xconfigure.height );
471 			break;
472 
473 		case ClientMessage:
474 			if (event.xclient.message_type == WmProtocolsPropId) {
475 				Atom data_atom = (Atom)event.xclient.data.l[0];
476 				if (data_atom == WmDeleteWindowPropId) {
477 					if (my_id==1)	return 1;		// main-window -> than exit
478 					return -1;		// delete me !
479 				}
480 			}
481 		}
482 	}
483 	return 0;
484 }
485 
wait_event()486 int Port::wait_event() {
487 static unsigned long	next=0;
488 int erg = 0;
489 
490 	current_time = get_current_time();
491 	if (!next||next>next_sec)		next=next_sec;
492 
493 	if (current_time<next) {
494 		struct timeval		timeout;
495 		unsigned long	dist = next-current_time;
496 		struct fd_set readfds_cp;
497 
498 		memcpy( &readfds_cp, &readfds, sizeof(readfds) );
499 		timeout.tv_sec  = dist / 100;
500 		timeout.tv_usec = dist % 100;
501 		select( nfds, FDS_TYPE &readfds_cp, 0, 0, &timeout );
502 		current_time = get_current_time();
503 	}
504 	if (current_time>next_sec) {
505 		next_sec = ((current_time/100)+1)*100;
506 		if (!board_p->finished) {
507 			char	 buffer[20];
508 			sprintf( buffer, "%02ld:%02ld",
509 				(next_sec/100) / 60, (next_sec/100) % 60 );
510 
511 			for( Port *current = first; current; current=current->next ) {
512 				current->UpdateTime(buffer);
513 			}
514 		}
515 	}
516 
517 	next = 0;
518 	for( Port *current = first; current; current=current->next ) {
519 		int delete_flag = current->empty_queue();
520 
521 		if (delete_flag<0) {
522 			delete current;
523 			if (first)	return erg+wait_event();
524 			else			return 1;
525 		}
526 		else erg+=delete_flag;
527 		unsigned long current_next = current->deselect();
528 		if (current_next) {
529 			if (!next||current_next<next)		next = current_next;
530 		}
531 	}
532 	return erg;
533 }
534 
gc_color_n(int id)535 GC Port::gc_color_n( int id ) {
536 Color	*current=colors;
537 int i;
538 
539 	for (i=color_id-1;i>id;i--)	current=current->next;
540 
541 	return( current->gc_n );
542 }
543 
Points(int id)544 int Port::Points( int id ) {
545 Port *current=first;
546 int i;
547 
548 	for (i=color_id-1;i>id;i--)	current=current->next;
549 	return( current->points );
550 }
551 
statistic()552 void Port::statistic() {
553 Port *current=first;
554 
555 	printf( "SUMMARY Points Selections\n" );
556 	for (current=first;current;current=current->next) {
557 		printf("%-10s %3d %-5d\n",
558 			current->color_name,
559 			current->points, current->selections );
560 	}
561 	if (board_p->finished) {
562 		printf( "TIME: %02ld:%02ld.%02ld\n",
563 				(board_p->finished/100) / 60,
564 				(board_p->finished/100) % 60,
565 				(board_p->finished%100) );
566 	}
567 }
568 
redraw(int x,int y)569 void Port::redraw( int x, int y )
570 {
571 Field *f= board_p->field(x,y);
572 
573 	if (!f)		return;
574 
575 	if (f->locked && !f->gone) {
576 		XCopyArea( display, tile[f->tile_id]->pixmap, window, gc_tile,
577 			0, 0, sizex, sizey, MFieldX(x), MFieldY(y) );
578 		if (!stipple_pmap||f->flash||f->lock_col!=my_id) {
579 			XFillRectangle( display, window,
580 				(f->flash)? gc_color_n(0) : gc_color_n(f->lock_col),
581 				MFieldX(x), MFieldY(y), sizex, sizey );
582 		}
583 #if (0)
584 		XSetFillStyle( display, gc_tile, FillStippled );
585 		XCopyArea( display, tile[f->tile_id]->pixmap, window, gc_tile,
586 			0, 0, sizex, sizey, MFieldX(x), MFieldY(y) );
587 #endif
588 	}
589 	else {
590 		if (remove_flag || !f->gone || f->lock_col!=my_id) {
591 			XCopyArea( display, ((f->found)?empty->pixmap:blank->pixmap),
592 				window, gc_tile, 0, 0, sizex, sizey, MFieldX(x), MFieldY(y) );
593 			XFillRectangle( display, window,
594 				(f->found)?gc_color_n(f->lock_col):gc_color_n(my_id),
595 				MFieldX(x), MFieldY(y), sizex, sizey );
596 		}
597 		else {
598 			XCopyArea( display, tile[f->tile_id]->pixmap, window, gc_tile,
599 				0, 0, sizex, sizey, MFieldX(x), MFieldY(y) );
600 		}
601 	}
602 }
603 
draw_block(int p,int x,int y)604 void Port::draw_block( int p, int x, int y ) {
605 	XFillRectangle( display, window, gc_color_n(p+1), x, y, bsizex, bsizey );
606 
607 	XSetForeground( display, gc_tile, bg );
608 	XFillRectangle( display, window, gc_tile, x, y, bsizex, bsizey );
609 
610 	XSetForeground( display, gc_tile, light );
611 	XDrawLine( display, window, gc_tile, x, y, x+bsizex-1, y );
612 	XDrawLine( display, window, gc_tile, x, y, x, y+bsizey-1 );
613 
614 	XSetForeground( display, gc_tile, dark );
615 	XDrawLine( display, window, gc_tile, x, y+bsizey-1, x+bsizex-1, y+bsizey-1 );
616 	XDrawLine( display, window, gc_tile, x+bsizex-1, y, x+bsizex-1, y+bsizey-1 );
617 }
618 
redraw_score(int x)619 void Port::redraw_score( int x )
620 {
621 	if (x>=nplayers || x<0)	return;
622 
623 	XFillRectangle( display, window, gc_color_n(my_id),
624 		SCol(x), STop(), bsizex, dheight*sizey );
625 
626 	XSetForeground( display, gc_tile, fg);
627 	XFillRectangle( display, window, gc_tile,
628 		SCol(x), STop(), bsizex, dheight*sizey );
629 
630 	XSetForeground( display, gc_tile, dark);
631 	XDrawLine( display, window, gc_tile,
632 		SCol(x), STop(), SCol(x+1)-1, STop() );
633 	XDrawLine( display, window, gc_tile,
634 		SCol(x), STop(), SCol(x), STop()+dheight*sizey-1 );
635 
636 	XSetForeground( display, gc_tile, light);
637 	XDrawLine( display, window, gc_tile,
638 		SCol(x), STop()+dheight*sizey-1, SCol(x+1)-1, STop()+dheight*sizey-1 );
639 	XDrawLine( display, window, gc_tile,
640 		SCol(x+1)-1, STop(), SCol(x+1)-1, STop()+dheight*sizey-1 );
641 
642 	int height = Points(x+1);
643 	for (int y=1;y<=height;y++) {
644 		draw_block( x, SCol(x), SRow(y-1) );
645 	}
646 	XFlush( display );
647 }
648 
redraw(int x1,int y1,int x2,int y2)649 void Port::redraw( int x1, int y1, int x2, int y2 )
650 {
651 int x1s,y1s,x2s,y2s;
652 int x, y;
653 
654 #if (1)
655 	XClearArea( display, window, x1, y1, x2-x1, y2-y1, False );
656 #endif
657 
658 // check for score redraw
659 	x1s = (x1-SCol(1))/bsizex;	// make it one field smaller
660 	x2s = (x2-SCol(0))/bsizex;
661 	if (x2s>=0) {
662 		for (x=x1s;x<=x2s;x++) {
663 			redraw_score(x);
664 		}
665 	}
666 
667 	x1s=(x1-offx-border)/sizex;
668 	y1s=(y1-offy-border)/sizey;
669 	x2s=(x2-offx-border)/sizex;
670 	y2s=(y2-offy-border)/sizey;
671 
672 	for (x=x1s-1;x<=x2s;x++) {
673 		for (y=y1s-1;y<=y2s;y++) {
674 			redraw( x, y );
675 		}
676 	}
677 }
678 
tile_redraw(int fid)679 void Port::tile_redraw( int fid )
680 {
681 int x = fid%board_p->dx;
682 int y = fid/board_p->dx;
683 
684 
685 	for ( Port *current = first; current; current = current->next )
686 	{	current->redraw( x, y );
687 //		XFlush( current->display );
688 		XSync( current->display, 0 );
689 	}
690 }
691 
flush_all()692 void Port::flush_all()
693 {
694 	for ( Port *current = first; current; current = current->next )
695 		XFlush( current->display );
696 }
697 
activate_next_player()698 void Port::activate_next_player()
699 {
700 Port *current;
701 
702 	if (sync_flag && active) {
703 		for ( current = first; current; current = current->next ) {
704 			if (current==this)	break;
705 		}
706 		Port	*next=(current->next)?current->next:first;
707 		current->set_active( 0 );
708 		next->set_active( 1 );
709 	}
710 }
711 
set_active(int a)712 void Port::set_active( int a ) {
713 	if ( a ) {
714 		XDefineCursor( display, window, normal_cursor );
715 	}
716 	else {
717 		XDefineCursor( display, window, idle_cursor );
718 	}
719 	active=a;
720 }
721 
activate_any_player()722 void Port::activate_any_player()
723 {
724 Port *current;
725 int	id=rand()%nplayers;
726 
727 	if (sync_flag) {
728 		for ( current = first; current; current = current->next ) {
729 			current->set_active( (id)?0:1 );
730 			id--;
731 		}
732 	}
733 }
734 
remove()735 int Port::remove() {
736 	if ((lock_count>1)&&(board_p->field(lock[1])->found)) {
737 		board_p->field(lock[1])->gone = 1;
738 		tile_redraw( lock[1] );
739 		board_p->field(lock[0])->gone = 1;
740 		tile_redraw( lock[0] );
741 		lock_count=0;
742 		points+=2;
743 
744 		for (Port *p=first;p;p=p->next) {
745 			p->redraw_score(my_id-1);
746 		}
747 		board_p->tile_removed(my_id);
748 		flash_time=0;
749 		return 1;
750 	}
751 	else {
752 		activate_next_player();
753 		return 0;
754 	}
755 }
756 
deselect()757 unsigned long Port::deselect()
758 {
759 unsigned long next = 0;
760 
761 	if (flash_time) {
762 		if (flash_time<current_time) {
763 			board_p->field(lock[0])->flash ^= 1;
764 			board_p->field(lock[1])->flash ^= 1;
765 			tile_redraw(lock[0]);
766 			tile_redraw(lock[1]);
767 			next=flash_time=current_time+FlashSpeed;
768 			// printf("FLASH %lu\n",flash_time);
769 		}
770 		else {
771 			next = flash_time;
772 			// printf("FLASH SUPPRESSED\n");
773 		}
774 	}
775 	if (lock_time&&current_time<lock_time)
776 									return (!next||next>lock_time)?lock_time:next;
777 
778 	if (lock_count>1) {
779 		if (!remove()) {
780 			board_p->field(lock[1])->locked = 0;
781 			tile_redraw( lock[1] );
782 		}
783 	}
784 	if (lock_count>0) {
785 		board_p->field(lock[0])->locked = 0;
786 		tile_redraw( lock[0] );
787 	}
788 	lock_count=0;
789 	lock_time =0;
790 
791 	return 0;
792 }
793 
selected(int x,int y)794 void Port::selected( int x, int y )
795 {
796 int	fid;
797 Field *f= board_p->field(x,y);
798 
799 	if (!f)	return;
800 
801 //printf( "Pos: (%d,%d), Tile: %d, Locks %d\n", x,y,f->tile_id,lock_count );
802 	if (lock_count==2) {
803 		if (!remove()) {
804 	//		XBell( display, 100 );
805 			return;
806 		}
807 	}
808 
809 	fid = x+board_p->dx*y;
810 
811 //printf("  fid: %d, removed: %d, lock_id: %d\n", fid, f->removed, f->lock_id );
812 
813 	if (f->found)		return;
814 	if (f->locked || !active)	{
815 #if (1)
816 		if (!active)	XBell( display,100 );
817 		return;
818 #else
819 		if (f->lock_col!=my_id){
820 		}
821 		else {
822 			if (lock[0]==fid) {
823 				lock[0]=lock[1];
824 			}
825 			lock_count--;
826 			f->locked=0;
827 			tile_redraw( fid );
828 			lock_time=current_time;
829 			return;
830 		}
831 #endif
832 	}
833 
834 	selections++;
835 
836 	f->lock_col = my_id;
837 	f->locked   = 1;
838 	lock[lock_count++] = fid;
839 
840 	if (lock_count==2) {
841 		if (board_p->field(lock[0])->tile_id==board_p->field(lock[1])->tile_id) {
842 			board_p->field(lock[0])->found = 1;
843 			board_p->field(lock[0])->flash = 1;
844 			board_p->field(lock[1])->found = 1;
845 			board_p->field(lock[1])->flash = 1;
846 			tile_redraw( lock[0] );
847 	//		tile_redraw( lock[1] );
848 			flash_time = current_time+FlashSpeed;
849 			// printf( "FLASH: %lu (current: %lu\n)\n", current_time, flash_time );
850 		}
851 	}
852 	tile_redraw( fid );
853 	lock_time = current_time + ((lock_count==2)?100:((sync_flag)?6000:300));
854 }
855 
find_font(const char * pattern,int size)856 const char *Port::find_font( const char *pattern, int size ) {
857 char	**font;
858 int	 count;
859 int	i;
860 char	*true_name    = 0;
861 char	*true_scale   = 0;
862 char	*bitmap_name  = 0;
863 char	*bitmap_scale = 0;
864 char	*closest_name = 0;
865 int	closest_scale = -1;
866 static char	ret_buffer[200];
867 
868 	font=XListFonts(display,pattern,100,&count);
869 
870 	for (i=0;i<count;i++) {
871 		int	sep;
872 		char	*scale;
873 
874 		scale = font[i];
875 		sep=7;
876 		while( *scale && sep ) {
877 			if (*scale++=='-')		sep--;
878 		}
879 		if (scale) {
880 			if (!strncmp("0-0-0-0-",scale,8)) {
881 				true_name   = font[i];
882 				true_scale  = scale;
883 			}
884 			else if (!strncmp("0-0-",scale,4)) {
885 				bitmap_name  = font[i];
886 				bitmap_scale = scale;
887 			}
888 			else {
889 				int csize = atoi(scale);
890 				if ( csize<size && csize>closest_scale ) {
891 					closest_name  = font[i];
892 					closest_scale = csize;
893 				}
894 			}
895 		}
896 	}
897 
898 	ret_buffer[0]='\0';
899 	if (bitmap_name) {
900 		strcpy( ret_buffer, bitmap_name );
901 		sprintf(ret_buffer+(bitmap_scale-bitmap_name),"%d%s", size, bitmap_scale+1 );
902 	}
903 	if (true_name) {
904 		strcpy( ret_buffer, true_name );
905 		sprintf(ret_buffer+(true_scale-true_name),"%d%s", size, true_scale+1 );
906 	}
907 	if ( closest_name && closest_scale > size-4 ) {
908 		strcpy(ret_buffer,closest_name);
909 	}
910 
911 	XFreeFontNames(font);
912 
913 	if (ret_buffer[0]=='\0') {
914 		fprintf(stderr,"\n" );
915 		fprintf(stderr,"*** Unable to find any matching fonts with pattern\n" );
916 		fprintf(stderr,"*** '%s' on display '%s'.\n", pattern, DisplayString(display) );
917 		fprintf(stderr,"*** Please make the font available via xset(1) or use the\n" );
918 		fprintf(stderr,"*** option -font <name> to select a different pattern.\n" );
919 		fprintf(stderr,"\n" );
920 		exit(-1);
921 	}
922 	// printf( "%2d %2d: %s\n", size, closest_scale, ret_buffer );
923 	return ret_buffer;
924 }
925 
resize(int width,int height)926 void Port::resize( int width, int height )
927 {
928 int	nsizex;
929 int	nsizey;
930 int  i;
931 //
932 // check window size
933 //
934 	nsizex = wsizex*width/WWidth();				// calculate new pixel values
935 	nsizey = wsizey*height/WHeight();
936 
937 	if (nsizex*wsizey<nsizey*wsizex) {			// check aspect ratio
938 				nsizey = nsizex*wsizey/wsizex;
939 	}
940 	else {		nsizex = nsizey*wsizex/wsizey;
941 	}
942 
943 	if (resize_lock!=0) {
944 		if (resize_lock>0) {
945 			nsizex=wsizex*resize_lock/100;
946 		}
947 		else {
948 			int ratio = (nsizex*100)/wsizex;
949 			ratio = 10*(ratio/10);
950 			nsizex=wsizex*ratio/100;
951 		}
952 	}
953 
954 	if ((nsizex==sizex)&&(nsizey==sizey)) {
955 		offx = (width-MWidth())/2;
956 		offy = (height-MHeight())/2;
957 		return;
958 	}
959 
960 	MInit(nsizex);
961 	offx   = (width-MWidth())/2;
962 	offy   = (height-MHeight())/2;
963 
964 	this->width = width;
965 	this->height = height;
966 //	XResizeWindow( display, window, MWidth(sizex), MHeight(sizey) );
967 
968 	// calculate screen resolution in dots per inch 25.4mm=1 inch
969 	// int res_x = (int)(WidthOfScreen(screen)/(WidthMMOfScreen(screen)/25.4));
970 	// int res_y = (int)(HeightOfScreen(screen)/(HeightMMOfScreen(screen)/25.4));
971 
972 
973 ScalableFont	*font;
974 
975 	if (param[Port::def_mode].font_mode) {
976  		font = new FlipFont(display,
977 					find_font(param[Port::def_mode].font,sizex-4 ) ,270);
978 	}
979 	else {
980  		font = new ScalableFont(display,
981 					find_font(param[Port::def_mode].font,sizey-10 ),0);
982 	}
983 
984 //
985 // initialize tiles
986 //
987 	for (i=0;i<board_p->ntiles;i++) {
988 		if ( tile[i] )		delete tile[i];
989 		tile[i] = new Tile( this, font, i );
990 	}
991 	if (blank)			delete blank;
992 	if (empty)			delete empty;
993 	empty = new Tile(this, font, -1);
994 	blank = new Tile(this, font, -2);
995 
996 	delete font;
997 }
998