Comments (15)
Right, the animation. If we want the animation then having Filer involved in rendering the shadow is a bad idea. We need to find a way for Menu to render the shadow itself. Most likely by using a "dummy window" (m_fakeWidget
) which is "behind" the real Menu window.
The m_fakeWidget
"dummy window" - how can we get it "behind" the real menu bar?
/*
* Copyright (C) 2020 PandaOS Team.
*
* Author: rekols <[email protected]>
* Portions: probono <[email protected]>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "mainwindow.h"
#include <QApplication>
#include <QHBoxLayout>
#include <QScreen>
#include <QPainter>
#include <QPainterPath>
#include <QDebug>
#include <QApplication>
#include <QLibraryInfo>
#include <KF5/KWindowSystem/KWindowSystem>
#include <QX11Info>
#include <QScreen>
#include <xcb/xcb.h>
#include <X11/Xlib.h>
MainWindow::MainWindow(QWidget *parent)
: QFrame(parent),
m_fakeWidget(new QWidget(nullptr)),
m_mainPanel(new MainPanel)
{
this->setObjectName("menuBar");
// Install the translations built-into Qt itself
qtTranslator.load("qt_" + QLocale::system().name(), QLibraryInfo::location(QLibraryInfo::TranslationsPath));
qApp->installTranslator(&qtTranslator);
// Install our own translations
translator1.load("menubar_" + QLocale::system().name(), QCoreApplication::applicationDirPath() + QString("/../share/menubar/translations/")); // probono: FHS-like path relative to main binary
qApp->installTranslator(&translator1);
translator2.load("menubar_" + QLocale::system().name(), QCoreApplication::applicationDirPath()); // probono: When qm files are next to the executable ("uninstalled"), useful during development
qApp->installTranslator(&translator2);
QHBoxLayout *layout = new QHBoxLayout;
layout->addSpacing(10);
layout->addWidget(m_mainPanel);
layout->addSpacing(10);
layout->setMargin(0);
layout->setSpacing(0);
setLayout(layout);
// m_fakeWidget->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowDoesNotAcceptFocus | Qt::SplashScreen);
m_fakeWidget->setWindowFlags(Qt::WindowDoesNotAcceptFocus);
// m_fakeWidget->setAttribute(Qt::WA_TranslucentBackground);
// Prevent menubar from becoming faded/translucent if we use a compositing manager
// that fades/makes translucent inactive windows
m_mainPanel->setWindowFlags(Qt::WindowDoesNotAcceptFocus);
setAttribute(Qt::WA_NoSystemBackground, false);
// setAttribute(Qt::WA_TranslucentBackground);
setWindowFlags(Qt::FramelessWindowHint);
KWindowSystem::setOnDesktop(effectiveWinId(), NET::OnAllDesktops);
// "Indicates a toplevel menu (AKA macmenu).
// This is a KDE extension to the _NET_WM_WINDOW_TYPE mechanism."
// Source:
// https://api.kde.org/frameworks/kwindowsystem/html/classNET.html#a4b3115c0f40e7bc8e38119cc44dd60e0
// Can be inspected with: xwininfo -wm, it contains "Window type: Kde Net Wm Window Type Topmenu"
// This should allow e.g., picom to set different settings regarding shadows and transparency
KWindowSystem::setType(winId(), NET::TopMenu);
//TODO:
//Call this when the user sets the primary display via xrandr
initSize();
//subscribe to changes on our display like if we change the screen resolution, orientation etc..
connect(qApp->primaryScreen(), &QScreen::geometryChanged, this, &MainWindow::initSize);
connect(qApp->primaryScreen(), &QScreen::orientationChanged, this, &MainWindow::initSize);
connect(qApp->primaryScreen(), &QScreen::virtualGeometryChanged, this, &MainWindow::initSize);
connect(qApp->primaryScreen(), &QScreen::availableGeometryChanged, this, &MainWindow::initSize);
connect(qApp->primaryScreen(), &QScreen::logicalDotsPerInchChanged, this, &MainWindow::initSize);
connect(qApp->primaryScreen(), &QScreen::physicalDotsPerInchChanged, this, &MainWindow::initSize);
connect(qApp->primaryScreen(), &QScreen::physicalSizeChanged, this, &MainWindow::initSize);
connect(qApp->primaryScreen(), &QScreen::primaryOrientationChanged, this, &MainWindow::initSize);
// Appear with an animation
QPropertyAnimation *animation = new QPropertyAnimation(this, "pos");
animation->setDuration(1500);
animation->setStartValue(QPoint(qApp->primaryScreen()->geometry().x(), -2 * qApp->primaryScreen()->geometry().height()));
animation->setEndValue(QPoint(qApp->primaryScreen()->geometry().x(),qApp->primaryScreen()->geometry().y()));
animation->setEasingCurve(QEasingCurve::OutCubic);
animation->start(QPropertyAnimation::DeleteWhenStopped);
this->activateWindow(); // probono: Ensure that we have the focus when menu is launched so that one can enter text in the search box
m_mainPanel->raise(); // probono: Trying to give typing focus to the search box that is in there. Needed? Does not seem tp hurt
}
MainWindow::~MainWindow()
{
}
void MainWindow::paintEvent(QPaintEvent *e)
{
// probono: Draw black rounded corners on the top edges
QPainter p(this);
p.setRenderHint(QPainter::Antialiasing);
p.setPen(Qt::NoPen);
int round_pixels = 5; // like /usr/local/etc/xdg/picom.conf // probono: Make this relative to the height of the MainWindow?
// QPainterPath::subtracted() takes InnerPath and subtracts it from OuterPath to produce the final shape
QPainterPath OuterPath;
OuterPath.addRect(0, 0, qApp->primaryScreen()->geometry().width(), 2*round_pixels);
QPainterPath InnerPath;
InnerPath.addRoundedRect(QRect(0, 0, qApp->primaryScreen()->geometry().width(), 4*round_pixels), round_pixels, round_pixels);
QPainterPath FillPath;
FillPath = OuterPath.subtracted(InnerPath);
p.fillPath(FillPath, Qt::black);
// Draw the other widgets
QWidget::paintEvent(e);
}
void MainWindow::initSize()
{
QRect primaryRect = qApp->primaryScreen()->geometry();
setFixedWidth(primaryRect.width());
// probono: Construct a populated(!) QMenuBar so that we can determine
// its height and use the same height for the MainWindow. Is there a better way?
QMenuBar *dummyMenuBar = new QMenuBar;
dummyMenuBar->setContentsMargins(0, 0, 0, 0);
dummyMenuBar->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding);
QMenu *dummyMenu = new QMenu;
dummyMenuBar->addMenu(dummyMenu);
qDebug() << "probono: dummyMenu->sizeHint().height():" << dummyMenu->sizeHint().height();
setFixedHeight(dummyMenuBar->sizeHint().height());
//move this to the active screen and xrandr position
move(qApp->primaryScreen()->geometry().x(), qApp->primaryScreen()->geometry().y());
setStrutPartial();
KWindowSystem::setState(winId(), NET::SkipTaskbar); // Do not show in Dock
KWindowSystem::setState(winId(), NET::StaysOnTop);
KWindowSystem::setState(winId(), NET::SkipPager);
KWindowSystem::setState(winId(), NET::SkipSwitcher);
// How can we set _NET_WM_STATE_ABOVE? KDE krunner has it set
// https://stackoverflow.com/a/27964691
// "window should be of type _NET_WM_TYPE_DOCK and you must first map it then move it
// to position, otherwise the WM may sometimes place it outside of it own strut."
// _NET_WM_WINDOW_TYPE_DOCK
KWindowSystem::setType(winId(), NET::Dock);
// probono: Set background gradient
// Commenting this out because possibly this interferes with theming via a QSS file via QtPlugin?
// this->setStyleSheet( "MainWindow { background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #fff, stop: 0.1 #eee, stop: 0.39 #eee, stop: 0.4 #ddd, stop: 1 #eee); }");
}
void MainWindow::setStrutPartial()
{
//不清真的作法,kwin设置blur后设置程序支撑导致模糊无效
//TRANSLATED Unclear practice, setting program support after kwin set blur causes blur invalid
QRect r(geometry());
m_fakeWidget->setFixedHeight(this->height());
m_fakeWidget->setFixedWidth(this->width());
m_fakeWidget->move(10,10);
// m_fakeWidget->setGeometry(r);
m_fakeWidget->setVisible(true);
const QRect windowRect = this->rect();
NETExtendedStrut strut;
strut.top_width = height(); // + 1; // 1 pixel between menu bar and maximized window not needed if we have a shadow
strut.top_start = x();
strut.top_end = x() + width();
KWindowSystem::setExtendedStrut(m_fakeWidget->winId(),
strut.left_width,
strut.left_start,
strut.left_end,
strut.right_width,
strut.right_start,
strut.right_end,
strut.top_width,
strut.top_start,
strut.top_end,
strut.bottom_width,
strut.bottom_start,
strut.bottom_end);
}
from filer.
I think you only need to split the Menu Bar and Options menu. This should solve the problem.
from filer.
Thinking a bit more about it, Filer could probably render the shadow as part of when it renders the wallpaper.
from filer.
Can you let Filter render the wallpaper to temporarily hide the menu bar while rendering the shadow, and then move the Menu bar from top to bottom with special effects?
from filer.
Just like this, it can temporarily hide the problem when the Menu bar renders the shadow.
https://user-images.githubusercontent.com/44593430/136714815-940a0114-5a6e-49fb-a6b2-d5148966a7c2.mp4
from filer.
It should be "forced to be ranked first" like a right-click menu or a sticky note.
On the Menubar Menu.
from filer.
So would always on top be better or does kwin do that with _NET_WM_DOCK?
from filer.
The real menu is always on top. But we don't want the shadow to be rendered by that window, otherwise it would be rendered over windows that are close to the menu. Hence, we want another (dummy) window behind the real window, and that should always be at the bottom and have the shadow.
from filer.
If the shadow is a transparent gradient image under the window layer instead of being generated by drawing, I think this will save the memory usage of global menu shadow generation.
But pay attention to this tip about drawing.
from filer.
The solution is quite simple if you think about it.
Let the code that draws the desktop also draw the shadow for the menu.
Since per the Human Interface Guidelines the menu must never go away (except for an application being in fullscreen, in which case you won't see the desktop), this is a perfectly acceptable solution.
Code along the lines of (not quite working yet but you should get the idea):
#include <QGraphicsEffect>
QRect shadowRect(QPoint(0, 22), QSize(1600, 10)); // TODO: Screen width instead of 1600
QLinearGradient alphaGradient(shadowRect.topLeft(), shadowRect.bottomLeft());
alphaGradient.setColorAt(0.0, Qt::black);
alphaGradient.setColorAt(1.0, Qt::transparent);
QGraphicsOpacityEffect *effect = new QGraphicsOpacityEffect;
effect->setOpacityMask(alphaGradient);
painter->fillRect(menuRect, effect);
But where to put it in?
desktopitemdelegate.cpp
has a ::paint
method where we can put it in, desktopwindow.cpp
hasn't.
The following is obviously not the correct way to do it but it is a working except for color gradients instead of transparency gradients being used.
void DesktopItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const {
Q_ASSERT(index.isValid());
QStyleOptionViewItem opt = option;
initStyleOption(&opt, index);
QPen origPen = painter->pen();
QRect menuRect(QPoint(0, 22), QSize(1600, 10));
QLinearGradient m_gradient(0,22,0,32);
m_gradient.setColorAt(0.0, Qt::darkGray);
m_gradient.setColorAt(1.0, Qt::white);
painter->fillRect(menuRect, m_gradient);
painter->setPen(origPen);
painter->save();
painter->setClipRect(option.rect);
Who knows enough about Qt to help get it done?
from filer.
Now using the proper transparency gradient. Actually easy, just define a QColor with R, G, B, Alpha.
Adding the following to desktopwindow.cpp
:
void DesktopWindow::paintEvent(QPaintEvent *)
{
// This gets drawn but BEHIND the wallpaper. FIXME: Draw above wallpaper
qDebug() << Q_FUNC_INFO;
QPainter painter(this);
QPen origPen = painter.pen();
QRect menuRect(QPoint(0, 22), QSize(1600, 30));
QLinearGradient m_gradient(0,22,0,52);
m_gradient.setColorAt(0.0, QColor(128, 128, 128, 255));
m_gradient.setColorAt(1.0, QColor(128, 128, 128, 0));
painter.fillRect(menuRect, m_gradient);
painter.setPen(origPen);
painter.save();
}
The object gets drawn, but behind the wallpaper. Hence it is only visible if the wallpaper is set to transparent.
We need to do this differently.
Maybe draw at the end of DesktopWindow::updateWallpaper()
? Doesnt seem to work...
Same if I put it into void FolderView::paintEvent(QPaintEvent *)
of folderview.cpp
.
from filer.
Maybe we need to create a pixmap that contains the wallpaper and the shadow, and use the combined pixmap instead of just the wallpaper image.
from filer.
As a temporary workaround, using a wallpaper image that has the shadow "built in":
https://github.com/helloSystem/ISO/releases/download/assets/graphite_shadow.jpg
Kinda crude but effective.
Let's not forget to undo that workaround once we found a proper solution for drawing the shadow using Qt.
from filer.
This is it:
QPen origPen = painter->pen();
QRect shadowRect(QPoint(0, 0), QSize(1600, 33));
QLinearGradient linearGradient(0,0,0,33);
linearGradient.setColorAt(0.00, QColor::fromRgbF(0, 0, 0, 0.3));
linearGradient.setColorAt(0.33, QColor::fromRgbF(0, 0, 0, 0.2));
linearGradient.setColorAt(1.00, QColor::fromRgbF(0, 0, 0, 0.0));
painter->fillRect(shadowRect, linearGradient);
painter->setPen(origPen);
painter->save();
painter->setClipRect(option.rect);
The only remaining question: Where to put this.
from filer.
@probonopd I recently found how to solve the problem of shadow coverage, Ubuntu Unity also has this problem, but it is well adjusted, that is, to reduce the spread of Kwin shadows.
This also reduces system power consumption in window shadow generation.
from filer.
Related Issues (20)
- Dragging a document onto the white area of an opened folder window crashes HOT 10
- The file filer on the LiveCD does not show the hard disk where hello os is installed
- Right-click menu customization options
- Global Menu should receive keyboard command combinations even if a file browser window is the focused window.
- Wayland does not support QWindow::requestActivate()
- plasmashell Global Menu 2.0 does not show the menu for the desktop
- The name of the hard disk is displayed incorrectly on the desktop HOT 1
- Add play feature for audio and video HOT 4
- Hinged folders
- Recursive calculation of folder sizes
- The selection of text is too wide but the selection of icons is normal
- Desplay-preference "Wallpaper mode and image file position" needs to be swapped HOT 1
- The specified location for moving files to the desktop is wrong HOT 1
- The desktop should not scroll when dragging the Icon HOT 1
- The media remains on after the media is removed HOT 1
- Right-clicking still displays the Paste option even if there is no copy.
- Media (Go Computer) folder does not display Hello system hard drive
- Go Computer Link Inconsistent
- Malicious Ukrainian translations HOT 5
- File names that are not in English cannot be opened.
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from filer.