mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2025-06-05 21:39:12 +02:00
Add support for draggable regions (issue #1645).
Regions are defined using the '-webkit-app-region: drag/no-drag' CSS property and passed to the CefDragHandler:: OnDraggableRegionsChanged callback.
This commit is contained in:
committed by
Marshall Greenblatt
parent
ead921a3f6
commit
c5b8b8b9c8
@@ -68,4 +68,10 @@ void BrowserWindow::OnSetLoadingState(bool isLoading,
|
||||
delegate_->OnSetLoadingState(isLoading, canGoBack, canGoForward);
|
||||
}
|
||||
|
||||
void BrowserWindow::OnSetDraggableRegions(
|
||||
const std::vector<CefDraggableRegion>& regions) {
|
||||
REQUIRE_MAIN_THREAD();
|
||||
delegate_->OnSetDraggableRegions(regions);
|
||||
}
|
||||
|
||||
} // namespace client
|
||||
|
@@ -39,6 +39,10 @@ class BrowserWindow : public ClientHandler::Delegate {
|
||||
bool canGoBack,
|
||||
bool canGoForward) = 0;
|
||||
|
||||
// Set the draggable regions.
|
||||
virtual void OnSetDraggableRegions(
|
||||
const std::vector<CefDraggableRegion>& regions) = 0;
|
||||
|
||||
protected:
|
||||
virtual ~Delegate() {}
|
||||
};
|
||||
@@ -101,6 +105,8 @@ class BrowserWindow : public ClientHandler::Delegate {
|
||||
void OnSetLoadingState(bool isLoading,
|
||||
bool canGoBack,
|
||||
bool canGoForward) OVERRIDE;
|
||||
void OnSetDraggableRegions(
|
||||
const std::vector<CefDraggableRegion>& regions) OVERRIDE;
|
||||
|
||||
Delegate* delegate_;
|
||||
CefRefPtr<CefBrowser> browser_;
|
||||
|
@@ -290,6 +290,14 @@ bool ClientHandler::OnDragEnter(CefRefPtr<CefBrowser> browser,
|
||||
return false;
|
||||
}
|
||||
|
||||
void ClientHandler::OnDraggableRegionsChanged(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
const std::vector<CefDraggableRegion>& regions) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
|
||||
NotifyDraggableRegions(regions);
|
||||
}
|
||||
|
||||
bool ClientHandler::OnRequestGeolocationPermission(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
const CefString& requesting_url,
|
||||
@@ -676,6 +684,19 @@ void ClientHandler::NotifyLoadingState(bool isLoading,
|
||||
delegate_->OnSetLoadingState(isLoading, canGoBack, canGoForward);
|
||||
}
|
||||
|
||||
void ClientHandler::NotifyDraggableRegions(
|
||||
const std::vector<CefDraggableRegion>& regions) {
|
||||
if (!CURRENTLY_ON_MAIN_THREAD()) {
|
||||
// Execute this method on the main thread.
|
||||
MAIN_POST_CLOSURE(
|
||||
base::Bind(&ClientHandler::NotifyDraggableRegions, this, regions));
|
||||
return;
|
||||
}
|
||||
|
||||
if (delegate_)
|
||||
delegate_->OnSetDraggableRegions(regions);
|
||||
}
|
||||
|
||||
void ClientHandler::BuildTestMenu(CefRefPtr<CefMenuModel> model) {
|
||||
if (model->GetCount() > 0)
|
||||
model->AddSeparator();
|
||||
|
@@ -57,6 +57,10 @@ class ClientHandler : public CefClient,
|
||||
bool canGoBack,
|
||||
bool canGoForward) = 0;
|
||||
|
||||
// Set the draggable regions.
|
||||
virtual void OnSetDraggableRegions(
|
||||
const std::vector<CefDraggableRegion>& regions) = 0;
|
||||
|
||||
protected:
|
||||
virtual ~Delegate() {}
|
||||
};
|
||||
@@ -152,6 +156,10 @@ class ClientHandler : public CefClient,
|
||||
CefRefPtr<CefDragData> dragData,
|
||||
CefDragHandler::DragOperationsMask mask) OVERRIDE;
|
||||
|
||||
void OnDraggableRegionsChanged(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
const std::vector<CefDraggableRegion>& regions) OVERRIDE;
|
||||
|
||||
// CefGeolocationHandler methods
|
||||
bool OnRequestGeolocationPermission(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
@@ -263,6 +271,8 @@ class ClientHandler : public CefClient,
|
||||
void NotifyLoadingState(bool isLoading,
|
||||
bool canGoBack,
|
||||
bool canGoForward);
|
||||
void NotifyDraggableRegions(
|
||||
const std::vector<CefDraggableRegion>& regions);
|
||||
|
||||
// Test context menu creation.
|
||||
void BuildTestMenu(CefRefPtr<CefMenuModel> model);
|
||||
@@ -288,7 +298,7 @@ class ClientHandler : public CefClient,
|
||||
// Handles the browser side of query routing. The renderer side is handled
|
||||
// in client_renderer.cc.
|
||||
CefRefPtr<CefMessageRouterBrowserSide> message_router_;
|
||||
|
||||
|
||||
// MAIN THREAD MEMBERS
|
||||
// The following members will only be accessed on the main thread. This will
|
||||
// be the same as the CEF UI thread except when using multi-threaded message
|
||||
|
@@ -387,6 +387,12 @@ void RootWindowGtk::OnSetLoadingState(bool isLoading,
|
||||
}
|
||||
}
|
||||
|
||||
void RootWindowGtk::OnSetDraggableRegions(
|
||||
const std::vector<CefDraggableRegion>& regions) {
|
||||
REQUIRE_MAIN_THREAD();
|
||||
// TODO(cef): Implement support for draggable regions on this platform.
|
||||
}
|
||||
|
||||
void RootWindowGtk::NotifyDestroyedIfDone() {
|
||||
// Notify once both the window and the browser have been destroyed.
|
||||
if (window_destroyed_ && browser_destroyed_)
|
||||
|
@@ -58,6 +58,8 @@ class RootWindowGtk : public RootWindow,
|
||||
void OnSetLoadingState(bool isLoading,
|
||||
bool canGoBack,
|
||||
bool canGoForward) OVERRIDE;
|
||||
void OnSetDraggableRegions(
|
||||
const std::vector<CefDraggableRegion>& regions) OVERRIDE;
|
||||
|
||||
void NotifyDestroyedIfDone();
|
||||
|
||||
|
@@ -64,6 +64,8 @@ class RootWindowMac : public RootWindow,
|
||||
void OnSetLoadingState(bool isLoading,
|
||||
bool canGoBack,
|
||||
bool canGoForward) OVERRIDE;
|
||||
void OnSetDraggableRegions(
|
||||
const std::vector<CefDraggableRegion>& regions) OVERRIDE;
|
||||
|
||||
void NotifyDestroyedIfDone();
|
||||
|
||||
|
@@ -576,6 +576,12 @@ void RootWindowMac::OnSetAddress(const std::string& url) {
|
||||
}
|
||||
}
|
||||
|
||||
void RootWindowMac::OnSetDraggableRegions(
|
||||
const std::vector<CefDraggableRegion>& regions) {
|
||||
REQUIRE_MAIN_THREAD();
|
||||
// TODO(cef): Implement support for draggable regions on this platform.
|
||||
}
|
||||
|
||||
void RootWindowMac::OnSetTitle(const std::string& title) {
|
||||
REQUIRE_MAIN_THREAD();
|
||||
|
||||
|
@@ -5,6 +5,7 @@
|
||||
#include "cefclient/browser/root_window_win.h"
|
||||
|
||||
#include "include/base/cef_bind.h"
|
||||
#include "include/base/cef_build.h"
|
||||
#include "include/cef_app.h"
|
||||
#include "cefclient/browser/browser_window_osr_win.h"
|
||||
#include "cefclient/browser/browser_window_std_win.h"
|
||||
@@ -51,6 +52,7 @@ RootWindowWin::RootWindowWin()
|
||||
start_rect_(),
|
||||
initialized_(false),
|
||||
hwnd_(NULL),
|
||||
draggable_region_(NULL),
|
||||
back_hwnd_(NULL),
|
||||
forward_hwnd_(NULL),
|
||||
reload_hwnd_(NULL),
|
||||
@@ -66,11 +68,16 @@ RootWindowWin::RootWindowWin()
|
||||
window_destroyed_(false),
|
||||
browser_destroyed_(false) {
|
||||
find_buff_[0] = 0;
|
||||
|
||||
// Create a HRGN representing the draggable window area.
|
||||
draggable_region_ = ::CreateRectRgn(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
RootWindowWin::~RootWindowWin() {
|
||||
REQUIRE_MAIN_THREAD();
|
||||
|
||||
::DeleteObject(draggable_region_);
|
||||
|
||||
// The window and browser should already have been destroyed.
|
||||
DCHECK(window_destroyed_);
|
||||
DCHECK(browser_destroyed_);
|
||||
@@ -513,6 +520,21 @@ LRESULT CALLBACK RootWindowWin::RootWndProc(HWND hWnd, UINT message,
|
||||
return 0; // Cancel the close.
|
||||
break;
|
||||
|
||||
case WM_NCHITTEST: {
|
||||
LRESULT hit = DefWindowProc(hWnd, message, wParam, lParam);
|
||||
if (hit == HTCLIENT) {
|
||||
POINTS points = MAKEPOINTS(lParam);
|
||||
POINT point = { points.x, points.y };
|
||||
::ScreenToClient(hWnd, &point);
|
||||
if (::PtInRegion(self->draggable_region_, point.x, point.y)) {
|
||||
// If cursor is inside a draggable region return HTCAPTION to allow
|
||||
// dragging.
|
||||
return HTCAPTION;
|
||||
}
|
||||
}
|
||||
return hit;
|
||||
}
|
||||
|
||||
case WM_NCDESTROY:
|
||||
// Clear the reference to |self|.
|
||||
SetUserDataPtr(hWnd, NULL);
|
||||
@@ -764,6 +786,111 @@ void RootWindowWin::OnSetLoadingState(bool isLoading,
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
LPCWSTR kParentWndProc = L"CefParentWndProc";
|
||||
LPCWSTR kDraggableRegion = L"CefDraggableRegion";
|
||||
|
||||
LRESULT CALLBACK SubclassedWindowProc(
|
||||
HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
WNDPROC hParentWndProc = reinterpret_cast<WNDPROC>(
|
||||
::GetPropW(hWnd, kParentWndProc));
|
||||
HRGN hRegion = reinterpret_cast<HRGN>(
|
||||
::GetPropW(hWnd, kDraggableRegion));
|
||||
|
||||
if (message == WM_NCHITTEST) {
|
||||
LRESULT hit = CallWindowProc(
|
||||
hParentWndProc, hWnd, message, wParam, lParam);
|
||||
if (hit == HTCLIENT) {
|
||||
POINTS points = MAKEPOINTS(lParam);
|
||||
POINT point = { points.x, points.y };
|
||||
::ScreenToClient(hWnd, &point);
|
||||
if (::PtInRegion(hRegion, point.x, point.y)) {
|
||||
// Let the parent window handle WM_NCHITTEST by returning HTTRANSPARENT
|
||||
// in child windows.
|
||||
return HTTRANSPARENT;
|
||||
}
|
||||
}
|
||||
return hit;
|
||||
}
|
||||
|
||||
return CallWindowProc(hParentWndProc, hWnd, message, wParam, lParam);
|
||||
}
|
||||
|
||||
void SubclassWindow(HWND hWnd, HRGN hRegion) {
|
||||
HANDLE hParentWndProc = ::GetPropW(hWnd, kParentWndProc);
|
||||
if (hParentWndProc) {
|
||||
return;
|
||||
}
|
||||
|
||||
SetLastError(0);
|
||||
LONG_PTR hOldWndProc = SetWindowLongPtr(
|
||||
hWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(SubclassedWindowProc));
|
||||
if (hOldWndProc == 0 && GetLastError() != ERROR_SUCCESS) {
|
||||
return;
|
||||
}
|
||||
|
||||
::SetPropW(hWnd, kParentWndProc, reinterpret_cast<HANDLE>(hOldWndProc));
|
||||
::SetPropW(hWnd, kDraggableRegion, reinterpret_cast<HANDLE>(hRegion));
|
||||
}
|
||||
|
||||
void UnSubclassWindow(HWND hWnd) {
|
||||
LONG_PTR hParentWndProc = reinterpret_cast<LONG_PTR>(
|
||||
::GetPropW(hWnd, kParentWndProc));
|
||||
if (hParentWndProc) {
|
||||
LONG_PTR hPreviousWndProc =
|
||||
SetWindowLongPtr(hWnd, GWLP_WNDPROC, hParentWndProc);
|
||||
ALLOW_UNUSED_LOCAL(hPreviousWndProc);
|
||||
DCHECK_EQ(hPreviousWndProc,
|
||||
reinterpret_cast<LONG_PTR>(SubclassedWindowProc));
|
||||
}
|
||||
|
||||
::RemovePropW(hWnd, kParentWndProc);
|
||||
::RemovePropW(hWnd, kDraggableRegion);
|
||||
}
|
||||
|
||||
BOOL CALLBACK SubclassWindowsProc(HWND hwnd, LPARAM lParam) {
|
||||
SubclassWindow(hwnd, reinterpret_cast<HRGN>(lParam));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CALLBACK UnSubclassWindowsProc(HWND hwnd, LPARAM lParam) {
|
||||
UnSubclassWindow(hwnd);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void RootWindowWin::OnSetDraggableRegions(
|
||||
const std::vector<CefDraggableRegion>& regions) {
|
||||
REQUIRE_MAIN_THREAD();
|
||||
|
||||
// Reset draggable region.
|
||||
::SetRectRgn(draggable_region_, 0, 0, 0, 0);
|
||||
|
||||
// Determine new draggable region.
|
||||
std::vector<CefDraggableRegion>::const_iterator it = regions.begin();
|
||||
for (;it != regions.end(); ++it) {
|
||||
HRGN region = ::CreateRectRgn(
|
||||
it->bounds.x, it->bounds.y,
|
||||
it->bounds.x + it->bounds.width,
|
||||
it->bounds.y + it->bounds.height);
|
||||
::CombineRgn(
|
||||
draggable_region_, draggable_region_, region,
|
||||
it->draggable ? RGN_OR : RGN_DIFF);
|
||||
::DeleteObject(region);
|
||||
}
|
||||
|
||||
// Subclass child window procedures in order to do hit-testing.
|
||||
// This will be a no-op, if it is already subclassed.
|
||||
if (hwnd_) {
|
||||
WNDENUMPROC proc = !regions.empty() ?
|
||||
SubclassWindowsProc : UnSubclassWindowsProc;
|
||||
::EnumChildWindows(
|
||||
hwnd_, proc, reinterpret_cast<LPARAM>(draggable_region_));
|
||||
}
|
||||
}
|
||||
|
||||
void RootWindowWin::NotifyDestroyedIfDone() {
|
||||
// Notify once both the window and the browser have been destroyed.
|
||||
if (window_destroyed_ && browser_destroyed_)
|
||||
|
@@ -90,6 +90,8 @@ class RootWindowWin : public RootWindow,
|
||||
void OnSetLoadingState(bool isLoading,
|
||||
bool canGoBack,
|
||||
bool canGoForward) OVERRIDE;
|
||||
void OnSetDraggableRegions(
|
||||
const std::vector<CefDraggableRegion>& regions) OVERRIDE;
|
||||
|
||||
void NotifyDestroyedIfDone();
|
||||
|
||||
@@ -106,6 +108,9 @@ class RootWindowWin : public RootWindow,
|
||||
// Main window.
|
||||
HWND hwnd_;
|
||||
|
||||
// Draggable region.
|
||||
HRGN draggable_region_;
|
||||
|
||||
// Buttons.
|
||||
HWND back_hwnd_;
|
||||
HWND forward_hwnd_;
|
||||
@@ -115,7 +120,7 @@ class RootWindowWin : public RootWindow,
|
||||
// URL text field.
|
||||
HWND edit_hwnd_;
|
||||
WNDPROC edit_wndproc_old_;
|
||||
|
||||
|
||||
// Find dialog.
|
||||
HWND find_hwnd_;
|
||||
UINT find_message_id_;
|
||||
|
Reference in New Issue
Block a user