removed building of a test application for target 'all'
[simple-launcher] / simple-launcher.cc
1 // This file is a part of Simple Launcher
2 //
3 // Copyright (C) 2006, 2007, Mikhail Sobolev
4 //
5 // Simple Launcher is free software; you can redistribute it and/or modify it
6 // under the terms of the GNU General Public License version 2 as published by
7 // the Free Software Foundation.
8 //
9 // This program is distributed in the hope that it will be useful, but WITHOUT
10 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12 // more details.
13 //
14 // You should have received a copy of the GNU General Public License along with
15 // this program; if not, write to the Free Software Foundation, Inc., 51
16 // Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17
18 #include <string>
19 #include <vector>
20 #include <fstream>
21
22 #include <dirent.h>
23
24 #include <gtk/gtk.h>
25
26 #include <hildon-home-plugin/hildon-home-plugin-interface.h>
27 #include <libosso.h>
28
29 #include "launcher-item.h"
30 #include "sla-list.h"
31 #include "launchable-item.h"
32 #include "settings-dialog.h"
33 #include "gconf-wrapper.h"
34
35 #define SL_APPLET_DBUS_NAME  "simple-launcher"
36 #define SL_APPLET_VERSION    "0.0"
37
38 #define SL_APPLET_GCONF_PATH  "/apps/simple-launcher"
39
40 class SimpleLauncherApplet {
41 public:
42   SimpleLauncherApplet(const GConfKey&);
43  ~SimpleLauncherApplet();
44
45   bool doInit(void *state_data, int *state_size);
46
47   void background() {}
48   void foreground() {}
49   int saveState(void **state_data, int *state_size);
50   GtkWidget *settings(GtkWindow *parent);
51
52   GtkWidget *getWidget() { return myWidget; }
53
54 private:
55   static void addItem(LauncherItems&, const std::string&, bool);
56
57   void loadConfig();
58   void saveConfig();
59
60   static void updateItems(LauncherItems&);
61   static void processDirectory(LauncherItems&, const std::string&);
62
63   bool initWidget();
64   void updateWidget();
65
66   void buttonPressed(GtkWidget *button, GdkEventButton *event);
67   void runDialog();
68
69   static void _button_pressed(GtkWidget *button, GdkEventButton *event, void *self);
70   static void _run_dialog(GtkMenuItem *, void *);
71
72 private:
73   // GConfClientWrapper myClient;
74   // GConfKey myMainSettings;
75
76   osso_context_t *myContext;
77
78   GtkWidget *myWidget;
79   GtkWindow *myParent;
80
81   LauncherItems myItems;
82
83   GConfBooleanOption myTransparent;
84   // bool myShowInfobanner; // FIXME: to implement
85   GConfIntegerOption myIconSize;
86   GConfIntegerOption myCanvasSize;
87
88   static char *ourDirs[];
89 };
90
91 // Hildon home applet interface functions
92
93 void *hildon_home_applet_lib_initialize(void *state_data, int *state_size, GtkWidget **widget) {
94   GConfKey baseKey(SL_APPLET_GCONF_PATH);
95
96   SimpleLauncherApplet *applet = new SimpleLauncherApplet(baseKey);
97
98   if (applet != NULL) {
99     if (applet->doInit(state_data, state_size)) {
100       *widget = applet->getWidget();
101     } else {
102       delete applet;
103       applet = NULL;
104     }
105   }
106
107   return (void*)applet;
108 }
109
110 void hildon_home_applet_lib_deinitialize(void *applet_data) {
111   SimpleLauncherApplet *applet = (SimpleLauncherApplet *)applet_data;
112
113   delete applet;
114 }
115
116 void hildon_home_applet_lib_background(void *applet_data) {
117   ((SimpleLauncherApplet *)applet_data)->background();
118 }
119
120 void hildon_home_applet_lib_foreground (void *applet_data) {
121   ((SimpleLauncherApplet *)applet_data)->foreground();
122 }
123
124 GtkWidget *hildon_home_applet_lib_settings(void *applet_data, GtkWindow *parent) {
125   return ((SimpleLauncherApplet *)applet_data)->settings(parent);
126 }
127
128 int hildon_home_applet_lib_save_state (void *applet_data, void **state_data, int *state_size) {
129   return ((SimpleLauncherApplet *)applet_data)->saveState(state_data, state_size);
130 }
131
132 // SimpleLauncherApplet implementation
133
134 char *SimpleLauncherApplet::ourDirs[] = {
135   "/usr/share/applications/hildon",
136   NULL
137 };
138
139 // SimpleLauncherApplet::SimpleLauncherApplet() : myMainSettings(myClient.getKey(SL_APPLET_GCONF_PATH)), myContext(NULL), myWidget(NULL), myParent(NULL) {
140 SimpleLauncherApplet::SimpleLauncherApplet(const GConfKey& base) : myContext(NULL), myWidget(NULL), myParent(NULL), myTransparent(base, "transparent", true), myIconSize(base, "icon_size", 48), myCanvasSize(base, "canvas_size", 1) {
141 }
142
143 bool SimpleLauncherApplet::doInit(void *state_data, int *state_size) {
144   if ((myContext = osso_initialize(SL_APPLET_DBUS_NAME, SL_APPLET_VERSION, FALSE, NULL)) == NULL) {
145     g_debug("sla-applet: failed to initialize the osso layer");
146     return false;
147   }
148
149   loadConfig();
150
151   if (!initWidget()) {
152     return false;
153   }
154
155   return true;
156 }
157
158 SimpleLauncherApplet::~SimpleLauncherApplet() {
159   myItems.clear();
160
161   if (myWidget != NULL) {
162     gtk_widget_destroy(myWidget);
163     myWidget = NULL;
164   }
165
166   if (myContext != NULL) {
167     osso_deinitialize(myContext);
168     myContext = NULL;
169   }
170 }
171
172 void SimpleLauncherApplet::addItem(LauncherItems& items, const std::string& name, bool enabled) {
173   if (!items.exists(name)) {
174     LaunchableItem *item = new LaunchableItem();
175
176     item->load(name);
177
178     if (enabled) {
179       item->enable();
180     } else {
181       item->disable();
182     }
183
184     items.add(name, item);
185   }
186 }
187
188 // FIXME: this probably should be done somehow differently
189 static char *configFileName="/home/user/.slarc";
190
191 void SimpleLauncherApplet::loadConfig() {
192   std::ifstream config(configFileName);
193
194   if (config) {
195     char *buffer = new char [1024];
196
197     while (config.getline(buffer, 1024)) {
198       char *p = strchr(buffer, ',');
199
200       if (p != NULL) {
201         *p++ = '\0';
202       }
203
204       addItem(myItems, buffer, (p != NULL && (*p == '1' || *p == 'y' || *p == 'Y')));
205     }
206
207     delete buffer;
208   }
209 }
210
211 void SimpleLauncherApplet::saveConfig() {
212   // TODO: make saving config an atomic operation
213   std::ofstream config(configFileName);
214
215   if (config) {
216     for (size_t i = 0 ; i < myItems.size() ; ++i) {
217       config << myItems.name(i) << ',' << myItems[i]->isEnabled() << std::endl;
218     }
219   }
220 }
221
222 void SimpleLauncherApplet::updateItems(LauncherItems& items) {
223   for (int i = 0 ; ourDirs[i] != NULL ; ++i) {
224     processDirectory(items, ourDirs[i]);
225   }
226 }
227
228 void SimpleLauncherApplet::processDirectory(LauncherItems& items, const std::string& dirname) {
229   DIR *dir = opendir(dirname.c_str());
230
231   if (dir != NULL) {
232     const std::string namePrefix = dirname + "/";
233     std::string shortName;
234     std::string desktopExtension = ".desktop";
235     const dirent *file;
236
237     while ((file = readdir(dir)) != 0) {
238       shortName = file->d_name;
239       if ((shortName == ".") || (shortName == "..")) {
240         continue;
241       }
242
243       if ((shortName.length() >= desktopExtension.length()) && (shortName.compare(shortName.length() - desktopExtension.length(), desktopExtension.length(), desktopExtension) == 0)) {
244         addItem(items, namePrefix+shortName, false);
245       }
246     }
247
248     closedir(dir);
249   }
250 }
251
252 bool SimpleLauncherApplet::initWidget() {
253   myWidget = gtk_hbox_new(false, 0);
254
255   if (myWidget != NULL) {
256     updateWidget();
257   }
258
259   return myWidget != NULL;
260 }
261
262 void SimpleLauncherApplet::updateWidget() {
263   gtk_container_foreach(GTK_CONTAINER(myWidget), (GtkCallback)gtk_widget_destroy, NULL);
264
265   GtkSizeGroup *group = gtk_size_group_new(GTK_SIZE_GROUP_BOTH);
266
267   int button_no = 0;
268
269   for (size_t i = 0 ; i < myItems.size() ; ++i) {
270     LauncherItem *item = myItems[i];
271
272     if (item != NULL && item->isEnabled()) {
273       GtkWidget *button = gtk_event_box_new();
274
275       gtk_widget_set_events(button, GDK_BUTTON_PRESS_MASK);
276       g_signal_connect(button, "button-press-event", G_CALLBACK(_button_pressed), this);
277
278       gtk_event_box_set_visible_window(GTK_EVENT_BOX(button), !myTransparent.value());
279       gtk_container_set_border_width(GTK_CONTAINER(button), myCanvasSize.value());
280
281       {
282         GdkPixbuf *pixbuf = item->getIcon(myIconSize.value());
283         gtk_container_add(GTK_CONTAINER(button), gtk_image_new_from_pixbuf(pixbuf));
284         g_object_unref(G_OBJECT(pixbuf));
285       }
286
287       gtk_object_set_user_data(GTK_OBJECT(button), item);
288
289       gtk_size_group_add_widget(group, button);
290
291       gtk_box_pack_start(GTK_BOX(myWidget), GTK_WIDGET(button), false, false, 0);
292
293       ++button_no;
294     }
295   }
296
297   g_object_unref(G_OBJECT(group));
298
299   int totalSize = myIconSize.value()+2*myCanvasSize.value();
300
301   if (button_no == 0) {
302     gtk_widget_set_size_request(myWidget, totalSize, totalSize);
303   } else {
304     gtk_widget_set_size_request(myWidget, button_no*totalSize, totalSize);
305   }
306
307   gtk_widget_show_all(myWidget);
308 }
309
310 void SimpleLauncherApplet::_button_pressed(GtkWidget *button, GdkEventButton *event, void *self) {
311   ((SimpleLauncherApplet *)self)->buttonPressed(button, event);
312 }
313
314 void SimpleLauncherApplet::buttonPressed(GtkWidget *button, GdkEventButton *event) {
315   if (button != NULL && event->button == 1) {
316     LaunchableItem *item = (LaunchableItem *)gtk_object_get_user_data(GTK_OBJECT(button));
317
318     if (item != NULL) {
319       item->activate(myContext);
320     }
321   }
322 }
323
324 int SimpleLauncherApplet::saveState(void **state_data, int *state_size) {
325   if (state_data != NULL) {
326     *state_data = NULL;
327   }
328
329   if (state_size != NULL) {
330     *state_size = 0;
331   }
332
333   return 1;
334 }
335
336 GtkWidget *SimpleLauncherApplet::settings(GtkWindow *parent) {
337   myParent = parent;  // FIXME: Ugly piece of code :(
338
339   GtkWidget *menuItem = gtk_menu_item_new_with_label("Launcher settings...");
340
341   g_signal_connect(menuItem, "activate", G_CALLBACK(_run_dialog), this);
342
343   return menuItem;
344 }
345
346 void SimpleLauncherApplet::_run_dialog(GtkMenuItem *, void *self) {
347   ((SimpleLauncherApplet *)self)->runDialog();
348 }
349
350 void SimpleLauncherApplet::runDialog() {
351   // We update the items before using them to avoid a small memory leak
352   // FIXME: deal with the situation in a better way (figure it out first :))
353   updateItems(myItems);       // User requested 'settings', let's give her the latest stuff :)
354
355   LauncherItems newItems = myItems;
356
357   // TODO: make it nicer... this code is ugly :(
358   SettingsDialog dialog(myParent, newItems, myTransparent, myIconSize, myCanvasSize);
359
360   switch (dialog.run()) {
361     case GTK_RESPONSE_OK:
362       myItems = newItems;
363       dialog.updateValues();  // FIXME: hackish :( make it better
364
365       saveConfig();   // save it immediately!
366       updateWidget();
367       break;
368
369     case GTK_RESPONSE_CANCEL:
370       break;
371
372     default:
373       ;     // FIXME: do I want to do anything in here?
374   }
375 }
376
377 // vim:ts=2:sw=2:et