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