]>
git.zerfleddert.de Git - micropolis/blob - src/sim/w_x.c
1 /* w_x.c: X Window System support
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.
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.
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/>.
21 * ADDITIONAL TERMS per GNU GPL Section 7
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.
29 * Any propagation or conveyance of this program must include this
30 * copyright notice and these terms.
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.
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.
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
65 struct XDisplay
*XDisplays
= NULL
;
75 unsigned char ColorIntensities
[] = {
76 /* COLOR_WHITE */ 255,
77 /* COLOR_YELLOW */ 170,
78 /* COLOR_ORANGE */ 127,
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,
95 ViewToTileCoords(SimView
*view
, int x
, int y
, int *outx
, int *outy
)
97 x
= (view
->pan_x
- ((view
->w_width
>>1) - x
)) >>4;
98 y
= (view
->pan_y
- ((view
->w_height
>>1) - y
)) >>4;
101 if (x
>= WORLD_X
) x
= WORLD_X
- 1;
103 if (y
>= WORLD_Y
) y
= WORLD_Y
- 1;
105 if (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
)
111 if (y
>= view
->tile_y
+ view
->tile_height
)
112 y
= view
->tile_y
+ view
->tile_height
- 1;
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
;
119 *outx
= x
; *outy
= y
;
123 ViewToPixelCoords(SimView
*view
, int x
, int y
, int *outx
, int *outy
)
125 x
= view
->pan_x
- ((view
->w_width
>>1) - x
);
126 y
= view
->pan_y
- ((view
->w_height
>>1) - y
);
129 if (x
>= (WORLD_X
<<4)) x
= (WORLD_X
<<4) - 1;
131 if (y
>= (WORLD_Y
<<4)) y
= (WORLD_Y
<<4) - 1;
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;
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;
147 *outx
= x
; *outy
= y
;
160 sim_skip
= sim_skips
;
163 switch (FlushStyle
) {
169 for (xd
= XDisplays
; xd
!= NULL
; xd
= xd
->next
)
174 for (xd
= XDisplays
; xd
!= NULL
; xd
= xd
->next
)
175 XSync(xd
->dpy
, False
);
179 if (XDisplays
&& XDisplays
->next
) {
180 for (xd
= XDisplays
; xd
!= NULL
; xd
= xd
->next
) {
184 for (xd
= XDisplays
; xd
!= NULL
; xd
= xd
->next
) {
185 XSync(xd
->dpy
, False
);
190 for (xd
= XDisplays
; xd
!= NULL
; xd
= xd
->next
) {
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
;
208 CatchXError(Display
*dpy
, XErrorEvent
*err
)
212 printf("GOT X ERROR code %d request code %d %d\n",
213 err
->error_code
, err
->request_code
, err
->minor_code
);
221 (void)XSetErrorHandler(CatchXError
);
226 while (sim
->editor
!= NULL
) {
227 DestroyView(sim
->editor
);
230 while (sim
->map
!= NULL
) {
231 DestroyView(sim
->map
);
234 while (sim
->graph
!= NULL
) {
235 DestroyGraph(sim
->graph
);
239 while (sim
->scam
!= NULL
) {
240 DestroyCam(sim
->scam
);
249 while (Tk_DoOneEvent(TK_DONT_WAIT
)) ;
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
;
264 sim
->scams
= 0; sim
->scam
= NULL
;
273 FindXDisplay(Tk_Window tkwin
)
277 unsigned long valuemask
= 0;
280 Display
*dpy
= Tk_Display(tkwin
);
281 Screen
*screen
= Tk_Screen(tkwin
);
283 char *display
= ":0"; /* XXX TODO: fix this for new x libs */
285 char *display
= dpy
->display_name
;
289 xd
&& (xd
->screen
!= screen
);
295 xd
= (struct XDisplay
*)ckalloc(sizeof (struct XDisplay
));
299 xd
->display
= (char *)ckalloc(strlen(display
) + 1);
300 xd
->tkDisplay
= ((TkWindow
*)tkwin
)->dispPtr
;
301 strcpy(xd
->display
, display
);
303 xd
->root
= RootWindowOfScreen(xd
->screen
);
305 xd
->visual
= Tk_DefaultVisual(xd
->screen
);
306 xd
->depth
= Tk_DefaultDepth(xd
->screen
);
307 xd
->colormap
= Tk_DefaultColormap(xd
->screen
);
309 xd
->color
= (xd
->depth
!= 1);
311 xd
->pixels
= (int *)ckalloc(16 * sizeof(int));
312 if (xd
->color
) { /* Color screen */
315 #define GETCOLOR(i, name) \
317 xd->pixels[i] = Rand16() & 255; \
319 if ((color = Tk_GetColor(tk_mainInterp, tkwin, \
320 None, name)) == NULL) { \
321 xd->pixels[i] = Rand16() & 255; \
324 switch (xd->depth) { \
330 if (xd->visual->red_mask == 0x7c00) { \
332 (((color->red >> (8 + 3)) & 0x1f) << (5 + 5)) | \
333 (((color->green >> (8 + 2)) & 0x1f) << (5)) | \
334 (((color->blue >> (8 + 3)) & 0x1f) << (0)); \
336 (((color->blue >> (8 + 3)) & 0x1f) << (5 + 5)) | \
337 (((color->green >> (8 + 2)) & 0x1f) << (5)) | \
338 (((color->red >> (8 + 3)) & 0x1f) << (0)); \
342 if (xd->visual->red_mask == 0xf800) { \
344 (((color->red >> (8 + 3)) & 0x1f) << (6 + 5)) | \
345 (((color->green >> (8 + 2)) & 0x3f) << (5)) | \
346 (((color->blue >> (8 + 3)) & 0x1f) << (0)); \
349 (((color->blue >> (8 + 3)) & 0x1f) << (6 + 5)) | \
350 (((color->green >> (8 + 2)) & 0x3f) << (5)) | \
351 (((color->red >> (8 + 3)) & 0x1f) << (0)); \
356 if (xd->visual->red_mask == 0xff0000) { \
358 ((color->red & 0xff) << 16) | \
359 ((color->green & 0xff) << 8) | \
360 ((color->blue & 0xff) << 0); \
363 ((color->blue & 0xff) << 16) | \
364 ((color->green & 0xff) << 8) | \
365 ((color->red & 0xff) << 0); \
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
);
378 GETCOLOR(COLOR_WHITE
, "#ffffff");
379 GETCOLOR(COLOR_BLACK
, "#000000");
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");
399 "Oh, dear. There don't seem to be enough free colors on X display \"%s\".\n",
402 "Micropolis will try to run anyway, but might look pretty weird!\n");
404 } else { /* Black and white screen */
405 int white
= WhitePixelOfScreen(xd
->screen
);
406 int black
= BlackPixelOfScreen(xd
->screen
);
408 xd
->pixels
[COLOR_WHITE
] = white
;
409 xd
->pixels
[COLOR_BLACK
] = black
;
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
;
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
);
435 { int major
, minor
, event
, error
, pixmaps
;
437 (XQueryExtension(xd
->dpy
, "MIT-SHM", /* Jeez! */
438 &major
, &event
, &error
) != True
) ||
439 (XShmQueryVersion(xd
->dpy
,
440 &major
, &minor
, &pixmaps
) != True
)) {
442 "Darn, X display \"%s\" doesn't support the shared memory extension.\n",
448 "Darn, X display \"%s\" claims to support the shared memory extension,\n",
451 "but is too lame to support shared memory pixmaps, so Micropolis will run slower.\n");
453 "Please complain to your X server vendor, %s\n",
454 XServerVendor(xd
->dpy
));
458 "Cool, I found the shared memory extension!\n");
460 "Disabled SHM, because it is currently broken!\n");
470 xd
->last_request_read
= -1;
471 xd
->big_tile_pixmap
= None
;
473 xd
->overlay_gc
= NULL
;
474 xd
->gray25_stipple
= None
;
475 xd
->gray50_stipple
= None
;
476 xd
->gray75_stipple
= None
;
477 xd
->vert_stipple
= None
;
478 xd
->horiz_stipple
= None
;
479 xd
->diag_stipple
= None
;
481 xd
->big_tile_image
= xd
->small_tile_image
= NULL
;
483 xd
->next
= XDisplays
; XDisplays
= xd
;
490 IncRefDisplay(XDisplay
*xd
)
496 DecRefDisplay(XDisplay
*xd
)
498 if ((--xd
->references
) == 0) {
499 /* I'd blow it away, but tk may still be using the display */
505 InitNewView(SimView
*view
, char *title
, int class, int w
, int h
)
510 unsigned long valuemask
= 0;
516 t
= (char *)ckalloc(strlen(title
) + 1);
523 view
->bigtiles
= view
->smalltiles
= NULL
;
525 view
->line_bytes
= 0;
526 view
->line_bytes8
= 0;
527 view
->pixel_bytes
= 0;
533 view
->skips
= view
->skip
= 0;
535 view
->map_state
= ALMAP
;
536 view
->show_editors
= 1;
537 view
->tool_showing
= 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;
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
;
562 /* This stuff was initialized in our caller (SimViewCmd) */
563 /* view->tkwin = NULL; */
564 /* view->interp = NULL; */
565 /* view->flags = 0; */
568 view
->shminfo
= NULL
;
570 view
->other_tiles
= NULL
;
572 view
->other_image
= NULL
;
573 view
->other_data
= NULL
;
575 view
->pixmap2
= None
;
576 view
->overlay_pixmap
= None
;
577 view
->overlay_valid
= 0;
578 view
->fontPtr
= NULL
;
580 view
->update_real
= view
->update_user
= view
->update_system
= 0.0;
581 view
->update_context
= 0;
583 view
->auto_going
= 0;
584 view
->auto_x_goal
= view
->auto_x_goal
= 0;
585 view
->auto_speed
= 75;
588 view
->width
= 0; view
->height
= 0;
589 view
->show_overlay
= 1;
590 view
->overlay_mode
= 0;
592 view
->x
= FindXDisplay(view
->tkwin
);
593 IncRefDisplay(view
->x
);
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
;
600 view
->type
= X_Mem_View
;
603 view
->x
->needs_swap
= !(*(unsigned char*) (&test
));
604 view
->x
->x_big_endian
= (ImageByteOrder(view
->x
->dpy
) == MSBFirst
);
608 view
->pixels
= view
->x
->pixels
;
610 if (w
== EDITOR_W
) w
= 256; /* XXX */
611 if (h
== EDITOR_H
) h
= 256; /* XXX */
613 view
->pan_x
= w
/ 2; view
->pan_y
= h
/ 2;
614 DoResizeView(view
, w
, h
);
622 DestroyView(SimView
*view
)
626 CancelRedrawView(view
);
628 for (vp
= ((view
->class == Editor_Class
) ?
629 (&sim
->editor
) : (&sim
->map
));
631 vp
= &((*vp
)->next
)) {
634 if (view
->class == Editor_Class
)
643 if (view
->title
!= NULL
) {
644 ckfree (view
->title
);
648 if (view
->pixmap
!= None
) {
649 XFreePixmap(view
->x
->dpy
, view
->pixmap
);
653 if (view
->pixmap2
!= None
) {
654 XFreePixmap(view
->x
->dpy
, view
->pixmap2
);
655 view
->pixmap2
= None
;
658 if (view
->overlay_pixmap
!= None
) {
659 XFreePixmap(view
->x
->dpy
, view
->overlay_pixmap
);
660 view
->overlay_pixmap
= None
;
663 if (view
->auto_scroll_token
) {
664 Tk_DeleteTimerHandler(view
->auto_scroll_token
);
665 view
->auto_scroll_token
= 0;
670 XShmDetach(view
->x
->dpy
, view
->shminfo
);
671 shmdt(view
->shminfo
->shmaddr
);
672 shmctl(view
->shminfo
->shmid
, IPC_RMID
, 0);
673 ckfree(view
->shminfo
);
674 view
->shminfo
= NULL
;
676 view
->image
->data
= NULL
;
678 XDestroyImage(view
->image
);
684 if (view
->image
->data
) {
685 ckfree(view
->image
->data
);
686 view
->image
->data
= NULL
;
689 XDestroyImage(view
->image
);
696 if (view
->other_image
) {
697 if (view
->other_image
->data
) {
698 ckfree(view
->other_image
->data
);
699 view
->other_image
->data
= NULL
;
701 view
->other_data
= NULL
;
702 XDestroyImage(view
->other_image
);
703 view
->other_image
= NULL
;
709 DecRefDisplay(view
->x
);
711 ckfree((char *) view
);
716 AllocPixels(int len
, unsigned char pixel
)
719 unsigned char *data
, *cp
;
721 cp
= data
= (unsigned char *)ckalloc(len
);
722 for (i
= len
; i
> 0; i
--) {
730 DoResizeView(SimView
*view
, int w
, int h
)
737 if (view
->class == Map_Class
) { /* Map_Class */
741 if (view
->pixmap2
== None
) {
743 view
->pixmap2
= XCreatePixmap(view
->x
->dpy
, view
->x
->root
,
744 w
, h
, view
->x
->depth
);
745 if (view
->pixmap2
== None
) {
747 "Sorry, Micropolis can't create a pixmap on X display \"%s\"!\n",
749 sim_exit(1); // Just sets tkMustExit and ExitReturn
754 } else { /* Editor_Class */
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
++;
761 if (resize
|| (view
->pixmap2
== None
)) {
762 if (view
->pixmap2
!= None
) {
763 XFreePixmap(view
->x
->dpy
, view
->pixmap2
);
764 view
->pixmap2
= None
;
766 view
->pixmap2
= XCreatePixmap(view
->x
->dpy
, view
->x
->root
,
767 view
->m_width
, view
->m_height
,
769 if (view
->pixmap2
== None
) {
771 "Sorry, Micropolis couldn't create a pixmap on X display \"%s\"!\n",
773 sim_exit(1); // Just sets tkMustExit and ExitReturn
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
;
784 view
->overlay_pixmap
= XCreatePixmap(view
->x
->dpy
, view
->x
->root
,
785 view
->m_width
, view
->m_height
,
787 if (view
->overlay_pixmap
== None
) {
789 "Sorry, Micropolis couldn't create another pixmap on X display \"%s\".\n",
791 sim_exit(1); // Just sets tkMustExit and ExitReturn
794 if (view
->x
->overlay_gc
== NULL
) {
795 unsigned long valuemask
= 0;
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
);
811 if (view
->type
!= X_Mem_View
) {
815 if (resize
|| (view
->image
== NULL
)) {
816 if (view
->shminfo
&& view
->image
) {
817 if (view
->pixmap
!= None
) {
818 XFreePixmap(view
->x
->dpy
, view
->pixmap
);
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
)
828 XDestroyImage(view
->image
);
833 /* XShmPixmapFormat is documented but does not exist !!! */
834 if (XShmPixmapFormat(view
->x
->dpy
) != ZPixmap
) {
836 "Darn, display \"%s\" has the wrong shared memory format.\n",
842 if (!view
->shminfo
) {
843 view
->shminfo
= (XShmSegmentInfo
*)ckalloc(sizeof (XShmSegmentInfo
));
847 XShmCreateImage(view
->x
->dpy
, view
->x
->visual
, view
->x
->depth
,
848 view
->x
->color
? ZPixmap
: XYBitmap
,
850 view
->m_width
, view
->m_height
);
852 view
->line_bytes
= view
->image
->bytes_per_line
;
854 switch (view
->x
->depth
) {
857 view
->pixel_bytes
= 0;
862 view
->pixel_bytes
= 1;
867 view
->pixel_bytes
= 2;
872 view
->pixel_bytes
= 2;
877 /* XXX: TODO: 24 and 32 bit support */
878 view
->pixel_bytes
= 4;
879 //view->pixel_bytes = 3;
884 /* XXX: TODO: 24 and 32 bit support */
885 view
->pixel_bytes
= 4;
890 view
->pixel_bytes
= 0;
896 view
->shminfo
->shmid
= shmget(IPC_PRIVATE
,
900 if (view
->shminfo
->shmid
< 0) {
903 "Darn, Micropolis can't share memory with X display \"%s\".\n",
908 view
->data
= (unsigned char *)shmat(view
->shminfo
->shmid
, 0, 0);
909 if ((int)view
->data
== -1) {
912 "Darn, Micropolis can't find any memory to share with display \"%s\".\n",
917 view
->image
->data
= (char *)view
->data
;
918 view
->shminfo
->shmaddr
= (char *)view
->data
;
919 view
->shminfo
->readOnly
= False
;
925 old
= XSetErrorHandler(CatchXError
);
928 XShmAttach(view
->x
->dpy
, view
->shminfo
);
931 "Darn, the X display \"%s\" can't access Micropolis's shared memory.\n",
936 XSync(view
->x
->dpy
, False
);
940 view
->pixmap
= XShmCreatePixmap(view
->x
->dpy
, view
->x
->root
,
941 view
->data
, view
->shminfo
,
942 view
->m_width
, view
->m_height
,
944 XSync(view
->x
->dpy
, False
);
947 (view
->pixmap
== None
)) {
949 "Darn, Micropolis couldn't get a shared memory pixmap on X display \"%s\".\n",
955 XSetErrorHandler(old
);
960 XShmDetach(view
->x
->dpy
, view
->shminfo
);
962 result
= shmdt(view
->shminfo
->shmaddr
);
963 result
= shmctl(view
->shminfo
->shmid
, IPC_RMID
, 0);
964 ckfree(view
->shminfo
);
965 view
->shminfo
= NULL
;
967 view
->image
->data
= NULL
;
969 XDestroyImage(view
->image
);
975 if (view
->x
->color
) {
976 XSetForeground(view
->x
->dpy
, view
->x
->gc
,
977 view
->pixels
[COLOR_LIGHTBROWN
]);
979 XSetForeground(view
->x
->dpy
, view
->x
->gc
,
980 view
->pixels
[COLOR_WHITE
]);
983 XFillRectangle(view
->x
->dpy
, view
->pixmap
, view
->x
->gc
,
984 0, 0, view
->m_width
, view
->m_height
);
993 "Falling back to the X network protocol on display \"%s\"...\n",
998 view
->type
= X_Wire_View
;
999 if (view
->pixmap
!= None
) {
1000 XFreePixmap(view
->x
->dpy
, view
->pixmap
);
1001 view
->pixmap
= None
;
1004 if (view
->shminfo
) {
1005 if (view
->shminfo
->shmid
>= 0) {
1006 if (view
->shminfo
->shmaddr
) {
1007 shmdt(view
->shminfo
->shmaddr
);
1009 shmctl(view
->shminfo
->shmid
, IPC_RMID
, 0);
1011 ckfree((char *)view
->shminfo
);
1012 view
->shminfo
= NULL
;
1016 view
->image
->data
= NULL
;
1017 XDestroyImage(view
->image
);
1021 view
->line_bytes
= 0;
1022 view
->pixel_bytes
= 0;
1027 if (resize
|| (view
->pixmap
== None
)) {
1028 if (view
->pixmap
!= None
) {
1029 XFreePixmap(view
->x
->dpy
, view
->pixmap
);
1030 view
->pixmap
= None
;
1032 view
->pixmap
= XCreatePixmap(view
->x
->dpy
, view
->x
->root
,
1033 view
->m_width
, view
->m_height
,
1035 if (view
->pixmap
== None
) {
1037 "Sorry, Micropolis can't create pixmap on X display \"%s\".\n",
1039 sim_exit(1); // Just sets tkMustExit and ExitReturn
1042 if (view
->x
->color
) {
1043 XSetForeground(view
->x
->dpy
, view
->x
->gc
,
1044 view
->pixels
[COLOR_LIGHTBROWN
]);
1046 XSetForeground(view
->x
->dpy
, view
->x
->gc
,
1047 view
->pixels
[COLOR_WHITE
]);
1049 XFillRectangle(view
->x
->dpy
, view
->pixmap
, view
->x
->gc
,
1050 0, 0, view
->m_width
, view
->m_height
);
1055 if (view
->class == Editor_Class
) {
1060 } else if (view
->class == Map_Class
) {
1062 if (view
->type
== X_Mem_View
) { /* Memory Map */
1064 if (view
->x
->color
) {
1066 /* Color, Shared Memory */
1068 view
->data8
= view
->data
;
1069 view
->line_bytes8
= view
->line_bytes
; /* XXX: ??? */
1071 switch (view
->x
->depth
) {
1074 view
->pixel_bytes
= 1;
1079 view
->pixel_bytes
= 2;
1084 view
->pixel_bytes
= 2;
1089 /* XXX: TODO: 24 and 32 bit support */
1090 view
->pixel_bytes
= 4;
1091 //view->pixel_bytes = 3;
1096 /* XXX: TODO: 24 and 32 bit support */
1097 view
->pixel_bytes
= 4;
1102 view
->pixel_bytes
= 0;
1110 /* Black and White, Shared Memory */
1112 if (view
->other_image
!= NULL
) {
1113 XDestroyImage(view
->other_image
);
1116 view
->line_bytes8
= view
->m_width
; /* XXX: fix depth */
1117 view
->pixel_bytes
= 0;
1120 view
->other_data
= view
->data8
=
1121 AllocPixels(view
->m_height
* view
->line_bytes8
, /* XXX: fix depth */
1122 view
->pixels
[COLOR_WHITE
]);
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 */
1130 } else { /* Wire Map */
1134 if (view
->image
!= NULL
) {
1135 XDestroyImage(view
->image
);
1139 if (view
->other_image
!= NULL
) {
1140 XDestroyImage(view
->other_image
);
1141 view
->other_image
= NULL
;
1144 if (view
->x
->color
) {
1148 switch (view
->x
->depth
) {
1151 view
->pixel_bytes
= 1;
1156 ((view
->m_width
* view
->pixel_bytes
) + 3) & (~3);
1160 view
->pixel_bytes
= 2;
1165 ((view
->m_width
* view
->pixel_bytes
) + 3) & (~3);
1169 view
->pixel_bytes
= 2;
1174 ((view
->m_width
* view
->pixel_bytes
) + 3) & (~3);
1178 view
->pixel_bytes
= 4;
1179 //view->pixel_bytes = 3;
1184 ((view
->m_width
* 4) + 3) & (~3);
1188 view
->pixel_bytes
= 4;
1193 ((view
->m_width
* 4) + 3) & (~3);
1197 assert(0); /* Unknown depth */
1207 /* Black and White, Wire */
1209 view
->pixel_bytes
= 0;
1212 (view
->m_width
+ 3) & (~3); /* XXX: handle depth */
1214 (view
->m_width
+ 7) >>3;
1221 AllocPixels(view
->m_height
* view
->line_bytes
, 0);
1223 XCreateImage(view
->x
->dpy
, view
->x
->visual
,
1225 view
->x
->color
? ZPixmap
: XYBitmap
,
1226 0, (char *)view
->data
,
1227 view
->m_width
, view
->m_height
,
1232 AllocPixels(view
->m_height
* view
->line_bytes8
, 0);
1234 XCreateImage(view
->x
->dpy
, view
->x
->visual
,
1237 0, (char *)view
->other_data
,
1238 view
->m_width
, view
->m_height
,
1242 if (view
->x
->color
) {
1243 view
->data8
= view
->data
;
1245 view
->data8
= view
->other_data
;
1252 DoPanBy(struct SimView
*view
, int dx
, int dy
)
1254 DoPanTo(view
, view
->pan_x
+ dx
, view
->pan_y
+ dy
);
1258 DoPanTo(struct SimView
*view
, int x
, int y
)
1260 if (view
->class != Editor_Class
) {
1266 if (x
> view
->i_width
) x
= view
->i_width
- 1;
1267 if (y
> view
->i_height
) y
= view
->i_height
- 1;
1268 if ((view
->pan_x
!= x
) ||
1269 (view
->pan_y
!= y
)) {
1276 /* #define DEBUG_PAN */
1278 DoAdjustPan(struct SimView
*view
)
1280 int ww2
= view
->w_width
>>1, wh2
= view
->w_height
>>1;
1281 int px
= view
->pan_x
, py
= view
->pan_y
;
1282 int last_tile_x
= view
->tile_x
, last_tile_y
= view
->tile_y
;
1283 int last_tile_width
= view
->tile_width
, last_tile_height
= view
->tile_height
;
1284 int total_width
= view
->m_width
>>4, total_height
= view
->m_height
>>4;
1285 //fprintf(stderr, "DoAdjustPan\n");
1288 printf("AdjustPan window %d %d ww2 %d wh2 %d pan %d %d\n",
1289 view
->w_width
, view
->w_height
, ww2
, wh2
, px
, py
);
1290 printf(" last tile %d %d %d %d\n",
1291 last_tile_x
, last_tile_y
, last_tile_width
, last_tile_height
);
1294 if ((view
->tile_x
= ((px
- ww2
) >>4)) < 0)
1296 if ((view
->tile_y
= ((py
- wh2
) >>4)) < 0)
1300 printf(" now tile %d %d\n", view
->tile_x
, view
->tile_y
);
1303 view
->tile_width
= ((15 + px
+ ww2
) >>4);
1304 view
->tile_height
= ((15 + py
+ wh2
) >>4);
1307 printf(" outer tile %d %d\n", view
->tile_width
, view
->tile_height
);
1310 if (view
->tile_width
> (view
->i_width
>>4))
1311 view
->tile_width
= (view
->i_width
>>4);
1312 view
->tile_width
-= view
->tile_x
;
1313 if (view
->tile_height
> (view
->i_height
>>4))
1314 view
->tile_height
= (view
->i_height
>>4);
1315 view
->tile_height
-= view
->tile_y
;
1318 printf(" tile size %d %d\n", view
->tile_width
, view
->tile_height
);
1321 if (view
->tile_width
> (view
->m_width
>>4))
1322 view
->tile_width
= (view
->m_width
>>4);
1323 if (view
->tile_height
> (view
->m_height
>>4))
1324 view
->tile_height
= (view
->m_height
>>4);
1327 printf(" clipped size %d %d\n", view
->tile_width
, view
->tile_height
);
1328 printf(" maximum size %d %d\n", view
->m_width
>>4, view
->m_height
>>4);
1331 view
->screen_x
= (ww2
- px
) + (view
->tile_x
<<4);
1332 view
->screen_y
= (wh2
- py
) + (view
->tile_y
<<4);
1333 view
->screen_width
= (view
->tile_width
<<4);
1334 view
->screen_height
= (view
->tile_height
<<4);
1337 printf(" screen %d %d %d %d\n",
1338 view
->screen_x
, view
->screen_y
,
1339 view
->screen_width
, view
->screen_height
);
1342 view
->overlay_mode
= 0;
1345 if (SimSpeed
== 0) {
1346 EventuallyRedrawView(view
);
1348 /* InvalidateEditors(); */
1349 if (view
->show_me
) {
1352 /* FixMicropolisTimer(); */
1354 { int dx
= last_tile_x
- view
->tile_x
,
1355 dy
= last_tile_y
- view
->tile_y
;
1356 short **want
= view
->other_tiles
,
1357 **have
= view
->tiles
;
1360 printf("scrolling %d %d\n", dx
, dy
);
1363 if ((dx
!= 0) || (dy
!= 0)) {
1365 width
= view
->tile_width
,
1366 height
= view
->tile_height
;
1368 for (col
= 0; col
< width
; col
++)
1369 memcpy(want
[col
], have
[col
], (height
* sizeof(short)));
1371 for (col
= 0; col
< total_width
; col
++) {
1373 for (row
= 0; row
< total_height
; row
++) {
1375 if ((x
>= 0) && (x
< width
) &&
1376 (y
>= 0) && (y
< height
)) {
1377 have
[col
][row
] = want
[x
][y
];
1379 have
[col
][row
] = -1;
1384 XCopyArea(view
->x
->dpy
, view
->pixmap
, view
->pixmap
, view
->x
->gc
,
1385 0, 0, view
->tile_width
<<4, view
->tile_height
<<4,
1388 if (view
->type
== X_Mem_View
) {
1389 XSync(view
->x
->dpy
, False
);
1396 AllocTiles(SimView
*view
)
1399 short **have
, **want
;
1400 int w
= view
->m_width
/ 16, h
= view
->m_height
/ 16;
1401 int n
= (w
+ 1) * sizeof (short *);
1406 have
= view
->tiles
=
1407 (short **)ckalloc(n
);
1409 want
= view
->other_tiles
=
1410 (short **)ckalloc(n
);
1412 have
[w
] = want
[w
] = NULL
;
1414 n
= h
* sizeof(short);
1415 for (col
= 0; col
< w
; col
++) {
1417 have
[col
] = (short *)ckalloc(n
);
1418 want
[col
] = (short *)ckalloc(n
);
1419 for (row
= 0; row
< h
; row
++) {
1420 have
[col
][row
] = -1;
1421 want
[col
][row
] = -1;
1427 FreeTiles(SimView
*view
)
1431 for (col
= 0; view
->tiles
[col
] != NULL
; col
++) {
1432 ckfree ((char *)view
->tiles
[col
]);
1433 ckfree ((char *)view
->other_tiles
[col
]);
1435 ckfree ((char *)view
->tiles
);
1437 ckfree ((char *)view
->other_tiles
);
1438 view
->other_tiles
= NULL
;
1442 #define POINT_BATCH 32
1447 /* XXX: todo: ink locking so someone doesn't erase ink that's being drawn */
1456 OldInk
= OldInk
->next
;
1458 ink
= (Ink
*)ckalloc(sizeof(Ink
));
1459 ink
->maxlength
= POINT_BATCH
;
1460 ink
->points
= (XPoint
*)ckalloc(POINT_BATCH
* sizeof(XPoint
));
1463 ink
->color
= COLOR_WHITE
;
1465 ink
->left
= ink
->right
= ink
->top
= ink
->bottom
=
1466 ink
->last_x
= ink
->last_y
= -1;
1478 StartInk(Ink
*ink
, int x
, int y
)
1481 ink
->left
= ink
->right
= ink
->last_x
= ink
->points
[0].x
= x
;
1482 ink
->top
= ink
->bottom
= ink
->last_y
= ink
->points
[0].y
= y
;
1486 AddInk(Ink
*ink
, int x
, int y
)
1488 int dx
= x
- ink
->last_x
;
1489 int dy
= y
- ink
->last_y
;
1491 if ((dx
!= 0) || (dy
!= 0)) {
1493 if (ink->length > 1) {
1495 (ink->points[ink->length - 1].x == 0) &&
1496 ((ink->points[ink->length - 1].y < 0) ?
1497 (dy < 0) : (dy > 0))) {
1498 ink->points[ink->length - 1].y += dy;
1500 } else if ((dy == 0) &&
1501 (ink->points[ink->length - 1].y == 0) &&
1502 ((ink->points[ink->length - 1].x < 0) ?
1503 (dx < 0) : (dx > 0))) {
1504 ink->points[ink->length - 1].x += dx;
1510 if (ink
->length
>= ink
->maxlength
) {
1511 ink
->maxlength
+= POINT_BATCH
;
1512 ink
->points
= (XPoint
*)realloc((void *)ink
->points
,
1513 ink
->maxlength
* sizeof(XPoint
));
1515 ink
->points
[ink
->length
].x
= dx
;
1516 ink
->points
[ink
->length
].y
= dy
;
1526 if (y
> ink
->bottom
)
1529 { int left
, right
, top
, bottom
;
1532 if (ink
->last_x
< x
) { left
= ink
->last_x
; right
= x
; }
1533 else { left
= x
; right
= ink
->last_x
; }
1534 if (ink
->last_y
< y
) { top
= ink
->last_y
; bottom
= y
; }
1535 else { top
= y
; bottom
= ink
->last_y
; }
1537 left
-= 5; right
+= 5; top
-= 5; bottom
+= 5;
1539 for (view
= sim
->editor
; view
!= NULL
; view
= view
->next
) {
1542 if ((right
>= (vleft
= view
->pan_x
- (view
->w_width
/ 2))) &&
1543 (left
<= vleft
+ view
->w_width
) &&
1544 (bottom
>= (vtop
= view
->pan_y
- (view
->w_height
/ 2))) &&
1545 (top
<= vtop
+ view
->w_height
)) {
1546 /* XXX: do studly incremental update instead */
1547 view
->overlay_mode
= 0;
1548 EventuallyRedrawView(view
);
1552 ink
->last_x
= x
; ink
->last_y
= y
;
1561 while (sim
->overlay
) {
1563 sim
->overlay
= ink
->next
;