// 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 "cefclient/osr_window_win.h" #include #include "include/base/cef_build.h" #include "cefclient/main_message_loop.h" #include "cefclient/resource.h" #include "cefclient/util_win.h" namespace client { namespace { const wchar_t kWndClass[] = L"Client_OsrWindow"; // Render at 30fps during rotation. const int kRenderDelay = 1000 / 30; // Helper that calls wglMakeCurrent. class ScopedGLContext { public: ScopedGLContext(HDC hdc, HGLRC hglrc, bool swap_buffers) : hdc_(hdc), swap_buffers_(swap_buffers) { BOOL result = wglMakeCurrent(hdc, hglrc); ALLOW_UNUSED_LOCAL(result); DCHECK(result); } ~ScopedGLContext() { BOOL result = wglMakeCurrent(NULL, NULL); DCHECK(result); if (swap_buffers_) { result = SwapBuffers(hdc_); DCHECK(result); } } private: const HDC hdc_; const bool swap_buffers_; }; } // namespace OsrWindowWin::OsrWindowWin(Delegate* delegate, bool transparent, bool show_update_rect) : delegate_(delegate), renderer_(transparent, show_update_rect), hwnd_(NULL), hdc_(NULL), hrc_(NULL), client_rect_(), painting_popup_(false), render_task_pending_(false), hidden_(false), last_mouse_pos_(), current_mouse_pos_(), mouse_rotation_(false), mouse_tracking_(false), last_click_x_(0), last_click_y_(0), last_click_button_(MBT_LEFT), last_click_count_(0), last_click_time_(0), last_mouse_down_on_view_(false) { DCHECK(delegate_); } OsrWindowWin::~OsrWindowWin() { CEF_REQUIRE_UI_THREAD(); // The native window should have already been destroyed. DCHECK(!hwnd_); } void OsrWindowWin::CreateBrowser(HWND parent_hwnd, const RECT& rect, CefRefPtr handler, const CefBrowserSettings& settings, const std::string& startup_url) { if (!CefCurrentlyOn(TID_UI)) { // Execute this method on the UI thread. CefPostTask(TID_UI, base::Bind(&OsrWindowWin::CreateBrowser, this, parent_hwnd, rect, handler, settings, startup_url)); return; } // Create the native window. Create(parent_hwnd, rect); CefWindowInfo window_info; window_info.SetAsWindowless(hwnd_, renderer_.IsTransparent()); // Create the browser asynchronously. CefBrowserHost::CreateBrowser(window_info, handler, startup_url, settings, NULL); } void OsrWindowWin::ShowPopup(HWND parent_hwnd, int x, int y, size_t width, size_t height) { if (!CefCurrentlyOn(TID_UI)) { // Execute this method on the UI thread. CefPostTask(TID_UI, base::Bind(&OsrWindowWin::ShowPopup, this, parent_hwnd, x, y, width, height)); return; } DCHECK(browser_.get()); // Create the native window. const RECT rect = {x, y, x + static_cast(width), y + static_cast(height)}; Create(parent_hwnd, rect); // Send resize notification so the compositor is assigned the correct // viewport size and begins rendering. browser_->GetHost()->WasResized(); Show(); } void OsrWindowWin::Show() { if (!CefCurrentlyOn(TID_UI)) { // Execute this method on the UI thread. CefPostTask(TID_UI, base::Bind(&OsrWindowWin::Show, this)); return; } if (!browser_) return; // Show the native window if not currently visible. if (hwnd_ && !::IsWindowVisible(hwnd_)) ShowWindow(hwnd_, SW_SHOW); if (hidden_) { // Set the browser as visible. browser_->GetHost()->WasHidden(false); hidden_ = false; } // Give focus to the browser. browser_->GetHost()->SendFocusEvent(true); } void OsrWindowWin::Hide() { if (!CefCurrentlyOn(TID_UI)) { // Execute this method on the UI thread. CefPostTask(TID_UI, base::Bind(&OsrWindowWin::Hide, this)); return; } if (!browser_) return; // Remove focus from the browser. browser_->GetHost()->SendFocusEvent(false); if (!hidden_) { // Set the browser as hidden. browser_->GetHost()->WasHidden(true); hidden_ = true; } } void OsrWindowWin::SetBounds(int x, int y, size_t width, size_t height) { if (!CefCurrentlyOn(TID_UI)) { // Execute this method on the UI thread. CefPostTask(TID_UI, base::Bind(&OsrWindowWin::SetBounds, this, x, y, width, height)); return; } if (hwnd_) { // Set the browser window bounds. ::SetWindowPos(hwnd_, NULL, x, y, static_cast(width), static_cast(height), SWP_NOZORDER); } } void OsrWindowWin::SetFocus() { if (!CefCurrentlyOn(TID_UI)) { // Execute this method on the UI thread. CefPostTask(TID_UI, base::Bind(&OsrWindowWin::SetFocus, this)); return; } if (hwnd_) { // Give focus to the native window. ::SetFocus(hwnd_); } } void OsrWindowWin::Create(HWND parent_hwnd, const RECT& rect) { CEF_REQUIRE_UI_THREAD(); DCHECK(!hwnd_ && !hdc_ && !hrc_); DCHECK(parent_hwnd); DCHECK(!::IsRectEmpty(&rect)); HINSTANCE hInst = ::GetModuleHandle(NULL); RegisterOsrClass(hInst); // Create the native window with a border so it's easier to visually identify // OSR windows. hwnd_ = ::CreateWindow(kWndClass, 0, WS_BORDER | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, parent_hwnd, 0, hInst, 0); CHECK(hwnd_); client_rect_ = rect; // Associate |this| with the window. SetUserDataPtr(hwnd_, this); #if defined(CEF_USE_ATL) // Create/register the drag&drop handler. drop_target_ = DropTargetWin::Create(this, hwnd_); HRESULT register_res = RegisterDragDrop(hwnd_, drop_target_); DCHECK_EQ(register_res, S_OK); #endif // Notify the window owner. NotifyNativeWindowCreated(hwnd_); } void OsrWindowWin::Destroy() { CEF_REQUIRE_UI_THREAD(); DCHECK(hwnd_ != NULL); #if defined(CEF_USE_ATL) // Revoke/delete the drag&drop handler. RevokeDragDrop(hwnd_); drop_target_ = NULL; #endif DisableGL(); // Destroy the native window. ::DestroyWindow(hwnd_); hwnd_ = NULL; } void OsrWindowWin::EnableGL() { CEF_REQUIRE_UI_THREAD(); PIXELFORMATDESCRIPTOR pfd; int format; // Get the device context. hdc_ = GetDC(hwnd_); // Set the pixel format for the DC. ZeroMemory(&pfd, sizeof(pfd)); pfd.nSize = sizeof(pfd); pfd.nVersion = 1; pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; pfd.iPixelType = PFD_TYPE_RGBA; pfd.cColorBits = 24; pfd.cDepthBits = 16; pfd.iLayerType = PFD_MAIN_PLANE; format = ChoosePixelFormat(hdc_, &pfd); SetPixelFormat(hdc_, format, &pfd); // Create and enable the render context. hrc_ = wglCreateContext(hdc_); ScopedGLContext scoped_gl_context(hdc_, hrc_, false); renderer_.Initialize(); } void OsrWindowWin::DisableGL() { CEF_REQUIRE_UI_THREAD(); if (!hdc_) return; { ScopedGLContext scoped_gl_context(hdc_, hrc_, false); renderer_.Cleanup(); } if (IsWindow(hwnd_)) { // wglDeleteContext will make the context not current before deleting it. BOOL result = wglDeleteContext(hrc_); ALLOW_UNUSED_LOCAL(result); DCHECK(result); ReleaseDC(hwnd_, hdc_); } hdc_ = NULL; hrc_ = NULL; } void OsrWindowWin::Invalidate() { CEF_REQUIRE_UI_THREAD(); // Don't post another task if the previous task is still pending. if (render_task_pending_) return; render_task_pending_ = true; CefPostDelayedTask(TID_UI, base::Bind(&OsrWindowWin::Render, this), kRenderDelay); } void OsrWindowWin::Render() { CEF_REQUIRE_UI_THREAD(); if (render_task_pending_) render_task_pending_ = false; if (!hdc_) EnableGL(); ScopedGLContext scoped_gl_context(hdc_, hrc_, true); renderer_.Render(); } void OsrWindowWin::NotifyNativeWindowCreated(HWND hwnd) { if (!CURRENTLY_ON_MAIN_THREAD()) { // Execute this method on the main thread. MAIN_POST_CLOSURE( base::Bind(&OsrWindowWin::NotifyNativeWindowCreated, this, hwnd)); return; } delegate_->OnOsrNativeWindowCreated(hwnd); } // static void OsrWindowWin::RegisterOsrClass(HINSTANCE hInstance) { // Only register the class one time. static bool class_registered = false; if (class_registered) return; class_registered = true; WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_OWNDC; wcex.lpfnWndProc = OsrWndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = NULL; wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wcex.lpszMenuName = NULL; wcex.lpszClassName = kWndClass; wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); RegisterClassEx(&wcex); } // static LRESULT CALLBACK OsrWindowWin::OsrWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { CEF_REQUIRE_UI_THREAD(); OsrWindowWin* self = GetUserDataPtr(hWnd); if (!self) return DefWindowProc(hWnd, message, wParam, lParam); switch (message) { case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: case WM_MBUTTONDOWN: case WM_LBUTTONUP: case WM_RBUTTONUP: case WM_MBUTTONUP: case WM_MOUSEMOVE: case WM_MOUSELEAVE: case WM_MOUSEWHEEL: if (self) self->OnMouseEvent(message, wParam, lParam); break; case WM_SIZE: if (self) self->OnSize(); break; case WM_SETFOCUS: case WM_KILLFOCUS: if (self) self->OnFocus(message == WM_SETFOCUS); break; case WM_CAPTURECHANGED: case WM_CANCELMODE: if (self) self->OnCaptureLost(); break; case WM_SYSCHAR: case WM_SYSKEYDOWN: case WM_SYSKEYUP: case WM_KEYDOWN: case WM_KEYUP: case WM_CHAR: if (self) self->OnKeyEvent(message, wParam, lParam); break; case WM_PAINT: if (self) self->OnPaint(); return 0; case WM_ERASEBKGND: // Never erase the background. return 0; case WM_NCDESTROY: // Clear the reference to |self|. SetUserDataPtr(hWnd, NULL); self->hwnd_ = NULL; break; } return DefWindowProc(hWnd, message, wParam, lParam); } void OsrWindowWin::OnMouseEvent(UINT message, WPARAM wParam, LPARAM lParam) { CefRefPtr browser_host; if (browser_) browser_host = browser_->GetHost(); LONG currentTime = 0; bool cancelPreviousClick = false; if (message == WM_LBUTTONDOWN || message == WM_RBUTTONDOWN || message == WM_MBUTTONDOWN || message == WM_MOUSEMOVE || message == WM_MOUSELEAVE) { currentTime = GetMessageTime(); int x = GET_X_LPARAM(lParam); int y = GET_Y_LPARAM(lParam); cancelPreviousClick = (abs(last_click_x_ - x) > (GetSystemMetrics(SM_CXDOUBLECLK) / 2)) || (abs(last_click_y_ - y) > (GetSystemMetrics(SM_CYDOUBLECLK) / 2)) || ((currentTime - last_click_time_) > GetDoubleClickTime()); if (cancelPreviousClick && (message == WM_MOUSEMOVE || message == WM_MOUSELEAVE)) { last_click_count_ = 0; last_click_x_ = 0; last_click_y_ = 0; last_click_time_ = 0; } } switch(message) { case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: case WM_MBUTTONDOWN: { ::SetCapture(hwnd_); ::SetFocus(hwnd_); int x = GET_X_LPARAM(lParam); int y = GET_Y_LPARAM(lParam); if (wParam & MK_SHIFT) { // Start rotation effect. last_mouse_pos_.x = current_mouse_pos_.x = x; last_mouse_pos_.y = current_mouse_pos_.y = y; mouse_rotation_ = true; } else { CefBrowserHost::MouseButtonType btnType = (message == WM_LBUTTONDOWN ? MBT_LEFT : ( message == WM_RBUTTONDOWN ? MBT_RIGHT : MBT_MIDDLE)); if (!cancelPreviousClick && (btnType == last_click_button_)) { ++last_click_count_; } else { last_click_count_ = 1; last_click_x_ = x; last_click_y_ = y; } last_click_time_ = currentTime; last_click_button_ = btnType; CefRefPtr browser_host = browser_->GetHost(); if (browser_host) { CefMouseEvent mouse_event; mouse_event.x = x; mouse_event.y = y; last_mouse_down_on_view_ = !IsOverPopupWidget(x, y); ApplyPopupOffset(mouse_event.x, mouse_event.y); mouse_event.modifiers = GetCefMouseModifiers(wParam); browser_host->SendMouseClickEvent(mouse_event, btnType, false, last_click_count_); } } } break; case WM_LBUTTONUP: case WM_RBUTTONUP: case WM_MBUTTONUP: if (GetCapture() == hwnd_) ReleaseCapture(); if (mouse_rotation_) { // End rotation effect. mouse_rotation_ = false; renderer_.SetSpin(0, 0); Invalidate(); } else { int x = GET_X_LPARAM(lParam); int y = GET_Y_LPARAM(lParam); CefBrowserHost::MouseButtonType btnType = (message == WM_LBUTTONUP ? MBT_LEFT : ( message == WM_RBUTTONUP ? MBT_RIGHT : MBT_MIDDLE)); if (browser_host) { CefMouseEvent mouse_event; mouse_event.x = x; mouse_event.y = y; if (last_mouse_down_on_view_ && IsOverPopupWidget(x, y) && (GetPopupXOffset() || GetPopupYOffset())) { break; } ApplyPopupOffset(mouse_event.x, mouse_event.y); mouse_event.modifiers = GetCefMouseModifiers(wParam); browser_host->SendMouseClickEvent(mouse_event, btnType, true, last_click_count_); } } break; case WM_MOUSEMOVE: { int x = GET_X_LPARAM(lParam); int y = GET_Y_LPARAM(lParam); if (mouse_rotation_) { // Apply rotation effect. current_mouse_pos_.x = x; current_mouse_pos_.y = y; renderer_.IncrementSpin( current_mouse_pos_.x - last_mouse_pos_.x, current_mouse_pos_.y - last_mouse_pos_.y); last_mouse_pos_.x = current_mouse_pos_.x; last_mouse_pos_.y = current_mouse_pos_.y; Invalidate(); } else { if (!mouse_tracking_) { // Start tracking mouse leave. Required for the WM_MOUSELEAVE event to // be generated. TRACKMOUSEEVENT tme; tme.cbSize = sizeof(TRACKMOUSEEVENT); tme.dwFlags = TME_LEAVE; tme.hwndTrack = hwnd_; TrackMouseEvent(&tme); mouse_tracking_ = true; } if (browser_host) { CefMouseEvent mouse_event; mouse_event.x = x; mouse_event.y = y; ApplyPopupOffset(mouse_event.x, mouse_event.y); mouse_event.modifiers = GetCefMouseModifiers(wParam); browser_host->SendMouseMoveEvent(mouse_event, false); } } break; } case WM_MOUSELEAVE: { if (mouse_tracking_) { // Stop tracking mouse leave. TRACKMOUSEEVENT tme; tme.cbSize = sizeof(TRACKMOUSEEVENT); tme.dwFlags = TME_LEAVE & TME_CANCEL; tme.hwndTrack = hwnd_; TrackMouseEvent(&tme); mouse_tracking_ = false; } if (browser_host) { // Determine the cursor position in screen coordinates. POINT p; ::GetCursorPos(&p); ::ScreenToClient(hwnd_, &p); CefMouseEvent mouse_event; mouse_event.x = p.x; mouse_event.y = p.y; mouse_event.modifiers = GetCefMouseModifiers(wParam); browser_host->SendMouseMoveEvent(mouse_event, true); } } break; case WM_MOUSEWHEEL: if (browser_host) { POINT screen_point = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)}; HWND scrolled_wnd = ::WindowFromPoint(screen_point); if (scrolled_wnd != hwnd_) break; ScreenToClient(hwnd_, &screen_point); int delta = GET_WHEEL_DELTA_WPARAM(wParam); CefMouseEvent mouse_event; mouse_event.x = screen_point.x; mouse_event.y = screen_point.y; ApplyPopupOffset(mouse_event.x, mouse_event.y); mouse_event.modifiers = GetCefMouseModifiers(wParam); browser_host->SendMouseWheelEvent(mouse_event, IsKeyDown(VK_SHIFT) ? delta : 0, !IsKeyDown(VK_SHIFT) ? delta : 0); } break; } } void OsrWindowWin::OnSize() { // Keep |client_rect_| up to date. ::GetClientRect(hwnd_, &client_rect_); if (browser_) browser_->GetHost()->WasResized(); } void OsrWindowWin::OnFocus(bool setFocus) { if (browser_) browser_->GetHost()->SendFocusEvent(setFocus); } void OsrWindowWin::OnCaptureLost() { if (mouse_rotation_) return; if (browser_) browser_->GetHost()->SendCaptureLostEvent(); } void OsrWindowWin::OnKeyEvent(UINT message, WPARAM wParam, LPARAM lParam) { if (!browser_) return; CefKeyEvent event; event.windows_key_code = wParam; event.native_key_code = lParam; event.is_system_key = message == WM_SYSCHAR || message == WM_SYSKEYDOWN || message == WM_SYSKEYUP; if (message == WM_KEYDOWN || message == WM_SYSKEYDOWN) event.type = KEYEVENT_RAWKEYDOWN; else if (message == WM_KEYUP || message == WM_SYSKEYUP) event.type = KEYEVENT_KEYUP; else event.type = KEYEVENT_CHAR; event.modifiers = GetCefKeyboardModifiers(wParam, lParam); browser_->GetHost()->SendKeyEvent(event); } void OsrWindowWin::OnPaint() { // Paint nothing here. Invalidate will cause OnPaint to be called for the // render handler. PAINTSTRUCT ps; BeginPaint(hwnd_, &ps); EndPaint(hwnd_, &ps); if (browser_) browser_->GetHost()->Invalidate(PET_VIEW); } bool OsrWindowWin::IsOverPopupWidget(int x, int y) const { CEF_REQUIRE_UI_THREAD(); const CefRect& rc = renderer_.popup_rect(); int popup_right = rc.x + rc.width; int popup_bottom = rc.y + rc.height; return (x >= rc.x) && (x < popup_right) && (y >= rc.y) && (y < popup_bottom); } int OsrWindowWin::GetPopupXOffset() const { CEF_REQUIRE_UI_THREAD(); return renderer_.original_popup_rect().x - renderer_.popup_rect().x; } int OsrWindowWin::GetPopupYOffset() const { CEF_REQUIRE_UI_THREAD(); return renderer_.original_popup_rect().y - renderer_.popup_rect().y; } void OsrWindowWin::ApplyPopupOffset(int& x, int& y) const { if (IsOverPopupWidget(x, y)) { x += GetPopupXOffset(); y += GetPopupYOffset(); } } void OsrWindowWin::OnAfterCreated(CefRefPtr browser) { CEF_REQUIRE_UI_THREAD(); DCHECK(!browser_); browser_ = browser; if (hwnd_) { // Show the browser window. Called asynchronously so that the browser has // time to create associated internal objects. CefPostTask(TID_UI, base::Bind(&OsrWindowWin::Show, this)); } } void OsrWindowWin::OnBeforeClose(CefRefPtr browser) { CEF_REQUIRE_UI_THREAD(); // Detach |this| from the ClientHandlerOsr. static_cast(browser_->GetHost()->GetClient().get())-> DetachOsrDelegate(); browser_ = NULL; Destroy(); } bool OsrWindowWin::GetRootScreenRect(CefRefPtr browser, CefRect& rect) { CEF_REQUIRE_UI_THREAD(); RECT window_rect = {0}; HWND root_window = GetAncestor(hwnd_, GA_ROOT); if (::GetWindowRect(root_window, &window_rect)) { rect = CefRect(window_rect.left, window_rect.top, window_rect.right - window_rect.left, window_rect.bottom - window_rect.top); return true; } return false; } bool OsrWindowWin::GetViewRect(CefRefPtr browser, CefRect& rect) { CEF_REQUIRE_UI_THREAD(); rect.x = rect.y = 0; rect.width = client_rect_.right - client_rect_.left; rect.height = client_rect_.bottom - client_rect_.top; return true; } bool OsrWindowWin::GetScreenPoint(CefRefPtr browser, int viewX, int viewY, int& screenX, int& screenY) { CEF_REQUIRE_UI_THREAD(); if (!::IsWindow(hwnd_)) return false; // Convert the point from view coordinates to actual screen coordinates. POINT screen_pt = {viewX, viewY}; ClientToScreen(hwnd_, &screen_pt); screenX = screen_pt.x; screenY = screen_pt.y; return true; } bool OsrWindowWin::GetScreenInfo(CefRefPtr browser, CefScreenInfo& screen_info) { CEF_REQUIRE_UI_THREAD(); return false; } void OsrWindowWin::OnPopupShow(CefRefPtr browser, bool show) { CEF_REQUIRE_UI_THREAD(); if (!show) { renderer_.ClearPopupRects(); browser->GetHost()->Invalidate(PET_VIEW); } renderer_.OnPopupShow(browser, show); } void OsrWindowWin::OnPopupSize(CefRefPtr browser, const CefRect& rect) { CEF_REQUIRE_UI_THREAD(); renderer_.OnPopupSize(browser, rect); } void OsrWindowWin::OnPaint(CefRefPtr browser, CefRenderHandler::PaintElementType type, const CefRenderHandler::RectList& dirtyRects, const void* buffer, int width, int height) { CEF_REQUIRE_UI_THREAD(); if (painting_popup_) { renderer_.OnPaint(browser, type, dirtyRects, buffer, width, height); return; } if (!hdc_) EnableGL(); ScopedGLContext scoped_gl_context(hdc_, hrc_, true); renderer_.OnPaint(browser, type, dirtyRects, buffer, width, height); if (type == PET_VIEW && !renderer_.popup_rect().IsEmpty()) { painting_popup_ = true; browser->GetHost()->Invalidate(PET_POPUP); painting_popup_ = false; } renderer_.Render(); } void OsrWindowWin::OnCursorChange( CefRefPtr browser, CefCursorHandle cursor, CefRenderHandler::CursorType type, const CefCursorInfo& custom_cursor_info) { CEF_REQUIRE_UI_THREAD(); if (!::IsWindow(hwnd_)) return; // Change the plugin window's cursor. SetClassLongPtr(hwnd_, GCLP_HCURSOR, static_cast(reinterpret_cast(cursor))); SetCursor(cursor); } bool OsrWindowWin::StartDragging( CefRefPtr browser, CefRefPtr drag_data, CefRenderHandler::DragOperationsMask allowed_ops, int x, int y) { CEF_REQUIRE_UI_THREAD(); #if defined(CEF_USE_ATL) if (!drop_target_) return false; current_drag_op_ = DRAG_OPERATION_NONE; CefBrowserHost::DragOperationsMask result = drop_target_->StartDragging(browser, drag_data, allowed_ops, x, y); current_drag_op_ = DRAG_OPERATION_NONE; POINT pt = {}; GetCursorPos(&pt); ScreenToClient(hwnd_, &pt); browser->GetHost()->DragSourceEndedAt(pt.x, pt.y, result); browser->GetHost()->DragSourceSystemDragEnded(); return true; #else // Cancel the drag. The dragging implementation requires ATL support. return false; #endif } void OsrWindowWin::UpdateDragCursor( CefRefPtr browser, CefRenderHandler::DragOperation operation) { CEF_REQUIRE_UI_THREAD(); #if defined(CEF_USE_ATL) current_drag_op_ = operation; #endif } #if defined(CEF_USE_ATL) CefBrowserHost::DragOperationsMask OsrWindowWin::OnDragEnter(CefRefPtr drag_data, CefMouseEvent ev, CefBrowserHost::DragOperationsMask effect) { if (browser_) { browser_->GetHost()->DragTargetDragEnter(drag_data, ev, effect); browser_->GetHost()->DragTargetDragOver(ev, effect); } return current_drag_op_; } CefBrowserHost::DragOperationsMask OsrWindowWin::OnDragOver(CefMouseEvent ev, CefBrowserHost::DragOperationsMask effect) { if (browser_) browser_->GetHost()->DragTargetDragOver(ev, effect); return current_drag_op_; } void OsrWindowWin::OnDragLeave() { if (browser_) browser_->GetHost()->DragTargetDragLeave(); } CefBrowserHost::DragOperationsMask OsrWindowWin::OnDrop(CefMouseEvent ev, CefBrowserHost::DragOperationsMask effect) { if (browser_) { browser_->GetHost()->DragTargetDragOver(ev, effect); browser_->GetHost()->DragTargetDrop(ev); } return current_drag_op_; } #endif // defined(CEF_USE_ATL) } // namespace client