blob: da511ec54f15f921c643d0bf994139cd871e3e78 [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 *
1285stdwin_getevent(sw, args)
1286 object *sw;
1287 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 }
1297 again:
1298 wgetevent(&e);
1299 if (e.type == WE_COMMAND && e.u.command == WC_CANCEL) {
1300 /* Turn keyboard interrupts into exceptions */
1301 err_set(KeyboardInterrupt);
1302 return NULL;
1303 }
1304 if (e.window == NULL && (e.type == WE_COMMAND || e.type == WE_CHAR))
1305 goto again;
Guido van Rossum124967c1990-11-06 15:17:35 +00001306 if (e.type == WE_COMMAND && e.u.command == WC_CLOSE) {
1307 /* Turn WC_CLOSE commands into WE_CLOSE events */
1308 e.type = WE_CLOSE;
1309 }
Guido van Rossum85a5fbb1990-10-14 12:07:46 +00001310 v = newtupleobject(3);
1311 if (v == NULL)
1312 return NULL;
1313 if ((w = newintobject((long)e.type)) == NULL) {
1314 DECREF(v);
1315 return NULL;
1316 }
1317 settupleitem(v, 0, w);
1318 if (e.window == NULL)
1319 w = None;
1320 else {
1321 int tag = wgettag(e.window);
1322 if (tag < 0 || tag >= MAXNWIN || windowlist[tag] == NULL)
1323 w = None;
1324 else
1325 w = (object *)windowlist[tag];
1326 }
1327if ((long)w == (long)0x80000001) {
1328err_setstr(SystemError, "bad pointer in stdwin.getevent()");
1329return NULL;
1330}
1331 INCREF(w);
1332 settupleitem(v, 1, w);
1333 switch (e.type) {
1334 case WE_CHAR:
1335 {
1336 char c[1];
1337 c[0] = e.u.character;
1338 w = newsizedstringobject(c, 1);
1339 }
1340 break;
1341 case WE_COMMAND:
1342 w = newintobject((long)e.u.command);
1343 break;
1344 case WE_DRAW:
1345 w = makerect(e.u.area.left, e.u.area.top,
1346 e.u.area.right, e.u.area.bottom);
1347 break;
1348 case WE_MOUSE_DOWN:
1349 case WE_MOUSE_MOVE:
1350 case WE_MOUSE_UP:
1351 w = makemouse(e.u.where.h, e.u.where.v,
1352 e.u.where.clicks,
1353 e.u.where.button,
1354 e.u.where.mask);
1355 break;
1356 case WE_MENU:
1357 if (e.u.m.id >= 0 && e.u.m.id < MAXNMENU &&
1358 menulist[e.u.m.id] != NULL)
1359 w = (object *)menulist[e.u.m.id];
1360 else
1361 w = None;
1362 w = makemenu(w, e.u.m.item);
1363 break;
Guido van Rossum5b10f451990-10-30 16:01:48 +00001364 case WE_LOST_SEL:
1365 w = newintobject((long)e.u.sel);
1366 break;
Guido van Rossum85a5fbb1990-10-14 12:07:46 +00001367 default:
1368 w = None;
1369 INCREF(w);
1370 break;
1371 }
1372 if (w == NULL) {
1373 DECREF(v);
1374 return NULL;
1375 }
1376 settupleitem(v, 2, w);
1377 return v;
1378}
1379
1380static object *
1381stdwin_setdefwinpos(sw, args)
1382 object *sw;
1383 object *args;
1384{
1385 int a[2];
1386 if (!getpointarg(args, a))
1387 return NULL;
1388 wsetdefwinpos(a[0], a[1]);
1389 INCREF(None);
1390 return None;
1391}
1392
1393static object *
1394stdwin_setdefwinsize(sw, args)
1395 object *sw;
1396 object *args;
1397{
1398 int a[2];
1399 if (!getpointarg(args, a))
1400 return NULL;
1401 wsetdefwinsize(a[0], a[1]);
1402 INCREF(None);
1403 return None;
1404}
1405
1406static object *
1407stdwin_menucreate(self, args)
1408 object *self;
1409 object *args;
1410{
1411 object *title;
1412 if (!getstrarg(args, &title))
1413 return NULL;
1414 wmenusetdeflocal(0);
1415 return (object *)newmenuobject(title);
1416}
1417
1418static object *
1419stdwin_askfile(self, args)
1420 object *self;
1421 object *args;
1422{
1423 object *prompt, *dflt;
1424 int new, ret;
1425 char buf[256];
1426 if (!getstrstrintarg(args, &prompt, &dflt, &new))
1427 return NULL;
1428 strncpy(buf, getstringvalue(dflt), sizeof buf);
1429 buf[sizeof buf - 1] = '\0';
1430 ret = waskfile(getstringvalue(prompt), buf, sizeof buf, new);
1431 if (!ret) {
1432 err_set(KeyboardInterrupt);
1433 return NULL;
1434 }
1435 return newstringobject(buf);
1436}
1437
1438static object *
1439stdwin_askync(self, args)
1440 object *self;
1441 object *args;
1442{
1443 object *prompt;
1444 int new, ret;
1445 if (!getstrintarg(args, &prompt, &new))
1446 return NULL;
1447 ret = waskync(getstringvalue(prompt), new);
1448 if (ret < 0) {
1449 err_set(KeyboardInterrupt);
1450 return NULL;
1451 }
1452 return newintobject((long)ret);
1453}
1454
1455static object *
1456stdwin_askstr(self, args)
1457 object *self;
1458 object *args;
1459{
1460 object *prompt, *dflt;
1461 int ret;
1462 char buf[256];
1463 if (!getstrstrarg(args, &prompt, &dflt))
1464 return NULL;
1465 strncpy(buf, getstringvalue(dflt), sizeof buf);
1466 buf[sizeof buf - 1] = '\0';
1467 ret = waskstr(getstringvalue(prompt), buf, sizeof buf);
1468 if (!ret) {
1469 err_set(KeyboardInterrupt);
1470 return NULL;
1471 }
1472 return newstringobject(buf);
1473}
1474
1475static object *
1476stdwin_message(self, args)
1477 object *self;
1478 object *args;
1479{
1480 object *msg;
1481 if (!getstrarg(args, &msg))
1482 return NULL;
1483 wmessage(getstringvalue(msg));
1484 INCREF(None);
1485 return None;
1486}
1487
1488static object *
1489stdwin_fleep(self, args)
1490 object *self;
1491 object *args;
1492{
1493 if (!getnoarg(args))
1494 return NULL;
1495 wfleep();
1496 INCREF(None);
1497 return None;
1498}
1499
1500static object *
1501stdwin_setcutbuffer(self, args)
1502 object *self;
1503 object *args;
1504{
Guido van Rossum5b10f451990-10-30 16:01:48 +00001505 int i;
Guido van Rossum85a5fbb1990-10-14 12:07:46 +00001506 object *str;
Guido van Rossum124967c1990-11-06 15:17:35 +00001507 if (!getintstrarg(args, &i, &str))
1508 return NULL;
Guido van Rossum5b10f451990-10-30 16:01:48 +00001509 wsetcutbuffer(i, getstringvalue(str), getstringsize(str));
Guido van Rossum85a5fbb1990-10-14 12:07:46 +00001510 INCREF(None);
1511 return None;
1512}
1513
1514static object *
1515stdwin_getcutbuffer(self, args)
1516 object *self;
1517 object *args;
1518{
Guido van Rossum5b10f451990-10-30 16:01:48 +00001519 int i;
Guido van Rossum85a5fbb1990-10-14 12:07:46 +00001520 char *str;
Guido van Rossum01769f01990-10-30 13:39:00 +00001521 int len;
Guido van Rossum124967c1990-11-06 15:17:35 +00001522 if (!getintarg(args, &i))
Guido van Rossum85a5fbb1990-10-14 12:07:46 +00001523 return NULL;
Guido van Rossum5b10f451990-10-30 16:01:48 +00001524 str = wgetcutbuffer(i, &len);
Guido van Rossum01769f01990-10-30 13:39:00 +00001525 if (str == NULL) {
Guido van Rossum85a5fbb1990-10-14 12:07:46 +00001526 str = "";
Guido van Rossum01769f01990-10-30 13:39:00 +00001527 len = 0;
1528 }
1529 return newsizedstringobject(str, len);
Guido van Rossum85a5fbb1990-10-14 12:07:46 +00001530}
1531
Guido van Rossum5b10f451990-10-30 16:01:48 +00001532static object *
1533stdwin_rotatecutbuffers(self, args)
1534 object *self;
1535 object *args;
1536{
1537 int i;
1538 if (!getintarg(args, &i))
1539 return NULL;
1540 wrotatecutbuffers(i);
1541 INCREF(None);
1542 return None;
1543}
1544
1545static object *
1546stdwin_getselection(self, args)
1547 object *self;
1548 object *args;
1549{
1550 int sel;
1551 char *data;
1552 int len;
1553 if (!getintarg(args, &sel))
1554 return NULL;
1555 data = wgetselection(sel, &len);
1556 if (data == NULL) {
1557 data = "";
1558 len = 0;
1559 }
1560 return newsizedstringobject(data, len);
1561}
1562
1563static object *
1564stdwin_resetselection(self, args)
1565 object *self;
1566 object *args;
1567{
1568 int sel;
1569 if (!getintarg(args, &sel))
1570 return NULL;
1571 wresetselection(sel);
1572 INCREF(None);
1573 return None;
1574}
1575
Guido van Rossum85a5fbb1990-10-14 12:07:46 +00001576static struct methodlist stdwin_methods[] = {
1577 {"askfile", stdwin_askfile},
1578 {"askstr", stdwin_askstr},
1579 {"askync", stdwin_askync},
1580 {"fleep", stdwin_fleep},
Guido van Rossum5b10f451990-10-30 16:01:48 +00001581 {"getselection", stdwin_getselection},
Guido van Rossum85a5fbb1990-10-14 12:07:46 +00001582 {"getcutbuffer", stdwin_getcutbuffer},
1583 {"getevent", stdwin_getevent},
1584 {"menucreate", stdwin_menucreate},
1585 {"message", stdwin_message},
1586 {"open", stdwin_open},
Guido van Rossum5b10f451990-10-30 16:01:48 +00001587 {"resetselection", stdwin_resetselection},
1588 {"rotatecutbuffers", stdwin_rotatecutbuffers},
Guido van Rossum85a5fbb1990-10-14 12:07:46 +00001589 {"setcutbuffer", stdwin_setcutbuffer},
1590 {"setdefwinpos", stdwin_setdefwinpos},
1591 {"setdefwinsize", stdwin_setdefwinsize},
1592
1593 /* Text measuring methods borrow code from drawing objects: */
1594 {"baseline", drawing_baseline},
1595 {"lineheight", drawing_lineheight},
1596 {"textbreak", drawing_textbreak},
1597 {"textwidth", drawing_textwidth},
1598 {NULL, NULL} /* sentinel */
1599};
1600
1601void
1602initstdwin()
1603{
1604 initmodule("stdwin", stdwin_methods);
1605}