diff options
31 files changed, 551 insertions, 203 deletions
@@ -18,21 +18,6 @@ For additional information about the project, please browse the official website **General Project Information: Table of Contents** -- [General TrueOS Information](#gentrosinfo) - - [TrueOS Project Documentation](#docs) - - [TrueOS Handbook](#trueosdoc) - - [Lumina Handbook](#luminadoc) - - [SysAdm Handbooks](#sysadmdoc) - - [Filing Issues or Feature Requests](#fileissues) - - [Community Channels](#community) - - [Discourse](#discourse) - - [Gitter](#gitter) - - [IRC](#irc) - - [Subreddit](#subreddit) - - [Social Media](#socialmedia) - -<!-- END GENERAL INFO TOC --> - Description <a name="description"></a> ===== @@ -45,7 +30,7 @@ Supported operating systems include (but are not limited to): Latest Versions <a name="latestversions"></a> ---- -Click [HERE](https://github.com/trueos/lumina/releases) to see all the available releases for the Lumina Desktop. +Click [HERE](https://github.com/lumina-desktop/lumina/releases) to see all the available releases for the Lumina Desktop. Click [HERE]() to see all the available branches of the Lumina Desktop source tree (includes development versions: X.Y.(Z > 0)). The master branch is where all development is performed and tested before the next version is tagged. Additionally, every version (development **and** release) of the project gets branched off of master at the time the version is tagged, so older versions may be fetched/patched/used as desired. @@ -66,7 +51,7 @@ To submit translations, please use the online [TrueOS Translation System](http:/ How to file bug reports or feature requests <a name="filebugs"></a> ---- -Please create a ticket through the [GitHub issues tracker](https://github.com/trueos/lumina/issues) on this repository. Similarly, if you want to send in patches or other source contributions, please send in a GitHub pull request so that it can get reviewed/committed as quickly as possible. +Please create a ticket through the [GitHub issues tracker](https://github.com/lumina-desktop/lumina/issues) on this repository. Similarly, if you want to send in patches or other source contributions, please send in a GitHub pull request so that it can get reviewed/committed as quickly as possible. How to build from source <a name="buildfromsource"></a> @@ -74,7 +59,7 @@ How to build from source <a name="buildfromsource"></a> 1) Checkout the source repo to your local box (GitHub gives a few methods for this) Examples: -* To checkout the master branch of the repo, run `git clone https://github.com/trueos/lumina` to create a "lumina" directory with a local copy of the source tree. +* To checkout the master branch of the repo, run `git clone https://github.com/lumina-desktop/lumina` to create a "lumina" directory with a local copy of the source tree. * To update an exising checkout of the Lumina repo, run "git pull" while within your local copy of the source tree. 2) In a terminal, change to the lumina repo directory (base dir, not one of the sub-projects) @@ -109,97 +94,31 @@ Examples: NOTE: The Lumina project is naturally broken down into a number of individual "sub-projects" which are designed to be built and packaged individually. These sub-projects all use the same overall dependencies, but might have differing library/runtime dependencies or even an alternate minimum-supported version of Qt. The sub-projects are broken down as follows: - * [lumina-core](https://github.com/trueos/lumina/tree/master/src-qt5/core): The core of the project (desktop itself) - * [lumina-coreutils](https://github.com/trueos/lumina/tree/master/src-qt5/core-utils): The core utilities for configuring/managing the desktop - * [desktop-utilities](https://github.com/trueos/lumina/tree/master/src-qt5/desktop-utils): Various support utilities for desktop systems. Every one of these utilities should be independently packaged. + * [lumina-core](https://github.com/lumina-desktop/lumina/tree/master/src-qt5/core): The core of the project (desktop itself) + * [lumina-coreutils](https://github.com/lumina-desktop/lumina/tree/master/src-qt5/core-utils): The core utilities for configuring/managing the desktop + * [desktop-utilities](https://github.com/lumina-desktop/lumina/tree/master/src-qt5/desktop-utils): Various support utilities for desktop systems. Every one of these utilities should be independently packaged. --- -# General TrueOS Information <a name="gentrosinfo"></a> - -This section describes where you can find more information about TrueOS and its related projects, file new issues on GitHub, and converse with other users or contributors to the project. - -## TrueOS Project Documentation <a name="docs"></a> - -A number of [Sphinx](http://www.sphinx-doc.org/en/stable/) generated reStructuredText handbooks are available to introduce you to the TrueOS, Lumina, and SysAdm projects. These handbooks are open source, and users are always encouraged to open GitHub issues or fix any errors they find in the documentation. - -### TrueOS Handbook <a name="trueosdoc"></a> - -The [TrueOS User Guide](https://www.trueos.org/handbook/trueos.html) is a comprehensive guide to install TrueOS, along with post-installation configuration help, recommendations for useful utilities and applications, and a help and support section containing solutions for common issues and links to community and development chat channels for uncommon issues. There is also a chapter describing the experimental TrueOS Pico project and links to the Lumina and SysAdm documentation. All TrueOS documentation is hosted on the [TrueOS website](https://www.trueos.org). - ### Lumina Handbook <a name="luminadoc"></a> The Lumina Desktop Environment has its own [handbook](https://lumina-desktop.org/handbook/), hosted on the [Lumina Website](https://lumina-desktop.org). This handbook contains brief installation instructions. However, due to the highly customizable nature of Lumina, the focus of the handbook lies mainly in documenting all user configurable settings. Each option is typically described in detail, with both text and screenshots. Finally, the suite of unique Qt5 utilities included with Lumina are also documented. TrueOS users are encouraged to review the Lumina documentation, as the Lumina Desktop Environment is installed by default with TrueOS. -### SysAdm Handbooks <a name="sysadmdoc"></a> - -Due to complexity of this project, SysAdm documentation is split into three different guides: - -1. **API Reference Guide** (https://api.sysadm.us/getstarted.html) - -The Application Programming Interface (API) Reference Guide is a comprehensive library of all API calls and WebSocket requests for SysAdm. In addition to documenting all SysAdm subsystems and classes, the guide provides detailed examples of requests and responses, authentication, and SSL certificate management. This guide is constantly updated, ensuring it provides accurate information at all times. - -2. **Client Handbook** (https://sysadm.us/handbook/client/) - -The SysAdm Client handbook documents all aspects of the SysAdm client, as well as describing of the PC-BSD system utilities is replaces. Detailed descriptions of utilities such as Appcafe, Life Preserver, and the Boot Environment Manager are contained here, as well as a general guide to using these utilities. TrueOS users are encouraged to reference this guide, as the SysAdm client is included with TrueOS. - -3. **Server Handbook** (https://sysadm.us/handbook/server/introduction.html) - -The Server handbook is a basic installation guide, walking new users through the process of initializing SysAdm with a bridge and server connection. - ## Filing Issues or Feature Requests <a name="fileissues"></a> -Due to the number of repositories under the TrueOS "umbrella", the TrueOS Project consolidates its issue trackers into a few repositories: - -* [trueos-core](https://github.com/trueos/trueos-core) : Used for general TrueOS issues, Pico issues, and feature requests. -* [lumina](https://github.com/trueos/lumina) : Issues related to using the Lumina Desktop Environment. -* [sysadm](https://github.com/trueos/sysadm) : Issues with using the SysAdm client or server. -* [trueos-docs](https://github.com/trueos/trueos-docs) : Issues related to the TrueOS Handbook. -* [lumina-docs](https://github.com/trueos/lumina-docs) : Issues related to the Lumina Handbook. -* [sysadm-docs](https://github.com/trueos/sysadm-docs) : Issues related to the SysAdm API Guide, Client, and Server Handbooks. -* [trueos-website](https://github.com/trueos/trueos-website) : Issues involving any of the TrueOS Project websites: +* [lumina](https://github.com/lumina-desktop/lumina) : Issues related to using the Lumina Desktop Environment. +* [lumina-website](https://github.com/lumina/lumina-website) : Issues involving the Lumina Desktop Project website: - https://www.lumina-desktop.org - - https://www.trueos.org - - https://www.sysadm.us The TrueOS handbook has detailed instructions to help you report a bug (https://www.trueos.org/handbook/helpsupport.html#report-a-bug). It is recommended to refer to these instructions when creating new GitHub issues. Better bug reports usually result in faster fixes! To request a feature, open a new issue in one of the related GitHub issue repositories and begin the title with *Feature Request:*. -## Community Channels <a name="community"></a> - -The TrueOS community has a wide variety of chat channels and forum options available for users to interact with not only each other, but contributors to the project and the core development team too. - -### Discourse <a name="discourse"></a> - -TrueOS has a [Discourse channel](https://discourse.trueos.org/) managed concurrently with the TrueOS Subreddit. New users need to sign up with Discourse in order to create posts, but it is possible to view posts without an account. - -### Gitter <a name="gitter"></a> - -The TrueOS Project uses Gitter to provide real-time chat and collaboration with TrueOS users and developers. Gitter does not require an application to use, but does require a login using either an existing GitHub or Twitter account. - -To access the TrueOS Gitter community, point a web browser to https://gitter.im/trueos. - -Gitter also maintains a full archive of the chat history. This means lengthy conversations about hardware issues or workarounds are always available for reference. To access the Gitter archive, navigate to the desired TrueOS room’s archive. For example, here is the address of the TrueOS Lobby archive: https://gitter.im/trueos/Lobby/archives. - -### IRC <a name="irc"></a> - -Like many open source projects, TrueOS has an Internet Relay Chat (IRC) channel so users can chat and get help in real time. To get connected, use this information in your IRC client: - -* Server name: irc.freenode.net -* Channel name: #trueos (note the # is required) - -### Subreddit <a name="subreddit"></a> - -The TrueOS Project also has a [Subreddit](https://www.reddit.com/r/TrueOS/) for users who prefer to use Reddit to ask questions and to search for or post how-tos. A Reddit account is not required in order to read the Subreddit, but it is necessary to create a login account to submit or comment on posts. - ## Social Media <a name="socialmedia"></a> The TrueOS Project also maintains a number of social media accounts you can watch: -* Facebook: https://www.facebook.com/groups/4210443834/ -* Linkedin: http://www.linkedin.com/groups?gid=1942544 -* TrueOS Blog: https://www.trueos.org/blog/ -* Twitter: https://twitter.com/TrueOS_Project/ +* Lumina Blog: https://lumina-desktop.org/blog/ +* Twitter: https://twitter.com/luminadesktop diff --git a/dev-tools/iconprobe/main.cpp b/dev-tools/iconprobe/main.cpp new file mode 100644 index 00000000..06599bf7 --- /dev/null +++ b/dev-tools/iconprobe/main.cpp @@ -0,0 +1,80 @@ +#include <QApplication> +#include <QDebug> +#include <QFile> +#include <QDir> +#include <QTextStream> +#include <QIcon> + +QString findInDir(QString dir, QString file){ + QDir _dir(dir); + QStringList files = _dir.entryList(QStringList() << file+".*", QDir::Files | QDir::NoDotAndDotDot, QDir::Name); + if(files.isEmpty()){ + QStringList dirs = _dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name); + QString tmp; + for(int i=0; i<dirs.length() && tmp.isEmpty(); i++){ + tmp = findInDir( _dir.absoluteFilePath(dirs[i]), file); + } + return tmp; + }else{ + return _dir.absoluteFilePath(files.first()); + } +} + +QStringList themeInherits(QString dir){ + QFile file(dir+"/index.theme"); + QStringList list; + if( file.open(QIODevice::Text | QIODevice::ReadOnly) ){ + QTextStream in(&file); + while(!in.atEnd()){ + QString line = in.readLine(); + if(line.startsWith("Inherits=")){ + //qDebug() << "Got Inherit Line" << line; + list = line.section("=",1,-1).split(";"); + break; //done now + } + } + file.close(); + } + return list; +} + +bool isIconTheme(QString dir){ + if(!QFile::exists(dir+"/index.theme")){ return false; } + QDir base(dir); + QStringList dirs = base.entryList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name); + dirs.removeAll("cursors"); + return (!dirs.isEmpty()); +} + +int main(int argc, char ** argv) +{ + QApplication a(argc, argv); + + QString icondir="/usr/local/share/icons"; + QStringList iconfiles; + if(argc<2){ iconfiles << "folder-downloads" << "start-here-lumina" << "firefox" << "utilities-terminal"; } + else{ iconfiles = QString(argv[1]).split(" "); } + + QDir dir(icondir); + QStringList themes = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name); + //Now look through them and see which themes have this file + QIcon::setThemeSearchPaths( QStringList() << icondir ); + for(int i=0; i<themes.length(); i++){ + QString themepath = dir.absoluteFilePath(themes[i]); + if( !isIconTheme(themepath) ){ continue; } + qDebug() << "Testing Theme:" << themes[i]; + QIcon::setThemeName(themes[i]); + QStringList inherits = themeInherits(themepath); + for(int j=0; j<inherits.length(); j++){ inherits << themeInherits(dir.absoluteFilePath(inherits[j])); } + qDebug() << " - Inherits From Themes (in order):" << inherits; + for(int j=0; j<iconfiles.length(); j++){ + qDebug() << " -------------------------"; + qDebug() << " - Looking for icon:" << iconfiles[j]; + qDebug() << " - Found File:" << findInDir(themepath, iconfiles[j]); + qDebug() << " - Has Theme Icon:" << QIcon::hasThemeIcon(iconfiles[j]); + qDebug() << " - Found Icon:" << QIcon::fromTheme(iconfiles[j]).name(); + } + qDebug() << " ================"; + } + return 0; +} diff --git a/dev-tools/iconprobe/test.pro b/dev-tools/iconprobe/test.pro new file mode 100644 index 00000000..48b02c00 --- /dev/null +++ b/dev-tools/iconprobe/test.pro @@ -0,0 +1,12 @@ +# Simple Qt program to test whether UI files can be loaded when there is no DBUS session running + +QT = core gui widgets +#Just for consistency - remove the dbus module from this app build (in case "gui" or "widgets" pulled it in) +QT -= dbus + +CONFIG += debug + +TARGET = test +target.path = $${PWD} + +SOURCES = main.cpp diff --git a/src-qt5/OS-detect.pri b/src-qt5/OS-detect.pri index f7c65d6f..be32aea6 100644 --- a/src-qt5/OS-detect.pri +++ b/src-qt5/OS-detect.pri @@ -127,6 +127,9 @@ isEmpty(OS){ RCC_DIR=./.build/rcc QMAKE_DISTCLEAN += -r ./.build + #Setup the default place for installing icons (use scalable dir for variable-size icons) + icons.path = $${L_SHAREDIR}/icons/hicolor/scalable/apps + #some other compile time flags CONFIG *= c++11 } diff --git a/src-qt5/core-utils/lumina-config/mainWindow.cpp b/src-qt5/core-utils/lumina-config/mainWindow.cpp index 566cd412..0dafc1da 100644 --- a/src-qt5/core-utils/lumina-config/mainWindow.cpp +++ b/src-qt5/core-utils/lumina-config/mainWindow.cpp @@ -11,14 +11,22 @@ #include "pages/getPage.h" #include "pages/page_main.h" +#include <QSettings> + //============= // PUBLIC //============= mainWindow::mainWindow() : QMainWindow(), ui(new Ui::mainWindow()){ ui->setupUi(this); + geomTimer = new QTimer(this); + geomTimer->setSingleShot(true); + geomTimer->setInterval(1000); //1 second + connect(geomTimer, SIGNAL(timeout()), this, SLOT(saveWinGeometry()) ); + APPSLIST = new XDGDesktopList(this, true); //keep this up to date while the app is open QTimer::singleShot(100, APPSLIST, SLOT(updateList())); //don't let this hold up the initial application loading cpage = "somerandomjunktostartwith"; + //Need to insert a spacer action in the toolbar QWidget *tmp = new QWidget(this); tmp->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); @@ -30,6 +38,9 @@ mainWindow::mainWindow() : QMainWindow(), ui(new Ui::mainWindow()){ setupIcons(); loadMonitors(); //changePage(""); //load the default main page + QSettings S("lumina-desktop","lumina-config"); + QRect geom = S.value("window_geometry", QRect()).toRect(); + if(!geom.isNull()){ this->setGeometry(geom); } } mainWindow::~mainWindow(){ @@ -58,7 +69,7 @@ void mainWindow::setupIcons(){ } void mainWindow::loadMonitors(){ - if(ui->actionMonitor->menu()==0){ + if(ui->actionMonitor->menu()==0){ ui->actionMonitor->setMenu( new QMenu(this) ); ui->actionMonitor->setWhatsThis("0"); connect( ui->actionMonitor->menu(), SIGNAL(triggered(QAction*)), this, SLOT(changeMonitor(QAction*)) ); @@ -76,7 +87,7 @@ void mainWindow::loadMonitors(){ ui->actionMonitor->setWhatsThis(tmp->whatsThis() ); } } - + } //============= @@ -114,6 +125,11 @@ void mainWindow::changePage(QString id){ //================ // PRIVATE SLOTS //================ +void mainWindow::saveWinGeometry(){ + QSettings S("lumina-desktop","lumina-config"); + S.setValue("window_geometry", this->geometry()); +} + //Page signal handling void mainWindow::pageCanSave(bool save){ ui->actionSave->setVisible(save); diff --git a/src-qt5/core-utils/lumina-config/mainWindow.h b/src-qt5/core-utils/lumina-config/mainWindow.h index 958daff9..c441de61 100644 --- a/src-qt5/core-utils/lumina-config/mainWindow.h +++ b/src-qt5/core-utils/lumina-config/mainWindow.h @@ -9,6 +9,9 @@ #include "globals.h" //#include "pages/getPage.h" +#include <QResizeEvent> +#include <QMoveEvent> + namespace Ui{ class mainWindow; }; @@ -28,11 +31,13 @@ private: Ui::mainWindow *ui; QShortcut *backShortcut, *quitShortcut; QString cpage; //current page - + QTimer *geomTimer; void changePage(QString id); private slots: + void saveWinGeometry(); + //Page signals void pageCanSave(bool); void pageSetTitle(QString); @@ -42,5 +47,17 @@ private slots: void on_actionBack_triggered(); void changeMonitor(QAction*); void quitShortcut_Triggered(); + +protected: + void resizeEvent(QResizeEvent *ev){ + if(geomTimer->isActive()){ geomTimer->stop(); } + geomTimer->start(); + QMainWindow::resizeEvent(ev); + } + void moveEvent(QMoveEvent *ev){ + if(geomTimer->isActive()){ geomTimer->stop(); } + geomTimer->start(); + QMainWindow::moveEvent(ev); + } }; #endif diff --git a/src-qt5/core/libLumina/LFileInfo.cpp b/src-qt5/core/libLumina/LFileInfo.cpp index e7d2b71a..3b659c75 100644 --- a/src-qt5/core/libLumina/LFileInfo.cpp +++ b/src-qt5/core/libLumina/LFileInfo.cpp @@ -35,29 +35,37 @@ void LFileInfo::loadExtraInfo(){ mime = "inode/directory"; //Special directory icons QString name = this->fileName().toLower(); - if(name=="desktop"){ icon = "user-desktop"; } - else if(name=="tmp"){ icon = "folder-temp"; } - else if(name=="video" || name=="videos"){ icon = "folder-video"; } - else if(name=="music" || name=="audio"){ icon = "folder-sound"; } - else if(name=="projects" || name=="devel"){ icon = "folder-development"; } - else if(name=="notes"){ icon = "folder-txt"; } - else if(name=="downloads"){ icon = "folder-downloads"; } - else if(name=="documents"){ icon = "folder-documents"; } - else if(name=="images" || name=="pictures"){ icon = "folder-image"; } - else if(this->absoluteFilePath().startsWith("/net/")){ icon = "folder-remote"; } - else if( !this->isReadable() ){ icon = "folder-locked"; } + if(name=="desktop"){ iconList << "user-desktop"; } + else if(name=="tmp"){ iconList << "folder-temp"; } + else if(name=="video" || name=="videos"){ iconList << "folder-video" << "camera-photo-film" ; } + else if(name=="music" || name=="audio"){ iconList << "folder-sound" << "media-playlist-audio"; } + else if(name=="projects" || name=="devel"){ iconList << "folder-development"; } + else if(name=="notes"){ iconList << "folder-txt" << "note-multiple-outline" << "note-multiple"; } + else if(name=="downloads"){ iconList << "folder-downloads" << "folder-download"; } + else if(name=="documents"){ iconList << "folder-documents"; } + else if(name=="images" || name=="pictures"){ iconList << "folder-image"; } + else if(this->absoluteFilePath().startsWith("/net/")){ iconList << "folder-remote"; } + else if( !this->isReadable() ){ iconList << "folder-locked"<< "folder-lock"; } + iconList << "folder"; }else if( this->suffix()=="desktop"){ mime = "application/x-desktop"; - icon = "application-x-desktop"; //default value + iconList << "application-x-desktop"; //default value desk = new XDGDesktop(this->absoluteFilePath(), 0); if(desk->type!=XDGDesktop::BAD){ //use the specific desktop file info (if possible) - if(!desk->icon.isEmpty()){ icon = desk->icon; } + if(!desk->icon.isEmpty()){ iconList << desk->icon; } } }else{ //Generic file, just determine the mimetype mime = LXDG::findAppMimeForFile(this->fileName()); } + //check the mimetype for an icon as needed + QString tmp = mime; + tmp.replace("/","-"); + iconList << tmp; + if(this->isExecutable()){ + iconList << "application-x-executable"; + } } bool LFileInfo::zfsAvailable(){ @@ -94,14 +102,9 @@ QString LFileInfo::mimetype(){ // -- Return the icon to use for this file QString LFileInfo::iconfile(){ - if(!icon.isEmpty()){ - return icon; - }else if(!mime.isEmpty()){ - QString tmp = mime; - tmp.replace("/","-"); - return tmp; - }else if(this->isExecutable()){ - return "application-x-executable"; + //Go through the icon list and find the first one that exists in the current theme + for(int i=0; i<iconList.length(); i++){ + if( QIcon::hasThemeIcon(iconList[i])){ return iconList[i]; } } return ""; //Fall back to nothing } diff --git a/src-qt5/core/libLumina/LFileInfo.h b/src-qt5/core/libLumina/LFileInfo.h index df1abb65..f72c8649 100644 --- a/src-qt5/core/libLumina/LFileInfo.h +++ b/src-qt5/core/libLumina/LFileInfo.h @@ -17,7 +17,8 @@ class LFileInfo : public QFileInfo{ private: - QString mime, icon, zfs_ds; + QString mime, zfs_ds; + QStringList iconList; XDGDesktop *desk; void loadExtraInfo(); diff --git a/src-qt5/core/lumina-desktop-unified/src-desktop/DesktopManager.cpp b/src-qt5/core/lumina-desktop-unified/src-desktop/DesktopManager.cpp index edde5ed7..32f84f93 100644 --- a/src-qt5/core/lumina-desktop-unified/src-desktop/DesktopManager.cpp +++ b/src-qt5/core/lumina-desktop-unified/src-desktop/DesktopManager.cpp @@ -129,6 +129,8 @@ void DesktopManager::NewWindowAvailable(NativeWindowObject* win){ #ifdef USE_WIDGETS qDebug() << "Got New Widget Window:" << win->name(); NativeWindow *tmp = new NativeWindow(win); + //Lumina::NWS->RequestReparent(win->id(), win->frameId(), tmp->relativeOrigin()); + QTimer::singleShot(10, tmp, SLOT(initProperties()) ); #endif syncWindowList(); } diff --git a/src-qt5/core/lumina-desktop-unified/src-desktop/src-cpp/PanelObject.h b/src-qt5/core/lumina-desktop-unified/src-desktop/src-cpp/PanelObject.h index 945deec0..5ae75ea4 100644 --- a/src-qt5/core/lumina-desktop-unified/src-desktop/src-cpp/PanelObject.h +++ b/src-qt5/core/lumina-desktop-unified/src-desktop/src-cpp/PanelObject.h @@ -41,6 +41,7 @@ public: Q_INVOKABLE int height(); Q_INVOKABLE bool isVertical(); Q_INVOKABLE QStringList plugins(); + Q_INVOKABLE QRect geometry(){ return geom; } public slots: void setBackground(QString fileOrColor); diff --git a/src-qt5/core/lumina-desktop-unified/src-desktop/src-widgets/NativeWindow.cpp b/src-qt5/core/lumina-desktop-unified/src-desktop/src-widgets/NativeWindow.cpp index 44b2d715..86dd8482 100644 --- a/src-qt5/core/lumina-desktop-unified/src-desktop/src-widgets/NativeWindow.cpp +++ b/src-qt5/core/lumina-desktop-unified/src-desktop/src-widgets/NativeWindow.cpp @@ -6,11 +6,34 @@ //=========================================== #include "NativeWindow.h" +#include <QWidget> +#include <QWindow> + // === PUBLIC === NativeWindow::NativeWindow( NativeWindowObject *obj ) : QFrame(0, Qt::Window | Qt::FramelessWindowHint){ WIN = obj; createFrame(); - WIN->addFrameWinID(this->winId()); + WIN->addFrameWinID(container->winId()); +} + +NativeWindow::~NativeWindow(){ + vlayout->deleteLater(); + toolbarL->deleteLater(); +} + +QPoint NativeWindow::relativeOrigin(){ + //Update all the margins for the frame + /*QList<int> frame = WIN->property(NativeWindowObject::FrameExtents).value<QList<int> >(); + //QList<int> : [Left, Right, Top, Bottom] in pixels + int topM = frame[2] - titleLabel->fontMetrics().height(); //figure out how much extra we have to work with + if(topM<0){ topM = 0; } + int botM = topM/2.0; + QPoint containerCorner(frame[0], topM-botM); + return containerCorner;*/ + return QPoint(0,0); +} + +void NativeWindow::initProperties(){ //Setup all the property connections connect(WIN, SIGNAL(winImageChanged()), this, SLOT(syncWinImage()) ); connect(WIN, SIGNAL(nameChanged()), this, SLOT(syncName()) ); @@ -21,28 +44,24 @@ NativeWindow::NativeWindow( NativeWindowObject *obj ) : QFrame(0, Qt::Window | Q connect(WIN, SIGNAL(winTypeChanged()), this, SLOT(syncWinType()) ); connect(WIN, SIGNAL(geomChanged()), this, SLOT(syncGeom()) ); connect(WIN, SIGNAL(WindowClosed(WId)), this, SLOT(deleteLater()) ); + + //Setup all the button connections + connect(minB, SIGNAL(clicked()), WIN, SLOT(toggleVisibility()) ); + connect(maxB, SIGNAL(clicked()), WIN, SLOT(toggleMaximize()) ); + connect(closeB, SIGNAL(clicked()), WIN, SLOT(requestClose()) ); + //Now Perform the initial property loads syncWinImage(); syncName(); syncTitle(); syncIcon(); syncSticky(); - syncVisibility(); syncWinType(); syncGeom(); - //Setup all the button connections - connect(minB, SIGNAL(clicked()), WIN, SLOT(toggleVisibility()) ); - connect(maxB, SIGNAL(clicked()), WIN, SLOT(toggleMaximize()) ); - connect(closeB, SIGNAL(clicked()), WIN, SLOT(requestClose()) ); - + syncVisibility(true); //init visibility - force it visible to start with } -NativeWindow::~NativeWindow(){ - vlayout->deleteLater(); - toolbarL->deleteLater(); -} - // === PRIVATE === void NativeWindow::createFrame(){ //Initialize the widgets @@ -62,7 +81,8 @@ void NativeWindow::createFrame(){ vlayout->setSpacing(0); toolbarL = new QHBoxLayout(); toolbarL->setSpacing(0); - + container = QWidget::createWindowContainer(QWindow::fromWinId(WIN->id()), this); + container->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); //vlayout.align titleLabel = new QLabel(this); titleLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); @@ -75,7 +95,7 @@ void NativeWindow::createFrame(){ toolbarL->addWidget(maxB); toolbarL->addWidget(closeB); vlayout->addLayout(toolbarL); - vlayout->addStretch(); + vlayout->addWidget(container); this->setLayout(vlayout); // Load the icons for the buttons loadIcons(); @@ -112,9 +132,13 @@ void NativeWindow::syncSticky(){ qDebug() << "Got Sticky Change:" << WIN->isSticky(); } -void NativeWindow::syncVisibility(){ - qDebug() << "Sync Visibility:" << WIN->isVisible(); - this->setVisible(WIN->isVisible()); +void NativeWindow::syncVisibility(bool init){ + if(init){ + WIN->setProperty(NativeWindowObject::Visible, true, true); //force it + }else{ + qDebug() << "Sync Visibility:" << WIN->isVisible(); + this->setVisible(WIN->isVisible()); + } } void NativeWindow::syncWinType(){ diff --git a/src-qt5/core/lumina-desktop-unified/src-desktop/src-widgets/NativeWindow.h b/src-qt5/core/lumina-desktop-unified/src-desktop/src-widgets/NativeWindow.h index 1d87ed71..f2fd822c 100644 --- a/src-qt5/core/lumina-desktop-unified/src-desktop/src-widgets/NativeWindow.h +++ b/src-qt5/core/lumina-desktop-unified/src-desktop/src-widgets/NativeWindow.h @@ -16,6 +16,11 @@ public: NativeWindow(NativeWindowObject *obj); ~NativeWindow(); + QPoint relativeOrigin(); //origin of the embedded window relative to the frame + +public slots: + void initProperties(); + private: //Core object NativeWindowObject *WIN; @@ -27,6 +32,7 @@ private: QHBoxLayout *toolbarL; QVBoxLayout *vlayout; QLabel *titleLabel; + QWidget *container; // Info cache variables QRect oldgeom; @@ -38,7 +44,7 @@ private slots: void syncTitle(); void syncIcon(); void syncSticky(); - void syncVisibility(); + void syncVisibility(bool init = false); void syncWinType(); void syncGeom(); }; diff --git a/src-qt5/core/lumina-desktop-unified/src-desktop/src-widgets/Panel.cpp b/src-qt5/core/lumina-desktop-unified/src-desktop/src-widgets/Panel.cpp new file mode 100644 index 00000000..3f75e8c8 --- /dev/null +++ b/src-qt5/core/lumina-desktop-unified/src-desktop/src-widgets/Panel.cpp @@ -0,0 +1,87 @@ +//=========================================== +// Lumina-desktop source code +// Copyright (c) 2018, Ken Moore +// Available under the 3-clause BSD license +// See the LICENSE file for full details +//=========================================== +#include "Panel.h" + +// PUBLIC +Panel::Panel(PanelObject *pobj) : QWidget(0, Qt::Window | Qt::FramelessWindowHint){ + this->setObjectName("LuminaPanelBackgroundWidget"); + obj = pobj; + layout = new QBoxLayout(QBoxLayout::LeftToRight, this); + this->setBackgroundRole(QPalette::AlternateBase); + connect(obj, SIGNAL(backgroundChanged()), this, SLOT(updateBackground()) ); + connect(obj, SIGNAL(geomChanged()), this, SLOT(updateGeom()) ); + connect(obj, SIGNAL(pluginsChanged()), this, SLOT(updatePlugins()) ); + connect(obj, SIGNAL(destroyed(QObject*)), this, SLOT(objectDestroyed(QObject*)) ); + updateGeom(); + updateBackground(); + updatePlugins(); + this->showNormal(); +} + +Panel::~Panel(){ + +} + +// PRIVATE +Plugin* Panel::findPlugin(QString id){ + for(int i=0; i<PLUGINS.count(); i++){ + if(PLUGINS[i]->id()==id){ return PLUGINS[i]; } + } + return 0; +} + +Plugin* Panel::createPlugin(QString id){ + + return 0; +} + +// PRIVATE SLOTS +void Panel::objectDestroyed(QObject *dobj){ + if(dobj == Q_NULLPTR || dobj == obj){ + //Make sure this widget is also cleaned up when the base object is deleted + this->deleteLater(); + } +} + +void Panel::updateGeom(){ + this->setGeometry(obj->geometry()); + this->setFixedSize(obj->geometry().size()); + layout->setDirection( obj->isVertical() ? QBoxLayout::TopToBottom : QBoxLayout::LeftToRight ); + for(int i=0; i<PLUGINS.length(); i++){ + PLUGINS[i]->setVertical( obj->isVertical() ); + } +} + +void Panel::updateBackground(){ + static QString PANELTEMPLATE = "QToolButton::menu-indicator{ image: none; } QWidget#LuminaPanelBackgroundWidget{ background: %1; }"; + QString bg = obj->background(); + //qDebug() << "Got panel BG:" << obj->name() << bg; + this->setStyleSheet(PANELTEMPLATE.arg(bg)); +} + +void Panel::updatePlugins(){ + QStringList plugs = obj->plugins(); + qDebug() << "Got panel plugins:" << obj->name() << plugs; + for(int i=0; i<plugs.length(); i++){ + lastplugins.removeAll(plugs[i]); //remove this from the last list (handled) + Plugin *plug = findPlugin(plugs[i]); + if(plug==0){ plug = createPlugin(plugs[i]); } + if(plug==0){ continue; } //not a valid plugin - just skip it + //Now setup the order of the plugins properly + if( layout->indexOf(plug) >=0 ){ + layout->removeWidget(plug); //remove from the layout for a moment + } + layout->insertWidget(i, plug); + } + //Now remove any plugins which were deleted from config + for(int i=0; i<lastplugins.length(); i++){ + Plugin *plug = findPlugin(lastplugins[i]); + if(plug==0){ continue; } + plug->deleteLater(); + } + lastplugins = plugs; +} diff --git a/src-qt5/core/lumina-desktop-unified/src-desktop/src-widgets/Panel.h b/src-qt5/core/lumina-desktop-unified/src-desktop/src-widgets/Panel.h new file mode 100644 index 00000000..64b0e239 --- /dev/null +++ b/src-qt5/core/lumina-desktop-unified/src-desktop/src-widgets/Panel.h @@ -0,0 +1,38 @@ +//=========================================== +// Lumina-desktop source code +// Copyright (c) 2018, Ken Moore +// Available under the 3-clause BSD license +// See the LICENSE file for full details +//=========================================== +// This is the Widgets version of a floating, top-level panel +//=========================================== +#ifndef _DESKTOP_WIDGETS_PANEL_H +#define _DESKTOP_WIDGETS_PANEL_H + +#include <global-includes.h> +#include <QBoxLayout> +#include "Plugin.h" + +class Panel : public QWidget { + Q_OBJECT +private: + PanelObject *obj; + QBoxLayout *layout; + QStringList lastplugins; + //Stuff for managing the plugins + QList<Plugin*> PLUGINS; + Plugin* findPlugin(QString id); + Plugin* createPlugin(QString id); + +public: + Panel(PanelObject *pobj); + ~Panel(); + +private slots: + void objectDestroyed(QObject*); + void updateGeom(); + void updateBackground(); + void updatePlugins(); + +}; +#endif diff --git a/src-qt5/core/lumina-desktop-unified/src-desktop/src-widgets/Plugin.h b/src-qt5/core/lumina-desktop-unified/src-desktop/src-widgets/Plugin.h new file mode 100644 index 00000000..0934374f --- /dev/null +++ b/src-qt5/core/lumina-desktop-unified/src-desktop/src-widgets/Plugin.h @@ -0,0 +1,58 @@ +//=========================================== +// Lumina-desktop source code +// Copyright (c) 2018, Ken Moore +// Available under the 3-clause BSD license +// See the LICENSE file for full details +//=========================================== +// This is the Widgets version of a generic plugin +//=========================================== +#ifndef _DESKTOP_WIDGETS_GENERIC_PLUGIN_H +#define _DESKTOP_WIDGETS_GENERIC_PLUGIN_H + +#include <global-includes.h> + +//Base plugin type for a canvas/widget +class Plugin : public QWidget{ + Q_OBJECT +private: + bool isPanelPlugin; + bool isVertical; //only used for panel plugins + QString _id; + +signals: + void orientationChanged(); + +public: + Plugin(QWidget *parent, QString id, bool panelplug = false) : QWidget(parent){ + isPanelPlugin = panelplug; + isVertical = false; + _id = id; + } + + void setVertical(bool set){ + if(set!=isVertical){ isVertical = set; emit orientationChanged(); } + } + + QString id(){ return _id; } + +private slots: + +}; + +//Special subclass for a button-based plugin +class PluginButton : public Plugin{ + Q_OBJECT +private: + QToolButton *button; + +public: + PluginButton(QWidget *parent, QString id, bool panelplug=false) : Plugin(parent, id, panelplug) { + button = new QToolButton(this); + this->setLayout( new QBoxLayout(QBoxLayout::LeftToRight) ); + this->layout()->setContentsMargins(0,0,0,0); + this->layout()->addWidget(button); + } + + ~PluginButton(){} +}; +#endif diff --git a/src-qt5/core/lumina-desktop-unified/src-desktop/src-widgets/RootDesktop.cpp b/src-qt5/core/lumina-desktop-unified/src-desktop/src-widgets/RootDesktop.cpp index 9e22a143..3c034dc6 100644 --- a/src-qt5/core/lumina-desktop-unified/src-desktop/src-widgets/RootDesktop.cpp +++ b/src-qt5/core/lumina-desktop-unified/src-desktop/src-widgets/RootDesktop.cpp @@ -6,6 +6,7 @@ //=========================================== #include <global-objects.h> #include "RootDesktop.h" +#include "Panel.h" // === PUBLIC === RootDesktop::RootDesktop(QWindow *) : QWidget(0, Qt::Widget | Qt::FramelessWindowHint | Qt::WindowStaysOnBottomHint){ @@ -66,7 +67,14 @@ void RootDesktop::on_screensChanged(){ } void RootDesktop::on_panelsChanged(){ - + QStringList pans = RootDesktopObject::instance()->panels(); + //Now find any new panels and create them as needed + for(int i=0; i<pans.length(); i++){ + if(lastpanels.contains(pans[i])){ continue; } //already created + //Need to create a new panel widget (self-maintained) + new Panel( RootDesktopObject::instance()->panel(pans[i]) ); + } + lastpanels = pans; //save this for the next time around } void RootDesktop::on_windowsChanged(){ diff --git a/src-qt5/core/lumina-desktop-unified/src-desktop/src-widgets/RootDesktop.h b/src-qt5/core/lumina-desktop-unified/src-desktop/src-widgets/RootDesktop.h index 16ce0e47..ff717074 100644 --- a/src-qt5/core/lumina-desktop-unified/src-desktop/src-widgets/RootDesktop.h +++ b/src-qt5/core/lumina-desktop-unified/src-desktop/src-widgets/RootDesktop.h @@ -20,7 +20,7 @@ public: private: QImage bgimage; - QStringList lastscreens; + QStringList lastscreens, lastpanels; QTimer *bgTimer; DesktopContextMenu *cmenu; diff --git a/src-qt5/core/lumina-desktop-unified/src-desktop/src-widgets/src-widgets.pri b/src-qt5/core/lumina-desktop-unified/src-desktop/src-widgets/src-widgets.pri index f1e200fd..7ed228f7 100644 --- a/src-qt5/core/lumina-desktop-unified/src-desktop/src-widgets/src-widgets.pri +++ b/src-qt5/core/lumina-desktop-unified/src-desktop/src-widgets/src-widgets.pri @@ -3,8 +3,11 @@ INCLUDEPATH *= $${PWD} SOURCES *= $${PWD}/RootDesktop.cpp \ $${PWD}/ContextMenu.cpp \ - $${PWD}/NativeWindow.cpp + $${PWD}/NativeWindow.cpp \ + $${PWD}/Panel.cpp HEADERS *= $${PWD}/RootDesktop.h \ $${PWD}/ContextMenu.h \ - $${PWD}/NativeWindow.h + $${PWD}/NativeWindow.h \ + $${PWD}/Panel.h \ + $${PWD}/Plugin.h diff --git a/src-qt5/core/lumina-desktop-unified/src-events/NativeWindowSystem.cpp b/src-qt5/core/lumina-desktop-unified/src-events/NativeWindowSystem.cpp index 65fa98a7..0d1e9c10 100644 --- a/src-qt5/core/lumina-desktop-unified/src-events/NativeWindowSystem.cpp +++ b/src-qt5/core/lumina-desktop-unified/src-events/NativeWindowSystem.cpp @@ -631,6 +631,7 @@ void NativeWindowSystem::SetupNewWindow(NativeWindowObject *win){ win->addDamageID( (uint) dmgID); //save this for later }else{ + /* //xcb_reparent_window(QX11Info::connection(), win->id(), this->winId(), 0, 0); //Also use a partial-composite here - make sure the window pixmap is available even when the window is obscured xcb_composite_redirect_window(QX11Info::connection(), win->id(), XCB_COMPOSITE_REDIRECT_AUTOMATIC); @@ -639,6 +640,7 @@ void NativeWindowSystem::SetupNewWindow(NativeWindowObject *win){ Damage dmgID = XDamageCreate(QX11Info::display(), win->id(), XDamageReportRawRectangles); win->addDamageID( (uint) dmgID); //save this for later + */ } //win->addFrameWinID(this->winId()); registerClientEvents(win->id()); @@ -795,7 +797,7 @@ void NativeWindowSystem::NewWindowDetected(WId id){ if(attr == 0){ return; } //could not get attributes of window if(attr->override_redirect){ free(attr); return; } //window has override redirect set (do not manage) free(attr); - xcb_reparent_window(QX11Info::connection(), id, QX11Info::appRootWindow(), 0, 0); + //xcb_reparent_window(QX11Info::connection(), id, QX11Info::appRootWindow(), 0, 0); //Now go ahead and create/populate the container for this window NativeWindowObject *win = new NativeWindowObject(id); diff --git a/src-qt5/core/lumina-desktop-unified/src-events/NativeWindowSystem.h b/src-qt5/core/lumina-desktop-unified/src-events/NativeWindowSystem.h index 0b6cd67e..f6033674 100644 --- a/src-qt5/core/lumina-desktop-unified/src-events/NativeWindowSystem.h +++ b/src-qt5/core/lumina-desktop-unified/src-events/NativeWindowSystem.h @@ -127,12 +127,14 @@ public slots: void NewMouseRelease(int buttoncode, WId win = 0); void CheckDamageID(WId); + void RequestReparent(WId, WId, QPoint); //client, parent, relative origin point in parent + + private slots: //These are the slots which are built-in and automatically connected when a new NativeWindow is created void RequestClose(WId); void RequestKill(WId); void RequestPing(WId); - void RequestReparent(WId, WId, QPoint); //client, parent, relative origin point in parent //Window-mgmt functions (see Window-mgmt.cpp for details) void ArrangeWindows(WId primary, QString type); diff --git a/src-qt5/core/lumina-desktop/LDesktopBackground.cpp b/src-qt5/core/lumina-desktop/LDesktopBackground.cpp index 6b458c24..22ee6dc4 100644 --- a/src-qt5/core/lumina-desktop/LDesktopBackground.cpp +++ b/src-qt5/core/lumina-desktop/LDesktopBackground.cpp @@ -46,7 +46,7 @@ QPixmap LDesktopBackground::setBackground(const QString& bgFile, const QString& } else { mode = Qt::KeepAspectRatio; } - if(bgImage.height() != geom.height() && bgImage.width() != geom.width() ){ bgImage = bgImage.scaled(geom.size(), mode); } + if(bgImage.height() != geom.height() && bgImage.width() != geom.width() ){ bgImage = bgImage.scaled(geom.size(), mode, Qt::SmoothTransformation); } //bgImage = bgImage.scaled(size(), mode); } diff --git a/src-qt5/core/lumina-desktop/LSession.cpp b/src-qt5/core/lumina-desktop/LSession.cpp index c1f49fc3..fe399e40 100644 --- a/src-qt5/core/lumina-desktop/LSession.cpp +++ b/src-qt5/core/lumina-desktop/LSession.cpp @@ -10,6 +10,7 @@ #include <QTime> #include <QScreen> #include <QtConcurrent> +#include <QMimeData> #include "LXcbEventFilter.h" #include "BootSplash.h" @@ -72,6 +73,11 @@ LSession::LSession(int &argc, char ** argv) : LSingleApplication(argc, argv, "lu connect(this, SIGNAL(screenAdded(QScreen*)), this, SLOT(screensChanged()) ); connect(this, SIGNAL(screenRemoved(QScreen*)), this, SLOT(screensChanged()) ); connect(this, SIGNAL(primaryScreenChanged(QScreen*)), this, SLOT(screensChanged()) ); + + // Clipboard + ignoreClipboard = false; + qRegisterMetaType<QClipboard::Mode>("QClipboard::Mode"); + connect(QApplication::clipboard(), SIGNAL(changed(QClipboard::Mode)), this, SLOT(handleClipboard(QClipboard::Mode))); } //end check for primary process } @@ -587,6 +593,31 @@ void LSession::SessionEnding(){ stopSystemTray(); //just in case it was not stopped properly earlier } +void LSession::handleClipboard(QClipboard::Mode mode){ + if ( !ignoreClipboard && mode == QClipboard::Clipboard ){ //only support Clipboard + const QMimeData *mime = QApplication::clipboard()->mimeData(mode); + if (mime==NULL) { return; } + if (mime->hasText() && !QApplication::clipboard()->ownsClipboard()) { + //preserve the entire mimeData set, not just the text + //Note that even when we want to "save" the test, we should keep the whole thing + // this preserves formatting codes and more that apps might need + QMimeData *copy = new QMimeData(); + QStringList fmts = mime->formats(); + for(int i=0; i<fmts.length(); i++){ copy->setData(fmts[i], mime->data(fmts[i])); } + ignoreClipboard = true; + QApplication::clipboard()->setMimeData(copy, mode); + ignoreClipboard = false; + //QMetaObject::invokeMethod(this, "storeClipboard", Qt::QueuedConnection, Q_ARG(QString, mime->text()), Q_ARG(QClipboard::Mode, mode)); + } + } +} + +void LSession::storeClipboard(QString text, QClipboard::Mode mode){ + ignoreClipboard = true; + QApplication::clipboard()->setText(text, mode); + ignoreClipboard = false; +} + //=============== // SYSTEM ACCESS //=============== diff --git a/src-qt5/core/lumina-desktop/LSession.h b/src-qt5/core/lumina-desktop/LSession.h index a25f3c15..824eede7 100644 --- a/src-qt5/core/lumina-desktop/LSession.h +++ b/src-qt5/core/lumina-desktop/LSession.h @@ -21,6 +21,7 @@ #include <QMediaPlayer> #include <QThread> #include <QUrl> +#include <QClipboard> #include "Globals.h" #include "AppMenu.h" @@ -141,6 +142,8 @@ private: int VersionStringToNumber(QString version); + bool ignoreClipboard; // flag for (handle/store)Clipboard + public slots: void StartLogout(); void StartShutdown(bool skipupdates = false); @@ -170,6 +173,10 @@ private slots: void SessionEnding(); + // Clipboard + void handleClipboard(QClipboard::Mode mode); + void storeClipboard(QString text, QClipboard::Mode mode); + signals: //System Tray Signals void VisualTrayAvailable(); //new Visual Tray Plugin can be registered diff --git a/src-qt5/core/lumina-desktop/fluxboxconf/fluxbox-keys b/src-qt5/core/lumina-desktop/fluxboxconf/fluxbox-keys index d3ee64ef..82d31e9c 100644 --- a/src-qt5/core/lumina-desktop/fluxboxconf/fluxbox-keys +++ b/src-qt5/core/lumina-desktop/fluxboxconf/fluxbox-keys @@ -49,16 +49,10 @@ OnTitlebar Mouse3 :WindowMenu # alt-tab Mod1 Tab :NextWindow (workspace=[current]) (workspace=[current]) !! FBCV13 !! Mod1 Shift Tab :PrevWindow (workspace=[current]) (workspace=[current]) !! FBCV13 !! -Control Tab :NextGroup (workspace=[current]) (workspace=[current]) -Control Shift Tab :PrevGroup (workspace=[current]) (workspace=[current]) - -# cycle through tabs in the current window -Mod4 Tab :NextTab -Mod4 Shift Tab :PrevTab # Arrange/Tile Current windows -Mod1 Left :ArrangeWindowsStackRight (Layer=Normal) -Mod1 Right :ArrangeWindowsStackLeft (Layer=Normal) +Mod1 Control Left :ArrangeWindowsStackRight (Layer=Normal) +Mod1 Control Right :ArrangeWindowsStackLeft (Layer=Normal) # go to a specific tab in the current window Mod4 1 :Tab 1 @@ -84,14 +78,6 @@ Mod1 F9 :If {Matches (Layer=Normal)} {Minimize} Mod1 F10 :If {Matches (Layer=Normal)} {Maximize} Mod1 F11 :If {Matches (Layer=Normal)} {Fullscreen} -# send the current window to previous/next workspace -Mod4 Left :If {Matches (Layer=Normal)} {SendToPrevWorkspace} -Mod4 Right :If {Matches (Layer=Normal)} {SendToNextWorkspace} - -# send the current window and follow it to previous/next workspace -Control Mod4 Left :If {Matches (Layer=Normal)} {TakeToPrevWorkspace} -Control Mod4 Right :If {Matches (Layer=Normal)} {TakeToNextWorkspace} - # change to a specific workspace Control F1 :Workspace 1 Control F2 :Workspace 2 @@ -109,9 +95,9 @@ Control F12 :Workspace 12 Control Mod1 Left :PrevWorkspace Control Mod1 Right :NextWorkspace -# Control + MouseWheel to change workspaces -Control Mouse4 :PrevWorkspace -Control Mouse5 :NextWorkspace +# Control+Alt + MouseWheel to change workspaces +Control Mod1 Mouse4 :PrevWorkspace +Control Mod1 Mouse5 :NextWorkspace # send the current window to a specific workspace Mod4 F1 :SendToWorkspace 1 @@ -152,3 +138,4 @@ Mod1 Home :Exec lumina-open -brightnessup Mod1 End :Exec lumina-open -brightnessdown F12 :Exec lumina-terminal -toggle 115 :Exec lumina-desktop --show-start +Mod4 space :Exec lumina-desktop --show-start diff --git a/src-qt5/core/lumina-desktop/lumina-desktop.pro b/src-qt5/core/lumina-desktop/lumina-desktop.pro index e36d11a2..cc4b63ae 100644 --- a/src-qt5/core/lumina-desktop/lumina-desktop.pro +++ b/src-qt5/core/lumina-desktop/lumina-desktop.pro @@ -69,9 +69,7 @@ RESOURCES+= Lumina-DE.qrc desktop.path = $${L_SESSDIR} desktop.files = Lumina-DE.desktop -icons.files = Lumina-DE.png \ - Insight-FileManager.png -icons.path = $${L_SHAREDIR}/pixmaps +icons.files = Lumina-DE.png fluxconf.files = fluxboxconf/fluxbox-init-rc \ fluxboxconf/fluxbox-keys diff --git a/src-qt5/core/lumina-session/session.cpp b/src-qt5/core/lumina-session/session.cpp index 743fc396..0f0a99eb 100644 --- a/src-qt5/core/lumina-session/session.cpp +++ b/src-qt5/core/lumina-session/session.cpp @@ -42,7 +42,7 @@ void LSession::procFinished(){ if(PROCS[i]->objectName()=="runtime"){ qDebug() << "Got Desktop Process Finished:" << PROCS[i]->exitCode(); //if(PROCS[i]->exitCode()==787){ PROCS[i]->start(QIODevice::ReadOnly); } //special internal restart code - //else{ + //else{ stopall(); //} }else if(PROCS[i]->objectName()=="wm" && wmfails<2){ wmfails++; PROCS[i]->start(QIODevice::ReadOnly); wmTimer->start(); } //restart the WM //if(PROCS[i]->program().section("/",-1) == "lumina-desktop"){ stopall(); } //start closing down everything @@ -53,14 +53,29 @@ void LSession::procFinished(){ } //qDebug() << " - Final Count:" << stopped << stopping; if(stopping || stopped==PROCS.length()){ + //Note about compton: It does not like running multiple sessions under the *same user* + // (even on different displays). Run a blanket killall on it when closing down so that + // any other Lumina sessions will automatically restart compton on that specific display + QProcess::execute("killall compton"); QCoreApplication::exit(0); + }else{ + //Make sure we restart the process as needed + for(int i=0; i<PROCS.length(); i++){ + if(PROCS[i]->state()==QProcess::NotRunning){ + //runtime/wm processes have special restart rules above + if(PROCS[i]->objectName()!="runtime" && PROCS[i]->objectName()!="wm"){ + PROCS[i]->start(QIODevice::ReadOnly); + } + } + } } } void LSession::startProcess(QString ID, QString command, QStringList watchfiles){ QString dir = QString(getenv("XDG_CONFIG_HOME"))+"/lumina-desktop/logs"; + QString display = QString(getenv("DISPLAY")).section(":",1,1); if(!QFile::exists(dir)){ QDir tmp(dir); tmp.mkpath(dir); } - QString logfile = dir+"/"+ID+".log"; + QString logfile = dir+"/"+ID+"_"+display+".log"; if(QFile::exists(logfile+".old")){ QFile::remove(logfile+".old"); } if(QFile::exists(logfile)){ QFile::rename(logfile,logfile+".old"); } @@ -86,6 +101,37 @@ void LSession::startProcess(QString ID, QString command, QStringList watchfiles) PROCS << proc; } +void LSession::setupCompositor(){ + //Compositing manager + QSettings settings("lumina-desktop","sessionsettings"); + if(settings.value("enableCompositing",false).toBool()){ + if(LUtils::isValidBinary("compton")){ + //Compton available - check the config file + QString set = QString(getenv("XDG_CONFIG_HOME"))+"/lumina-desktop/compton.conf"; + if(!QFile::exists(set)){ + if(QFile::exists(LOS::LuminaShare()+"/compton.conf")){ + QFile::copy(LOS::LuminaShare()+"/compton.conf", set); + } + } + //Auto-detect if GLX is available on the system and turn it on/off as needed + bool startcompton = true; + if(LUtils::isValidBinary("glxinfo")){ + bool hasAccel =! LUtils::getCmdOutput("glxinfo -B").filter("direct rendering:").filter("Yes").isEmpty(); + qDebug() << "Detected GPU Acceleration:" << hasAccel; + QStringList info = LUtils::readFile(set); + for(int i=0; i<info.length(); i++){ + if(info[i].section("=",0,0).simplified()=="backend"){ info[i] = QString("backend = \"")+ (hasAccel ? "glx" : "xrender")+"\""; break; } //replace this line + } + LUtils::writeFile(set, info, true); + if( !hasAccel && settings.value("compositingWithGpuAccelOnly",true).toBool() ){ startcompton = false; } + } + QString disp = getenv("DISPLAY"); + if(startcompton && QFile::exists(set)){ startProcess("compositing","compton -d "+disp+" --config \""+set+"\"", QStringList() << set); } + else if(startcompton){ startProcess("compositing","compton -d "+disp); } + }else if(LUtils::isValidBinary("xcompmgr") && !settings.value("compositingWithGpuAccelOnly",true).toBool() ){ startProcess("compositing","xcompmgr"); } + } +} + void LSession::start(bool unified){ //First check for a valid installation if(!LUtils::isValidBinary("lumina-desktop") ){ @@ -128,32 +174,7 @@ void LSession::start(bool unified){ startProcess("wm", cmd, QStringList() << confDir+"/fluxbox-init" << confDir+"/fluxbox-keys"); } //Compositing manager - QSettings settings("lumina-desktop","sessionsettings"); - if(settings.value("enableCompositing",false).toBool()){ - if(LUtils::isValidBinary("compton")){ - //Compton available - check the config file - QString set = QString(getenv("XDG_CONFIG_HOME"))+"/lumina-desktop/compton.conf"; - if(!QFile::exists(set)){ - if(QFile::exists(LOS::LuminaShare()+"/compton.conf")){ - QFile::copy(LOS::LuminaShare()+"/compton.conf", set); - } - } - //Auto-detect if GLX is available on the system and turn it on/off as needed - bool startcompton = true; - if(LUtils::isValidBinary("glxinfo")){ - bool hasAccel =! LUtils::getCmdOutput("glxinfo -B").filter("direct rendering:").filter("Yes").isEmpty(); - qDebug() << "Detected GPU Acceleration:" << hasAccel; - QStringList info = LUtils::readFile(set); - for(int i=0; i<info.length(); i++){ - if(info[i].section("=",0,0).simplified()=="backend"){ info[i] = QString("backend = \"")+ (hasAccel ? "glx" : "xrender")+"\""; break; } //replace this line - } - LUtils::writeFile(set, info, true); - if( !hasAccel && settings.value("compositingWithGpuAccelOnly",true).toBool() ){ startcompton = false; } - } - if(startcompton && QFile::exists(set)){ startProcess("compositing","compton --config \""+set+"\"", QStringList() << set); } - else if(startcompton){ startProcess("compositing","compton"); } - }else if(LUtils::isValidBinary("xcompmgr") && !settings.value("compositingWithGpuAccelOnly",true).toBool() ){ startProcess("compositing","xcompmgr"); } - } + setupCompositor(); } else { if(!LUtils::isValidBinary(WM)){ exit(1); @@ -166,6 +187,7 @@ void LSession::start(bool unified){ if(LUtils::isValidBinary("xscreensaver")){ startProcess("screensaver","xscreensaver -no-splash"); } }else{ //unified process + setupCompositor(); startProcess("runtime","lumina-desktop-unified"); } } diff --git a/src-qt5/core/lumina-session/session.h b/src-qt5/core/lumina-session/session.h index 3bbcbb8e..6f7f8e36 100644 --- a/src-qt5/core/lumina-session/session.h +++ b/src-qt5/core/lumina-session/session.h @@ -63,6 +63,8 @@ private: int wmfails; QTimer *wmTimer; + void setupCompositor(); + private slots: void stopall(); diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine-qtplugin/lthemeengineplatformtheme.cpp b/src-qt5/core/lumina-theme-engine/src/lthemeengine-qtplugin/lthemeengineplatformtheme.cpp index 789b3990..a6e05000 100644 --- a/src-qt5/core/lumina-theme-engine/src/lthemeengine-qtplugin/lthemeengineplatformtheme.cpp +++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine-qtplugin/lthemeengineplatformtheme.cpp @@ -7,6 +7,7 @@ #include <QTimer> #include <QIcon> #include <QRegExp> +#include <QWindow> #ifdef QT_WIDGETS_LIB #include <QStyle> diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine/lthemeengine.cpp b/src-qt5/core/lumina-theme-engine/src/lthemeengine/lthemeengine.cpp index cb491aa6..9ffe39f8 100644 --- a/src-qt5/core/lumina-theme-engine/src/lthemeengine/lthemeengine.cpp +++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine/lthemeengine.cpp @@ -61,7 +61,10 @@ QStringList lthemeengine::sharedStyleSheetPath(){ dirs << QString(getenv("XDG_CONFIG_HOME")); dirs << QString(getenv("XDG_CONFIG_DIRS")).split(":"); dirs << QString(getenv("XDG_DATA_DIRS")).split(":"); - for(int i=0; i<dirs.length(); i++){ dirs[i].append("/lthemeengine/qss/"); } + for(int i=0; i<dirs.length(); i++){ + if (!dirs[i].endsWith("/")){ dirs[i].append("/"); } + dirs[i].append("lthemeengine/qss/"); + } if(dirs.isEmpty()){ dirs << LTHEMEENGINE_DATADIR"/lthemeengine/qss/"; } //no XDG settings - use the hardcoded path return dirs; } @@ -75,7 +78,10 @@ QStringList lthemeengine::sharedDesktopStyleSheetPath(){ dirs << QString(getenv("XDG_CONFIG_HOME")); dirs << QString(getenv("XDG_CONFIG_DIRS")).split(":"); dirs << QString(getenv("XDG_DATA_DIRS")).split(":"); - for(int i=0; i<dirs.length(); i++){ dirs[i].append("/lthemeengine/desktop_qss/"); } + for(int i=0; i<dirs.length(); i++){ + if (!dirs[i].endsWith("/")){ dirs[i].append("/"); } + dirs[i].append("lthemeengine/desktop_qss/"); + } if(dirs.isEmpty()){ dirs << LTHEMEENGINE_DATADIR"/lthemeengine/desktop_qss/"; } //no XDG settings - use the hardcoded path return dirs; } @@ -89,7 +95,10 @@ QStringList lthemeengine::sharedColorSchemePath(){ dirs << QString(getenv("XDG_CONFIG_HOME")); dirs << QString(getenv("XDG_CONFIG_DIRS")).split(":"); dirs << QString(getenv("XDG_DATA_DIRS")).split(":"); - for(int i=0; i<dirs.length(); i++){ dirs[i].append("/lthemeengine/colors/"); } + for(int i=0; i<dirs.length(); i++){ + if (!dirs[i].endsWith("/")){ dirs[i].append("/"); } + dirs[i].append("lthemeengine/colors/"); + } if(dirs.isEmpty()){ dirs << LTHEMEENGINE_DATADIR"/lthemeengine/colors/"; } //no XDG settings - use the hardcoded path qDebug() << "Got Color Dirs:" << dirs; return dirs; diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine/qsspage.cpp b/src-qt5/core/lumina-theme-engine/src/lthemeengine/qsspage.cpp index 3140c553..72cde6b3 100644 --- a/src-qt5/core/lumina-theme-engine/src/lthemeengine/qsspage.cpp +++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine/qsspage.cpp @@ -239,26 +239,36 @@ void QSSPage::readSettings(){ void QSSPage::findStyleSheets(QStringList paths, QStringList enabled){ paths.removeDuplicates(); + std::reverse(enabled.begin(), enabled.end()); // reverse for proper order + QMap<int, QString> sortedStylesSheets; for(int i=0; i<paths.length(); i++){ if(!QFile::exists(paths[i])){ continue; } QDir dir(paths[i]); dir.setFilter(QDir::Files); dir.setNameFilters(QStringList() << "*.qss"); foreach (QFileInfo info, dir.entryInfoList()){ + if(enabled.contains(info.filePath())){ sortedStylesSheets[enabled.indexOf(info.filePath())] = info.filePath(); } + else{ + QListWidgetItem *item = new QListWidgetItem(info.fileName()); + item->setToolTip(info.filePath()); + item->setData(QSS_FULL_PATH_ROLE, info.filePath()); + item->setData(QSS_WRITABLE_ROLE, info.isWritable()); + m_ui->list_disabled->addItem(item); + } + } + } + QMapIterator<int, QString> i(sortedStylesSheets); + while (i.hasNext()) { + i.next(); + QFileInfo info(i.value()); + if (info.isFile()) { QListWidgetItem *item = new QListWidgetItem(info.fileName()); item->setToolTip(info.filePath()); item->setData(QSS_FULL_PATH_ROLE, info.filePath()); item->setData(QSS_WRITABLE_ROLE, info.isWritable()); - if( enabled.contains(info.filePath()) ){ m_ui->qssListWidget->addItem(item); } - else{ m_ui->list_disabled->addItem(item); } + m_ui->qssListWidget->addItem(item); } } - //Now ensure the priority of the items in the active list is correct - for(int i = 0; i < m_ui->qssListWidget->count(); ++i){ - QListWidgetItem *item = m_ui->qssListWidget->item(i); - int index = enabled.indexOf( item->data(QSS_FULL_PATH_ROLE).toString() ); - if(index>=0){ m_ui->qssListWidget->insertItem(index, item); }// item->move(m_ui->qssListWidget->count() - 1 - index); } - } m_ui->list_disabled->sortItems(Qt::AscendingOrder); } diff --git a/src-qt5/desktop-utils/lumina-fm/lumina-fm.pro b/src-qt5/desktop-utils/lumina-fm/lumina-fm.pro index b59aface..10502af1 100644 --- a/src-qt5/desktop-utils/lumina-fm/lumina-fm.pro +++ b/src-qt5/desktop-utils/lumina-fm/lumina-fm.pro @@ -58,7 +58,6 @@ FORMS += MainUI.ui \ OPWidget.ui icons.files = Insight-FileManager.png -icons.path = $${L_SHAREDIR}/pixmaps TRANSLATIONS = i18n/lumina-fm_af.ts \ |