blob: 68162ce615ba3840caeb2178283ee447a41c39f5 [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
Guido van Rossum5b10f451990-10-30 16:01:48 +00001160static object *
1161window_setselection(self, args)
1162 windowobject *self;
1163 object *args;
1164{
1165 int sel;
1166 object *str;
1167 int ok;
1168 if (!getintstrarg(args, &sel, &str))
1169 return NULL;
1170 ok = wsetselection(self->w_win, sel,
1171 getstringvalue(str), (int)getstringsize(str));
1172 return newintobject(ok);
1173}
1174
1175static object *
1176window_setwincursor(self, args)
1177 windowobject *self;
1178 object *args;
1179{
1180 object *str;
1181 CURSOR *c;
1182 if (!getstrarg(args, &str))
1183 return NULL;
1184 c = wfetchcursor(getstringvalue(str));
1185 if (c == NULL) {
1186 err_setstr(RuntimeError, "no such cursor");
1187 return NULL;
1188 }
1189 wsetwincursor(self->w_win, c);
1190 INCREF(None);
1191 return None;
1192}
1193
Guido van Rossum85a5fbb1990-10-14 12:07:46 +00001194static struct methodlist window_methods[] = {
1195 {"begindrawing",window_begindrawing},
1196 {"change", window_change},
1197 {"getdocsize", window_getdocsize},
1198 {"getorigin", window_getorigin},
1199 {"gettitle", window_gettitle},
1200 {"getwinsize", window_getwinsize},
1201 {"menucreate", window_menucreate},
1202 {"scroll", window_scroll},
Guido van Rossum5b10f451990-10-30 16:01:48 +00001203 {"setwincursor",window_setwincursor},
Guido van Rossum85a5fbb1990-10-14 12:07:46 +00001204 {"setdocsize", window_setdocsize},
1205 {"setorigin", window_setorigin},
Guido van Rossum5b10f451990-10-30 16:01:48 +00001206 {"setselection",window_setselection},
Guido van Rossum85a5fbb1990-10-14 12:07:46 +00001207 {"settimer", window_settimer},
1208 {"settitle", window_settitle},
1209 {"show", window_show},
1210 {"textcreate", window_textcreate},
1211 {NULL, NULL} /* sentinel */
1212};
1213
1214static object *
1215window_getattr(wp, name)
1216 windowobject *wp;
1217 char *name;
1218{
1219 if (wp->w_attr != NULL) {
1220 object *v = dictlookup(wp->w_attr, name);
1221 if (v != NULL) {
1222 INCREF(v);
1223 return v;
1224 }
1225 }
1226 return findmethod(window_methods, (object *)wp, name);
1227}
1228
1229static int
1230window_setattr(wp, name, v)
1231 windowobject *wp;
1232 char *name;
1233 object *v;
1234{
1235 if (wp->w_attr == NULL) {
1236 wp->w_attr = newdictobject();
1237 if (wp->w_attr == NULL)
1238 return -1;
1239 }
1240 if (v == NULL)
1241 return dictremove(wp->w_attr, name);
1242 else
1243 return dictinsert(wp->w_attr, name, v);
1244}
1245
1246static typeobject Windowtype = {
1247 OB_HEAD_INIT(&Typetype)
1248 0, /*ob_size*/
1249 "window", /*tp_name*/
1250 sizeof(windowobject), /*tp_size*/
1251 0, /*tp_itemsize*/
1252 /* methods */
1253 window_dealloc, /*tp_dealloc*/
1254 window_print, /*tp_print*/
1255 window_getattr, /*tp_getattr*/
1256 window_setattr, /*tp_setattr*/
1257 0, /*tp_compare*/
1258 0, /*tp_repr*/
1259};
1260
1261/* Stdwin methods */
1262
1263static object *
1264stdwin_open(sw, args)
1265 object *sw;
1266 object *args;
1267{
1268 int tag;
1269 object *title;
1270 windowobject *wp;
1271 if (!getstrarg(args, &title))
1272 return NULL;
1273 for (tag = 0; tag < MAXNWIN; tag++) {
1274 if (windowlist[tag] == NULL)
1275 break;
1276 }
1277 if (tag >= MAXNWIN)
1278 return err_nomem();
1279 wp = NEWOBJ(windowobject, &Windowtype);
1280 if (wp == NULL)
1281 return NULL;
1282 INCREF(title);
1283 wp->w_title = title;
1284 wp->w_win = wopen(getstringvalue(title), (void (*)()) NULL);
1285 wp->w_attr = NULL;
1286 if (wp->w_win == NULL) {
1287 DECREF(wp);
1288 return NULL;
1289 }
1290 windowlist[tag] = wp;
1291 wsettag(wp->w_win, tag);
1292 return (object *)wp;
1293}
1294
1295static object *
1296stdwin_getevent(sw, args)
1297 object *sw;
1298 object *args;
1299{
1300 EVENT e;
1301 object *v, *w;
1302 if (!getnoarg(args))
1303 return NULL;
1304 if (Drawing != NULL) {
1305 err_setstr(RuntimeError, "cannot getevent() while drawing");
1306 return NULL;
1307 }
1308 again:
1309 wgetevent(&e);
1310 if (e.type == WE_COMMAND && e.u.command == WC_CANCEL) {
1311 /* Turn keyboard interrupts into exceptions */
1312 err_set(KeyboardInterrupt);
1313 return NULL;
1314 }
1315 if (e.window == NULL && (e.type == WE_COMMAND || e.type == WE_CHAR))
1316 goto again;
1317 v = newtupleobject(3);
1318 if (v == NULL)
1319 return NULL;
1320 if ((w = newintobject((long)e.type)) == NULL) {
1321 DECREF(v);
1322 return NULL;
1323 }
1324 settupleitem(v, 0, w);
1325 if (e.window == NULL)
1326 w = None;
1327 else {
1328 int tag = wgettag(e.window);
1329 if (tag < 0 || tag >= MAXNWIN || windowlist[tag] == NULL)
1330 w = None;
1331 else
1332 w = (object *)windowlist[tag];
1333 }
1334if ((long)w == (long)0x80000001) {
1335err_setstr(SystemError, "bad pointer in stdwin.getevent()");
1336return NULL;
1337}
1338 INCREF(w);
1339 settupleitem(v, 1, w);
1340 switch (e.type) {
1341 case WE_CHAR:
1342 {
1343 char c[1];
1344 c[0] = e.u.character;
1345 w = newsizedstringobject(c, 1);
1346 }
1347 break;
1348 case WE_COMMAND:
1349 w = newintobject((long)e.u.command);
1350 break;
1351 case WE_DRAW:
1352 w = makerect(e.u.area.left, e.u.area.top,
1353 e.u.area.right, e.u.area.bottom);
1354 break;
1355 case WE_MOUSE_DOWN:
1356 case WE_MOUSE_MOVE:
1357 case WE_MOUSE_UP:
1358 w = makemouse(e.u.where.h, e.u.where.v,
1359 e.u.where.clicks,
1360 e.u.where.button,
1361 e.u.where.mask);
1362 break;
1363 case WE_MENU:
1364 if (e.u.m.id >= 0 && e.u.m.id < MAXNMENU &&
1365 menulist[e.u.m.id] != NULL)
1366 w = (object *)menulist[e.u.m.id];
1367 else
1368 w = None;
1369 w = makemenu(w, e.u.m.item);
1370 break;
Guido van Rossum5b10f451990-10-30 16:01:48 +00001371 case WE_LOST_SEL:
1372 w = newintobject((long)e.u.sel);
1373 break;
Guido van Rossum85a5fbb1990-10-14 12:07:46 +00001374 default:
1375 w = None;
1376 INCREF(w);
1377 break;
1378 }
1379 if (w == NULL) {
1380 DECREF(v);
1381 return NULL;
1382 }
1383 settupleitem(v, 2, w);
1384 return v;
1385}
1386
1387static object *
1388stdwin_setdefwinpos(sw, args)
1389 object *sw;
1390 object *args;
1391{
1392 int a[2];
1393 if (!getpointarg(args, a))
1394 return NULL;
1395 wsetdefwinpos(a[0], a[1]);
1396 INCREF(None);
1397 return None;
1398}
1399
1400static object *
1401stdwin_setdefwinsize(sw, args)
1402 object *sw;
1403 object *args;
1404{
1405 int a[2];
1406 if (!getpointarg(args, a))
1407 return NULL;
1408 wsetdefwinsize(a[0], a[1]);
1409 INCREF(None);
1410 return None;
1411}
1412
1413static object *
1414stdwin_menucreate(self, args)
1415 object *self;
1416 object *args;
1417{
1418 object *title;
1419 if (!getstrarg(args, &title))
1420 return NULL;
1421 wmenusetdeflocal(0);
1422 return (object *)newmenuobject(title);
1423}
1424
1425static object *
1426stdwin_askfile(self, args)
1427 object *self;
1428 object *args;
1429{
1430 object *prompt, *dflt;
1431 int new, ret;
1432 char buf[256];
1433 if (!getstrstrintarg(args, &prompt, &dflt, &new))
1434 return NULL;
1435 strncpy(buf, getstringvalue(dflt), sizeof buf);
1436 buf[sizeof buf - 1] = '\0';
1437 ret = waskfile(getstringvalue(prompt), buf, sizeof buf, new);
1438 if (!ret) {
1439 err_set(KeyboardInterrupt);
1440 return NULL;
1441 }
1442 return newstringobject(buf);
1443}
1444
1445static object *
1446stdwin_askync(self, args)
1447 object *self;
1448 object *args;
1449{
1450 object *prompt;
1451 int new, ret;
1452 if (!getstrintarg(args, &prompt, &new))
1453 return NULL;
1454 ret = waskync(getstringvalue(prompt), new);
1455 if (ret < 0) {
1456 err_set(KeyboardInterrupt);
1457 return NULL;
1458 }
1459 return newintobject((long)ret);
1460}
1461
1462static object *
1463stdwin_askstr(self, args)
1464 object *self;
1465 object *args;
1466{
1467 object *prompt, *dflt;
1468 int ret;
1469 char buf[256];
1470 if (!getstrstrarg(args, &prompt, &dflt))
1471 return NULL;
1472 strncpy(buf, getstringvalue(dflt), sizeof buf);
1473 buf[sizeof buf - 1] = '\0';
1474 ret = waskstr(getstringvalue(prompt), buf, sizeof buf);
1475 if (!ret) {
1476 err_set(KeyboardInterrupt);
1477 return NULL;
1478 }
1479 return newstringobject(buf);
1480}
1481
1482static object *
1483stdwin_message(self, args)
1484 object *self;
1485 object *args;
1486{
1487 object *msg;
1488 if (!getstrarg(args, &msg))
1489 return NULL;
1490 wmessage(getstringvalue(msg));
1491 INCREF(None);
1492 return None;
1493}
1494
1495static object *
1496stdwin_fleep(self, args)
1497 object *self;
1498 object *args;
1499{
1500 if (!getnoarg(args))
1501 return NULL;
1502 wfleep();
1503 INCREF(None);
1504 return None;
1505}
1506
1507static object *
1508stdwin_setcutbuffer(self, args)
1509 object *self;
1510 object *args;
1511{
Guido van Rossum5b10f451990-10-30 16:01:48 +00001512 int i;
Guido van Rossum85a5fbb1990-10-14 12:07:46 +00001513 object *str;
Guido van Rossum5b10f451990-10-30 16:01:48 +00001514 /* Compatibility hack: setcutbuffer(str) === setcutbuffer(0, str) */
1515 if (args != NULL && !is_tupleobject(args)) {
1516 if (!getstrarg(args, &str))
1517 return NULL;
1518 }
1519 else {
1520 if (!getintstrarg(args, &i, &str))
1521 return NULL;
1522 }
1523 wsetcutbuffer(i, getstringvalue(str), getstringsize(str));
Guido van Rossum85a5fbb1990-10-14 12:07:46 +00001524 INCREF(None);
1525 return None;
1526}
1527
1528static object *
1529stdwin_getcutbuffer(self, args)
1530 object *self;
1531 object *args;
1532{
Guido van Rossum5b10f451990-10-30 16:01:48 +00001533 int i;
Guido van Rossum85a5fbb1990-10-14 12:07:46 +00001534 char *str;
Guido van Rossum01769f01990-10-30 13:39:00 +00001535 int len;
Guido van Rossum5b10f451990-10-30 16:01:48 +00001536 /* Compatibility hack: getcutbuffer() === getcutbuffer(0) */
1537 if (args == NULL)
1538 i = 0;
1539 else if (!getintarg(args, &i))
Guido van Rossum85a5fbb1990-10-14 12:07:46 +00001540 return NULL;
Guido van Rossum5b10f451990-10-30 16:01:48 +00001541 str = wgetcutbuffer(i, &len);
Guido van Rossum01769f01990-10-30 13:39:00 +00001542 if (str == NULL) {
Guido van Rossum85a5fbb1990-10-14 12:07:46 +00001543 str = "";
Guido van Rossum01769f01990-10-30 13:39:00 +00001544 len = 0;
1545 }
1546 return newsizedstringobject(str, len);
Guido van Rossum85a5fbb1990-10-14 12:07:46 +00001547}
1548
Guido van Rossum5b10f451990-10-30 16:01:48 +00001549static object *
1550stdwin_rotatecutbuffers(self, args)
1551 object *self;
1552 object *args;
1553{
1554 int i;
1555 if (!getintarg(args, &i))
1556 return NULL;
1557 wrotatecutbuffers(i);
1558 INCREF(None);
1559 return None;
1560}
1561
1562static object *
1563stdwin_getselection(self, args)
1564 object *self;
1565 object *args;
1566{
1567 int sel;
1568 char *data;
1569 int len;
1570 if (!getintarg(args, &sel))
1571 return NULL;
1572 data = wgetselection(sel, &len);
1573 if (data == NULL) {
1574 data = "";
1575 len = 0;
1576 }
1577 return newsizedstringobject(data, len);
1578}
1579
1580static object *
1581stdwin_resetselection(self, args)
1582 object *self;
1583 object *args;
1584{
1585 int sel;
1586 if (!getintarg(args, &sel))
1587 return NULL;
1588 wresetselection(sel);
1589 INCREF(None);
1590 return None;
1591}
1592
Guido van Rossum85a5fbb1990-10-14 12:07:46 +00001593static struct methodlist stdwin_methods[] = {
1594 {"askfile", stdwin_askfile},
1595 {"askstr", stdwin_askstr},
1596 {"askync", stdwin_askync},
1597 {"fleep", stdwin_fleep},
Guido van Rossum5b10f451990-10-30 16:01:48 +00001598 {"getselection", stdwin_getselection},
Guido van Rossum85a5fbb1990-10-14 12:07:46 +00001599 {"getcutbuffer", stdwin_getcutbuffer},
1600 {"getevent", stdwin_getevent},
1601 {"menucreate", stdwin_menucreate},
1602 {"message", stdwin_message},
1603 {"open", stdwin_open},
Guido van Rossum5b10f451990-10-30 16:01:48 +00001604 {"resetselection", stdwin_resetselection},
1605 {"rotatecutbuffers", stdwin_rotatecutbuffers},
Guido van Rossum85a5fbb1990-10-14 12:07:46 +00001606 {"setcutbuffer", stdwin_setcutbuffer},
1607 {"setdefwinpos", stdwin_setdefwinpos},
1608 {"setdefwinsize", stdwin_setdefwinsize},
1609
1610 /* Text measuring methods borrow code from drawing objects: */
1611 {"baseline", drawing_baseline},
1612 {"lineheight", drawing_lineheight},
1613 {"textbreak", drawing_textbreak},
1614 {"textwidth", drawing_textwidth},
1615 {NULL, NULL} /* sentinel */
1616};
1617
1618void
1619initstdwin()
1620{
1621 initmodule("stdwin", stdwin_methods);
1622}