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