3ad6c04cc9b527ac9e4e14b31676de0101fb1a6f
[micropolis] / src / sim / w_x.c
1 /* w_x.c: X Window System support
2 *
3 * Micropolis, Unix Version. This game was released for the Unix platform
4 * in or about 1990 and has been modified for inclusion in the One Laptop
5 * Per Child program. Copyright (C) 1989 - 2007 Electronic Arts Inc. If
6 * you need assistance with this program, you may contact:
7 * http://wiki.laptop.org/go/Micropolis or email micropolis@laptop.org.
8 *
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or (at
12 * your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details. You should have received a
18 * copy of the GNU General Public License along with this program. If
19 * not, see <http://www.gnu.org/licenses/>.
20 *
21 * ADDITIONAL TERMS per GNU GPL Section 7
22 *
23 * No trademark or publicity rights are granted. This license does NOT
24 * give you any right, title or interest in the trademark SimCity or any
25 * other Electronic Arts trademark. You may not distribute any
26 * modification of this program using the trademark SimCity or claim any
27 * affliation or association with Electronic Arts Inc. or its employees.
28 *
29 * Any propagation or conveyance of this program must include this
30 * copyright notice and these terms.
31 *
32 * If you convey this program (or any modifications of it) and assume
33 * contractual liability for the program to recipients of it, you agree
34 * to indemnify Electronic Arts for any liability that those contractual
35 * assumptions impose on Electronic Arts.
36 *
37 * You may not misrepresent the origins of this program; modified
38 * versions of the program must be marked as such and not identified as
39 * the original program.
40 *
41 * This disclaimer supplements the one included in the General Public
42 * License. TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, THIS
43 * PROGRAM IS PROVIDED TO YOU "AS IS," WITH ALL FAULTS, WITHOUT WARRANTY
44 * OF ANY KIND, AND YOUR USE IS AT YOUR SOLE RISK. THE ENTIRE RISK OF
45 * SATISFACTORY QUALITY AND PERFORMANCE RESIDES WITH YOU. ELECTRONIC ARTS
46 * DISCLAIMS ANY AND ALL EXPRESS, IMPLIED OR STATUTORY WARRANTIES,
47 * INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY,
48 * FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT OF THIRD PARTY
49 * RIGHTS, AND WARRANTIES (IF ANY) ARISING FROM A COURSE OF DEALING,
50 * USAGE, OR TRADE PRACTICE. ELECTRONIC ARTS DOES NOT WARRANT AGAINST
51 * INTERFERENCE WITH YOUR ENJOYMENT OF THE PROGRAM; THAT THE PROGRAM WILL
52 * MEET YOUR REQUIREMENTS; THAT OPERATION OF THE PROGRAM WILL BE
53 * UNINTERRUPTED OR ERROR-FREE, OR THAT THE PROGRAM WILL BE COMPATIBLE
54 * WITH THIRD PARTY SOFTWARE OR THAT ANY ERRORS IN THE PROGRAM WILL BE
55 * CORRECTED. NO ORAL OR WRITTEN ADVICE PROVIDED BY ELECTRONIC ARTS OR
56 * ANY AUTHORIZED REPRESENTATIVE SHALL CREATE A WARRANTY. SOME
57 * JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF OR LIMITATIONS ON IMPLIED
58 * WARRANTIES OR THE LIMITATIONS ON THE APPLICABLE STATUTORY RIGHTS OF A
59 * CONSUMER, SO SOME OR ALL OF THE ABOVE EXCLUSIONS AND LIMITATIONS MAY
60 * NOT APPLY TO YOU.
61 */
62 #include "sim.h"
63
64
65 struct XDisplay *XDisplays = NULL;
66 int DisplayCount = 0;
67 #ifdef IS_LINUX
68 int FlushStyle = 3;
69 #else
70 int FlushStyle = 4;
71 #endif
72 int GotXError;
73
74
75 unsigned char ColorIntensities[] = {
76 /* COLOR_WHITE */ 255,
77 /* COLOR_YELLOW */ 170,
78 /* COLOR_ORANGE */ 127,
79 /* COLOR_RED */ 85,
80 /* COLOR_DARKRED */ 63,
81 /* COLOR_DARKBLUE */ 76,
82 /* COLOR_LIGHTBLUE */ 144,
83 /* COLOR_BROWN */ 118,
84 /* COLOR_LIGHTGREEN */ 76,
85 /* COLOR_DARKGREEN */ 42,
86 /* COLOR_OLIVE */ 118,
87 /* COLOR_LIGHTBROWN */ 144,
88 /* COLOR_LIGHTGRAY */ 191,
89 /* COLOR_MEDIUMGRAY */ 127,
90 /* COLOR_DARKGRAY */ 63,
91 /* COLOR_BLACK */ 0,
92 };
93
94
95 ViewToTileCoords(SimView *view, int x, int y, int *outx, int *outy)
96 {
97 x = (view->pan_x - ((view->w_width >>1) - x)) >>4;
98 y = (view->pan_y - ((view->w_height >>1) - y)) >>4;
99
100 if (x < 0) x = 0;
101 if (x >= WORLD_X) x = WORLD_X - 1;
102 if (y < 0) y = 0;
103 if (y >= WORLD_Y) y = WORLD_Y - 1;
104
105 if (x < view->tile_x)
106 x = view->tile_x;
107 if (x >= view->tile_x + view->tile_width)
108 x = view->tile_x + view->tile_width - 1;
109 if (y < view->tile_y)
110 y = view->tile_y;
111 if (y >= view->tile_y + view->tile_height)
112 y = view->tile_y + view->tile_height - 1;
113
114 if (view->tool_x_const != -1)
115 x = view->tool_x_const;
116 if (view->tool_y_const != -1)
117 y = view->tool_y_const;
118
119 *outx = x; *outy = y;
120 }
121
122
123 ViewToPixelCoords(SimView *view, int x, int y, int *outx, int *outy)
124 {
125 x = view->pan_x - ((view->w_width >>1) - x);
126 y = view->pan_y - ((view->w_height >>1) - y);
127
128 if (x < 0) x = 0;
129 if (x >= (WORLD_X <<4)) x = (WORLD_X <<4) - 1;
130 if (y < 0) y = 0;
131 if (y >= (WORLD_Y <<4)) y = (WORLD_Y <<4) - 1;
132
133 if (x < (view->tile_x <<4))
134 x = (view->tile_x <<4);
135 if (x >= ((view->tile_x + view->tile_width) <<4))
136 x = ((view->tile_x + view->tile_width) <<4) - 1;
137 if (y < (view->tile_y <<4))
138 y = (view->tile_y <<4);
139 if (y >= ((view->tile_y + view->tile_height) <<4))
140 y = ((view->tile_y + view->tile_height) <<4) - 1;
141
142 if (view->tool_x_const != -1)
143 x = (view->tool_x_const <<4) + 8;
144 if (view->tool_y_const != -1)
145 y = (view->tool_y_const <<4) + 8;
146
147 *outx = x; *outy = y;
148 }
149
150
151 UpdateFlush()
152 {
153 struct XDisplay *xd;
154
155 if (sim_skips > 0) {
156 if (sim_skip > 0) {
157 sim_skip--;
158 return;
159 }
160 sim_skip = sim_skips;
161 }
162
163 switch (FlushStyle) {
164
165 case 0:
166 break;
167
168 case 1:
169 for (xd = XDisplays; xd != NULL; xd = xd->next)
170 XFlush(xd->dpy);
171 break;
172
173 case 2:
174 for (xd = XDisplays; xd != NULL; xd = xd->next)
175 XSync(xd->dpy, False);
176 break;
177
178 case 3:
179 if (XDisplays && XDisplays->next) {
180 for (xd = XDisplays; xd != NULL; xd = xd->next) {
181 XFlush(xd->dpy);
182 }
183 }
184 for (xd = XDisplays; xd != NULL; xd = xd->next) {
185 XSync(xd->dpy, False);
186 }
187 break;
188
189 case 4:
190 for (xd = XDisplays; xd != NULL; xd = xd->next) {
191 #ifndef IS_LINUX
192 /* XXX TODO: figure this out for linux and new x libs */
193 if ((xd->request != xd->dpy->request) ||
194 (xd->last_request_read != xd->dpy->last_request_read)) {
195 XSync(xd->dpy, False);
196 xd->request = xd->dpy->request;
197 xd->last_request_read = xd->dpy->last_request_read;
198 }
199 #endif
200 }
201 break;
202
203 }
204 }
205
206
207 int
208 CatchXError(Display *dpy, XErrorEvent *err)
209 {
210 GotXError = 1;
211 #if 0
212 printf("GOT X ERROR code %d request code %d %d\n",
213 err->error_code, err->request_code, err->minor_code);
214 #endif
215 return (0);
216 }
217
218
219 DoStopMicropolis()
220 {
221 (void)XSetErrorHandler(CatchXError);
222
223 StopToolkit();
224
225 if (sim) {
226 while (sim->editor != NULL) {
227 DestroyView(sim->editor);
228 }
229
230 while (sim->map != NULL) {
231 DestroyView(sim->map);
232 }
233
234 while (sim->graph != NULL) {
235 DestroyGraph(sim->graph);
236 }
237
238 #ifdef CAM
239 while (sim->scam != NULL) {
240 DestroyCam(sim->scam);
241 }
242 #endif
243 }
244 }
245
246
247 DoTimeoutListen()
248 {
249 while (Tk_DoOneEvent(TK_DONT_WAIT)) ;
250 }
251
252
253 Sim *
254 MakeNewSim()
255 {
256 Sim *sim;
257
258 sim = (Sim *)ckalloc(sizeof(Sim));
259 sim->editors = 0; sim->editor = NULL;
260 sim->maps = 0; sim->map = NULL;
261 sim->graphs = 0; sim->graph = NULL;
262 sim->sprites = 0; sim->sprite = NULL;
263 #ifdef CAM
264 sim->scams = 0; sim->scam = NULL;
265 #endif
266 sim->overlay = NULL;
267
268 return (sim);
269 }
270
271
272 XDisplay *
273 FindXDisplay(Tk_Window tkwin)
274 {
275 XDisplay *xd;
276 int d = 8;
277 unsigned long valuemask = 0;
278 XGCValues values;
279 XColor rgb, *color;
280 Display *dpy = Tk_Display(tkwin);
281 Screen *screen = Tk_Screen(tkwin);
282 #ifdef IS_LINUX
283 char *display = ":0"; /* XXX TODO: fix this for new x libs */
284 #else
285 char *display = dpy->display_name;
286 #endif
287
288 for (xd = XDisplays;
289 xd && (xd->screen != screen);
290 xd = xd->next) ;
291
292 if (xd != NULL) {
293 return (xd);
294 } else {
295 xd = (struct XDisplay *)ckalloc(sizeof (struct XDisplay));
296
297 xd->references = 0;
298 xd->dpy = dpy;
299 xd->display = (char *)ckalloc(strlen(display) + 1);
300 xd->tkDisplay = ((TkWindow *)tkwin)->dispPtr;
301 strcpy(xd->display, display);
302 xd->screen = screen;
303 xd->root = RootWindowOfScreen(xd->screen);
304
305 xd->visual = Tk_DefaultVisual(xd->screen);
306 xd->depth = Tk_DefaultDepth(xd->screen);
307 xd->colormap = Tk_DefaultColormap(xd->screen);
308
309 xd->color = (xd->depth != 1);
310
311 xd->pixels = (int *)ckalloc(16 * sizeof(int));
312 if (xd->color) { /* Color screen */
313 int GotColor = 1;
314
315 #define GETCOLOR(i, name) \
316 if (!GotColor) { \
317 xd->pixels[i] = Rand16() & 255; \
318 } else { \
319 if ((color = Tk_GetColor(tk_mainInterp, tkwin, \
320 None, name)) == NULL) { \
321 xd->pixels[i] = Rand16() & 255; \
322 GotColor = 0; \
323 } else { \
324 switch (xd->depth) { \
325 case 8: \
326 xd->pixels[i] = \
327 color->pixel; \
328 break; \
329 case 15: \
330 if (xd->visual->red_mask == 0x7c00) { \
331 xd->pixels[i] = \
332 (((color->red >> (8 + 3)) & 0x1f) << (5 + 5)) | \
333 (((color->green >> (8 + 2)) & 0x1f) << (5)) | \
334 (((color->blue >> (8 + 3)) & 0x1f) << (0)); \
335 } else { \
336 (((color->blue >> (8 + 3)) & 0x1f) << (5 + 5)) | \
337 (((color->green >> (8 + 2)) & 0x1f) << (5)) | \
338 (((color->red >> (8 + 3)) & 0x1f) << (0)); \
339 } \
340 break; \
341 case 16: \
342 if (xd->visual->red_mask == 0xf800) { \
343 xd->pixels[i] = \
344 (((color->red >> (8 + 3)) & 0x1f) << (6 + 5)) | \
345 (((color->green >> (8 + 2)) & 0x3f) << (5)) | \
346 (((color->blue >> (8 + 3)) & 0x1f) << (0)); \
347 } else { \
348 xd->pixels[i] = \
349 (((color->blue >> (8 + 3)) & 0x1f) << (6 + 5)) | \
350 (((color->green >> (8 + 2)) & 0x3f) << (5)) | \
351 (((color->red >> (8 + 3)) & 0x1f) << (0)); \
352 } \
353 break; \
354 case 24: \
355 case 32: \
356 if (xd->visual->red_mask == 0xff0000) { \
357 xd->pixels[i] = \
358 ((color->red & 0xff) << 16) | \
359 ((color->green & 0xff) << 8) | \
360 ((color->blue & 0xff) << 0); \
361 } else { \
362 xd->pixels[i] = \
363 ((color->blue & 0xff) << 16) | \
364 ((color->green & 0xff) << 8) | \
365 ((color->red & 0xff) << 0); \
366 } \
367 break; \
368 } \
369 } \
370 }
371
372 if ((xd->depth == 8) &&
373 (Tk_DefaultColormap(xd->screen) ==
374 DefaultColormapOfScreen(xd->screen))) {
375 xd->pixels[COLOR_WHITE] = WhitePixelOfScreen(xd->screen);
376 xd->pixels[COLOR_BLACK] = BlackPixelOfScreen(xd->screen);
377 } else {
378 GETCOLOR(COLOR_WHITE, "#ffffff");
379 GETCOLOR(COLOR_BLACK, "#000000");
380 }
381
382 GETCOLOR(COLOR_YELLOW, "#ffff00");
383 GETCOLOR(COLOR_ORANGE, "#ff7f00");
384 GETCOLOR(COLOR_RED, "#ff0000");
385 GETCOLOR(COLOR_DARKRED, "#bf0000");
386 GETCOLOR(COLOR_DARKBLUE, "#0000e6");
387 GETCOLOR(COLOR_LIGHTBLUE, "#6666e6");
388 GETCOLOR(COLOR_BROWN, "#cc4c4c");
389 GETCOLOR(COLOR_LIGHTGREEN, "#00e600");
390 GETCOLOR(COLOR_DARKGREEN, "#007f00");
391 GETCOLOR(COLOR_OLIVE, "#997f4c");
392 GETCOLOR(COLOR_LIGHTBROWN, "#cc7f66");
393 GETCOLOR(COLOR_LIGHTGRAY, "#bfbfbf");
394 GETCOLOR(COLOR_MEDIUMGRAY, "#7f7f7f");
395 GETCOLOR(COLOR_DARKGRAY, "#3f3f3f");
396
397 if (!GotColor) {
398 fprintf(stderr,
399 "Oh, dear. There don't seem to be enough free colors on X display \"%s\".\n",
400 xd->display);
401 fprintf(stderr,
402 "Micropolis will try to run anyway, but might look pretty weird!\n");
403 }
404 } else { /* Black and white screen */
405 int white = WhitePixelOfScreen(xd->screen);
406 int black = BlackPixelOfScreen(xd->screen);
407
408 xd->pixels[COLOR_WHITE] = white;
409 xd->pixels[COLOR_BLACK] = black;
410
411 xd->pixels[COLOR_YELLOW] = white;
412 xd->pixels[COLOR_ORANGE] = white;
413 xd->pixels[COLOR_RED] = white;
414 xd->pixels[COLOR_DARKRED] = black;
415 xd->pixels[COLOR_DARKBLUE] = black;
416 xd->pixels[COLOR_LIGHTBLUE] = white;
417 xd->pixels[COLOR_BROWN] = black;
418 xd->pixels[COLOR_LIGHTGREEN] = white;
419 xd->pixels[COLOR_DARKGREEN] = black;
420 xd->pixels[COLOR_OLIVE] = black;
421 xd->pixels[COLOR_LIGHTBROWN] = white;
422 xd->pixels[COLOR_LIGHTGRAY] = white;
423 xd->pixels[COLOR_MEDIUMGRAY] = white;
424 xd->pixels[COLOR_DARKGRAY] = black;
425 }
426
427 xd->gc = Tk_DefaultGC(xd->screen);
428 XSetForeground(xd->dpy, xd->gc, xd->pixels[COLOR_BLACK]);
429 XSetBackground(xd->dpy, xd->gc, xd->pixels[COLOR_WHITE]);
430 XSetLineAttributes(xd->dpy, xd->gc,
431 1, LineSolid, CapButt, JoinMiter);
432 XSetGraphicsExposures(xd->dpy, xd->gc, False);
433
434 #ifndef MSDOS
435 { int major, minor, event, error, pixmaps;
436 if (WireMode ||
437 (XQueryExtension(xd->dpy, "MIT-SHM", /* Jeez! */
438 &major, &event, &error) != True) ||
439 (XShmQueryVersion(xd->dpy,
440 &major, &minor, &pixmaps) != True)) {
441 fprintf(stderr,
442 "Darn, X display \"%s\" doesn't support the shared memory extension.\n",
443 xd->display);
444 xd->shared = 0;
445 } else {
446 if (!pixmaps) {
447 fprintf(stderr,
448 "Darn, X display \"%s\" claims to support the shared memory extension,\n",
449 xd->display);
450 fprintf(stderr,
451 "but is too lame to support shared memory pixmaps, so Micropolis will run slower.\n");
452 fprintf(stderr,
453 "Please complain to your X server vendor, %s\n",
454 XServerVendor(xd->dpy));
455 xd->shared = -1;
456 } else {
457 fprintf(stderr,
458 "Cool, I found the shared memory extension!\n");
459 xd->shared = 1;
460 }
461 }
462 }
463 #else
464 xd->shared = 0;
465 #endif
466
467 xd->request = -1;
468 xd->last_request_read = -1;
469 xd->big_tile_pixmap = None;
470 xd->objects = NULL;
471 xd->overlay_gc = NULL;
472 xd->gray25_stipple = None;
473 xd->gray50_stipple = None;
474 xd->gray75_stipple = None;
475 xd->vert_stipple = None;
476 xd->horiz_stipple = None;
477 xd->diag_stipple = None;
478
479 xd->big_tile_image = xd->small_tile_image = NULL;
480
481 xd->next = XDisplays; XDisplays = xd;
482 }
483
484 return (xd);
485 }
486
487
488 IncRefDisplay(XDisplay *xd)
489 {
490 xd->references++;
491 }
492
493
494 DecRefDisplay(XDisplay *xd)
495 {
496 if ((--xd->references) == 0) {
497 /* I'd blow it away, but tk may still be using the display */
498 }
499 }
500
501
502 SimView *
503 InitNewView(SimView *view, char *title, int class, int w, int h)
504 {
505 int type, i;
506 int test = 1;
507 int d = 8;
508 unsigned long valuemask = 0;
509 char *t;
510 struct XDisplay *xd;
511 XGCValues values;
512 XColor rgb, *color;
513
514 t = (char *)ckalloc(strlen(title) + 1);
515 strcpy(t, title);
516
517 view->next = NULL;
518 view->title = t;
519 view->type = -1;
520 view->class = class;
521 view->bigtiles = view->smalltiles = NULL;
522 view->pixels = NULL;
523 view->line_bytes = 0;
524 view->line_bytes8 = 0;
525 view->pixel_bytes = 0;
526 view->depth = 0;
527 view->data = NULL;
528 view->data8 = NULL;
529 view->visible = 0;
530 view->invalid = 0;
531 view->skips = view->skip = 0;
532 view->update = 0;
533 view->map_state = ALMAP;
534 view->show_editors = 1;
535 view->tool_showing = 0;
536 view->tool_mode = 0;
537 view->tool_x = view->tool_y = 0;
538 view->tool_x_const = view->tool_y_const = -1;
539 view->tool_state = dozeState;
540 view->tool_state_save = -1;
541 view->super_user = 0;
542 view->show_me = 1;
543 view->dynamic_filter = 0;
544 view->auto_scroll_token = 0;
545 view->tool_event_time = 0;
546 view->tool_last_event_time = 0;
547 view->w_x = view->w_y = 0;
548 view->w_width = view->w_height = 16;
549 view->m_width = view->m_height = 0;
550 view->i_width = w; view->i_height = h;
551 view->pan_x = view->pan_y = 0;
552 view->tile_x = view->tile_y = 0;
553 view->tile_width = view->tile_height = 0;
554 view->screen_x = view->screen_y = 0;
555 view->screen_width = view->screen_height = 0;
556 view->last_x = view->last_y = view->last_button = 0;
557 view->track_info = NULL;
558 view->message_var = NULL;
559
560 /* This stuff was initialized in our caller (SimViewCmd) */
561 /* view->tkwin = NULL; */
562 /* view->interp = NULL; */
563 /* view->flags = 0; */
564
565 view->x = NULL;
566 view->shminfo = NULL;
567 view->tiles = NULL;
568 view->other_tiles = NULL;
569 view->image = NULL;
570 view->other_image = NULL;
571 view->other_data = NULL;
572 view->pixmap = None;
573 view->pixmap2 = None;
574 view->overlay_pixmap = None;
575 view->overlay_valid = 0;
576 view->fontPtr = NULL;
577 view->updates = 0;
578 view->update_real = view->update_user = view->update_system = 0.0;
579 view->update_context = 0;
580 view->auto_goto = 0;
581 view->auto_going = 0;
582 view->auto_x_goal = view->auto_x_goal = 0;
583 view->auto_speed = 75;
584 view->follow = NULL;
585 view->sound = 1;
586 view->width = 0; view->height = 0;
587 view->show_overlay = 1;
588 view->overlay_mode = 0;
589
590 view->x = FindXDisplay(view->tkwin);
591 IncRefDisplay(view->x);
592
593 /* view->x->shared is 1 if the shared memory extension is present and
594 supports shared memory pixmaps, and -1 if it is present but doesn't. */
595 if (view->x->shared != 1) {
596 view->type = X_Wire_View;
597 } else {
598 view->type = X_Mem_View;
599 }
600
601 view->x->needs_swap = !(*(unsigned char*) (&test));
602 view->x->x_big_endian = (ImageByteOrder(view->x->dpy) == MSBFirst);
603
604
605 GetPixmaps(view->x);
606 view->pixels = view->x->pixels;
607
608 if (w == EDITOR_W) w = 256; /* XXX */
609 if (h == EDITOR_H) h = 256; /* XXX */
610
611 view->pan_x = w / 2; view->pan_y = h / 2;
612 DoResizeView(view, w, h);
613
614 GetViewTiles(view);
615
616 return (view);
617 }
618
619
620 DestroyView(SimView *view)
621 {
622 SimView **vp;
623
624 CancelRedrawView(view);
625
626 for (vp = ((view->class == Editor_Class) ?
627 (&sim->editor) : (&sim->map));
628 (*vp) != NULL;
629 vp = &((*vp)->next)) {
630 if ((*vp) == view) {
631 (*vp) = view->next;
632 if (view->class == Editor_Class)
633 sim->editors--;
634 else
635 sim->maps--;
636
637 break;
638 }
639 }
640
641 if (view->title != NULL) {
642 ckfree (view->title);
643 view->title = NULL;
644 }
645
646 if (view->pixmap != None) {
647 XFreePixmap(view->x->dpy, view->pixmap);
648 view->pixmap = None;
649 }
650
651 if (view->pixmap2 != None) {
652 XFreePixmap(view->x->dpy, view->pixmap2);
653 view->pixmap2 = None;
654 }
655
656 if (view->overlay_pixmap != None) {
657 XFreePixmap(view->x->dpy, view->overlay_pixmap);
658 view->overlay_pixmap = None;
659 }
660
661 if (view->auto_scroll_token) {
662 Tk_DeleteTimerHandler(view->auto_scroll_token);
663 view->auto_scroll_token = 0;
664 }
665
666 #ifndef MSDOS
667 if (view->shminfo) {
668 XShmDetach(view->x->dpy, view->shminfo);
669 shmdt(view->shminfo->shmaddr);
670 shmctl(view->shminfo->shmid, IPC_RMID, 0);
671 ckfree(view->shminfo);
672 view->shminfo = NULL;
673 if (view->image) {
674 view->image->data = NULL;
675 view->data = NULL;
676 XDestroyImage(view->image);
677 view->image = NULL;
678 }
679 } else {
680 #endif
681 if (view->image) {
682 if (view->image->data) {
683 ckfree(view->image->data);
684 view->image->data = NULL;
685 }
686 view->data = NULL;
687 XDestroyImage(view->image);
688 view->image = NULL;
689 }
690 #ifndef MSDOS
691 }
692 #endif
693
694 if (view->other_image) {
695 if (view->other_image->data) {
696 ckfree(view->other_image->data);
697 view->other_image->data = NULL;
698 }
699 view->other_data = NULL;
700 XDestroyImage(view->other_image);
701 view->other_image = NULL;
702 }
703
704 if (view->tiles)
705 FreeTiles(view);
706
707 DecRefDisplay(view->x);
708
709 ckfree((char *) view);
710 }
711
712
713 unsigned char *
714 AllocPixels(int len, unsigned char pixel)
715 {
716 int i;
717 unsigned char *data, *cp;
718
719 cp = data = (unsigned char *)ckalloc(len);
720 for (i = len; i > 0; i--) {
721 *(cp++) = pixel;
722 }
723
724 return (data);
725 }
726
727
728 DoResizeView(SimView *view, int w, int h)
729 {
730 int resize = 0;
731
732 view->w_width = w;
733 view->w_height = h;
734
735 if (view->class == Map_Class) { /* Map_Class */
736 view->m_width = w;
737 view->m_height = h;
738
739 if (view->pixmap2 == None) {
740
741 view->pixmap2 = XCreatePixmap(view->x->dpy, view->x->root,
742 w, h, view->x->depth);
743 if (view->pixmap2 == None) {
744 fprintf(stderr,
745 "Sorry, Micropolis can't create a pixmap on X display \"%s\"!\n",
746 view->x->display);
747 sim_exit(1); // Just sets tkMustExit and ExitReturn
748 return;
749 }
750 }
751
752 } else { /* Editor_Class */
753
754 if ((w = (w + 31) & (~15)) > view->m_width)
755 view->m_width = w, resize++;
756 if ((h = (h + 31) & (~15)) > view->m_height)
757 view->m_height = h, resize++;
758
759 if (resize || (view->pixmap2 == None)) {
760 if (view->pixmap2 != None) {
761 XFreePixmap(view->x->dpy, view->pixmap2);
762 view->pixmap2 = None;
763 }
764 view->pixmap2 = XCreatePixmap(view->x->dpy, view->x->root,
765 view->m_width, view->m_height,
766 view->x->depth);
767 if (view->pixmap2 == None) {
768 fprintf(stderr,
769 "Sorry, Micropolis couldn't create a pixmap on X display \"%s\"!\n",
770 view->x->display);
771 sim_exit(1); // Just sets tkMustExit and ExitReturn
772 return;
773 }
774 }
775
776 if (resize || (view->overlay_pixmap == None)) {
777 view->overlay_mode = 0;
778 if (view->overlay_pixmap != None) {
779 XFreePixmap(view->x->dpy, view->overlay_pixmap);
780 view->overlay_pixmap = None;
781 }
782 view->overlay_pixmap = XCreatePixmap(view->x->dpy, view->x->root,
783 view->m_width, view->m_height,
784 1);
785 if (view->overlay_pixmap == None) {
786 fprintf(stderr,
787 "Sorry, Micropolis couldn't create another pixmap on X display \"%s\".\n",
788 view->x->display);
789 sim_exit(1); // Just sets tkMustExit and ExitReturn
790 return;
791 }
792 if (view->x->overlay_gc == NULL) {
793 unsigned long valuemask = 0;
794 XGCValues values;
795
796 view->x->overlay_gc =
797 XCreateGC(view->x->dpy, view->overlay_pixmap, valuemask, &values);
798 XSetForeground(view->x->dpy, view->x->overlay_gc, 0);
799 XSetBackground(view->x->dpy, view->x->overlay_gc, 1);
800 XSetLineAttributes(view->x->dpy, view->x->overlay_gc,
801 1, LineSolid, CapButt, JoinMiter);
802 XSetGraphicsExposures(view->x->dpy, view->x->overlay_gc, False);
803 }
804 }
805
806 }
807
808 #ifndef MSDOS
809 if (view->type != X_Mem_View) {
810 goto SPRING_FORWARD;
811 }
812
813 if (resize || (view->image == NULL)) {
814 if (view->shminfo && view->image) {
815 if (view->pixmap != None) {
816 XFreePixmap(view->x->dpy, view->pixmap);
817 view->pixmap = None;
818 }
819 XShmDetach(view->x->dpy, view->shminfo);
820 shmdt(view->shminfo->shmaddr);
821 shmctl(view->shminfo->shmid, IPC_RMID, 0);
822 view->image->data = NULL;
823 if (view->data == view->data8)
824 view->data8 = NULL;
825 view->data = NULL;
826 XDestroyImage(view->image);
827 view->image = NULL;
828 }
829
830 #if 0
831 /* XShmPixmapFormat is documented but does not exist !!! */
832 if (XShmPixmapFormat(view->x->dpy) != ZPixmap) {
833 fprintf(stderr,
834 "Darn, display \"%s\" has the wrong shared memory format.\n",
835 view->x->display);
836 goto FALL_BACK;
837 }
838 #endif
839
840 if (!view->shminfo) {
841 view->shminfo = (XShmSegmentInfo *)ckalloc(sizeof (XShmSegmentInfo));
842 }
843
844 view->image =
845 XShmCreateImage(view->x->dpy, view->x->visual, view->x->depth,
846 view->x->color ? ZPixmap : XYBitmap,
847 NULL, view->shminfo,
848 view->m_width, view->m_height);
849
850 view->line_bytes = view->image->bytes_per_line;
851
852 switch (view->x->depth) {
853
854 case 1:
855 view->pixel_bytes = 0;
856 view->depth = 1;
857 break;
858
859 case 8:
860 view->pixel_bytes = 1;
861 view->depth = 8;
862 break;
863
864 case 15:
865 view->pixel_bytes = 2;
866 view->depth = 15;
867 break;
868
869 case 16:
870 view->pixel_bytes = 2;
871 view->depth = 16;
872 break;
873
874 case 24:
875 /* XXX: TODO: 24 and 32 bit support */
876 view->pixel_bytes = 4;
877 //view->pixel_bytes = 3;
878 view->depth = 24;
879 break;
880
881 case 32:
882 /* XXX: TODO: 24 and 32 bit support */
883 view->pixel_bytes = 4;
884 view->depth = 32;
885 break;
886
887 default:
888 view->pixel_bytes = 0;
889 view->depth = 0;
890 break;
891
892 } // switch
893
894 view->shminfo->shmid = shmget(IPC_PRIVATE,
895 (view->line_bytes *
896 view->m_height),
897 (IPC_CREAT | 0777));
898 if (view->shminfo->shmid < 0) {
899 perror("shmget");
900 fprintf(stderr,
901 "Darn, Micropolis can't share memory with X display \"%s\".\n",
902 view->x->display);
903 goto FALL_BACK;
904 }
905
906 view->data = (unsigned char *)shmat(view->shminfo->shmid, 0, 0);
907 if ((int)view->data == -1) {
908 perror("shmat");
909 fprintf(stderr,
910 "Darn, Micropolis can't find any memory to share with display \"%s\".\n",
911 view->x->display);
912 goto FALL_BACK;
913 }
914
915 view->image->data = (char *)view->data;
916 view->shminfo->shmaddr = (char *)view->data;
917 view->shminfo->readOnly = False;
918
919 { int (*old)();
920 int result;
921 int attached = 0;
922 GotXError = 0;
923 old = XSetErrorHandler(CatchXError);
924
925 result =
926 XShmAttach(view->x->dpy, view->shminfo);
927 if (result == 0) {
928 fprintf(stderr,
929 "Darn, the X display \"%s\" can't access Micropolis's shared memory.\n",
930 view->x->display);
931 GotXError = 1;
932 }
933
934 XSync(view->x->dpy, False);
935
936 if (!GotXError) {
937 attached = 1;
938 view->pixmap = XShmCreatePixmap(view->x->dpy, view->x->root,
939 view->data, view->shminfo,
940 view->m_width, view->m_height,
941 view->x->depth);
942 XSync(view->x->dpy, False);
943
944 if (GotXError ||
945 (view->pixmap == None)) {
946 fprintf(stderr,
947 "Darn, Micropolis couldn't get a shared memory pixmap on X display \"%s\".\n",
948 view->x->display);
949 GotXError = 1;
950 }
951 }
952
953 XSetErrorHandler(old);
954
955 if (GotXError) {
956 view->pixmap = None;
957 if (attached) {
958 XShmDetach(view->x->dpy, view->shminfo);
959 } // if
960 result = shmdt(view->shminfo->shmaddr);
961 result = shmctl(view->shminfo->shmid, IPC_RMID, 0);
962 ckfree(view->shminfo);
963 view->shminfo = NULL;
964 if (view->image) {
965 view->image->data = NULL;
966 view->data = NULL;
967 XDestroyImage(view->image);
968 view->image = NULL;
969 }
970 goto FALL_BACK;
971 }
972
973 if (view->x->color) {
974 XSetForeground(view->x->dpy, view->x->gc,
975 view->pixels[COLOR_LIGHTBROWN]);
976 } else {
977 XSetForeground(view->x->dpy, view->x->gc,
978 view->pixels[COLOR_WHITE]);
979 }
980
981 XFillRectangle(view->x->dpy, view->pixmap, view->x->gc,
982 0, 0, view->m_width, view->m_height);
983 }
984 }
985
986 goto FINISH;
987
988 FALL_BACK:
989
990 fprintf(stderr,
991 "Falling back to the X network protocol on display \"%s\"...\n",
992 view->x->display);
993 #endif
994
995 view->x->shared = 0;
996 view->type = X_Wire_View;
997 if (view->pixmap != None) {
998 XFreePixmap(view->x->dpy, view->pixmap);
999 view->pixmap = None;
1000 }
1001 #ifndef MSDOS
1002 if (view->shminfo) {
1003 if (view->shminfo->shmid >= 0) {
1004 if (view->shminfo->shmaddr) {
1005 shmdt(view->shminfo->shmaddr);
1006 }
1007 shmctl(view->shminfo->shmid, IPC_RMID, 0);
1008 }
1009 ckfree((char *)view->shminfo);
1010 view->shminfo = NULL;
1011 }
1012 #endif
1013 if (view->image) {
1014 view->image->data = NULL;
1015 XDestroyImage(view->image);
1016 view->image = NULL;
1017 }
1018 view->data = NULL;
1019 view->line_bytes = 0;
1020 view->pixel_bytes = 0;
1021 view->depth = 0;
1022
1023 SPRING_FORWARD:
1024
1025 if (resize || (view->pixmap == None)) {
1026 if (view->pixmap != None) {
1027 XFreePixmap(view->x->dpy, view->pixmap);
1028 view->pixmap = None;
1029 }
1030 view->pixmap = XCreatePixmap(view->x->dpy, view->x->root,
1031 view->m_width, view->m_height,
1032 view->x->depth);
1033 if (view->pixmap == None) {
1034 fprintf(stderr,
1035 "Sorry, Micropolis can't create pixmap on X display \"%s\".\n",
1036 view->x->display);
1037 sim_exit(1); // Just sets tkMustExit and ExitReturn
1038 return;
1039 }
1040 if (view->x->color) {
1041 XSetForeground(view->x->dpy, view->x->gc,
1042 view->pixels[COLOR_LIGHTBROWN]);
1043 } else {
1044 XSetForeground(view->x->dpy, view->x->gc,
1045 view->pixels[COLOR_WHITE]);
1046 }
1047 XFillRectangle(view->x->dpy, view->pixmap, view->x->gc,
1048 0, 0, view->m_width, view->m_height);
1049 }
1050
1051 FINISH:
1052
1053 if (view->class == Editor_Class) {
1054
1055 AllocTiles(view);
1056 DoAdjustPan(view);
1057
1058 } else if (view->class == Map_Class) {
1059
1060 if (view->type == X_Mem_View) { /* Memory Map */
1061
1062 if (view->x->color) {
1063
1064 /* Color, Shared Memory */
1065
1066 view->data8 = view->data;
1067 view->line_bytes8 = view->line_bytes; /* XXX: ??? */
1068
1069 switch (view->x->depth) {
1070
1071 case 8:
1072 view->pixel_bytes = 1;
1073 view->depth = 8;
1074 break;
1075
1076 case 15:
1077 view->pixel_bytes = 2;
1078 view->depth = 15;
1079 break;
1080
1081 case 16:
1082 view->pixel_bytes = 2;
1083 view->depth = 16;
1084 break;
1085
1086 case 24:
1087 /* XXX: TODO: 24 and 32 bit support */
1088 view->pixel_bytes = 4;
1089 //view->pixel_bytes = 3;
1090 view->depth = 24;
1091 break;
1092
1093 case 32:
1094 /* XXX: TODO: 24 and 32 bit support */
1095 view->pixel_bytes = 4;
1096 view->depth = 32;
1097 break;
1098
1099 default:
1100 view->pixel_bytes = 0;
1101 view->depth = 0;
1102 break;
1103
1104 } // switch
1105
1106 } else {
1107
1108 /* Black and White, Shared Memory */
1109
1110 if (view->other_image != NULL) {
1111 XDestroyImage(view->other_image);
1112 }
1113
1114 view->line_bytes8 = view->m_width; /* XXX: fix depth */
1115 view->pixel_bytes = 0;
1116 view->depth = 1;
1117
1118 view->other_data = view->data8 =
1119 AllocPixels(view->m_height * view->line_bytes8, /* XXX: fix depth */
1120 view->pixels[COLOR_WHITE]);
1121 view->other_image =
1122 XCreateImage(view->x->dpy, view->x->visual, 8, /* XXX: fix depth */
1123 ZPixmap, 0, (char *)view->other_data,
1124 view->m_width, view->m_height,
1125 8, view->line_bytes8); /* XXX: fix depth */
1126 }
1127
1128 } else { /* Wire Map */
1129 int bitmap_pad;
1130 int bitmap_depth;
1131
1132 if (view->image != NULL) {
1133 XDestroyImage(view->image);
1134 view->image = NULL;
1135 }
1136
1137 if (view->other_image != NULL) {
1138 XDestroyImage(view->other_image);
1139 view->other_image = NULL;
1140 }
1141
1142 if (view->x->color) {
1143
1144 /* Color, Wire */
1145
1146 switch (view->x->depth) {
1147
1148 case 8:
1149 view->pixel_bytes = 1;
1150 view->depth = 8;
1151 bitmap_pad = 8;
1152 bitmap_depth = 8;
1153 view->line_bytes8 =
1154 ((view->m_width * view->pixel_bytes) + 3) & (~3);
1155 break;
1156
1157 case 15:
1158 view->pixel_bytes = 2;
1159 view->depth = 15;
1160 bitmap_pad = 16;
1161 bitmap_depth = 15;
1162 view->line_bytes8 =
1163 ((view->m_width * view->pixel_bytes) + 3) & (~3);
1164 break;
1165
1166 case 16:
1167 view->pixel_bytes = 2;
1168 view->depth = 16;
1169 bitmap_pad = 16;
1170 bitmap_depth = 16;
1171 view->line_bytes8 =
1172 ((view->m_width * view->pixel_bytes) + 3) & (~3);
1173 break;
1174
1175 case 24:
1176 view->pixel_bytes = 4;
1177 //view->pixel_bytes = 3;
1178 view->depth = 24;
1179 bitmap_depth = 24;
1180 bitmap_pad = 32;
1181 view->line_bytes8 =
1182 ((view->m_width * 4) + 3) & (~3);
1183 break;
1184
1185 case 32:
1186 view->pixel_bytes = 4;
1187 view->depth = 32;
1188 bitmap_pad = 32;
1189 bitmap_depth = 32;
1190 view->line_bytes8 =
1191 ((view->m_width * 4) + 3) & (~3);
1192 break;
1193
1194 default:
1195 assert(0); /* Unknown depth */
1196 break;
1197
1198 } // switch
1199
1200 view->line_bytes =
1201 view->line_bytes8;
1202
1203 } else {
1204
1205 /* Black and White, Wire */
1206
1207 view->pixel_bytes = 0;
1208 view->depth = 1;
1209 view->line_bytes8 =
1210 (view->m_width + 3) & (~3); /* XXX: handle depth */
1211 view->line_bytes =
1212 (view->m_width + 7) >>3;
1213 bitmap_pad = 8;
1214 bitmap_depth = 8;
1215
1216 }
1217
1218 view->data =
1219 AllocPixels(view->m_height * view->line_bytes, 0);
1220 view->image =
1221 XCreateImage(view->x->dpy, view->x->visual,
1222 bitmap_depth,
1223 view->x->color ? ZPixmap : XYBitmap,
1224 0, (char *)view->data,
1225 view->m_width, view->m_height,
1226 bitmap_pad,
1227 view->line_bytes);
1228
1229 view->other_data =
1230 AllocPixels(view->m_height * view->line_bytes8, 0);
1231 view->other_image =
1232 XCreateImage(view->x->dpy, view->x->visual,
1233 bitmap_depth,
1234 ZPixmap,
1235 0, (char *)view->other_data,
1236 view->m_width, view->m_height,
1237 bitmap_pad,
1238 view->line_bytes);
1239
1240 if (view->x->color) {
1241 view->data8 = view->data;
1242 } else {
1243 view->data8 = view->other_data;
1244 }
1245 }
1246 }
1247 }
1248
1249
1250 DoPanBy(struct SimView *view, int dx, int dy)
1251 {
1252 DoPanTo(view, view->pan_x + dx, view->pan_y + dy);
1253 }
1254
1255
1256 DoPanTo(struct SimView *view, int x, int y)
1257 {
1258 if (view->class != Editor_Class) {
1259 return;
1260 }
1261
1262 if (x < 0) x = 0;
1263 if (y < 0) y = 0;
1264 if (x > view->i_width) x = view->i_width - 1;
1265 if (y > view->i_height) y = view->i_height - 1;
1266 if ((view->pan_x != x) ||
1267 (view->pan_y != y)) {
1268 view->pan_x = x;
1269 view->pan_y = y;
1270 DoAdjustPan(view);
1271 }
1272 }
1273
1274 /* #define DEBUG_PAN */
1275
1276 DoAdjustPan(struct SimView *view)
1277 {
1278 int ww2 = view->w_width >>1, wh2 = view->w_height >>1;
1279 int px = view->pan_x, py = view->pan_y;
1280 int last_tile_x = view->tile_x, last_tile_y = view->tile_y;
1281 int last_tile_width = view->tile_width, last_tile_height = view->tile_height;
1282 int total_width = view->m_width >>4, total_height = view->m_height >>4;
1283 //fprintf(stderr, "DoAdjustPan\n");
1284
1285 #ifdef DEBUG_PAN
1286 printf("AdjustPan window %d %d ww2 %d wh2 %d pan %d %d\n",
1287 view->w_width, view->w_height, ww2, wh2, px, py);
1288 printf(" last tile %d %d %d %d\n",
1289 last_tile_x, last_tile_y, last_tile_width, last_tile_height);
1290 #endif
1291
1292 if ((view->tile_x = ((px - ww2) >>4)) < 0)
1293 view->tile_x = 0;
1294 if ((view->tile_y = ((py - wh2) >>4)) < 0)
1295 view->tile_y = 0;
1296
1297 #ifdef DEBUG_PAN
1298 printf(" now tile %d %d\n", view->tile_x, view->tile_y);
1299 #endif
1300
1301 view->tile_width = ((15 + px + ww2) >>4);
1302 view->tile_height = ((15 + py + wh2) >>4);
1303
1304 #ifdef DEBUG_PAN
1305 printf(" outer tile %d %d\n", view->tile_width, view->tile_height);
1306 #endif
1307
1308 if (view->tile_width > (view->i_width >>4))
1309 view->tile_width = (view->i_width >>4);
1310 view->tile_width -= view->tile_x;
1311 if (view->tile_height > (view->i_height >>4))
1312 view->tile_height = (view->i_height >>4);
1313 view->tile_height -= view->tile_y;
1314
1315 #ifdef DEBUG_PAN
1316 printf(" tile size %d %d\n", view->tile_width, view->tile_height);
1317 #endif
1318
1319 if (view->tile_width > (view->m_width >>4))
1320 view->tile_width = (view->m_width >>4);
1321 if (view->tile_height > (view->m_height >>4))
1322 view->tile_height = (view->m_height >>4);
1323
1324 #ifdef DEBUG_PAN
1325 printf(" clipped size %d %d\n", view->tile_width, view->tile_height);
1326 printf(" maximum size %d %d\n", view->m_width >>4, view->m_height >>4);
1327 #endif
1328
1329 view->screen_x = (ww2 - px) + (view->tile_x <<4);
1330 view->screen_y = (wh2 - py) + (view->tile_y <<4);
1331 view->screen_width = (view->tile_width <<4);
1332 view->screen_height = (view->tile_height <<4);
1333
1334 #ifdef DEBUG_PAN
1335 printf(" screen %d %d %d %d\n",
1336 view->screen_x, view->screen_y,
1337 view->screen_width, view->screen_height);
1338 #endif
1339
1340 view->overlay_mode = 0;
1341 // view->skip = 0;
1342 view->invalid = 1;
1343 if (SimSpeed == 0) {
1344 EventuallyRedrawView(view);
1345 }
1346 /* InvalidateEditors(); */
1347 if (view->show_me) {
1348 RedrawMaps();
1349 }
1350 /* FixMicropolisTimer(); */
1351
1352 { int dx = last_tile_x - view->tile_x,
1353 dy = last_tile_y - view->tile_y;
1354 short **want = view->other_tiles,
1355 **have = view->tiles;
1356
1357 #ifdef DEBUG_PAN
1358 printf("scrolling %d %d\n", dx, dy);
1359 #endif
1360
1361 if ((dx != 0) || (dy != 0)) {
1362 int row, col, x, y,
1363 width = view->tile_width,
1364 height = view->tile_height;
1365
1366 for (col = 0; col < width; col++)
1367 memcpy(want[col], have[col], (height * sizeof(short)));
1368
1369 for (col = 0; col < total_width; col++) {
1370 x = col - dx;
1371 for (row = 0; row < total_height; row++) {
1372 y = row - dy;
1373 if ((x >= 0) && (x < width) &&
1374 (y >= 0) && (y < height)) {
1375 have[col][row] = want[x][y];
1376 } else {
1377 have[col][row] = -1;
1378 }
1379 }
1380 }
1381
1382 XCopyArea(view->x->dpy, view->pixmap, view->pixmap, view->x->gc,
1383 0, 0, view->tile_width <<4, view->tile_height <<4,
1384 dx <<4, dy <<4);
1385
1386 if (view->type == X_Mem_View) {
1387 XSync(view->x->dpy, False);
1388 }
1389 }
1390 }
1391 }
1392
1393
1394 AllocTiles(SimView *view)
1395 {
1396 int row, col;
1397 short **have, **want;
1398 int w = view->m_width / 16, h = view->m_height / 16;
1399 int n = (w + 1) * sizeof (short *);
1400
1401 if (view->tiles)
1402 FreeTiles(view);
1403
1404 have = view->tiles =
1405 (short **)ckalloc(n);
1406
1407 want = view->other_tiles =
1408 (short **)ckalloc(n);
1409
1410 have[w] = want[w] = NULL;
1411
1412 n = h * sizeof(short);
1413 for (col = 0; col < w; col++) {
1414
1415 have[col] = (short *)ckalloc(n);
1416 want[col] = (short *)ckalloc(n);
1417 for (row = 0; row < h; row++) {
1418 have[col][row] = -1;
1419 want[col][row] = -1;
1420 }
1421 }
1422 }
1423
1424
1425 FreeTiles(SimView *view)
1426 {
1427 int col;
1428
1429 for (col = 0; view->tiles[col] != NULL; col++) {
1430 ckfree ((char *)view->tiles[col]);
1431 ckfree ((char *)view->other_tiles[col]);
1432 }
1433 ckfree ((char *)view->tiles);
1434 view->tiles = NULL;
1435 ckfree ((char *)view->other_tiles);
1436 view->other_tiles = NULL;
1437 }
1438
1439
1440 #define POINT_BATCH 32
1441
1442 Ink *OldInk = NULL;
1443
1444
1445 /* XXX: todo: ink locking so someone doesn't erase ink that's being drawn */
1446
1447 Ink *
1448 NewInk()
1449 {
1450 Ink *ink;
1451
1452 if (OldInk) {
1453 ink = OldInk;
1454 OldInk = OldInk->next;
1455 } else {
1456 ink = (Ink *)ckalloc(sizeof(Ink));
1457 ink->maxlength = POINT_BATCH;
1458 ink->points = (XPoint *)ckalloc(POINT_BATCH * sizeof(XPoint));
1459 }
1460 ink->length = 0;
1461 ink->color = COLOR_WHITE;
1462 ink->next = NULL;
1463 ink->left = ink->right = ink->top = ink->bottom =
1464 ink->last_x = ink->last_y = -1;
1465 return (ink);
1466 }
1467
1468
1469 FreeInk(Ink *ink)
1470 {
1471 ink->next = OldInk;
1472 OldInk = ink;
1473 }
1474
1475
1476 StartInk(Ink *ink, int x, int y)
1477 {
1478 ink->length = 1;
1479 ink->left = ink->right = ink->last_x = ink->points[0].x = x;
1480 ink->top = ink->bottom = ink->last_y = ink->points[0].y = y;
1481 }
1482
1483
1484 AddInk(Ink *ink, int x, int y)
1485 {
1486 int dx = x - ink->last_x;
1487 int dy = y - ink->last_y;
1488
1489 if ((dx != 0) || (dy != 0)) {
1490 /*
1491 if (ink->length > 1) {
1492 if ((dx == 0) &&
1493 (ink->points[ink->length - 1].x == 0) &&
1494 ((ink->points[ink->length - 1].y < 0) ?
1495 (dy < 0) : (dy > 0))) {
1496 ink->points[ink->length - 1].y += dy;
1497 goto ADJUST;
1498 } else if ((dy == 0) &&
1499 (ink->points[ink->length - 1].y == 0) &&
1500 ((ink->points[ink->length - 1].x < 0) ?
1501 (dx < 0) : (dx > 0))) {
1502 ink->points[ink->length - 1].x += dx;
1503 goto ADJUST;
1504 }
1505 }
1506 */
1507
1508 if (ink->length >= ink->maxlength) {
1509 ink->maxlength += POINT_BATCH;
1510 ink->points = (XPoint *)realloc((void *)ink->points,
1511 ink->maxlength * sizeof(XPoint));
1512 }
1513 ink->points[ink->length].x = dx;
1514 ink->points[ink->length].y = dy;
1515 ink->length++;
1516
1517 ADJUST:
1518 if (x < ink->left)
1519 ink->left = x;
1520 if (x > ink->right)
1521 ink->right = x;
1522 if (y < ink->top)
1523 ink->top = y;
1524 if (y > ink->bottom)
1525 ink->bottom = y;
1526
1527 { int left, right, top, bottom;
1528 SimView *view;
1529
1530 if (ink->last_x < x) { left = ink->last_x; right = x; }
1531 else { left = x; right = ink->last_x; }
1532 if (ink->last_y < y) { top = ink->last_y; bottom = y; }
1533 else { top = y; bottom = ink->last_y; }
1534
1535 left -= 5; right += 5; top -= 5; bottom += 5;
1536
1537 for (view = sim->editor; view != NULL; view = view->next) {
1538 int vleft, vtop;
1539
1540 if ((right >= (vleft = view->pan_x - (view->w_width / 2))) &&
1541 (left <= vleft + view->w_width) &&
1542 (bottom >= (vtop = view->pan_y - (view->w_height / 2))) &&
1543 (top <= vtop + view->w_height)) {
1544 /* XXX: do studly incremental update instead */
1545 view->overlay_mode = 0;
1546 EventuallyRedrawView(view);
1547 }
1548 }
1549 }
1550 ink->last_x = x; ink->last_y = y;
1551 }
1552 }
1553
1554
1555 EraseOverlay()
1556 {
1557 Ink *ink;
1558
1559 while (sim->overlay) {
1560 ink = sim->overlay;
1561 sim->overlay = ink->next;
1562 FreeInk(ink);
1563 }
1564 }
Impressum, Datenschutz