mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2025-02-26 08:58:18 +01: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:
parent
ead921a3f6
commit
c5b8b8b9c8
1
cef.gyp
1
cef.gyp
@ -415,6 +415,7 @@
|
||||
'tests/unittests/display_unittest.cc',
|
||||
'tests/unittests/dom_unittest.cc',
|
||||
'tests/unittests/download_unittest.cc',
|
||||
'tests/unittests/draggable_regions_unittest.cc',
|
||||
'tests/unittests/frame_unittest.cc',
|
||||
'tests/unittests/geolocation_unittest.cc',
|
||||
'tests/unittests/jsdialog_unittest.cc',
|
||||
|
@ -66,6 +66,17 @@ typedef struct _cef_drag_handler_t {
|
||||
int (CEF_CALLBACK *on_drag_enter)(struct _cef_drag_handler_t* self,
|
||||
struct _cef_browser_t* browser, struct _cef_drag_data_t* dragData,
|
||||
cef_drag_operations_mask_t mask);
|
||||
|
||||
///
|
||||
// Called whenever draggable regions for the browser window change. These can
|
||||
// be specified using the '-webkit-app-region: drag/no-drag' CSS-property. If
|
||||
// draggable regions are never defined in a document this function will also
|
||||
// never be called. If the last draggable region is removed from a document
|
||||
// this function will be called with an NULL vector.
|
||||
///
|
||||
void (CEF_CALLBACK *on_draggable_regions_changed)(
|
||||
struct _cef_drag_handler_t* self, struct _cef_browser_t* browser,
|
||||
size_t regionsCount, cef_draggable_region_t const* regions);
|
||||
} cef_drag_handler_t;
|
||||
|
||||
|
||||
|
@ -61,6 +61,18 @@ class CefDragHandler : public virtual CefBase {
|
||||
virtual bool OnDragEnter(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefDragData> dragData,
|
||||
DragOperationsMask mask) { return false; }
|
||||
|
||||
///
|
||||
// Called whenever draggable regions for the browser window change. These can
|
||||
// be specified using the '-webkit-app-region: drag/no-drag' CSS-property. If
|
||||
// draggable regions are never defined in a document this method will also
|
||||
// never be called. If the last draggable region is removed from a document
|
||||
// this method will be called with an empty vector.
|
||||
///
|
||||
/*--cef()--*/
|
||||
virtual void OnDraggableRegionsChanged(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
const std::vector<CefDraggableRegion>& regions) {}
|
||||
};
|
||||
|
||||
#endif // CEF_INCLUDE_CEF_DRAG_HANDLER_H_
|
||||
|
@ -1265,6 +1265,21 @@ typedef struct _cef_size_t {
|
||||
int height;
|
||||
} cef_size_t;
|
||||
|
||||
///
|
||||
// Structure representing a draggable region.
|
||||
///
|
||||
typedef struct _cef_draggable_region_t {
|
||||
///
|
||||
// Bounds of the region.
|
||||
///
|
||||
cef_rect_t bounds;
|
||||
|
||||
///
|
||||
// True (1) this this region is draggable and false (0) otherwise.
|
||||
///
|
||||
int draggable;
|
||||
} cef_draggable_region_t;
|
||||
|
||||
///
|
||||
// Existing process IDs.
|
||||
///
|
||||
|
@ -257,6 +257,50 @@ inline bool operator!=(const CefSize& a, const CefSize& b) {
|
||||
}
|
||||
|
||||
|
||||
struct CefDraggableRegionTraits {
|
||||
typedef cef_draggable_region_t struct_type;
|
||||
|
||||
static inline void init(struct_type* s) {}
|
||||
static inline void clear(struct_type* s) {}
|
||||
|
||||
static inline void set(const struct_type* src, struct_type* target,
|
||||
bool copy) {
|
||||
*target = *src;
|
||||
}
|
||||
};
|
||||
|
||||
///
|
||||
// Class representing a draggable region.
|
||||
///
|
||||
class CefDraggableRegion : public CefStructBase<CefDraggableRegionTraits> {
|
||||
public:
|
||||
typedef CefStructBase<CefDraggableRegionTraits> parent;
|
||||
|
||||
CefDraggableRegion() : parent() {}
|
||||
CefDraggableRegion(const cef_draggable_region_t& r) // NOLINT(runtime/explicit)
|
||||
: parent(r) {}
|
||||
CefDraggableRegion(const CefDraggableRegion& r) // NOLINT(runtime/explicit)
|
||||
: parent(r) {}
|
||||
CefDraggableRegion(const CefRect& bounds, bool draggable) : parent() {
|
||||
Set(bounds, draggable);
|
||||
}
|
||||
|
||||
void Set(const CefRect& bounds, bool draggable) {
|
||||
this->bounds = bounds, this->draggable = draggable;
|
||||
}
|
||||
};
|
||||
|
||||
inline bool operator==(const CefDraggableRegion& a,
|
||||
const CefDraggableRegion& b) {
|
||||
return a.bounds == b.bounds && a.draggable == b.draggable;
|
||||
}
|
||||
|
||||
inline bool operator!=(const CefDraggableRegion& a,
|
||||
const CefDraggableRegion& b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
|
||||
struct CefScreenInfoTraits {
|
||||
typedef cef_screen_info_t struct_type;
|
||||
|
||||
|
@ -2659,6 +2659,8 @@ bool CefBrowserHostImpl::OnMessageReceived(const IPC::Message& message) {
|
||||
IPC_BEGIN_MESSAGE_MAP(CefBrowserHostImpl, message)
|
||||
IPC_MESSAGE_HANDLER(CefHostMsg_FrameIdentified, OnFrameIdentified)
|
||||
IPC_MESSAGE_HANDLER(CefHostMsg_DidFinishLoad, OnDidFinishLoad)
|
||||
IPC_MESSAGE_HANDLER(CefHostMsg_UpdateDraggableRegions,
|
||||
OnUpdateDraggableRegions)
|
||||
IPC_MESSAGE_HANDLER(CefHostMsg_Request, OnRequest)
|
||||
IPC_MESSAGE_HANDLER(CefHostMsg_Response, OnResponse)
|
||||
IPC_MESSAGE_HANDLER(CefHostMsg_ResponseAck, OnResponseAck)
|
||||
@ -2716,6 +2718,26 @@ void CefBrowserHostImpl::OnDidFinishLoad(int64 frame_id,
|
||||
OnLoadEnd(frame, validated_url, http_status_code);
|
||||
}
|
||||
|
||||
void CefBrowserHostImpl::OnUpdateDraggableRegions(
|
||||
const std::vector<Cef_DraggableRegion_Params>& regions) {
|
||||
std::vector<CefDraggableRegion> draggable_regions;
|
||||
draggable_regions.reserve(regions.size());
|
||||
|
||||
std::vector<Cef_DraggableRegion_Params>::const_iterator it = regions.begin();
|
||||
for (; it != regions.end(); ++it) {
|
||||
const gfx::Rect& rect(it->bounds);
|
||||
const CefRect bounds(rect.x(), rect.y(), rect.width(), rect.height());
|
||||
draggable_regions.push_back(CefDraggableRegion(bounds, it->draggable));
|
||||
}
|
||||
|
||||
if (client_.get()) {
|
||||
CefRefPtr<CefDragHandler> handler = client_->GetDragHandler();
|
||||
if (handler.get()) {
|
||||
handler->OnDraggableRegionsChanged(this, draggable_regions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CefBrowserHostImpl::OnRequest(const Cef_Request_Params& params) {
|
||||
bool success = false;
|
||||
std::string response;
|
||||
|
@ -64,6 +64,7 @@ class Widget;
|
||||
class CefWindowX11;
|
||||
#endif
|
||||
|
||||
struct Cef_DraggableRegion_Params;
|
||||
struct Cef_Request_Params;
|
||||
struct Cef_Response_Params;
|
||||
class CefBrowserInfo;
|
||||
@ -477,6 +478,8 @@ class CefBrowserHostImpl : public CefBrowserHost,
|
||||
const GURL& validated_url,
|
||||
bool is_main_frame,
|
||||
int http_status_code);
|
||||
void OnUpdateDraggableRegions(
|
||||
const std::vector<Cef_DraggableRegion_Params>& regions);
|
||||
void OnRequest(const Cef_Request_Params& params);
|
||||
void OnResponse(const Cef_Response_Params& params);
|
||||
void OnResponseAck(int request_id);
|
||||
|
@ -68,6 +68,12 @@ IPC_STRUCT_BEGIN(Cef_CrossOriginWhiteListEntry_Params)
|
||||
IPC_STRUCT_MEMBER(bool, allow_target_subdomains)
|
||||
IPC_STRUCT_END()
|
||||
|
||||
// Parameters structure for a draggable region.
|
||||
IPC_STRUCT_BEGIN(Cef_DraggableRegion_Params)
|
||||
IPC_STRUCT_MEMBER(gfx::Rect, bounds)
|
||||
IPC_STRUCT_MEMBER(bool, draggable)
|
||||
IPC_STRUCT_END()
|
||||
|
||||
|
||||
// Messages sent from the browser to the renderer.
|
||||
|
||||
@ -189,6 +195,10 @@ IPC_MESSAGE_ROUTED1(CefHostMsg_Response,
|
||||
IPC_MESSAGE_ROUTED1(CefHostMsg_ResponseAck,
|
||||
int /* request_id */)
|
||||
|
||||
// Sent by the renderer when the draggable regions are updated.
|
||||
IPC_MESSAGE_ROUTED1(CefHostMsg_UpdateDraggableRegions,
|
||||
std::vector<Cef_DraggableRegion_Params> /* regions */)
|
||||
|
||||
|
||||
// Singly-included section for struct and custom IPC traits.
|
||||
#ifndef CEF_LIBCEF_COMMON_CEF_MESSAGES_H_
|
||||
|
@ -571,6 +571,19 @@ void CefBrowserImpl::FocusedNodeChanged(const blink::WebNode& node) {
|
||||
}
|
||||
}
|
||||
|
||||
void CefBrowserImpl::DraggableRegionsChanged(blink::WebFrame* frame) {
|
||||
blink::WebVector<blink::WebDraggableRegion> webregions =
|
||||
frame->document().draggableRegions();
|
||||
std::vector<Cef_DraggableRegion_Params> regions;
|
||||
for (size_t i = 0; i < webregions.size(); ++i) {
|
||||
Cef_DraggableRegion_Params region;
|
||||
region.bounds = webregions[i].bounds;
|
||||
region.draggable = webregions[i].draggable;
|
||||
regions.push_back(region);
|
||||
}
|
||||
Send(new CefHostMsg_UpdateDraggableRegions(routing_id(), regions));
|
||||
}
|
||||
|
||||
bool CefBrowserImpl::OnMessageReceived(const IPC::Message& message) {
|
||||
bool handled = true;
|
||||
IPC_BEGIN_MESSAGE_MAP(CefBrowserImpl, message)
|
||||
|
@ -119,6 +119,7 @@ class CefBrowserImpl : public CefBrowser,
|
||||
bool is_new_navigation) override;
|
||||
void FrameDetached(blink::WebFrame* frame) override;
|
||||
void FocusedNodeChanged(const blink::WebNode& node) override;
|
||||
void DraggableRegionsChanged(blink::WebFrame* frame) override;
|
||||
bool OnMessageReceived(const IPC::Message& message) override;
|
||||
|
||||
// RenderViewObserver::OnMessageReceived message handlers.
|
||||
|
@ -46,6 +46,37 @@ int CEF_CALLBACK drag_handler_on_drag_enter(struct _cef_drag_handler_t* self,
|
||||
return _retval;
|
||||
}
|
||||
|
||||
void CEF_CALLBACK drag_handler_on_draggable_regions_changed(
|
||||
struct _cef_drag_handler_t* self, cef_browser_t* browser,
|
||||
size_t regionsCount, cef_draggable_region_t const* regions) {
|
||||
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
|
||||
|
||||
DCHECK(self);
|
||||
if (!self)
|
||||
return;
|
||||
// Verify param: browser; type: refptr_diff
|
||||
DCHECK(browser);
|
||||
if (!browser)
|
||||
return;
|
||||
// Verify param: regions; type: simple_vec_byref_const
|
||||
DCHECK(regionsCount == 0 || regions);
|
||||
if (regionsCount > 0 && !regions)
|
||||
return;
|
||||
|
||||
// Translate param: regions; type: simple_vec_byref_const
|
||||
std::vector<CefDraggableRegion > regionsList;
|
||||
if (regionsCount > 0) {
|
||||
for (size_t i = 0; i < regionsCount; ++i) {
|
||||
regionsList.push_back(regions[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Execute
|
||||
CefDragHandlerCppToC::Get(self)->OnDraggableRegionsChanged(
|
||||
CefBrowserCToCpp::Wrap(browser),
|
||||
regionsList);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
@ -53,6 +84,8 @@ int CEF_CALLBACK drag_handler_on_drag_enter(struct _cef_drag_handler_t* self,
|
||||
|
||||
CefDragHandlerCppToC::CefDragHandlerCppToC() {
|
||||
GetStruct()->on_drag_enter = drag_handler_on_drag_enter;
|
||||
GetStruct()->on_draggable_regions_changed =
|
||||
drag_handler_on_draggable_regions_changed;
|
||||
}
|
||||
|
||||
template<> CefRefPtr<CefDragHandler> CefCppToC<CefDragHandlerCppToC,
|
||||
|
@ -44,6 +44,44 @@ bool CefDragHandlerCToCpp::OnDragEnter(CefRefPtr<CefBrowser> browser,
|
||||
return _retval?true:false;
|
||||
}
|
||||
|
||||
void CefDragHandlerCToCpp::OnDraggableRegionsChanged(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
const std::vector<CefDraggableRegion>& regions) {
|
||||
cef_drag_handler_t* _struct = GetStruct();
|
||||
if (CEF_MEMBER_MISSING(_struct, on_draggable_regions_changed))
|
||||
return;
|
||||
|
||||
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
|
||||
|
||||
// Verify param: browser; type: refptr_diff
|
||||
DCHECK(browser.get());
|
||||
if (!browser.get())
|
||||
return;
|
||||
|
||||
// Translate param: regions; type: simple_vec_byref_const
|
||||
const size_t regionsCount = regions.size();
|
||||
cef_draggable_region_t* regionsList = NULL;
|
||||
if (regionsCount > 0) {
|
||||
regionsList = new cef_draggable_region_t[regionsCount];
|
||||
DCHECK(regionsList);
|
||||
if (regionsList) {
|
||||
for (size_t i = 0; i < regionsCount; ++i) {
|
||||
regionsList[i] = regions[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Execute
|
||||
_struct->on_draggable_regions_changed(_struct,
|
||||
CefBrowserCppToC::Wrap(browser),
|
||||
regionsCount,
|
||||
regionsList);
|
||||
|
||||
// Restore param:regions; type: simple_vec_byref_const
|
||||
if (regionsList)
|
||||
delete [] regionsList;
|
||||
}
|
||||
|
||||
|
||||
// CONSTRUCTOR - Do not edit by hand.
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
#pragma message("Warning: "__FILE__" may be accessed DLL-side only")
|
||||
#else // BUILDING_CEF_SHARED
|
||||
|
||||
#include <vector>
|
||||
#include "include/cef_drag_handler.h"
|
||||
#include "include/capi/cef_drag_handler_capi.h"
|
||||
#include "libcef_dll/ctocpp/ctocpp.h"
|
||||
@ -33,6 +34,8 @@ class CefDragHandlerCToCpp
|
||||
// CefDragHandler methods.
|
||||
bool OnDragEnter(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefDragData> dragData, DragOperationsMask mask) override;
|
||||
void OnDraggableRegionsChanged(CefRefPtr<CefBrowser> browser,
|
||||
const std::vector<CefDraggableRegion>& regions) override;
|
||||
};
|
||||
|
||||
#endif // BUILDING_CEF_SHARED
|
||||
|
@ -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);
|
||||
|
@ -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_;
|
||||
|
171
tests/unittests/draggable_regions_unittest.cc
Normal file
171
tests/unittests/draggable_regions_unittest.cc
Normal file
@ -0,0 +1,171 @@
|
||||
// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
|
||||
// reserved. Use of this source code is governed by a BSD-style license that
|
||||
// can be found in the LICENSE file.
|
||||
|
||||
// Include this first to avoid type conflicts with CEF headers.
|
||||
#include "tests/unittests/chromium_includes.h"
|
||||
|
||||
#include "include/wrapper/cef_closure_task.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "tests/unittests/test_handler.h"
|
||||
|
||||
namespace {
|
||||
|
||||
const char kTestURLWithRegions[] = "http://test.com/regions";
|
||||
const char kTestHTMLWithRegions[] =
|
||||
"<html>"
|
||||
" <body>"
|
||||
" <div style=\"position: absolute; top: 50px; left: 50px; width: 200px; "
|
||||
"height: 200px; background-color: red; -webkit-app-region: drag;\">"
|
||||
" <div style=\"position: absolute; top: 50%; left: 50%; "
|
||||
"transform: translate(-50%, -50%); width: 50px; height: 50px; "
|
||||
"background-color: blue; -webkit-app-region: no-drag;\">"
|
||||
" </div>"
|
||||
" </div>"
|
||||
" </body>"
|
||||
"</html>";
|
||||
|
||||
const char kTestURLWithoutRegions[] = "http://test.com/no-regions";
|
||||
const char kTestHTMLWithoutRegions[] =
|
||||
"<html><body>Hello World!</body></html>";
|
||||
|
||||
const char kTestURLWithChangingRegions[] = "http://test.com/changing-regions";
|
||||
const char kTestHTMLWithChangingRegions[] =
|
||||
"<html>"
|
||||
" <body>"
|
||||
" <div id=\"layer\" style=\"position: absolute; top: 50px; left: 50px; "
|
||||
"width: 200px; height: 200px; background-color: red; "
|
||||
"-webkit-app-region: drag;\">"
|
||||
" <div style=\"position: absolute; top: 50%; left: 50%; "
|
||||
"transform: translate(-50%, -50%); width: 50px; height: 50px; "
|
||||
"background-color: blue; -webkit-app-region: no-drag;\">"
|
||||
" </div>"
|
||||
" </div>"
|
||||
" <script>"
|
||||
" window.setTimeout(function() {"
|
||||
" var layer = document.getElementById('layer');"
|
||||
" layer.style.top = '0px';"
|
||||
" layer.style.left = '0px';"
|
||||
" }, 500);"
|
||||
" </script>"
|
||||
" </body>"
|
||||
"</html>";
|
||||
|
||||
class DraggableRegionsTestHandler : public TestHandler {
|
||||
public:
|
||||
DraggableRegionsTestHandler()
|
||||
: step_(kStepWithRegions) {}
|
||||
|
||||
void RunTest() override {
|
||||
// Add HTML documents with and without draggable regions.
|
||||
AddResource(kTestURLWithRegions, kTestHTMLWithRegions, "text/html");
|
||||
AddResource(kTestURLWithoutRegions, kTestHTMLWithoutRegions, "text/html");
|
||||
AddResource(kTestURLWithChangingRegions, kTestHTMLWithChangingRegions,
|
||||
"text/html");
|
||||
|
||||
// Create the browser
|
||||
CreateBrowser(kTestURLWithRegions);
|
||||
|
||||
// Time out the test after a reasonable period of time.
|
||||
SetTestTimeout();
|
||||
}
|
||||
|
||||
void OnDraggableRegionsChanged(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
const std::vector<CefDraggableRegion>& regions) override {
|
||||
EXPECT_TRUE(CefCurrentlyOn(TID_UI));
|
||||
EXPECT_TRUE(browser->IsSame(GetBrowser()));
|
||||
|
||||
did_call_on_draggable_regions_changed_.yes();
|
||||
|
||||
switch (step_) {
|
||||
case kStepWithRegions:
|
||||
case kStepWithChangingRegions1:
|
||||
EXPECT_EQ(2U, regions.size());
|
||||
EXPECT_EQ(50, regions[0].bounds.x);
|
||||
EXPECT_EQ(50, regions[0].bounds.y);
|
||||
EXPECT_EQ(200, regions[0].bounds.width);
|
||||
EXPECT_EQ(200, regions[0].bounds.height);
|
||||
EXPECT_EQ(1, regions[0].draggable);
|
||||
EXPECT_EQ(125, regions[1].bounds.x);
|
||||
EXPECT_EQ(125, regions[1].bounds.y);
|
||||
EXPECT_EQ(50, regions[1].bounds.width);
|
||||
EXPECT_EQ(50, regions[1].bounds.height);
|
||||
EXPECT_EQ(0, regions[1].draggable);
|
||||
break;
|
||||
case kStepWithChangingRegions2:
|
||||
EXPECT_EQ(2U, regions.size());
|
||||
EXPECT_EQ(0, regions[0].bounds.x);
|
||||
EXPECT_EQ(0, regions[0].bounds.y);
|
||||
EXPECT_EQ(200, regions[0].bounds.width);
|
||||
EXPECT_EQ(200, regions[0].bounds.height);
|
||||
EXPECT_EQ(1, regions[0].draggable);
|
||||
EXPECT_EQ(75, regions[1].bounds.x);
|
||||
EXPECT_EQ(75, regions[1].bounds.y);
|
||||
EXPECT_EQ(50, regions[1].bounds.width);
|
||||
EXPECT_EQ(50, regions[1].bounds.height);
|
||||
EXPECT_EQ(0, regions[1].draggable);
|
||||
break;
|
||||
case kStepWithoutRegions:
|
||||
// Should not be reached.
|
||||
EXPECT_TRUE(false);
|
||||
break;
|
||||
}
|
||||
|
||||
NextTest(browser);
|
||||
}
|
||||
|
||||
void DestroyTest() override {
|
||||
EXPECT_EQ(false, did_call_on_draggable_regions_changed_);
|
||||
|
||||
TestHandler::DestroyTest();
|
||||
}
|
||||
|
||||
private:
|
||||
void NextTest(CefRefPtr<CefBrowser> browser) {
|
||||
CefRefPtr<CefFrame> frame(browser->GetMainFrame());
|
||||
|
||||
did_call_on_draggable_regions_changed_.reset();
|
||||
|
||||
switch (step_) {
|
||||
case kStepWithRegions:
|
||||
step_ = kStepWithChangingRegions1;
|
||||
frame->LoadURL(kTestURLWithChangingRegions);
|
||||
break;
|
||||
case kStepWithChangingRegions1:
|
||||
step_ = kStepWithChangingRegions2;
|
||||
break;
|
||||
case kStepWithChangingRegions2:
|
||||
step_ = kStepWithoutRegions;
|
||||
frame->LoadURL(kTestURLWithoutRegions);
|
||||
// Needed because this test doesn't call OnDraggableRegionsChanged.
|
||||
CefPostDelayedTask(TID_UI,
|
||||
base::Bind(&DraggableRegionsTestHandler::DestroyTest, this), 500);
|
||||
break;
|
||||
case kStepWithoutRegions: {
|
||||
// Should not be reached.
|
||||
EXPECT_TRUE(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum Step {
|
||||
kStepWithRegions,
|
||||
kStepWithChangingRegions1,
|
||||
kStepWithChangingRegions2,
|
||||
kStepWithoutRegions,
|
||||
} step_;
|
||||
|
||||
TrackCallback did_call_on_draggable_regions_changed_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
// Verify that draggable regions work.
|
||||
TEST(DraggableRegionsTest, DraggableRegions) {
|
||||
CefRefPtr<DraggableRegionsTestHandler> handler =
|
||||
new DraggableRegionsTestHandler();
|
||||
handler->ExecuteTest();
|
||||
ReleaseAndWaitForDestructor(handler);
|
||||
}
|
@ -805,7 +805,7 @@ class OSRTestHandler : public RoutingTestHandler,
|
||||
|
||||
bool StartDragging(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefDragData> drag_data,
|
||||
DragOperationsMask allowed_ops,
|
||||
CefRenderHandler::DragOperationsMask allowed_ops,
|
||||
int x, int y) override {
|
||||
if (test_type_ == OSR_TEST_DRAG_DROP_START_DRAGGING && started()) {
|
||||
DestroySucceededTestSoon();
|
||||
|
@ -37,6 +37,7 @@ class TestHandler : public CefClient,
|
||||
public CefDialogHandler,
|
||||
public CefDisplayHandler,
|
||||
public CefDownloadHandler,
|
||||
public CefDragHandler,
|
||||
public CefGeolocationHandler,
|
||||
public CefJSDialogHandler,
|
||||
public CefLifeSpanHandler,
|
||||
@ -139,6 +140,9 @@ class TestHandler : public CefClient,
|
||||
CefRefPtr<CefDownloadHandler> GetDownloadHandler() override {
|
||||
return this;
|
||||
}
|
||||
CefRefPtr<CefDragHandler> GetDragHandler() override {
|
||||
return this;
|
||||
}
|
||||
CefRefPtr<CefGeolocationHandler> GetGeolocationHandler() override {
|
||||
return this;
|
||||
}
|
||||
@ -162,6 +166,11 @@ class TestHandler : public CefClient,
|
||||
const CefString& suggested_name,
|
||||
CefRefPtr<CefBeforeDownloadCallback> callback) override {}
|
||||
|
||||
// CefDragHandler methods
|
||||
void OnDraggableRegionsChanged(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
const std::vector<CefDraggableRegion>& regions) override {}
|
||||
|
||||
// CefLifeSpanHandler methods
|
||||
void OnAfterCreated(CefRefPtr<CefBrowser> browser) override;
|
||||
void OnBeforeClose(CefRefPtr<CefBrowser> browser) override;
|
||||
|
@ -403,6 +403,7 @@ _simpletypes = {
|
||||
'CefPoint' : ['cef_point_t', 'CefPoint()'],
|
||||
'CefRect' : ['cef_rect_t', 'CefRect()'],
|
||||
'CefSize' : ['cef_size_t', 'CefSize()'],
|
||||
'CefDraggableRegion' : ['cef_draggable_region_t', 'CefDraggableRegion()'],
|
||||
'CefPageRange' : ['cef_page_range_t', 'CefPageRange()'],
|
||||
'CefThreadId' : ['cef_thread_id_t', 'TID_UI'],
|
||||
'CefTime' : ['cef_time_t', 'CefTime()'],
|
||||
|
Loading…
x
Reference in New Issue
Block a user