Fix usage of the first parameter for TranslateAccelerator: this should be the handle...
[reactos.git] / reactos / base / applications / magnify / magnifier.c
1 /*
2 * PROJECT: ReactOS Magnify
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/applications/magnify/magnifier.c
5 * PURPOSE: Magnification of parts of the screen.
6 * AUTHORS:
7 * Marc Piulachs <marc.piulachs@codexchange.net>
8 * David Quintana <gigaherz@gmail.com>
9 */
10
11 /* TODO: Support AppBar types other than ABE_TOP */
12
13 #include "magnifier.h"
14
15 #include <winbase.h>
16 #include <winuser.h>
17 #include <wingdi.h>
18 #include <winnls.h>
19 #include <shellapi.h>
20 #include <windowsx.h>
21
22 #include "resource.h"
23
24 #define APPMSG_NOTIFYICON (WM_APP+1)
25 #define APPMSG_APPBAR (WM_APP+2)
26
27 const TCHAR szWindowClass[] = TEXT("MAGNIFIER");
28
29 /* Global Variables */
30 HINSTANCE hInst;
31 HWND hMainWnd;
32
33 #define MAX_LOADSTRING 100
34 TCHAR szTitle[MAX_LOADSTRING];
35
36 #define TIMER_SPEED 1
37 #define REPAINT_SPEED 100
38
39 DWORD lastTicks = 0;
40
41 HWND hDesktopWindow = NULL;
42
43 NOTIFYICONDATA nid;
44 HICON notifyIcon;
45 HMENU notifyMenu;
46 HWND hOptionsDialog;
47 BOOL bOptionsDialog = FALSE;
48 BOOL bRecreateOffscreenDC = TRUE;
49 LONG sourceWidth = 0;
50 LONG sourceHeight = 0;
51 HDC hdcOffscreen = NULL;
52 HBITMAP hbmpOffscreen = NULL;
53 HANDLE hbmpOld;
54 POINT ptDragOffset;
55 INT nearEdge;
56
57 /* Current magnified area */
58 POINT cp;
59
60 /* Last positions */
61 POINT pMouse;
62 POINT pCaret;
63 POINT pFocus;
64 HWND pCaretWnd;
65 HWND pFocusWnd;
66
67 ATOM MyRegisterClass(HINSTANCE hInstance);
68 BOOL InitInstance(HINSTANCE, int);
69 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
70 INT_PTR CALLBACK AboutProc(HWND, UINT, WPARAM, LPARAM);
71 INT_PTR CALLBACK OptionsProc(HWND, UINT, WPARAM, LPARAM);
72 INT_PTR CALLBACK WarningProc(HWND, UINT, WPARAM, LPARAM);
73
74 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
75 {
76 MSG msg;
77 HACCEL hAccelTable;
78
79 UNREFERENCED_PARAMETER(hPrevInstance);
80 UNREFERENCED_PARAMETER(lpCmdLine);
81
82 switch (GetUserDefaultUILanguage())
83 {
84 case MAKELANGID(LANG_HEBREW, SUBLANG_DEFAULT):
85 SetProcessDefaultLayout(LAYOUT_RTL);
86 break;
87
88 default:
89 break;
90 }
91
92 /* Initialize global strings */
93 LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
94 MyRegisterClass(hInstance);
95
96 /* Perform application initialization */
97 if (!InitInstance(hInstance, nCmdShow))
98 return FALSE;
99
100 hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_MAGNIFIER));
101
102 /* Main message loop */
103 while (GetMessage(&msg, NULL, 0, 0))
104 {
105 if (!TranslateAccelerator(hMainWnd, hAccelTable, &msg))
106 {
107 TranslateMessage(&msg);
108 DispatchMessage(&msg);
109 }
110 }
111
112
113 SelectObject(hdcOffscreen, hbmpOld);
114 DeleteObject (hbmpOffscreen);
115 DeleteDC(hdcOffscreen);
116
117 return (int) msg.wParam;
118 }
119
120 ATOM MyRegisterClass(HINSTANCE hInstance)
121 {
122 WNDCLASS wc;
123
124 wc.style = CS_HREDRAW | CS_VREDRAW;
125 wc.lpfnWndProc = WndProc;
126 wc.cbClsExtra = 0;
127 wc.cbWndExtra = 0;
128 wc.hInstance = hInstance;
129 wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON));
130 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
131 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
132 wc.lpszMenuName = NULL; //MAKEINTRESOURCE(IDC_MAGNIFIER);
133 wc.lpszClassName = szWindowClass;
134
135 return RegisterClass(&wc);
136 }
137
138 void DoAppBarStuff(DWORD mode)
139 {
140 UINT uState;
141 APPBARDATA data = {0};
142 data.cbSize = sizeof(data);
143 data.hWnd = hMainWnd;
144 data.uCallbackMessage = APPMSG_APPBAR;
145
146 if (mode == ABM_NEW || mode == ABM_SETPOS)
147 {
148 HWND hWndOrder = HWND_BOTTOM;
149 int rcw, rch;
150 RECT rcWorkArea;
151 SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWorkArea, 0);
152
153 if(mode == ABM_NEW)
154 {
155 SHAppBarMessage(ABM_NEW, &data);
156
157 switch(AppBarConfig.uEdge)
158 {
159 case ABE_LEFT:
160 data.rc.top = rcWorkArea.top;
161 data.rc.bottom = rcWorkArea.bottom;
162 data.rc.left = rcWorkArea.left;
163 data.rc.right = data.rc.left + AppBarConfig.appBarSizes.left;
164 break;
165 case ABE_TOP:
166 data.rc.left = rcWorkArea.left;
167 data.rc.right = rcWorkArea.right;
168 data.rc.top = rcWorkArea.top;
169 data.rc.bottom = data.rc.top + AppBarConfig.appBarSizes.top;
170 break;
171 case ABE_RIGHT:
172 data.rc.top = rcWorkArea.top;
173 data.rc.bottom = rcWorkArea.bottom;
174 data.rc.right = rcWorkArea.left;
175 data.rc.left = data.rc.right - AppBarConfig.appBarSizes.right;
176 break;
177 case ABE_BOTTOM:
178 data.rc.left = rcWorkArea.left;
179 data.rc.right = rcWorkArea.right;
180 data.rc.bottom = rcWorkArea.bottom;
181 data.rc.top = data.rc.bottom - AppBarConfig.appBarSizes.bottom;
182 break;
183 }
184 }
185 else
186 {
187 GetWindowRect(hMainWnd, &data.rc);
188 }
189
190 data.uEdge = AppBarConfig.uEdge;
191 uState = SHAppBarMessage(ABM_QUERYPOS, &data);
192
193 uState = SHAppBarMessage(ABM_SETPOS, &data);
194
195 rcw = data.rc.right-data.rc.left;
196 rch = data.rc.bottom-data.rc.top;
197
198 uState = SHAppBarMessage(ABM_GETSTATE, &data);
199 if(uState & ABS_ALWAYSONTOP)
200 hWndOrder = HWND_TOPMOST;
201
202 SetWindowPos(hMainWnd, hWndOrder, data.rc.left, data.rc.top, rcw, rch, SWP_SHOWWINDOW|SWP_NOCOPYBITS);
203
204 }
205 else if(mode == ABM_GETSTATE)
206 {
207 HWND hWndOrder = HWND_BOTTOM;
208 uState = SHAppBarMessage(ABM_GETSTATE, &data);
209 if(uState & ABS_ALWAYSONTOP)
210 hWndOrder = HWND_TOPMOST;
211 SetWindowPos(hMainWnd, hWndOrder, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
212 }
213 else if(mode == ABM_ACTIVATE)
214 {
215 SHAppBarMessage(ABM_ACTIVATE, &data);
216 }
217 else if(mode == ABM_WINDOWPOSCHANGED)
218 {
219 SHAppBarMessage(ABM_WINDOWPOSCHANGED, &data);
220 }
221 else if(mode == ABM_REMOVE)
222 {
223 SHAppBarMessage(ABM_REMOVE, &data);
224 }
225 }
226
227 void AttachAppBar(INT uEdge)
228 {
229 if (AppBarConfig.uEdge == uEdge)
230 return;
231
232 if(AppBarConfig.uEdge < 0 && uEdge >= 0)
233 {
234 SetWindowLongPtr(hMainWnd, GWL_STYLE, GetWindowLongPtr(hMainWnd, GWL_STYLE) & (~WS_CAPTION));
235 }
236 else if(uEdge < 0 && AppBarConfig.uEdge>=0)
237 {
238 SetWindowLongPtr(hMainWnd, GWL_STYLE, GetWindowLongPtr(hMainWnd, GWL_STYLE) | WS_CAPTION);
239 SetWindowPos(hMainWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_FRAMECHANGED);
240 }
241
242 if(AppBarConfig.uEdge >= 0)
243 {
244 DoAppBarStuff(ABM_REMOVE);
245 }
246
247 if (uEdge >=0)
248 {
249 AppBarConfig.uEdge = uEdge;
250 DoAppBarStuff(ABM_NEW);
251 }
252 else
253 {
254 RECT rc = AppBarConfig.rcFloating;
255 SetWindowPos(hMainWnd, HWND_TOPMOST, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, 0);
256 }
257
258 AppBarConfig.uEdge = uEdge;
259 }
260
261 BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
262 {
263 RECT rc;
264 DWORD exStyles = WS_EX_TOOLWINDOW | WS_EX_CONTROLPARENT;
265 DWORD dwStyles = WS_SIZEBOX | WS_SYSMENU | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_POPUP;
266
267 /* Load settings from registry */
268 LoadSettings();
269
270 rc = AppBarConfig.rcFloating;
271
272 hInst = hInstance; // Store instance handle in our global variable
273
274 if (AppBarConfig.uEdge<0)
275 {
276 dwStyles |= WS_CAPTION;
277 exStyles |= WS_EX_TOPMOST;
278 }
279
280 /* Create the Window */
281 hMainWnd = CreateWindowEx(
282 exStyles,
283 szWindowClass,
284 szTitle,
285 dwStyles,
286 rc.left,
287 rc.top,
288 rc.right-rc.left,
289 rc.bottom-rc.top,
290 NULL,
291 NULL,
292 hInstance,
293 NULL);
294
295 if (!hMainWnd)
296 return FALSE;
297
298 if (AppBarConfig.uEdge>=0) DoAppBarStuff(ABM_NEW);
299 else SetWindowPos(hMainWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW);
300
301 // In Windows 2003's Magnifier, the "Start Minimized" setting
302 // refers exclusively to the options dialog, not the main window itself.
303 hOptionsDialog = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_DIALOGOPTIONS), hMainWnd, OptionsProc);
304 if (bStartMinimized)
305 ShowWindow(hOptionsDialog, SW_HIDE);
306 else
307 ShowWindow(hOptionsDialog, SW_SHOW);
308
309 if (bShowWarning)
310 DialogBox(hInstance, MAKEINTRESOURCE(IDD_WARNINGDIALOG), hMainWnd, WarningProc);
311
312 return TRUE;
313 }
314
315 void Refresh()
316 {
317 if (!IsIconic(hMainWnd))
318 {
319 /* Invalidate the client area forcing a WM_PAINT message */
320 InvalidateRgn(hMainWnd, NULL, TRUE);
321 }
322 }
323
324 void GetBestOverlapWithMonitors(LPRECT rect)
325 {
326 int rcLeft, rcTop;
327 int rcWidth, rcHeight;
328 RECT rcMon;
329 HMONITOR hMon = MonitorFromRect(rect, MONITOR_DEFAULTTONEAREST);
330 MONITORINFO info;
331 info.cbSize = sizeof(info);
332
333 GetMonitorInfo(hMon, &info);
334
335 rcMon = info.rcMonitor;
336
337 rcLeft = rect->left;
338 rcTop = rect->top;
339 rcWidth = (rect->right - rect->left);
340 rcHeight = (rect->bottom - rect->top);
341
342 if (rcLeft < rcMon.left)
343 rcLeft = rcMon.left;
344
345 if (rcTop < rcMon.top)
346 rcTop = rcMon.top;
347
348 if (rcLeft > (rcMon.right - rcWidth))
349 rcLeft = (rcMon.right - rcWidth);
350
351 if (rcTop > (rcMon.bottom - rcHeight))
352 rcTop = (rcMon.bottom - rcHeight);
353
354 OffsetRect(rect, (rcLeft-rect->left), (rcTop-rect->top));
355 }
356
357 void Draw(HDC aDc)
358 {
359 HDC desktopHdc = NULL;
360
361 RECT sourceRect, intersectedRect;
362 RECT targetRect, appRect;
363 DWORD rop = SRCCOPY;
364 CURSORINFO cinfo;
365 ICONINFO iinfo;
366
367 int AppWidth, AppHeight;
368
369 if (bInvertColors)
370 rop = NOTSRCCOPY;
371
372 desktopHdc = GetDC(0);
373
374 GetClientRect(hMainWnd, &appRect);
375 AppWidth = (appRect.right - appRect.left);
376 AppHeight = (appRect.bottom - appRect.top);
377
378 ZeroMemory(&cinfo, sizeof(cinfo));
379 ZeroMemory(&iinfo, sizeof(iinfo));
380 cinfo.cbSize = sizeof(cinfo);
381 GetCursorInfo(&cinfo);
382 GetIconInfo(cinfo.hCursor, &iinfo);
383
384 targetRect = appRect;
385 ClientToScreen(hMainWnd, (POINT*)&targetRect.left);
386 ClientToScreen(hMainWnd, (POINT*)&targetRect.right);
387
388 if (bRecreateOffscreenDC || !hdcOffscreen)
389 {
390 bRecreateOffscreenDC = FALSE;
391
392 if(hdcOffscreen)
393 {
394 SelectObject(hdcOffscreen, hbmpOld);
395 DeleteObject (hbmpOffscreen);
396 DeleteDC(hdcOffscreen);
397 }
398
399 sourceWidth = AppWidth / iZoom;
400 sourceHeight = AppHeight / iZoom;
401
402 /* Create a memory DC compatible with client area DC */
403 hdcOffscreen = CreateCompatibleDC(desktopHdc);
404
405 /* Create a bitmap compatible with the client area DC */
406 hbmpOffscreen = CreateCompatibleBitmap(
407 desktopHdc,
408 sourceWidth,
409 sourceHeight);
410
411 /* Select our bitmap in memory DC and save the old one */
412 hbmpOld = SelectObject(hdcOffscreen , hbmpOffscreen);
413 }
414
415 GetWindowRect(hDesktopWindow, &sourceRect);
416 sourceRect.left = (cp.x) - (sourceWidth /2);
417 sourceRect.top = (cp.y) - (sourceHeight /2);
418 sourceRect.right = sourceRect.left + sourceWidth;
419 sourceRect.bottom = sourceRect.top + sourceHeight;
420
421 GetBestOverlapWithMonitors(&sourceRect);
422
423 /* Paint the screen bitmap to our in memory DC */
424 BitBlt(
425 hdcOffscreen,
426 0,
427 0,
428 sourceWidth,
429 sourceHeight,
430 desktopHdc,
431 sourceRect.left,
432 sourceRect.top,
433 rop);
434
435 if (IntersectRect(&intersectedRect, &sourceRect, &targetRect))
436 {
437 OffsetRect(&intersectedRect, -sourceRect.left, -sourceRect.top);
438 FillRect(hdcOffscreen, &intersectedRect, GetStockObject(DC_BRUSH));
439 }
440
441 /* Draw the mouse pointer in the right position */
442 DrawIcon(
443 hdcOffscreen ,
444 pMouse.x - iinfo.xHotspot - sourceRect.left, // - 10,
445 pMouse.y - iinfo.yHotspot - sourceRect.top, // - 10,
446 cinfo.hCursor);
447
448 /* Blast the stretched image from memory DC to window DC */
449 StretchBlt(
450 aDc,
451 0,
452 0,
453 AppWidth,
454 AppHeight,
455 hdcOffscreen,
456 0,
457 0,
458 sourceWidth,
459 sourceHeight,
460 SRCCOPY | NOMIRRORBITMAP);
461
462 /* Cleanup */
463 if (iinfo.hbmMask)
464 DeleteObject(iinfo.hbmMask);
465 if (iinfo.hbmColor)
466 DeleteObject(iinfo.hbmColor);
467 ReleaseDC(hDesktopWindow, desktopHdc);
468 }
469
470 void HandleNotifyIconMessage(HWND hWnd, WPARAM wParam, LPARAM lParam)
471 {
472 POINT pt;
473
474 switch(lParam)
475 {
476 case WM_LBUTTONUP:
477 PostMessage(hMainWnd, WM_COMMAND, IDM_OPTIONS, 0);
478 break;
479 case WM_RBUTTONUP:
480 GetCursorPos (&pt);
481 TrackPopupMenu(notifyMenu, 0, pt.x, pt.y, 0, hWnd, NULL);
482 break;
483 }
484 }
485
486 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
487 {
488 int wmId;
489
490 switch (message)
491 {
492 case WM_TIMER:
493 {
494 BOOL hasMoved = FALSE;
495
496 GUITHREADINFO guiInfo;
497 guiInfo.cbSize = sizeof(guiInfo);
498
499 GetGUIThreadInfo(0, &guiInfo);
500
501 if (bFollowMouse)
502 {
503 POINT pNewMouse;
504
505 //Get current mouse position
506 GetCursorPos (&pNewMouse);
507
508 #define PointsAreEqual(pt1, pt2) (((pt1).x == (pt2).x) && ((pt1).y == (pt2).y))
509
510 //If mouse has moved ...
511 if (!PointsAreEqual(pMouse, pNewMouse))
512 {
513 //Update to new position
514 pMouse = pNewMouse;
515 cp = pNewMouse;
516 hasMoved = TRUE;
517 }
518 }
519
520 if(guiInfo.hwndActive != hMainWnd)
521 {
522 if (bFollowCaret)
523 {
524 if (guiInfo.hwndCaret)
525 {
526 POINT ptCaret;
527 ptCaret.x = (guiInfo.rcCaret.left + guiInfo.rcCaret.right) / 2;
528 ptCaret.y = (guiInfo.rcCaret.top + guiInfo.rcCaret.bottom) / 2;
529
530 if ((pCaretWnd != guiInfo.hwndCaret) || !PointsAreEqual(pCaret, ptCaret))
531 {
532 //Update to new position
533 pCaret = ptCaret;
534 pCaretWnd = guiInfo.hwndCaret;
535 if(!hasMoved)
536 {
537 ClientToScreen (guiInfo.hwndCaret, (LPPOINT) &ptCaret);
538 cp = ptCaret;
539 hasMoved = TRUE;
540 }
541 }
542 }
543 else
544 {
545 pCaretWnd = NULL;
546 }
547 }
548
549 if (bFollowFocus)
550 {
551 if(guiInfo.hwndFocus && !guiInfo.hwndCaret)
552 {
553 POINT ptFocus;
554 RECT activeRect;
555
556 //Get current control focus
557 GetWindowRect(guiInfo.hwndFocus, &activeRect);
558 ptFocus.x = (activeRect.left + activeRect.right) / 2;
559 ptFocus.y = (activeRect.top + activeRect.bottom) / 2;
560
561 if((guiInfo.hwndFocus != pFocusWnd) || !PointsAreEqual(pFocus, ptFocus))
562 {
563 //Update to new position
564 pFocus = ptFocus;
565 pFocusWnd = guiInfo.hwndFocus;
566 if(!hasMoved)
567 {
568 cp = ptFocus;
569 hasMoved = TRUE;
570 }
571 }
572 }
573 else
574 {
575 pFocusWnd = NULL;
576 }
577 }
578 }
579
580 if(!hasMoved)
581 {
582 DWORD newTicks = GetTickCount();
583 DWORD elapsed = (newTicks - lastTicks);
584 if(elapsed > REPAINT_SPEED)
585 {
586 hasMoved = TRUE;
587 }
588 }
589
590 if(hasMoved)
591 {
592 lastTicks = GetTickCount();
593 Refresh();
594 }
595
596 return 0;
597 }
598
599 case WM_COMMAND:
600 {
601 wmId = LOWORD(wParam);
602 /* Parse the menu selections */
603 switch (wmId)
604 {
605 case IDM_OPTIONS:
606 if(bOptionsDialog)
607 {
608 ShowWindow(hOptionsDialog, SW_HIDE);
609 }
610 else
611 {
612 ShowWindow(hOptionsDialog, SW_SHOW);
613 }
614 break;
615 case IDM_ABOUT:
616 DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, AboutProc);
617 break;
618 case IDM_EXIT:
619 DestroyWindow(hWnd);
620 break;
621 default:
622 return DefWindowProc(hWnd, message, wParam, lParam);
623 }
624 return 0;
625 }
626
627 case WM_PAINT:
628 {
629 PAINTSTRUCT PaintStruct;
630 HDC dc;
631 dc = BeginPaint(hWnd, &PaintStruct);
632 Draw(dc);
633 EndPaint(hWnd, &PaintStruct);
634 return 0;
635 }
636
637 case WM_CONTEXTMENU:
638 TrackPopupMenu(notifyMenu, 0, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), 0, hWnd, NULL);
639 return 0;
640
641 case WM_LBUTTONDOWN:
642 {
643 RECT rc;
644 POINT pt;
645 SetCapture(hWnd);
646
647 GetCursorPos(&pt);
648 GetWindowRect(hWnd, &rc);
649 ptDragOffset.x = pt.x - rc.left;
650 ptDragOffset.y = pt.y - rc.top;
651
652 nearEdge = AppBarConfig.uEdge;
653
654 break;
655 }
656 case WM_MOUSEMOVE:
657 if(GetCapture() == hWnd)
658 {
659 RECT rc;
660 POINT pt;
661 RECT rcWorkArea;
662 SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWorkArea, 0);
663 GetCursorPos(&pt);
664 GetWindowRect(hWnd, &rc);
665
666 if(AppBarConfig.uEdge>=0)
667 {
668 if (pt.x >= rcWorkArea.left && pt.x <= rcWorkArea.right &&
669 pt.y >= rcWorkArea.top && pt.y <= rcWorkArea.bottom)
670 {
671 AttachAppBar(-2);
672
673 // Fixup offset
674 GetWindowRect(hWnd, &rc);
675 ptDragOffset.x = (rc.right-rc.left)/2;
676 ptDragOffset.y = 2;
677
678 rc.left = pt.x - ptDragOffset.x;
679 rc.top = pt.y - ptDragOffset.y;
680
681 SetWindowPos(hWnd, HWND_TOPMOST, rc.left, rc.top, 0, 0, SWP_NOSIZE);
682 }
683 }
684 else
685 {
686 if(pt.x <= rcWorkArea.left+8 && nearEdge != ABE_LEFT)
687 {
688 AttachAppBar(ABE_LEFT);
689 nearEdge = ABE_LEFT;
690 }
691 else if(pt.y <= rcWorkArea.top+8 && nearEdge != ABE_TOP)
692 {
693 AttachAppBar(ABE_TOP);
694 nearEdge = ABE_TOP;
695 }
696 else if(pt.x >= rcWorkArea.right-8 && nearEdge != ABE_RIGHT)
697 {
698 AttachAppBar(ABE_RIGHT);
699 nearEdge = ABE_RIGHT;
700 }
701 else if(pt.y >= rcWorkArea.bottom-8 && nearEdge != ABE_BOTTOM)
702 {
703 AttachAppBar(ABE_BOTTOM);
704 nearEdge = ABE_BOTTOM;
705 }
706 else
707 {
708 rc.left = pt.x - ptDragOffset.x;
709 rc.top = pt.y - ptDragOffset.y;
710
711 SetWindowPos(hWnd, HWND_TOPMOST, rc.left, rc.top, 0, 0, SWP_NOSIZE);
712 nearEdge = -1;
713 }
714 }
715
716 pMouse = pt;
717 Refresh();
718 }
719 break;
720 case WM_LBUTTONUP:
721 if(GetCapture() == hWnd)
722 {
723 if (AppBarConfig.uEdge>=0)
724 DoAppBarStuff(ABM_GETSTATE);
725 else
726 SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
727 ReleaseCapture();
728 }
729
730 case WM_SIZE:
731 if(AppBarConfig.uEdge>=0) DoAppBarStuff(ABM_SETPOS);
732 /* fallthrough */
733 case WM_DISPLAYCHANGE:
734 bRecreateOffscreenDC = TRUE;
735 Refresh();
736 break;
737
738 case WM_ERASEBKGND:
739 // handle WM_ERASEBKGND by simply returning non-zero because we did all the drawing in WM_PAINT.
740 return 0;
741
742 case WM_DESTROY:
743 if(AppBarConfig.uEdge>=0) DoAppBarStuff(ABM_REMOVE);
744
745 /* Save settings to registry */
746 SaveSettings();
747 KillTimer(hWnd , 1);
748 PostQuitMessage(0);
749
750 /* Cleanup notification icon */
751 ZeroMemory(&nid, sizeof(nid));
752 nid.cbSize = sizeof(nid);
753 nid.uFlags = NIF_MESSAGE;
754 nid.hWnd = hWnd;
755 nid.uCallbackMessage = APPMSG_NOTIFYICON;
756 Shell_NotifyIcon(NIM_DELETE, &nid);
757
758 DestroyIcon(notifyIcon);
759
760 DestroyWindow(hOptionsDialog);
761 return 0;
762
763 case WM_CREATE:
764 {
765 HMENU tempMenu;
766
767 /* Get the desktop window */
768 hDesktopWindow = GetDesktopWindow();
769
770 /* Set the timer */
771 SetTimer (hWnd , 1, TIMER_SPEED , NULL);
772
773 /* Notification icon */
774 notifyIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_ICON), IMAGE_ICON, 16, 16, 0);
775
776 ZeroMemory(&nid, sizeof(nid));
777 nid.cbSize = sizeof(nid);
778 nid.uFlags = NIF_ICON | NIF_MESSAGE;
779 nid.hWnd = hWnd;
780 nid.uCallbackMessage = APPMSG_NOTIFYICON;
781 nid.hIcon = notifyIcon;
782 Shell_NotifyIcon(NIM_ADD, &nid);
783
784 tempMenu = LoadMenu(hInst, MAKEINTRESOURCE(IDC_MAGNIFIER));
785 notifyMenu = GetSubMenu(tempMenu, 0);
786 RemoveMenu(tempMenu, 0, MF_BYPOSITION);
787 DestroyMenu(tempMenu);
788 return 0;
789 }
790
791 case APPMSG_APPBAR:
792 {
793 switch (wParam)
794 {
795 case ABN_STATECHANGE:
796 DoAppBarStuff(ABM_GETSTATE);
797 break;
798 case ABN_POSCHANGED:
799 DoAppBarStuff(ABM_SETPOS);
800 break;
801 case ABN_FULLSCREENAPP:
802 {
803 if(!lParam)
804 {
805 DoAppBarStuff(ABM_GETSTATE);
806 break;
807 }
808
809 SetWindowPos(hMainWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
810 break;
811 }
812 case ABN_WINDOWARRANGE:
813 if(lParam)
814 ShowWindow(hMainWnd, SW_HIDE);
815 else
816 ShowWindow(hMainWnd, SW_SHOW);
817 }
818 return 0;
819 }
820
821 case APPMSG_NOTIFYICON:
822 HandleNotifyIconMessage(hWnd, wParam, lParam);
823 return 0;
824
825 case WM_ACTIVATE:
826 if(AppBarConfig.uEdge>=0) DoAppBarStuff(ABM_ACTIVATE);
827 break;
828
829 case WM_WINDOWPOSCHANGED:
830 if(AppBarConfig.uEdge>=0) DoAppBarStuff(ABM_WINDOWPOSCHANGED);
831 Refresh();
832 break;
833
834 default:
835 break;
836 }
837
838 return DefWindowProc(hWnd, message, wParam, lParam);
839 }
840
841 INT_PTR CALLBACK AboutProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
842 {
843 UNREFERENCED_PARAMETER(lParam);
844 switch (message)
845 {
846 case WM_INITDIALOG:
847 return (INT_PTR)TRUE;
848
849 case WM_COMMAND:
850 if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
851 {
852 EndDialog(hDlg, LOWORD(wParam));
853 return (INT_PTR)TRUE;
854 }
855 break;
856 }
857
858 return (INT_PTR)FALSE;
859 }
860
861 INT_PTR CALLBACK OptionsProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
862 {
863 UNREFERENCED_PARAMETER(lParam);
864 switch (message)
865 {
866 case WM_SHOWWINDOW:
867 bOptionsDialog = wParam;
868 break;
869 case WM_INITDIALOG:
870 {
871 // Add the zoom items...
872 SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("1"));
873 SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("2"));
874 SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("3"));
875 SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("4"));
876 SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("5"));
877 SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("6"));
878 SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("7"));
879 SendDlgItemMessage(hDlg, IDC_ZOOM, CB_ADDSTRING, 0, (LPARAM)("8"));
880
881 SendDlgItemMessage(hDlg, IDC_ZOOM, CB_SETCURSEL, iZoom - 1, 0);
882
883 if (bFollowMouse)
884 SendDlgItemMessage(hDlg,IDC_FOLLOWMOUSECHECK,BM_SETCHECK , wParam ,0);
885
886 if (bFollowFocus)
887 SendDlgItemMessage(hDlg,IDC_FOLLOWKEYBOARDCHECK,BM_SETCHECK , wParam ,0);
888
889 if (bFollowCaret)
890 SendDlgItemMessage(hDlg,IDC_FOLLOWTEXTEDITINGCHECK,BM_SETCHECK , wParam ,0);
891
892 if (bInvertColors)
893 SendDlgItemMessage(hDlg,IDC_INVERTCOLORSCHECK,BM_SETCHECK , wParam ,0);
894
895 if (bStartMinimized)
896 SendDlgItemMessage(hDlg,IDC_STARTMINIMIZEDCHECK,BM_SETCHECK , wParam ,0);
897
898 if (bShowMagnifier)
899 SendDlgItemMessage(hDlg,IDC_SHOWMAGNIFIERCHECK,BM_SETCHECK , wParam ,0);
900
901 return (INT_PTR)TRUE;
902 }
903
904 case WM_COMMAND:
905 switch (LOWORD(wParam))
906 {
907 case IDOK:
908 case IDCANCEL:
909 ShowWindow(hDlg, SW_HIDE);
910 return (INT_PTR)TRUE;
911
912 case IDC_BUTTON_HELP:
913 /* Unimplemented */
914 MessageBox(hDlg , TEXT("Magnifier help not available yet!") , TEXT("Help") , MB_OK);
915 break;
916 case IDC_ZOOM:
917 if (HIWORD(wParam) == CBN_SELCHANGE)
918 {
919 HWND hCombo = GetDlgItem(hDlg,IDC_ZOOM);
920
921 /* Get index of current selection and the text of that selection */
922 iZoom = SendMessage( hCombo, CB_GETCURSEL, (WPARAM) wParam, (LPARAM) lParam ) + 1;
923
924 /* Update the magnifier UI */
925 Refresh();
926 }
927 break;
928 case IDC_INVERTCOLORSCHECK:
929 bInvertColors = IsDlgButtonChecked(hDlg, IDC_INVERTCOLORSCHECK);
930 Refresh();
931 break;
932 case IDC_FOLLOWMOUSECHECK:
933 bFollowMouse = IsDlgButtonChecked(hDlg, IDC_FOLLOWMOUSECHECK);
934 break;
935 case IDC_FOLLOWKEYBOARDCHECK:
936 bFollowFocus = IsDlgButtonChecked(hDlg, IDC_FOLLOWKEYBOARDCHECK);
937 break;
938 case IDC_FOLLOWTEXTEDITINGCHECK:
939 bFollowCaret = IsDlgButtonChecked(hDlg, IDC_FOLLOWTEXTEDITINGCHECK);
940 break;
941 case IDC_STARTMINIMIZEDCHECK:
942 bStartMinimized = IsDlgButtonChecked(hDlg, IDC_STARTMINIMIZEDCHECK);
943 break;
944 case IDC_SHOWMAGNIFIER:
945 bShowMagnifier = IsDlgButtonChecked(hDlg, IDC_SHOWMAGNIFIERCHECK);
946 if (bShowMagnifier)
947 ShowWindow (hMainWnd , SW_SHOW);
948 else
949 ShowWindow (hMainWnd , SW_HIDE);
950 break;
951 }
952 }
953
954 return (INT_PTR)FALSE;
955 }
956
957 INT_PTR CALLBACK WarningProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
958 {
959 UNREFERENCED_PARAMETER(lParam);
960
961 switch (message)
962 {
963 case WM_INITDIALOG:
964 return (INT_PTR)TRUE;
965
966 case WM_COMMAND:
967 switch (LOWORD(wParam))
968 {
969 case IDC_SHOWWARNINGCHECK:
970 bShowWarning = !IsDlgButtonChecked(hDlg, IDC_SHOWWARNINGCHECK);
971 break;
972 }
973 if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
974 {
975 EndDialog(hDlg, LOWORD(wParam));
976 return (INT_PTR)TRUE;
977 }
978 break;
979 }
980
981 return (INT_PTR)FALSE;
982 }