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