1 /*****************************************************************************/
2 /*									     */
3 /*									     */
4 /*	X patience version 2 -- module X-events.c			     */
5 /*									     */
6 /*	Event handlers for the X interface				     */
7 /*	written by Heiko Eissfeldt and Michael Bischoff			     */
8 /*	see COPYRIGHT.xpat2 for Copyright details			     */
9 /*									     */
10 /*									     */
11 /*****************************************************************************/
12 #include "X-pat.h"
13 
14 /* #define LABER */
15 
16 Display *dpy;
17 int screen;
18 unsigned long blackpixel;
19 unsigned long whitepixel;
20 GC blackgc;
21 GC whitegc;
22 
23 /* flush event queue */
flush_display(void)24 void flush_display(void) {
25     XSync(dpy, 0);	/* text first! */
26 }
27 
28 #ifdef useXlib
intersect(int x1,int w1,int x2,int w2)29 static int intersect(int x1, int w1, int x2, int w2) {
30     if (x1 < x2)
31 	return x1+w1 > x2;
32     else
33 	return x2+w2 > x1;
34 }
35 #endif
36 
37 /* events for Xlib AND Xaw interface */
38 /* event entry points are: key_press, button_press, button_release,
39    mouse_motion (only called with button 3 pressed) redraw_table */
40 
41 
key_press(XKeyPressedEvent * xev)42 void key_press(XKeyPressedEvent *xev) {
43     char str[32];
44     int num;
45 
46 #define	get_name_field()	get_selection()
47 
48     num = XLookupString(xev, str, 31, NULL, NULL);
49     if (num == 0)
50 	return;
51     str[num] = '\0';		/* NULL to terminate it */
52 
53     show_exposed_card(False);
54     key_pressed(str);
55 }
56 
57 /* SPEEDUP does not work yet */
58 #ifdef SPEEDUP
59 static int pile_is_drawn[MAXPILES] = { 0, 0 };
60 static int buttons_are_drawn = 0;
61 #endif
62 
63 extern int table_clear;
64 
redraw_table(XExposeEvent * xev)65 void redraw_table(XExposeEvent *xev) {
66     int i;
67     table_clear = 0;
68 #ifdef useXlib
69     if (intersect(0, graphic.buttons_height, xev->y, xev->height))
70 #ifdef SPEEDUP
71 	if (!buttons_are_drawn++)
72 #endif
73 	    redraw_buttons(xev->x, xev->y, xev->width, xev->height, table, button.num, button.b);
74     if (intersect(graphic.buttons_height, graphic.message_height, xev->y, xev->height))
75 	show_message(NULL);
76     if (xev->count && xev->y + xev->height < graphic.yoff)	/* else may miss the last event */
77 	return;
78 #endif
79 
80 #ifdef LABER
81     printf("request for expose %d,%d of size %d,%d, cnt %d\n", xev->x, xev->y, xev->width, xev->height, xev->count);
82     /* printf("height of 0=%d, 8=%d\n", p.geo[0], p.geo[8].h); */
83 #endif
84 
85     for (i = 0; i < game.numpiles; ++i) {
86 	struct pilegeometry *p;
87 #ifdef SPEEDUP
88 	if (pile_is_drawn[i]++)
89 	    continue;
90 #endif
91 	p = geo.pg + i;
92 	if (NOT_DISPLAYED(p) ||
93 	    xev->x >= p->x + p->w || xev->x + xev->width <= p->x ||
94 	    xev->y >= p->y + p->h || xev->y + xev->height <= p->y)
95 	    continue;	/* this pile is not affected */
96 #ifdef LABER
97 	printf("request for update pile %d of pos %d,%d, size %d,%d\n", i,
98 	       p->x, p->y, p->w, p->h);
99 #endif
100 	draw_pileupdate(i, 0);
101     }
102     if (!xev->count) {
103 	show_arrow(2);				/* Update hint arrow */
104     }
105 #ifdef LABER
106     if (!xev->count)
107 	printf("         => last expose-table call\n");
108 #endif
109 #ifdef SPEEDUP
110     if (xev->count)
111 	return;
112     /* was last event, unmark piles */
113     for (i = 0; i < MAXPILES; ++i)
114 	pile_is_drawn[i] = 0;
115     buttons_are_drawn = 0;
116 #endif
117 }
118 
119 
120 /* the pointer is somewhere in the area of pile i */
121 /* check, if a card has to be exposed */
122 
expose_card(Pileindex i,int x,int y)123 static void expose_card(Pileindex i, int x, int y) {
124     struct pilegeometry *p;
125     Cardindex ind;
126 
127     if (EMPTY(i))
128 	return;
129     p = geo.pg + i;
130 #if 0
131     ind = game.ind[i];
132     while (ind != INDEX_OF_LAST_CARD(i) && y >=	p->y + graphic.cardy[ind+1])
133         ++ind;
134 #else
135     ind = FindCardOfMousePos(i, x, y);
136 #endif
137     if (ind == INDEX_OF_LAST_CARD(i))   /* the most bottom card don't has to */
138         ind = -1;                       /* be put on foreground */
139     if (graphic.zoomed_card != ind) {   /* change of state */
140 	show_exposed_card(False);	/* hide it */
141         /* graphic.zoomed_card is now -1 */
142         if (ind >= 0) {
143   	    graphic.zoomed_card = ind;
144 	    show_exposed_card(True);
145         }
146     }
147 }
148 
mouse_motion(XPointerMovedEvent * xev)149 void mouse_motion(XPointerMovedEvent *xev) {
150     Pileindex i;
151     /* find new pile */
152     for (i = FIRST_SLOT; i <= LAST_SLOT; ++i) {
153 	struct pilegeometry *p;
154 	p = geo.pg + i;
155 	if (xev->x >= p->x && xev->x < p->x + p->w &&
156 	    xev->y >= p->y && xev->y < p->y + p->h) {
157 	    /* yeah, a slot is hit */
158 	    /* find out which card is the target */
159 	    expose_card(i, xev->x - p->x, xev->y - p->y);
160 	    return;
161         }
162     }
163     /* pointer moved out of scope: */
164     show_exposed_card(False);
165 }
166 
button_release(XButtonPressedEvent * xev)167 void button_release(XButtonPressedEvent *xev) {
168     show_exposed_card(False);
169 }
170 
button_press(XButtonPressedEvent * xev)171 void button_press(XButtonPressedEvent *xev) {
172     Pileindex i;
173 
174     show_exposed_card(False);
175 #ifdef useXlib
176     {	void (*func)(void);
177 	func = check_button_list(button.b, button.num, xev);
178 
179 	/* check for hit button */
180 	if (func) {
181 	    (*func)();
182 	    return;
183 	}
184     }
185 #endif
186 
187     for (i = 0; i < game.numpiles; ++i) {
188 	struct pilegeometry *p;
189 	p = geo.pg + i;
190 	if (NOT_DISPLAYED(p))
191 	    continue;
192 	if (xev->x >= p->x && xev->x < p->x + p->w &&
193 	    xev->y >= p->y && xev->y < p->y + p->h) {
194 	    Cardindex cardi;
195 #if 0
196 	    if EMPTY(i)
197 		cardi = -1;
198 	    else {
199 		cardi = INDEX_OF_LAST_CARD(i);
200 		if (game.piletype[i] == Slot)
201 		    /* possibly a different card */
202 		    while (cardi != INDEX_OF_FIRST_CARD(i) &&
203 			   graphic.cardy[cardi] > xev->y - graphic.pile[i].y)
204 			--cardi;
205 	    }
206 #else
207 	    cardi = FindCardOfMousePos(i, xev->x - p->x, xev->y - p->y);
208 	    if (cardi == -2)	/* below := lowest */
209 		cardi = INDEX_OF_LAST_CARD(i);
210 #endif
211 	    switch (xev->button) {
212 	    case Button1:            /* quick move */
213 		button_pressed(i, cardi, 1);
214 		break;
215 	    case Button2:            /* select / deselect */
216 		button_pressed(i, cardi, 2);
217 		break;
218 	    case Button3:
219 #ifdef BUTTON_3_DRAGS_CARD
220 		button_pressed(i, cardi, 3);
221 #else
222 #ifndef useXview
223 		if (game.piletype[i] == Slot)
224 		    expose_card(i, xev->x - p->x, xev->y - p->y);
225 #else
226 		if (game.piletype[i] == Slot && cardi >= 0) {
227 		    expose_card(i, xev->x - p->x, xev->y - p->y);
228 		} else {
229 		    menu_show(cmenu, canvas, bp_event, 0);
230 		    return;
231 		}
232 #endif
233 		break;
234 #endif
235 	    }
236 	    return;
237 	}
238     }
239 #ifdef useXview
240     if (xev->button == Button3)
241     {
242 	menu_show(cmenu, canvas, bp_event, 0);
243 	return;
244     }
245 #endif
246     button_pressed(-1, -1, -1);		/* cancel action */
247 }
248 
249 /*****************************************************************************/
250 /*									     */
251 /*	Functions for resize events and resize requests			     */
252 /*									     */
253 /*****************************************************************************/
254 
255 /* 1) hard resizes (i.e. forcing the outer window to change size) */
256 /*    I think these are not liked in the Xaw community */
257 
cmd_MinWindow(void)258 void cmd_MinWindow(void) {
259     XSize_t w, h;
260     w = geo.min_width;
261     h = geo.min_height;
262 /*    printf("Force resize to min (%d,%d)\n", w, h); */
263     Force_Resize(w, h);
264 }
265 
cmd_PreferredWindow(void)266 void cmd_PreferredWindow(void) {
267     XSize_t w, h;
268     w = geo.preferred_width;
269     h = geo.preferred_height;
270 /*    printf("Force resize to prf (%d,%d)\n", w, h); */
271     Force_Resize(w, h);
272 }
273 
274 /* event handler function. This function is called by the Widget in response
275    to a request from us. In Xaw, this is a resize of the logical area, i.e.
276    of the virtual size of the tableau. */
277 
resize_event(XSize_t w,XSize_t h)278 void resize_event(XSize_t w, XSize_t h) {
279 #ifdef LABER
280     printf("resize event to (%d,%d) called\n", w, h);
281 #endif
282     if (game.graphic)
283 	cmd_ResetHints();
284     if (graphic.height == h && graphic.width == w)
285 	return;		/* no change of size */
286 
287     /* in xlib, we must clear the new area by hand; there may be illegal data
288        left in the server. This applies to Xaw as well */
289     {   XExposeEvent xev;
290 	xev.count = -1;
291         if (game.graphic) {
292 	    if (graphic.height < h) {
293 		/* window is greater now */
294 		XClearArea(dpy, table, 0, graphic.height, graphic.width, h - graphic.height, True);
295 		++xev.count;
296 	    }
297 	    if (graphic.width < w) {
298 		/* window is greater now */
299 		XClearArea(dpy, table, graphic.width, 0, w - graphic.width, h, True);
300 		++xev.count;
301 	    }
302 	    if (xev.count >= 0) {
303 		/* generate synthetic expose events for the new area */
304 		/* this must be done before we possibly change the layout */
305 		if (graphic.height < h) {
306 		    /* window is greater now */
307 		    xev.x = 0;
308 		    xev.y = graphic.height;
309 		    xev.width = graphic.width;
310 		    xev.height = h - graphic.height;
311 		    redraw_table(&xev);
312 		    --xev.count;
313 		}
314 		if (graphic.width < w) {
315 		    /* window is greater now */
316 		    xev.x = graphic.width;
317 		    xev.y = 0;
318 		    xev.width = w - graphic.width;
319 		    xev.height = h;
320 		    redraw_table(&xev);
321 		}
322 	    }
323 	}
324     }
325     graphic.height = h;
326     graphic.width = w;
327 
328     if (!game.graphic)
329 	return;
330 #ifdef useXlib
331     confirm.x = (graphic.width - confirm.w) / 2;
332     confirm.y = (graphic.height - confirm.h) / 2;
333     XMoveWindow(dpy, confirm.win, confirm.x, confirm.y);
334 #endif
335 
336     if (graphic.autolayout) {
337 	cmd_Layout();	/* change everything */
338     } else {
339 	Pileindex i;
340 	/* fix piles    THIS IS WRONG FOR 2-ROW LAYOUTS!!!! FIX THIS! */
341 	for (i = 0; i < rules.numslots; ++i)
342 	    geo.pg[XPATSLOT(i)].h = geo.h - geo.pg[XPATSLOT(i)].y;
343 
344 	for (i = FIRST_SLOT; i <= LAST_SLOT; ++i)
345 	    if (pile_resize(i))
346 		draw_pileupdate(i, 0);
347     }
348 
349 }
350