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