1 /*
2 * tkTest.c --
3 *
4 * This file contains C command procedures for a bunch of additional
5 * Tcl commands that are used for testing out Tcl's C interfaces.
6 * These commands are not normally included in Tcl applications;
7 * they're only used for testing.
8 *
9 * Copyright (c) 1993-1994 The Regents of the University of California.
10 * Copyright (c) 1994-1996 Sun Microsystems, Inc.
11 *
12 * See the file "license.terms" for information on usage and redistribution
13 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
14 *
15 * SCCS: @(#) tkTest.c 1.35 96/10/03 11:22:26
16 */
17
18 #include "tkInt.h"
19
20 #ifdef WIN_TCL
21 #include "tkWinInt.h"
22 #endif
23
24 /*
25 * The table below describes events and is used by the "testevent"
26 * command.
27 */
28
29 typedef struct {
30 char *name; /* Name of event. */
31 int type; /* Event type for X, such as
32 * ButtonPress. */
33 } EventInfo;
34
35 static EventInfo eventArray[] = {
36 {"Motion", MotionNotify},
37 {"Button", ButtonPress},
38 {"ButtonPress", ButtonPress},
39 {"ButtonRelease", ButtonRelease},
40 {"Colormap", ColormapNotify},
41 {"Enter", EnterNotify},
42 {"Leave", LeaveNotify},
43 {"Expose", Expose},
44 {"FocusIn", FocusIn},
45 {"FocusOut", FocusOut},
46 {"Keymap", KeymapNotify},
47 {"Key", KeyPress},
48 {"KeyPress", KeyPress},
49 {"KeyRelease", KeyRelease},
50 {"Property", PropertyNotify},
51 {"ResizeRequest", ResizeRequest},
52 {"Circulate", CirculateNotify},
53 {"Configure", ConfigureNotify},
54 {"Destroy", DestroyNotify},
55 {"Gravity", GravityNotify},
56 {"Map", MapNotify},
57 {"Reparent", ReparentNotify},
58 {"Unmap", UnmapNotify},
59 {"Visibility", VisibilityNotify},
60 {"CirculateRequest",CirculateRequest},
61 {"ConfigureRequest",ConfigureRequest},
62 {"MapRequest", MapRequest},
63 {(char *) NULL, 0}
64 };
65
66 /*
67 * The defines and table below are used to classify events into
68 * various groups. The reason for this is that logically identical
69 * fields (e.g. "state") appear at different places in different
70 * types of events. The classification masks can be used to figure
71 * out quickly where to extract information from events.
72 */
73
74 #define KEY_BUTTON_MOTION 0x1
75 #define CROSSING 0x2
76 #define FOCUS 0x4
77 #define EXPOSE 0x8
78 #define VISIBILITY 0x10
79 #define CREATE 0x20
80 #define MAP 0x40
81 #define REPARENT 0x80
82 #define CONFIG 0x100
83 #define CONFIG_REQ 0x200
84 #define RESIZE_REQ 0x400
85 #define GRAVITY 0x800
86 #define PROP 0x1000
87 #define SEL_CLEAR 0x2000
88 #define SEL_REQ 0x4000
89 #define SEL_NOTIFY 0x8000
90 #define COLORMAP 0x10000
91 #define MAPPING 0x20000
92
93 static int flagArray[LASTEvent] = {
94 /* Not used */ 0,
95 /* Not used */ 0,
96 /* KeyPress */ KEY_BUTTON_MOTION,
97 /* KeyRelease */ KEY_BUTTON_MOTION,
98 /* ButtonPress */ KEY_BUTTON_MOTION,
99 /* ButtonRelease */ KEY_BUTTON_MOTION,
100 /* MotionNotify */ KEY_BUTTON_MOTION,
101 /* EnterNotify */ CROSSING,
102 /* LeaveNotify */ CROSSING,
103 /* FocusIn */ FOCUS,
104 /* FocusOut */ FOCUS,
105 /* KeymapNotify */ 0,
106 /* Expose */ EXPOSE,
107 /* GraphicsExpose */ EXPOSE,
108 /* NoExpose */ 0,
109 /* VisibilityNotify */ VISIBILITY,
110 /* CreateNotify */ CREATE,
111 /* DestroyNotify */ 0,
112 /* UnmapNotify */ 0,
113 /* MapNotify */ MAP,
114 /* MapRequest */ 0,
115 /* ReparentNotify */ REPARENT,
116 /* ConfigureNotify */ CONFIG,
117 /* ConfigureRequest */ CONFIG_REQ,
118 /* GravityNotify */ 0,
119 /* ResizeRequest */ RESIZE_REQ,
120 /* CirculateNotify */ 0,
121 /* CirculateRequest */ 0,
122 /* PropertyNotify */ PROP,
123 /* SelectionClear */ SEL_CLEAR,
124 /* SelectionRequest */ SEL_REQ,
125 /* SelectionNotify */ SEL_NOTIFY,
126 /* ColormapNotify */ COLORMAP,
127 /* ClientMessage */ 0,
128 /* MappingNotify */ MAPPING
129 };
130
131 /*
132 * The following data structure represents the master for a test
133 * image:
134 */
135
136 typedef struct TImageMaster {
137 Tk_ImageMaster master; /* Tk's token for image master. */
138 Tcl_Interp *interp; /* Interpreter for application. */
139 int width, height; /* Dimensions of image. */
140 char *imageName; /* Name of image (malloc-ed). */
141 char *varName; /* Name of variable in which to log
142 * events for image (malloc-ed). */
143 } TImageMaster;
144
145 /*
146 * The following data structure represents a particular use of a
147 * particular test image.
148 */
149
150 typedef struct TImageInstance {
151 TImageMaster *masterPtr; /* Pointer to master for image. */
152 XColor *fg; /* Foreground color for drawing in image. */
153 GC gc; /* Graphics context for drawing in image. */
154 } TImageInstance;
155
156 /*
157 * The type record for test images:
158 */
159
160 static int ImageCreate _ANSI_ARGS_((Tcl_Interp *interp,
161 char *name, int argc, char **argv,
162 Tk_ImageType *typePtr, Tk_ImageMaster master,
163 ClientData *clientDataPtr));
164 static ClientData ImageGet _ANSI_ARGS_((Tk_Window tkwin,
165 ClientData clientData));
166 static void ImageDisplay _ANSI_ARGS_((ClientData clientData,
167 Display *display, Drawable drawable,
168 int imageX, int imageY, int width,
169 int height, int drawableX,
170 int drawableY));
171 static void ImageFree _ANSI_ARGS_((ClientData clientData,
172 Display *display));
173 static void ImageDelete _ANSI_ARGS_((ClientData clientData));
174
175 static Tk_ImageType imageType = {
176 "test", /* name */
177 ImageCreate, /* createProc */
178 ImageGet, /* getProc */
179 ImageDisplay, /* displayProc */
180 ImageFree, /* freeProc */
181 ImageDelete, /* deleteProc */
182 (Tk_ImageType *) NULL /* nextPtr */
183 };
184
185 /*
186 * One of the following structures describes each of the interpreters
187 * created by the "testnewapp" command. This information is used by
188 * the "testdeleteinterps" command to destroy all of those interpreters.
189 */
190
191 typedef struct NewApp {
192 Tcl_Interp *interp; /* Token for interpreter. */
193 struct NewApp *nextPtr; /* Next in list of new interpreters. */
194 } NewApp;
195
196 static NewApp *newAppPtr = NULL;
197 /* First in list of all new interpreters. */
198
199 /*
200 * Declaration for the square widget's class command procedure:
201 */
202
203 extern int SquareCmd _ANSI_ARGS_((ClientData clientData,
204 Tcl_Interp *interp, int argc, char *argv[]));
205
206 /*
207 * Forward declarations for procedures defined later in this file:
208 */
209
210 int Tktest_Init _ANSI_ARGS_((Tcl_Interp *interp));
211 static int ImageCmd _ANSI_ARGS_((ClientData dummy,
212 Tcl_Interp *interp, int argc, char **argv));
213 #ifdef WIN_TCL
214 static int TestclipboardCmd _ANSI_ARGS_((ClientData dummy,
215 Tcl_Interp *interp, int argc, char **argv));
216 #endif
217 static int TestdeleteappsCmd _ANSI_ARGS_((ClientData dummy,
218 Tcl_Interp *interp, int argc, char **argv));
219 static int TesteventCmd _ANSI_ARGS_((ClientData dummy,
220 Tcl_Interp *interp, int argc, char **argv));
221 static int TestmakeexistCmd _ANSI_ARGS_((ClientData dummy,
222 Tcl_Interp *interp, int argc, char **argv));
223 static int TestsendCmd _ANSI_ARGS_((ClientData dummy,
224 Tcl_Interp *interp, int argc, char **argv));
225
226 /*
227 *----------------------------------------------------------------------
228 *
229 * Tktest_Init --
230 *
231 * This procedure performs intialization for the Tk test
232 * suite exensions.
233 *
234 * Results:
235 * Returns a standard Tcl completion code, and leaves an error
236 * message in interp->result if an error occurs.
237 *
238 * Side effects:
239 * Creates several test commands.
240 *
241 *----------------------------------------------------------------------
242 */
243
244 int
Tktest_Init(interp)245 Tktest_Init(interp)
246 Tcl_Interp *interp; /* Interpreter for application. */
247 {
248 static int initialized = 0;
249
250 /*
251 * Create additional commands for testing Tk.
252 */
253
254 if (Tcl_PkgProvide(interp, "Tktest", TK_VERSION) == TCL_ERROR) {
255 return TCL_ERROR;
256 }
257
258 Tcl_CreateCommand(interp, "square", SquareCmd,
259 (ClientData) Tk_MainWindow(interp), (Tcl_CmdDeleteProc *) NULL);
260 #ifdef WIN_TCL
261 Tcl_CreateCommand(interp, "testclipboard", TestclipboardCmd,
262 (ClientData) Tk_MainWindow(interp), (Tcl_CmdDeleteProc *) NULL);
263 #endif
264 Tcl_CreateCommand(interp, "testdeleteapps", TestdeleteappsCmd,
265 (ClientData) Tk_MainWindow(interp), (Tcl_CmdDeleteProc *) NULL);
266 Tcl_CreateCommand(interp, "testevent", TesteventCmd,
267 (ClientData) Tk_MainWindow(interp), (Tcl_CmdDeleteProc *) NULL);
268 Tcl_CreateCommand(interp, "testmakeexist", TestmakeexistCmd,
269 (ClientData) Tk_MainWindow(interp), (Tcl_CmdDeleteProc *) NULL);
270 Tcl_CreateCommand(interp, "testsend", TestsendCmd,
271 (ClientData) Tk_MainWindow(interp), (Tcl_CmdDeleteProc *) NULL);
272
273 /*
274 * Create test image type.
275 */
276
277 if (!initialized) {
278 initialized = 1;
279 Tk_CreateImageType(&imageType);
280 }
281 return TCL_OK;
282 }
283
284 /*
285 *----------------------------------------------------------------------
286 *
287 * TestclipboardCmd --
288 *
289 * This procedure implements the testclipboard command. It provides
290 * a way to determine the actual contents of the Windows clipboard.
291 *
292 * Results:
293 * A standard Tcl result.
294 *
295 * Side effects:
296 * None.
297 *
298 *----------------------------------------------------------------------
299 */
300
301 #ifdef WIN_TCL
302 static int
TestclipboardCmd(clientData,interp,argc,argv)303 TestclipboardCmd(clientData, interp, argc, argv)
304 ClientData clientData; /* Main window for application. */
305 Tcl_Interp *interp; /* Current interpreter. */
306 int argc; /* Number of arguments. */
307 char **argv; /* Argument strings. */
308 {
309 TkWindow *winPtr = (TkWindow *) clientData;
310 HGLOBAL handle;
311 char *data;
312
313 if (OpenClipboard(NULL)) {
314 handle = GetClipboardData(CF_TEXT);
315 if (handle != NULL) {
316 data = GlobalLock(handle);
317 Tcl_AppendResult(interp, data, (char *) NULL);
318 GlobalUnlock(handle);
319 }
320 CloseClipboard();
321 }
322 return TCL_OK;
323 }
324 #endif
325
326 /*
327 *----------------------------------------------------------------------
328 *
329 * TestdeleteappsCmd --
330 *
331 * This procedure implements the "testdeleteapps" command. It cleans
332 * up all the interpreters left behind by the "testnewapp" command.
333 *
334 * Results:
335 * A standard Tcl result.
336 *
337 * Side effects:
338 * All the intepreters created by previous calls to "testnewapp"
339 * get deleted.
340 *
341 *----------------------------------------------------------------------
342 */
343
344 /* ARGSUSED */
345 static int
TestdeleteappsCmd(clientData,interp,argc,argv)346 TestdeleteappsCmd(clientData, interp, argc, argv)
347 ClientData clientData; /* Main window for application. */
348 Tcl_Interp *interp; /* Current interpreter. */
349 int argc; /* Number of arguments. */
350 char **argv; /* Argument strings. */
351 {
352 NewApp *nextPtr;
353
354 while (newAppPtr != NULL) {
355 nextPtr = newAppPtr->nextPtr;
356 Tcl_DeleteInterp(newAppPtr->interp);
357 ckfree((char *) newAppPtr);
358 newAppPtr = nextPtr;
359 }
360 return TCL_OK;
361 }
362
363 /*
364 *----------------------------------------------------------------------
365 *
366 * TesteventCmd --
367 *
368 * This procedure implements the "testevent" command. It allows
369 * events to be generated on the fly, for testing event-handling.
370 *
371 * Results:
372 * A standard Tcl result.
373 *
374 * Side effects:
375 * Creates and handles events.
376 *
377 *----------------------------------------------------------------------
378 */
379
380 /* ARGSUSED */
381 static int
TesteventCmd(clientData,interp,argc,argv)382 TesteventCmd(clientData, interp, argc, argv)
383 ClientData clientData; /* Main window for application. */
384 Tcl_Interp *interp; /* Current interpreter. */
385 int argc; /* Number of arguments. */
386 char **argv; /* Argument strings. */
387 {
388 Tk_Window main = (Tk_Window) clientData;
389 Tk_Window tkwin, tkwin2;
390 XEvent event;
391 EventInfo *eiPtr;
392 char *field, *value;
393 int i, number, flags;
394 KeySym keysym;
395
396 if ((argc < 3) || !(argc & 1)) {
397 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
398 " window type ?field value field value ...?\"",
399 (char *) NULL);
400 return TCL_ERROR;
401 }
402 tkwin = Tk_NameToWindow(interp, argv[1], main);
403 if (tkwin == NULL) {
404 return TCL_ERROR;
405 }
406
407 /*
408 * Get the type of the event.
409 */
410
411 memset((VOID *) &event, 0, sizeof(event));
412 for (eiPtr = eventArray; ; eiPtr++) {
413 if (eiPtr->name == NULL) {
414 Tcl_AppendResult(interp, "bad event type \"", argv[2],
415 "\"", (char *) NULL);
416 return TCL_ERROR;
417 }
418 if (strcmp(eiPtr->name, argv[2]) == 0) {
419 event.xany.type = eiPtr->type;
420 break;
421 }
422 }
423
424 /*
425 * Fill in fields that are common to all events.
426 */
427
428 event.xany.serial = NextRequest(Tk_Display(tkwin));
429 event.xany.send_event = False;
430 event.xany.window = Tk_WindowId(tkwin);
431 event.xany.display = Tk_Display(tkwin);
432
433 /*
434 * Process the remaining arguments to fill in additional fields
435 * of the event.
436 */
437
438 flags = flagArray[event.xany.type];
439 for (i = 3; i < argc; i += 2) {
440 field = argv[i];
441 value = argv[i+1];
442 if (strcmp(field, "-above") == 0) {
443 tkwin2 = Tk_NameToWindow(interp, value, main);
444 if (tkwin2 == NULL) {
445 return TCL_ERROR;
446 }
447 event.xconfigure.above = Tk_WindowId(tkwin2);
448 } else if (strcmp(field, "-borderwidth") == 0) {
449 if (Tcl_GetInt(interp, value, &number) != TCL_OK) {
450 return TCL_ERROR;
451 }
452 event.xcreatewindow.border_width = number;
453 } else if (strcmp(field, "-button") == 0) {
454 if (Tcl_GetInt(interp, value, &number) != TCL_OK) {
455 return TCL_ERROR;
456 }
457 event.xbutton.button = number;
458 } else if (strcmp(field, "-count") == 0) {
459 if (Tcl_GetInt(interp, value, &number) != TCL_OK) {
460 return TCL_ERROR;
461 }
462 if (flags & EXPOSE) {
463 event.xexpose.count = number;
464 } else if (flags & MAPPING) {
465 event.xmapping.count = number;
466 }
467 } else if (strcmp(field, "-detail") == 0) {
468 if (flags & (CROSSING|FOCUS)) {
469 if (strcmp(value, "NotifyAncestor") == 0) {
470 number = NotifyAncestor;
471 } else if (strcmp(value, "NotifyVirtual") == 0) {
472 number = NotifyVirtual;
473 } else if (strcmp(value, "NotifyInferior") == 0) {
474 number = NotifyInferior;
475 } else if (strcmp(value, "NotifyNonlinear") == 0) {
476 number = NotifyNonlinear;
477 } else if (strcmp(value, "NotifyNonlinearVirtual") == 0) {
478 number = NotifyNonlinearVirtual;
479 } else if (strcmp(value, "NotifyPointer") == 0) {
480 number = NotifyPointer;
481 } else if (strcmp(value, "NotifyPointerRoot") == 0) {
482 number = NotifyPointerRoot;
483 } else if (strcmp(value, "NotifyDetailNone") == 0) {
484 number = NotifyDetailNone;
485 } else {
486 Tcl_AppendResult(interp, "bad detail \"", value, "\"",
487 (char *) NULL);
488 return TCL_ERROR;
489 }
490 if (flags & FOCUS) {
491 event.xfocus.detail = number;
492 } else {
493 event.xcrossing.detail = number;
494 }
495 } else if (flags & CONFIG_REQ) {
496 if (strcmp(value, "Above") == 0) {
497 number = Above;
498 } else if (strcmp(value, "Below") == 0) {
499 number = Below;
500 } else if (strcmp(value, "TopIf") == 0) {
501 number = TopIf;
502 } else if (strcmp(value, "BottomIf") == 0) {
503 number = BottomIf;
504 } else if (strcmp(value, "Opposite") == 0) {
505 number = Opposite;
506 } else {
507 Tcl_AppendResult(interp, "bad detail \"", value, "\"",
508 (char *) NULL);
509 return TCL_ERROR;
510 }
511 event.xconfigurerequest.detail = number;
512 }
513 } else if (strcmp(field, "-focus") == 0) {
514 if (Tcl_GetInt(interp, value, &number) != TCL_OK) {
515 return TCL_ERROR;
516 }
517 event.xcrossing.focus = number;
518 } else if (strcmp(field, "-height") == 0) {
519 if (Tcl_GetInt(interp, value, &number) != TCL_OK) {
520 return TCL_ERROR;
521 }
522 if (flags & EXPOSE) {
523 event.xexpose.height = number;
524 } else if (flags & (CONFIG|CONFIG_REQ)) {
525 event.xconfigure.height = number;
526 } else if (flags & RESIZE_REQ) {
527 event.xresizerequest.height = number;
528 }
529 } else if (strcmp(field, "-keycode") == 0) {
530 if (Tcl_GetInt(interp, value, &number) != TCL_OK) {
531 return TCL_ERROR;
532 }
533 event.xkey.keycode = number;
534 } else if (strcmp(field, "-keysym") == 0) {
535 keysym = TkStringToKeysym(value);
536 if (keysym == NoSymbol) {
537 Tcl_AppendResult(interp, "unknown keysym \"", value,
538 "\"", (char *) NULL);
539 return TCL_ERROR;
540 }
541 number = XKeysymToKeycode(event.xany.display, keysym);
542 if (number == 0) {
543 Tcl_AppendResult(interp, "no keycode for keysym \"", value,
544 "\"", (char *) NULL);
545 return TCL_ERROR;
546 }
547 event.xkey.keycode = number;
548 } else if (strcmp(field, "-mode") == 0) {
549 if (strcmp(value, "NotifyNormal") == 0) {
550 number = NotifyNormal;
551 } else if (strcmp(value, "NotifyGrab") == 0) {
552 number = NotifyGrab;
553 } else if (strcmp(value, "NotifyUngrab") == 0) {
554 number = NotifyUngrab;
555 } else if (strcmp(value, "NotifyWhileGrabbed") == 0) {
556 number = NotifyWhileGrabbed;
557 } else {
558 Tcl_AppendResult(interp, "bad mode \"", value, "\"",
559 (char *) NULL);
560 return TCL_ERROR;
561 }
562 if (flags & CROSSING) {
563 event.xcrossing.mode = number;
564 } else if (flags & FOCUS) {
565 event.xfocus.mode = number;
566 }
567 } else if (strcmp(field, "-override") == 0) {
568 if (Tcl_GetInt(interp, value, &number) != TCL_OK) {
569 return TCL_ERROR;
570 }
571 if (flags & CREATE) {
572 event.xcreatewindow.override_redirect = number;
573 } else if (flags & MAP) {
574 event.xmap.override_redirect = number;
575 } else if (flags & REPARENT) {
576 event.xreparent.override_redirect = number;
577 } else if (flags & CONFIG) {
578 event.xconfigure.override_redirect = number;
579 }
580 } else if (strcmp(field, "-place") == 0) {
581 if (strcmp(value, "PlaceOnTop") == 0) {
582 event.xcirculate.place = PlaceOnTop;
583 } else if (strcmp(value, "PlaceOnBottom") == 0) {
584 event.xcirculate.place = PlaceOnBottom;
585 } else if (strcmp(value, "bogus") == 0) {
586 event.xcirculate.place = 147;
587 } else {
588 Tcl_AppendResult(interp, "bad place \"", value, "\"",
589 (char *) NULL);
590 return TCL_ERROR;
591 }
592 } else if (strcmp(field, "-root") == 0) {
593 if (Tcl_GetInt(interp, value, &number) != TCL_OK) {
594 return TCL_ERROR;
595 }
596 event.xkey.root = number;
597 } else if (strcmp(field, "-rootx") == 0) {
598 if (Tcl_GetInt(interp, value, &number) != TCL_OK) {
599 return TCL_ERROR;
600 }
601 event.xkey.x_root = number;
602 } else if (strcmp(field, "-rooty") == 0) {
603 if (Tcl_GetInt(interp, value, &number) != TCL_OK) {
604 return TCL_ERROR;
605 }
606 event.xkey.y_root = number;
607 } else if (strcmp(field, "-sendevent") == 0) {
608 if (Tcl_GetInt(interp, value, &number) != TCL_OK) {
609 return TCL_ERROR;
610 }
611 event.xany.send_event = number;
612 } else if (strcmp(field, "-serial") == 0) {
613 if (Tcl_GetInt(interp, value, &number) != TCL_OK) {
614 return TCL_ERROR;
615 }
616 event.xany.serial = number;
617 } else if (strcmp(field, "-state") == 0) {
618 if (flags & KEY_BUTTON_MOTION) {
619 if (Tcl_GetInt(interp, value, &number) != TCL_OK) {
620 return TCL_ERROR;
621 }
622 event.xkey.state = number;
623 } else if (flags & CROSSING) {
624 if (Tcl_GetInt(interp, value, &number) != TCL_OK) {
625 return TCL_ERROR;
626 }
627 event.xcrossing.state = number;
628 } else if (flags & VISIBILITY) {
629 if (strcmp(value, "VisibilityUnobscured") == 0) {
630 number = VisibilityUnobscured;
631 } else if (strcmp(value, "VisibilityPartiallyObscured") == 0) {
632 number = VisibilityPartiallyObscured;
633 } else if (strcmp(value, "VisibilityFullyObscured") == 0) {
634 number = VisibilityFullyObscured;
635 } else {
636 Tcl_AppendResult(interp, "bad state \"", value, "\"",
637 (char *) NULL);
638 return TCL_ERROR;
639 }
640 event.xvisibility.state = number;
641 }
642 } else if (strcmp(field, "-subwindow") == 0) {
643 tkwin2 = Tk_NameToWindow(interp, value, main);
644 if (tkwin2 == NULL) {
645 return TCL_ERROR;
646 }
647 event.xkey.subwindow = Tk_WindowId(tkwin2);
648 } else if (strcmp(field, "-time") == 0) {
649 if (Tcl_GetInt(interp, value, &number) != TCL_OK) {
650 return TCL_ERROR;
651 }
652 if (flags & (KEY_BUTTON_MOTION|PROP|SEL_CLEAR)) {
653 event.xkey.time = (Time) number;
654 } else if (flags & SEL_REQ) {
655 event.xselectionrequest.time = (Time) number;
656 } else if (flags & SEL_NOTIFY) {
657 event.xselection.time = (Time) number;
658 }
659 } else if (strcmp(field, "-valueMask") == 0) {
660 if (Tcl_GetInt(interp, value, &number) != TCL_OK) {
661 return TCL_ERROR;
662 }
663 event.xconfigurerequest.value_mask = number;
664 } else if (strcmp(field, "-width") == 0) {
665 if (Tcl_GetInt(interp, value, &number) != TCL_OK) {
666 return TCL_ERROR;
667 }
668 if (flags & EXPOSE) {
669 event.xexpose.width = number;
670 } else if (flags & (CONFIG|CONFIG_REQ)) {
671 event.xconfigure.width = number;
672 } else if (flags & RESIZE_REQ) {
673 event.xresizerequest.width = number;
674 }
675 } else if (strcmp(field, "-window") == 0) {
676 tkwin2 = Tk_NameToWindow(interp, value, main);
677 if (tkwin2 == NULL) {
678 return TCL_ERROR;
679 }
680 event.xmap.window = Tk_WindowId(tkwin2);
681 } else if (strcmp(field, "-x") == 0) {
682 int rootX, rootY;
683 if (Tcl_GetInt(interp, value, &number) != TCL_OK) {
684 return TCL_ERROR;
685 }
686 Tk_GetRootCoords(tkwin, &rootX, &rootY);
687 rootX += number;
688 if (flags & KEY_BUTTON_MOTION) {
689 event.xkey.x = number;
690 event.xkey.x_root = rootX;
691 } else if (flags & EXPOSE) {
692 event.xexpose.x = number;
693 } else if (flags & (CREATE|CONFIG|GRAVITY|CONFIG_REQ)) {
694 event.xcreatewindow.x = number;
695 } else if (flags & REPARENT) {
696 event.xreparent.x = number;
697 } else if (flags & CROSSING) {
698 event.xcrossing.x = number;
699 event.xcrossing.x_root = rootY;
700 }
701 } else if (strcmp(field, "-y") == 0) {
702 int rootX, rootY;
703 if (Tcl_GetInt(interp, value, &number) != TCL_OK) {
704 return TCL_ERROR;
705 }
706 Tk_GetRootCoords(tkwin, &rootX, &rootY);
707 rootY += number;
708 if (flags & KEY_BUTTON_MOTION) {
709 event.xkey.y = number;
710 event.xkey.y_root = rootY;
711 } else if (flags & EXPOSE) {
712 event.xexpose.y = number;
713 } else if (flags & (CREATE|CONFIG|GRAVITY|CONFIG_REQ)) {
714 event.xcreatewindow.y = number;
715 } else if (flags & REPARENT) {
716 event.xreparent.y = number;
717 } else if (flags & CROSSING) {
718 event.xcrossing.y = number;
719 event.xcrossing.y_root = rootY;
720 }
721 } else {
722 Tcl_AppendResult(interp, "bad option \"", field, "\"",
723 (char *) NULL);
724 return TCL_ERROR;
725 }
726 }
727 Tk_HandleEvent(&event);
728 return TCL_OK;
729 }
730
731 /*
732 *----------------------------------------------------------------------
733 *
734 * TestmakeexistCmd --
735 *
736 * This procedure implements the "testmakeexist" command. It calls
737 * Tk_MakeWindowExist on each of its arguments to force the windows
738 * to be created.
739 *
740 * Results:
741 * A standard Tcl result.
742 *
743 * Side effects:
744 * Forces windows to be created.
745 *
746 *----------------------------------------------------------------------
747 */
748
749 /* ARGSUSED */
750 static int
TestmakeexistCmd(clientData,interp,argc,argv)751 TestmakeexistCmd(clientData, interp, argc, argv)
752 ClientData clientData; /* Main window for application. */
753 Tcl_Interp *interp; /* Current interpreter. */
754 int argc; /* Number of arguments. */
755 char **argv; /* Argument strings. */
756 {
757 Tk_Window main = (Tk_Window) clientData;
758 int i;
759 Tk_Window tkwin;
760
761 for (i = 1; i < argc; i++) {
762 tkwin = Tk_NameToWindow(interp, argv[i], main);
763 if (tkwin == NULL) {
764 return TCL_ERROR;
765 }
766 Tk_MakeWindowExist(tkwin);
767 }
768
769 return TCL_OK;
770 }
771
772 /*
773 *----------------------------------------------------------------------
774 *
775 * ImageCreate --
776 *
777 * This procedure is called by the Tk image code to create "test"
778 * images.
779 *
780 * Results:
781 * A standard Tcl result.
782 *
783 * Side effects:
784 * The data structure for a new image is allocated.
785 *
786 *----------------------------------------------------------------------
787 */
788
789 /* ARGSUSED */
790 static int
ImageCreate(interp,name,argc,argv,typePtr,master,clientDataPtr)791 ImageCreate(interp, name, argc, argv, typePtr, master, clientDataPtr)
792 Tcl_Interp *interp; /* Interpreter for application containing
793 * image. */
794 char *name; /* Name to use for image. */
795 int argc; /* Number of arguments. */
796 char **argv; /* Argument strings for options (doesn't
797 * include image name or type). */
798 Tk_ImageType *typePtr; /* Pointer to our type record (not used). */
799 Tk_ImageMaster master; /* Token for image, to be used by us in
800 * later callbacks. */
801 ClientData *clientDataPtr; /* Store manager's token for image here;
802 * it will be returned in later callbacks. */
803 {
804 TImageMaster *timPtr;
805 char *varName;
806 int i;
807
808 varName = "log";
809 for (i = 0; i < argc; i += 2) {
810 if (strcmp(argv[i], "-variable") != 0) {
811 Tcl_AppendResult(interp, "bad option name \"", argv[i],
812 "\"", (char *) NULL);
813 return TCL_ERROR;
814 }
815 if ((i+1) == argc) {
816 Tcl_AppendResult(interp, "no value given for \"", argv[i],
817 "\" option", (char *) NULL);
818 return TCL_ERROR;
819 }
820 varName = argv[i+1];
821 }
822 timPtr = (TImageMaster *) ckalloc(sizeof(TImageMaster));
823 timPtr->master = master;
824 timPtr->interp = interp;
825 timPtr->width = 30;
826 timPtr->height = 15;
827 timPtr->imageName = (char *) ckalloc((unsigned) (strlen(name) + 1));
828 strcpy(timPtr->imageName, name);
829 timPtr->varName = (char *) ckalloc((unsigned) (strlen(varName) + 1));
830 strcpy(timPtr->varName, varName);
831 Tcl_CreateCommand(interp, name, ImageCmd, (ClientData) timPtr,
832 (Tcl_CmdDeleteProc *) NULL);
833 *clientDataPtr = (ClientData) timPtr;
834 Tk_ImageChanged(master, 0, 0, 30, 15, 30, 15);
835 return TCL_OK;
836 }
837
838 /*
839 *----------------------------------------------------------------------
840 *
841 * ImageCmd --
842 *
843 * This procedure implements the commands corresponding to individual
844 * images.
845 *
846 * Results:
847 * A standard Tcl result.
848 *
849 * Side effects:
850 * Forces windows to be created.
851 *
852 *----------------------------------------------------------------------
853 */
854
855 /* ARGSUSED */
856 static int
ImageCmd(clientData,interp,argc,argv)857 ImageCmd(clientData, interp, argc, argv)
858 ClientData clientData; /* Main window for application. */
859 Tcl_Interp *interp; /* Current interpreter. */
860 int argc; /* Number of arguments. */
861 char **argv; /* Argument strings. */
862 {
863 TImageMaster *timPtr = (TImageMaster *) clientData;
864 int x, y, width, height;
865
866 if (argc < 2) {
867 Tcl_AppendResult(interp, "wrong # args: should be \"",
868 argv[0], "option ?arg arg ...?", (char *) NULL);
869 return TCL_ERROR;
870 }
871 if (strcmp(argv[1], "changed") == 0) {
872 if (argc != 8) {
873 Tcl_AppendResult(interp, "wrong # args: should be \"",
874 argv[0], " changed x y width height imageWidth imageHeight",
875 (char *) NULL);
876 return TCL_ERROR;
877 }
878 if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK)
879 || (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)
880 || (Tcl_GetInt(interp, argv[4], &width) != TCL_OK)
881 || (Tcl_GetInt(interp, argv[5], &height) != TCL_OK)
882 || (Tcl_GetInt(interp, argv[6], &timPtr->width) != TCL_OK)
883 || (Tcl_GetInt(interp, argv[7], &timPtr->height) != TCL_OK)) {
884 return TCL_ERROR;
885 }
886 Tk_ImageChanged(timPtr->master, x, y, width, height, timPtr->width,
887 timPtr->height);
888 } else {
889 Tcl_AppendResult(interp, "bad option \"", argv[1],
890 "\": must be changed", (char *) NULL);
891 return TCL_ERROR;
892 }
893 return TCL_OK;
894 }
895
896 /*
897 *----------------------------------------------------------------------
898 *
899 * ImageGet --
900 *
901 * This procedure is called by Tk to set things up for using a
902 * test image in a particular widget.
903 *
904 * Results:
905 * The return value is a token for the image instance, which is
906 * used in future callbacks to ImageDisplay and ImageFree.
907 *
908 * Side effects:
909 * None.
910 *
911 *----------------------------------------------------------------------
912 */
913
914 static ClientData
ImageGet(tkwin,clientData)915 ImageGet(tkwin, clientData)
916 Tk_Window tkwin; /* Token for window in which image will
917 * be used. */
918 ClientData clientData; /* Pointer to TImageMaster for image. */
919 {
920 TImageMaster *timPtr = (TImageMaster *) clientData;
921 TImageInstance *instPtr;
922 char buffer[100];
923 XGCValues gcValues;
924
925 sprintf(buffer, "%s get", timPtr->imageName);
926 Tcl_SetVar(timPtr->interp, timPtr->varName, buffer,
927 TCL_GLOBAL_ONLY|TCL_APPEND_VALUE|TCL_LIST_ELEMENT);
928
929 instPtr = (TImageInstance *) ckalloc(sizeof(TImageInstance));
930 instPtr->masterPtr = timPtr;
931 instPtr->fg = Tk_GetColor(timPtr->interp, tkwin, "#ff0000");
932 gcValues.foreground = instPtr->fg->pixel;
933 instPtr->gc = Tk_GetGC(tkwin, GCForeground, &gcValues);
934 return (ClientData) instPtr;
935 }
936
937 /*
938 *----------------------------------------------------------------------
939 *
940 * ImageDisplay --
941 *
942 * This procedure is invoked to redisplay part or all of an
943 * image in a given drawable.
944 *
945 * Results:
946 * None.
947 *
948 * Side effects:
949 * The image gets partially redrawn, as an "X" that shows the
950 * exact redraw area.
951 *
952 *----------------------------------------------------------------------
953 */
954
955 static void
ImageDisplay(clientData,display,drawable,imageX,imageY,width,height,drawableX,drawableY)956 ImageDisplay(clientData, display, drawable, imageX, imageY, width, height,
957 drawableX, drawableY)
958 ClientData clientData; /* Pointer to TImageInstance for image. */
959 Display *display; /* Display to use for drawing. */
960 Drawable drawable; /* Where to redraw image. */
961 int imageX, imageY; /* Origin of area to redraw, relative to
962 * origin of image. */
963 int width, height; /* Dimensions of area to redraw. */
964 int drawableX, drawableY; /* Coordinates in drawable corresponding to
965 * imageX and imageY. */
966 {
967 TImageInstance *instPtr = (TImageInstance *) clientData;
968 char buffer[200];
969
970 sprintf(buffer, "%s display %d %d %d %d %d %d",
971 instPtr->masterPtr->imageName, imageX, imageY, width, height,
972 drawableX, drawableY);
973 Tcl_SetVar(instPtr->masterPtr->interp, instPtr->masterPtr->varName, buffer,
974 TCL_GLOBAL_ONLY|TCL_APPEND_VALUE|TCL_LIST_ELEMENT);
975 if (width > (instPtr->masterPtr->width - imageX)) {
976 width = instPtr->masterPtr->width - imageX;
977 }
978 if (height > (instPtr->masterPtr->height - imageY)) {
979 height = instPtr->masterPtr->height - imageY;
980 }
981 XDrawRectangle(display, drawable, instPtr->gc, drawableX, drawableY,
982 (unsigned) (width-1), (unsigned) (height-1));
983 XDrawLine(display, drawable, instPtr->gc, drawableX, drawableY,
984 (int) (drawableX + width - 1), (int) (drawableY + height - 1));
985 XDrawLine(display, drawable, instPtr->gc, drawableX,
986 (int) (drawableY + height - 1),
987 (int) (drawableX + width - 1), drawableY);
988 }
989
990 /*
991 *----------------------------------------------------------------------
992 *
993 * ImageFree --
994 *
995 * This procedure is called when an instance of an image is
996 * no longer used.
997 *
998 * Results:
999 * None.
1000 *
1001 * Side effects:
1002 * Information related to the instance is freed.
1003 *
1004 *----------------------------------------------------------------------
1005 */
1006
1007 static void
ImageFree(clientData,display)1008 ImageFree(clientData, display)
1009 ClientData clientData; /* Pointer to TImageInstance for instance. */
1010 Display *display; /* Display where image was to be drawn. */
1011 {
1012 TImageInstance *instPtr = (TImageInstance *) clientData;
1013 char buffer[200];
1014
1015 sprintf(buffer, "%s free", instPtr->masterPtr->imageName);
1016 Tcl_SetVar(instPtr->masterPtr->interp, instPtr->masterPtr->varName, buffer,
1017 TCL_GLOBAL_ONLY|TCL_APPEND_VALUE|TCL_LIST_ELEMENT);
1018 Tk_FreeColor(instPtr->fg);
1019 Tk_FreeGC(display, instPtr->gc);
1020 ckfree((char *) instPtr);
1021 }
1022
1023 /*
1024 *----------------------------------------------------------------------
1025 *
1026 * ImageDelete --
1027 *
1028 * This procedure is called to clean up a test image when
1029 * an application goes away.
1030 *
1031 * Results:
1032 * None.
1033 *
1034 * Side effects:
1035 * Information about the image is deleted.
1036 *
1037 *----------------------------------------------------------------------
1038 */
1039
1040 static void
ImageDelete(clientData)1041 ImageDelete(clientData)
1042 ClientData clientData; /* Pointer to TImageMaster for image. When
1043 * this procedure is called, no more
1044 * instances exist. */
1045 {
1046 TImageMaster *timPtr = (TImageMaster *) clientData;
1047 char buffer[100];
1048
1049 sprintf(buffer, "%s delete", timPtr->imageName);
1050 Tcl_SetVar(timPtr->interp, timPtr->varName, buffer,
1051 TCL_GLOBAL_ONLY|TCL_APPEND_VALUE|TCL_LIST_ELEMENT);
1052
1053 Tcl_DeleteCommand(timPtr->interp, timPtr->imageName);
1054 ckfree(timPtr->imageName);
1055 ckfree(timPtr->varName);
1056 ckfree((char *) timPtr);
1057 }
1058
1059 /*
1060 *----------------------------------------------------------------------
1061 *
1062 * TestsendCmd --
1063 *
1064 * This procedure implements the "testsend" command. It provides
1065 * a set of functions for testing the "send" command and support
1066 * procedure in tkSend.c.
1067 *
1068 * Results:
1069 * A standard Tcl result.
1070 *
1071 * Side effects:
1072 * Depends on option; see below.
1073 *
1074 *----------------------------------------------------------------------
1075 */
1076
1077 /* ARGSUSED */
1078 static int
TestsendCmd(clientData,interp,argc,argv)1079 TestsendCmd(clientData, interp, argc, argv)
1080 ClientData clientData; /* Main window for application. */
1081 Tcl_Interp *interp; /* Current interpreter. */
1082 int argc; /* Number of arguments. */
1083 char **argv; /* Argument strings. */
1084 {
1085 TkWindow *winPtr = (TkWindow *) clientData;
1086
1087 if (argc < 2) {
1088 Tcl_AppendResult(interp, "wrong # args; must be \"", argv[0],
1089 " option ?arg ...?\"", (char *) NULL);
1090 return TCL_ERROR;
1091 }
1092
1093 #ifndef WIN_TCL
1094 if (strcmp(argv[1], "bogus") == 0) {
1095 XChangeProperty(winPtr->dispPtr->display,
1096 RootWindow(winPtr->dispPtr->display, 0),
1097 winPtr->dispPtr->registryProperty, XA_INTEGER, 32,
1098 PropModeReplace,
1099 (unsigned char *) "This is bogus information", 6);
1100 } else if (strcmp(argv[1], "prop") == 0) {
1101 int result, actualFormat, length;
1102 unsigned long bytesAfter;
1103 Atom actualType, propName;
1104 char *property, *p, *end;
1105 Window w;
1106
1107 if ((argc != 4) && (argc != 5)) {
1108 Tcl_AppendResult(interp, "wrong # args; must be \"", argv[0],
1109 " prop window name ?value ?\"", (char *) NULL);
1110 return TCL_ERROR;
1111 }
1112 if (strcmp(argv[2], "root") == 0) {
1113 w = RootWindow(winPtr->dispPtr->display, 0);
1114 } else if (strcmp(argv[2], "comm") == 0) {
1115 w = Tk_WindowId(winPtr->dispPtr->commTkwin);
1116 } else {
1117 w = strtoul(argv[2], &end, 0);
1118 }
1119 propName = Tk_InternAtom((Tk_Window) winPtr, argv[3]);
1120 if (argc == 4) {
1121 property = NULL;
1122 result = XGetWindowProperty(winPtr->dispPtr->display,
1123 w, propName, 0, 100000, False, XA_STRING,
1124 &actualType, &actualFormat, (unsigned long *) &length,
1125 &bytesAfter, (unsigned char **) &property);
1126 if ((result == Success) && (actualType != None)
1127 && (actualFormat == 8) && (actualType == XA_STRING)) {
1128 for (p = property; (p-property) < length; p++) {
1129 if (*p == 0) {
1130 *p = '\n';
1131 }
1132 }
1133 Tcl_SetResult(interp, property, TCL_VOLATILE);
1134 }
1135 if (property != NULL) {
1136 XFree(property);
1137 }
1138 } else {
1139 if (argv[4][0] == 0) {
1140 XDeleteProperty(winPtr->dispPtr->display, w, propName);
1141 } else {
1142 for (p = argv[4]; *p != 0; p++) {
1143 if (*p == '\n') {
1144 *p = 0;
1145 }
1146 }
1147 XChangeProperty(winPtr->dispPtr->display,
1148 w, propName, XA_STRING, 8, PropModeReplace,
1149 (unsigned char *) argv[4], p-argv[4]);
1150 }
1151 }
1152 } else if (strcmp(argv[1], "serial") == 0) {
1153 sprintf(interp->result, "%d", tkSendSerial+1);
1154 } else {
1155 Tcl_AppendResult(interp, "bad option \"", argv[1],
1156 "\": must be bogus, prop, or serial", (char *) NULL);
1157 return TCL_ERROR;
1158 }
1159 #endif
1160 return TCL_OK;
1161 }
1162