15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/gfx/win/hwnd_util.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/i18n/rtl.h"
87d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/strings/string_util.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/metro.h"
103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/win/win_util.h"
11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/gfx/point.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/rect.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/size.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)namespace gfx {
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Adjust the window to fit.
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AdjustWindowToFit(HWND hwnd, const RECT& bounds, bool fit_to_monitor) {
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (fit_to_monitor) {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Get the monitor.
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HMONITOR hmon = MonitorFromRect(&bounds, MONITOR_DEFAULTTONEAREST);
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (hmon) {
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      MONITORINFO mi;
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mi.cbSize = sizeof(mi);
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      GetMonitorInfo(hmon, &mi);
28d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      Rect window_rect(bounds);
29d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      Rect monitor_rect(mi.rcWork);
30d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      Rect new_window_rect = window_rect;
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new_window_rect.AdjustToFit(monitor_rect);
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (new_window_rect != window_rect) {
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Window doesn't fit on monitor, move and possibly resize.
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SetWindowPos(hwnd, 0, new_window_rect.x(), new_window_rect.y(),
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     new_window_rect.width(), new_window_rect.height(),
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     SWP_NOACTIVATE | SWP_NOZORDER);
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Else fall through.
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "Unable to find default monitor";
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Fall through.
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }  // Else fall through.
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The window is not being fit to monitor, or the window fits on the monitor
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // as is, or we have no monitor info; reset the bounds.
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ::SetWindowPos(hwnd, 0, bounds.left, bounds.top,
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 bounds.right - bounds.left, bounds.bottom - bounds.top,
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 SWP_NOACTIVATE | SWP_NOZORDER);
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
530f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)// Turn off optimizations for these functions so they show up in crash reports.
540f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)MSVC_DISABLE_OPTIMIZE();
550f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
560f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)void CrashOutOfMemory() {
57cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  PLOG(FATAL);
580f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
590f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
600f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)void CrashAccessDenied() {
61cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  PLOG(FATAL);
620f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
630f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
640f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)// Crash isn't one of the ones we commonly see.
650f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)void CrashOther() {
66cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  PLOG(FATAL);
670f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
680f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
690f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)MSVC_ENABLE_OPTIMIZE();
700f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::string16 GetClassName(HWND window) {
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // GetClassNameW will return a truncated result (properly null terminated) if
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the given buffer is not large enough.  So, it is not possible to determine
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // that we got the entire class name if the result is exactly equal to the
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // size of the buffer minus one.
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD buffer_size = MAX_PATH;
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (true) {
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::wstring output;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DWORD size_ret =
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GetClassNameW(window, WriteInto(&output, buffer_size), buffer_size);
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (size_ret == 0)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (size_ret < (buffer_size - 1)) {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      output.resize(size_ret);
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return output;
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    buffer_size *= 2;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return std::wstring();  // error
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma warning(push)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma warning(disable:4312 4244)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WNDPROC SetWindowProc(HWND hwnd, WNDPROC proc) {
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The reason we don't return the SetwindowLongPtr() value is that it returns
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the orignal window procedure and not the current one. I don't know if it is
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // a bug or an intended feature.
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WNDPROC oldwindow_proc =
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reinterpret_cast<WNDPROC>(GetWindowLongPtr(hwnd, GWLP_WNDPROC));
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetWindowLongPtr(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(proc));
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return oldwindow_proc;
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void* SetWindowUserData(HWND hwnd, void* user_data) {
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reinterpret_cast<void*>(SetWindowLongPtr(hwnd, GWLP_USERDATA,
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          reinterpret_cast<LONG_PTR>(user_data)));
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void* GetWindowUserData(HWND hwnd) {
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD process_id = 0;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD thread_id = GetWindowThreadProcessId(hwnd, &process_id);
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // A window outside the current process needs to be ignored.
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (process_id != ::GetCurrentProcessId())
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return reinterpret_cast<void*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma warning(pop)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DoesWindowBelongToActiveWindow(HWND window) {
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(window);
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HWND top_window = ::GetAncestor(window, GA_ROOT);
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!top_window)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HWND active_top_window = ::GetAncestor(::GetForegroundWindow(), GA_ROOT);
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (top_window == active_top_window);
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CenterAndSizeWindow(HWND parent,
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         HWND window,
136d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                         const Size& pref) {
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(window && pref.width() > 0 && pref.height() > 0);
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Calculate the ideal bounds.
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RECT window_bounds;
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RECT center_bounds = {0};
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (parent) {
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If there is a parent, center over the parents bounds.
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ::GetWindowRect(parent, &center_bounds);
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (::IsRectEmpty(&center_bounds)) {
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No parent or no parent rect. Center over the monitor the window is on.
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HMONITOR monitor = MonitorFromWindow(window, MONITOR_DEFAULTTONEAREST);
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (monitor) {
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      MONITORINFO mi = {0};
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mi.cbSize = sizeof(mi);
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      GetMonitorInfo(monitor, &mi);
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      center_bounds = mi.rcWork;
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "Unable to get default monitor";
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  window_bounds.left = center_bounds.left;
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pref.width() < (center_bounds.right - center_bounds.left)) {
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    window_bounds.left +=
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (center_bounds.right - center_bounds.left - pref.width()) / 2;
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  window_bounds.right = window_bounds.left + pref.width();
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  window_bounds.top = center_bounds.top;
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pref.height() < (center_bounds.bottom - center_bounds.top)) {
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    window_bounds.top +=
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (center_bounds.bottom - center_bounds.top - pref.height()) / 2;
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  window_bounds.bottom = window_bounds.top + pref.height();
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we're centering a child window, we are positioning in client
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // coordinates, and as such we need to offset the target rectangle by the
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // position of the parent window.
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (::GetWindowLong(window, GWL_STYLE) & WS_CHILD) {
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(parent && ::GetParent(window) == parent);
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    POINT topleft = { window_bounds.left, window_bounds.top };
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ::MapWindowPoints(HWND_DESKTOP, parent, &topleft, 1);
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    window_bounds.left = topleft.x;
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    window_bounds.top = topleft.y;
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    window_bounds.right = window_bounds.left + pref.width();
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    window_bounds.bottom = window_bounds.top + pref.height();
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AdjustWindowToFit(window, window_bounds, !parent);
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CheckWindowCreated(HWND hwnd) {
1910f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (!hwnd) {
1920f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    switch (GetLastError()) {
1930f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      case ERROR_NOT_ENOUGH_MEMORY:
1940f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        CrashOutOfMemory();
1950f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        break;
1960f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      case ERROR_ACCESS_DENIED:
1970f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        CrashAccessDenied();
1980f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        break;
1990f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      default:
2000f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        CrashOther();
2010f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        break;
2020f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    }
203cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    PLOG(FATAL);
2040f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
207c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void ShowSystemMenu(HWND window) {
208c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  RECT rect;
209c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GetWindowRect(window, &rect);
210effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  Point point = Point(base::i18n::IsRTL() ? rect.right : rect.left, rect.top);
211c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  static const int kSystemMenuOffset = 10;
212effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  point.Offset(base::i18n::IsRTL() ? -kSystemMenuOffset : kSystemMenuOffset,
213effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch               kSystemMenuOffset);
214c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ShowSystemMenuAtPoint(window, point);
215c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
216c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
217d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void ShowSystemMenuAtPoint(HWND window, const Point& point) {
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In the Metro process, we never want to show the system menu.
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (base::win::IsMetroProcess())
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UINT flags = TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_RETURNCMD;
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (base::i18n::IsRTL())
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    flags |= TPM_RIGHTALIGN;
224c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  HMENU menu = GetSystemMenu(window, FALSE);
225c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const int command =
226c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      TrackPopupMenu(menu, flags, point.x(), point.y(), 0, window, NULL);
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (command)
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SendMessage(window, WM_SYSCOMMAND, command, 0);
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" {
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef HWND (*RootWindow)();
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HWND GetWindowToParentTo(bool get_real_hwnd) {
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HMODULE metro = base::win::GetMetroModule();
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!metro)
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return get_real_hwnd ? ::GetDesktopWindow() : HWND_DESKTOP;
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In windows 8 metro-mode the root window is not the desktop.
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RootWindow root_window =
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reinterpret_cast<RootWindow>(::GetProcAddress(metro, "GetRootWindow"));
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return root_window();
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}  // namespace gfx
246