xref: /petsc/src/sys/classes/draw/impls/win32/win32draw.c (revision 2fa40bb9206b96114faa7cb222621ec184d31cd2)
1 
2 #include <petscsys.h>
3 #include <petsc/private/drawimpl.h>
4 #include <../src/sys/classes/draw/impls/win32/win32draw.h>
5 
6 #define IDC_FOUR       109
7 #define IDI_FOUR       107
8 #define IDM_EXIT       105
9 #define IDR_POPUP      103
10 #define MAX_LOADSTRING 100
11 
12 #if !defined(SelectPen)
13 #define SelectPen(hdc, hpen)      ((HPEN)SelectObject((hdc), (HGDIOBJ)(HPEN)(hpen)))
14 #endif
15 #if !defined(SelectFont)
16 #define SelectFont(hdc,hfont)    ((HFONT)SelectObject((hdc), (HGDIOBJ)(HFONT)(hfont)))
17 #endif
18 #if !defined(SelectBrush)
19 #define SelectBrush(hdc,hbrush) ((HBRUSH)SelectObject((hdc), (HGDIOBJ)(HBRUSH)(hbrush)))
20 #endif
21 #if !defined(GetStockBrush)
22 #define GetStockBrush(i)      ((HBRUSH)GetStockObject(i))
23 #endif
24 
25 #define XTRANS(draw,win,x) \
26     (int)(((win)->w)*((draw)->port_xl + (((x - (draw)->coor_xl)*         \
27                             ((draw)->port_xr - (draw)->port_xl))/        \
28                             ((draw)->coor_xr - (draw)->coor_xl))))
29 #define YTRANS(draw,win,y) \
30     (int)(((win)->h)*(1.0-(draw)->port_yl - (((y - (draw)->coor_yl)*     \
31                                 ((draw)->port_yr - (draw)->port_yl))/    \
32                                 ((draw)->coor_yr - (draw)->coor_yl))))
33 
34 HINSTANCE  hInst;
35 HANDLE     g_hWindowListMutex = NULL;
36 WindowNode WindowListHead     = NULL;
37 
38 /* Hard coded color hue until hue.c works with this */
39 unsigned char RedMap[]   = {255,0,255,0,0,0,255,127,34,255,238,165,255,255,190,255,255,238,0,255,105,154,135,0,0,244,152,176,220,216,50,255};
40 unsigned char GreenMap[] = {255,0,0,255,255,0,0,255,139,165,130,42,182,127,190,255,215,162,197,246,105,205,206,100,0,164,245,224,17,191,205,240};
41 unsigned char BlueMap[]  = {255,0,0,0,255,255,225,212,34,0,238,42,193,80,190,0,0,173,205,143,105,50,235,0,128,96,255,230,120,216,50,245};
42 
43 /* Foward declarations of functions included in this code module: */
44 LRESULT CALLBACK PetscWndProc(HWND, UINT, WPARAM, LPARAM);
45 static PetscErrorCode TranslateColor_Win32(PetscDraw,int);
46 static PetscErrorCode AverageColorRectangle_Win32(PetscDraw,int,int,int,int);
47 static PetscErrorCode AverageColorTriangle_Win32(PetscDraw,int,int,int);
48 static PetscErrorCode deletemouselist_Win32(WindowNode);
49 static void OnPaint_Win32(HWND);
50 static void OnDestroy_Win32(HWND);
51 static PetscErrorCode MouseRecord_Win32(HWND,PetscDrawButton);
52 static PetscErrorCode PetscDrawGetPopup_Win32(PetscDraw,PetscDraw*);
53 
54 static PetscErrorCode PetscDrawSetDoubleBuffer_Win32(PetscDraw draw)
55 {
56   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
57   HDC             hdc      = GetDC(windraw->hWnd);
58 
59   PetscFunctionBegin;
60   windraw->node->DoubleBuffer    = CreateCompatibleDC(hdc);
61   windraw->node->DoubleBufferBit = CreateCompatibleBitmap(hdc,windraw->w,windraw->h);
62   windraw->node->dbstore         = SelectObject(windraw->node->DoubleBuffer,windraw->node->DoubleBufferBit);
63   /* Fill background of second buffer */
64   ExtFloodFill(windraw->node->DoubleBuffer,0,0,COLOR_WINDOW,FLOODFILLBORDER);
65   /* Copy current buffer into seconf buffer and set window data as double buffered */
66   BitBlt(windraw->node->DoubleBuffer,0,0,windraw->w,windraw->h,
67          windraw->node->Buffer,0,0, SRCCOPY);
68 
69   windraw->node->DoubleBuffered = PETSC_TRUE;
70   ReleaseDC(windraw->hWnd,hdc);
71   PetscFunctionReturn(0);
72 }
73 
74 static PetscErrorCode PetscDrawFlush_Win32(PetscDraw draw)
75 {
76   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
77   HDC             hdc      = GetDC(windraw->hWnd);
78 
79   PetscFunctionBegin;
80   /* flush double buffer into primary buffer */
81   BitBlt(windraw->node->Buffer,0,0,windraw->w,windraw->h,
82          windraw->node->DoubleBuffer,0,0,SRCCOPY);
83   /* flush double buffer into window */
84   BitBlt(hdc,0,0,windraw->w,windraw->h,
85          windraw->node->DoubleBuffer, 0,0,SRCCOPY);
86   ReleaseDC(windraw->hWnd,hdc);
87   PetscFunctionReturn(0);
88 }
89 
90 static PetscErrorCode deletemouselist_Win32(WindowNode deletelist)
91 {
92   /* Called upon window close. Frees memory of linked list of stored mouse commands */
93   MouseNode node;
94 
95   while (deletelist->MouseListHead) {
96     node = deletelist->MouseListHead;
97     if (deletelist->MouseListHead->mnext) deletelist->MouseListHead = deletelist->MouseListHead->mnext;
98     PetscFree(node);
99   }
100   deletelist->MouseListHead = deletelist->MouseListTail = NULL;
101   if (deletelist->wprev) deletelist->wprev->wnext = deletelist->wnext;
102   if (deletelist->wnext) deletelist->wnext->wprev = deletelist->wprev;
103   PetscFree(deletelist);
104   return 0;
105 }
106 
107 static PetscErrorCode PetscDrawGetMouseButton_Win32(PetscDraw draw, PetscDrawButton *button,PetscReal *x_user,PetscReal *y_user,PetscReal *x_phys,PetscReal *y_phys)
108 {
109   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
110   WindowNode      current;
111   MouseNode       node=0;
112 
113   PetscFunctionBegin;
114   /* Make sure no other code is using the linked list at this moment */
115   WaitForSingleObject(g_hWindowListMutex, INFINITE);
116   /* Look for the node that matches the window you are using */
117   current = WindowListHead;
118   while (current) {
119     if (current->hWnd == windraw->hWnd) {
120       current->IsGetMouseOn = TRUE;
121       break;
122     } else current = current->wnext;
123   }
124   /* If no actions have occurred, wait for one */
125   node = current->MouseListHead;
126   if (!node) {
127     ReleaseMutex(g_hWindowListMutex);
128     WaitForSingleObject(current->event, INFINITE);
129     WaitForSingleObject(g_hWindowListMutex, INFINITE);
130   }
131   /* once we have the information, assign the pointers to it */
132   *button = current->MouseListHead->Button;
133   *x_user = current->MouseListHead->user.x;
134   *y_user = current->MouseListHead->user.y;
135   /* optional arguments */
136   if (x_phys) *x_phys = current->MouseListHead->phys.x;
137   if (y_phys) *y_phys = current->MouseListHead->phys.y;
138   /* remove set of information from sub linked-list, delete the node */
139   current->MouseListHead = current->MouseListHead->mnext;
140   if (!current->MouseListHead) {
141     ResetEvent(current->event);
142     current->MouseListTail = NULL;
143   }
144   if (node) PetscFree(node);
145 
146   /* Release mutex so that  other code can use
147      the linked list now that we are done with it */
148   ReleaseMutex(g_hWindowListMutex);
149   PetscFunctionReturn(0);
150 }
151 
152 static PetscErrorCode PetscDrawPause_Win32(PetscDraw draw)
153 {
154   PetscFunctionBegin;
155   PetscSleep(draw->pause);
156   PetscFunctionReturn(0);
157 }
158 
159 static PetscErrorCode TranslateColor_Win32(PetscDraw draw,int color)
160 {
161   /* Maps single color value into the RGB colors in our tables */
162   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
163   windraw->currentcolor = RGB(RedMap[color],GreenMap[color],BlueMap[color]);
164   return 0;
165 }
166 
167 static PetscErrorCode AverageColorRectangle_Win32(PetscDraw draw,int c1,int c2, int c3, int c4)
168 {
169   /* Averages colors given at points of rectangle and sets color from color table
170     will be changed once the color gradient problem is worked out */
171   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
172   windraw->currentcolor = RGB(((RedMap[c1]+RedMap[c2]+RedMap[c3]+RedMap[c4])/4),
173                               ((GreenMap[c1]+GreenMap[c2]+GreenMap[c3]+GreenMap[c4])/4),
174                               ((BlueMap[c1]+BlueMap[c2]+BlueMap[c3]+BlueMap[c4])/4));
175   return 0;
176 }
177 
178 static PetscErrorCode AverageColorTriangle_Win32(PetscDraw draw,int c1,int c2,int c3)
179 {
180   /* Averages colors given at points of rectangle and sets color from color table
181     will be changed once the color gradient problem is worked out */
182   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
183   windraw->currentcolor = RGB((RedMap[c1]+RedMap[c2]+RedMap[c3])/3,
184                               (GreenMap[c1]+GreenMap[c2]+GreenMap[c3])/3,
185                               (BlueMap[c1]+BlueMap[c2]+BlueMap[c3])/3);
186   return 0;
187 }
188 
189 static PetscErrorCode PetscDrawRectangle_Win32(PetscDraw draw,PetscReal xl,PetscReal yl,PetscReal xr,PetscReal yr,int c1,int c2,int c3,int c4)
190 {
191   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
192   HBRUSH          hbrush;
193   RECT            rect;
194   int             x1,yone,x2,y2;
195   HDC             hdc;
196 
197   PetscFunctionBegin;
198   x1   = XTRANS(draw,windraw,xl);
199   x2   = XTRANS(draw,windraw,xr);
200   yone = YTRANS(draw,windraw,yl);
201   y2   = YTRANS(draw,windraw,yr);
202   SetRect(&rect,x1,y2,x2,yone);
203   if (c1==c2 && c2==c3 && c3==c4) TranslateColor_Win32(draw,c1);
204   else AverageColorRectangle_Win32(draw,c1,c2,c3,c4);
205   hbrush = CreateSolidBrush(windraw->currentcolor);
206 
207   if (windraw->node->DoubleBuffered) hdc = windraw->node->DoubleBuffer;
208   else                               hdc = windraw->node->Buffer;
209 
210   FillRect(hdc,&rect,hbrush);
211   /* Forces a WM_PAINT message and erases background */
212   InvalidateRect(windraw->hWnd,NULL,TRUE);
213   UpdateWindow(windraw->hWnd);
214   PetscFunctionReturn(0);
215 }
216 
217 static PetscErrorCode PetscDrawLine_Win32(PetscDraw draw,PetscReal xl,PetscReal yl,PetscReal xr,PetscReal yr,int color)
218 {
219   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
220   HPEN            hpen;
221   int             x1,yone,x2,y2;
222   HDC             hdc;
223 
224   PetscFunctionBegin;
225   TranslateColor_Win32(draw,color);
226   x1   = XTRANS(draw,windraw,xl);x2  = XTRANS(draw,windraw,xr);
227   yone = YTRANS(draw,windraw,yl);y2  = YTRANS(draw,windraw,yr);
228   hpen = CreatePen (PS_SOLID, windraw->linewidth, windraw->currentcolor);
229   if (windraw->node->DoubleBuffered) hdc = windraw->node->DoubleBuffer;
230   else                               hdc = windraw->node->Buffer;
231 
232   SelectPen(hdc,hpen);
233   MoveToEx(hdc,x1,yone,NULL);
234   LineTo(hdc,x2,y2);
235   /* Forces a WM_PAINT message and erases background */
236   InvalidateRect(windraw->hWnd,NULL,TRUE);
237   UpdateWindow(windraw->hWnd);
238   PetscFunctionReturn(0);
239 }
240 
241 static PetscErrorCode PetscDrawLineSetWidth_Win32(PetscDraw draw,PetscReal width)
242 {
243   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
244   int             averagesize,finalwidth;
245   RECT            rect;
246 
247   PetscFunctionBegin;
248   GetClientRect(windraw->hWnd,&rect);
249   averagesize = ((rect.right - rect.left)+(rect.bottom - rect.top))/2;
250   finalwidth  = (int)PetscFloorReal(averagesize*width);
251   if (finalwidth < 1) finalwidth = 1; /* minimum size PetscDrawLine can except */
252 
253   windraw->linewidth = finalwidth;
254   PetscFunctionReturn(0);
255 }
256 
257 static PetscErrorCode PetscDrawLineGetWidth_Win32(PetscDraw draw,PetscReal *width)
258 {
259   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
260 
261   PetscFunctionBegin;
262   *width = (PetscReal)windraw->linewidth;
263   PetscFunctionReturn(0);
264 }
265 
266 static PetscErrorCode PetscDrawPoint_Win32(PetscDraw draw,PetscReal x,PetscReal y,int color)
267 {
268   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
269   HBRUSH          hbrush;
270   HRGN            hrgn;
271   int             radius;
272   int             x1,yone;
273   HDC             hdc;
274 
275   PetscFunctionBegin;
276   TranslateColor_Win32(draw,color);
277   x1     = XTRANS(draw,windraw,x);
278   yone   = YTRANS(draw,windraw,y);
279   hbrush = CreateSolidBrush(windraw->currentcolor);
280   if (windraw->node->DoubleBuffered) hdc = windraw->node->DoubleBuffer;
281   else                               hdc = windraw->node->Buffer;
282 
283   /* desired size is one logical pixel so just turn it on */
284   if (windraw->pointdiameter == 1) SetPixelV(hdc,x1,yone,windraw->currentcolor);
285   else {
286     /* draw point around position determined */
287     radius = windraw->pointdiameter/2; /* integer division */
288     hrgn   = CreateEllipticRgn(x1-radius,yone-radius,x1+radius,yone+radius);
289     FillRgn(hdc,hrgn,hbrush);
290   }
291   /* Forces a WM_PAINT and erases background */
292   InvalidateRect(windraw->hWnd,NULL,TRUE);
293   UpdateWindow(windraw->hWnd);
294   PetscFunctionReturn(0);
295 }
296 
297 static PetscErrorCode PetscDrawPointSetSize_Win32(PetscDraw draw,PetscReal width)
298 {
299   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
300   int             averagesize,diameter;
301   RECT            rect;
302 
303   PetscFunctionBegin;
304   GetClientRect(windraw->hWnd,&rect);
305   averagesize = ((rect.right - rect.left)+(rect.bottom - rect.top))/2;
306   diameter    = (int)PetscFloorReal(averagesize*width);
307   if (diameter < 1) diameter = 1;
308   windraw->pointdiameter = diameter;
309   PetscFunctionReturn(0);
310 }
311 
312 static PetscErrorCode PetscDrawString_Win32(PetscDraw draw,PetscReal x,PetscReal y,int color,const char *text)
313 {
314   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
315   RECT            r;
316   HFONT           hfont;
317   LOGFONT         logfont;
318   int             x1,yone;
319   HDC             hdc;
320 
321   PetscFunctionBegin;
322   x1       = XTRANS(draw,windraw,x);
323   yone     = YTRANS(draw,windraw,y);
324   r.bottom = yone;
325   r.left   = x1;
326   r.right  = x1 + 1;
327   r.top    = yone + 1;
328 
329   logfont.lfHeight         = windraw->stringheight;
330   logfont.lfWidth          = windraw->stringwidth;
331   logfont.lfEscapement     = 0;
332   logfont.lfOrientation    = 0;
333   logfont.lfCharSet        = 0;
334   logfont.lfClipPrecision  = 0;
335   logfont.lfItalic         = 0;
336   logfont.lfOutPrecision   = 0;
337   logfont.lfPitchAndFamily = DEFAULT_PITCH;
338   logfont.lfQuality        = DEFAULT_QUALITY;
339   logfont.lfStrikeOut      = 0;
340   logfont.lfUnderline      = 0;
341   logfont.lfWeight         = FW_NORMAL;
342 
343   hfont = CreateFontIndirect(&logfont);
344   TranslateColor_Win32(draw,color);
345   if (windraw->node->DoubleBuffered) hdc = windraw->node->DoubleBuffer;
346   else                               hdc = windraw->node->Buffer;
347 
348   SelectFont(hdc,hfont);
349   SetTextColor(hdc,windraw->currentcolor);
350   DrawText(hdc,text,lstrlen(text),&r,DT_NOCLIP);
351   DeleteObject(hfont);
352   /* Forces a WM_PAINT message and erases background */
353   InvalidateRect(windraw->hWnd,NULL,TRUE);
354   UpdateWindow(windraw->hWnd);
355   PetscFunctionReturn(0);
356 }
357 
358 static PetscErrorCode PetscDrawStringVertical_Win32(PetscDraw draw,PetscReal x,PetscReal y,int color,const char *text)
359 {
360   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
361   RECT            r;
362   HFONT           hfont;
363   LOGFONT         logfont;
364   int             x1,yone;
365   HDC             hdc;
366 
367   PetscFunctionBegin;
368   x1       = XTRANS(draw,windraw,x);
369   yone     = YTRANS(draw,windraw,y);
370   r.left   = x1;
371   r.bottom = yone + 30;
372   r.right  = x1 + 1;
373   r.top    = yone - 30;
374 
375   logfont.lfEscapement     = 2700; /* Causes verticle text drawing */
376   logfont.lfHeight         = windraw->stringheight;
377   logfont.lfWidth          = windraw->stringwidth;
378   logfont.lfOrientation    = 0;
379   logfont.lfCharSet        = DEFAULT_CHARSET;
380   logfont.lfClipPrecision  = 0;
381   logfont.lfItalic         = 0;
382   logfont.lfOutPrecision   = 0;
383   logfont.lfPitchAndFamily = DEFAULT_PITCH;
384   logfont.lfQuality        = DEFAULT_QUALITY;
385   logfont.lfStrikeOut      = 0;
386   logfont.lfUnderline      = 0;
387   logfont.lfWeight         = FW_NORMAL;
388 
389   hfont = CreateFontIndirect(&logfont);
390   TranslateColor_Win32(draw,color);
391   if (windraw->node->DoubleBuffered) hdc = windraw->node->DoubleBuffer;
392   else                               hdc = windraw->node->Buffer;
393 
394   SelectFont(hdc,hfont);
395   SetTextColor(hdc,windraw->currentcolor);
396   DrawText(hdc,text,lstrlen(text),&r,DT_NOCLIP | DT_SINGLELINE);
397   DeleteObject(hfont);
398   /* Forces a WM_PAINT message and erases background */
399   InvalidateRect(windraw->hWnd,NULL,TRUE);
400   UpdateWindow(windraw->hWnd);
401   PetscFunctionReturn(0);
402 }
403 
404 static PetscErrorCode PetscDrawStringSetSize_Win32(PetscDraw draw,PetscReal width,PetscReal height)
405 {
406   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
407   int             w,h;
408 
409   PetscFunctionBegin;
410   w = (int)((windraw->w)*width *(draw->port_xr - draw->port_xl)/(draw->coor_xr - draw->coor_xl));
411   h = (int)((windraw->h)*height*(draw->port_yr - draw->port_yl)/(draw->coor_yr - draw->coor_yl));
412   if (h < 1) h = 1;
413   if (w < 1) w = 1;
414   windraw->stringheight = h;
415   windraw->stringwidth  = w;
416   PetscFunctionReturn(0);
417 }
418 static PetscErrorCode PetscDrawStringGetSize_Win32(PetscDraw draw,PetscReal *width,PetscReal *height)
419 {
420   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
421   double          scaleX   = (draw->coor_xr - draw->coor_xl)/(draw->w)*(draw->port_xr - draw->port_xl);
422   double          scaleY   = (draw->coor_yr - draw->coor_yl)/(draw->h)*(draw->port_yr - draw->port_yl);
423 
424   PetscFunctionBegin;
425   if (height) *height = (double)windraw->stringheight*scaleY;
426   if (width)  *width  = (double)windraw->stringwidth*scaleX;
427   PetscFunctionReturn(0);
428 }
429 
430 static PetscErrorCode PetscDrawResizeWindow_Win32(PetscDraw draw,int w,int h)
431 {
432   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
433   RECT            r;
434 
435   PetscFunctionBegin;
436   GetWindowRect(windraw->hWnd,&r);
437   MoveWindow(windraw->hWnd,r.left,r.top,(int)w,(int)h,TRUE);
438   /* set all variable dealing with window dimensions */
439   windraw->node->bitheight = windraw->h = draw->h = h;
440   windraw->node->bitwidth  = windraw->w = draw->w = w;
441   /* set up graphic buffers with the new size of window */
442   SetBitmapDimensionEx(windraw->node->BufferBit,w,h,NULL);
443   if (windraw->node->DoubleBuffered) SetBitmapDimensionEx(windraw->node->DoubleBufferBit,w,h,NULL);
444   windraw->haveresized = PETSC_TRUE;
445   PetscFunctionReturn(0);
446 }
447 
448 static PetscErrorCode PetscDrawCheckResizedWindow_Win32(PetscDraw draw)
449 {
450   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
451 
452   PetscFunctionBegin;
453   if (windraw->haveresized == 1) PetscFunctionReturn(1);
454   else PetscFunctionReturn(0);
455 }
456 
457 static PetscErrorCode PetscDrawSetTitle_Win32(PetscDraw draw, const char title[])
458 {
459   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
460 
461   PetscFunctionBegin;
462   SetWindowText(windraw->hWnd,title);
463   PetscFunctionReturn(0);
464 }
465 
466 static PetscErrorCode PetscDrawClear_Win32(PetscDraw draw)
467 {
468   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
469 
470   PetscFunctionBegin;
471   /* clear primary buffer */
472   ExtFloodFill(windraw->node->Buffer,0,0,COLOR_WINDOW,FLOODFILLBORDER);
473   /* if exists clear secondary buffer */
474   if (windraw->node->DoubleBuffered) ExtFloodFill(windraw->node->DoubleBuffer,0,0,COLOR_WINDOW,FLOODFILLBORDER);
475 
476   /* force WM_PAINT message so cleared buffer will show */
477   InvalidateRect(windraw->hWnd,NULL,TRUE);
478   UpdateWindow(windraw->hWnd);
479   PetscFunctionReturn(0);
480 }
481 
482 static PetscErrorCode PetscDrawTriangle_Win32(PetscDraw draw,PetscReal x1,PetscReal yone,PetscReal x2,PetscReal y2,
483                                               PetscReal x3,PetscReal y3,int c1,int c2,int c3)
484 {
485   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
486   HBRUSH          hbrush;
487   HPEN            hpen;
488   int             p1x,p1y,p2x,p2y,p3x,p3y;
489   HDC             bit;
490 
491   PetscFunctionBegin;
492   AverageColorTriangle_Win32(draw,c1,c2,c3);
493   hbrush = CreateSolidBrush(windraw->currentcolor);
494   hpen   = CreatePen(PS_SOLID,0,windraw->currentcolor);
495   p1x    = XTRANS(draw,windraw,x1);
496   p2x    = XTRANS(draw,windraw,x2);
497   p3x    = XTRANS(draw,windraw,x3);
498   p1y    = YTRANS(draw,windraw,yone);
499   p2y    = YTRANS(draw,windraw,y2);
500   p3y    = YTRANS(draw,windraw,y3);
501 
502   if (windraw->node->DoubleBuffered) bit = windraw->node->DoubleBuffer;
503   else                               bit = windraw->node->Buffer;
504 
505   BeginPath(bit);
506   MoveToEx(bit,p1x,p1y,NULL);
507   LineTo(bit,p2x,p2y);
508   LineTo(bit,p3x,p3y);
509   LineTo(bit,p1x,p1y);
510   EndPath(bit);
511   SelectPen(bit,hpen);
512   SelectBrush(bit,hbrush);
513   StrokeAndFillPath(bit);
514   /* Forces a WM_PAINT message and erases background */
515   InvalidateRect(windraw->hWnd,NULL,TRUE);
516   UpdateWindow(windraw->hWnd);
517   PetscFunctionReturn(0);
518 }
519 
520 void PopMessageLoopThread_Win32(PetscDraw popdraw)
521 {
522   PetscDraw_Win32 *pop = (PetscDraw_Win32*)popdraw->data;
523   MSG             msg;
524   HWND            hWnd = NULL;
525   const char      PopClassName[] = "PETSc Window Pop Class";
526   RECT            r;
527   int             width,height;
528   WNDCLASSEX      myclass;
529   LPVOID          lpMsgBuf;
530 
531   PetscFunctionBegin;
532   /* initialize window class parameters */
533   myclass.cbSize        = sizeof(WNDCLASSEX);
534   myclass.style         = CS_OWNDC;
535   myclass.lpfnWndProc   = (WNDPROC)PetscWndProc;
536   myclass.cbClsExtra    = 0;
537   myclass.cbWndExtra    = 0;
538   myclass.hInstance     = NULL;
539   myclass.hIcon         = NULL;
540   myclass.hCursor       = LoadCursor(NULL, IDC_ARROW);
541   myclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
542   myclass.lpszMenuName  = NULL;
543   myclass.lpszClassName = PopClassName;
544   myclass.hIconSm       = NULL;
545 
546   RegisterClassEx(&myclass);
547 
548   SetRect(&r,0,0,450,450);
549 
550   width  = (r.right - r.left) / 3;
551   height = (r.bottom - r.top) / 3;
552 
553   hWnd = CreateWindowEx(0,
554                         PopClassName,
555                         NULL,
556                         WS_POPUPWINDOW | WS_CAPTION,
557                         0,0,
558                         width,height,
559                         NULL,
560                         NULL,
561                         hInst,
562                         NULL);
563   pop->x = 0;
564   pop->y = 0;
565   pop->w = width;
566   pop->h = height;
567 
568   if (!hWnd) {
569     lpMsgBuf = (LPVOID)"Window Not Successfully Created";
570     MessageBox(NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION);
571     LocalFree(lpMsgBuf);
572     exit(0);
573   }
574   pop->hWnd = hWnd;
575   /* display and update new popup window */
576   ShowWindow(pop->hWnd, SW_SHOWNORMAL);
577   UpdateWindow(pop->hWnd);
578   SetEvent(pop->hReadyEvent);
579 
580   while (GetMessage(&msg, pop->hWnd, 0, 0)) {
581     TranslateMessage(&msg);
582     DispatchMessage(&msg);
583   }
584   PetscFunctionReturnVoid();
585 }
586 
587 static PetscErrorCode PetscDrawDestroy_Win32(PetscDraw draw)
588 {
589   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
590 
591   PetscFunctionBegin;
592   SendMessage(windraw->hWnd,WM_DESTROY,0,0);
593   PetscFree(draw->data);
594   PetscFunctionReturn(0);
595 }
596 
597 void MessageLoopThread_Win32(PetscDraw draw)
598 {
599   PetscDraw_Win32 *windraw = (PetscDraw_Win32*)draw->data;
600   MSG             msg;
601   HWND            hWnd = NULL;
602   const char      classname[] = "PETSc Window Class";
603   WNDCLASSEX      wclass;
604   LPVOID          lpMsgBuf;
605 
606   PetscFunctionBegin;
607   /* initialize window class parameters */
608   wclass.cbSize        = sizeof(WNDCLASSEX);
609   wclass.style         = CS_SAVEBITS | CS_HREDRAW | CS_VREDRAW;
610   wclass.lpfnWndProc   = (WNDPROC)PetscWndProc;
611   wclass.cbClsExtra    = 0;
612   wclass.cbWndExtra    = 0;
613   wclass.hInstance     = NULL;
614   wclass.hIcon         = LoadIcon(NULL,IDI_APPLICATION);
615   wclass.hCursor       = LoadCursor(NULL,IDC_ARROW);
616   wclass.hbrBackground = GetStockBrush(WHITE_BRUSH);
617   wclass.lpszMenuName  = NULL;
618   wclass.lpszClassName = classname;
619   wclass.hIconSm       = NULL;
620 
621   RegisterClassEx(&wclass);
622 
623   hWnd = CreateWindowEx(0,
624                         classname,
625                         NULL,
626                         WS_OVERLAPPEDWINDOW,
627                         draw->x,
628                         draw->y,
629                         draw->w,
630                         draw->h,
631                         NULL,
632                         NULL,
633                         hInst,
634                         NULL);
635 
636   if (!hWnd) {
637     lpMsgBuf = (LPVOID)"Window Not Successfully Created";
638     MessageBox(NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION);
639     LocalFree(lpMsgBuf);
640     exit(0);
641   }
642   windraw->hWnd = hWnd;
643   /* display and update new window */
644   ShowWindow(hWnd,SW_SHOWNORMAL);
645   UpdateWindow(hWnd);
646   SetEvent(windraw->hReadyEvent);
647 
648   while (GetMessage(&msg,hWnd, 0, 0)) {
649     TranslateMessage(&msg);
650     DispatchMessage(&msg);
651   }
652   PetscFunctionReturnVoid();
653 }
654 
655 static struct _PetscDrawOps DvOps = { PetscDrawSetDoubleBuffer_Win32,
656                                       PetscDrawFlush_Win32,
657                                       PetscDrawLine_Win32,
658                                       PetscDrawLineSetWidth_Win32,
659                                       PetscDrawLineGetWidth_Win32,
660                                       PetscDrawPoint_Win32,
661                                       PetscDrawPointSetSize_Win32,
662                                       PetscDrawString_Win32,
663                                       PetscDrawStringVertical_Win32,
664                                       PetscDrawStringSetSize_Win32,
665                                       PetscDrawStringGetSize_Win32,
666                                       0,
667                                       PetscDrawClear_Win32,
668                                       PetscDrawRectangle_Win32,
669                                       PetscDrawTriangle_Win32,
670                                       0,
671                                       PetscDrawGetMouseButton_Win32,
672                                       PetscDrawPause_Win32,
673                                       0,
674                                       0,
675                                       PetscDrawGetPopup_Win32,
676                                       PetscDrawSetTitle_Win32,
677                                       PetscDrawCheckResizedWindow_Win32,
678                                       PetscDrawResizeWindow_Win32,
679                                       PetscDrawDestroy_Win32,
680                                       0,
681                                       0,
682                                       0,
683                                       0};
684 
685 static PetscErrorCode PetscDrawGetPopup_Win32(PetscDraw draw,PetscDraw *popup)
686 {
687   PetscErrorCode  ierr;
688   PetscDraw_Win32 *win = (PetscDraw_Win32*)draw->data;
689   PetscBool       flg  = PETSC_TRUE;
690 
691   PetscFunctionBegin;
692   ierr = PetscOptionsGetBool(((PetscObject)draw)->options,((PetscObject)draw)->prefix,"-draw_popup",&flg,NULL);CHKERRQ(ierr);
693   if (flg) {
694     ierr = PetscDrawCreate(PetscObjectComm((PetscObject)draw),NULL,NULL,win->x,win->y+win->h+36,220,220,popup);CHKERRQ(ierr);
695     ierr = PetscDrawSetType(*popup,PETSC_DRAW_WIN32);CHKERRQ(ierr);
696     draw->popup = *popup;
697   } else {
698     *popup = NULL;
699   }
700   PetscFunctionReturn(0);
701 }
702 PETSC_EXTERN PetscErrorCode  PetscDrawCreate_Win32(PetscDraw draw)
703 {
704   PetscDraw_Win32 *windraw;
705   HANDLE          hThread = NULL;
706   PetscErrorCode  ierr;
707   WindowNode      newnode;
708 
709   PetscFunctionBegin;
710   ierr       = PetscNew(&windraw);CHKERRQ(ierr);
711   draw->data = windraw;
712 
713   /* the following is temporary fix for initializing a global datastructure */
714   if (!g_hWindowListMutex) g_hWindowListMutex = CreateMutex(NULL,FALSE,NULL);
715   ierr = PetscMemcpy(draw->ops,&DvOps,sizeof(DvOps));CHKERRQ(ierr);
716 
717   windraw->hReadyEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
718   /* makes call to MessageLoopThread to creat window and attach a thread */
719   CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)MessageLoopThread_Win32,draw,0,(LPDWORD)hThread);
720   CloseHandle(hThread);
721   WaitForSingleObject(windraw->hReadyEvent,INFINITE);
722   CloseHandle(windraw->hReadyEvent);
723   WaitForSingleObject(g_hWindowListMutex,INFINITE);
724 
725   ierr                   = PetscNew(&newnode);CHKERRQ(ierr);
726   newnode->MouseListHead = NULL;
727   newnode->MouseListTail = NULL;
728   newnode->wnext         = WindowListHead;
729   newnode->wprev         = NULL;
730   newnode->hWnd          = windraw->hWnd;
731   if (WindowListHead) WindowListHead->wprev = newnode;
732   WindowListHead         = newnode;
733   windraw->hdc           = GetDC(windraw->hWnd);
734 
735   windraw->stringheight  = 10;
736   windraw->stringwidth   = 6;
737   windraw->linewidth     = 1;    /* default pixel sizes of graphics until user changes them */
738   windraw->pointdiameter = 1;
739   windraw->node          = newnode;
740 
741   windraw->x = draw->x;
742   windraw->y = draw->y;
743   windraw->w = newnode->bitwidth    = draw->w;
744   windraw->h = newnode->bitheight   = draw->h;
745 
746   /* Create and initialize primary graphics buffer */
747   newnode->Buffer    = CreateCompatibleDC(windraw->hdc);
748   newnode->BufferBit = CreateCompatibleBitmap(windraw->hdc,windraw->w,windraw->h);
749   newnode->store     = SelectObject(newnode->Buffer,newnode->BufferBit);
750   ExtFloodFill(newnode->Buffer,0,0,COLOR_WINDOW,FLOODFILLBORDER);
751 
752   newnode->event          = CreateEvent(NULL,TRUE,FALSE,NULL);
753   newnode->DoubleBuffered = PETSC_FALSE;
754 
755   ReleaseDC(windraw->hWnd,windraw->hdc);
756   ReleaseMutex(g_hWindowListMutex);
757   PetscFunctionReturn(0);
758 }
759 
760 /* FUNCTION: PetscWndProc(HWND, unsigned, WORD, LONG)
761    PURPOSE:  Processes messages for the main window.
762    WM_COMMAND  - process the application menu
763    WM_PAINT    - Paint the main window
764    WM_DESTROY  - post a quit message and return */
765 
766 LRESULT CALLBACK PetscWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
767 {
768   int wmId;
769 
770   PetscFunctionBegin;
771   switch (message) {
772     HANDLE_MSG(hWnd,WM_PAINT,OnPaint_Win32);
773     HANDLE_MSG(hWnd,WM_DESTROY,OnDestroy_Win32);
774   case WM_COMMAND:
775     wmId    = LOWORD(wParam);
776     /* Parse the menu selections:*/
777     switch (wmId) {
778     case IDM_EXIT:
779       DestroyWindow(hWnd);
780       break;
781     default:
782       return DefWindowProc(hWnd, message, wParam, lParam);
783     }
784     break;
785   case WM_LBUTTONUP:
786     MouseRecord_Win32(hWnd,PETSC_BUTTON_LEFT);
787     break;
788   case WM_RBUTTONUP:
789     MouseRecord_Win32(hWnd,PETSC_BUTTON_RIGHT);
790     break;
791   case WM_MBUTTONUP:
792     MouseRecord_Win32(hWnd,PETSC_BUTTON_CENTER);
793     break;
794   default:
795     PetscFunctionReturn(DefWindowProc(hWnd, message, wParam, lParam));
796   }
797   PetscFunctionReturn(0);
798 }
799 
800 static void OnPaint_Win32(HWND hWnd)
801 {
802   PAINTSTRUCT ps;
803   HDC         hdc;
804   WindowNode  current = NULL;
805 
806   PetscFunctionBegin;
807   InvalidateRect(hWnd,NULL,TRUE);
808   WaitForSingleObject(g_hWindowListMutex, INFINITE);
809   current = WindowListHead;
810   hdc     = BeginPaint(hWnd, &ps);
811 
812   while (current) {
813     if (current->hWnd == hWnd) {
814       /* flushes primary buffer to window */
815       BitBlt(hdc,0,0,GetDeviceCaps(hdc,HORZRES),GetDeviceCaps(hdc,VERTRES),
816              current->Buffer,0,0,SRCCOPY);
817 
818       /* StretchBlt(hdc,0,0,w,h,
819         current->Buffer,0,0,current->bitwidth,current->bitheight,SRCCOPY); */
820       break;
821     }
822     current = current->wnext;
823   }
824   EndPaint(hWnd, &ps);
825   ReleaseMutex(g_hWindowListMutex);
826   PetscFunctionReturnVoid();
827 }
828 
829 static PetscErrorCode MouseRecord_Win32(HWND hWnd,PetscDrawButton button)
830 {
831   /* Called by all three mouse button actions
832     Records needed mouse data in windows data structure */
833   WindowNode     current = NULL;
834   MouseNode      newnode;
835   POINT          mousepos;
836   PetscErrorCode ierr;
837 
838   PetscFunctionBegin;
839   WaitForSingleObject(g_hWindowListMutex, INFINITE);
840   current = WindowListHead;
841   if (current->IsGetMouseOn == TRUE) {
842 
843     SetEvent(current->event);
844     while (current) {
845       if (current->hWnd == hWnd) {
846 
847         ierr            = PetscNew(&newnode);CHKERRQ(ierr);
848         newnode->Button = button;
849         GetCursorPos(&mousepos);
850         newnode->user.x = mousepos.x;
851         newnode->user.y = mousepos.y;
852         ScreenToClient(hWnd,&mousepos);
853         newnode->phys.x = mousepos.x;
854         newnode->phys.y = mousepos.y;
855         if (!current->MouseListTail) {
856           current->MouseListHead = newnode;
857           current->MouseListTail = newnode;
858         } else {
859           current->MouseListTail->mnext = newnode;
860           current->MouseListTail        = newnode;
861         }
862         newnode->mnext = NULL;
863 
864         break;
865       }
866       current = current->wnext;
867     }
868   }
869   ReleaseMutex(g_hWindowListMutex);
870   PetscFunctionReturn(0);
871 }
872 
873 static void OnDestroy_Win32(HWND hWnd)
874 {
875   /* searches linked list of window data and frees corresponding memory */
876   WindowNode current;
877 
878   PetscFunctionBegin;
879   WaitForSingleObject(g_hWindowListMutex, INFINITE);
880   current = WindowListHead;
881 
882   SetEvent(current->event);
883   while (current) {
884     if (current->hWnd == hWnd) {
885       if (current->wprev) current->wprev->wnext = current->wnext;
886       else WindowListHead = current->wnext;
887       if (current->MouseListHead) deletemouselist_Win32(current);
888       else PetscFree(current);
889       break;
890     }
891     current = current->wnext;
892   }
893   ReleaseMutex(g_hWindowListMutex);
894   PostQuitMessage(0);
895   PetscFunctionReturnVoid();
896 }
897