From ae1888597246e608c5327fccd4fa68273017b8b8 Mon Sep 17 00:00:00 2001 From: "Richard Wedlich (rootzrich)" Date: Sun, 14 Dec 2014 17:29:54 +0100 Subject: [PATCH] implements autohide taskbar #134. modified for use with qt5. implemented xcb events. works ok, ecxcept if the systray plugin is used. --- cmake/FindXCB.cmake | 54 ++++ panel/CMakeLists.txt | 4 + panel/config/configpaneldialog.cpp | 17 +- panel/config/configpaneldialog.h | 5 + panel/config/configpaneldialog.ui | 24 ++ panel/lxqtpanel.cpp | 508 +++++++++++++++++++++++++++++++++---- panel/lxqtpanel.h | 72 +++++- panel/lxqtpanelapplication.cpp | 7 + panel/lxqtpanelapplication.h | 7 + panel/lxqtpanellayout.cpp | 5 +- panel/lxqtpanellayout.h | 2 + panel/lxqtpanellimits.h | 3 + panel/plugin.cpp | 2 + panel/plugin.h | 2 + plugin-mount/lxqtmountplugin.cpp | 7 - plugin-mount/lxqtmountplugin.h | 1 - plugin-volume/lxqtvolume.cpp | 4 - plugin-volume/lxqtvolume.h | 1 - 18 files changed, 654 insertions(+), 71 deletions(-) create mode 100644 cmake/FindXCB.cmake diff --git a/cmake/FindXCB.cmake b/cmake/FindXCB.cmake new file mode 100644 index 0000000..b23d790 --- /dev/null +++ b/cmake/FindXCB.cmake @@ -0,0 +1,54 @@ +# - Try to find libxcb +# Once done this will define +# +# LIBXCB_FOUND - system has libxcb +# LIBXCB_LIBRARIES - Link these to use libxcb +# LIBXCB_INCLUDE_DIR - the libxcb include dir +# LIBXCB_DEFINITIONS - compiler switches required for using libxcb + +# Copyright (c) 2008 Helio Chissini de Castro, +# Copyright (c) 2007, Matthias Kretz, +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +IF (NOT WIN32) + IF (LIBXCB_INCLUDE_DIR AND LIBXCB_LIBRARIES) + # in cache already + SET(XCB_FIND_QUIETLY TRUE) + ENDIF (LIBXCB_INCLUDE_DIR AND LIBXCB_LIBRARIES) + + FIND_PACKAGE(PkgConfig) + PKG_CHECK_MODULES(PKG_XCB xcb) + + SET(LIBXCB_DEFINITIONS ${PKG_XCB_CFLAGS}) + + FIND_PATH(LIBXCB_INCLUDE_DIR xcb/xcb.h ${PKG_XCB_INCLUDE_DIRS}) + FIND_LIBRARY(LIBXCB_LIBRARIES NAMES xcb libxcb PATHS ${PKG_XCB_LIBRARY_DIRS}) + + include(FindPackageHandleStandardArgs) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(XCB DEFAULT_MSG LIBXCB_LIBRARIES LIBXCB_INCLUDE_DIR) + + MARK_AS_ADVANCED(LIBXCB_INCLUDE_DIR LIBXCB_LIBRARIES XCBPROC_EXECUTABLE) +ENDIF (NOT WIN32) diff --git a/panel/CMakeLists.txt b/panel/CMakeLists.txt index bdbfd9b..4ac9114 100644 --- a/panel/CMakeLists.txt +++ b/panel/CMakeLists.txt @@ -1,5 +1,7 @@ set(PROJECT lxqt-panel) +find_package(XCB REQUIRED) + set(lxqt-panel_PRIV_H_FILES lxqtpanel.h lxqtpanelapplication.h @@ -44,6 +46,7 @@ set(MOCS set(LIBRARIES ${LXQT_LIBRARIES} ${QTXDG_LIBRARIES} + ${LIBXCB_LIBRARIES} ) set(RESOURCES "") @@ -67,6 +70,7 @@ project(${PROJECT}) include_directories( ${CMAKE_CURRENT_BINARY_DIR} + ${LIBXCB_INCLUDE_DIR} ${LXQT_INCLUDE_DIRS} ${LXQT_INCLUDE_DIRS}/LXQt # FIXME: liblxqt seems to be broken, workaround it. ) diff --git a/panel/config/configpaneldialog.cpp b/panel/config/configpaneldialog.cpp index cb34770..27fd079 100644 --- a/panel/config/configpaneldialog.cpp +++ b/panel/config/configpaneldialog.cpp @@ -117,6 +117,9 @@ ConfigPanelWidget::ConfigPanelWidget(LxQtPanel *panel, QWidget *parent) : mOldPosition = mPanel->position(); mPosition = mOldPosition; + mOldAutohideTb = mPanel->autohideTb(); + mOldAutohideDuration = mPanel->autohideDuration(); + ui->spinBox_panelSize->setMinimum(PANEL_MINIMUM_SIZE); ui->spinBox_panelSize->setMaximum(PANEL_MAXIMUM_SIZE); @@ -139,6 +142,9 @@ ConfigPanelWidget::ConfigPanelWidget(LxQtPanel *panel, QWidget *parent) : connect(ui->comboBox_alignment, SIGNAL(activated(int)), this, SLOT(editChanged())); connect(ui->comboBox_position, SIGNAL(activated(int)), this, SLOT(positionChanged())); + connect(ui->checkBox_autohideTb, SIGNAL(stateChanged(int)), this, SLOT(editChanged())); + connect(ui->spinBox_autohideDuration, SIGNAL(valueChanged(int)), this, SLOT(editChanged())); + connect(ui->checkBox_customFontColor, SIGNAL(toggled(bool)), this, SLOT(editChanged())); connect(ui->pushButton_customFontColor, SIGNAL(clicked(bool)), this, SLOT(pickFontColor())); connect(ui->checkBox_customBgColor, SIGNAL(toggled(bool)), this, SLOT(editChanged())); @@ -146,7 +152,7 @@ ConfigPanelWidget::ConfigPanelWidget(LxQtPanel *panel, QWidget *parent) : connect(ui->checkBox_customBgImage, SIGNAL(toggled(bool)), this, SLOT(editChanged())); connect(ui->lineEdit_customBgImage, SIGNAL(textChanged(QString)), this, SLOT(editChanged())); connect(ui->pushButton_customBgImage, SIGNAL(clicked(bool)), this, SLOT(pickBackgroundImage())); - connect(ui->slider_opacity, SIGNAL(sliderReleased()), this, SLOT(editChanged())); + connect(ui->slider_opacity, SIGNAL(sliderReleased()), this, SLOT(editChanged())); } @@ -168,10 +174,14 @@ void ConfigPanelWidget::reset() widthTypeChanged(); ui->spinBox_length->setValue(mOldLength); + ui->checkBox_autohideTb->setChecked(mOldAutohideTb); + ui->spinBox_autohideDuration->setValue(mOldAutohideDuration); + mFontColor.setNamedColor(mOldFontColor.name()); ui->pushButton_customFontColor->setStyleSheet(QString("background: %1").arg(mOldFontColor.name())); mBackgroundColor.setNamedColor(mOldBackgroundColor.name()); ui->pushButton_customBgColor->setStyleSheet(QString("background: %1").arg(mOldBackgroundColor.name())); + ui->lineEdit_customBgImage->setText(mOldBackgroundImage); ui->slider_opacity->setValue(mOldOpacity); @@ -295,6 +305,7 @@ void ConfigPanelWidget::editChanged() mPanel->setPosition(mScreenNum, mPosition, true); mPanel->setFontColor(ui->checkBox_customFontColor->isChecked() ? mFontColor : QColor(), true); + if (ui->checkBox_customBgColor->isChecked()) { mPanel->setBackgroundColor(mBackgroundColor, true); @@ -308,6 +319,10 @@ void ConfigPanelWidget::editChanged() QString image = ui->checkBox_customBgImage->isChecked() ? ui->lineEdit_customBgImage->text() : QString(); mPanel->setBackgroundImage(image, true); + + // autohide + mPanel->setAutohide(ui->checkBox_autohideTb->isChecked()); + mPanel->setAutohideDuration(ui->spinBox_autohideDuration->value()); } diff --git a/panel/config/configpaneldialog.h b/panel/config/configpaneldialog.h index 605e005..95d303d 100644 --- a/panel/config/configpaneldialog.h +++ b/panel/config/configpaneldialog.h @@ -100,7 +100,12 @@ private slots: LxQtPanel::Alignment mOldAlignment; ILxQtPanel::Position mOldPosition; int mOldScreenNum; + + bool mOldAutohideTb; + int mOldAutohideDuration; + QColor mOldFontColor; + QColor mOldBackgroundColor; QString mOldBackgroundImage; int mOldOpacity; diff --git a/panel/config/configpaneldialog.ui b/panel/config/configpaneldialog.ui index f72ca29..ba78b64 100644 --- a/panel/config/configpaneldialog.ui +++ b/panel/config/configpaneldialog.ui @@ -211,6 +211,30 @@ + + + + Autohide this panel + + + + + + + Autohide duration: [ms] + + + + + + + 0 + + + 10000 + + + diff --git a/panel/lxqtpanel.cpp b/panel/lxqtpanel.cpp index a70e1f0..c7f39db 100644 --- a/panel/lxqtpanel.cpp +++ b/panel/lxqtpanel.cpp @@ -48,6 +48,8 @@ #include #include +#include + #include #include @@ -66,6 +68,11 @@ #define CFG_KEY_OPACITY "opacity" #define CFG_KEY_PLUGINS "plugins" +#define CFG_KEY_AUTOHIDE "autohideTb" +#define CFG_KEY_AUTOHIDEDURATION "autohideDuration" +#define AUTOHIDETB_SPACE 1 // unit pixels + + /************************************************ Returns the Position by the string. String is one of "Top", "Left", "Bottom", "Right", string is not case sensitive. @@ -112,6 +119,13 @@ LxQtPanel::LxQtPanel(const QString &configGroup, QWidget *parent) : mIconSize(0), mLineCount(0), mLength(0), + mPanelActivated(0), + mChilds(0), + mAutoHideActive(false), + mAutoHideLock(false), + mAutohidePanel(0), + mAutoHidePermanentLock(false), + mAnimationOffset(100), mAlignment(AlignmentLeft), mPosition(ILxQtPanel::PositionBottom) { @@ -137,6 +151,8 @@ LxQtPanel::LxQtPanel(const QString &configGroup, QWidget *parent) : setWindowTitle("LxQt Panel"); setObjectName(QString("LxQtPanel %1").arg(configGroup)); + animationPanel = new VariantAnimation(parent, &mAnimationOffset); + LxQtPanelWidget = new QFrame(this); LxQtPanelWidget->setObjectName("BackgroundWidget"); QGridLayout* lav = new QGridLayout(); @@ -158,6 +174,9 @@ LxQtPanel::LxQtPanel(const QString &configGroup, QWidget *parent) : connect(LxQt::Settings::globalSettings(), SIGNAL(settingsChanged()), this, SLOT(update())); connect(lxqtApp, SIGNAL(themeChanged()), this, SLOT(realign())); + connect(mLayout,SIGNAL(pluginMoving()), this, SLOT(autohidePermanentLock())); + connect(mLayout,SIGNAL(pluginMoved()), this, SLOT(autohidePermanentUnlock())); + LxQtPanelApplication *app = reinterpret_cast(qApp); mSettings = app->settings(); readSettings(); @@ -165,7 +184,19 @@ LxQtPanel::LxQtPanel(const QString &configGroup, QWidget *parent) : ensureVisible(); loadPlugins(); + // panel autohide animation + animationPanel->setStartValue(0); + animationPanel->setEndValue(100); + animationPanel->setEasingCurve(QEasingCurve::OutExpo); //QEasingCurve::OutSine // QEasingCurve::OutInBack // QEasingCurve::OutCirc + animationPanel->setDuration(mAutoHideDuration); + connect (animationPanel,SIGNAL(valueChanged()), this, SLOT(updateOffset())); + + // startup apply show or hide + autohideActive(mAutoHideTb); + show(); + + qApp->installNativeEventFilter(this); } @@ -205,6 +236,9 @@ void LxQtPanel::readSettings() if (!image.isEmpty()) setBackgroundImage(image, false); + // autohide + setAutohide(mSettings->value(CFG_KEY_AUTOHIDE,PANEL_DEFAULT_AUTOHIDE).toBool()); + setAutohideDuration(mSettings->value(CFG_KEY_AUTOHIDEDURATION,PANEL_DEFAULT_AUTOHIDEDURATION).toInt()); mSettings->endGroup(); } @@ -243,6 +277,9 @@ void LxQtPanel::saveSettings(bool later) mSettings->setValue(CFG_KEY_ALIGNMENT, mAlignment); + mSettings->setValue(CFG_KEY_AUTOHIDE, mAutoHideTb); + mSettings->setValue(CFG_KEY_AUTOHIDEDURATION, mAutoHideDuration); + mSettings->setValue(CFG_KEY_FONTCOLOR, mFontColor.isValid() ? mFontColor : QColor()); mSettings->setValue(CFG_KEY_BACKGROUNDCOLOR, mBackgroundColor.isValid() ? mBackgroundColor : QColor()); mSettings->setValue(CFG_KEY_BACKGROUNDIMAGE, QFileInfo(mBackgroundImage).exists() ? mBackgroundImage : QString()); @@ -342,6 +379,7 @@ Plugin *LxQtPanel::loadPlugin(const LxQt::PluginInfo &desktopFile, const QString connect(plugin, SIGNAL(startMove()), mLayout, SLOT(startMovePlugin())); connect(plugin, SIGNAL(remove()), this, SLOT(removePlugin())); connect(this, SIGNAL(realigned()), plugin, SLOT(realign())); + mLayout->addWidget(plugin); return plugin; } @@ -354,6 +392,68 @@ Plugin *LxQtPanel::loadPlugin(const LxQt::PluginInfo &desktopFile, const QString /************************************************ ************************************************/ +void VariantAnimation::updateCurrentValue(const QVariant &value) +{ + if (*currentValue != value.toInt()) + { + *currentValue = value.toInt(); + emit valueChanged(); + } +} + + + +/************************************************ + + ************************************************/ +void LxQtPanel::updateOffset() +{ + const QRect currentScreen = QApplication::desktop()->screenGeometry(mScreenNum); + + int defaultsize; + if (isHorizontal()) + defaultsize = rect.height(); + else + defaultsize = rect.width(); + + if (mAutoHideTb) + mOffset = mAnimationOffset; + else + mOffset = 100; + + // percent to pixels + int mOffsetPixels = (defaultsize * (100 - mOffset)/100); + if (mOffsetPixels >= defaultsize) + mOffsetPixels = defaultsize - 1; + + if (isHorizontal()) + { + // Position Horiz ...................... + if (mPosition == ILxQtPanel::PositionTop) + rect.moveTop(currentScreen.top() - mOffsetPixels); + else + rect.moveBottom(currentScreen.bottom() + mOffsetPixels); + } + else + { + // Position Vert ....................... + if (mPosition == ILxQtPanel::PositionLeft) + rect.moveLeft(currentScreen.left() - mOffsetPixels); + else + rect.moveRight(currentScreen.right() + mOffsetPixels); + } + + if (rect != geometry()) + { + setGeometry(rect); + setFixedSize(rect.size()); + } +} + + +/************************************************ + + ************************************************/ void LxQtPanel::realign() { if (!isVisible()) @@ -371,7 +471,6 @@ void LxQtPanel::realign() const QRect currentScreen = QApplication::desktop()->screenGeometry(mScreenNum); QSize size = sizeHint(); - QRect rect; if (isHorizontal()) { @@ -380,6 +479,7 @@ void LxQtPanel::realign() // Size ....................... rect.setHeight(qMax(PANEL_MINIMUM_SIZE, size.height())); + if (mLengthInPercents) rect.setWidth(currentScreen.width() * mLength / 100.0); else @@ -392,7 +492,7 @@ void LxQtPanel::realign() rect.setWidth(qMax(rect.size().width(), mLayout->minimumSize().width())); - // Horiz ...................... + // Alignment switch (mAlignment) { case LxQtPanel::AlignmentLeft: @@ -407,12 +507,6 @@ void LxQtPanel::realign() rect.moveRight(currentScreen.right()); break; } - - // Vert ....................... - if (mPosition == ILxQtPanel::PositionTop) - rect.moveTop(currentScreen.top()); - else - rect.moveBottom(currentScreen.bottom()); } else { @@ -421,6 +515,7 @@ void LxQtPanel::realign() // Size ....................... rect.setWidth(qMax(PANEL_MINIMUM_SIZE, size.width())); + if (mLengthInPercents) rect.setHeight(currentScreen.height() * mLength / 100.0); else @@ -433,7 +528,7 @@ void LxQtPanel::realign() rect.setHeight(qMax(rect.size().height(), mLayout->minimumSize().height())); - // Vert ....................... + // Alignment switch (mAlignment) { case LxQtPanel::AlignmentLeft: @@ -448,18 +543,37 @@ void LxQtPanel::realign() rect.moveBottom(currentScreen.bottom()); break; } - - // Horiz ...................... - if (mPosition == ILxQtPanel::PositionLeft) - rect.moveLeft(currentScreen.left()); - else - rect.moveRight(currentScreen.right()); } - if (rect != geometry()) + + // autohide + if (mAutoHideTb) { - setGeometry(rect); - setFixedSize(rect.size()); + // panel should hide or not? + if (mAutoHideActive && !mAutoHideLock && !mChilds && !mAutoHidePermanentLock) + { + // switch animation direction if necessary + if (animationPanel->direction() == QAbstractAnimation::Forward) + { + animationPanel->setDirection(QAbstractAnimation::Backward); + if (animationPanel->state() == QAbstractAnimation::Stopped) + animationPanel->start(); + } + } + else + { + // switch animation direction if necessary + if (animationPanel->direction() == QAbstractAnimation::Backward) + { + animationPanel->setDirection(QAbstractAnimation::Forward); + if (animationPanel->state() == QAbstractAnimation::Stopped) + animationPanel->start(); + } + } } + + // for autohide + updateOffset(); + // Reserve our space on the screen .......... // It's possible that our geometry is not changed, but screen resolution is changed, // so resetting WM_STRUT is still needed. To make it simple, we always do it. @@ -482,44 +596,57 @@ void LxQtPanel::updateWmStrut() // So, we use the geometry of the whole screen to calculate the strut rather than using the geometry of individual monitors. // Though the spec only mention Xinerama and did not mention XRandR, the rule should still be applied. // At least openbox is implemented like this. - switch (mPosition) + if (mAutoHideTb) { - case LxQtPanel::PositionTop: - KWindowSystem::setExtendedStrut(wid, - /* Left */ 0, 0, 0, - /* Right */ 0, 0, 0, - /* Top */ height(), rect.left(), rect.right(), - /* Bottom */ 0, 0, 0 - ); - break; - - case LxQtPanel::PositionBottom: - KWindowSystem::setExtendedStrut(wid, - /* Left */ 0, 0, 0, - /* Right */ 0, 0, 0, - /* Top */ 0, 0, 0, - /* Bottom */ wholeScreen.bottom() - rect.y(), rect.left(), rect.right() - ); - break; - - case LxQtPanel::PositionLeft: - KWindowSystem::setExtendedStrut(wid, - /* Left */ width(), rect.top(), rect.bottom(), - /* Right */ 0, 0, 0, - /* Top */ 0, 0, 0, - /* Bottom */ 0, 0, 0 - ); - - break; - - case LxQtPanel::PositionRight: - KWindowSystem::setExtendedStrut(wid, - /* Left */ 0, 0, 0, - /* Right */ wholeScreen.right() - rect.x(), rect.top(), rect.bottom(), - /* Top */ 0, 0, 0, - /* Bottom */ 0, 0, 0 - ); - break; + // No space reserved for a hidden taskbar + KWindowSystem::setExtendedStrut(wid, + /* Left */ 0, 0, 0, + /* Right */ 0, 0, 0, + /* Top */ 0, 0, 0, + /* Bottom */ 0, 0, 0 + ); + } + else + { + switch (mPosition) + { + case LxQtPanel::PositionTop: + KWindowSystem::setExtendedStrut(wid, + /* Left */ 0, 0, 0, + /* Right */ 0, 0, 0, + /* Top */ height(), rect.left(), rect.right(), + /* Bottom */ 0, 0, 0 + ); + break; + + case LxQtPanel::PositionBottom: + KWindowSystem::setExtendedStrut(wid, + /* Left */ 0, 0, 0, + /* Right */ 0, 0, 0, + /* Top */ 0, 0, 0, + /* Bottom */ wholeScreen.bottom() - rect.y(), rect.left(), rect.right() + ); + break; + + case LxQtPanel::PositionLeft: + KWindowSystem::setExtendedStrut(wid, + /* Left */ width(), rect.top(), rect.bottom(), + /* Right */ 0, 0, 0, + /* Top */ 0, 0, 0, + /* Bottom */ 0, 0, 0 + ); + + break; + + case LxQtPanel::PositionRight: + KWindowSystem::setExtendedStrut(wid, + /* Left */ 0, 0, 0, + /* Right */ wholeScreen.right() - rect.x(), rect.top(), rect.bottom(), + /* Top */ 0, 0, 0, + /* Bottom */ 0, 0, 0 + ); + break; + } } } @@ -605,6 +732,11 @@ void LxQtPanel::showAddPluginDialog() dialog->setWindowTitle(tr("Add Panel Widgets")); dialog->setAttribute(Qt::WA_DeleteOnClose); connect(dialog, SIGNAL(pluginSelected(const LxQt::PluginInfo&)), this, SLOT(addPlugin(const LxQt::PluginInfo&))); + + connect(dialog,SIGNAL(destroyed()), this, SLOT(autohidePermanentUnlock())); + + emit autohidePermanentLock(); + connect(this, SIGNAL(pluginAdded(QString)), dialog, SLOT(pluginAdded(const QString &))); connect(this, SIGNAL(pluginRemoved(QString)), dialog, SLOT(pluginRemoved(const QString &))); } @@ -706,6 +838,50 @@ void LxQtPanel::setIconSize(int value, bool save) /************************************************ + * + * *********************************************/ +void LxQtPanel::setAutohide(bool value) +{ + if (mAutoHideTb != value) + { + mAutoHideTb = value; + updateStyleSheet(); + saveSettings(true); + + if (value) + { + mAutoHideActive = true; + mAutoHideLock = false; + mAutoHidePermanentLock = false; + mMapped.clear(); + } + + realign(); + emit realigned(); + } +} + + +/************************************************ + * + * *********************************************/ +void LxQtPanel::setAutohideDuration(int value) +{ + if (mAutoHideDuration != value) + { + mAutoHideDuration = value; + updateStyleSheet(); + saveSettings(true); + + animationPanel->setDuration(mAutoHideDuration); + + realign(); + emit realigned(); + } +} + + +/************************************************ ************************************************/ void LxQtPanel::setLineCount(int value, bool save) @@ -858,6 +1034,192 @@ void LxQtPanel::setOpacity(int opacity, bool save) /************************************************ ************************************************/ +void LxQtPanel::autohideActive(bool value) +{ + if (!mAutoHideTb && !mAutoHideActive) + return; + + mAutoHideActive = value; +} + + +/************************************************ + + ************************************************/ +void LxQtPanel::autohideCheckLock() +{ + if (!mMapped.count() && !mChilds) + autohideUnlock(); + else + autohideLock(); +} + + +/************************************************ + + ************************************************/ +void LxQtPanel::autohideLock() +{ + if (!mAutoHideLock) + { + mAutoHideLock = true; + + realign(); + emit realigned(); + } +} + + +/************************************************ + + ************************************************/ +void LxQtPanel::autohideUnlock() +{ + if (mAutoHideLock) + { + mAutoHideLock = false; + + realign(); + emit realigned(); + } +} + + +/************************************************ +Will permanently lock the autohide function. until autohidePermanentUnlock is called. +Increments mAutoHidePermantenLock. Only if this var is 0 the panel can hide. + ************************************************/ +void LxQtPanel::autohidePermanentLock() +{ + mAutoHidePermanentLock += 1; + + realign(); + emit realigned(); +} + + +/************************************************ + + ************************************************/ +void LxQtPanel::autohidePermanentUnlock() +{ + if (mAutoHidePermanentLock) + mAutoHidePermanentLock -= 1; + + realign(); + emit realigned(); +} + + +/************************************************ + + ************************************************/ +bool LxQtPanel::nativeEventFilter(const QByteArray &eventType, void *message, long *) +{ + + if (!mAutoHideTb) + return false; + + if (eventType != "xcb_generic_event_t") + { + qDebug () << "No XCB Event: " << eventType; + return false; + } + + xcb_generic_event_t* event = static_cast(message); + int event_type = event->response_type & ~0x80; + + switch (event_type) + { + + case XCB_ENTER_NOTIFY: + { + xcb_enter_notify_event_t *enter = (xcb_enter_notify_event_t *)event; + + mAutohidePanel = enter->event; + + // check if this panel was entered + if (effectiveWinId() == enter->event) { + + // This variable is used to indicate that this panel has been hovered (so the initialization is complete) + // because at startup the e.g. ChildAdded event is called multiple times, but this is irrelevant for the autohide function + mPanelActivated = true; + + // disallow panel to hide + autohideActive(false); + + realign(); + emit realigned(); + } + + break; + } + + case XCB_LEAVE_NOTIFY: + { + xcb_leave_notify_event_t *leave = (xcb_leave_notify_event_t *)event; + + if (effectiveWinId() == leave->event) { + + // allow panel to hide + autohideActive(true); + + realign(); + emit realigned(); + } + + break; + } + + case XCB_MAP_NOTIFY: + { + // nativeFilterEvent is called for all panels simultaneously, we want the call only for the panel currently active + // in this case mAutohidePanel is set to the corresponding window-id on EnterEvent + if (mAutohidePanel == effectiveWinId()) + { + + xcb_map_notify_event_t *map = (xcb_map_notify_event_t *)event; + + // add window to mapped list + if (mAutoHideTb) + { + xcb_drawable_t draw = (xcb_drawable_t )map->event; + + xcb_query_tree_cookie_t treeCookie = xcb_query_tree (QX11Info::connection(), draw); + xcb_query_tree_reply_t *tree = xcb_query_tree_reply (QX11Info::connection(), treeCookie, NULL); + + // this check aims for windows opened from within the panel. + // applications that are showing in systray are also causing mapping events, but should not have parent=root window-id. + if (tree->parent == tree->root && mPanelActivated) + mMapped << map->event; + autohideCheckLock(); + } + + } + + break; + } + + case XCB_UNMAP_NOTIFY: + { + + xcb_unmap_notify_event_t *unmap = (xcb_unmap_notify_event_t *)event; + + mMapped -= unmap->event; + autohideCheckLock(); + + break; + } + + } + + return false; +} + + +/************************************************ + + ************************************************/ QRect LxQtPanel::globalGometry() const { return QRect(mapToGlobal(QPoint(0, 0)), this->size()); @@ -865,6 +1227,41 @@ QRect LxQtPanel::globalGometry() const /************************************************ +when a child is added from the panel it shouldn't hide + ************************************************/ +void LxQtPanel::childEvent(QChildEvent *event) +{ + + if (!mAutoHideTb) + return; + + switch (event->type()) + { + case QEvent::ChildAdded: + + if (mPanelActivated) + mChilds += 1; + + autohideCheckLock(); + break; + + case QEvent::ChildRemoved: + + if (mChilds <= 1) + mChilds = 0; + else + mChilds -= 1; + + autohideCheckLock(); + break; + + default: + break; + } +} + + +/************************************************ ************************************************/ bool LxQtPanel::event(QEvent *event) @@ -908,6 +1305,7 @@ bool LxQtPanel::event(QEvent *event) return QFrame::event(event); } + /************************************************ ************************************************/ diff --git a/panel/lxqtpanel.h b/panel/lxqtpanel.h index f1b2123..07ed453 100644 --- a/panel/lxqtpanel.h +++ b/panel/lxqtpanel.h @@ -29,14 +29,23 @@ #ifndef LXQTPANEL_H #define LXQTPANEL_H +#include + #include #include #include + +#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) +#include +#endif + #include "ilxqtpanel.h" #include "lxqtpanelglobals.h" +#include class QMenu; class Plugin; +class VariantAnimation; namespace LxQt { class Settings; @@ -46,7 +55,7 @@ class LxQtPanelLayout; /*! \brief The LxQtPanel class provides a single lxqt-panel. */ -class LXQT_PANEL_API LxQtPanel : public QFrame, public ILxQtPanel +class LXQT_PANEL_API LxQtPanel : public QFrame, public QAbstractNativeEventFilter, public ILxQtPanel { Q_OBJECT @@ -59,6 +68,13 @@ class LXQT_PANEL_API LxQtPanel : public QFrame, public ILxQtPanel AlignmentRight = 1 }; + enum AutohideMsg { + NoMsg = 0, + RemoveWindow = 1, + SaveWindow = 2, + SysTrayConfigure = 3 + }; + LxQtPanel(const QString &configGroup, QWidget *parent = 0); virtual ~LxQtPanel(); @@ -86,6 +102,10 @@ class LXQT_PANEL_API LxQtPanel : public QFrame, public ILxQtPanel int lineCount() const { return mLineCount; } int length() const { return mLength; } bool lengthInPercents() const { return mLengthInPercents; } + + bool autohideTb() const {return mAutoHideTb; } + int autohideDuration() const {return mAutoHideDuration; } + LxQtPanel::Alignment alignment() const { return mAlignment; } int screenNum() const { return mScreenNum; } QColor fontColor() const { return mFontColor; }; @@ -95,10 +115,19 @@ class LXQT_PANEL_API LxQtPanel : public QFrame, public ILxQtPanel LxQt::Settings *settings() const { return mSettings; } + bool nativeEventFilter(const QByteArray &eventType, void *message, long *); + public slots: void show(); // Settings + + // autohide + void setAutohide(bool value); + void setAutohideDuration(int value); + void autohidePermanentLock(); + void autohidePermanentUnlock(); + void setPanelSize(int value, bool save); void setIconSize(int value, bool save); void setLineCount(int value, bool save); @@ -123,16 +152,21 @@ public slots: protected: bool event(QEvent *event); void showEvent(QShowEvent *event); + void childEvent(QChildEvent *event); private slots: void addPlugin(const LxQt::PluginInfo &desktopFile); void showConfigDialog(); void showAddPluginDialog(); void realign(); + void removePlugin(); void pluginMoved(); void userRequestForDeletion(); + //autohide + void updateOffset(); + private: LxQtPanelLayout* mLayout; LxQt::Settings *mSettings; @@ -156,6 +190,25 @@ private slots: int mLength; bool mLengthInPercents; + // autohide + bool mPanelActivated; + bool mChilds; + bool mAutoHideTb; + int mAutoHideDuration; + bool mAutoHideActive; + bool mAutoHideLock; + unsigned long int mAutohidePanel; + int mAutoHidePermanentLock; + void autohideActive(bool value); + void autohideLock (); + void autohideCheckLock (); + void autohideUnlock (); + QSet mMapped; + QRect rect; + int mOffset; + int mAnimationOffset; + VariantAnimation *animationPanel; + Alignment mAlignment; ILxQtPanel::Position mPosition; @@ -171,5 +224,22 @@ private slots: void updateStyleSheet(); }; +class VariantAnimation : public QVariantAnimation +{ + Q_OBJECT + +public: + VariantAnimation(QObject* parent = 0, int* val = 0): + QVariantAnimation(parent) { currentValue = val; } + +private: + int *currentValue; + +signals: + void valueChanged(); + +protected: + virtual void updateCurrentValue(const QVariant& value); +}; #endif // LXQTPANEL_H diff --git a/panel/lxqtpanelapplication.cpp b/panel/lxqtpanelapplication.cpp index 4e0fa14..9a0830d 100644 --- a/panel/lxqtpanelapplication.cpp +++ b/panel/lxqtpanelapplication.cpp @@ -32,6 +32,10 @@ #include #include #include + +//# #include + +//# #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) #include #include @@ -174,6 +178,9 @@ void LxQtPanelApplication::screenDestroyed(QObject* screenObj) qApp->setQuitOnLastWindowClosed(true); } +//#else + + void LxQtPanelApplication::removePanel(LxQtPanel* panel) { Q_ASSERT(mPanels.contains(panel)); diff --git a/panel/lxqtpanelapplication.h b/panel/lxqtpanelapplication.h index 0b5f258..96483e5 100644 --- a/panel/lxqtpanelapplication.h +++ b/panel/lxqtpanelapplication.h @@ -32,6 +32,13 @@ #include #include "ilxqtpanelplugin.h" +// from system tray plugin +#define SYSTEM_TRAY_REQUEST_DOCK 0 + +#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) +#include +#endif + class QScreen; class LxQtPanel; diff --git a/panel/lxqtpanellayout.cpp b/panel/lxqtpanellayout.cpp index 4cabdb1..e98b998 100644 --- a/panel/lxqtpanellayout.cpp +++ b/panel/lxqtpanellayout.cpp @@ -945,6 +945,8 @@ void LxQtPanelLayout::startMovePlugin() PluginMoveProcessor *moveProcessor = new PluginMoveProcessor(this, plugin); moveProcessor->start(); connect(moveProcessor, SIGNAL(finished()), this, SLOT(finishMovePlugin())); + + emit pluginMoving(); } } @@ -960,6 +962,7 @@ void LxQtPanelLayout::finishMovePlugin() Plugin *plugin = moveProcessor->plugin(); int n = indexOf(plugin); plugin->setAlignment(ncount() ? Plugin::AlignLeft : Plugin::AlignRight); - emit pluginMoved(); } + + emit pluginMoved(); } diff --git a/panel/lxqtpanellayout.h b/panel/lxqtpanellayout.h index e3b950b..5fbc11f 100644 --- a/panel/lxqtpanellayout.h +++ b/panel/lxqtpanellayout.h @@ -74,8 +74,10 @@ class LXQT_PANEL_API LxQtPanelLayout : public QLayout void setPosition(ILxQtPanel::Position value); static bool itemIsSeparate(QLayoutItem *item); + signals: void pluginMoved(); + void pluginMoving(); public slots: void startMovePlugin(); diff --git a/panel/lxqtpanellimits.h b/panel/lxqtpanellimits.h index ffc7dea..935f66b 100644 --- a/panel/lxqtpanellimits.h +++ b/panel/lxqtpanellimits.h @@ -35,6 +35,9 @@ #define PANEL_DEFAULT_ICON_SIZE 22 #define PANEL_DEFAULT_LINE_COUNT 1 +#define PANEL_DEFAULT_AUTOHIDE 0 +#define PANEL_DEFAULT_AUTOHIDEDURATION 300 + #define PANEL_DEFAULT_BACKGROUND_COLOR "#CCCCCC" #define SETTINGS_SAVE_DELAY 3000 diff --git a/panel/plugin.cpp b/panel/plugin.cpp index e0504e6..67616b5 100644 --- a/panel/plugin.cpp +++ b/panel/plugin.cpp @@ -367,11 +367,13 @@ void Plugin::showConfigureDialog() dialog = mPlugin->configureDialog(); refs[name()] = dialog; connect(this, SIGNAL(destroyed()), dialog, SLOT(close())); + connect(dialog, SIGNAL(destroyed()), mPanel,SLOT(autohidePermanentUnlock())); } if (!dialog) return; + emit autoHidePermanentLock(); dialog->show(); dialog->raise(); dialog->activateWindow(); diff --git a/panel/plugin.h b/panel/plugin.h index ca47c1f..1f168cb 100644 --- a/panel/plugin.h +++ b/panel/plugin.h @@ -88,6 +88,8 @@ public slots: signals: void startMove(); void remove(); + void autoHidePermanentLock(); + void autoHidePermanentUnlock(); protected: void contextMenuEvent(QContextMenuEvent *event); diff --git a/plugin-mount/lxqtmountplugin.cpp b/plugin-mount/lxqtmountplugin.cpp index 379ed03..77c78b2 100644 --- a/plugin-mount/lxqtmountplugin.cpp +++ b/plugin-mount/lxqtmountplugin.cpp @@ -60,13 +60,6 @@ QWidget *LxQtMountPlugin::widget() } -void LxQtMountPlugin::realign() -{ - if(mPopup) - mPopup->hide(); -} - - QDialog *LxQtMountPlugin::configureDialog() { if(mPopup) diff --git a/plugin-mount/lxqtmountplugin.h b/plugin-mount/lxqtmountplugin.h index a2e66b5..eeef267 100644 --- a/plugin-mount/lxqtmountplugin.h +++ b/plugin-mount/lxqtmountplugin.h @@ -55,7 +55,6 @@ class LxQtMountPlugin : public QObject, public ILxQtPanelPlugin virtual QWidget *widget(); virtual QString themeId() const { return "LxQtMount"; } virtual ILxQtPanelPlugin::Flags flags() const { return PreferRightAlignment | HaveConfigDialog ; } - void realign(); QDialog *configureDialog(); LxQt::MountManager *mountManager() const { return mMountManager; } diff --git a/plugin-volume/lxqtvolume.cpp b/plugin-volume/lxqtvolume.cpp index 6dd2977..0f9ee2d 100644 --- a/plugin-volume/lxqtvolume.cpp +++ b/plugin-volume/lxqtvolume.cpp @@ -226,10 +226,6 @@ QWidget *LxQtVolume::widget() return m_volumeButton; } -void LxQtVolume::realign() -{ -} - QDialog *LxQtVolume::configureDialog() { if(!m_configDialog) diff --git a/plugin-volume/lxqtvolume.h b/plugin-volume/lxqtvolume.h index b72fe3f..e9d159e 100644 --- a/plugin-volume/lxqtvolume.h +++ b/plugin-volume/lxqtvolume.h @@ -56,7 +56,6 @@ class LxQtVolume : public QObject, public ILxQtPanelPlugin virtual QWidget *widget(); virtual QString themeId() const { return "Volume"; } virtual ILxQtPanelPlugin::Flags flags() const { return PreferRightAlignment | HaveConfigDialog ; } - void realign(); QDialog *configureDialog(); void setAudioEngine(AudioEngine *engine);