1 /*
2 * Copyright © 2009 CNRS
3 * Copyright © 2009-2017 Inria. All rights reserved.
4 * Copyright © 2009-2010, 2012 Université Bordeaux
5 * Copyright © 2011 Cisco Systems, Inc. All rights reserved.
6 * See COPYING in top-level directory.
7 */
8
9 #include <private/autogen/config.h>
10 #include <hwloc.h>
11
12 #include <stdlib.h>
13 #include <stdio.h>
14 #ifdef HAVE_UNISTD_H
15 #include <unistd.h>
16 #endif
17 #include <string.h>
18
19 #include <windows.h>
20 #include <windowsx.h>
21
22 #include "lstopo.h"
23
24 /* windows back-end. */
25
26 static struct color {
27 int r, g, b;
28 HGDIOBJ brush;
29 } *colors;
30
31 struct lstopo_windows_output {
32 struct lstopo_output loutput; /* must be at the beginning */
33 int drawing;
34 PAINTSTRUCT ps;
35 HWND toplevel;
36 unsigned max_x;
37 unsigned max_y;
38 };
39
40 static int numcolors;
41
42 static HGDIOBJ
rgb_to_brush(int r,int g,int b)43 rgb_to_brush(int r, int g, int b)
44 {
45 int i;
46
47 for (i = 0; i < numcolors; i++)
48 if (colors[i].r == r && colors[i].g == g && colors[i].b == b)
49 return colors[i].brush;
50
51 fprintf(stderr, "color #%02x%02x%02x not declared\n", r, g, b);
52 exit(EXIT_FAILURE);
53 }
54
55 struct draw_methods windows_draw_methods;
56
57 static struct lstopo_windows_output the_output;
58 static int state, control;
59 static int the_x, the_y, x_delta, y_delta;
60 static int finish;
61 static int the_width, the_height;
62 static int win_width, win_height;
63 static unsigned int the_fontsize, the_gridsize;
64 static float the_scale;
65
66 static void
67 windows_box(void *output, int r, int g, int b, unsigned depth __hwloc_attribute_unused, unsigned x, unsigned width, unsigned y, unsigned height);
68
69 static LRESULT CALLBACK
WndProc(HWND hwnd,UINT message,WPARAM wparam,LPARAM lparam)70 WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
71 {
72 int redraw = 0;
73 switch (message) {
74 case WM_CHAR: {
75 switch (wparam) {
76 case '+':
77 the_scale *= 1.2f;
78 redraw = 1;
79 break;
80 case '-':
81 the_scale /= 1.2f;
82 redraw = 1;
83 break;
84 case 'f':
85 case 'F': {
86 float wscale, hscale;
87 wscale = win_width / (float)the_width;
88 hscale = win_height / (float)the_height;
89 the_scale *= wscale > hscale ? hscale : wscale;
90 redraw = 1;
91 break;
92 }
93 case '1':
94 the_scale = 1.0;
95 redraw = 1;
96 break;
97 case 'q':
98 case 'Q':
99 finish = 1;
100 break;
101 }
102 break;
103 }
104
105 case WM_PAINT: {
106 HFONT font;
107 BeginPaint(hwnd, &the_output.ps);
108 font = CreateFont(fontsize, 0, 0, 0, 0, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, NULL);
109 SelectObject(the_output.ps.hdc, (HGDIOBJ) font);
110 SetBkMode(the_output.ps.hdc, TRANSPARENT);
111 windows_box(&the_output, 0xff, 0xff, 0xff, 0, 0, win_width, 0, win_height);
112 the_output.max_x = 0;
113 the_output.max_y = 0;
114 output_draw(&the_output.loutput);
115 the_width = the_output.max_x;
116 the_height = the_output.max_y;
117 DeleteObject(font);
118 EndPaint(hwnd, &the_output.ps);
119 break;
120 }
121 case WM_LBUTTONDOWN:
122 state = 1;
123 the_x = GET_X_LPARAM(lparam);
124 the_y = GET_Y_LPARAM(lparam);
125 break;
126 case WM_LBUTTONUP:
127 state = 0;
128 break;
129 case WM_MOUSEMOVE:
130 if (!(wparam & MK_LBUTTON))
131 state = 0;
132 if (state) {
133 int new_x = GET_X_LPARAM(lparam);
134 int new_y = GET_Y_LPARAM(lparam);
135 x_delta -= new_x - the_x;
136 y_delta -= new_y - the_y;
137 the_x = new_x;
138 the_y = new_y;
139 redraw = 1;
140 }
141 break;
142 case WM_KEYDOWN:
143 switch (wparam) {
144 case VK_ESCAPE:
145 finish = 1;
146 break;
147 case VK_LEFT:
148 x_delta -= win_width/10;
149 redraw = 1;
150 break;
151 case VK_RIGHT:
152 x_delta += win_width/10;
153 redraw = 1;
154 break;
155 case VK_UP:
156 y_delta -= win_height/10;
157 redraw = 1;
158 break;
159 case VK_DOWN:
160 y_delta += win_height/10;
161 redraw = 1;
162 break;
163 case VK_PRIOR:
164 if (control) {
165 x_delta -= win_width;
166 redraw = 1;
167 } else {
168 y_delta -= win_height;
169 redraw = 1;
170 }
171 break;
172 case VK_NEXT:
173 if (control) {
174 x_delta += win_width;
175 redraw = 1;
176 } else {
177 y_delta += win_height;
178 redraw = 1;
179 }
180 break;
181 case VK_HOME:
182 x_delta = 0;
183 y_delta = 0;
184 redraw = 1;
185 break;
186 case VK_END:
187 x_delta = INT_MAX;
188 y_delta = INT_MAX;
189 redraw = 1;
190 break;
191 case VK_CONTROL:
192 control = 1;
193 break;
194 }
195 break;
196 case WM_KEYUP:
197 switch (wparam) {
198 case VK_CONTROL:
199 control = 0;
200 break;
201 }
202 break;
203 case WM_DESTROY:
204 /* only kill the program if closing the actual toplevel, not the fake one */
205 if (hwnd == the_output.toplevel)
206 PostQuitMessage(0);
207 return 0;
208 case WM_SIZE: {
209 float wscale, hscale;
210 win_width = LOWORD(lparam);
211 win_height = HIWORD(lparam);
212 wscale = win_width / (float)the_width;
213 hscale = win_height / (float)the_height;
214 the_scale *= wscale > hscale ? hscale : wscale;
215 if (the_scale < 1.0f)
216 the_scale = 1.0f;
217 redraw = 1;
218 break;
219 }
220 }
221 if (redraw) {
222 if (x_delta > the_width - win_width)
223 x_delta = the_width - win_width;
224 if (y_delta > the_height - win_height)
225 y_delta = the_height - win_height;
226 if (x_delta < 0)
227 x_delta = 0;
228 if (y_delta < 0)
229 y_delta = 0;
230 fontsize = (unsigned)(the_fontsize * the_scale);
231 gridsize = (unsigned)(the_gridsize * the_scale);
232 RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE);
233 }
234 return DefWindowProc(hwnd, message, wparam, lparam);
235 }
236
237 static void
windows_init(void * output)238 windows_init(void *output)
239 {
240 struct lstopo_windows_output *woutput = output;
241 WNDCLASS wndclass;
242 HWND toplevel, faketoplevel;
243 unsigned width, height;
244 HFONT font;
245
246 /* make sure WM_DESTROY on the faketoplevel won't kill the program */
247 woutput->toplevel = NULL;
248
249 /* create the toplevel window, with random size for now */
250 memset(&wndclass, 0, sizeof(wndclass));
251 wndclass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
252 wndclass.hCursor = LoadCursor(NULL, IDC_SIZEALL);
253 wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
254 wndclass.lpfnWndProc = WndProc;
255 wndclass.lpszClassName = "lstopo";
256
257 RegisterClass(&wndclass);
258
259 /* compute the maximal needed size, this may require the toplevel window in the future */
260 woutput->max_x = 0;
261 woutput->max_y = 0;
262 woutput->drawing = 0;
263 faketoplevel = CreateWindow("lstopo", "lstopo", WS_OVERLAPPEDWINDOW,
264 CW_USEDEFAULT, CW_USEDEFAULT,
265 10, 10, NULL, NULL, NULL, NULL);
266 BeginPaint(faketoplevel, &woutput->ps);
267 font = CreateFont(fontsize, 0, 0, 0, 0, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, NULL);
268 SelectObject(woutput->ps.hdc, (HGDIOBJ) font);
269 output_draw(&woutput->loutput);
270 DeleteObject(font);
271 EndPaint(faketoplevel, &woutput->ps);
272 DestroyWindow(faketoplevel);
273 woutput->drawing = 1;
274
275 /* now create the actual toplevel with the sizes */
276 width = woutput->max_x;
277 height = woutput->max_y;
278
279 win_width = width + 2*GetSystemMetrics(SM_CXSIZEFRAME);
280 win_height = height + 2*GetSystemMetrics(SM_CYSIZEFRAME) + GetSystemMetrics(SM_CYCAPTION);
281
282 if (win_width > GetSystemMetrics(SM_CXFULLSCREEN))
283 win_width = GetSystemMetrics(SM_CXFULLSCREEN);
284
285 if (win_height > GetSystemMetrics(SM_CYFULLSCREEN))
286 win_height = GetSystemMetrics(SM_CYFULLSCREEN);
287
288 toplevel = CreateWindow("lstopo", "lstopo", WS_OVERLAPPEDWINDOW,
289 CW_USEDEFAULT, CW_USEDEFAULT,
290 win_width, win_height, NULL, NULL, NULL, NULL);
291 woutput->toplevel = toplevel;
292
293 the_width = width;
294 the_height = height;
295
296 the_scale = 1.0f;
297
298 the_fontsize = fontsize;
299 the_gridsize = gridsize;
300
301 /* and display the window */
302 ShowWindow(toplevel, SW_SHOWDEFAULT);
303
304 printf("\n");
305 printf("Keyboard shortcuts:\n");
306 printf(" Zoom-in or out .................... + -\n");
307 printf(" Try to fit scale to window ........ f F\n");
308 printf(" Reset scale to default ............ 1\n");
309 printf(" Scroll vertically ................. Up Down PageUp PageDown\n");
310 printf(" Scroll horizontally ............... Left Right Ctrl+PageUp/Down\n");
311 printf(" Scroll to the top-left corner ..... Home\n");
312 printf(" Scroll to the bottom-right corner . End\n");
313 printf(" Exit .............................. q Q Esc\n");
314 printf("\n\n");
315 }
316
317 static void
windows_declare_color(void * output,int r,int g,int b)318 windows_declare_color(void *output, int r, int g, int b)
319 {
320 struct lstopo_windows_output *woutput = output;
321 HBRUSH brush;
322 COLORREF color;
323 struct color *tmp;
324
325 if (!woutput->drawing)
326 return;
327
328 color = RGB(r, g, b);
329 brush = CreateSolidBrush(color);
330 if (!brush) {
331 fprintf(stderr,"Could not allocate color %02x%02x%02x\n", r, g, b);
332 exit(EXIT_FAILURE);
333 }
334
335 tmp = realloc(colors, sizeof(*colors) * (numcolors + 1));
336 if (!tmp) {
337 fprintf(stderr, "Failed to realloc the colors array\n");
338 return;
339 }
340 colors = tmp;
341 colors[numcolors].r = r;
342 colors[numcolors].g = g;
343 colors[numcolors].b = b;
344 colors[numcolors].brush = (HGDIOBJ) brush;
345 numcolors++;
346 }
347
348 static void
windows_box(void * output,int r,int g,int b,unsigned depth __hwloc_attribute_unused,unsigned x,unsigned width,unsigned y,unsigned height)349 windows_box(void *output, int r, int g, int b, unsigned depth __hwloc_attribute_unused, unsigned x, unsigned width, unsigned y, unsigned height)
350 {
351 struct lstopo_windows_output *woutput = output;
352 PAINTSTRUCT *ps = &woutput->ps;
353
354 if (x > woutput->max_x)
355 woutput->max_x = x;
356 if (x+width > woutput->max_x)
357 woutput->max_x = x + width;
358 if (y > woutput->max_y)
359 woutput->max_y = y;
360 if (y + height > woutput->max_y)
361 woutput->max_y = y + height;
362
363 if (!woutput->drawing)
364 return;
365
366 SelectObject(ps->hdc, rgb_to_brush(r, g, b));
367 SetBkColor(ps->hdc, RGB(r, g, b));
368 Rectangle(ps->hdc, x - x_delta, y - y_delta, x + width - x_delta, y + height - y_delta);
369 }
370
371 static void
windows_line(void * output,int r,int g,int b,unsigned depth __hwloc_attribute_unused,unsigned x1,unsigned y1,unsigned x2,unsigned y2)372 windows_line(void *output, int r, int g, int b, unsigned depth __hwloc_attribute_unused, unsigned x1, unsigned y1, unsigned x2, unsigned y2)
373 {
374 struct lstopo_windows_output *woutput = output;
375 PAINTSTRUCT *ps = &woutput->ps;
376
377 if (x1 > woutput->max_x)
378 woutput->max_x = x1;
379 if (x2 > woutput->max_x)
380 woutput->max_x = x2;
381 if (y1 > woutput->max_y)
382 woutput->max_y = y1;
383 if (y2 > woutput->max_y)
384 woutput->max_y = y2;
385
386 if (!woutput->drawing)
387 return;
388
389 SelectObject(ps->hdc, rgb_to_brush(r, g, b));
390 MoveToEx(ps->hdc, x1 - x_delta, y1 - y_delta, NULL);
391 LineTo(ps->hdc, x2 - x_delta, y2 - y_delta);
392 }
393
394 static void
windows_text(void * output,int r,int g,int b,unsigned depth __hwloc_attribute_unused,unsigned x,unsigned y,const char * text)395 windows_text(void *output, int r, int g, int b, unsigned depth __hwloc_attribute_unused, unsigned x, unsigned y, const char *text)
396 {
397 struct lstopo_windows_output *woutput = output;
398 PAINTSTRUCT *ps = &woutput->ps;
399
400 if (!woutput->drawing)
401 return;
402
403 SetTextColor(ps->hdc, RGB(r, g, b));
404 TextOut(ps->hdc, x - x_delta, y - y_delta, text, (int)strlen(text));
405 }
406
407 static void
windows_textsize(void * output,const char * text,unsigned textlength,unsigned * width)408 windows_textsize(void *output, const char *text, unsigned textlength, unsigned *width)
409 {
410 struct lstopo_windows_output *woutput = output;
411 PAINTSTRUCT *ps = &woutput->ps;
412 SIZE size;
413
414 GetTextExtentPoint32(ps->hdc, text, textlength, &size);
415 *width = size.cx;
416 }
417
418 struct draw_methods windows_draw_methods = {
419 windows_init,
420 windows_declare_color,
421 windows_box,
422 windows_line,
423 windows_text,
424 windows_textsize,
425 };
426
427 void
output_windows(struct lstopo_output * loutput,const char * filename __hwloc_attribute_unused)428 output_windows (struct lstopo_output *loutput, const char *filename __hwloc_attribute_unused)
429 {
430 MSG msg;
431
432 memset(&the_output, 0, sizeof(the_output));
433 memcpy(&the_output.loutput, loutput, sizeof(*loutput));
434 the_output.loutput.methods = &windows_draw_methods;
435
436 output_draw_start(&the_output.loutput);
437 UpdateWindow(the_output.toplevel);
438 while (!finish && GetMessage(&msg, NULL, 0, 0)) {
439 TranslateMessage(&msg);
440 DispatchMessage(&msg);
441 }
442 }
443