C++
Windows
OpenCV

OpenCVのWindowをスナップさせたくない

OpenCVでWindowを作成し、画面の端に近づけると、勝手にスナップします。
微妙な位置に配置したい時など困りますので、この余計な機能を消してしまいましょう。

ソースを修正する

問題の個所は、「sources/modules/highgui/src/window_w32.cpp」にあります。

window_w32.cpp
    case WM_WINDOWPOSCHANGING:
       {
          // Snap window to screen edges with multi-monitor support. // Adi Shavit
          LPWINDOWPOS pos = (LPWINDOWPOS)lParam;

          RECT rect;
          GetWindowRect(window->frame, &rect);

          HMONITOR hMonitor;
          hMonitor = MonitorFromRect(&rect, MONITOR_DEFAULTTONEAREST);

          MONITORINFO mi;
          mi.cbSize = sizeof(mi);
          GetMonitorInfo(hMonitor, &mi);

          const int SNAP_DISTANCE = 15;

          if (abs(pos->x - mi.rcMonitor.left) <= SNAP_DISTANCE)
             pos->x = mi.rcMonitor.left;               // snap to left edge
          else
             if (abs(pos->x + pos->cx - mi.rcMonitor.right) <= SNAP_DISTANCE)
                pos->x = mi.rcMonitor.right - pos->cx; // snap to right edge

          if (abs(pos->y - mi.rcMonitor.top) <= SNAP_DISTANCE)
             pos->y = mi.rcMonitor.top;                 // snap to top edge
          else
             if (abs(pos->y + pos->cy - mi.rcMonitor.bottom) <= SNAP_DISTANCE)
                pos->y = mi.rcMonitor.bottom - pos->cy; // snap to bottom edge
       }

画面の上下左右15pixel以内になると「0」にしてしまうという力技を見せてくれています。
こんな処理は、さくっとコメントアウトしてしまいましょう。

window_w32.cpp
    case WM_WINDOWPOSCHANGING:
//       {
//          // Snap window to screen edges with multi-monitor support. // Adi Shavit
//          LPWINDOWPOS pos = (LPWINDOWPOS)lParam;
//
//          RECT rect;
//          GetWindowRect(window->frame, &rect);
//
//          HMONITOR hMonitor;
//          hMonitor = MonitorFromRect(&rect, MONITOR_DEFAULTTONEAREST);
//
//          MONITORINFO mi;
//          mi.cbSize = sizeof(mi);
//          GetMonitorInfo(hMonitor, &mi);
//
//          const int SNAP_DISTANCE = 15;
//
//          if (abs(pos->x - mi.rcMonitor.left) <= SNAP_DISTANCE)
//             pos->x = mi.rcMonitor.left;               // snap to left edge
//          else
//             if (abs(pos->x + pos->cx - mi.rcMonitor.right) <= SNAP_DISTANCE)
//                pos->x = mi.rcMonitor.right - pos->cx; // snap to right edge
//
//          if (abs(pos->y - mi.rcMonitor.top) <= SNAP_DISTANCE)
//             pos->y = mi.rcMonitor.top;                 // snap to top edge
//          else
//             if (abs(pos->y + pos->cy - mi.rcMonitor.bottom) <= SNAP_DISTANCE)
//                pos->y = mi.rcMonitor.bottom - pos->cy; // snap to bottom edge
//       }

※一応イベントは受け取り、下の処理(アクティブならフォーカスを当てる)を実行出来るよう、breakしたりはしません

余談

Windows10ではOSが余計なことをしてくれるそうですが、そちらは設定で変更できるようです。

まとめ

「小さな親切、大きなお世話」ということで、将来のバージョンでは削除されていることを祈ります。