]>
Commit | Line | Data |
---|---|---|
6a5fa4e0 MG |
1 | /* w_cam.c |
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 | #ifdef CAM | |
66 | ||
67 | ||
68 | Tk_ConfigSpec SimCamConfigSpecs[] = { | |
69 | {TK_CONFIG_PIXELS, "-width", "width", "Width", | |
70 | 0, Tk_Offset(SimCam, w_width), 0}, | |
71 | {TK_CONFIG_PIXELS, "-height", "height", "Height", | |
72 | 0, Tk_Offset(SimCam, w_height), 0}, | |
73 | {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, | |
74 | (char *) NULL, 0, 0} | |
75 | }; | |
76 | ||
77 | ||
78 | Tk_ConfigSpec CamConfigSpecs[] = { | |
79 | {TK_CONFIG_PIXELS, "-wrap", "wrap", "Wrap", | |
80 | 0, Tk_Offset(Cam, wrap), 0}, | |
81 | {TK_CONFIG_PIXELS, "-steps", "steps", "Steps", | |
82 | 0, Tk_Offset(Cam, steps), 0}, | |
83 | {TK_CONFIG_PIXELS, "-frob", "frob", "Frob", | |
84 | 0, Tk_Offset(Cam, frob), 0}, | |
85 | {TK_CONFIG_PIXELS, "-x", "x", "X", | |
86 | 0, Tk_Offset(Cam, x), 0}, | |
87 | {TK_CONFIG_PIXELS, "-y", "y", "Y", | |
88 | 0, Tk_Offset(Cam, y), 0}, | |
89 | {TK_CONFIG_PIXELS, "-width", "width", "Width", | |
90 | 0, Tk_Offset(Cam, width), 0}, | |
91 | {TK_CONFIG_PIXELS, "-height", "height", "Height", | |
92 | 0, Tk_Offset(Cam, height), 0}, | |
93 | {TK_CONFIG_PIXELS, "-dx", "dx", "Dx", | |
94 | 0, Tk_Offset(Cam, dx), 0}, | |
95 | {TK_CONFIG_PIXELS, "-dy", "dy", "Dy", | |
96 | 0, Tk_Offset(Cam, dy), 0}, | |
97 | {TK_CONFIG_PIXELS, "-gx", "gx", "Gx", | |
98 | 0, Tk_Offset(Cam, gx), 0}, | |
99 | {TK_CONFIG_PIXELS, "-gy", "gy", "Gy", | |
100 | 0, Tk_Offset(Cam, gy), 0}, | |
101 | {TK_CONFIG_PIXELS, "-dragging", "dragging", "Dragging", | |
102 | 0, Tk_Offset(Cam, dragging), 0}, | |
103 | {TK_CONFIG_PIXELS, "-setx", "setx", "SetX", | |
104 | "-1", Tk_Offset(Cam, set_x), 0}, | |
105 | {TK_CONFIG_PIXELS, "-sety", "sety", "SetY", | |
106 | "-1", Tk_Offset(Cam, set_y), 0}, | |
107 | {TK_CONFIG_PIXELS, "-setwidth", "setwidth", "SetWidth", | |
108 | "-1", Tk_Offset(Cam, set_width), 0}, | |
109 | {TK_CONFIG_PIXELS, "-setheight", "setheight", "SetHeight", | |
110 | "-1", Tk_Offset(Cam, set_height), 0}, | |
111 | {TK_CONFIG_PIXELS, "-setx0", "setx0", "SetX0", | |
112 | "-1", Tk_Offset(Cam, set_x0), 0}, | |
113 | {TK_CONFIG_PIXELS, "-sety0", "sety0", "SetY0", | |
114 | "-1", Tk_Offset(Cam, set_y0), 0}, | |
115 | {TK_CONFIG_PIXELS, "-setx1", "setx1", "SetX1", | |
116 | "-1", Tk_Offset(Cam, set_x1), 0}, | |
117 | {TK_CONFIG_PIXELS, "-sety1", "sety1", "SetY1", | |
118 | "-1", Tk_Offset(Cam, set_y1), 0}, | |
119 | {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, | |
120 | (char *) NULL, 0, 0} | |
121 | }; | |
122 | ||
123 | ||
124 | Tcl_HashTable CamCmds; | |
125 | ||
126 | int next_cam_id = 1; | |
127 | ||
128 | ||
129 | static void | |
130 | DisplaySimCam(ClientData clientData) | |
131 | { | |
132 | SimCam *scam = (SimCam *) clientData; | |
133 | Tk_Window tkwin = scam->tkwin; | |
134 | Pixmap pm = None; | |
135 | Drawable d; | |
136 | ||
137 | scam->flags &= ~VIEW_REDRAW_PENDING; | |
138 | if (scam->visible && (tkwin != NULL) && Tk_IsMapped(tkwin)) { | |
139 | DoUpdateCam(scam); | |
140 | } | |
141 | } | |
142 | ||
143 | ||
144 | void | |
145 | DestroyCam(SimCam *scam, Cam *cam) | |
146 | { | |
147 | Cam **cp; | |
148 | ||
149 | for (cp = &scam->cam_list; | |
150 | (*cp) != NULL; | |
151 | cp = &((*cp)->next)) { | |
152 | if ((*cp) == cam) { | |
153 | (*cp) = cam->next; | |
154 | scam->cam_count--; | |
155 | if (cam->front != NULL) { | |
156 | ckfree(cam->front); | |
157 | } | |
158 | if (cam->back != NULL) { | |
159 | if (cam->back->mem != NULL) { | |
160 | ckfree(cam->back->mem); | |
161 | } | |
162 | ckfree(cam->back); | |
163 | } | |
164 | if (cam->rule != NULL) { | |
165 | ckfree(cam->rule); | |
166 | } | |
167 | if (cam->name != NULL) { | |
168 | ckfree(cam->name); | |
169 | } | |
170 | ckfree(cam); | |
171 | break; | |
172 | } | |
173 | } | |
174 | } | |
175 | ||
176 | ||
177 | void | |
178 | DestroyScam(ClientData cdata) | |
179 | { | |
180 | SimCam *scam = (SimCam *)cdata; | |
181 | SimCam **cp; | |
182 | ||
183 | CancelRedrawView(scam); | |
184 | ||
185 | while (scam->cam_list) { | |
186 | DestroyCam(scam, scam->cam_list); | |
187 | } | |
188 | ||
189 | for (cp = &sim->scam; | |
190 | (*cp) != NULL; | |
191 | cp = &((*cp)->next)) { | |
192 | if ((*cp) == scam) { | |
193 | (*cp) = scam->next; | |
194 | sim->scams--; | |
195 | break; | |
196 | } | |
197 | } | |
198 | ||
199 | if (scam->shminfo != NULL) { | |
200 | XShmDetach(scam->x->dpy, scam->shminfo); | |
201 | shmdt(scam->shminfo->shmaddr); | |
202 | shmctl(scam->shminfo->shmid, IPC_RMID, 0); | |
203 | ckfree(scam->shminfo); | |
204 | scam->shminfo = NULL; | |
205 | if (scam->image) { | |
206 | scam->image->data = NULL; | |
207 | scam->data = NULL; | |
208 | XDestroyImage(scam->image); | |
209 | scam->image = NULL; | |
210 | } | |
211 | } else { | |
212 | if (scam->image) { | |
213 | if (scam->image->data) { | |
214 | ckfree(scam->image->data); | |
215 | scam->image->data = NULL; | |
216 | } | |
217 | scam->data = NULL; | |
218 | XDestroyImage(scam->image); | |
219 | scam->image = NULL; | |
220 | } | |
221 | } | |
222 | ||
223 | DecRefDisplay(scam->x); | |
224 | ||
225 | ckfree((char *) scam); | |
226 | } | |
227 | ||
228 | ||
229 | void | |
230 | CamEventProc(ClientData clientData, XEvent *eventPtr) | |
231 | { | |
232 | SimCam *scam = (SimCam *) clientData; | |
233 | ||
234 | if ((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) { | |
235 | scam->visible = 1; | |
236 | EventuallyRedrawCam(scam); | |
237 | } else if (eventPtr->type == MapNotify) { | |
238 | scam->visible = 1; | |
239 | } else if (eventPtr->type == UnmapNotify) { | |
240 | scam->visible = 0; | |
241 | } else if (eventPtr->type == VisibilityNotify) { | |
242 | if (eventPtr->xvisibility.state == VisibilityFullyObscured) | |
243 | scam->visible = 0; | |
244 | else | |
245 | scam->visible = 1; | |
246 | } else if (eventPtr->type == ConfigureNotify) { | |
247 | DoResizeCam(scam, | |
248 | eventPtr->xconfigure.width, | |
249 | eventPtr->xconfigure.height); | |
250 | EventuallyRedrawCam(scam); | |
251 | } else if (eventPtr->type == DestroyNotify) { | |
252 | Tcl_DeleteCommand(scam->interp, Tk_PathName(scam->tkwin)); | |
253 | scam->tkwin = NULL; | |
254 | if (scam->flags & VIEW_REDRAW_PENDING) { | |
255 | Tk_CancelIdleCall(DisplaySimCam, (ClientData) scam); | |
256 | } | |
257 | Tk_EventuallyFree((ClientData) scam, DestroyScam); | |
258 | } | |
259 | } | |
260 | ||
261 | ||
262 | int | |
263 | DoCamCmd(CLIENT_ARGS) | |
264 | { | |
265 | SimCam *scam = (SimCam *) clientData; | |
266 | Tcl_HashEntry *ent; | |
267 | int result = TCL_OK; | |
268 | int (*cmd)(); | |
269 | ||
270 | if (argc < 2) { | |
271 | return TCL_ERROR; | |
272 | } | |
273 | ||
274 | if (ent = Tcl_FindHashEntry(&CamCmds, argv[1])) { | |
275 | cmd = (int (*)())ent->clientData; | |
276 | Tk_Preserve((ClientData) scam); | |
277 | result = cmd(scam, interp, argc, argv); | |
278 | Tk_Release((ClientData) scam); | |
279 | } else { | |
280 | Tcl_AppendResult(interp, "unknown command name: \"", | |
281 | argv[0], " ", argv[1], "\".", (char *) NULL); | |
282 | result = TCL_ERROR; | |
283 | } | |
284 | return result; | |
285 | } | |
286 | ||
287 | ||
288 | int | |
289 | CamCmd(CLIENT_ARGS) | |
290 | { | |
291 | Tk_Window tkwin = (Tk_Window) clientData; | |
292 | SimCam *scam; | |
293 | ||
294 | if (argc < 2) { | |
295 | Tcl_AppendResult(interp, "wrong # args: should be \"", | |
296 | argv[0], " pathName ?options?\"", (char *) NULL); | |
297 | return TCL_ERROR; | |
298 | } | |
299 | ||
300 | tkwin = Tk_CreateWindowFromPath(interp, tkwin, | |
301 | argv[1], (char *) NULL); | |
302 | if (tkwin == NULL) { | |
303 | return TCL_ERROR; | |
304 | } | |
305 | ||
306 | scam = (SimCam *)ckalloc(sizeof (SimCam)); | |
307 | ||
308 | scam->w_x = 0; | |
309 | scam->w_y = 0; | |
310 | scam->w_width = 0; | |
311 | scam->w_height = 0; | |
312 | scam->visible = 0; | |
313 | scam->invalid = 1; | |
314 | scam->skips = 0; | |
315 | scam->skip = 0; | |
316 | scam->tkwin = tkwin; | |
317 | scam->interp = interp; | |
318 | scam->flags = 0; | |
319 | scam->x = NULL; | |
320 | scam->image = NULL; | |
321 | scam->shminfo = NULL; | |
322 | scam->line_bytes = 0; | |
323 | scam->data = NULL; | |
324 | scam->cam_count = 0; | |
325 | scam->cam_list = NULL; | |
326 | ||
327 | Tk_SetClass(scam->tkwin, "Cam"); | |
328 | ||
329 | Tk_CreateEventHandler(scam->tkwin, | |
330 | VisibilityChangeMask | | |
331 | ExposureMask | | |
332 | StructureNotifyMask | | |
333 | EnterWindowMask | | |
334 | LeaveWindowMask | | |
335 | PointerMotionMask, | |
336 | CamEventProc, (ClientData) scam); | |
337 | Tcl_CreateCommand(interp, Tk_PathName(scam->tkwin), | |
338 | DoCamCmd, (ClientData) scam, (void (*)()) NULL); | |
339 | ||
340 | Tk_MakeWindowExist(scam->tkwin); | |
341 | ||
342 | if (getenv("XSYNCHRONIZE") != NULL) { | |
343 | XSynchronize(Tk_Display(tkwin), 1); | |
344 | } | |
345 | ||
346 | InitNewCam(scam); | |
347 | DoNewCam(scam); | |
348 | ||
349 | if (ConfigureCam(interp, scam, argc-2, argv+2, 0) != TCL_OK) { | |
350 | /* XXX: destroy scam */ | |
351 | Tk_DestroyWindow(scam->tkwin); | |
352 | return TCL_ERROR; | |
353 | } | |
354 | ||
355 | scam->invalid = 1; | |
356 | ||
357 | interp->result = Tk_PathName(scam->tkwin); | |
358 | return TCL_OK; | |
359 | } | |
360 | ||
361 | ||
362 | int | |
363 | ConfigureCam(Tcl_Interp *interp, SimCam *scam, | |
364 | int argc, char **argv, int flags) | |
365 | { | |
366 | if (Tk_ConfigureWidget(interp, scam->tkwin, SimCamConfigSpecs, | |
367 | argc, argv, (char *) scam, flags) != TCL_OK) { | |
368 | return TCL_ERROR; | |
369 | } | |
370 | ||
371 | if (scam->w_width || scam->w_height) { | |
372 | Tk_GeometryRequest(scam->tkwin, scam->w_width, scam->w_height); | |
373 | } | |
374 | ||
375 | EventuallyRedrawCam(scam); | |
376 | ||
377 | return TCL_OK; | |
378 | } | |
379 | ||
380 | ||
381 | EventuallyRedrawCam(SimCam *scam) | |
382 | { | |
383 | if (!(scam->flags & VIEW_REDRAW_PENDING)) { | |
384 | Tk_DoWhenIdle(DisplaySimCam, (ClientData) scam); | |
385 | scam->flags |= VIEW_REDRAW_PENDING; | |
386 | } | |
387 | } | |
388 | ||
389 | ||
390 | CamCmdconfigure(CAM_ARGS) | |
391 | { | |
392 | int result = TCL_OK; | |
393 | ||
394 | if (argc == 2) { | |
395 | result = Tk_ConfigureInfo(interp, scam->tkwin, SimCamConfigSpecs, | |
396 | (char *) scam, (char *) NULL, 0); | |
397 | } else if (argc == 3) { | |
398 | result = Tk_ConfigureInfo(interp, scam->tkwin, SimCamConfigSpecs, | |
399 | (char *) scam, argv[2], 0); | |
400 | } else { | |
401 | result = ConfigureCam(interp, scam, argc-2, argv+2, | |
402 | TK_CONFIG_ARGV_ONLY); | |
403 | } | |
404 | return result; | |
405 | } | |
406 | ||
407 | ||
408 | CamCmdposition(CAM_ARGS) | |
409 | { | |
410 | if ((argc != 2) && (argc != 4)) { | |
411 | return TCL_ERROR; | |
412 | } | |
413 | if (argc == 4) { | |
414 | int x, y; | |
415 | ||
416 | if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK) | |
417 | || (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) { | |
418 | return TCL_ERROR; | |
419 | } | |
420 | scam->w_x = x; | |
421 | scam->w_y = y; | |
422 | } | |
423 | sprintf(interp->result, "%d %d", scam->w_x, scam->w_y); | |
424 | return TCL_OK; | |
425 | } | |
426 | ||
427 | ||
428 | CamCmdsize(CAM_ARGS) | |
429 | { | |
430 | if ((argc != 2) && (argc != 4)) { | |
431 | return TCL_ERROR; | |
432 | } | |
433 | if (argc == 4) { | |
434 | int w, h; | |
435 | ||
436 | if (Tcl_GetInt(interp, argv[2], &w) != TCL_OK) { | |
437 | return TCL_ERROR; | |
438 | } | |
439 | if (Tcl_GetInt(interp, argv[3], &h) != TCL_OK) { | |
440 | return TCL_ERROR; | |
441 | } | |
442 | scam->w_width = w; | |
443 | scam->w_height = h; | |
444 | } | |
445 | sprintf(interp->result, "%d %d", scam->w_width, scam->w_height); | |
446 | return TCL_OK; | |
447 | } | |
448 | ||
449 | ||
450 | CamCmdVisible(CAM_ARGS) | |
451 | { | |
452 | int visible; | |
453 | ||
454 | if ((argc != 2) && (argc != 3)) { | |
455 | return TCL_ERROR; | |
456 | } | |
457 | ||
458 | if (argc == 3) { | |
459 | if ((Tcl_GetInt(interp, argv[2], &visible) != TCL_OK) || | |
460 | (visible < 0) || (visible > 1)) { | |
461 | return TCL_ERROR; | |
462 | } | |
463 | ||
464 | visible = visible && Tk_IsMapped(scam->tkwin); | |
465 | scam->visible = visible; | |
466 | } | |
467 | ||
468 | sprintf(interp->result, "%d", scam->visible); | |
469 | return TCL_OK; | |
470 | } | |
471 | ||
472 | ||
473 | CamCmdStoreColor(CAM_ARGS) | |
474 | { | |
475 | int index, r, g, b, err; | |
476 | XColor color; | |
477 | ||
478 | if (argc != 6) { | |
479 | return TCL_ERROR; | |
480 | } | |
481 | ||
482 | if ((Tcl_GetInt(interp, argv[2], &index) != TCL_OK) || | |
483 | (Tcl_GetInt(interp, argv[2], &r) != TCL_OK) || | |
484 | (Tcl_GetInt(interp, argv[2], &g) != TCL_OK) || | |
485 | (Tcl_GetInt(interp, argv[2], &b) != TCL_OK)) { | |
486 | return TCL_ERROR; | |
487 | } | |
488 | ||
489 | color.pixel = index; | |
490 | color.red = r; | |
491 | color.green = g; | |
492 | color.blue = b; | |
493 | color.flags = DoRed | DoGreen | DoBlue; | |
494 | err = XStoreColor(scam->x->dpy, scam->x->colormap, &color); | |
495 | ||
496 | sprintf(interp->result, "%d", err); | |
497 | return TCL_OK; | |
498 | } | |
499 | ||
500 | ||
501 | CamCmdNewCam(CAM_ARGS) | |
502 | { | |
503 | Cam *cam; | |
504 | char *name; | |
505 | char *rule_name = NULL; | |
506 | int rule_number = 0; | |
507 | int x, y, w, h; | |
508 | ||
509 | if (argc < 8) { | |
510 | return TCL_ERROR; | |
511 | } | |
512 | ||
513 | name = argv[2]; | |
514 | ||
515 | if ((Tcl_GetInt(interp, argv[3], &rule_number) != TCL_OK) || | |
516 | (rule_number == 0)) { | |
517 | rule_name = argv[3]; | |
518 | } | |
519 | ||
520 | if ((Tcl_GetInt(interp, argv[4], &x) != TCL_OK) || | |
521 | (Tcl_GetInt(interp, argv[5], &y) != TCL_OK) || | |
522 | (Tcl_GetInt(interp, argv[6], &w) != TCL_OK) || | |
523 | (Tcl_GetInt(interp, argv[7], &h) != TCL_OK)) { | |
524 | return TCL_ERROR; | |
525 | } | |
526 | ||
527 | cam = (Cam *)find_cam_by_name(scam, name); | |
528 | ||
529 | if (cam != NULL) { | |
530 | DestroyCam(scam, cam); | |
531 | } | |
532 | ||
533 | cam = (Cam *)new_cam(scam, x, y, w, h, 0, 0, NULL); | |
534 | cam->name = (char *)malloc(strlen(name) + 1); | |
535 | strcpy(cam->name, name); | |
536 | ||
537 | if (rule_name != NULL) { | |
538 | cam_load_rule(cam, rule_name); | |
539 | } else { | |
540 | cam_set_neighborhood(cam, rule_number); | |
541 | } | |
542 | ||
543 | return Tk_ConfigureWidget(interp, scam->tkwin, CamConfigSpecs, | |
544 | argc - 8, argv + 8, (char *) cam, 0); | |
545 | } | |
546 | ||
547 | ||
548 | CamCmdDeleteCam(CAM_ARGS) | |
549 | { | |
550 | Cam *cam; | |
551 | char *name; | |
552 | ||
553 | if (argc != 3) { | |
554 | return TCL_ERROR; | |
555 | } | |
556 | ||
557 | name = argv[2]; | |
558 | ||
559 | cam = (Cam *)find_cam_by_name(scam, name); | |
560 | ||
561 | if (cam != NULL) { | |
562 | DestroyCam(scam, cam); | |
563 | } | |
564 | ||
565 | return TCL_OK; | |
566 | } | |
567 | ||
568 | ||
569 | CamCmdRandomizeCam(CAM_ARGS) | |
570 | { | |
571 | Cam *cam; | |
572 | char *name; | |
573 | ||
574 | if (argc != 3) { | |
575 | return TCL_ERROR; | |
576 | } | |
577 | ||
578 | name = argv[2]; | |
579 | ||
580 | cam = (Cam *)find_cam_by_name(scam, name); | |
581 | ||
582 | if (cam != NULL) { | |
583 | cam_randomize(cam); | |
584 | } | |
585 | ||
586 | return TCL_OK; | |
587 | } | |
588 | ||
589 | ||
590 | CamCmdConfigCam(CAM_ARGS) | |
591 | { | |
592 | Cam *cam; | |
593 | int result = TCL_OK; | |
594 | ||
595 | if (argc < 3) { | |
596 | return TCL_ERROR; | |
597 | } | |
598 | ||
599 | cam = (Cam *)find_cam_by_name(scam, argv[2]); | |
600 | ||
601 | if (cam == NULL) { | |
602 | return TCL_ERROR; | |
603 | } | |
604 | ||
605 | if (argc == 3) { | |
606 | result = Tk_ConfigureInfo(interp, scam->tkwin, CamConfigSpecs, | |
607 | (char *) cam, (char *) NULL, 0); | |
608 | } else if (argc == 4) { | |
609 | result = Tk_ConfigureInfo(interp, scam->tkwin, CamConfigSpecs, | |
610 | (char *) cam, argv[3], 0); | |
611 | } else { | |
612 | result = Tk_ConfigureWidget(interp, scam->tkwin, CamConfigSpecs, | |
613 | argc - 3, argv + 3, (char *) cam, 0); | |
614 | } | |
615 | ||
616 | return result; | |
617 | } | |
618 | ||
619 | ||
620 | CamCmdFindCam(CAM_ARGS) | |
621 | { | |
622 | Cam *cam; | |
623 | int x, y; | |
624 | ||
625 | if (argc != 4) { | |
626 | return TCL_ERROR; | |
627 | } | |
628 | ||
629 | if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK) || | |
630 | (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) { | |
631 | return TCL_ERROR; | |
632 | } | |
633 | ||
634 | cam = (Cam *)find_cam(scam, x, y); | |
635 | sprintf(interp->result, "%s", (cam == NULL) ? "" : cam->name); | |
636 | ||
637 | return TCL_OK; | |
638 | } | |
639 | ||
640 | ||
641 | CamCmdFindSomeCam(CAM_ARGS) | |
642 | { | |
643 | Cam *cam; | |
644 | int x, y; | |
645 | ||
646 | if (argc != 4) { | |
647 | return TCL_ERROR; | |
648 | } | |
649 | ||
650 | if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK) || | |
651 | (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) { | |
652 | return TCL_ERROR; | |
653 | } | |
654 | ||
655 | cam = (Cam *)find_cam(scam, x, y); | |
656 | if (cam == NULL) { | |
657 | cam = scam->cam_list; | |
658 | } | |
659 | ||
660 | sprintf(interp->result, "%s", (cam == NULL) ? "" : cam->name); | |
661 | ||
662 | return TCL_OK; | |
663 | } | |
664 | ||
665 | /*************************************************************************/ | |
666 | ||
667 | InitNewCam(SimCam *scam) | |
668 | { | |
669 | scam->x = (XDisplay *)FindXDisplay(scam->tkwin); | |
670 | IncRefDisplay(scam->x); | |
671 | ||
672 | DoResizeCam(scam, 512, 512); | |
673 | ||
674 | init_scam(scam); | |
675 | } | |
676 | ||
677 | ||
678 | DoResizeCam(SimCam *scam, int w, int h) | |
679 | { | |
680 | Cam *cam; | |
681 | ||
682 | for (cam = scam->cam_list; cam != NULL; cam = cam->next) { | |
683 | if (cam->front->width > w) w = cam->front->width; | |
684 | if (cam->front->height > h) h = cam->front->height; | |
685 | } | |
686 | ||
687 | scam->w_width = w; | |
688 | scam->w_height = h; | |
689 | ||
690 | if (scam->shminfo != NULL) { | |
691 | XShmDetach(scam->x->dpy, scam->shminfo); | |
692 | shmdt(scam->shminfo->shmaddr); | |
693 | shmctl(scam->shminfo->shmid, IPC_RMID, 0); | |
694 | ckfree(scam->shminfo); | |
695 | scam->shminfo = NULL; | |
696 | if (scam->image) { | |
697 | scam->image->data = NULL; | |
698 | scam->data = NULL; | |
699 | XDestroyImage(scam->image); | |
700 | scam->image = NULL; | |
701 | } | |
702 | } else { | |
703 | if (scam->image) { | |
704 | if (scam->image->data) { | |
705 | ckfree(scam->image->data); | |
706 | scam->image->data = NULL; | |
707 | } | |
708 | scam->data = NULL; | |
709 | XDestroyImage(scam->image); | |
710 | scam->image = NULL; | |
711 | } | |
712 | } | |
713 | ||
714 | if (scam->x->shared) { | |
715 | scam->shminfo = (XShmSegmentInfo *)ckalloc(sizeof (XShmSegmentInfo)); | |
716 | ||
717 | scam->image = | |
718 | XShmCreateImage(scam->x->dpy, scam->x->visual, scam->x->depth, | |
719 | scam->x->color ? ZPixmap : XYBitmap, | |
720 | NULL, scam->shminfo, | |
721 | scam->w_width, scam->w_height); | |
722 | ||
723 | scam->line_bytes = scam->image->bytes_per_line; | |
724 | scam->shminfo->readOnly = False; | |
725 | scam->shminfo->shmid = shmget(IPC_PRIVATE, | |
726 | (scam->line_bytes * | |
727 | scam->w_height), | |
728 | (IPC_CREAT | 0777)); | |
729 | if (scam->shminfo->shmid < 0) { | |
730 | perror("shmget"); | |
731 | fprintf(stderr, | |
732 | "Drat, Micropolis can't share memory with X display \"%s\".\n", | |
733 | scam->x->display); | |
734 | goto FALL_BACK; | |
735 | } | |
736 | ||
737 | scam->data = (unsigned char *)shmat(scam->shminfo->shmid, 0, 0); | |
738 | scam->image->data = (char *)scam->data; | |
739 | if ((int)scam->data == -1) { | |
740 | perror("shmat"); | |
741 | fprintf(stderr, | |
742 | "Drat, Micropolis can't find any memory to share with display \"%s\".\n", | |
743 | scam->x->display); | |
744 | goto FALL_BACK; | |
745 | } | |
746 | ||
747 | scam->shminfo->shmaddr = (char *)scam->data; | |
748 | scam->shminfo->readOnly = False; | |
749 | ||
750 | ||
751 | { int (*old)(); | |
752 | int CatchXError(); | |
753 | ||
754 | GotXError = 0; | |
755 | old = XSetErrorHandler(CatchXError); | |
756 | ||
757 | if (XShmAttach(scam->x->dpy, scam->shminfo) == 0) { | |
758 | fprintf(stderr, | |
759 | "Drat, the X display \"%s\" can't access Micropolis's shared memory.\n", | |
760 | scam->x->display); | |
761 | GotXError = 1; | |
762 | } | |
763 | ||
764 | XSync(scam->x->dpy, False); | |
765 | ||
766 | XSetErrorHandler(old); | |
767 | ||
768 | if (GotXError) { | |
769 | goto FALL_BACK; | |
770 | } | |
771 | } | |
772 | } else { | |
773 | goto SPRING_FORWARD; | |
774 | FALL_BACK: | |
775 | fprintf(stderr, | |
776 | "Falling back to the X network protocol on display \"%s\"...\n", | |
777 | scam->x->display); | |
778 | SPRING_FORWARD: | |
779 | scam->x->shared = 0; | |
780 | if (scam->shminfo) { | |
781 | if (scam->shminfo->shmid >= 0) { | |
782 | if (scam->shminfo->shmaddr) { | |
783 | shmdt(scam->shminfo->shmaddr); | |
784 | } | |
785 | shmctl(scam->shminfo->shmid, IPC_RMID, 0); | |
786 | } | |
787 | ckfree((char *)scam->shminfo); | |
788 | scam->shminfo = NULL; | |
789 | } | |
790 | if (scam->image) { | |
791 | scam->image->data = NULL; | |
792 | XDestroyImage(scam->image); | |
793 | scam->image = NULL; | |
794 | } | |
795 | scam->data = NULL; | |
796 | scam->line_bytes = scam->w_width; | |
797 | scam->data = (Byte *)ckalloc(scam->line_bytes * scam->w_height); | |
798 | scam->image = | |
799 | XCreateImage(scam->x->dpy, scam->x->visual, | |
800 | scam->x->depth, | |
801 | scam->x->color ? ZPixmap : XYBitmap, | |
802 | 0, (char *)scam->data, | |
803 | scam->w_width, scam->w_height, | |
804 | 8, scam->line_bytes); /* XXX: handle other depths */ | |
805 | } | |
806 | ||
807 | for (cam = scam->cam_list; cam != NULL; cam = cam->next) { | |
808 | if (cam->x + cam->front->width > scam->w_width) { | |
809 | cam->x = scam->w_width - cam->front->width; | |
810 | } | |
811 | if (cam->y + cam->front->height > scam->w_height) { | |
812 | cam->y = scam->w_height - cam->front->height; | |
813 | } | |
814 | cam->front->line_bytes = scam->line_bytes; | |
815 | cam->front->mem = /* XXX: handle other depths */ | |
816 | (Byte *)scam->data + cam->x + (scam->line_bytes * cam->y); | |
817 | } | |
818 | } | |
819 | ||
820 | ||
821 | DoNewCam(SimCam *scam) | |
822 | { | |
823 | sim->scams++; scam->next = sim->scam; sim->scam = scam; | |
824 | scam->invalid = 1; | |
825 | } | |
826 | ||
827 | ||
828 | DoUpdateCam(SimCam *scam) | |
829 | { | |
830 | if (!scam->visible) { | |
831 | return; | |
832 | } | |
833 | ||
834 | if (scam->invalid) { | |
835 | scam->invalid = 0; | |
836 | } | |
837 | ||
838 | if (scam->x->shared) { | |
839 | XShmPutImage(scam->x->dpy, Tk_WindowId(scam->tkwin), scam->x->gc, | |
840 | scam->image, 0, 0, | |
841 | 0, 0, scam->w_width, scam->w_height, | |
842 | False); | |
843 | } else { | |
844 | XPutImage(scam->x->dpy, Tk_WindowId(scam->tkwin), scam->x->gc, | |
845 | scam->image, 0, 0, | |
846 | 0, 0, scam->w_width, scam->w_height); | |
847 | } | |
848 | } | |
849 | ||
850 | ||
851 | cam_command_init() | |
852 | { | |
853 | int new; | |
854 | extern int TileCamCmd(CLIENT_ARGS); | |
855 | ||
856 | Tcl_CreateCommand(tk_mainInterp, "camview", CamCmd, | |
857 | (ClientData)MainWindow, (void (*)()) NULL); | |
858 | ||
859 | Tcl_InitHashTable(&CamCmds, TCL_STRING_KEYS); | |
860 | ||
861 | #define CAM_CMD(name) HASHED_CMD(Cam, name) | |
862 | ||
863 | CAM_CMD(configure); | |
864 | CAM_CMD(position); | |
865 | CAM_CMD(size); | |
866 | CAM_CMD(Visible); | |
867 | CAM_CMD(StoreColor); | |
868 | CAM_CMD(NewCam); | |
869 | CAM_CMD(DeleteCam); | |
870 | CAM_CMD(RandomizeCam); | |
871 | CAM_CMD(ConfigCam); | |
872 | CAM_CMD(FindCam); | |
873 | CAM_CMD(FindSomeCam); | |
874 | } | |
875 | ||
876 | ||
877 | #endif /* CAM */ |