1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
|
//===========================================
// Lumina-DE source code
// Copyright (c) 2012-2014, Ken Moore
// Available under the 3-clause BSD license
// See the LICENSE file for full details
//===========================================
#include "LSession.h"
#include <LuminaOS.h>
#include <Phonon/MediaObject>
#include <Phonon/AudioOutput>
#include <QThread>
//X includes (these need to be last due to Qt compile issues)
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/extensions/Xrender.h>
//Private/global variables (for static function access)
//static WId LuminaSessionTrayID;
static AppMenu *appmenu;
static SettingsMenu *settingsmenu;
static QTranslator *currTranslator;
static Phonon::MediaObject *mediaObj;
static Phonon::AudioOutput *audioOut;
static QThread *audioThread;
static QSettings *sessionsettings;
LSession::LSession(int &argc, char ** argv) : QApplication(argc, argv){
this->setApplicationName("Lumina Desktop Environment");
this->setApplicationVersion("0.6.3");
this->setOrganizationName("LuminaDesktopEnvironment");
this->setQuitOnLastWindowClosed(false); //since the LDesktop's are not necessarily "window"s
//Enabled a few of the simple effects by default
this->setEffectEnabled( Qt::UI_AnimateMenu, true);
this->setEffectEnabled( Qt::UI_AnimateCombo, true);
this->setEffectEnabled( Qt::UI_AnimateTooltip, true);
this->setStyle( new MenuProxyStyle); //QMenu icon size override
//LuminaSessionTrayID = 0;
}
LSession::~LSession(){
WM->stopWM();
for(int i=0; i<DESKTOPS.length(); i++){
delete DESKTOPS[i];
}
delete WM;
delete settingsmenu;
delete appmenu;
delete currTranslator;
delete mediaObj;
delete audioOut;
}
void LSession::setupSession(){
qDebug() << "Initializing Session";
//Load the stylesheet
loadStyleSheet();
//Setup the QSettings default paths
QSettings::setPath(QSettings::NativeFormat, QSettings::UserScope, QDir::homePath()+"/.lumina");
sessionsettings = new QSettings("LuminaDE", "sessionsettings");
//Setup the user's lumina settings directory as necessary
checkUserFiles(); //adds these files to the watcher as well
//Initialize the internal variables
DESKTOPS.clear();
//Launch Fluxbox
qDebug() << " - Launching Fluxbox";
WM = new WMProcess();
WM->startWM();
//Initialize the desktops
updateDesktops();
//Initialize the global menus
qDebug() << " - Initialize system menus";
appmenu = new AppMenu();
settingsmenu = new SettingsMenu();
/*//Setup the audio output systems for the desktop
qDebug() << " - Initialize audio systems";
mediaObj = new Phonon::MediaObject(0);
audioOut = new Phonon::AudioOutput(Phonon::MusicCategory,0);
qDebug() << " -- Initialize new audio thread";
audioThread = new QThread(this);
if(mediaObj && audioOut){ //in case Phonon errors for some reason
qDebug() << " -- Create path between audio objects";
Phonon::createPath(mediaObj, audioOut);
qDebug() << " -- Move audio objects to separate thread";
mediaObj->moveToThread(audioThread);
audioOut->moveToThread(audioThread);
}*/
//Now setup the system watcher for changes
qDebug() << " - Initialize file system watcher";
watcher = new QFileSystemWatcher(this);
watcher->addPath( QDir::homePath()+"/.lumina/stylesheet.qss" );
//watcher->addPath( QDir::homePath()+"/.lumina/LuminaDE/desktopsettings.conf" );
watcher->addPath( QDir::homePath()+"/.lumina/fluxbox-init" );
watcher->addPath( QDir::homePath()+"/.lumina/fluxbox-keys" );
//connect internal signals/slots
connect(this->desktop(), SIGNAL(screenCountChanged(int)), this, SLOT(updateDesktops()) );
connect(watcher, SIGNAL(directoryChanged(QString)), this, SLOT(watcherChange(QString)) );
connect(watcher, SIGNAL(fileChanged(QString)), this, SLOT(watcherChange(QString)) );
connect(this, SIGNAL(aboutToQuit()), this, SLOT(SessionEnding()) );
}
bool LSession::LoadLocale(QString langCode){
QTranslator translator;
if ( ! QFile::exists(LOS::LuminaShare()+"i18n/lumina-desktop_" + langCode + ".qm" ) ) langCode.truncate(langCode.indexOf("_"));
bool ok = translator.load( QString("lumina-desktop_") + langCode, LOS::LuminaShare()+"i18n/" );
if(ok){
//Remove any old translator
if(currTranslator != 0){ this->removeTranslator(currTranslator); }
//Insert the new translator
currTranslator = &translator;
this->installTranslator( currTranslator );
qDebug() << "Loaded Locale:" << langCode;
}else{
qDebug() << "Invalid Locale:" << langCode;
}
emit LocaleChanged();
return ok;
}
void LSession::launchStartupApps(){
//First start any system-defined startups, then do user defined
qDebug() << "Launching startup applications";
for(int i=0; i<2; i++){
QString startfile;
if(i==0){startfile = LOS::LuminaShare()+"startapps"; }
else{ startfile = QDir::homePath()+"/.lumina/startapps"; }
if(!QFile::exists(startfile)){ continue; } //go to the next
QFile file(startfile);
if( file.open(QIODevice::ReadOnly | QIODevice::Text) ){
QTextStream in(&file);
while(!in.atEnd()){
QString entry = in.readLine();
if(entry.startsWith("#") || entry.isEmpty()){ continue; }
//Might put other sanity checks here
qDebug() << " - Starting Application:" << entry;
LSession::LaunchApplication(entry);
}
file.close();
}
}
//Now play the login music
if(sessionsettings->value("PlayStartupAudio",true).toBool()){
LSession::playAudioFile(LOS::LuminaShare()+"Login.ogg");
}
if(sessionsettings->value("EnableNumlock",true).toBool()){
QProcess::startDetached("numlockx on");
}
}
void LSession::watcherChange(QString changed){
qDebug() << "Session Watcher Change:" << changed;
if(changed.endsWith("stylesheet.qss")){ loadStyleSheet(); }
else if(changed.endsWith("fluxbox-init") || changed.endsWith("fluxbox-keys")){ refreshWindowManager(); }
else{ emit DesktopConfigChanged(); }
}
void LSession::checkUserFiles(){
//version conversion examples: [1.0.0 -> 100], [1.2.0 -> 120], [0.6.0 -> 60]
int oldversion = sessionsettings->value("DesktopVersion",0).toString().remove(".").toInt();
bool newversion = ( oldversion < this->applicationVersion().remove(".").toInt() );
//Check for the desktop settings file
QString dset = QDir::homePath()+"/.lumina/LuminaDE/desktopsettings.conf";
bool firstrun = false;
if(!QFile::exists(dset) || oldversion < 50){
if( oldversion < 50 ){ QFile::remove(dset); qDebug() << "Current desktop settings obsolete: Re-implementing defaults"; }
else{ firstrun = true; }
if(QFile::exists(LOS::LuminaShare()+"desktopsettings.conf")){
if( QFile::copy(LOS::LuminaShare()+"desktopsettings.conf", dset) ){
QFile::setPermissions(dset, QFile::ReadUser | QFile::WriteUser | QFile::ReadOwner | QFile::WriteOwner);
}
}
}
//Check for the default applications file for lumina-open
dset = QDir::homePath()+"/.lumina/LuminaDE/lumina-open.conf";
if(!QFile::exists(dset)){
firstrun = true;
if(QFile::exists(LOS::LuminaShare()+"defaultapps.conf")){
if( QFile::copy(LOS::LuminaShare()+"defaultapps.conf", dset) ){
QFile::setPermissions(dset, QFile::ReadUser | QFile::WriteUser | QFile::ReadOwner | QFile::WriteOwner);
}
}
}
//Check the fluxbox configuration files
dset = QDir::homePath()+"/.lumina/";
bool fluxcopy = false;
if(!QFile::exists(dset+"fluxbox-init")){ fluxcopy=true; }
else if(!QFile::exists(dset+"fluxbox-keys")){fluxcopy=true; }
else if(oldversion < 60){ fluxcopy=true; qDebug() << "Current fluxbox settings obsolete: Re-implementing defaults"; }
if(fluxcopy){
if(QFile::exists(dset+"fluxbox-init")){ QFile::remove(dset+"fluxbox-init"); }
if(QFile::exists(dset+"fluxbox-keys")){ QFile::remove(dset+"fluxbox-keys"); }
QFile::copy(":/fluxboxconf/fluxbox-init-rc", dset+"fluxbox-init");
QFile::copy(":/fluxboxconf/fluxbox-keys", dset+"fluxbox-keys");
QFile::setPermissions(dset+"fluxbox-init", QFile::ReadOwner | QFile::WriteOwner | QFile::ReadUser | QFile::ReadOther | QFile::ReadGroup);
QFile::setPermissions(dset+"fluxbox-keys", QFile::ReadOwner | QFile::WriteOwner | QFile::ReadUser | QFile::ReadOther | QFile::ReadGroup);
}
if(firstrun){ qDebug() << "First time using Lumina!!"; }
else if(newversion){
qDebug() << "Updating session file to current version";
}
//Save the current version of the session to the settings file (for next time)
sessionsettings->setValue("DesktopVersion", this->applicationVersion());
}
void LSession::loadStyleSheet(){
QString ss = QDir::homePath()+"/.lumina/stylesheet.qss";
if(!QFile::exists(ss)){ ss = LOS::LuminaShare()+"stylesheet.qss"; }
if(!QFile::exists(ss)){ return; } //no default stylesheet on the system
//Now read/apply the custom stylesheet
QFile file(ss);
if( file.open(QIODevice::ReadOnly | QIODevice::Text) ){
QTextStream in(&file);
QString sheet = in.readAll();
file.close();
//Now fix/apply the sheet
sheet.replace("\n"," "); //make sure there are no newlines
this->setStyleSheet(sheet);
}
}
void LSession::refreshWindowManager(){
WM->updateWM();
}
void LSession::updateDesktops(){
qDebug() << " - Update Desktops";
QDesktopWidget *DW = this->desktop();
for(int i=0; i<DW->screenCount(); i++){
bool found = false;
for(int j=0; j<DESKTOPS.length() && !found; j++){
if(DESKTOPS[j]->Screen()==i){ found = true; }
}
if(!found){
//Start the desktop on the new screen
qDebug() << " - Start desktop on screen:" << i;
DESKTOPS << new LDesktop(i);
}
}
//Now go through and make sure to delete any desktops for detached screens
for(int i=0; i<DESKTOPS.length(); i++){
if(DESKTOPS[i]->Screen() >= DW->screenCount()){
qDebug() << " - Hide desktop on screen:" << DESKTOPS[i]->Screen();
DESKTOPS[i]->hide();
}else{
DESKTOPS[i]->show();
}
}
}
void LSession::SessionEnding(){
audioThread->wait(3000); //wait a max of 3 seconds for the audio thread to finish
}
bool LSession::x11EventFilter(XEvent *event){
//Detect X Event types and send the appropriate signal(s)
emit TrayEvent(event); //Make sure the tray also can check this event
switch(event->type){
// -------------------------
case PropertyNotify:
//qDebug() << "Property Event:";
if(event->xproperty.atom == XInternAtom(QX11Info::display(),"_NET_CLIENT_LIST",false) \
|| event->xproperty.atom == XInternAtom(QX11Info::display(),"_NET_ACTIVE_WINDOW",false) \
|| event->xproperty.atom == XInternAtom(QX11Info::display(),"_NET_WM_NAME",false) \
|| event->xproperty.atom == XInternAtom(QX11Info::display(),"_NET_WM_VISIBLE_NAME",false) \
|| event->xproperty.atom == XInternAtom(QX11Info::display(),"_NET_WM_ICON_NAME",false) \
|| event->xproperty.atom == XInternAtom(QX11Info::display(),"_NET_WM_STATE",false) \
|| event->xproperty.atom == XInternAtom(QX11Info::display(),"_NET_WM_VISIBLE_ICON_NAME",false) ){
LSession::restoreOverrideCursor(); //restore the mouse cursor back to normal (new window opened?)
emit WindowListEvent();
}
break;
}
// -----------------------
//Now continue on with the event handling (don't change it)
return false;
}
//===============
// SYSTEM ACCESS
//===============
void LSession::LaunchApplication(QString cmd){
LSession::setOverrideCursor(QCursor(Qt::BusyCursor));
QProcess::startDetached(cmd);
}
AppMenu* LSession::applicationMenu(){
return appmenu;
}
SettingsMenu* LSession::settingsMenu(){
return settingsmenu;
}
QSettings* LSession::sessionSettings(){
return sessionsettings;
}
void LSession::systemWindow(){
SystemWindow win;
win.exec();
LSession::processEvents();
}
//Play System Audio
void LSession::playAudioFile(QString filepath){
//Setup the audio output systems for the desktop
bool init = false;
if(audioThread==0){ qDebug() << " - Initialize audio systems"; audioThread = new QThread(); init = true; }
if(mediaObj==0){ qDebug() << " - Initialize Phonon media Object"; mediaObj = new Phonon::MediaObject(); init = true;}
//if(audioOut==0){ qDebug() << " - Initialize Phonon audio output"; audioOut = new Phonon::AudioOutput(); init=true;}
if(mediaObj && audioOut && init){ //in case Phonon errors for some reason
qDebug() << " -- Create path between audio objects";
Phonon::createPath(mediaObj, audioOut);
qDebug() << " -- Move audio objects to separate thread";
mediaObj->moveToThread(audioThread);
audioOut->moveToThread(audioThread);
}
if(mediaObj !=0 && audioOut!=0){
mediaObj->setCurrentSource(QUrl(filepath));
mediaObj->play();
audioThread->start();
}
}
|