A lot of hot codegit add *
[on:on.git] / shell / on.cpp
1     #include "on.h"
2
3 On::On(QWidget *parent)
4     : QWebView(parent)
5 {
6     setWindow();
7     setWebSettings();
8     setBackground();
9     setUrl(QUrl("/usr/share/on/shell/index.html"));
10     setNative();
11     connect(page()->mainFrame(), SIGNAL(javaScriptWindowObjectCleared()), this, SLOT(setNative()));
12     setWatchers();
13 }
14
15 On::~On()
16 {
17
18 }
19
20 QString On::release() { return QString("Asturix On PreAlpha"); }
21
22 QString On::username() { return QDir::homePath().remove("/home/"); }
23
24 QString On::userDir(int dir) { return QDesktopServices::storageLocation(QDesktopServices::StandardLocation(dir)); }
25
26 QString On::userDirName(int dir) { return QDesktopServices::displayName(QDesktopServices::StandardLocation(dir)); }
27
28 QString On::lang() {
29     QString lang = QLocale::system().name().split("_").first();
30     if (lang == "C") {
31         lang = "en";
32     }
33     return lang;
34 }
35
36 // Set the window that is going to be the whole desktop
37 void On::setWindow()
38 {
39
40     if(getenv("QT_GRAPHICSSYSTEM") == 0) {
41         QApplication::setGraphicsSystem("raster");
42     }
43
44     QDesktopWidget* desktop = QApplication::desktop();
45     const QRect screen = desktop->screenGeometry(this);
46
47     static Atom atom = XInternAtom(QX11Info::display(), "_NET_WM_DESKTOP", False);
48     ulong data[1];
49     data[0] = 0xFFFFFFFF;
50     XChangeProperty(QX11Info::display(), winId(), atom, atom, 32, PropModeReplace, (unsigned char *) data, 1);
51
52     setWindowFlags(Qt::WindowStaysOnBottomHint);
53     setAttribute(Qt::WA_X11NetWmWindowTypeDesktop);
54     //showMaximized();
55
56     setGeometry(0, 24, desktop->width(), desktop->height());
57
58     if (QX11Info::isCompositingManagerRunning()) {
59         setAttribute(Qt::WA_TranslucentBackground);
60     } else {
61         setAutoFillBackground(true);
62     }
63
64     //setContextMenuPolicy(Qt::NoContextMenu);
65 }
66
67 // Set some things of WebKit
68 void On::setWebSettings() {
69     QSettings cfg(QSettings::IniFormat, QSettings::UserScope, "asturix", "on");
70     QString cfgDir = QFileInfo(cfg.fileName()).absolutePath() + "/";
71     settings()->setLocalStoragePath(cfgDir);
72     settings()->setIconDatabasePath(cfgDir);
73     settings()->setOfflineStoragePath(cfgDir);
74     settings()->setAttribute(QWebSettings::AcceleratedCompositingEnabled, true);
75     settings()->setAttribute(QWebSettings::JavascriptCanAccessClipboard, true);
76     settings()->setAttribute(QWebSettings::LocalContentCanAccessFileUrls, true);
77     settings()->setAttribute(QWebSettings::LocalContentCanAccessRemoteUrls, true);
78     settings()->setAttribute(QWebSettings::LocalStorageEnabled, true);
79     settings()->setAttribute(QWebSettings::LocalStorageDatabaseEnabled, true);
80     settings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true);
81 }
82
83 // Add this to the Javascript window object so this can be accessed from web code
84 void On::setNative() {
85     page()->mainFrame()->addToJavaScriptWindowObject("native", this);
86 }
87
88 // Set the background
89 // TODO: Bind to the Dconf property so if the user changes the background On changes it too
90 // TODO: Notify On if the background changed
91 // NOTE: The background is controlled by Qt because setting it as a CSS background is too slow
92 void On::setBackground() {
93     //QConf *backgroundConf = new QConf("org.gnome.desktop.background")
94     //backgroundConf->notify("picture-uri");
95     GSettings *backgroundSettings = g_settings_new("org.gnome.desktop.background");
96     QString bg = QString(g_variant_get_string(g_settings_get_value(backgroundSettings, "picture-uri"), 0));
97     QPalette p = palette();
98     QRect rect = this->rect();
99     if (!bg.isEmpty()) {
100         bg = bg.remove("file://");
101         QPixmap background(QFileInfo(bg).canonicalFilePath());
102         QSize size(rect.width(), rect.height());
103         QPixmap pixmap(background.scaled(size));
104         p.setBrush(QPalette::Background, pixmap);
105         // TODO: Modes. picture-options: zoom, fill, span, scale, center, tile
106     } else {
107         QColor primColor(g_variant_get_string(g_settings_get_value(backgroundSettings, "primary-color"), 0));
108         QColor secColor(g_variant_get_string(g_settings_get_value(backgroundSettings, "secondary-color"), 0));
109         QString mode = QString(g_variant_get_string(g_settings_get_value(backgroundSettings, "color-shading-type"), 0));
110         QBrush brush;
111         if (mode == "solid") {
112             brush = QBrush(primColor);
113         } else if (mode == "vertical") {
114             QLinearGradient grad(QPointF(0, 0), QPointF(0, rect.height()));
115             grad.setColorAt(0, primColor);
116             grad.setColorAt(1, secColor);
117             brush = QBrush(grad);
118         } else {
119             QLinearGradient grad(QPointF(0, 0), QPointF(rect.width(), 0));
120             grad.setColorAt(0, primColor);
121             grad.setColorAt(1, secColor);
122             brush = QBrush(grad);
123         }
124         p.setBrush(QPalette::Background, brush);
125     }
126     setPalette(p);
127     p.setBrush(QPalette::Base, Qt::transparent);
128     page()->setPalette(p);
129     setAttribute(Qt::WA_OpaquePaintEvent, false);
130     g_object_unref(backgroundSettings);
131 }
132
133 // Return a string list with file uri and mode
134 QStringList On::getBackground() {
135     GSettings *background = g_settings_new("org.gnome.desktop.background");
136     QString bg = QString(g_variant_get_string(g_settings_get_value(background, "picture-uri"), 0));
137     QString mode;
138     if (!bg.isEmpty()) {
139         mode = QString(g_variant_get_string(g_settings_get_value(background, "picture-options"), 0));
140         bg = "url('"+bg+"')";
141     } else {
142         QColor primColor = QColor(g_variant_get_string(g_settings_get_value(background, "primary-color"), 0));
143         QColor secColor = QColor(g_variant_get_string(g_settings_get_value(background, "secondary-color"), 0));
144         bg = primColor.name() + "," + secColor.name();
145         mode = QString(g_variant_get_string(g_settings_get_value(background, "color-shading-type"), 0));
146     }
147     g_object_unref(background);
148     return (QStringList() << bg << mode);
149 }
150
151 QStringList On::appsMenu() {
152     return apps;
153 }
154
155 void On::setAppsMenu(QStringList list) {
156     apps = list;
157 }
158
159 // Build the apps menu in different thread
160 void On::getAppsMenuAsync() {
161     QFuture<QStringList> future = QtConcurrent::run(this, &On::getAppsMenu);
162     QStringList apps = future.result();
163     setAppsMenu(apps);
164     page()->mainFrame()->evaluateJavaScript("refreshAppsMenu();");
165 }
166
167 // Get Chromium bookmarks
168 QString On::getBookmarks() {
169     QFile file(QDir::homePath()+"/.config/chromium/Default/Bookmarks");
170     if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
171         QString contents;
172         while (!file.atEnd()) {
173             QByteArray line = file.readLine();
174             contents.append(line);
175         }
176         return contents;
177     }
178     return QString();
179 }
180
181 // Build the bookmarks list in different thread
182 // UNUSED
183 // TODO: Use it
184 void On::getBookmarksAsync() {
185     QFuture<QString> future = QtConcurrent::run(this, &On::getBookmarks);
186     QString bookmarks = future.result();
187     page()->mainFrame()->evaluateJavaScript("refreshPlacesMenu();");
188 }
189
190 // Get Chromium bookmarks
191 QString On::getFirefoxBookmarks() {
192     QFile file(QDir::homePath()+"/.mozilla/firefox/gcf8epya.default/bookmarkbackups/bookmarks-2011-07-05.json");
193     file.open(QIODevice::ReadOnly | QIODevice::Text);
194     QString contents;
195     while (!file.atEnd()) {
196         QByteArray line = file.readLine();
197         contents.append(line);
198     }
199     return contents;
200 }
201
202 // Build the bookmarks list in different thread
203 // UNUSED
204 // TODO: Use it
205 void On::getFirefoxBookmarksAsync() {
206     QFuture<QString> future = QtConcurrent::run(this, &On::getFirefoxBookmarks);
207     QString bookmarks = future.result();
208     page()->mainFrame()->evaluateJavaScript("refreshPlacesMenu();");
209 }
210
211 // Return a string list with 0: appname 1: appicon 2: appexec
212 QStringList On::getAppsMenu() {
213     QDirIterator walker("/usr/share/applications", QStringList("*.desktop"), QDir::AllEntries, QDirIterator::Subdirectories);
214     QStringList apps;
215     g_desktop_app_info_set_desktop_env(release().toAscii());
216     while(walker.hasNext()) {
217         qDebug(walker.next().toAscii());
218         GAppInfo* appInfo = (GAppInfo*)g_desktop_app_info_new(walker.fileName().toAscii());
219         if (g_app_info_should_show(appInfo)) {
220             QString name = getAppName(walker.fileName());
221             QString icon = getAppIcon(walker.fileName());
222             QString exec = getAppExec(walker.fileName());
223             //if (!name.isEmpty() && !icon.isEmpty() && !exec.isEmpty()) {
224                 apps.append(name);
225                 apps.append(icon);
226                 apps.append(exec);
227             //}
228         }
229         g_object_unref(appInfo);
230     }
231     return apps;
232 }
233
234 // Get the app name of a desktop entry
235 QString On::getAppName(QString app) {
236     GAppInfo* appInfo = (GAppInfo*)g_desktop_app_info_new(app.toAscii());
237     //QString a = QString::fromUtf8(g_app_info_get_name(appInfo));
238     QString a = QString::fromUtf8(g_app_info_get_display_name(appInfo));
239     g_object_unref(appInfo);
240     return a;
241 }
242
243 // Get the description name of a desktop entry
244 QString On::getAppDescription(QString app) {
245     GAppInfo* appInfo = (GAppInfo*)g_desktop_app_info_new(app.toAscii());
246     QString a = g_app_info_get_description(appInfo);
247     g_object_unref(appInfo);
248     return a;
249 }
250
251 // Get the base64 of the app icon of a desktop entry
252 QString On::getAppIcon(QString app) {
253     GAppInfo* appInfo = (GAppInfo*)g_desktop_app_info_new(app.toAscii());
254     GIcon *g_icon = g_app_info_get_icon(appInfo);
255     GtkIconInfo *icon_info = gtk_icon_theme_lookup_by_gicon(gtk_icon_theme_get_default(), g_icon, 48, (GtkIconLookupFlags)0);
256     GdkPixbuf *pixbuf = gtk_icon_info_load_icon(icon_info, NULL);
257     gtk_icon_info_free(icon_info);
258     g_object_unref(g_icon);
259
260     if (pixbuf == NULL) {
261         return QString();
262     }
263
264     QImage image(gdk_pixbuf_get_pixels(pixbuf),
265                    gdk_pixbuf_get_width(pixbuf),
266                    gdk_pixbuf_get_height(pixbuf),
267                    gdk_pixbuf_get_rowstride(pixbuf),
268                    QImage::Format_ARGB32);
269     QImage swappedImage = image.rgbSwapped();
270
271     QByteArray byteArray;
272     QBuffer buffer(&byteArray);
273     swappedImage.save(&buffer, "PNG");
274     QString iconBase64 = QString::fromLatin1(byteArray.toBase64().data());
275
276     g_object_unref(pixbuf);
277     g_object_unref(appInfo);
278
279     return iconBase64;
280 }
281
282 // Get the categories of a desktop entry
283 // TODO: GIO doesn't provide a method to do that. Look for a form to retrieve categories
284 QString On::getAppCategories(QString app) {
285     GAppInfo* appInfo = (GAppInfo*)g_desktop_app_info_new(app.toAscii());
286     QString a = /*g_desktop_app_info_get_categories(appInfo)*/"s";
287     g_object_unref(appInfo);
288     return a;
289 }
290
291 // Get the command to execute of a desktop entry
292 QString On::getAppExec(QString app) {
293     //GAppInfo* appInfo = (GAppInfo*)g_desktop_app_info_new_from_filename(QString("/usr/share/applications/"+app).toAscii());
294     GAppInfo* appInfo = (GAppInfo*)g_desktop_app_info_new(app.toAscii());
295     QString a = g_app_info_get_commandline(appInfo);
296     a.remove("%u", Qt::CaseInsensitive);
297     a.remove("%f", Qt::CaseInsensitive);
298     return a;
299 }
300
301 // Get the base64 of the theme icon
302 QString On::getThemeIcon(QString icon) {
303     GtkIconInfo *iconInfo;
304     if (icon.contains("/") && !QFile::exists(icon)) {
305         iconInfo = gtk_icon_theme_lookup_icon(gtk_icon_theme_get_default(), "application-default-icon", 48, (GtkIconLookupFlags)0);
306         icon = gtk_icon_info_get_filename(iconInfo);
307     } else {
308         iconInfo = gtk_icon_theme_lookup_icon(gtk_icon_theme_get_default(), icon.toAscii(), 48, (GtkIconLookupFlags)0);
309         icon = gtk_icon_info_get_filename(iconInfo);
310     }
311     GdkPixbuf *pixbuf = gtk_icon_info_load_icon(iconInfo, NULL);
312     gtk_icon_info_free(iconInfo);
313
314     if (pixbuf == NULL) {
315         return QString();
316     }
317
318     QImage image(gdk_pixbuf_get_pixels(pixbuf),
319                    gdk_pixbuf_get_width(pixbuf),
320                    gdk_pixbuf_get_height(pixbuf),
321                    gdk_pixbuf_get_rowstride(pixbuf),
322                    QImage::Format_ARGB32);
323     QImage swappedImage = image.rgbSwapped();
324
325     QByteArray byteArray;
326     QBuffer buffer(&byteArray);
327     swappedImage.save(&buffer, "PNG");
328     QString iconBase64 = QString::fromLatin1(byteArray.toBase64().data());
329
330     g_object_unref(pixbuf);
331
332     return iconBase64;
333 }
334
335
336 // Set some watchers so we can monitorize dirs, files etc.
337 void On::setWatchers() {
338     QFileSystemWatcher *appsWatcher = new QFileSystemWatcher;
339     appsWatcher->addPath("/usr/share/applications/");
340     appsWatcher->addPath(QDir::homePath()+"/.local/share/applications");
341     connect(appsWatcher, SIGNAL(directoryChanged(QString)), this, SLOT(appsChanged(QString)));
342
343     // TODO: Add Firefox & other browser support
344     QFileSystemWatcher *bookmarksWatcher = new QFileSystemWatcher;
345     bookmarksWatcher->addPath(QDir::homePath()+"/.config/chromium/Default/Bookmarks");
346     connect(bookmarksWatcher, SIGNAL(directoryChanged(QString)), this, SLOT(bookmarksChanged(QString)));
347 }
348
349 // Execute code when the /usr/share/applications dir is modified
350 // NOTE: We have to do it because Glib is not compatible with signals, so we can't define new signals
351 void On::appsChanged(QString path) {
352     getAppsMenuAsync();
353 }
354
355 // Execute code when the bookmarks dir is modified
356 void On::bookmarksChanged(QString path) {
357     getBookmarksAsync();
358 }
359
360 // Execute a command
361 // NOTE: The buffer of the process is being read and shown
362 void On::exec(QString exec) {
363     /*QProcess proc;
364     proc.start("/bin/sh -c \""+exec+"\"");*/
365     QProcess::startDetached("/bin/sh -c \""+exec+"\"");
366 }
367
368 // Get widget list
369 QStringList On::widgetList() {
370     return widgets;
371 }
372
373 void On::setWidgetList(QStringList list) {
374     widgets = list;
375 }
376
377 // Get widget list
378 QStringList On::getWidgetList() {
379     QDirIterator walker("/usr/share/on/shell/widgets", QStringList("*.json"), QDir::AllEntries, QDirIterator::Subdirectories);
380     QStringList widgets;
381     while(walker.hasNext()) {
382         qDebug(walker.next().toAscii());
383         QString id = walker.fileName().remove(".json");
384         //widgets.append(id);
385         QFile file("/usr/share/on/shell/widgets/"+id+".json");
386         file.open(QIODevice::ReadOnly | QIODevice::Text);
387         QString contents;
388         while (!file.atEnd()) {
389             QByteArray line = file.readLine();
390             contents.append(line);
391         }
392         widgets.append(contents);
393     }
394     return widgets;
395 }
396
397 // Build the widget list in different thread<div id="ext-gen1029" class="x-scroller x-layout-box-inner x-layout-box" style="-webkit-box-orient: vertical; -webkit-box-direction: normal; -webkit-box-pack: start; min-height: 753px; width: 1280px; -webkit-transform: translate3d(0px, 0px, 0px); "><div id="ext-comp-1111" class=" x-container" style="margin-top: 20px; margin-right: 20px; margin-bottom: 20px; margin-left: 20px; "><div class="x-layout-box-inner x-layout-box" id="ext-gen1350" style="-webkit-box-orient: horizontal; -webkit-box-direction: normal; -webkit-box-pack: start; -webkit-box-align: center; min-width: 1240px; height: 0px; "></div></div></div>
398 void On::getWidgetListAsync() {
399     QFuture<QStringList> future = QtConcurrent::run(this, &On::getWidgetList);
400     QStringList widgets = future.result();
401     setWidgetList(widgets);
402     page()->mainFrame()->evaluateJavaScript("refreshWidgetList();");
403 }
404
405 void On::showNotification(QString title, QString content, QString themeIcon, int time) {
406     //QProcess::startDetached("notify-send "+title+" "+content+" -i "+themeIcon);
407
408     NotifyNotification *notif = notify_notification_new(title.toUtf8(), content.toUtf8(), themeIcon.toUtf8());
409     notify_notification_set_timeout(notif, time);
410     notify_notification_show(notif, NULL);
411     g_object_unref(notif);
412 }
413
414 void On::logout() {
415     //QProcess::startDetached("lxsession-logout");
416     QProcess::startDetached("gnome-session-quit --logout");
417     //close();
418 }