1 /* $Id$ $Revision$ */
2 /* vim:set shiftwidth=4 ts=8: */
3 
4 /*************************************************************************
5  * Copyright (c) 2011 AT&T Intellectual Property
6  * All rights reserved. This program and the accompanying materials
7  * are made available under the terms of the Eclipse Public License v1.0
8  * which accompanies this distribution, and is available at
9  * http://www.eclipse.org/legal/epl-v10.html
10  *
11  * Contributors: See CVS logs. Details at http://www.graphviz.org/
12  *************************************************************************/
13 
14 /* Lefteris Koutsofios - AT&T Labs Research */
15 
16 #include "common.h"
17 #include "g.h"
18 #include "gcommon.h"
19 #include "mem.h"
20 
21 #define WCU widget->u.c
22 #define WVU widget->u.v
23 
24 FILE *Gxfp;
25 int Gxfd;
26 int Gpopdownflag;
27 int Gdepth;
28 int Gnocallbacks;
29 int menuselected;
30 int menupoped;
31 
32 char *Gbufp = NULL;
33 int Gbufn = 0, Gbufi = 0;
34 
35 PIXpoint_t *Gppp;
36 int Gppn, Gppi;
37 
38 Gfont_t *Gfontp;
39 int Gfontn;
40 
41 static HFONT deffont;
42 static int twobmouse;
43 static HWND palettechanged;
44 
45 LRESULT CALLBACK LeftyWndProc (HWND, UINT, WPARAM, LPARAM);
46 LRESULT CALLBACK ArrayWndProc (HWND, UINT, WPARAM, LPARAM);
47 LRESULT CALLBACK CanvasWndProc (HWND, UINT, WPARAM, LPARAM);
48 LRESULT CALLBACK LabelWndProc (HWND, UINT, WPARAM, LPARAM);
49 LRESULT CALLBACK ScrollWndProc (HWND, UINT, WPARAM, LPARAM);
50 
51 static void processcommand (Gwidget_t *, WPARAM, LPARAM);
52 static void handleresize (Gwidget_t *);
53 
Ginitgraphics(void)54 int Ginitgraphics (void) {
55     WNDCLASS wc;
56     HDC hdc;
57     ATOM rtn;
58 
59     if (!hprevinstance) {
60         wc.style = NULL;
61         wc.lpfnWndProc = LeftyWndProc;
62         wc.cbClsExtra = 0;
63         wc.cbWndExtra = 0;
64         wc.hInstance = hinstance;
65         wc.hIcon = LoadIcon ((HINSTANCE) NULL, IDI_APPLICATION);
66         wc.hCursor = LoadCursor ((HINSTANCE) NULL, IDC_ARROW);
67         wc.hbrBackground = GetStockObject (WHITE_BRUSH);
68         wc.lpszMenuName = 0;
69         wc.lpszClassName = "LeftyClass";
70         if (!(rtn = RegisterClass (&wc)))
71             panic1 (POS, "GXinit", "register class rtn = %d", (int) rtn);
72 
73         wc.style = NULL;
74         wc.lpfnWndProc = ArrayWndProc;
75         wc.cbClsExtra = 0;
76         wc.cbWndExtra = 0;
77         wc.hInstance = hinstance;
78         wc.hIcon = LoadIcon ((HINSTANCE) NULL, IDI_APPLICATION);
79         wc.hCursor = LoadCursor ((HINSTANCE) NULL, IDC_ARROW);
80         wc.hbrBackground = GetStockObject (WHITE_BRUSH);
81         wc.lpszMenuName = 0;
82         wc.lpszClassName = "ArrayClass";
83         if (!(rtn = RegisterClass (&wc)))
84             panic1 (POS, "GXinit", "register class rtn = %d", (int) rtn);
85 
86         wc.style = CS_OWNDC;
87         wc.lpfnWndProc = CanvasWndProc;
88         wc.cbClsExtra = 0;
89         wc.cbWndExtra = 0;
90         wc.hInstance = hinstance;
91         wc.hIcon = LoadIcon ((HINSTANCE) NULL, IDI_APPLICATION);
92         wc.hCursor = NULL;
93         wc.hbrBackground = GetStockObject (WHITE_BRUSH);
94         wc.lpszMenuName = 0;
95         wc.lpszClassName = "CanvasClass";
96         if (!(rtn = RegisterClass (&wc)))
97             panic1 (POS, "GXinit", "register class rtn = %d", (int) rtn);
98 
99         wc.style = NULL;
100         wc.lpfnWndProc = ScrollWndProc;
101         wc.cbClsExtra = 0;
102         wc.cbWndExtra = 0;
103         wc.hInstance = hinstance;
104         wc.hIcon = LoadIcon ((HINSTANCE) NULL, IDI_APPLICATION);
105         wc.hCursor = LoadCursor ((HINSTANCE) NULL, IDC_ARROW);
106         wc.hbrBackground = GetStockObject (WHITE_BRUSH);
107         wc.lpszMenuName = 0;
108         wc.lpszClassName = "ScrollClass";
109         if (!(rtn = RegisterClass (&wc)))
110             panic1 (POS, "GXinit", "register class rtn = %d", (int) rtn);
111 
112         wc.style = NULL;
113         wc.lpfnWndProc = LabelWndProc;
114         wc.cbClsExtra = 0;
115         wc.cbWndExtra = 0;
116         wc.hInstance = hinstance;
117         wc.hIcon = LoadIcon ((HINSTANCE) NULL, IDI_APPLICATION);
118         wc.hCursor = LoadCursor ((HINSTANCE) NULL, IDC_ARROW);
119         wc.hbrBackground = GetStockObject (WHITE_BRUSH);
120         wc.lpszMenuName = 0;
121         wc.lpszClassName = "LabelClass";
122         if (!(rtn = RegisterClass (&wc)))
123             panic1 (POS, "GXinit", "register class rtn = %d", (int) rtn);
124     }
125     if (getenv ("LEFTY3BMOUSE"))
126         twobmouse = FALSE;
127     else
128         twobmouse = TRUE;
129     hdc = GetDC ((HWND) NULL);
130     Gdepth = GetDeviceCaps (hdc, BITSPIXEL);
131     deffont = GetStockObject (SYSTEM_FONT);
132 #ifndef FEATURE_MS
133     if (!(Gxfp = fopen ("/dev/windows", "r")))
134         panic1 (POS, "GXinit", "cannot open windows device");
135     Gxfd = fileno (Gxfp);
136 #endif
137     Gpopdownflag = FALSE;
138     Gbufp = Marrayalloc ((long) BUFINCR * BUFSIZE);
139     Gbufn = BUFINCR;
140     Gppp = Marrayalloc ((long) PPINCR * PPSIZE);
141     Gppn = PPINCR;
142     Gfontp = Marrayalloc ((long) FONTSIZE);
143     Gfontn = 1;
144     Gfontp[0].name = strdup ("default");
145     if (!Gdefaultfont)
146         Gfontp[0].font = deffont;
147     else if (Gdefaultfont[0] != '\000')
148         Gfontp[0].font = CreateFont (
149             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Gdefaultfont
150         );
151     else
152         Gfontp[0].font = NULL;
153     ReleaseDC ((HWND) NULL, hdc);
154     Gnocallbacks = FALSE;
155     return 0;
156 }
157 
Gtermgraphics(void)158 int Gtermgraphics (void) {
159     int fi;
160 
161     for (fi = 0; fi < Gfontn; fi++)
162         free (Gfontp[fi].name);
163     Marrayfree (Gfontp), Gfontp = NULL, Gfontn = 0;
164     Marrayfree (Gppp), Gppp = NULL, Gppn = 0;
165     Marrayfree (Gbufp), Gbufp = NULL, Gbufn = 0;
166     return 0;
167 }
168 
Gsync(void)169 int Gsync (void) {
170     return 0;
171 }
172 
Gresetbstate(int wi)173 int Gresetbstate (int wi) {
174     Gcw_t *cw;
175     int bn;
176 
177     cw = Gwidgets[wi].u.c;
178     bn = cw->bstate[0] + cw->bstate[1] + cw->bstate[2];
179     cw->bstate[0] = cw->bstate[1] = cw->bstate[2] = 0;
180     cw->buttonsdown -= bn;
181     Gbuttonsdown -= bn;
182     return 0;
183 }
184 
Gprocessevents(int waitflag,int mode)185 int Gprocessevents (int waitflag, int mode) {
186     MSG msg;
187     int rtn;
188 
189     rtn = 0;
190     switch (waitflag) {
191     case TRUE:
192         if (!GetMessage(&msg, (HWND) NULL, (UINT) NULL, (UINT) NULL))
193             exit (msg.wParam);
194         TranslateMessage(&msg);
195         DispatchMessage(&msg);
196         if (mode == G_ONEEVENT)
197             return 1;
198         rtn = 1;
199         /* FALL THROUGH */
200     case FALSE:
201         while (PeekMessage(&msg, (HWND) 0, (UINT) 0, (UINT) 0, PM_REMOVE)) {
202             if (msg.message == WM_QUIT)
203                 exit (msg.wParam);
204             TranslateMessage(&msg);
205             DispatchMessage(&msg);
206             if (mode == G_ONEEVENT)
207                 return 1;
208             rtn = 1;
209         }
210         break;
211     }
212     return rtn;
213 }
214 
LeftyWndProc(HWND hwnd,UINT message,WPARAM wparam,LPARAM lparam)215 LRESULT CALLBACK LeftyWndProc (
216     HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam
217 ) {
218     Gwidget_t *widget;
219     WINDOWPOS *wpos;
220     Gevent_t gev;
221 
222     widget = findwidget (hwnd, G_VIEWWIDGET);
223     switch (message) {
224     case WM_WINDOWPOSCHANGED:
225         if (Gnocallbacks || !widget)
226             return (DefWindowProc(hwnd, message, wparam, lparam));
227         wpos = (WINDOWPOS *) lparam;
228         if (!(wpos->flags & SWP_NOSIZE))
229             handleresize (widget);
230         break;
231     case WM_COMMAND:
232         if (Gnocallbacks || !widget)
233             return (DefWindowProc(hwnd, message, wparam, lparam));
234         processcommand (widget, wparam, lparam);
235         break;
236     case WM_CLOSE:
237         if (!widget)
238             exit (0);
239         if (WVU->closing)
240             DestroyWindow (hwnd);
241         if (Gnocallbacks)
242             exit (0);
243         gev.type = 0, gev.code = 0, gev.data = 0;
244         gev.wi = widget - &Gwidgets[0];
245         if (WVU->func)
246             (*WVU->func) (&gev);
247         else
248             exit (0);
249         break;
250     case WM_PALETTECHANGED:
251         palettechanged = (HWND) wparam;
252         break;
253     default:
254         return (DefWindowProc(hwnd, message, wparam, lparam));
255     }
256     return 0;
257 }
258 
ArrayWndProc(HWND hwnd,UINT message,WPARAM wparam,LPARAM lparam)259 LRESULT CALLBACK ArrayWndProc (
260     HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam
261 ) {
262     Gwidget_t *widget;
263     WINDOWPOS *wpos;
264 
265     if (Gnocallbacks || !(widget = findwidget (hwnd, G_ARRAYWIDGET)))
266         return (DefWindowProc(hwnd, message, wparam, lparam));
267     switch (message) {
268     case WM_WINDOWPOSCHANGED:
269         wpos = (WINDOWPOS *) lparam;
270         if (!(wpos->flags & SWP_NOSIZE))
271             handleresize (widget);
272         break;
273     case WM_COMMAND:
274         processcommand (widget, wparam, lparam);
275         break;
276     default:
277         return (DefWindowProc (hwnd, message, wparam, lparam));
278     }
279     return 0;
280 }
281 
CanvasWndProc(HWND hwnd,UINT message,WPARAM wparam,LPARAM lparam)282 LRESULT CALLBACK CanvasWndProc (
283     HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam
284 ) {
285     Gwidget_t *widget;
286     WINDOWPOS *wpos;
287     PIXpoint_t pp;
288     Gevent_t gev;
289     POINT p;
290     int wi, bn;
291 
292     static int cntlflag;
293 
294     if (Gnocallbacks || !(widget = findwidget (hwnd, G_CANVASWIDGET)))
295         return (DefWindowProc(hwnd, message, wparam, lparam));
296     Gpopdownflag = FALSE;
297     switch (message) {
298     case WM_PAINT:
299         if (palettechanged != hwnd)
300             RealizePalette (widget->u.c->gc);
301         Gneedredraw = widget->u.c->needredraw = TRUE;
302         Gadjustclip (widget);
303         return (DefWindowProc(hwnd, message, wparam, lparam));
304     case WM_WINDOWPOSCHANGED:
305         wpos = (WINDOWPOS *) lparam;
306         if (!(wpos->flags & SWP_NOSIZE))
307             handleresize (widget);
308         return 0;
309     case WM_MOUSEACTIVATE:
310         SetFocus (widget->w);
311         return (DefWindowProc(hwnd, message, wparam, lparam));
312     case WM_COMMAND:
313         processcommand (widget, wparam, lparam);
314         return 0;
315     case WM_CHAR:
316         gev.type = G_KEYBD;
317         gev.code = G_DOWN;   /* I don't know how to get up events so I make */
318         Gpopdownflag = TRUE; /* the code after this switch send the up event */
319         gev.data = wparam;
320         GetCursorPos (&p);
321         ScreenToClient (widget->w, &p);
322         pp.x = p.x, pp.y = p.y;
323         gev.p = ppixtodraw (widget, pp);
324         /* continues after the end of this switch */
325         break;
326     case WM_LBUTTONDOWN:
327     case WM_LBUTTONUP:
328     case WM_MBUTTONDOWN:
329     case WM_MBUTTONUP:
330     case WM_RBUTTONDOWN:
331     case WM_RBUTTONUP:
332         gev.type = G_MOUSE;
333         if (twobmouse) {
334             if (message == WM_LBUTTONDOWN && (wparam & MK_CONTROL))
335                 message = WM_MBUTTONDOWN, cntlflag = TRUE;
336             if (message == WM_LBUTTONUP && cntlflag)
337                 message = WM_MBUTTONUP, cntlflag = FALSE;
338         }
339         switch (message) {
340         case WM_LBUTTONDOWN: gev.code = G_DOWN, gev.data = G_LEFT;   break;
341         case WM_LBUTTONUP:   gev.code = G_UP,   gev.data = G_LEFT;   break;
342         case WM_MBUTTONDOWN: gev.code = G_DOWN, gev.data = G_MIDDLE; break;
343         case WM_MBUTTONUP:   gev.code = G_UP,   gev.data = G_MIDDLE; break;
344         case WM_RBUTTONDOWN: gev.code = G_DOWN, gev.data = G_RIGHT;  break;
345         case WM_RBUTTONUP:   gev.code = G_UP,   gev.data = G_RIGHT;  break;
346         }
347         pp.x = LOWORD (lparam), pp.y = HIWORD (lparam);
348         gev.p = ppixtodraw (widget, pp);
349         bn = WCU->bstate[gev.data];
350         WCU->bstate[gev.data] = (gev.code == G_DOWN) ? 1 : 0;
351         bn = WCU->bstate[gev.data] - bn;
352         widget->u.c->buttonsdown += bn;
353         Gbuttonsdown += bn;
354         /* continues after the end of this switch */
355         break;
356     default:
357         return (DefWindowProc(hwnd, message, wparam, lparam));
358     }
359     wi = gev.wi = widget - &Gwidgets[0];
360     if (widget->u.c->func)
361         (*widget->u.c->func) (&gev);
362     if (Gpopdownflag) {
363         Gpopdownflag = FALSE;
364         if (gev.code == G_DOWN) {
365             gev.code = G_UP;
366             widget = &Gwidgets[wi];
367             WCU->bstate[gev.data] = 0;
368             widget->u.c->buttonsdown--;
369             Gbuttonsdown--;
370             if (widget->inuse && widget->u.c->func)
371                 (*widget->u.c->func) (&gev);
372         }
373     }
374     return 0;
375 }
376 
LabelWndProc(HWND hwnd,UINT message,WPARAM wparam,LPARAM lparam)377 LRESULT CALLBACK LabelWndProc (
378     HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam
379 ) {
380     Gwidget_t *widget;
381     PAINTSTRUCT paintstruct;
382     WINDOWPOS *wpos;
383     Gevent_t gev;
384     RECT r;
385     HDC hdc;
386     int wi;
387 
388     if (Gnocallbacks || !(widget = findwidget (hwnd, G_LABELWIDGET)))
389         return (DefWindowProc(hwnd, message, wparam, lparam));
390     switch (message) {
391     case WM_PAINT:
392         hdc = BeginPaint (widget->w, &paintstruct);
393         GetWindowText (widget->w, &Gbufp[0], Gbufn);
394         GetClientRect (widget->w, &r);
395         DrawText (hdc, (LPCSTR) &Gbufp[0], strlen (Gbufp), &r, DT_LEFT);
396         EndPaint (widget->w, &paintstruct);
397         return (DefWindowProc(hwnd, message, wparam, lparam));
398     case WM_WINDOWPOSCHANGED:
399         wpos = (WINDOWPOS *) lparam;
400         if (!(wpos->flags & SWP_NOSIZE))
401             handleresize (widget);
402         return 0;
403     case WM_COMMAND:
404         processcommand (widget, wparam, lparam);
405         return 0;
406     case WM_KEYDOWN:
407     case WM_KEYUP:
408         gev.type = G_KEYBD;
409         gev.code = (message == WM_KEYDOWN) ? G_DOWN : G_UP;
410         gev.data = wparam;
411         /* continues after the end of this switch */
412         break;
413     case WM_LBUTTONDOWN:
414     case WM_LBUTTONUP:
415     case WM_MBUTTONDOWN:
416     case WM_MBUTTONUP:
417     case WM_RBUTTONDOWN:
418     case WM_RBUTTONUP:
419         gev.type = G_MOUSE;
420         if (wparam & MK_CONTROL) {
421             if (message == WM_LBUTTONDOWN)
422                 message = WM_MBUTTONDOWN;
423             else if (message == WM_LBUTTONUP)
424                 message = WM_MBUTTONUP;
425         }
426         switch (message) {
427         case WM_LBUTTONDOWN: gev.code = G_DOWN, gev.data = G_LEFT;   break;
428         case WM_LBUTTONUP:   gev.code = G_UP,   gev.data = G_LEFT;   break;
429         case WM_MBUTTONDOWN: gev.code = G_DOWN, gev.data = G_MIDDLE; break;
430         case WM_MBUTTONUP:   gev.code = G_UP,   gev.data = G_MIDDLE; break;
431         case WM_RBUTTONDOWN: gev.code = G_DOWN, gev.data = G_RIGHT;  break;
432         case WM_RBUTTONUP:   gev.code = G_UP,   gev.data = G_RIGHT;  break;
433         }
434         /* continues after the end of this switch */
435         break;
436     default:
437         return (DefWindowProc(hwnd, message, wparam, lparam));
438     }
439     wi = gev.wi = widget - &Gwidgets[0];
440     if (widget->u.l->func)
441         (*widget->u.l->func) (&gev);
442     if (Gpopdownflag) {
443         Gpopdownflag = FALSE;
444         if (gev.type == G_MOUSE && gev.code == G_DOWN) {
445             gev.code = G_UP;
446             widget = &Gwidgets[wi];
447             if (widget->inuse && widget->u.l->func)
448                 (*widget->u.l->func) (&gev);
449         }
450     }
451     return 0;
452 }
453 
ScrollWndProc(HWND hwnd,UINT message,WPARAM wparam,LPARAM lparam)454 LRESULT CALLBACK ScrollWndProc (
455     HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam
456 ) {
457     Gwidget_t *widget, *child;
458     WINDOWPOS *wpos;
459     PIXpoint_t po;
460     RECT r;
461     int dummy, dx, dy, wi;
462 
463     if (Gnocallbacks || !(widget = findwidget (hwnd, G_SCROLLWIDGET)))
464         return (DefWindowProc(hwnd, message, wparam, lparam));
465     switch (message) {
466     case WM_WINDOWPOSCHANGED:
467         wpos = (WINDOWPOS *) lparam;
468         if (!(wpos->flags & SWP_NOSIZE))
469             handleresize (widget);
470         break;
471     case WM_HSCROLL:
472     case WM_VSCROLL:
473         for (wi = 0; wi < Gwidgetn; wi++) {
474             child = &Gwidgets[wi];
475             if (child->inuse && child->pwi == widget - &Gwidgets[0])
476                 break;
477         }
478         if (wi == Gwidgetn)
479             return (DefWindowProc(hwnd, message, wparam, lparam));
480         GetClientRect (widget->w, &r);
481         GetScrollRange (widget->w, SB_HORZ, &dummy, &dx);
482         GetScrollRange (widget->w, SB_VERT, &dummy, &dy);
483         po.x = GetScrollPos (widget->w, SB_HORZ);
484         po.y = GetScrollPos (widget->w, SB_VERT);
485         switch (message) {
486         case WM_HSCROLL:
487             switch (LOWORD (wparam)) {
488             case SB_BOTTOM:        po.x = dx;                  break;
489             case SB_LINEDOWN:      po.x += 10;                 break;
490             case SB_LINEUP:        po.x -= 10;                 break;
491             case SB_PAGEDOWN:      po.x += (r.right - r.left); break;
492             case SB_PAGEUP:        po.x -= (r.right - r.left); break;
493             case SB_THUMBPOSITION: po.x = HIWORD (wparam);     break;
494             case SB_THUMBTRACK:    po.x = HIWORD (wparam);     break;
495             case SB_TOP:           po.x = 0;                   break;
496             }
497             po.x = min (po.x, dx);
498             po.x = max (po.x, 0);
499             SetScrollPos (widget->w, SB_HORZ, po.x, TRUE);
500             SetWindowPos (
501                 child->w, (HWND) NULL, -po.x, -po.y, 0, 0,
502                 SWP_NOSIZE | SWP_NOZORDER
503             );
504             break;
505         case WM_VSCROLL:
506             switch (LOWORD (wparam)) {
507             case SB_BOTTOM:        po.y = dy;                  break;
508             case SB_LINEDOWN:      po.y += 10;                 break;
509             case SB_LINEUP:        po.y -= 10;                 break;
510             case SB_PAGEDOWN:      po.y += (r.bottom - r.top); break;
511             case SB_PAGEUP:        po.y -= (r.bottom - r.top); break;
512             case SB_THUMBPOSITION: po.y = HIWORD (wparam);     break;
513             case SB_THUMBTRACK:    po.y = HIWORD (wparam);     break;
514             case SB_TOP:           po.y = 0;                   break;
515             }
516             po.y = min (po.y, dy);
517             po.y = max (po.y, 0);
518             SetScrollPos (widget->w, SB_VERT, po.y, TRUE);
519             SetWindowPos (
520                 child->w, (HWND) NULL, -po.x, -po.y, 0, 0,
521                 SWP_NOSIZE | SWP_NOZORDER
522             );
523             break;
524         }
525         break;
526     default:
527         return (DefWindowProc (hwnd, message, wparam, lparam));
528     }
529     return 0;
530 }
531 
processcommand(Gwidget_t * widget,WPARAM wparam,LPARAM lparam)532 static void processcommand (Gwidget_t *widget, WPARAM wparam, LPARAM lparam) {
533     Gwidget_t *child;
534     WORD l;
535     int n;
536 
537     if (lparam == 0) { /* it's a menu */
538         if (LOWORD (wparam) != 999)
539             menuselected = LOWORD (wparam);
540         menupoped = FALSE;
541         return;
542     }
543     if (!(LOWORD (wparam) > 0 && LOWORD (wparam) < Gwidgetn))
544         return;
545     child = &Gwidgets[LOWORD (wparam)];
546     if (!child->inuse)
547         return;
548 
549     switch (child->type) {
550     case G_TEXTWIDGET:
551         if (HIWORD (wparam) == EN_CHANGE) { /* it's a text widget message */
552             if ((n = SendMessage (child->w, EM_GETLINECOUNT, 0, 0L)) < 2)
553                 return;
554             *((WORD *) &Gbufp[0]) = Gbufn - 1;
555             l = SendMessage (
556                 child->w, EM_GETLINE, n - 1, (LPARAM) (LPSTR) &Gbufp[0]
557             );
558             if (l != 0)
559                 return; /* no carriage return yet */
560             *((WORD *) &Gbufp[0]) = Gbufn - 1;
561             l = SendMessage (
562                 child->w, EM_GETLINE, n - 2, (LPARAM) (LPSTR) &Gbufp[0]
563             );
564             Gbufp[l] = 0;
565             if (l > 0 && child->u.t->func)
566                 (*child->u.t->func) (child - &Gwidgets[0], &Gbufp[0]);
567         }
568         break;
569     case G_BUTTONWIDGET:
570         if (child->u.b->func)
571             (*child->u.b->func) (child - &Gwidgets[0], child->udata);
572         break;
573     }
574 }
575 
Gadjustwrect(Gwidget_t * parent,PIXsize_t * psp)576 void Gadjustwrect (Gwidget_t *parent, PIXsize_t *psp) {
577     RECT r;
578 
579     GetClientRect (parent->w, &r);
580     switch (parent->type) {
581     case G_ARRAYWIDGET:
582         if (parent->u.a->data.type == G_AWHARRAY)
583             psp->y = r.bottom - r.top;
584         else
585             psp->x = r.right - r.left;
586         break;
587     case G_SCROLLWIDGET:
588         psp->x = max (psp->x, r.right - r.left);
589         psp->y = max (psp->y, r.bottom - r.top);
590         break;
591     case G_VIEWWIDGET:
592     case G_QUERYWIDGET:
593         psp->x = r.right - r.left;
594         psp->y = r.bottom - r.top;
595         break;
596     }
597 }
598 
handleresize(Gwidget_t * widget)599 static void handleresize (Gwidget_t *widget) {
600     Gwidget_t *parent, *child;
601     PIXsize_t ps1, ps2;
602     PIXpoint_t po;
603     DWORD wflags1, wflags2;
604     RECT r;
605     int dx, dy, wi, i;
606 
607     wflags1 = SWP_NOMOVE | SWP_NOZORDER;
608     wflags2 = SWP_NOSIZE | SWP_NOZORDER;
609     GetWindowRect (widget->w, &r);
610     ps1.x = r.right - r.left, ps1.y = r.bottom - r.top;
611     ps2 = ps1;
612     /* first, take care of parent */
613     parent = (widget->pwi == -1) ? NULL : &Gwidgets[widget->pwi];
614     if (!parent)
615         goto handlechildren;
616     switch (parent->type) {
617     case G_VIEWWIDGET:
618         Gadjustwrect (parent, &ps1);
619         if (ps1.x != ps2.x || ps1.y != ps2.y) {
620             Gnocallbacks = TRUE;
621             SetWindowPos (widget->w, (HWND) NULL, 0, 0, ps1.x, ps1.y, wflags1);
622             Gnocallbacks = FALSE;
623         }
624         break;
625     case G_ARRAYWIDGET:
626         Gnocallbacks = TRUE;
627         Gawresize (parent);
628         Gnocallbacks = FALSE;
629         break;
630     case G_SCROLLWIDGET:
631         Gnocallbacks = TRUE;
632         for (i = 0; i  < 2; i++) {
633             Gadjustwrect (parent, &ps1);
634             if (ps1.x > ps2.x || ps1.y > ps2.y)
635                 SetWindowPos (
636                     widget->w, (HWND) NULL, 0, 0, ps1.x, ps1.y, wflags1
637                 );
638             GetClientRect (parent->w, &r);
639             ps2.x = r.right - r.left, ps2.y = r.bottom - r.top;
640             dx = max (0, ps1.x - ps2.x);
641             dy = max (0, ps1.y - ps2.y);
642             SetScrollRange (parent->w, SB_HORZ, 0, dx, TRUE);
643             SetScrollRange (parent->w, SB_VERT, 0, dy, TRUE);
644             po.x = GetScrollPos (parent->w, SB_HORZ);
645             po.y = GetScrollPos (parent->w, SB_VERT);
646             po.x = min (po.x, dx);
647             po.x = max (po.x, 0);
648             SetScrollPos (parent->w, SB_HORZ, po.x, TRUE);
649             po.y = min (po.y, dy);
650             po.y = max (po.y, 0);
651             SetScrollPos (parent->w, SB_VERT, po.y, TRUE);
652             SetWindowPos (widget->w, (HWND) NULL, -po.x, -po.y, 0, 0, wflags2);
653             ps2 = ps1;
654         }
655         Gnocallbacks = FALSE;
656         break;
657     }
658 
659 handlechildren:
660     for (wi = 0; wi < Gwidgetn; wi++) {
661         child = &Gwidgets[wi];
662         if (child->inuse && child->pwi == widget - &Gwidgets[0])
663             break;
664     }
665     if (wi == Gwidgetn)
666         return;
667     GetWindowRect (child->w, &r);
668     ps1.x = r.right - r.left, ps1.y = r.bottom - r.top;
669     ps2 = ps1;
670     switch (widget->type) {
671     case G_VIEWWIDGET:
672         Gadjustwrect (widget, &ps1);
673         if (ps1.x != ps2.x || ps1.y != ps2.y)
674             SetWindowPos (child->w, (HWND) NULL, 0, 0, ps1.x, ps1.y, wflags1);
675         break;
676     case G_ARRAYWIDGET:
677         Gawresize (widget);
678         break;
679     case G_SCROLLWIDGET:
680         Gadjustwrect (widget, &ps1);
681         if (ps1.x > ps2.x || ps1.y > ps2.y)
682             SetWindowPos (child->w, (HWND) NULL, 0, 0, ps1.x, ps1.y, wflags1);
683         GetClientRect (widget->w, &r);
684         ps2.x = r.right - r.left, ps2.y = r.bottom - r.top;
685         dx = max (0, ps1.x - ps2.x);
686         dy = max (0, ps1.y - ps2.y);
687         SetScrollRange (widget->w, SB_HORZ, 0, dx, TRUE);
688         SetScrollRange (widget->w, SB_VERT, 0, dy, TRUE);
689         po.x = GetScrollPos (widget->w, SB_HORZ);
690         po.y = GetScrollPos (widget->w, SB_VERT);
691         po.x = min (po.x, dx);
692         po.x = max (po.x, 0);
693         SetScrollPos (widget->w, SB_HORZ, po.x, TRUE);
694         po.y = min (po.y, dy);
695         po.y = max (po.y, 0);
696         SetScrollPos (widget->w, SB_VERT, po.y, TRUE);
697         SetWindowPos (child->w, (HWND) NULL, -po.x, -po.y, 0, 0, wflags2);
698         break;
699     }
700 }
701