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