diff --git a/AppMenu.cxx b/AppMenu.cxx
index cf1fe29..397cfca 100644
--- a/AppMenu.cxx
+++ b/AppMenu.cxx
@@ -1,195 +1,196 @@
// SPDX-License-Identifier: GPL-3.0-or-later
/*
- Copyright 2017 Martin Koller, kollix@aon.at
+ Copyright 2017 - 2019 Martin Koller, kollix@aon.at
This file is part of liquidshell.
liquidshell 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
(at your option) any later version.
liquidshell 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 liquidshell. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include
-#include
+#include
#include
#include
#include
#include
#include
//--------------------------------------------------------------------------------
AppMenu::AppMenu(DesktopPanel *parent)
: Launcher(parent, "AppMenu")
{
button = new QToolButton; // QToolButton is smaller than QPushButton
adjustIconSize();
button->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
popup = new Menu(button);
connect(button, &QToolButton::pressed, this, &AppMenu::showMenu);
layout()->addWidget(button);
loadConfig(QStandardPaths::writableLocation(QStandardPaths::DesktopLocation));
connect(parent, &DesktopPanel::rowsChanged, this, &AppMenu::adjustIconSize);
connect(KIconLoader::global(), &KIconLoader::iconLoaderSettingsChanged, this, &AppMenu::adjustIconSize);
connect(KIconLoader::global(), &KIconLoader::iconLoaderSettingsChanged, this, &AppMenu::fill);
- connect(QApplication::desktop(), &QDesktopWidget::resized, this, &AppMenu::fill);
+ connect(QApplication::primaryScreen(), &QScreen::geometryChanged, this, &AppMenu::fill);
+ connect(qApp, &QApplication::primaryScreenChanged, this, &AppMenu::fill);
}
//--------------------------------------------------------------------------------
void AppMenu::adjustIconSize()
{
const int MAX_ROWS = qobject_cast(parentWidget())->getRows();
if ( MAX_ROWS > 1 )
button->setIconSize(QSize(48, 48));
else
{
int size = KIconLoader::global()->currentSize(KIconLoader::Panel);
button->setIconSize(QSize(size, size));
}
}
//--------------------------------------------------------------------------------
void AppMenu::fill()
{
KDesktopFile desktopFile(dirPath + "/.directory");
if ( !desktopFile.readIcon().isEmpty() )
button->setIcon(QIcon::fromTheme(desktopFile.readIcon()));
else if ( dirPath == QStandardPaths::writableLocation(QStandardPaths::DesktopLocation) )
button->setIcon(QIcon::fromTheme("user-desktop"));
else // fallback
button->setIcon(QIcon::fromTheme("folder"));
QLayoutItem *child;
while ( (child = popup->layout()->takeAt(0)) )
{
delete child->widget();
delete child;
}
QDir dir(dirPath);
QFileInfoList entries = dir.entryInfoList(QDir::AllEntries | QDir::NoDotDot);
int row = 0, col = 0, h = 0;
- const int maxHeight = QApplication::desktop()->height() - parentWidget()->sizeHint().height();
+ const int maxHeight = QApplication::primaryScreen()->size().height() - parentWidget()->sizeHint().height();
for (const QFileInfo &info : entries)
{
QUrl url(QUrl::fromLocalFile(info.absoluteFilePath()));
QString name;
QIcon icon;
KFileItem item(url);
if ( item.isDesktopFile() )
{
KDesktopFile desktopFile(info.absoluteFilePath());
if ( desktopFile.noDisplay() )
continue;
name = desktopFile.readName();
if ( name.isEmpty() )
name = desktopFile.readGenericName();
QString iconName = desktopFile.readIcon();
icon = QIcon::fromTheme(iconName.isEmpty() ? name : iconName);
}
else if ( info.isDir() )
{
if ( info.fileName() == "." )
{
name = info.dir().dirName();
icon = button->icon();
}
else
icon = QIcon::fromTheme("folder");
}
else
{
QMimeDatabase db;
icon = QIcon::fromTheme(db.mimeTypeForFile(info.absoluteFilePath()).iconName());
}
if ( name.isEmpty() )
name = info.fileName();
IconButton *entryButton = new IconButton(this, icon, 32, name);
connect(entryButton, &IconButton::clicked, [this, url]() { popup->close(); new KRun(url, nullptr); });
h += entryButton->sizeHint().height();
if ( h >= maxHeight )
{
h = entryButton->sizeHint().height();
col++;
row = 0;
}
static_cast(popup->layout())->addWidget(entryButton, row++, col);
}
}
//--------------------------------------------------------------------------------
void AppMenu::showMenu()
{
popup->exec();
button->setDown(false);
}
//--------------------------------------------------------------------------------
//--------------------------------------------------------------------------------
//--------------------------------------------------------------------------------
Menu::Menu(QWidget *parent)
: QMenu(parent)
{
QGridLayout *grid = new QGridLayout(this);
grid->setContentsMargins(QMargins());
grid->setSpacing(0);
}
//--------------------------------------------------------------------------------
void Menu::hideEvent(QHideEvent *event)
{
Q_UNUSED(event);
eventLoop.exit();
}
//--------------------------------------------------------------------------------
void Menu::exec()
{
adjustSize();
QPoint p = parentWidget()->mapToGlobal(QPoint(0, 0));
move(p.x(), p.y() - height());
show();
eventLoop.exec();
}
//--------------------------------------------------------------------------------
diff --git a/ClockWidget.cxx b/ClockWidget.cxx
index 9b3ad96..a1e5c27 100644
--- a/ClockWidget.cxx
+++ b/ClockWidget.cxx
@@ -1,248 +1,248 @@
// SPDX-License-Identifier: GPL-3.0-or-later
/*
- Copyright 2017,2018 Martin Koller, kollix@aon.at
+ Copyright 2017 - 2019 Martin Koller, kollix@aon.at
This file is part of liquidshell.
liquidshell 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
(at your option) any later version.
liquidshell 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 liquidshell. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include
-#include
+#include
#include
#include
#include
#include
#include
#include
#include
#include
//--------------------------------------------------------------------------------
CalendarPopup::CalendarPopup(QWidget *parent)
: QFrame(parent)
{
setWindowFlags(windowFlags() | Qt::Popup);
setFrameShape(QFrame::StyledPanel);
QVBoxLayout *vbox = new QVBoxLayout(this);
vbox->setContentsMargins(QMargins());
cal = new QCalendarWidget;
vbox->addWidget(cal);
QPushButton *today = new QPushButton(QIcon::fromTheme("go-jump-today"), QString());
vbox->addWidget(today);
connect(today, &QPushButton::clicked, this, &CalendarPopup::goToday);
}
//--------------------------------------------------------------------------------
void CalendarPopup::goToday()
{
cal->showToday();
cal->setSelectedDate(QDate::currentDate());
}
//--------------------------------------------------------------------------------
//--------------------------------------------------------------------------------
//--------------------------------------------------------------------------------
ClockWidget::ClockWidget(DesktopPanel *parent)
: QFrame(parent), calendar(nullptr)
{
ensurePolished(); // make sure we already have the css applied
timer = new QTimer(this);
// if seconds are shown, update every second, else less often
if ( timeFormat.contains('s') )
timer->setInterval(1000);
else
timer->setInterval(5000);
timer->start();
connect(timer, &QTimer::timeout, this, &ClockWidget::tick);
connect(parent, &DesktopPanel::rowsChanged, this, &ClockWidget::fill);
timeLabel = new QLabel(this);
dayLabel = new QLabel(this);
dateLabel = new QLabel(this);
timeLabel->setObjectName("time");
dayLabel->setObjectName("day");
dateLabel->setObjectName("date");
timeLabel->setTextFormat(Qt::PlainText);
dayLabel->setTextFormat(Qt::PlainText);
dateLabel->setTextFormat(Qt::PlainText);
timeLabel->setAlignment(Qt::AlignCenter);
dayLabel->setAlignment(Qt::AlignCenter);
dateLabel->setAlignment(Qt::AlignCenter);
QFont f = font();
f.setPointSizeF(fontInfo().pointSizeF() * 1.5);
f.setBold(true);
timeLabel->setFont(f);
fill();
timeLabel->setVisible(!timeFormat.isEmpty());
dayLabel->setVisible(!dayFormat.isEmpty());
dateLabel->setVisible(!dateFormat.isEmpty());
// context menu
QAction *action = new QAction(this);
action->setIcon(QIcon::fromTheme("configure"));
action->setText(i18n("Select Timezones..."));
addAction(action);
connect(action, &QAction::triggered,
[this]()
{
ClockWidgetConfigureDialog dialog(parentWidget(), timeZoneIds);
dialog.setWindowTitle(i18n("Select Timezones"));
dialog.resize(600, 400);
if ( dialog.exec() == QDialog::Accepted )
{
timeZoneIds = dialog.getSelectedTimeZoneIds();
KConfig config;
KConfigGroup group = config.group("ClockWidget");
QStringList list;
for (const QByteArray &id : timeZoneIds)
list.append(id);
group.writeEntry("timeZoneIds", list);
tick(); // update tooltip
}
}
);
action = new QAction(this);
action->setIcon(QIcon::fromTheme("preferences-system-time"));
action->setText(i18n("Configure Date & Time..."));
addAction(action);
connect(action, &QAction::triggered,
[this]()
{
auto dialog = new KCMultiDialog(parentWidget());
dialog->setAttribute(Qt::WA_DeleteOnClose);
dialog->setWindowTitle(i18n("Date & Time"));
dialog->addModule("clock");
dialog->adjustSize();
dialog->show();
}
);
setContextMenuPolicy(Qt::ActionsContextMenu);
// load config
KConfig config;
KConfigGroup group = config.group("ClockWidget");
QStringList list;
list = group.readEntry("timeZoneIds", QStringList());
for (const QString &id : list)
timeZoneIds.append(id.toLatin1());
tick();
timeLabel->setFixedHeight(timeLabel->fontMetrics().tightBoundingRect(timeLabel->text()).height() + 2);
dayLabel->setFixedHeight(dayLabel->fontMetrics().tightBoundingRect(dayLabel->text()).height() + 4);
dateLabel->setFixedHeight(dateLabel->fontMetrics().tightBoundingRect(dateLabel->text()).height() + 4);
}
//--------------------------------------------------------------------------------
void ClockWidget::fill()
{
delete layout();
const int MAX_ROWS = qobject_cast(parentWidget())->getRows();
QBoxLayout *box;
if ( MAX_ROWS >= 2 )
{
box = new QVBoxLayout(this);
box->setSpacing(0);
}
else
{
box = new QHBoxLayout(this);
}
box->setContentsMargins(QMargins());
box->addWidget(timeLabel);
box->addWidget(dayLabel);
box->addWidget(dateLabel);
}
//--------------------------------------------------------------------------------
void ClockWidget::tick()
{
QDateTime dateTimeUtc = QDateTime::currentDateTimeUtc();
QDateTime dateTime = dateTimeUtc.toLocalTime();
timeLabel->setText(dateTime.time().toString(timeFormat));
dayLabel->setText(dateTime.date().toString(dayFormat));
dateLabel->setText(dateTime.date().toString(dateFormat));
if ( !timeZoneIds.isEmpty() )
{
QString tip = "";
for (const QByteArray &id : timeZoneIds)
{
QTimeZone timeZone(id);
QDateTime dt = dateTimeUtc;
dateTime = dt.toTimeZone(timeZone);
tip += QString("%1 | %2 | %3 | %4 |
")
.arg(QLatin1String(id))
.arg(dateTime.time().toString(timeFormat))
.arg(dateTime.date().toString(dayFormat))
.arg(dateTime.date().toString(dateFormat));
}
tip += "
";
setToolTip(tip);
}
}
//--------------------------------------------------------------------------------
void ClockWidget::mousePressEvent(QMouseEvent *event)
{
if ( event->button() == Qt::LeftButton )
{
if ( !calendar )
calendar = new CalendarPopup(this);
calendar->goToday();
QPoint point = mapToGlobal(pos());
- QRect screen = QApplication::desktop()->availableGeometry(this);
+ QRect screen = QApplication::primaryScreen()->availableGeometry();
point.setX(std::min(point.x(), screen.x() + screen.width() - calendar->sizeHint().width()));
point.setY(point.y() - calendar->sizeHint().height());
calendar->move(point);
calendar->show();
}
}
//--------------------------------------------------------------------------------
diff --git a/ConfigureDesktopDialog.cxx b/ConfigureDesktopDialog.cxx
index 7924dfe..fca1603 100644
--- a/ConfigureDesktopDialog.cxx
+++ b/ConfigureDesktopDialog.cxx
@@ -1,178 +1,178 @@
// SPDX-License-Identifier: GPL-3.0-or-later
/*
- Copyright 2017 Martin Koller, kollix@aon.at
+ Copyright 2017 - 2019 Martin Koller, kollix@aon.at
This file is part of liquidshell.
liquidshell 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
(at your option) any later version.
liquidshell 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 liquidshell. If not, see .
*/
#include
#include
#include
#include
#include
-#include
+#include
#include
#include
//--------------------------------------------------------------------------------
ConfigureDesktopDialog::ConfigureDesktopDialog(QWidget *parent, const DesktopWidget::Wallpaper &wp)
: QDialog(parent), wallpaper(wp)
{
ui.setupUi(this);
ui.iconView->setIconSize(QSize(200, 200));
connect(ui.iconView, &QListWidget::itemClicked,
[this](QListWidgetItem *item)
{
ui.kurlrequester->setUrl(QUrl::fromLocalFile(item->data(Qt::UserRole).toString()));
wallpaper.fileName = ui.kurlrequester->url().toLocalFile();
emit changed();
});
showImages();
QPushButton *newstuff = ui.buttonBox->addButton(i18n("Get New Wallpapers..."), QDialogButtonBox::ActionRole);
newstuff->setIcon(QIcon::fromTheme("get-hot-new-stuff"));
connect(newstuff, &QPushButton::clicked,
[this]()
{
KNS3::DownloadDialog dialog("wallpaper.knsrc", this);
dialog.setTitle(i18n("Download Wallpapers"));
dialog.exec();
if ( dialog.changedEntries().count() )
showImages();
});
ui.kcolorcombo->setColor(wallpaper.color);
ui.kurlrequester->setUrl(QUrl::fromLocalFile(wallpaper.fileName));
connect(ui.kcolorcombo, &KColorCombo::activated,
[this](const QColor &col) { wallpaper.color = col; emit changed(); });
connect(ui.kurlrequester, &KUrlRequester::urlSelected,
[this](const QUrl &url) { wallpaper.fileName = url.toLocalFile(); emit changed(); });
// older compiler can't use this
//connect(ui.kurlrequester, QOverload::of(&KUrlRequester::returnPressed),
// [this](const QString &text) { wallpaper.fileName = text; emit changed(); });
connect(ui.kurlrequester, SIGNAL(returnPressed(QString)), this, SLOT(returnPressed(QString)));
if ( wallpaper.mode == "Scaled" )
ui.scaledIgnoreRatioButton->setChecked(true);
else if ( wallpaper.mode == "ScaledKeepRatio" )
ui.scaledKeepRatioButton->setChecked(true);
else if ( wallpaper.mode == "ScaledKeepRatioExpand" )
ui.scaledKeepRatioClipButton->setChecked(true);
else
ui.origSizeButton->setChecked(true);
buttonGroup.addButton(ui.origSizeButton);
buttonGroup.addButton(ui.scaledIgnoreRatioButton);
buttonGroup.addButton(ui.scaledKeepRatioButton);
buttonGroup.addButton(ui.scaledKeepRatioClipButton);
connect(&buttonGroup, SIGNAL(buttonClicked(QAbstractButton *)),
this, SLOT(buttonClicked(QAbstractButton *)));
}
//--------------------------------------------------------------------------------
void ConfigureDesktopDialog::returnPressed(const QString &text)
{
wallpaper.fileName = text;
emit changed();
}
//--------------------------------------------------------------------------------
void ConfigureDesktopDialog::buttonClicked(QAbstractButton *button)
{
if ( button == ui.origSizeButton )
wallpaper.mode = "";
else if ( button == ui.scaledIgnoreRatioButton )
wallpaper.mode = "Scaled";
else if ( button == ui.scaledKeepRatioButton )
wallpaper.mode = "ScaledKeepRatio";
else if ( button == ui.scaledKeepRatioClipButton )
wallpaper.mode = "ScaledKeepRatioExpand";
emit changed();
}
//--------------------------------------------------------------------------------
void ConfigureDesktopDialog::showImages()
{
// create filter (list of patterns) for image files we can read
QMimeDatabase db;
QStringList filterList;
foreach (const QByteArray &type, QImageReader::supportedMimeTypes())
{
QMimeType mime(db.mimeTypeForName(QString::fromLatin1(type)));
if ( mime.isValid() )
{
foreach (const QString &pattern, mime.globPatterns())
filterList << pattern;
}
}
ui.iconView->clear();
QStringList dirNames = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation,
"wallpapers", QStandardPaths::LocateDirectory);
const QString geometryString = QString("%1x%2")
- .arg(QApplication::desktop()->width())
- .arg(QApplication::desktop()->height());
+ .arg(QApplication::primaryScreen()->size().width())
+ .arg(QApplication::primaryScreen()->size().height());
for (const QString &dirName : dirNames)
{
// check for file directly in this folder
QStringList fileNames = QDir(dirName).entryList(filterList, QDir::Files | QDir::Readable);
for (const QString &fileName : fileNames)
{
QPixmap pixmap(dirName + '/' + fileName);
QListWidgetItem *item = new QListWidgetItem(pixmap, fileName, ui.iconView);
item->setData(Qt::UserRole, dirName + '/' + fileName);
item->setToolTip(QString("%1 (%2x%3)").arg(fileName).arg(pixmap.width()).arg(pixmap.height()));
}
// check for files in the special subdirs
for (const QString &subdir : QDir(dirName).entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::Readable))
{
QDir dir(dirName + '/' + subdir + "/contents/images");
QString chosenFilePath;
for (const QString &fileName : dir.entryList(filterList, QDir::Files | QDir::Readable))
{
chosenFilePath = dir.absoluteFilePath(fileName);
if ( fileName.startsWith(geometryString) )
break; // just take one
}
if ( !chosenFilePath.isEmpty() )
{
QPixmap pixmap(chosenFilePath);
QListWidgetItem *item = new QListWidgetItem(pixmap, subdir, ui.iconView);
item->setData(Qt::UserRole, chosenFilePath);
item->setToolTip(QString("%1 (%2x%3)").arg(subdir).arg(pixmap.width()).arg(pixmap.height()));
}
}
}
}
//--------------------------------------------------------------------------------
diff --git a/DesktopWidget.cxx b/DesktopWidget.cxx
index 4a1d6c0..d5e8d97 100644
--- a/DesktopWidget.cxx
+++ b/DesktopWidget.cxx
@@ -1,396 +1,399 @@
// SPDX-License-Identifier: GPL-3.0-or-later
/*
- Copyright 2017, 2018 Martin Koller, kollix@aon.at
+ Copyright 2017 - 2019 Martin Koller, kollix@aon.at
This file is part of liquidshell.
liquidshell 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
(at your option) any later version.
liquidshell 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 liquidshell. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include
-#include
+#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//--------------------------------------------------------------------------------
int DesktopWidget::appletNum = 0;
//--------------------------------------------------------------------------------
DesktopWidget::DesktopWidget()
: QWidget(nullptr, Qt::WindowDoesNotAcceptFocus)
{
setAttribute(Qt::WA_AlwaysShowToolTips);
setAutoFillBackground(true);
- setFixedSize(QApplication::desktop()->size());
+ setFixedSize(QApplication::primaryScreen()->virtualSize());
setWindowIcon(QIcon::fromTheme("liquidshell"));
KWindowSystem::setType(winId(), NET::Desktop);
panel = new DesktopPanel(nullptr);
panel->show();
connect(panel, &DesktopPanel::resized, this, &DesktopWidget::placePanel);
placePanel();
connect(KWindowSystem::self(), &KWindowSystem::currentDesktopChanged, this, &DesktopWidget::desktopChanged);
connect(KWindowSystem::self(), &KWindowSystem::numberOfDesktopsChanged, this, &DesktopWidget::loadSettings);
setContextMenuPolicy(Qt::ActionsContextMenu);
QAction *action = new QAction(QIcon::fromTheme("configure"), i18n("Configure Wallpaper..."), this);
connect(action, &QAction::triggered, this, &DesktopWidget::configureWallpaper);
addAction(action);
action = new QAction(i18n("Add Applet"), this);
addAction(action);
QMenu *menu = new QMenu;
action->setMenu(menu);
action = menu->addAction(QIcon::fromTheme("weather-clouds"), i18n("Weather"));
connect(action, &QAction::triggered, [this]() { addApplet("Weather"); });
action = menu->addAction(QIcon::fromTheme("drive-harddisk"), i18n("Disk Usage"));
connect(action, &QAction::triggered, [this]() { addApplet("DiskUsage"); });
action = menu->addAction(QIcon::fromTheme("image-x-generix"), i18n("Picture Frame"));
connect(action, &QAction::triggered, [this]() { addApplet("PictureFrame"); });
action = new QAction(QIcon::fromTheme("preferences-desktop-display"), i18n("Configure Display..."), this);
connect(action, &QAction::triggered, this, &DesktopWidget::configureDisplay);
addAction(action);
action = new QAction(QIcon::fromTheme("system-run"), i18n("Run Command..."), this);
connect(action, &QAction::triggered,
[]()
{
QDBusConnection::sessionBus().send(
QDBusMessage::createMethodCall("org.kde.krunner", "/App",
"org.kde.krunner.App", "display"));
});
addAction(action);
action = new QAction(i18n("Help"), this);
KHelpMenu *helpMenu = new KHelpMenu(this);
helpMenu->action(KHelpMenu::menuHelpContents)->setVisible(false); // no handbook
helpMenu->action(KHelpMenu::menuWhatsThis)->setVisible(false);
action->setMenu(helpMenu->menu());
addAction(action);
// restore applets
KConfig config;
KConfigGroup group = config.group("DesktopApplets");
QStringList appletNames = group.readEntry("applets", QStringList());
for (const QString &appletName : appletNames)
{
DesktopApplet *applet = nullptr;
if ( appletName.startsWith("Weather_") )
applet = new WeatherApplet(this, appletName);
else if ( appletName.startsWith("DiskUsage_") )
applet = new DiskUsageApplet(this, appletName);
else if ( appletName.startsWith("PictureFrame_") )
applet = new PictureFrameApplet(this, appletName);
if ( applet )
{
int num = appletName.mid(appletName.indexOf('_') + 1).toInt();
if ( num > appletNum )
appletNum = num;
applet->loadConfig();
applets.append(applet);
connect(applet, &DesktopApplet::removeThis, this, &DesktopWidget::removeApplet);
}
}
loadSettings();
- connect(QApplication::desktop(), &QDesktopWidget::primaryScreenChanged, this, &DesktopWidget::placePanel);
+ connect(qApp, &QApplication::primaryScreenChanged, this, &DesktopWidget::placePanel);
- connect(QApplication::desktop(), &QDesktopWidget::screenCountChanged,
- [this]() { setFixedSize(QApplication::desktop()->size()); desktopChanged(); });
+ connect(qApp, &QApplication::screenAdded,
+ [this]() { setFixedSize(QApplication::primaryScreen()->virtualSize()); desktopChanged(); });
- connect(QApplication::desktop(), &QDesktopWidget::resized,
- [this]() { setFixedSize(QApplication::desktop()->size()); placePanel(); desktopChanged(); });
+ connect(qApp, &QApplication::screenRemoved,
+ [this]() { setFixedSize(QApplication::primaryScreen()->virtualSize()); desktopChanged(); });
+
+ connect(QApplication::primaryScreen(), &QScreen::virtualGeometryChanged,
+ [this]() { setFixedSize(QApplication::primaryScreen()->virtualSize()); placePanel(); desktopChanged(); });
new OnScreenVolume(this);
}
//--------------------------------------------------------------------------------
void DesktopWidget::loadSettings()
{
// simple check for default files matching current desktop size
QStringList dirNames = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation,
"wallpapers", QStandardPaths::LocateDirectory);
QStringList defaultFiles;
const QString geometryString = QString("%1x%2").arg(width()).arg(height());
for (const QString &dirName : dirNames)
{
for (const QString &subdir : QDir(dirName).entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::Readable))
{
QDir dir(dirName + '/' + subdir + "/contents/images");
for (const QString &fileName : dir.entryList(QDir::Files | QDir::Readable))
{
if ( fileName.startsWith(geometryString) )
defaultFiles.append(dir.absoluteFilePath(fileName));
}
}
}
KConfig config;
for (int i = wallpapers.count() + 1; i <= KWindowSystem::numberOfDesktops(); i++)
{
KConfigGroup group = config.group(QString("Desktop_%1").arg(i));
Wallpaper wallpaper;
wallpaper.color = group.readEntry("color", QColor(Qt::black));
wallpaper.mode = group.readEntry("wallpaperMode", QString());
int idx = defaultFiles.count() ? ((i - 1) % defaultFiles.count()) : -1;
wallpaper.fileName = group.readEntry("wallpaper", (idx != -1) ? defaultFiles[idx] : QString());
wallpapers.append(wallpaper);
}
wallpapers.resize(KWindowSystem::numberOfDesktops()); // if we had more before, reduce size
wallpapers.squeeze();
desktopChanged();
}
//--------------------------------------------------------------------------------
void DesktopWidget::configureWallpaper()
{
if ( dialog ) // already open, do nothing
return;
bool showingDesktop = KWindowSystem::showingDesktop();
KWindowSystem::setShowingDesktop(true);
int desktopNum = currentDesktop;
Wallpaper origWallpaper = wallpapers[desktopNum];
dialog = new ConfigureDesktopDialog(nullptr, wallpapers[desktopNum]);
connect(dialog, &ConfigureDesktopDialog::changed,
[=]() { wallpapers[desktopNum] = dialog->getWallpaper(); desktopChanged(); });
connect(dialog, &QDialog::finished,
[=](int result)
{
if ( result == QDialog::Rejected )
{
wallpapers[desktopNum] = origWallpaper;
desktopChanged();
}
else // store in config file
{
const Wallpaper &wallpaper = wallpapers[desktopNum];
KConfig config;
KConfigGroup group = config.group(QString("Desktop_%1").arg(desktopNum + 1));
group.writeEntry("color", wallpaper.color);
group.writeEntry("wallpaper", wallpaper.fileName);
group.writeEntry("wallpaperMode", wallpaper.mode);
}
KWindowSystem::setShowingDesktop(showingDesktop); // restore
dialog->deleteLater();
dialog = nullptr;
});
dialog->show(); // not modal
}
//--------------------------------------------------------------------------------
void DesktopWidget::configureDisplay()
{
KCMultiDialog *dialog = new KCMultiDialog(this);
dialog->setAttribute(Qt::WA_DeleteOnClose);
dialog->addModule("kcm_kscreen");
dialog->adjustSize();
dialog->setWindowTitle(i18n("Configure Display"));
dialog->show(); // not modal
}
//--------------------------------------------------------------------------------
void DesktopWidget::placePanel()
{
int panelHeight = qMin(panel->sizeHint().height(), panel->height());
- QRect r = QApplication::desktop()->screenGeometry();
+ QRect r = QApplication::primaryScreen()->geometry();
panel->setGeometry(r.x(), r.y() + r.height() - panelHeight, r.width(), panelHeight);
KWindowSystem::setStrut(panel->winId(), 0, 0, 0, panelHeight);
}
//--------------------------------------------------------------------------------
void DesktopWidget::desktopChanged()
{
// free memory in previous shown desktop
if ( (currentDesktop >= 0) && (currentDesktop < wallpapers.count()) )
wallpapers[currentDesktop].pixmaps.clear();
currentDesktop = KWindowSystem::currentDesktop() - 1; // num to index
if ( currentDesktop >= wallpapers.count() )
return;
Wallpaper &wallpaper = wallpapers[currentDesktop];
if ( wallpaper.color.isValid() )
{
QPalette pal = palette();
pal.setColor(backgroundRole(), wallpaper.color);
setPalette(pal);
}
if ( !wallpaper.fileName.isEmpty() )
{
QPixmap pixmap(wallpaper.fileName);
if ( !pixmap.isNull() )
{
- for (int i = 0; i < QApplication::desktop()->screenCount(); i++)
+ for (int i = 0; i < QApplication::screens().count(); i++)
{
- QRect r = QApplication::desktop()->screenGeometry(i);
+ QRect r = QApplication::screens().at(i)->geometry();
QPixmap scaledPixmap = pixmap;
if ( wallpaper.mode == "Scaled" )
scaledPixmap = pixmap.scaled(r.size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
else if ( wallpaper.mode == "ScaledKeepRatio" )
scaledPixmap = pixmap.scaled(r.size(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
else if ( wallpaper.mode == "ScaledKeepRatioExpand" )
scaledPixmap = pixmap.scaled(r.size(), Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
wallpaper.pixmaps.append(scaledPixmap);
}
}
}
update();
// show applets for new desktop
for (DesktopApplet *applet : applets)
{
if ( !applet->isConfiguring() )
applet->setVisible(applet->isOnDesktop(currentDesktop + 1));
}
}
//--------------------------------------------------------------------------------
void DesktopWidget::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event)
if ( currentDesktop < wallpapers.count() )
{
Wallpaper &wallpaper = wallpapers[currentDesktop];
QPainter painter(this);
- for (int i = 0; i < QApplication::desktop()->screenCount(); i++)
+ for (int i = 0; i < QApplication::screens().count(); i++)
{
if ( i < wallpaper.pixmaps.count() )
{
- QRect r = QApplication::desktop()->screenGeometry(i);
+ QRect r = QApplication::screens().at(i)->geometry();
painter.setClipRect(r);
painter.drawPixmap(r.x() + (r.width() - wallpaper.pixmaps[i].width()) / 2,
r.y() + (r.height() - wallpaper.pixmaps[i].height()) / 2,
wallpaper.pixmaps[i]);
}
}
}
}
//--------------------------------------------------------------------------------
void DesktopWidget::addApplet(const QString &type)
{
DesktopApplet *applet = nullptr;
if ( type == "Weather" )
{
applet = new WeatherApplet(this, QString("%1_%2").arg(type).arg(++appletNum));
}
else if ( type == "DiskUsage" )
{
applet = new DiskUsageApplet(this, QString("%1_%2").arg(type).arg(++appletNum));
}
else if ( type == "PictureFrame" )
{
applet = new PictureFrameApplet(this, QString("%1_%2").arg(type).arg(++appletNum));
}
if ( applet )
{
applets.append(applet);
applet->loadConfig(); // defaults + size
applet->move(QCursor::pos());
applet->saveConfig();
applet->show();
connect(applet, &DesktopApplet::removeThis, this, &DesktopWidget::removeApplet);
}
saveAppletsList();
}
//--------------------------------------------------------------------------------
void DesktopWidget::removeApplet(DesktopApplet *applet)
{
applets.removeOne(applet);
applet->deleteLater();
saveAppletsList();
}
//--------------------------------------------------------------------------------
void DesktopWidget::saveAppletsList()
{
KConfig config;
KConfigGroup group = config.group("DesktopApplets");
QStringList appletNames;
for (DesktopApplet *applet : applets)
appletNames.append(applet->getId());
group.writeEntry("applets", appletNames);
}
//--------------------------------------------------------------------------------
diff --git a/DesktopWidget.hxx b/DesktopWidget.hxx
index 84cf505..8587dc4 100644
--- a/DesktopWidget.hxx
+++ b/DesktopWidget.hxx
@@ -1,71 +1,71 @@
// SPDX-License-Identifier: GPL-3.0-or-later
/*
Copyright 2017 Martin Koller, kollix@aon.at
This file is part of liquidshell.
liquidshell 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
(at your option) any later version.
liquidshell 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 liquidshell. If not, see .
*/
#ifndef DESKTOP_WIDGET_H
#define DESKTOP_WIDGET_H
#include
#include
#include
class DesktopPanel;
class DesktopApplet;
class ConfigureDesktopDialog;
class DesktopWidget : public QWidget
{
Q_OBJECT
public:
DesktopWidget();
struct Wallpaper
{
QString fileName, mode;
QColor color;
QVector pixmaps; // per screen
};
protected:
- virtual void paintEvent(QPaintEvent *event);
+ void paintEvent(QPaintEvent *event) override;
private Q_SLOTS:
void loadSettings();
void placePanel();
void desktopChanged();
void configureWallpaper();
void configureDisplay();
void addApplet(const QString &type);
void removeApplet(DesktopApplet *applet);
private:
void saveAppletsList();
private:
DesktopPanel *panel = nullptr;
ConfigureDesktopDialog *dialog = nullptr;
QVector wallpapers;
int currentDesktop = -1;
QVector applets;
static int appletNum;
};
#endif
diff --git a/NotificationList.cxx b/NotificationList.cxx
index fb66cf7..828660b 100644
--- a/NotificationList.cxx
+++ b/NotificationList.cxx
@@ -1,332 +1,332 @@
// SPDX-License-Identifier: GPL-3.0-or-later
/*
- Copyright 2017,2018 Martin Koller, kollix@aon.at
+ Copyright 2017 - 2019 Martin Koller, kollix@aon.at
This file is part of liquidshell.
liquidshell 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
(at your option) any later version.
liquidshell 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 liquidshell. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
-#include
+#include
#include
#include
#include
#include
#include
#include
static const Qt::WindowFlags POPUP_FLAGS = Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint;
//--------------------------------------------------------------------------------
NotifyItem::NotifyItem(QWidget *parent, uint theId, const QString &app,
const QString &theSummary, const QString &theBody, const QIcon &icon,
const QStringList &theActions)
: QFrame(parent, POPUP_FLAGS), id(theId), appName(app), summary(theSummary), body(theBody), actions(theActions)
{
setAttribute(Qt::WA_ShowWithoutActivating); // avoid focus stealing
setFrameShape(QFrame::StyledPanel);
QMargins margins = contentsMargins();
margins.setRight(0); // allow the close button to reach to the right screen border - easier to click
setContentsMargins(margins);
QVBoxLayout *vbox = new QVBoxLayout;
timeLabel = new QLabel;
iconLabel = new QLabel;
vbox->addWidget(timeLabel, 0, Qt::AlignTop | Qt::AlignHCenter);
vbox->addWidget(iconLabel, 0, Qt::AlignTop | Qt::AlignHCenter);
QVBoxLayout *centerBox = new QVBoxLayout;
QHBoxLayout *hbox = new QHBoxLayout(this);
margins = hbox->contentsMargins();
margins.setRight(0); // allow the close button to reach to the right screen border - easier to click
hbox->setContentsMargins(margins);
textLabel = new QLabel;
QToolButton *closeButton = new QToolButton;
// easier to click with larger size
closeButton->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
closeButton->setMinimumWidth(40);
closeButton->setAutoRaise(true);
closeButton->setIcon(QIcon::fromTheme("window-close"));
connect(closeButton, &QToolButton::clicked, this, &NotifyItem::deleteLater);
textLabel->setWordWrap(true);
textLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
textLabel->setOpenExternalLinks(true);
textLabel->setMinimumWidth(300);
textLabel->setMaximumWidth(600);
textLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
centerBox->addWidget(textLabel);
if ( actions.count() )
{
QHBoxLayout *actionBox = new QHBoxLayout;
centerBox->addLayout(actionBox);
for (int i = 0; i < actions.count(); i++)
{
if ( ((i % 2) != 0) && !actions[i].isEmpty() ) // id
{
QPushButton *button = new QPushButton;
button->setText(actions[i]);
actionBox->addWidget(button);
QString key = actions[i - 1];
connect(button, &QPushButton::clicked, this,
[this, key]()
{
QDBusMessage msg =
QDBusMessage::createSignal("/org/freedesktop/Notifications",
"org.freedesktop.Notifications",
"ActionInvoked");
msg << id << key;
QDBusConnection::sessionBus().send(msg);
});
}
}
}
hbox->addLayout(vbox);
hbox->addLayout(centerBox);
hbox->addWidget(closeButton);
iconLabel->setFixedSize(32, 32);
iconLabel->setPixmap(icon.pixmap(iconLabel->size()));
QString title = (appName == summary) ? appName : (appName + ": " + summary);
textLabel->setText(QString("%1
%2")
.arg(title)
.arg(body));
timeLabel->setText(QTime::currentTime().toString(Qt::SystemLocaleShortDate));
}
//--------------------------------------------------------------------------------
void NotifyItem::destroySysResources()
{
destroy();
}
//--------------------------------------------------------------------------------
//--------------------------------------------------------------------------------
//--------------------------------------------------------------------------------
NotificationList::NotificationList(QWidget *parent)
: QWidget(parent)
{
setWindowFlags(windowFlags() | Qt::Tool);
setWindowTitle(i18n("Notifications"));
scrollArea = new QScrollArea;
scrollArea->setWidgetResizable(true);
QWidget *listWidget = new QWidget;
listVbox = new QVBoxLayout(listWidget);
listVbox->setContentsMargins(QMargins());
listVbox->addStretch();
scrollArea->setWidget(listWidget);
QVBoxLayout *vbox = new QVBoxLayout(this);
vbox->setContentsMargins(QMargins());
vbox->addWidget(scrollArea);
QPushButton *clearButton = new QPushButton;
clearButton->setIcon(QIcon::fromTheme("edit-clear-list"));
connect(clearButton, &QPushButton::clicked, this, [this]() { for (NotifyItem *item : items) item->deleteLater(); });
vbox->addWidget(clearButton);
resize(500, 300);
}
//--------------------------------------------------------------------------------
NotificationList::~NotificationList()
{
for (NotifyItem *item : items)
item->disconnect(); // make sure destroyed() is no longer triggered
}
//--------------------------------------------------------------------------------
void NotificationList::addItem(uint id, const QString &appName, const QString &summary, const QString &body,
const QIcon &icon, const QStringList &actions, const QVariantMap &hints, int timeout)
{
QPointer item = new NotifyItem(nullptr, id, appName, summary, body, icon, actions);
item->resize(500, item->sizeHint().height());
KWindowSystem::setState(item->winId(), NET::SkipTaskbar | NET::SkipPager);
items.append(item.data());
placeItems();
int wordCount = body.splitRef(' ', QString::SkipEmptyParts).count();
bool neverExpires = timeout == 0; // according to spec
if ( timeout <= 0 )
{
timeout = 4000 + 250 * wordCount;
if ( actions.count() )
timeout += 15000; // give user more time to think ...
}
// 0=low, 1=normal, 2=critical
if ( hints.contains("urgency") && (hints["urgency"].toInt() == 2) )
{
neverExpires = true;
timeout = 20000; // just show it longer since its urgent
}
bool transient = hints.contains("transient") ? hints["transient"].toBool() : false;
// if there are actions, show it longer
if ( actions.count() || neverExpires )
transient = false;
// exceptions ...
if ( transient && hints.contains("x-kde-eventId") )
{
// I'd like to keep this much longer
if ( hints["x-kde-eventId"].toString() == "new-email" )
transient = false;
}
// I often get the same notification multiple times (e.g. KDE-connect or EWS akonadi resource)
// but I don't want to fill up the screen with useless duplicate information. Therefore
// whenever the same notification is received while another instance of it is still visible,
// only put it in the list-view (it has a different id, therefore still store it), but don't show it as popup
for (NotifyItem *it : items)
{
if ( (it != item) && // not the new item already in items
!it->parentWidget() && // temporary item not in the list-view yet
(appName == it->appName) && (summary == it->summary) &&
(body == it->body) && (actions == it->actions) )
{
timeout = 0;
}
}
numItems++;
emit itemsCountChanged();
connect(item.data(), &NotifyItem::destroyed, this,
[this](QObject *obj)
{
items.removeOne(static_cast(obj));
placeItems();
if ( --numItems == 0 )
{
hide();
emit listNowEmpty();
}
else
emit itemsCountChanged();
}
);
QTimer::singleShot(timeout,
[=]()
{
if ( item )
{
// sometimes there were some leftover/half-functioning windows. This seems to avoid that
item->destroySysResources();
listVbox->insertWidget(listVbox->count() - 1, item); // insert before stretch
item->show();
placeItems(); // reorder the remaining ones
scrollArea->setWidgetResizable(true); // to update scrollbars, else next line does not work
scrollArea->ensureWidgetVisible(item);
if ( !neverExpires )
{
if ( !appTimeouts.contains(appName) )
appTimeouts.insert(appName, 10); // default: 10 minutes lifetime
int expireTimeout;
if ( transient )
expireTimeout = 2 * 60 * 1000; // still keep it a short time
else
expireTimeout = appTimeouts[appName] * 60 * 1000;
QTimer::singleShot(expireTimeout, item.data(), &NotifyItem::deleteLater);
}
}
}
);
}
//--------------------------------------------------------------------------------
void NotificationList::closeItem(uint id)
{
for (NotifyItem *item : items)
{
if ( item->id == id )
{
item->deleteLater();
break;
}
}
}
//--------------------------------------------------------------------------------
void NotificationList::placeItems()
{
- QRect screen = QApplication::desktop()->availableGeometry(this);
+ QRect screen = QApplication::primaryScreen()->availableGeometry();
QPoint point = parentWidget()->mapToGlobal(parentWidget()->pos());
int x = point.x();
int y = screen.bottom();
for (NotifyItem *item : items)
{
if ( !item->parentWidget() ) // temporary item not in the list yet
{
y -= item->sizeHint().height();
y -= 5; // a small space
point.setX(std::min(x, screen.x() + screen.width() - item->sizeHint().width()));
point.setY(y);
item->move(point);
item->show();
}
}
}
//--------------------------------------------------------------------------------
diff --git a/OnScreenVolume.cxx b/OnScreenVolume.cxx
index f0f78e4..43ff959 100644
--- a/OnScreenVolume.cxx
+++ b/OnScreenVolume.cxx
@@ -1,175 +1,175 @@
// SPDX-License-Identifier: GPL-3.0-or-later
/*
- Copyright 2017 Martin Koller, kollix@aon.at
+ Copyright 2017 - 2019 Martin Koller, kollix@aon.at
This file is part of liquidshell.
liquidshell 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
(at your option) any later version.
liquidshell 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 liquidshell. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include
-#include
+#include
#include
#include
#include
#include
//--------------------------------------------------------------------------------
OnScreenVolume::OnScreenVolume(QWidget *parent)
: QProgressBar(parent)
{
setWindowFlags(Qt::Window | Qt::FramelessWindowHint | Qt::WindowDoesNotAcceptFocus);
setFixedSize(400, 40);
hide();
KWindowSystem::setState(winId(), NET::KeepAbove);
KWindowSystem::setType(winId(), NET::Dock);
KWindowSystem::setOnAllDesktops(winId(), true);
hideTimer.setInterval(1000);
hideTimer.setSingleShot(true);
connect(&hideTimer, &QTimer::timeout, this, &QWidget::hide);
QDBusConnection::sessionBus()
.connect("org.kde.kmix", "/Mixers",
"org.kde.KMix.MixSet", "masterChanged",
this, SLOT(getMasterMixer()));
if ( !QDBusConnection::sessionBus().interface()->isServiceRegistered("org.kde.kmix") )
{
QDBusServiceWatcher *w = new QDBusServiceWatcher("org.kde.kmix", QDBusConnection::sessionBus(),
QDBusServiceWatcher::WatchForRegistration, this);
connect(w, &QDBusServiceWatcher::serviceRegistered, this, &OnScreenVolume::getMasterMixer);
}
else
getMasterMixer();
}
//--------------------------------------------------------------------------------
void OnScreenVolume::getMasterMixer()
{
QDBusMessage msg = QDBusMessage::createMethodCall("org.kde.kmix", "/Mixers",
"org.freedesktop.DBus.Properties",
"GetAll");
msg << "org.kde.KMix.MixSet";
QDBusConnection::sessionBus()
.callWithCallback(msg, this,
SLOT(gotMasterMixer(QDBusMessage)),
SLOT(gotMasterMixerError(QDBusError, QDBusMessage)));
}
//--------------------------------------------------------------------------------
void OnScreenVolume::gotMasterMixerError(QDBusError error, QDBusMessage msg)
{
Q_UNUSED(error)
Q_UNUSED(msg)
if ( retryTimer.interval() == 0 )
{
// the service could already be registered but no object yet
retryTimer.setInterval(1000);
retryTimer.setSingleShot(true);
connect(&retryTimer, &QTimer::timeout, this, &OnScreenVolume::getMasterMixer);
}
retryTimer.start();
}
//--------------------------------------------------------------------------------
void OnScreenVolume::gotMasterMixer(QDBusMessage msg)
{
QDBusReply reply = msg;
if ( !reply.isValid() )
return;
if ( !masterMixer.isEmpty() )
{
// disconnect previous master mixer
QDBusConnection::sessionBus()
.disconnect("org.kde.kmix", "/Mixers/" + masterMixer,
"org.kde.KMix.Mixer", "controlChanged",
this, SLOT(controlChanged()));
}
masterMixer = reply.value()["currentMasterMixer"].toString();
masterMixer.replace(':', '_');
masterControl = reply.value()["currentMasterControl"].toString();
masterControl.replace('.', '_');
masterControl.replace('-', '_');
//qDebug() << masterMixer << masterControl;
QDBusConnection::sessionBus()
.connect("org.kde.kmix", "/Mixers/" + masterMixer,
"org.kde.KMix.Mixer", "controlChanged",
this, SLOT(controlChanged()));
}
//--------------------------------------------------------------------------------
void OnScreenVolume::controlChanged()
{
QDBusMessage msg =
QDBusMessage::createMethodCall("org.kde.kmix", "/Mixers/" + masterMixer + '/' + masterControl,
"org.freedesktop.DBus.Properties",
"Get");
msg << "org.kde.KMix.Control" << "volume";
QDBusConnection::sessionBus().callWithCallback(msg, this, SLOT(volumeChanged(QDBusMessage)));
}
//--------------------------------------------------------------------------------
void OnScreenVolume::volumeChanged(QDBusMessage reply)
{
if ( reply.type() == QDBusMessage::ErrorMessage )
return;
if ( reply.arguments().count() && (reply.arguments()[0].value().variant().toInt() != value()) )
{
setValue(reply.arguments()[0].value().variant().toInt());
if ( !isVisible() ) // just always once before showing
{
KConfig config("kmixrc");
KConfigGroup group = config.group("Global");
if ( !group.readEntry("showOSD", true) )
return;
}
- move((QApplication::desktop()->width() - width()) / 2,
- QApplication::desktop()->height() * 0.8);
+ move((QApplication::primaryScreen()->size().width() - width()) / 2,
+ QApplication::primaryScreen()->size().height() * 0.8);
show();
hideTimer.start();
}
}
//--------------------------------------------------------------------------------
diff --git a/SysTrayItem.cxx b/SysTrayItem.cxx
index 41674ec..1b526c1 100644
--- a/SysTrayItem.cxx
+++ b/SysTrayItem.cxx
@@ -1,90 +1,90 @@
// SPDX-License-Identifier: GPL-3.0-or-later
/*
- Copyright 2017 Martin Koller, kollix@aon.at
+ Copyright 2017 - 2019 Martin Koller, kollix@aon.at
This file is part of liquidshell.
liquidshell 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
(at your option) any later version.
liquidshell 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 liquidshell. If not, see .
*/
#include
#include
#include
-#include
+#include
#include
#include
#include
//--------------------------------------------------------------------------------
SysTrayItem::SysTrayItem(QWidget *parent, const QString &icon)
: QLabel(parent), iconName(icon)
{
setFixedSize(QSize(22, 22));
if ( !iconName.isEmpty() )
{
setPixmap(QIcon::fromTheme(iconName).pixmap(size()));
connect(KIconLoader::global(), &KIconLoader::iconLoaderSettingsChanged, this,
[this]() { setPixmap(QIcon::fromTheme(iconName).pixmap(size())); });
}
}
//--------------------------------------------------------------------------------
void SysTrayItem::mousePressEvent(QMouseEvent *event)
{
if ( event->button() != Qt::LeftButton )
return;
toggleDetailsList();
}
//--------------------------------------------------------------------------------
void SysTrayItem::showDetailsList()
{
QWidget *detailsList = getDetailsList();
if ( !detailsList )
return;
QPoint point = mapToGlobal(pos());
- QRect screen = QApplication::desktop()->availableGeometry(this);
- point.setX(std::min(point.x(), screen.x() + screen.width() - detailsList->size().width()));
- point.setY(screen.bottom() - detailsList->size().height());
+ QRect screen = QApplication::primaryScreen()->availableGeometry();
+ point.setX(std::min(point.x(), screen.x() + screen.width() - detailsList->width()));
+ point.setY(screen.bottom() - detailsList->height());
detailsList->move(point);
detailsList->show();
KWindowSystem::raiseWindow(detailsList->winId());
}
//--------------------------------------------------------------------------------
void SysTrayItem::toggleDetailsList()
{
QWidget *detailsList = getDetailsList();
if ( !detailsList )
return;
if ( detailsList->isVisible() )
detailsList->close();
else
showDetailsList();
}
//--------------------------------------------------------------------------------
diff --git a/WeatherApplet.cxx b/WeatherApplet.cxx
index f59f100..5d9eacb 100644
--- a/WeatherApplet.cxx
+++ b/WeatherApplet.cxx
@@ -1,401 +1,401 @@
// SPDX-License-Identifier: GPL-3.0-or-later
/*
Copyright 2017 Martin Koller, kollix@aon.at
This file is part of liquidshell.
liquidshell 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
(at your option) any later version.
liquidshell 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 liquidshell. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//--------------------------------------------------------------------------------
QString WeatherApplet::apiKey;
//--------------------------------------------------------------------------------
WeatherApplet::WeatherApplet(QWidget *parent, const QString &theId)
: DesktopApplet(parent, theId)
{
setAutoFillBackground(true);
timer.setInterval(600000); // 10min smallest update interval for free data
connect(&timer, &QTimer::timeout, this, &WeatherApplet::fetchData);
QVBoxLayout *vbox = new QVBoxLayout(this);
cityLabel = new QLabel(this);
cityLabel->setObjectName("city");
cityLabel->setWordWrap(true);
QFont f = font();
f.setPointSizeF(fontInfo().pointSizeF() * 2);
f.setBold(true);
cityLabel->setFont(f);
vbox->addWidget(cityLabel);
QGridLayout *grid = new QGridLayout;
vbox->addLayout(grid);
grid->addWidget(new QLabel(i18n("Temperature:"), this), 0, 0);
grid->addWidget(tempLabel = new QLabel, 0, 1);
grid->addWidget(new QLabel(i18n("Pressure:"), this), 1, 0);
grid->addWidget(pressureLabel = new QLabel, 1, 1);
grid->addWidget(new QLabel(i18n("Humidity:"), this), 2, 0);
grid->addWidget(humidityLabel = new QLabel, 2, 1);
grid->addWidget(new QLabel(i18n("Wind Speed:"), this), 3, 0);
grid->addWidget(windSpeedLabel = new QLabel, 3, 1);
grid->addWidget(new QLabel(i18n("Wind Direction:"), this), 4, 0);
grid->addWidget(windDirectionLabel = new QLabel, 4, 1);
for (int i = 0; i < 4; i++)
{
shortForecast[i] = new ForecastWidget(this, false);
grid->addWidget(shortForecast[i], 0, 2 + i, 5, 1, Qt::AlignCenter);
}
QHBoxLayout *hbox = new QHBoxLayout;
vbox->addLayout(hbox);
for (int i = 0; i < 5; i++)
{
forecast[i] = new ForecastWidget(this);
hbox->addWidget(forecast[i]);
if ( i < 4 )
hbox->addStretch();
}
connect(NetworkManager::notifier(), &NetworkManager::Notifier::connectivityChanged, this,
[this](NetworkManager::Connectivity connectivity)
{
if ( connectivity == NetworkManager::Full )
fetchData();
});
}
//--------------------------------------------------------------------------------
QSize WeatherApplet::sizeHint() const
{
return QSize(700, 300);
}
//--------------------------------------------------------------------------------
void WeatherApplet::loadConfig()
{
KConfig config;
KConfigGroup group = config.group("Weather");
apiKey = group.readEntry("apiKey", QString());
group = config.group(id);
cityId = group.readEntry("cityId", QString());
units = group.readEntry("units", QString("metric"));
DesktopApplet::loadConfig();
if ( apiKey.isEmpty() || cityId.isEmpty() )
cityLabel->setText(i18n("Not configured"));
}
//--------------------------------------------------------------------------------
void WeatherApplet::showEvent(QShowEvent *)
{
// only query every 10 minutes, which is the limit for free data
if ( !timer.isActive() )
{
timer.start();
fetchData();
}
}
//--------------------------------------------------------------------------------
void WeatherApplet::fetchData()
{
if ( !isVisible() || apiKey.isEmpty() || cityId.isEmpty() )
return;
QString url = QString("http://api.openweathermap.org/data/2.5/weather?APPID=%1&units=%2&id=%3")
.arg(apiKey, units, cityId);
KIO::StoredTransferJob *job = KIO::storedGet(QUrl(url), KIO::Reload, KIO::HideProgressInfo);
connect(job, &KIO::Job::result, this, &WeatherApplet::gotData);
url = QString("http://api.openweathermap.org/data/2.5/forecast?APPID=%1&units=%2&id=%3")
.arg(apiKey, units, cityId);
job = KIO::storedGet(QUrl(url), KIO::Reload, KIO::HideProgressInfo);
connect(job, &KIO::Job::result, this, &WeatherApplet::gotData);
}
//--------------------------------------------------------------------------------
void WeatherApplet::gotData(KJob *job)
{
if ( job->error() )
{
cityLabel->setText(job->errorString());
return;
}
QJsonDocument doc = QJsonDocument::fromJson(static_cast(job)->data());
if ( doc.isNull() || !doc.isObject() )
return;
QString tempUnit = i18n("°K");
if ( units == "metric" ) tempUnit = i18n("°C");
else if ( units == "imperial" ) tempUnit = i18n("°F");
QJsonObject data = doc.object();
if ( data.contains("city") && data["city"].isObject() )
cityLabel->setText(data["city"].toObject()["name"].toString());
// current
if ( data.contains("main") && data["main"].isObject() )
{
QJsonObject mainData = data["main"].toObject();
double temp = mainData["temp"].toDouble();
tempLabel->setText(i18n("%1 %2", locale().toString(temp, 'f', 1), tempUnit));
double pressure = mainData["pressure"].toDouble();
pressureLabel->setText(i18n("%1 hPa", locale().toString(pressure, 'f', 1)));
double humidity = mainData["humidity"].toDouble();
humidityLabel->setText(i18n("%1 %", locale().toString(humidity, 'f', 1)));
}
if ( data.contains("wind") && data["wind"].isObject() )
{
QJsonObject windData = data["wind"].toObject();
QString speedUnit = "m/s";
if ( units == "imperial" ) speedUnit = "mi/h";
double speed = windData["speed"].toDouble();
windSpeedLabel->setText(i18n("%1 %2", locale().toString(speed, 'f', 0), speedUnit));
double deg = windData["deg"].toDouble();
windDirectionLabel->setText(i18n("%1 °", locale().toString(deg, 'f', 0)));
}
if ( data.contains("weather") && data["weather"].isArray() )
{
QDateTime dt = QDateTime::fromMSecsSinceEpoch(qint64(data["dt"].toInt()) * 1000);
shortForecast[0]->day->setText(dt.time().toString(Qt::SystemLocaleShortDate));
setIcon(shortForecast[0]->icon, data["weather"].toArray()[0].toObject()["icon"].toString());
}
// forecast
if ( data.contains("list") && data["list"].isArray() )
{
for (int i = 0; i < 5; i++)
forecast[i]->hide();
QJsonArray array = data["list"].toArray();
// 3 hours short forecast
for (int i = 0; i < 3; i++)
{
setIcon(shortForecast[1 + i]->icon, array[i].toObject()["weather"].toArray()[0].toObject()["icon"].toString());
QDateTime dt = QDateTime::fromMSecsSinceEpoch(qint64(array[i].toObject()["dt"].toInt()) * 1000);
shortForecast[1 + i]->day->setText(dt.time().toString(Qt::SystemLocaleShortDate));
shortForecast[1 + i]->show();
}
QHash minTemp, maxTemp; // key = day
for (QJsonValue value : array)
{
QJsonObject obj = value.toObject();
int day = QDateTime::fromMSecsSinceEpoch(qint64(obj["dt"].toInt()) * 1000).date().dayOfWeek();
double temp = obj["main"].toObject()["temp"].toDouble();
if ( !minTemp.contains(day) )
{
minTemp.insert(day, temp);
maxTemp.insert(day, temp);
}
else
{
if ( temp < minTemp[day] ) minTemp[day] = temp;
if ( temp > maxTemp[day] ) maxTemp[day] = temp;
}
}
int idx = 0;
for (QJsonValue value : array)
{
QJsonObject obj = value.toObject();
if ( obj["dt_txt"].toString().contains("12:00") )
{
QString icon = obj["weather"].toArray()[0].toObject()["icon"].toString();
setIcon(forecast[idx]->icon, icon);
int day = QDateTime::fromMSecsSinceEpoch(qint64(obj["dt"].toInt()) * 1000).date().dayOfWeek();
- forecast[idx]->day->setText(QDate::shortDayName(day));
+ forecast[idx]->day->setText(locale().dayName(day, QLocale::ShortFormat));
forecast[idx]->min->setText(i18n("%1 %2", locale().toString(minTemp[day], 'f', 1), tempUnit));
forecast[idx]->max->setText(i18n("%1 %2", locale().toString(maxTemp[day], 'f', 1), tempUnit));
forecast[idx]->show();
idx++;
if ( idx == 5 ) break;
}
}
}
timer.start(); // after showEvent make sure to wait another full timeout phase
}
//--------------------------------------------------------------------------------
void WeatherApplet::setIcon(QLabel *label, const QString &icon)
{
QString cacheDir = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) +
"/api.openweathermap.org/";
QDir dir;
dir.mkpath(cacheDir);
QString filePath = cacheDir + icon + ".png";
if ( QFile::exists(filePath) )
{
QPixmap pixmap(filePath);
if ( !pixmap.isNull() )
label->setPixmap(pixmap);
}
else
{
KIO::StoredTransferJob *job =
KIO::storedGet(QUrl("http://api.openweathermap.org/img/w/" + icon), KIO::Reload, KIO::HideProgressInfo);
connect(job, &KIO::Job::result, this,
[label, filePath](KJob *job)
{
if ( job->error() )
return;
QPixmap pixmap;
pixmap.loadFromData(static_cast(job)->data());
if ( !pixmap.isNull() )
{
label->setPixmap(pixmap);
pixmap.save(filePath, "PNG");
}
});
}
}
//--------------------------------------------------------------------------------
//--------------------------------------------------------------------------------
//--------------------------------------------------------------------------------
ForecastWidget::ForecastWidget(QWidget *parent, bool showMinMax)
: QWidget(parent)
{
QGridLayout *grid = new QGridLayout(this);
if ( showMinMax )
{
min = new QLabel(this);
max = new QLabel(this);
min->setAlignment(Qt::AlignRight);
max->setAlignment(Qt::AlignRight);
grid->addWidget(max, 0, 1);
grid->addWidget(min, 1, 1);
}
day = new QLabel(this);
icon = new QLabel(this);
day->setAlignment(Qt::AlignCenter);
icon->setFixedSize(64, 64);
icon->setScaledContents(true);
grid->addWidget(day, 2, 0, 1, 2);
grid->addWidget(icon, 0, 0, 2, 1);
setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
}
//--------------------------------------------------------------------------------
void WeatherApplet::configure()
{
if ( dialog )
{
dialog->raise();
dialog->activateWindow();
return;
}
dialog = new WeatherAppletConfigureDialog(this);
dialog->setWindowTitle(i18n("Configure Weather Applet"));
dialog->setAttribute(Qt::WA_DeleteOnClose);
dialog->show();
connect(dialog.data(), &QDialog::accepted, this,
[this]()
{
saveConfig();
KConfig config;
KConfigGroup group = config.group("Weather");
group.writeEntry("apiKey", apiKey);
group = config.group(id);
group.writeEntry("cityId", cityId);
group.writeEntry("units", units);
if ( !apiKey.isEmpty() && !cityId.isEmpty() )
{
fetchData();
timer.start();
}
else
{
cityLabel->setText(i18n("Not configured"));
}
});
}
//--------------------------------------------------------------------------------