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