Linux下Qt实现无边框可缩放的窗口

在Linux平台上做desktop应用的还是非常少的。所以基本上网上这部分资料是没有的。Linux平台又不像Win那么多API。这次的实现,本来自己想写xlib的函数的,然后机智的我从deepin的代码里把他们封装好的抠出来了,然后补充了一些x11的封装函数。来完成最终的效果。

本篇文章纯粹抛砖引玉,毕竟只是个demo。简单的说一下遇到的坑。

代码

实现上很简单,重写qt的三个函数就可以。

void FLWidget_Linux::mouseMoveEvent(QMouseEvent *event)
{
#ifdef Q_OS_LINUX
     const int x = event->x();
     const int y = event->y();

     if (resizingCornerEdge == XUtils::CornerEdge::kInvalid)
     {
      XUtils::UpdateCursorShape(this, x, y, this->layout()->contentsMargins(), ResizeHandleWidth);
     }
#endif

 return QWidget::mouseMoveEvent(event);
}

void FLWidget_Linux::mousePressEvent(QMouseEvent *event)
{
#ifdef Q_OS_LINUX
 const int x = event->x();
 const int y = event->y();
 if (event->button() == Qt::LeftButton)
 {
      const XUtils::CornerEdge ce = XUtils::GetCornerEdge(this, x, y, this->layout()->contentsMargins(), ResizeHandleWidth);
      if (ce != XUtils::CornerEdge::kInvalid)
      {
           resizingCornerEdge = ce;
           //send x11 move event dont send mouserrelease event
           XUtils::SendButtonRelease(this, event->pos(), event->globalPos());
           XUtils::StartResizing(this, QCursor::pos(), ce);
      }
 }
#endif
 return QWidget::mousePressEvent(event);

void FLWidget_Linux::mouseReleaseEvent(QMouseEvent *event)
{
#ifdef Q_OS_LINUX
     resizingCornerEdge = XUtils::CornerEdge::kInvalid;
#endif
     return QWidget::mouseReleaseEvent(event);
}

只重写这三个函数就可以完成对应的功能,当然还得有XUtils。
XUtils是deepin封装的一个功能namespace。封装了常用的xlib操作qt的widget的一些函数。
然后我补充了一个他们的函数

主要是调用的xlib的mousemove之后,Qt接受不到release事件,需要手动再发一个

XUtils::SendButtonRelease(this, event->pos(), event->globalPos());
void SendButtonRelease(const QWidget *widget,
          const QPoint &pos, const QPoint &globalPos)
{
 const auto display = QX11Info::display();
 const auto screen = QX11Info::appScreen();

 XEvent xevent;
 memset(&xevent, 0, sizeof(XEvent));

 xevent.type = ButtonRelease;
 xevent.xbutton.button = Button1;
 xevent.xbutton.window = widget->effectiveWinId();
 xevent.xbutton.x = pos.x();
 xevent.xbutton.y = pos.y();
 xevent.xbutton.x_root = globalPos.x();
 xevent.xbutton.y_root = globalPos.y();
 xevent.xbutton.display = display;

 XSendEvent(display, widget->effectiveWinId(), False, ButtonReleaseMask, &xevent);
 XFlush(display);
}

昨天整理了下文档,发到github上了,欢迎star跟fork

https://github.com/CryFeiFei/FLWidget


文章作者: 张小飞
版权声明: 本博客所有文章除特別声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 张小飞 !
  目录