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