blob: 3f472bb333259de885353d6a9f13df50f7a334f9 [file] [log] [blame]
Guido van Rossum85a5fbb1990-10-14 12:07:46 +00001/* Stdwin module */
2
3/* Stdwin itself is a module, not a separate object type.
4 Object types defined here:
5 wp: a window
6 dp: a drawing structure (only one can exist at a time)
7 mp: a menu
8 tp: a textedit block
9*/
10
11/* Rules for translating C stdwin function calls into Python stwin:
12 - All names drop their initial letter 'w'
13 - Functions with a window as first parameter are methods of window objects
14 - There is no equivalent for wclose(); just delete the window object
15 (all references to it!) (XXX maybe this is a bad idea)
16 - w.begindrawing() returns a drawing object
17 - There is no equivalent for wenddrawing(win); just delete the drawing
18 object (all references to it!) (XXX maybe this is a bad idea)
19 - Functions that may only be used inside wbegindrawing / wendddrawing
20 are methods of the drawing object; this includes the text measurement
21 functions (which however have doubles as module functions).
22 - Methods of the drawing object drop an initial 'draw' from their name
23 if they have it, e.g., wdrawline() --> d.line()
24 - The obvious type conversions: int --> intobject; string --> stringobject
25 - A text parameter followed by a length parameter is only a text (string)
26 parameter in Python
27 - A point or other pair of horizontal and vertical coordinates is always
28 a pair of integers in Python
29 - Two points forming a rectangle or endpoints of a line segment are a
30 pair of points in Python
31 - The arguments to d.elarc() are three points.
32 - The functions wgetclip() and wsetclip() are translated into
33 stdwin.getcutbuffer() and stdwin.setcutbuffer(); 'clip' is really
34 a bad word for what these functions do (clipping has a different
35 meaning in the drawing world), while cutbuffer is standard X jargon.
36 - For textedit, similar rules hold, but they are less strict.
37 XXX more?
38*/
39
40#include <stdio.h>
41#include "stdwin.h"
42
43#include "PROTO.h"
44#include "object.h"
45#include "intobject.h"
46#include "stringobject.h"
47#include "tupleobject.h"
48#include "dictobject.h"
49#include "methodobject.h"
50#include "moduleobject.h"
51#include "objimpl.h"
52#include "import.h"
53#include "modsupport.h"
54#include "errors.h"
55
56
57/* Window and menu object types declared here because of forward references */
58
59typedef struct {
60 OB_HEAD
61 object *w_title;
62 WINDOW *w_win;
63 object *w_attr; /* Attributes dictionary */
64} windowobject;
65
66extern typeobject Windowtype; /* Really static, forward */
67
68#define is_windowobject(wp) ((wp)->ob_type == &Windowtype)
69
70typedef struct {
71 OB_HEAD
72 MENU *m_menu;
73 int m_id;
74 object *m_attr; /* Attributes dictionary */
75} menuobject;
76
77extern typeobject Menutype; /* Really static, forward */
78
79#define is_menuobject(mp) ((mp)->ob_type == &Menutype)
80
81
82/* Strongly stdwin-specific argument handlers */
83
84static int
85getmousedetail(v, ep)
86 object *v;
87 EVENT *ep;
88{
89 if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 4)
90 return err_badarg();
91 return getintintarg(gettupleitem(v, 0),
92 &ep->u.where.h, &ep->u.where.v) &&
93 getintarg(gettupleitem(v, 1), &ep->u.where.clicks) &&
94 getintarg(gettupleitem(v, 2), &ep->u.where.button) &&
95 getintarg(gettupleitem(v, 3), &ep->u.where.mask);
96}
97
98static int
99getmenudetail(v, ep)
100 object *v;
101 EVENT *ep;
102{
103 object *mp;
104 if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2)
105 return err_badarg();
106 mp = gettupleitem(v, 0);
107 if (mp == NULL || !is_menuobject(mp))
108 return err_badarg();
109 ep->u.m.id = ((menuobject *)mp) -> m_id;
110 return getintarg(gettupleitem(v, 1), &ep->u.m.item);
111}
112
113static int
114geteventarg(v, ep)
115 object *v;
116 EVENT *ep;
117{
118 object *wp, *detail;
119 int a[4];
120 if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 3)
121 return err_badarg();
122 if (!getintarg(gettupleitem(v, 0), &ep->type))
123 return 0;
124 wp = gettupleitem(v, 1);
125 if (wp == None)
126 ep->window = NULL;
127 else if (wp == NULL || !is_windowobject(wp))
128 return err_badarg();
129 else
130 ep->window = ((windowobject *)wp) -> w_win;
131 detail = gettupleitem(v, 2);
132 switch (ep->type) {
133 case WE_CHAR:
134 if (!is_stringobject(detail) || getstringsize(detail) != 1)
135 return err_badarg();
136 ep->u.character = getstringvalue(detail)[0];
137 return 1;
138 case WE_COMMAND:
139 return getintarg(detail, &ep->u.command);
140 case WE_DRAW:
141 if (!getrectarg(detail, a))
142 return 0;
143 ep->u.area.left = a[0];
144 ep->u.area.top = a[1];
145 ep->u.area.right = a[2];
146 ep->u.area.bottom = a[3];
147 return 1;
148 case WE_MOUSE_DOWN:
149 case WE_MOUSE_UP:
150 case WE_MOUSE_MOVE:
151 return getmousedetail(detail, ep);
152 case WE_MENU:
153 return getmenudetail(detail, ep);
154 default:
155 return 1;
156 }
157}
158
159
160/* Return construction tools */
161
162static object *
163makepoint(a, b)
164 int a, b;
165{
166 object *v;
167 object *w;
168 if ((v = newtupleobject(2)) == NULL)
169 return NULL;
170 if ((w = newintobject((long)a)) == NULL ||
171 settupleitem(v, 0, w) != 0 ||
172 (w = newintobject((long)b)) == NULL ||
173 settupleitem(v, 1, w) != 0) {
174 DECREF(v);
175 return NULL;
176 }
177 return v;
178}
179
180static object *
181makerect(a, b, c, d)
182 int a, b, c, d;
183{
184 object *v;
185 object *w;
186 if ((v = newtupleobject(2)) == NULL)
187 return NULL;
188 if ((w = makepoint(a, b)) == NULL ||
189 settupleitem(v, 0, w) != 0 ||
190 (w = makepoint(c, d)) == NULL ||
191 settupleitem(v, 1, w) != 0) {
192 DECREF(v);
193 return NULL;
194 }
195 return v;
196}
197
198static object *
199makemouse(hor, ver, clicks, button, mask)
200 int hor, ver, clicks, button, mask;
201{
202 object *v;
203 object *w;
204 if ((v = newtupleobject(4)) == NULL)
205 return NULL;
206 if ((w = makepoint(hor, ver)) == NULL ||
207 settupleitem(v, 0, w) != 0 ||
208 (w = newintobject((long)clicks)) == NULL ||
209 settupleitem(v, 1, w) != 0 ||
210 (w = newintobject((long)button)) == NULL ||
211 settupleitem(v, 2, w) != 0 ||
212 (w = newintobject((long)mask)) == NULL ||
213 settupleitem(v, 3, w) != 0) {
214 DECREF(v);
215 return NULL;
216 }
217 return v;
218}
219
220static object *
221makemenu(mp, item)
222 object *mp;
223 int item;
224{
225 object *v;
226 object *w;
227 if ((v = newtupleobject(2)) == NULL)
228 return NULL;
229 INCREF(mp);
230 if (settupleitem(v, 0, mp) != 0 ||
231 (w = newintobject((long)item)) == NULL ||
232 settupleitem(v, 1, w) != 0) {
233 DECREF(v);
234 return NULL;
235 }
236 return v;
237}
238
239
240/* Drawing objects */
241
242typedef struct {
243 OB_HEAD
244 windowobject *d_ref;
245} drawingobject;
246
247static drawingobject *Drawing; /* Set to current drawing object, or NULL */
248
249/* Drawing methods */
250
251static void
252drawing_dealloc(dp)
253 drawingobject *dp;
254{
255 wenddrawing(dp->d_ref->w_win);
256 Drawing = NULL;
257 DECREF(dp->d_ref);
258 free((char *)dp);
259}
260
261static object *
262drawing_generic(dp, args, func)
263 drawingobject *dp;
264 object *args;
265 void (*func) FPROTO((int, int, int, int));
266{
267 int a[4];
268 if (!getrectarg(args, a))
269 return NULL;
270 (*func)(a[0], a[1], a[2], a[3]);
271 INCREF(None);
272 return None;
273}
274
275static object *
276drawing_line(dp, args)
277 drawingobject *dp;
278 object *args;
279{
280 drawing_generic(dp, args, wdrawline);
281}
282
283static object *
284drawing_xorline(dp, args)
285 drawingobject *dp;
286 object *args;
287{
288 drawing_generic(dp, args, wxorline);
289}
290
291static object *
292drawing_circle(dp, args)
293 drawingobject *dp;
294 object *args;
295{
296 int a[3];
297 if (!getpointintarg(args, a))
298 return NULL;
299 wdrawcircle(a[0], a[1], a[2]);
300 INCREF(None);
301 return None;
302}
303
304static object *
305drawing_elarc(dp, args)
306 drawingobject *dp;
307 object *args;
308{
309 int a[6];
310 if (!get3pointarg(args, a))
311 return NULL;
312 wdrawelarc(a[0], a[1], a[2], a[3], a[4], a[5]);
313 INCREF(None);
314 return None;
315}
316
317static object *
318drawing_box(dp, args)
319 drawingobject *dp;
320 object *args;
321{
322 drawing_generic(dp, args, wdrawbox);
323}
324
325static object *
326drawing_erase(dp, args)
327 drawingobject *dp;
328 object *args;
329{
330 drawing_generic(dp, args, werase);
331}
332
333static object *
334drawing_paint(dp, args)
335 drawingobject *dp;
336 object *args;
337{
338 drawing_generic(dp, args, wpaint);
339}
340
341static object *
342drawing_invert(dp, args)
343 drawingobject *dp;
344 object *args;
345{
346 drawing_generic(dp, args, winvert);
347}
348
349static object *
350drawing_cliprect(dp, args)
351 drawingobject *dp;
352 object *args;
353{
354 drawing_generic(dp, args, wcliprect);
355}
356
357static object *
358drawing_noclip(dp, args)
359 drawingobject *dp;
360 object *args;
361{
362 if (!getnoarg(args))
363 return NULL;
364 wnoclip();
365 INCREF(None);
366 return None;
367}
368
369static object *
370drawing_shade(dp, args)
371 drawingobject *dp;
372 object *args;
373{
374 int a[5];
375 if (!getrectintarg(args, a))
376 return NULL;
377 wshade(a[0], a[1], a[2], a[3], a[4]);
378 INCREF(None);
379 return None;
380}
381
382static object *
383drawing_text(dp, args)
384 drawingobject *dp;
385 object *args;
386{
387 int a[2];
388 object *s;
389 if (!getpointstrarg(args, a, &s))
390 return NULL;
391 wdrawtext(a[0], a[1], getstringvalue(s), (int)getstringsize(s));
392 INCREF(None);
393 return None;
394}
395
396/* The following four are also used as stdwin functions */
397
398static object *
399drawing_lineheight(dp, args)
400 drawingobject *dp;
401 object *args;
402{
403 if (!getnoarg(args))
404 return NULL;
405 return newintobject((long)wlineheight());
406}
407
408static object *
409drawing_baseline(dp, args)
410 drawingobject *dp;
411 object *args;
412{
413 if (!getnoarg(args))
414 return NULL;
415 return newintobject((long)wbaseline());
416}
417
418static object *
419drawing_textwidth(dp, args)
420 drawingobject *dp;
421 object *args;
422{
423 object *s;
424 if (!getstrarg(args, &s))
425 return NULL;
426 return newintobject(
427 (long)wtextwidth(getstringvalue(s), (int)getstringsize(s)));
428}
429
430static object *
431drawing_textbreak(dp, args)
432 drawingobject *dp;
433 object *args;
434{
435 object *s;
436 int a;
437 if (!getstrintarg(args, &s, &a))
438 return NULL;
439 return newintobject(
440 (long)wtextbreak(getstringvalue(s), (int)getstringsize(s), a));
441}
442
443static struct methodlist drawing_methods[] = {
444 {"box", drawing_box},
445 {"circle", drawing_circle},
446 {"cliprect", drawing_cliprect},
447 {"elarc", drawing_elarc},
448 {"erase", drawing_erase},
449 {"invert", drawing_invert},
450 {"line", drawing_line},
451 {"noclip", drawing_noclip},
452 {"paint", drawing_paint},
453 {"shade", drawing_shade},
454 {"text", drawing_text},
455 {"xorline", drawing_xorline},
456
457 /* Text measuring methods: */
458 {"baseline", drawing_baseline},
459 {"lineheight", drawing_lineheight},
460 {"textbreak", drawing_textbreak},
461 {"textwidth", drawing_textwidth},
462 {NULL, NULL} /* sentinel */
463};
464
465static object *
466drawing_getattr(wp, name)
467 drawingobject *wp;
468 char *name;
469{
470 return findmethod(drawing_methods, (object *)wp, name);
471}
472
473static typeobject Drawingtype = {
474 OB_HEAD_INIT(&Typetype)
475 0, /*ob_size*/
476 "drawing", /*tp_name*/
477 sizeof(drawingobject), /*tp_size*/
478 0, /*tp_itemsize*/
479 /* methods */
480 drawing_dealloc, /*tp_dealloc*/
481 0, /*tp_print*/
482 drawing_getattr, /*tp_getattr*/
483 0, /*tp_setattr*/
484 0, /*tp_compare*/
485 0, /*tp_repr*/
486};
487
488
489/* Text(edit) objects */
490
491typedef struct {
492 OB_HEAD
493 TEXTEDIT *t_text;
494 windowobject *t_ref;
495 object *t_attr; /* Attributes dictionary */
496} textobject;
497
498extern typeobject Texttype; /* Really static, forward */
499
500static textobject *
501newtextobject(wp, left, top, right, bottom)
502 windowobject *wp;
503 int left, top, right, bottom;
504{
505 textobject *tp;
506 tp = NEWOBJ(textobject, &Texttype);
507 if (tp == NULL)
508 return NULL;
509 tp->t_attr = NULL;
510 INCREF(wp);
511 tp->t_ref = wp;
512 tp->t_text = tecreate(wp->w_win, left, top, right, bottom);
513 if (tp->t_text == NULL) {
514 DECREF(tp);
515 return (textobject *) err_nomem();
516 }
517 return tp;
518}
519
520/* Text(edit) methods */
521
522static void
523text_dealloc(tp)
524 textobject *tp;
525{
526 if (tp->t_text != NULL)
527 tefree(tp->t_text);
528 if (tp->t_attr != NULL)
529 DECREF(tp->t_attr);
530 DECREF(tp->t_ref);
531 DEL(tp);
532}
533
534static object *
535text_arrow(self, args)
536 textobject *self;
537 object *args;
538{
539 int code;
540 if (!getintarg(args, &code))
541 return NULL;
542 tearrow(self->t_text, code);
543 INCREF(None);
544 return None;
545}
546
547static object *
548text_draw(self, args)
549 textobject *self;
550 object *args;
551{
552 register TEXTEDIT *tp = self->t_text;
553 int a[4];
554 int left, top, right, bottom;
555 if (!getrectarg(args, a))
556 return NULL;
557 if (Drawing != NULL) {
558 err_setstr(RuntimeError, "not drawing");
559 return NULL;
560 }
561 /* Clip to text area and ignore if area is empty */
562 left = tegetleft(tp);
563 top = tegettop(tp);
564 right = tegetright(tp);
565 bottom = tegetbottom(tp);
566 if (a[0] < left) a[0] = left;
567 if (a[1] < top) a[1] = top;
568 if (a[2] > right) a[2] = right;
569 if (a[3] > bottom) a[3] = bottom;
570 if (a[0] < a[2] && a[1] < a[3]) {
571 /* Hide/show focus around draw call; these are undocumented,
572 but required here to get the highlighting correct.
573 The call to werase is also required for this reason.
574 Finally, this forces us to require (above) that we are NOT
575 already drawing. */
576 tehidefocus(tp);
577 wbegindrawing(self->t_ref->w_win);
578 werase(a[0], a[1], a[2], a[3]);
579 tedrawnew(tp, a[0], a[1], a[2], a[3]);
580 wenddrawing(self->t_ref->w_win);
581 teshowfocus(tp);
582 }
583 INCREF(None);
584 return None;
585}
586
587static object *
588text_event(self, args)
589 textobject *self;
590 object *args;
591{
592 register TEXTEDIT *tp = self->t_text;
593 EVENT e;
594 if (!geteventarg(args, &e))
595 return NULL;
596 if (e.type == WE_MOUSE_DOWN) {
597 /* Cheat at the left margin */
598 if (e.u.where.h < 0 && tegetleft(tp) == 0)
599 e.u.where.h = 0;
600 /* XXX should also check right margin and bottom,
601 but we have no wgetdocsize() yet */
602 }
603 return newintobject((long) teevent(tp, &e));
604}
605
606static object *
607text_getfocus(self, args)
608 textobject *self;
609 object *args;
610{
611 if (!getnoarg(args))
612 return NULL;
613 return makepoint(tegetfoc1(self->t_text), tegetfoc2(self->t_text));
614}
615
616static object *
617text_getfocustext(self, args)
618 textobject *self;
619 object *args;
620{
621 int f1, f2;
622 char *text;
623 if (!getnoarg(args))
624 return NULL;
625 f1 = tegetfoc1(self->t_text);
626 f2 = tegetfoc2(self->t_text);
627 text = tegettext(self->t_text);
628 return newsizedstringobject(text + f1, f2-f1);
629}
630
631static object *
632text_getrect(self, args)
633 textobject *self;
634 object *args;
635{
636 if (!getnoarg(args))
637 return NULL;
638 return makerect(tegetleft(self->t_text),
639 tegettop(self->t_text),
640 tegetright(self->t_text),
641 tegetbottom(self->t_text));
642}
643
644static object *
645text_gettext(self, args)
646 textobject *self;
647 object *args;
648{
649 if (!getnoarg(args))
650 return NULL;
651 return newsizedstringobject(tegettext(self->t_text),
652 tegetlen(self->t_text));
653}
654
655static object *
656text_move(self, args)
657 textobject *self;
658 object *args;
659{
660 int a[4];
661 if (!getrectarg(args, a))
662 return NULL;
663 temovenew(self->t_text, a[0], a[1], a[2], a[3]);
664 INCREF(None);
665 return None;
666}
667
668static object *
669text_setfocus(self, args)
670 textobject *self;
671 object *args;
672{
673 int a[2];
674 if (!getpointarg(args, a))
675 return NULL;
676 tesetfocus(self->t_text, a[0], a[1]);
677 INCREF(None);
678 return None;
679}
680
681static object *
682text_replace(self, args)
683 textobject *self;
684 object *args;
685{
686 object *text;
687 if (!getstrarg(args, &text))
688 return NULL;
689 tereplace(self->t_text, getstringvalue(text));
690 INCREF(None);
691 return None;
692}
693
694static struct methodlist text_methods[] = {
695 "arrow", text_arrow,
696 "draw", text_draw,
697 "event", text_event,
698 "getfocus", text_getfocus,
699 "getfocustext", text_getfocustext,
700 "getrect", text_getrect,
701 "gettext", text_gettext,
702 "move", text_move,
703 "replace", text_replace,
704 "setfocus", text_setfocus,
705 {NULL, NULL} /* sentinel */
706};
707
708static object *
709text_getattr(tp, name)
710 textobject *tp;
711 char *name;
712{
713 if (tp->t_attr != NULL) {
714 object *v = dictlookup(tp->t_attr, name);
715 if (v != NULL) {
716 INCREF(v);
717 return v;
718 }
719 }
720 return findmethod(text_methods, (object *)tp, name);
721}
722
723static int
724text_setattr(tp, name, v)
725 textobject *tp;
726 char *name;
727 object *v;
728{
729 if (tp->t_attr == NULL) {
730 tp->t_attr = newdictobject();
731 if (tp->t_attr == NULL)
732 return -1;
733 }
734 if (v == NULL)
735 return dictremove(tp->t_attr, name);
736 else
737 return dictinsert(tp->t_attr, name, v);
738}
739
740static typeobject Texttype = {
741 OB_HEAD_INIT(&Typetype)
742 0, /*ob_size*/
743 "textedit", /*tp_name*/
744 sizeof(textobject), /*tp_size*/
745 0, /*tp_itemsize*/
746 /* methods */
747 text_dealloc, /*tp_dealloc*/
748 0, /*tp_print*/
749 text_getattr, /*tp_getattr*/
750 text_setattr, /*tp_setattr*/
751 0, /*tp_compare*/
752 0, /*tp_repr*/
753};
754
755
756/* Menu objects */
757
758#define MAXNMENU 50
759static menuobject *menulist[MAXNMENU]; /* Slot 0 unused */
760
761static menuobject *
762newmenuobject(title)
763 object *title;
764{
765 int id;
766 MENU *menu;
767 menuobject *mp;
768 for (id = 1; id < MAXNMENU; id++) {
769 if (menulist[id] == NULL)
770 break;
771 }
772 if (id >= MAXNMENU)
773 return (menuobject *) err_nomem();
774 menu = wmenucreate(id, getstringvalue(title));
775 if (menu == NULL)
776 return (menuobject *) err_nomem();
777 mp = NEWOBJ(menuobject, &Menutype);
778 if (mp != NULL) {
779 mp->m_menu = menu;
780 mp->m_id = id;
781 mp->m_attr = NULL;
782 menulist[id] = mp;
783 }
784 else
785 wmenudelete(menu);
786 return mp;
787}
788
789/* Menu methods */
790
791static void
792menu_dealloc(mp)
793 menuobject *mp;
794{
795
796 int id = mp->m_id;
797 if (id >= 0 && id < MAXNMENU) {
798 menulist[id] = NULL;
799 }
800 wmenudelete(mp->m_menu);
801 if (mp->m_attr != NULL)
802 DECREF(mp->m_attr);
803 DEL(mp);
804}
805
806static object *
807menu_additem(self, args)
808 menuobject *self;
809 object *args;
810{
811 object *text;
812 int shortcut;
813 if (is_tupleobject(args)) {
814 object *v;
815 if (!getstrstrarg(args, &text, &v))
816 return NULL;
817 if (getstringsize(v) != 1) {
818 err_badarg();
819 return NULL;
820 }
821 shortcut = *getstringvalue(v) & 0xff;
822 }
823 else {
824 if (!getstrarg(args, &text))
825 return NULL;
826 shortcut = -1;
827 }
828 wmenuadditem(self->m_menu, getstringvalue(text), shortcut);
829 INCREF(None);
830 return None;
831}
832
833static object *
834menu_setitem(self, args)
835 menuobject *self;
836 object *args;
837{
838 int index;
839 object *text;
840 if (!getintstrarg(args, &index, &text))
841 return NULL;
842 wmenusetitem(self->m_menu, index, getstringvalue(text));
843 INCREF(None);
844 return None;
845}
846
847static object *
848menu_enable(self, args)
849 menuobject *self;
850 object *args;
851{
852 int index;
853 int flag;
854 if (!getintintarg(args, &index, &flag))
855 return NULL;
856 wmenuenable(self->m_menu, index, flag);
857 INCREF(None);
858 return None;
859}
860
861static object *
862menu_check(self, args)
863 menuobject *self;
864 object *args;
865{
866 int index;
867 int flag;
868 if (!getintintarg(args, &index, &flag))
869 return NULL;
870 wmenucheck(self->m_menu, index, flag);
871 INCREF(None);
872 return None;
873}
874
875static struct methodlist menu_methods[] = {
876 "additem", menu_additem,
877 "setitem", menu_setitem,
878 "enable", menu_enable,
879 "check", menu_check,
880 {NULL, NULL} /* sentinel */
881};
882
883static object *
884menu_getattr(mp, name)
885 menuobject *mp;
886 char *name;
887{
888 if (mp->m_attr != NULL) {
889 object *v = dictlookup(mp->m_attr, name);
890 if (v != NULL) {
891 INCREF(v);
892 return v;
893 }
894 }
895 return findmethod(menu_methods, (object *)mp, name);
896}
897
898static int
899menu_setattr(mp, name, v)
900 menuobject *mp;
901 char *name;
902 object *v;
903{
904 if (mp->m_attr == NULL) {
905 mp->m_attr = newdictobject();
906 if (mp->m_attr == NULL)
907 return -1;
908 }
909 if (v == NULL)
910 return dictremove(mp->m_attr, name);
911 else
912 return dictinsert(mp->m_attr, name, v);
913}
914
915static typeobject Menutype = {
916 OB_HEAD_INIT(&Typetype)
917 0, /*ob_size*/
918 "menu", /*tp_name*/
919 sizeof(menuobject), /*tp_size*/
920 0, /*tp_itemsize*/
921 /* methods */
922 menu_dealloc, /*tp_dealloc*/
923 0, /*tp_print*/
924 menu_getattr, /*tp_getattr*/
925 menu_setattr, /*tp_setattr*/
926 0, /*tp_compare*/
927 0, /*tp_repr*/
928};
929
930
931/* Windows */
932
933#define MAXNWIN 50
934static windowobject *windowlist[MAXNWIN];
935
936/* Window methods */
937
938static void
939window_dealloc(wp)
940 windowobject *wp;
941{
942 if (wp->w_win != NULL) {
943 int tag = wgettag(wp->w_win);
944 if (tag >= 0 && tag < MAXNWIN)
945 windowlist[tag] = NULL;
946 else
947 fprintf(stderr, "XXX help! tag %d in window_dealloc\n",
948 tag);
949 wclose(wp->w_win);
950 }
951 DECREF(wp->w_title);
952 if (wp->w_attr != NULL)
953 DECREF(wp->w_attr);
954 free((char *)wp);
955}
956
957static void
958window_print(wp, fp, flags)
959 windowobject *wp;
960 FILE *fp;
961 int flags;
962{
963 fprintf(fp, "<window titled '%s'>", getstringvalue(wp->w_title));
964}
965
966static object *
967window_begindrawing(wp, args)
968 windowobject *wp;
969 object *args;
970{
971 drawingobject *dp;
972 if (!getnoarg(args))
973 return NULL;
974 if (Drawing != NULL) {
975 err_setstr(RuntimeError, "already drawing");
976 return NULL;
977 }
978 dp = NEWOBJ(drawingobject, &Drawingtype);
979 if (dp == NULL)
980 return NULL;
981 Drawing = dp;
982 INCREF(wp);
983 dp->d_ref = wp;
984 wbegindrawing(wp->w_win);
985 return (object *)dp;
986}
987
988static object *
989window_change(wp, args)
990 windowobject *wp;
991 object *args;
992{
993 int a[4];
994 if (!getrectarg(args, a))
995 return NULL;
996 wchange(wp->w_win, a[0], a[1], a[2], a[3]);
997 INCREF(None);
998 return None;
999}
1000
1001static object *
1002window_gettitle(wp, args)
1003 windowobject *wp;
1004 object *args;
1005{
1006 if (!getnoarg(args))
1007 return NULL;
1008 INCREF(wp->w_title);
1009 return wp->w_title;
1010}
1011
1012static object *
1013window_getwinsize(wp, args)
1014 windowobject *wp;
1015 object *args;
1016{
1017 int width, height;
1018 if (!getnoarg(args))
1019 return NULL;
1020 wgetwinsize(wp->w_win, &width, &height);
1021 return makepoint(width, height);
1022}
1023
1024static object *
1025window_getdocsize(wp, args)
1026 windowobject *wp;
1027 object *args;
1028{
1029 int width, height;
1030 if (!getnoarg(args))
1031 return NULL;
1032 wgetdocsize(wp->w_win, &width, &height);
1033 return makepoint(width, height);
1034}
1035
1036static object *
1037window_getorigin(wp, args)
1038 windowobject *wp;
1039 object *args;
1040{
1041 int width, height;
1042 if (!getnoarg(args))
1043 return NULL;
1044 wgetorigin(wp->w_win, &width, &height);
1045 return makepoint(width, height);
1046}
1047
1048static object *
1049window_scroll(wp, args)
1050 windowobject *wp;
1051 object *args;
1052{
1053 int a[6];
1054 if (!getrectpointarg(args, a))
1055 return NULL;
1056 wscroll(wp->w_win, a[0], a[1], a[2], a[3], a[4], a[5]);
1057 INCREF(None);
1058 return None;
1059}
1060
1061static object *
1062window_setdocsize(wp, args)
1063 windowobject *wp;
1064 object *args;
1065{
1066 int a[2];
1067 if (!getpointarg(args, a))
1068 return NULL;
1069 wsetdocsize(wp->w_win, a[0], a[1]);
1070 INCREF(None);
1071 return None;
1072}
1073
1074static object *
1075window_setorigin(wp, args)
1076 windowobject *wp;
1077 object *args;
1078{
1079 int a[2];
1080 if (!getpointarg(args, a))
1081 return NULL;
1082 wsetorigin(wp->w_win, a[0], a[1]);
1083 INCREF(None);
1084 return None;
1085}
1086
1087static object *
1088window_settitle(wp, args)
1089 windowobject *wp;
1090 object *args;
1091{
1092 object *title;
1093 if (!getstrarg(args, &title))
1094 return NULL;
1095 DECREF(wp->w_title);
1096 INCREF(title);
1097 wp->w_title = title;
1098 wsettitle(wp->w_win, getstringvalue(title));
1099 INCREF(None);
1100 return None;
1101}
1102
1103static object *
1104window_show(wp, args)
1105 windowobject *wp;
1106 object *args;
1107{
1108 int a[4];
1109 if (!getrectarg(args, a))
1110 return NULL;
1111 wshow(wp->w_win, a[0], a[1], a[2], a[3]);
1112 INCREF(None);
1113 return None;
1114}
1115
1116static object *
1117window_settimer(wp, args)
1118 windowobject *wp;
1119 object *args;
1120{
1121 int a;
1122 if (!getintarg(args, &a))
1123 return NULL;
1124 wsettimer(wp->w_win, a);
1125 INCREF(None);
1126 return None;
1127}
1128
1129static object *
1130window_menucreate(self, args)
1131 windowobject *self;
1132 object *args;
1133{
1134 menuobject *mp;
1135 object *title;
1136 if (!getstrarg(args, &title))
1137 return NULL;
1138 wmenusetdeflocal(1);
1139 mp = newmenuobject(title);
1140 if (mp == NULL)
1141 return NULL;
1142 wmenuattach(self->w_win, mp->m_menu);
1143 return (object *)mp;
1144}
1145
1146static object *
1147window_textcreate(self, args)
1148 windowobject *self;
1149 object *args;
1150{
1151 textobject *tp;
1152 int a[4];
1153 if (!getrectarg(args, a))
1154 return NULL;
1155 return (object *)
1156 newtextobject(self, a[0], a[1], a[2], a[3]);
1157}
1158
1159static struct methodlist window_methods[] = {
1160 {"begindrawing",window_begindrawing},
1161 {"change", window_change},
1162 {"getdocsize", window_getdocsize},
1163 {"getorigin", window_getorigin},
1164 {"gettitle", window_gettitle},
1165 {"getwinsize", window_getwinsize},
1166 {"menucreate", window_menucreate},
1167 {"scroll", window_scroll},
1168 {"setdocsize", window_setdocsize},
1169 {"setorigin", window_setorigin},
1170 {"settimer", window_settimer},
1171 {"settitle", window_settitle},
1172 {"show", window_show},
1173 {"textcreate", window_textcreate},
1174 {NULL, NULL} /* sentinel */
1175};
1176
1177static object *
1178window_getattr(wp, name)
1179 windowobject *wp;
1180 char *name;
1181{
1182 if (wp->w_attr != NULL) {
1183 object *v = dictlookup(wp->w_attr, name);
1184 if (v != NULL) {
1185 INCREF(v);
1186 return v;
1187 }
1188 }
1189 return findmethod(window_methods, (object *)wp, name);
1190}
1191
1192static int
1193window_setattr(wp, name, v)
1194 windowobject *wp;
1195 char *name;
1196 object *v;
1197{
1198 if (wp->w_attr == NULL) {
1199 wp->w_attr = newdictobject();
1200 if (wp->w_attr == NULL)
1201 return -1;
1202 }
1203 if (v == NULL)
1204 return dictremove(wp->w_attr, name);
1205 else
1206 return dictinsert(wp->w_attr, name, v);
1207}
1208
1209static typeobject Windowtype = {
1210 OB_HEAD_INIT(&Typetype)
1211 0, /*ob_size*/
1212 "window", /*tp_name*/
1213 sizeof(windowobject), /*tp_size*/
1214 0, /*tp_itemsize*/
1215 /* methods */
1216 window_dealloc, /*tp_dealloc*/
1217 window_print, /*tp_print*/
1218 window_getattr, /*tp_getattr*/
1219 window_setattr, /*tp_setattr*/
1220 0, /*tp_compare*/
1221 0, /*tp_repr*/
1222};
1223
1224/* Stdwin methods */
1225
1226static object *
1227stdwin_open(sw, args)
1228 object *sw;
1229 object *args;
1230{
1231 int tag;
1232 object *title;
1233 windowobject *wp;
1234 if (!getstrarg(args, &title))
1235 return NULL;
1236 for (tag = 0; tag < MAXNWIN; tag++) {
1237 if (windowlist[tag] == NULL)
1238 break;
1239 }
1240 if (tag >= MAXNWIN)
1241 return err_nomem();
1242 wp = NEWOBJ(windowobject, &Windowtype);
1243 if (wp == NULL)
1244 return NULL;
1245 INCREF(title);
1246 wp->w_title = title;
1247 wp->w_win = wopen(getstringvalue(title), (void (*)()) NULL);
1248 wp->w_attr = NULL;
1249 if (wp->w_win == NULL) {
1250 DECREF(wp);
1251 return NULL;
1252 }
1253 windowlist[tag] = wp;
1254 wsettag(wp->w_win, tag);
1255 return (object *)wp;
1256}
1257
1258static object *
1259stdwin_getevent(sw, args)
1260 object *sw;
1261 object *args;
1262{
1263 EVENT e;
1264 object *v, *w;
1265 if (!getnoarg(args))
1266 return NULL;
1267 if (Drawing != NULL) {
1268 err_setstr(RuntimeError, "cannot getevent() while drawing");
1269 return NULL;
1270 }
1271 again:
1272 wgetevent(&e);
1273 if (e.type == WE_COMMAND && e.u.command == WC_CANCEL) {
1274 /* Turn keyboard interrupts into exceptions */
1275 err_set(KeyboardInterrupt);
1276 return NULL;
1277 }
1278 if (e.window == NULL && (e.type == WE_COMMAND || e.type == WE_CHAR))
1279 goto again;
1280 v = newtupleobject(3);
1281 if (v == NULL)
1282 return NULL;
1283 if ((w = newintobject((long)e.type)) == NULL) {
1284 DECREF(v);
1285 return NULL;
1286 }
1287 settupleitem(v, 0, w);
1288 if (e.window == NULL)
1289 w = None;
1290 else {
1291 int tag = wgettag(e.window);
1292 if (tag < 0 || tag >= MAXNWIN || windowlist[tag] == NULL)
1293 w = None;
1294 else
1295 w = (object *)windowlist[tag];
1296 }
1297if ((long)w == (long)0x80000001) {
1298err_setstr(SystemError, "bad pointer in stdwin.getevent()");
1299return NULL;
1300}
1301 INCREF(w);
1302 settupleitem(v, 1, w);
1303 switch (e.type) {
1304 case WE_CHAR:
1305 {
1306 char c[1];
1307 c[0] = e.u.character;
1308 w = newsizedstringobject(c, 1);
1309 }
1310 break;
1311 case WE_COMMAND:
1312 w = newintobject((long)e.u.command);
1313 break;
1314 case WE_DRAW:
1315 w = makerect(e.u.area.left, e.u.area.top,
1316 e.u.area.right, e.u.area.bottom);
1317 break;
1318 case WE_MOUSE_DOWN:
1319 case WE_MOUSE_MOVE:
1320 case WE_MOUSE_UP:
1321 w = makemouse(e.u.where.h, e.u.where.v,
1322 e.u.where.clicks,
1323 e.u.where.button,
1324 e.u.where.mask);
1325 break;
1326 case WE_MENU:
1327 if (e.u.m.id >= 0 && e.u.m.id < MAXNMENU &&
1328 menulist[e.u.m.id] != NULL)
1329 w = (object *)menulist[e.u.m.id];
1330 else
1331 w = None;
1332 w = makemenu(w, e.u.m.item);
1333 break;
1334 default:
1335 w = None;
1336 INCREF(w);
1337 break;
1338 }
1339 if (w == NULL) {
1340 DECREF(v);
1341 return NULL;
1342 }
1343 settupleitem(v, 2, w);
1344 return v;
1345}
1346
1347static object *
1348stdwin_setdefwinpos(sw, args)
1349 object *sw;
1350 object *args;
1351{
1352 int a[2];
1353 if (!getpointarg(args, a))
1354 return NULL;
1355 wsetdefwinpos(a[0], a[1]);
1356 INCREF(None);
1357 return None;
1358}
1359
1360static object *
1361stdwin_setdefwinsize(sw, args)
1362 object *sw;
1363 object *args;
1364{
1365 int a[2];
1366 if (!getpointarg(args, a))
1367 return NULL;
1368 wsetdefwinsize(a[0], a[1]);
1369 INCREF(None);
1370 return None;
1371}
1372
1373static object *
1374stdwin_menucreate(self, args)
1375 object *self;
1376 object *args;
1377{
1378 object *title;
1379 if (!getstrarg(args, &title))
1380 return NULL;
1381 wmenusetdeflocal(0);
1382 return (object *)newmenuobject(title);
1383}
1384
1385static object *
1386stdwin_askfile(self, args)
1387 object *self;
1388 object *args;
1389{
1390 object *prompt, *dflt;
1391 int new, ret;
1392 char buf[256];
1393 if (!getstrstrintarg(args, &prompt, &dflt, &new))
1394 return NULL;
1395 strncpy(buf, getstringvalue(dflt), sizeof buf);
1396 buf[sizeof buf - 1] = '\0';
1397 ret = waskfile(getstringvalue(prompt), buf, sizeof buf, new);
1398 if (!ret) {
1399 err_set(KeyboardInterrupt);
1400 return NULL;
1401 }
1402 return newstringobject(buf);
1403}
1404
1405static object *
1406stdwin_askync(self, args)
1407 object *self;
1408 object *args;
1409{
1410 object *prompt;
1411 int new, ret;
1412 if (!getstrintarg(args, &prompt, &new))
1413 return NULL;
1414 ret = waskync(getstringvalue(prompt), new);
1415 if (ret < 0) {
1416 err_set(KeyboardInterrupt);
1417 return NULL;
1418 }
1419 return newintobject((long)ret);
1420}
1421
1422static object *
1423stdwin_askstr(self, args)
1424 object *self;
1425 object *args;
1426{
1427 object *prompt, *dflt;
1428 int ret;
1429 char buf[256];
1430 if (!getstrstrarg(args, &prompt, &dflt))
1431 return NULL;
1432 strncpy(buf, getstringvalue(dflt), sizeof buf);
1433 buf[sizeof buf - 1] = '\0';
1434 ret = waskstr(getstringvalue(prompt), buf, sizeof buf);
1435 if (!ret) {
1436 err_set(KeyboardInterrupt);
1437 return NULL;
1438 }
1439 return newstringobject(buf);
1440}
1441
1442static object *
1443stdwin_message(self, args)
1444 object *self;
1445 object *args;
1446{
1447 object *msg;
1448 if (!getstrarg(args, &msg))
1449 return NULL;
1450 wmessage(getstringvalue(msg));
1451 INCREF(None);
1452 return None;
1453}
1454
1455static object *
1456stdwin_fleep(self, args)
1457 object *self;
1458 object *args;
1459{
1460 if (!getnoarg(args))
1461 return NULL;
1462 wfleep();
1463 INCREF(None);
1464 return None;
1465}
1466
1467static object *
1468stdwin_setcutbuffer(self, args)
1469 object *self;
1470 object *args;
1471{
1472 object *str;
1473 if (!getstrarg(args, &str))
1474 return NULL;
1475 wsetclip(getstringvalue(str), getstringsize(str));
1476 INCREF(None);
1477 return None;
1478}
1479
1480static object *
1481stdwin_getcutbuffer(self, args)
1482 object *self;
1483 object *args;
1484{
1485 char *str;
1486 if (!getnoarg(args))
1487 return NULL;
1488 str = wgetclip();
1489 if (str == NULL)
1490 str = "";
1491 return newstringobject(str);
1492}
1493
1494static struct methodlist stdwin_methods[] = {
1495 {"askfile", stdwin_askfile},
1496 {"askstr", stdwin_askstr},
1497 {"askync", stdwin_askync},
1498 {"fleep", stdwin_fleep},
1499 {"getcutbuffer", stdwin_getcutbuffer},
1500 {"getevent", stdwin_getevent},
1501 {"menucreate", stdwin_menucreate},
1502 {"message", stdwin_message},
1503 {"open", stdwin_open},
1504 {"setcutbuffer", stdwin_setcutbuffer},
1505 {"setdefwinpos", stdwin_setdefwinpos},
1506 {"setdefwinsize", stdwin_setdefwinsize},
1507
1508 /* Text measuring methods borrow code from drawing objects: */
1509 {"baseline", drawing_baseline},
1510 {"lineheight", drawing_lineheight},
1511 {"textbreak", drawing_textbreak},
1512 {"textwidth", drawing_textwidth},
1513 {NULL, NULL} /* sentinel */
1514};
1515
1516void
1517initstdwin()
1518{
1519 initmodule("stdwin", stdwin_methods);
1520}