How to adjust the position and size of CEF browser in Linux?

1 week ago 4
ARTICLE AD BOX

I embedded CEF into QT and initialized it successfully, but I am helpless on how to modify the size and position.

I used the latest version of CEF compilation:

cef_binary_142.0.17+g60aac24+chromium-142.0.7444.176_linux64

I compiled using cmake on the latest version of Ubuntu:Ubuntu 24.04.3 LTS

The following is the core problem code:

//==================Create a browser window that works very well. CefWindowInfo window_info; WId hwnd = (WId)winId(); CefRect rect(0, 0, width(), height()); //window_info.SetAsWindowless // window_info.SetAsWindowless(static_cast<CefWindowHandle>(hwnd)); window_info.SetAsChild(static_cast<CefWindowHandle>(hwnd), rect); //window_info.runtime_style = CEF_RUNTIME_STYLE_DEFAULT; CefBrowserSettings browser_settings; browser_settings.webgl = cef_state_t::STATE_ENABLED; CefRefPtr<CefWidget> handler = CefRefPtr<CefWidget>(this); //keep "browser_" in m_browserlist browser_ = CefBrowserHost::CreateBrowserSync(window_info, handler, url.toStdString(), browser_settings, nullptr, nullptr); m_browserlist.push_back(browser_); //==================Try to adjust the position and size of CEF browser in Linux //==================This doesn't work for (size_t i = 0; i < m_browserlist.size(); i++) { auto browser = m_browserlist[i]; if (browser.get()) { CefWindowHandle hwnd_ = browser->GetHost()->GetWindowHandle(); if (hwnd_) { //get cef display???I found it in cefsimple-test-code Display* disp = cef_get_xdisplay(); Window parent_xwindow = DefaultRootWindow(disp); hwnd_ = parent_xwindow; XWindowAttributes attrs; if (!disp) { return; } if (!XGetWindowAttributes(disp, static_cast<Window>(hwnd_), &attrs)) { return; } QRect rec = geometry(); // resize and move, but it doesn't work. linuxMoveWindow(disp, hwnd_, rec.x(), rec.y(), sz.width(), sz.height(), true); // resize and move, but it doesn't work too. //linuxMoveWindow(disp, browser->GetHost()->GetWindowHandle(), rec.x(), rec.y(), sz.width(), sz.height(), true); } } } //=======================linuxMoveWindow method /** *The complete replacement function for MoveWindow in Linux *@ param display X11 display *@ param window handle *@ param x new X coordinate *@ param y new Y coordinate *@ paramwidth new width *@ param height new height *Does @ param redraw (bRepaint parameter of Windows MoveWindow) *@ return returns true for success and false for failure */ bool linuxMoveWindow(Display* display, Window window, int x, int y, int width, int height, bool repaint = true) { if (!display || !window) return false; // Does the window exist XWindowAttributes attrs; if (!XGetWindowAttributes(display, window, &attrs)) { qWarning() << "Window does not exist or is invalid"; return false; } // Does the window viewable if (attrs.map_state != IsViewable) { qWarning() << "Window is not viewable, cannot move/resize"; return false; } // resize and move XMoveResizeWindow(display, window, x, y, width, height); // repaint if (repaint) { XClearArea(display, window, 0, 0, width, height, True); } // done XSync(display, False); return true; }

The following is the runnable source code:

(main.cpp , cefwidget.h)

#include "mainwindow.h" #include "CefWidget.h" #include <QApplication> #include "include/cef_app.h" #include "include/cef_command_line.h" #include <QtWidgets/QApplication> #include <QVBoxLayout> #include <QTimer> #ifdef Q_OS_WIN #include <windows.h> #else #include <unistd.h> #endif #include <signal.h> void signalHandler(int signum) { if (signum == SIGTRAP) { qDebug() << "Ignoring SIGTRAP signal"; return; } } int main(int argc, char *argv[]) { int result = 0; signal(SIGTRAP, signalHandler); qputenv("LANG", "en_US.UTF-8"); qputenv("LANGUAGE", "en_US:en"); qputenv("LC_ALL", "en_US.UTF-8"); //qputenv("QT_LOGGING_RULES", "*.debug=false"); qputenv("CEF_DEBUG", "0"); std::setlocale(LC_ALL, "en_US.UTF-8"); std::setlocale(LC_NUMERIC, "C"); // ========== CEF init ========== #ifdef Q_OS_WIN HINSTANCE hInstance = GetModuleHandle(NULL); CefMainArgs main_args(hInstance); #else CefMainArgs main_args(argc, argv); #endif int exit_code = CefExecuteProcess(main_args, nullptr, nullptr); if (exit_code >= 0) { // The sub-process has completed so return here. return exit_code; } // Parse command-line arguments for use in this method. CefRefPtr<CefCommandLine> command_line = CefCommandLine::CreateCommandLine(); #ifdef Q_OS_WIN command_line->InitFromString(::GetCommandLineW()); #else // Linux argc/argv command_line->InitFromArgv(argc, argv); #endif // debug disable command_line->AppendSwitch("--disable-breakpad"); command_line->AppendSwitch("--disable-in-process-stack-traces"); command_line->AppendSwitch("--disable-d3d11"); command_line->AppendSwitch("--disable-gpu"); command_line->AppendSwitch("--disable-software-rasterizer"); command_line->AppendSwitch("--no-sandbox"); command_line->AppendSwitch("--disable-gpu-compositing"); // Pdf extension disable command_line->AppendSwitch("--disable-pdf-extension"); command_line->AppendSwitch("--disable-extensions"); command_line->AppendSwitch("--disable-plugins-discovery"); command_line->AppendSwitch("--disable-component-update"); command_line->AppendSwitch("--disable-background-networking"); command_line->AppendSwitch("--disable-default-apps"); command_line->AppendSwitch("--disable-sync"); // net stuff command_line->AppendSwitch("--disable-quic"); command_line->AppendSwitch("--disable-http2"); command_line->AppendSwitch("--enable-simple-cache-backend"); command_line->AppendSwitch("--no-proxy-server"); command_line->AppendSwitch("--disable-features=NetworkService"); command_line->AppendSwitch("--disable-features=VizDisplayCompositor"); // cpu command_line->AppendSwitch("--disable-renderer-priority-management"); command_line->AppendSwitch("--disable-background-timer-throttling"); command_line->AppendSwitch("--disable-backgrounding-occluded-windows"); command_line->AppendSwitch("--disable-ipc-flooding-protection"); CefSettings settings; settings.no_sandbox = true; settings.windowless_rendering_enabled = true; settings.multi_threaded_message_loop = false; //settings.log_severity = LOGSEVERITY_DISABLE;//log settings.log_severity = LOGSEVERITY_VERBOSE;//log to console CefString(&settings.log_file).FromString("/dev/stdout");//log to console settings.uncaught_exception_stack_size = 10;//log detail // set exe path std::string exe_path = argv[0]; CefString(&settings.browser_subprocess_path).FromString(exe_path); // set resource path std::string resources_path = exe_path.substr(0, exe_path.find_last_of("/")); CefString(&settings.resources_dir_path).FromString(resources_path); CefString(&settings.locales_dir_path).FromString(resources_path + "/locales"); // set cache path std::string cache_path = std::string(getenv("HOME")) + "/.cache/cef_test"; CefString(&settings.cache_path).FromString(cache_path); // ========== Qt init ========== //QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling); QApplication app(argc, argv); app.setApplicationName("CefTest"); app.setOrganizationName("YourOrg"); MainWindow window; CefRefPtr<QCefApp> cefApp(new QCefApp(&window)); // ========== CEF init ========== qDebug()<<"init cef"; bool cef_initialized = CefInitialize(main_args, settings, cefApp.get(), nullptr); if (!cef_initialized) { qCritical() << "Failed to initialize CEF"; return -1; } qDebug() << "CEF initialized successfully"; // ========== CEF message loop ========== QTimer* timer = new QTimer; timer->setInterval(10); QObject::connect(timer, &QTimer::timeout, [=,&window]() { static bool initflag = false; if (cefApp->GetWidget()) { if (initflag == false) { initflag = true; ////Cannot be used as a child control, QT window will flash and draw continuously, CPU will run to full capacity directly // QVBoxLayout* layout = new QVBoxLayout; // layout->setContentsMargins(0, 0, 0, 0); // layout->setSpacing(0); // layout->addWidget(cefApp->GetWidget()); // //window.setStyleSheet("QWidget{background:white;}"); // window.centralWidget()->setLayout(layout); window.show();//set a test url inside window.setCefApp(cefApp); //Delay some time for webpage loading QTimer::singleShot(100, [=,&window](){ auto geo = window.geometry(); cefApp->GetWidget()->setGeometry(geo); cefApp->GetWidget()->show(); }); } CefDoMessageLoopWork(); } }); timer->start(); result = app.exec(); // ========== clear ========== timer->stop(); timer->deleteLater(); //cefApp = nullptr; CefShutdown(); return result; } #pragma once #include <QWidget> #include <QPainter> #include <QTimer> #include <QShowEvent> #include <QGuiApplication> #include "include/cef_app.h" #include "include/cef_client.h" #include "include/cef_render_handler.h" #include "include/cef_browser.h" #include "include/cef_image.h" #ifdef Q_OS_WIN #include <windows.h> #elif defined(Q_OS_LINUX) #include <X11/Xlib.h> #include <X11/Xutil.h> #elif defined(Q_OS_MAC) #include <Carbon/Carbon.h> #endif #include <QDateTime> #include <QStandardPaths> class CefWidget : public QWidget, public CefClient, public CefRenderHandler { Q_OBJECT public: CefWidget(QWidget* parent = nullptr) : QWidget(parent) { setAttribute(Qt::WA_NativeWindow); setAttribute(Qt::WA_PaintOnScreen); setAttribute(Qt::WA_OpaquePaintEvent); setAutoFillBackground(false); QRect rec = QRect(0, 0, 800, 600); setGeometry(rec) ; } ~CefWidget() { if (browser_) { browser_->GetHost()->CloseBrowser(true); } } void initCef(const QString& url) { qDebug() << "==========>initCef!!!!!!!" << url; CefWindowInfo window_info; WId hwnd = (WId)winId(); CefRect rect(0, 0, width(), height()); //window_info.SetAsWindowless // window_info.SetAsWindowless(static_cast<CefWindowHandle>(hwnd)); window_info.SetAsChild(static_cast<CefWindowHandle>(hwnd), rect); //window_info.runtime_style = CEF_RUNTIME_STYLE_DEFAULT; CefBrowserSettings browser_settings; browser_settings.webgl = cef_state_t::STATE_ENABLED; CefRefPtr<CefWidget> handler = CefRefPtr<CefWidget>(this); browser_ = CefBrowserHost::CreateBrowserSync(window_info, handler, url.toStdString(), browser_settings, nullptr, nullptr); m_browserlist.push_back(browser_); } void showEvent(QShowEvent* e) { if (e->type() == QShowEvent::Show) { qDebug() << "showEvent!!!!!!!"; //QTImer:: initCef("https://www.baidu.com"); } } /** *The complete replacement function for MoveWindow in Linux *@ param display X11 display *@ param window handle *@ param x new X coordinate *@ param y new Y coordinate *@ paramwidth new width *@ param height new height *Does @ param redraw (bRepaint parameter of Windows MoveWindow) *@ return returns true for success and false for failure */ bool linuxMoveWindow(Display* display, Window window, int x, int y, int width, int height, bool repaint = true) { if (!display || !window) return false; // Does the window exist XWindowAttributes attrs; if (!XGetWindowAttributes(display, window, &attrs)) { qWarning() << "Window does not exist or is invalid"; return false; } // Does the window viewable if (attrs.map_state != IsViewable) { qWarning() << "Window is not viewable, cannot move/resize"; return false; } // resize and move XMoveResizeWindow(display, window, x, y, width, height); // repaint if (repaint) { XClearArea(display, window, 0, 0, width, height, True); } // done XSync(display, False); return true; } void resizeEvent(QResizeEvent* e) { qDebug() <<"resizeEvent"<<e->size(); QWidget::resizeEvent(e); if (m_browserlist.size() > 0) { for (size_t i = 0; i < m_browserlist.size(); i++) { auto browser = m_browserlist[i]; if (browser.get()) { CefWindowHandle hwnd_ = browser->GetHost()->GetWindowHandle(); if (hwnd_) { int factor = 100;//DPIHelper::GetCurrentScaleFactor(); QSize sz = e->size() * (factor / 100.0); #ifdef Q_OS_WIN ::MoveWindow(hwnd_, 0, 0, e->size().width() * (factor / 100.0), e->size().height() * (factor / 100.0), TRUE); #elif defined(Q_OS_LINUX) #if defined(CEF_X11) Display* disp = cef_get_xdisplay(); Window parent_xwindow = DefaultRootWindow(disp); hwnd_ = parent_xwindow; XWindowAttributes attrs; if (!disp) { return; } if (!XGetWindowAttributes(disp, static_cast<Window>(hwnd_), &attrs)) { return; } QRect rec = geometry(); // resize and move window linuxMoveWindow(disp, hwnd_, rec.x(), rec.y(), sz.width(), sz.height(), true); #endif #else return; #endif } } } } } void refreshUrl() { if (browser_) { browser_->Reload(); } } void GetViewRect(CefRefPtr<CefBrowser> browser, CefRect& rect) override { qDebug() << "==========>GetViewRect!!!!!!!"<<this->rect(); rect.Set(0, 0, width(), height()); return; } virtual void OnPaint(CefRefPtr<CefBrowser> browser, PaintElementType type, const RectList& dirtyRects, const void* buffer, int width, int height) override { qDebug() << "==========>OnPaint!!!!!!!" << this->rect(); QPainter painter(this); QImage image(static_cast<const uchar*>(buffer), width, height, QImage::Format_ARGB32_Premultiplied); painter.drawImage(0, 0, image); } private: CefRefPtr<CefBrowser> browser_; QList<CefRefPtr<CefBrowser>> m_browserlist; // === IMPLEMENT_REFCOUNTING === // Add functions: AddRef(), Release(), HasOneRef(), HasAtLeastOneRef() IMPLEMENT_REFCOUNTING(CefWidget); }; // Implement application-level callbacks for the browser process. class QCefApp : public CefApp, public CefBrowserProcessHandler { public: QCefApp(QWidget* parent) { m_parent = parent; } CefWidget* GetWidget() { return m_widget; } // CefApp methods: CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler() override { qDebug() << "===========GetBrowserProcessHandler:" << this; return this; } // CefBrowserProcessHandler methods: void OnContextInitialized() override { qDebug() << "===========OnContextInitialized:"; m_widget = new CefWidget(m_parent); qDebug() << "===========OnContextInitialized:" << m_widget; } CefRefPtr<CefClient> GetDefaultClient() override { qDebug() << "===========GetDefaultClient:" << m_widget; return m_widget; } virtual void OnBeforeCommandLineProcessing( const CefString& process_type, CefRefPtr<CefCommandLine> command_line) override { } private: CefWidget* m_widget = nullptr; QWidget* m_parent = nullptr; private: // Include the default reference counting implementation. IMPLEMENT_REFCOUNTING(QCefApp); };
Read Entire Article