Skip to content

Commit 533d174

Browse files
helywinSleepProgger
andcommitted
Finished implementing maximize for linux.
Added FloatingContainerForc*TitleBar to switch between native and custom titlebar. Co-authored-by: SleepProgger <SleepProgger@users.noreply.github.com>
1 parent 48fb999 commit 533d174

10 files changed

+533
-37
lines changed

src/DockFocusController.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ static void updateDockAreaFocusStyle(CDockAreaWidget* DockArea, bool Focused)
8383
#ifdef Q_OS_LINUX
8484
static void updateFloatingWidgetFocusStyle(CFloatingDockContainer* FloatingWidget, bool Focused)
8585
{
86+
if(FloatingWidget->hasNativeTitleBar()){
87+
return;
88+
}
8689
auto TitleBar = qobject_cast<CFloatingWidgetTitleBar*>(FloatingWidget->titleBarWidget());
8790
if (!TitleBar)
8891
{

src/DockManager.cpp

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -368,8 +368,6 @@ void DockManagerPrivate::restoreDockAreasIndices()
368368
}
369369
}
370370

371-
372-
373371
//============================================================================
374372
void DockManagerPrivate::emitTopLevelEvents()
375373
{
@@ -476,6 +474,10 @@ CDockManager::CDockManager(QWidget *parent) :
476474
{
477475
d->FocusController = new CDockFocusController(this);
478476
}
477+
478+
#ifdef Q_OS_LINUX
479+
window()->installEventFilter(this);
480+
#endif
479481
}
480482

481483
//============================================================================
@@ -489,6 +491,53 @@ CDockManager::~CDockManager()
489491
delete d;
490492
}
491493

494+
//============================================================================
495+
#ifdef Q_OS_LINUX
496+
bool CDockManager::eventFilter(QObject *obj, QEvent *e){
497+
// Emulate Qt:Tool behaviour.
498+
// Required because on some WMs Tool windows can't be maximized.
499+
500+
// Window always on top of the MainWindow.
501+
if(e->type() == QEvent::WindowActivate){
502+
for(auto _window : floatingWidgets()){
503+
if(!_window->isVisible() || window()->isMinimized()){
504+
continue;
505+
}
506+
// setWindowFlags(Qt::WindowStaysOnTopHint) will hide the window and thus requires a show call.
507+
// This then leads to flickering and a nasty endless loop (also buggy behaviour on Ubuntu).
508+
// So we just do it ourself.
509+
internal::xcb_update_prop(true, _window->window()->winId(), "_NET_WM_STATE", "_NET_WM_STATE_ABOVE", "_NET_WM_STATE_STAYS_ON_TOP");
510+
}
511+
}
512+
else if(e->type() == QEvent::WindowDeactivate){
513+
for(auto _window : floatingWidgets()){
514+
if(!_window->isVisible() || window()->isMinimized()){
515+
continue;
516+
}
517+
internal::xcb_update_prop(false, _window->window()->winId(), "_NET_WM_STATE", "_NET_WM_STATE_ABOVE", "_NET_WM_STATE_STAYS_ON_TOP");
518+
_window->raise();
519+
}
520+
}
521+
522+
// Sync minimize with MainWindow
523+
if(e->type() == QEvent::WindowStateChange){
524+
for(auto _window : floatingWidgets()){
525+
if(! _window->isVisible()){
526+
continue;
527+
}
528+
if(window()->isMinimized()){
529+
_window->showMinimized();
530+
} else {
531+
_window->setWindowState(_window->windowState() & (~Qt::WindowMinimized));
532+
}
533+
}
534+
if(!window()->isMinimized()){
535+
QApplication::setActiveWindow(window());
536+
}
537+
}
538+
return Super::eventFilter(obj, e);
539+
}
540+
#endif
492541

493542
//============================================================================
494543
void CDockManager::registerFloatingWidget(CFloatingDockContainer* FloatingWidget)

src/DockManager.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,9 +178,17 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget
178178
FloatingContainerHasWidgetIcon = 0x80000, //!< If set, the Floating Widget icon reflects the icon of the current dock widget otherwise it displays application icon
179179
HideSingleCentralWidgetTitleBar = 0x100000, //!< If there is only one single visible dock widget in the main dock container (the dock manager) and if this flag is set, then the titlebar of this dock widget will be hidden
180180
//!< this only makes sense for non draggable and non floatable widgets and enables the creation of some kind of "central" widget
181+
181182
FocusHighlighting = 0x200000, //!< enables styling of focused dock widget tabs or floating widget titlebar
182183
EqualSplitOnInsertion = 0x400000, ///!< if enabled, the space is equally distributed to all widgets in a splitter
183184

185+
FloatingContainerForceNativeTitleBar = 0x800000, //!< Linux only ! Forces all FloatingContainer to use the native title bar. This might break docking for FloatinContainer on some Window Managers (like Kwin/KDE).
186+
//!< If neither this nor FloatingContainerForceCustomTitleBar is set (the default) native titlebars are used except on known bad systems.
187+
//! Users can overwrite this by setting the environment variable ADS_UseNativeTitle to "1" or "0".
188+
FloatingContainerForceCustomTitleBar = 0x1000000,//!< Linux only ! Forces all FloatingContainer to use a custom title bar.
189+
//!< If neither this nor FloatingContainerForceNativeTitleBar is set (the default) native titlebars are used except on known bad systems.
190+
//! Users can overwrite this by setting the environment variable ADS_UseNativeTitle to "1" or "0".
191+
184192
DefaultDockAreaButtons = DockAreaHasCloseButton
185193
| DockAreaHasUndockButton
186194
| DockAreaHasTabsMenuButton,///< default configuration of dock area title bar buttons
@@ -464,6 +472,10 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget
464472
widget->setFocus(Qt::OtherFocusReason);
465473
}
466474

475+
#ifdef Q_OS_LINUX
476+
bool eventFilter(QObject *obj, QEvent *e) override;
477+
#endif
478+
467479
public slots:
468480
/**
469481
* Opens the perspective with the given name.

src/FloatingDockContainer.cpp

Lines changed: 137 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,7 @@ struct FloatingDockContainerPrivate
376376
#ifdef Q_OS_LINUX
377377
QWidget* MouseEventHandler = nullptr;
378378
CFloatingWidgetTitleBar* TitleBar = nullptr;
379+
bool IsResizing = false;
379380
#endif
380381

381382
/**
@@ -410,10 +411,11 @@ struct FloatingDockContainerPrivate
410411
void setWindowTitle(const QString &Text)
411412
{
412413
#ifdef Q_OS_LINUX
413-
TitleBar->setTitle(Text);
414-
#else
415-
_this->setWindowTitle(Text);
414+
if(TitleBar){
415+
TitleBar->setTitle(Text);
416+
}
416417
#endif
418+
_this->setWindowTitle(Text);
417419
}
418420

419421
/**
@@ -604,13 +606,36 @@ CFloatingDockContainer::CFloatingDockContainer(CDockManager *DockManager) :
604606
SLOT(onDockAreasAddedOrRemoved()));
605607

606608
#ifdef Q_OS_LINUX
607-
d->TitleBar = new CFloatingWidgetTitleBar(this);
608-
setWindowFlags(windowFlags() | Qt::Tool);
609-
QDockWidget::setWidget(d->DockContainer);
610-
QDockWidget::setFloating(true);
611-
QDockWidget::setFeatures(QDockWidget::AllDockWidgetFeatures);
612-
setTitleBarWidget(d->TitleBar);
613-
connect(d->TitleBar, SIGNAL(closeRequested()), SLOT(close()));
609+
QDockWidget::setWidget(d->DockContainer);
610+
QDockWidget::setFloating(true);
611+
QDockWidget::setFeatures(QDockWidget::AllDockWidgetFeatures);
612+
613+
// KDE doesn't seem to fire MoveEvents while moving windows, so for now no native titlebar for everything using KWin.
614+
QString window_manager = internal::windowManager().toUpper().split(" ")[0];
615+
bool native_window = window_manager != "KWIN";
616+
// FloatingContainerForce*TitleBar is overwritten by the "ADS_UseNativeTitle" environment variable if set.
617+
auto env = qgetenv("ADS_UseNativeTitle").toUpper();
618+
if (env == "1"){
619+
native_window = true;
620+
} else if (env == "0"){
621+
native_window = false;
622+
} else if ( DockManager->testConfigFlag( CDockManager::FloatingContainerForceNativeTitleBar )){
623+
native_window = true;
624+
} else if ( DockManager->testConfigFlag( CDockManager::FloatingContainerForceCustomTitleBar )){
625+
native_window = false;
626+
}
627+
if(native_window){
628+
setTitleBarWidget(new QWidget());
629+
setWindowFlags(Qt::Window | Qt::WindowMaximizeButtonHint | Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint);
630+
} else {
631+
d->TitleBar = new CFloatingWidgetTitleBar(this);
632+
setTitleBarWidget(d->TitleBar);
633+
setWindowFlags(Qt::Window | Qt::WindowMinMaxButtonsHint | Qt::FramelessWindowHint);
634+
d->TitleBar->enableCloseButton(isClosable());
635+
connect(d->TitleBar, SIGNAL(closeRequested()), SLOT(close()));
636+
connect(d->TitleBar, &CFloatingWidgetTitleBar::maximizeRequested,
637+
this, &CFloatingDockContainer::onMaximizeRequest);
638+
}
614639
#else
615640
setWindowFlags(
616641
Qt::Window | Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint);
@@ -629,9 +654,7 @@ CFloatingDockContainer::CFloatingDockContainer(CDockAreaWidget *DockArea) :
629654
CFloatingDockContainer(DockArea->dockManager())
630655
{
631656
d->DockContainer->addDockArea(DockArea);
632-
#ifdef Q_OS_LINUX
633-
d->TitleBar->enableCloseButton(isClosable());
634-
#endif
657+
635658
auto TopLevelDockWidget = topLevelDockWidget();
636659
if (TopLevelDockWidget)
637660
{
@@ -646,9 +669,6 @@ CFloatingDockContainer::CFloatingDockContainer(CDockWidget *DockWidget) :
646669
CFloatingDockContainer(DockWidget->dockManager())
647670
{
648671
d->DockContainer->addDockWidget(CenterDockWidgetArea, DockWidget);
649-
#ifdef Q_OS_LINUX
650-
d->TitleBar->enableCloseButton(isClosable());
651-
#endif
652672
auto TopLevelDockWidget = topLevelDockWidget();
653673
if (TopLevelDockWidget)
654674
{
@@ -678,12 +698,18 @@ CDockContainerWidget* CFloatingDockContainer::dockContainer() const
678698
//============================================================================
679699
void CFloatingDockContainer::changeEvent(QEvent *event)
680700
{
681-
QWidget::changeEvent(event);
701+
Super::changeEvent(event);
682702
if ((event->type() == QEvent::ActivationChange) && isActiveWindow())
683703
{
684704
ADS_PRINT("FloatingWidget::changeEvent QEvent::ActivationChange ");
685705
d->zOrderIndex = ++zOrderCounter;
686-
return;
706+
707+
#ifdef Q_OS_LINUX
708+
if(d->DraggingState == DraggingFloatingWidget){
709+
d->titleMouseReleaseEvent();
710+
d->DraggingState = DraggingInactive;
711+
}
712+
#endif
687713
}
688714
}
689715

@@ -825,21 +851,33 @@ void CFloatingDockContainer::startFloating(const QPoint &DragStartMousePos,
825851
#ifndef Q_OS_LINUX
826852
Q_UNUSED(MouseEventHandler)
827853
#endif
854+
#ifdef Q_OS_LINUX
855+
if (!isMaximized()) {
856+
resize(Size);
857+
d->DragStartMousePosition = DragStartMousePos;
858+
}
859+
#else
828860
resize(Size);
829-
d->setState(DragState);
830861
d->DragStartMousePosition = DragStartMousePos;
862+
#endif
863+
d->setState(DragState);
831864
#ifdef Q_OS_LINUX
832865
if (DraggingFloatingWidget == DragState)
833866
{
834-
setAttribute(Qt::WA_X11NetWmWindowTypeDock, true);
835867
d->MouseEventHandler = MouseEventHandler;
836868
if (d->MouseEventHandler)
837869
{
838870
d->MouseEventHandler->grabMouse();
839871
}
840872
}
841873
#endif
874+
#ifdef Q_OS_LINUX
875+
if (!isMaximized()) {
876+
moveFloating();
877+
}
878+
#else
842879
moveFloating();
880+
#endif
843881
show();
844882
}
845883

@@ -850,7 +888,6 @@ void CFloatingDockContainer::moveFloating()
850888
const QPoint moveToPos = QCursor::pos() - d->DragStartMousePosition
851889
- QPoint(BorderSize, 0);
852890
move(moveToPos);
853-
854891
switch (d->DraggingState)
855892
{
856893
case DraggingMousePressed:
@@ -949,11 +986,16 @@ bool CFloatingDockContainer::restoreState(CDockingStateReader &Stream,
949986
{
950987
return false;
951988
}
952-
953989
onDockAreasAddedOrRemoved();
990+
#ifdef Q_OS_LINUX
991+
if(d->TitleBar){
992+
d->TitleBar->setMaximizedIcon(windowState() == Qt::WindowMaximized);
993+
}
994+
#endif
954995
return true;
955996
}
956997

998+
957999
//============================================================================
9581000
bool CFloatingDockContainer::hasTopLevelDockWidget() const
9591001
{
@@ -977,19 +1019,17 @@ void CFloatingDockContainer::finishDragging()
9771019
{
9781020
ADS_PRINT("CFloatingDockContainer::finishDragging");
9791021
#ifdef Q_OS_LINUX
980-
setAttribute(Qt::WA_X11NetWmWindowTypeDock, false);
981-
setWindowOpacity(1);
982-
activateWindow();
983-
if (d->MouseEventHandler)
984-
{
985-
d->MouseEventHandler->releaseMouse();
986-
d->MouseEventHandler = nullptr;
987-
}
1022+
setWindowOpacity(1);
1023+
activateWindow();
1024+
if (d->MouseEventHandler)
1025+
{
1026+
d->MouseEventHandler->releaseMouse();
1027+
d->MouseEventHandler = nullptr;
1028+
}
9881029
#endif
989-
d->titleMouseReleaseEvent();
1030+
d->titleMouseReleaseEvent();
9901031
}
9911032

992-
9931033
#ifdef Q_OS_MACOS
9941034
//============================================================================
9951035
bool CFloatingDockContainer::event(QEvent *e)
@@ -1092,6 +1132,71 @@ void CFloatingDockContainer::moveEvent(QMoveEvent *event)
10921132
}
10931133
#endif
10941134

1135+
1136+
#ifdef Q_OS_LINUX
1137+
void CFloatingDockContainer::onMaximizeRequest()
1138+
{
1139+
if(windowState() == Qt::WindowMaximized){
1140+
showNormal();
1141+
}else{
1142+
showMaximized();
1143+
}
1144+
}
1145+
1146+
void CFloatingDockContainer::showNormal(bool fixGeometry)
1147+
{
1148+
if (windowState() == Qt::WindowMaximized)
1149+
{
1150+
QRect oldNormal = normalGeometry();
1151+
Super::showNormal();
1152+
if(fixGeometry)
1153+
{
1154+
setGeometry(oldNormal);
1155+
}
1156+
}
1157+
if(d->TitleBar){
1158+
d->TitleBar->setMaximizedIcon(false);
1159+
}
1160+
}
1161+
1162+
void CFloatingDockContainer::showMaximized()
1163+
{
1164+
Super::showMaximized();
1165+
if(d->TitleBar){
1166+
d->TitleBar->setMaximizedIcon(true);
1167+
}
1168+
}
1169+
1170+
bool CFloatingDockContainer::isMaximized() const
1171+
{
1172+
return windowState() == Qt::WindowMaximized;
1173+
}
1174+
1175+
void CFloatingDockContainer::show(){
1176+
// Prevent this window from showing in the taskbar and pager (alt+tab)
1177+
internal::xcb_add_prop(true, winId(), "_NET_WM_STATE", "_NET_WM_STATE_SKIP_TASKBAR");
1178+
internal::xcb_add_prop(true, winId(), "_NET_WM_STATE", "_NET_WM_STATE_SKIP_PAGER");
1179+
Super::show();
1180+
}
1181+
void CFloatingDockContainer::resizeEvent(QResizeEvent *event){
1182+
d->IsResizing = true;
1183+
Super::resizeEvent(event);
1184+
}
1185+
1186+
void CFloatingDockContainer::moveEvent(QMoveEvent *event){
1187+
Super::moveEvent(event);
1188+
if(!d->IsResizing && event->spontaneous()){
1189+
d->DraggingState = DraggingFloatingWidget;
1190+
d->updateDropOverlays(QCursor::pos());
1191+
}
1192+
d->IsResizing = false;
1193+
}
1194+
1195+
bool CFloatingDockContainer::hasNativeTitleBar(){
1196+
return d->TitleBar == nullptr;
1197+
}
1198+
#endif
1199+
10951200
} // namespace ads
10961201

10971202
//---------------------------------------------------------------------------

0 commit comments

Comments
 (0)