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