X-Git-Url: http://git.maemo.org/git/?p=simple-launcher;a=blobdiff_plain;f=simple-launcher.cc;h=3ebd1da1abf386b1c038cb31be76af971c59e80d;hp=5e31a96294247078ff580e95ab30b8b986ecf885;hb=f878e3159dae33edbe62bddbccedf087cec84aba;hpb=a6117e286571199af04f6b83d8a4af3d08c6a57b diff --git a/simple-launcher.cc b/simple-launcher.cc index 5e31a96..3ebd1da 100644 --- a/simple-launcher.cc +++ b/simple-launcher.cc @@ -1,29 +1,58 @@ +// This file is a part of Simple Launcher +// +// Copyright (C) 2006, 2007, Mikhail Sobolev +// +// Simple Launcher is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License version 2 as published by +// the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +// more details. +// +// You should have received a copy of the GNU General Public License along with +// this program; if not, write to the Free Software Foundation, Inc., 51 +// Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include #include +#include + +#include #include -#include #include #include "launcher-item.h" +#include "launchable-item.h" +#include "settings-dialog.h" +#include "gconf-wrapper.h" + +#define SL_APPLET_DBUS_NAME "simple-launcher" +#define SL_APPLET_VERSION "0.0" + +#define SL_APPLET_GCONF_PATH "/apps/simple-launcher" + +// A copy of interface functions from hildon-home-plugin-interface (new hildon desktop does not have it) {{{ extern "C" { - void *hildon_home_applet_lib_initialize (void *state_data, int *state_size, GtkWidget **widget); - void hildon_home_applet_lib_deinitialize (void *applet_data); - void hildon_home_applet_lib_background (void *applet_data); - void hildon_home_applet_lib_foreground(void *applet_data); + + void *hildon_home_applet_lib_initialize(void *state_data, int *state_size, GtkWidget **widget); int hildon_home_applet_lib_save_state(void *applet_data, void **state_data, int *state_size); + void hildon_home_applet_lib_background(void *applet_data); + void hildon_home_applet_lib_foreground(void *applet_data); + void hildon_home_applet_lib_deinitialize(void *applet_data); GtkWidget *hildon_home_applet_lib_settings(void *applet_data, GtkWindow *parent); + }; -#define SLA_APPLET_DBUS_NAME "simple-launcher" -#define SLA_APPLET_VERSION "0.0" +// }}} class SimpleLauncherApplet { public: - SimpleLauncherApplet(); + SimpleLauncherApplet(const GConfKey&); ~SimpleLauncherApplet(); bool doInit(void *state_data, int *state_size); @@ -36,30 +65,54 @@ public: GtkWidget *getWidget() { return myWidget; } private: + static void addItem(LauncherItems&, const std::string&, bool); + + void loadConfig(); + void saveConfig(); + + static void updateItems(LauncherItems&); + static void processDirectory(LauncherItems&, const std::string&); + bool initWidget(); + void updateWidget(); + + void buttonPressed(GtkWidget *button, GdkEventButton *event); + void runDialog(); - bool startApplication(const std::string& application); + static void _button_pressed(GtkWidget *button, GdkEventButton *event, void *self); + static void _run_dialog(GtkMenuItem *, void *); private: + // GConfClientWrapper myClient; + // GConfKey myMainSettings; + osso_context_t *myContext; + GtkWidget *myWidget; + GtkWindow *myParent; + + LauncherItems myItems; - std::vector myItems; + GConfBooleanOption myTransparent; + // bool myShowInfobanner; // FIXME: to implement + GConfIntegerOption myIconSize; - static char *ourFiles[]; + static char *ourDirs[]; }; // Hildon home applet interface functions void *hildon_home_applet_lib_initialize(void *state_data, int *state_size, GtkWidget **widget) { - SimpleLauncherApplet *applet = new SimpleLauncherApplet(); + GConfKey baseKey(SL_APPLET_GCONF_PATH); + + SimpleLauncherApplet *applet = new SimpleLauncherApplet(baseKey); - if (applet != 0) { + if (applet != NULL) { if (applet->doInit(state_data, state_size)) { *widget = applet->getWidget(); } else { delete applet; - applet = 0; + applet = NULL; } } @@ -90,71 +143,212 @@ int hildon_home_applet_lib_save_state (void *applet_data, void **state_data, int // SimpleLauncherApplet implementation -char *SimpleLauncherApplet::ourFiles[] = { - 0 +char *SimpleLauncherApplet::ourDirs[] = { + "/usr/share/applications/hildon", + NULL }; -SimpleLauncherApplet::SimpleLauncherApplet(): myContext(0), myWidget(0) { +// SimpleLauncherApplet::SimpleLauncherApplet() : myMainSettings(myClient.getKey(SL_APPLET_GCONF_PATH)), myContext(NULL), myWidget(NULL), myParent(NULL) { +SimpleLauncherApplet::SimpleLauncherApplet(const GConfKey& base) : myContext(NULL), myWidget(NULL), myParent(NULL), myTransparent(base, "transparent", false), myIconSize(base, "icon_size", 48) { } bool SimpleLauncherApplet::doInit(void *state_data, int *state_size) { - if ((myContext = osso_initialize(SLA_APPLET_DBUS_NAME, SLA_APPLET_VERSION, FALSE, NULL)) == 0) { + if ((myContext = osso_initialize(SL_APPLET_DBUS_NAME, SL_APPLET_VERSION, FALSE, NULL)) == NULL) { g_debug("sla-applet: failed to initialize the osso layer"); return false; } + loadConfig(); + if (!initWidget()) { return false; } - for (int i = 0 ; ourFiles[i] != 0 ; ++i) { - LauncherItem *item = new LauncherItem(); + return true; +} - if (item->load(ourFiles[i])) { - myItems.push_back(item); +SimpleLauncherApplet::~SimpleLauncherApplet() { + myItems.clear(); +#if 0 + // This does not seem to be necessary + if (myWidget != NULL) { + gtk_widget_destroy(myWidget); + myWidget = NULL; + } +#endif + if (myContext != NULL) { + osso_deinitialize(myContext); + myContext = NULL; + } +} + +void SimpleLauncherApplet::addItem(LauncherItems& items, const std::string& name, bool enabled) { + if (!items.exists(name)) { + LaunchableItem *item = new LaunchableItem(); + + item->load(name); + + if (enabled) { + item->enable(); } else { - delete item; + item->disable(); } + + items.add(name, item); } +} - // g_signal_connect (applet->myWidget, "do_search", G_CALLBACK (mis_applet_do_search), (gpointer)applet); +// {{{ Configuration file managment +static const gchar *getConfigFileName() { + static gchar *configFileName = NULL; - gtk_widget_show_all(myWidget); + if (configFileName == NULL) { + configFileName = g_build_filename(g_get_home_dir(), ".slarc", NULL); + } - return true; + return configFileName; } -SimpleLauncherApplet::~SimpleLauncherApplet() { - for (std::vector::iterator it = myItems.begin(); it != myItems.end(); ++it) { - if (*it != 0) { - delete *it; - *it = 0; +void SimpleLauncherApplet::loadConfig() { + std::ifstream config(getConfigFileName()); + + if (config) { + char *buffer = new char [1024]; + + while (config.getline(buffer, 1024)) { + char *p = strchr(buffer, ','); + + if (p != NULL) { + *p++ = '\0'; + } + + addItem(myItems, buffer, (p != NULL && (*p == '1' || *p == 'y' || *p == 'Y'))); } + + delete [] buffer; } +} - myItems.resize(0); +void SimpleLauncherApplet::saveConfig() { + // TODO: make saving config an atomic operation + std::ofstream config(getConfigFileName()); - if (myWidget != 0) { - gtk_widget_destroy(myWidget); - myWidget = 0; + if (config) { + for (size_t i = 0 ; i < myItems.size() ; ++i) { + config << myItems.name(i) << ',' << myItems[i]->isEnabled() << std::endl; + } + } +} + +// }}} + +void SimpleLauncherApplet::updateItems(LauncherItems& items) { + for (int i = 0 ; ourDirs[i] != NULL ; ++i) { + processDirectory(items, ourDirs[i]); } +} - if (myContext != 0) { - osso_deinitialize(myContext); - myContext = 0; +void SimpleLauncherApplet::processDirectory(LauncherItems& items, const std::string& dirname) { + DIR *dir = opendir(dirname.c_str()); + + if (dir != NULL) { + const std::string namePrefix = dirname + "/"; + std::string shortName; + std::string desktopExtension = ".desktop"; + const dirent *file; + + while ((file = readdir(dir)) != 0) { + shortName = file->d_name; + if ((shortName == ".") || (shortName == "..")) { + continue; + } + + if ((shortName.length() >= desktopExtension.length()) && (shortName.compare(shortName.length() - desktopExtension.length(), desktopExtension.length(), desktopExtension) == 0)) { + addItem(items, namePrefix+shortName, false); + } + } + + closedir(dir); } } bool SimpleLauncherApplet::initWidget() { - return false; + myWidget = gtk_hbox_new(false, 0); + + if (myWidget != NULL) { + updateWidget(); + } + + return myWidget != NULL; +} + +void SimpleLauncherApplet::updateWidget() { + gtk_container_foreach(GTK_CONTAINER(myWidget), (GtkCallback)gtk_widget_destroy, NULL); + + GtkSizeGroup *group = gtk_size_group_new(GTK_SIZE_GROUP_BOTH); + + int button_no = 0; + + for (size_t i = 0 ; i < myItems.size() ; ++i) { + LauncherItem *item = myItems[i]; + + if (item != NULL && item->isEnabled()) { + GtkWidget *button = gtk_event_box_new(); + + gtk_widget_set_events(button, GDK_BUTTON_PRESS_MASK); + g_signal_connect(button, "button-press-event", G_CALLBACK(_button_pressed), this); + + gtk_event_box_set_visible_window(GTK_EVENT_BOX(button), !myTransparent.value()); + + { + GdkPixbuf *pixbuf = item->getIcon(myIconSize.value()); + gtk_container_add(GTK_CONTAINER(button), gtk_image_new_from_pixbuf(pixbuf)); + g_object_unref(G_OBJECT(pixbuf)); + } + + gtk_object_set_user_data(GTK_OBJECT(button), item); + + gtk_size_group_add_widget(group, button); + + gtk_box_pack_start(GTK_BOX(myWidget), GTK_WIDGET(button), false, false, 0); + + ++button_no; + } + } + + g_object_unref(G_OBJECT(group)); + + int totalSize = myIconSize.value(); + + if (button_no == 0) { + gtk_widget_set_size_request(myWidget, totalSize, totalSize); + } else { + gtk_widget_set_size_request(myWidget, button_no*totalSize, totalSize); + } + + gtk_widget_show_all(myWidget); +} + +void SimpleLauncherApplet::_button_pressed(GtkWidget *button, GdkEventButton *event, void *self) { + ((SimpleLauncherApplet *)self)->buttonPressed(button, event); +} + +void SimpleLauncherApplet::buttonPressed(GtkWidget *button, GdkEventButton *event) { + if (button != NULL && event->button == 1) { + LaunchableItem *item = (LaunchableItem *)gtk_object_get_user_data(GTK_OBJECT(button)); + + if (item != NULL) { + item->activate(myContext); + } + } } int SimpleLauncherApplet::saveState(void **state_data, int *state_size) { - if (state_data != 0) { - *state_data = 0; + if (state_data != NULL) { + *state_data = NULL; } - if (state_size != 0) { + if (state_size != NULL) { *state_size = 0; } @@ -162,13 +356,46 @@ int SimpleLauncherApplet::saveState(void **state_data, int *state_size) { } GtkWidget *SimpleLauncherApplet::settings(GtkWindow *parent) { - // TODO: in case we want SimpleLauncherApplet to be configurable, this method - // should return a gtk_menu_item that would be included in home settings - // menu. Method should make sure that when we activate that item, a - // corresponding dialog appears. - return 0; + myParent = parent; // FIXME: Ugly piece of code :( + + GtkWidget *menuItem = gtk_menu_item_new_with_label("Launcher settings..."); + + g_signal_connect(menuItem, "activate", G_CALLBACK(_run_dialog), this); + + return menuItem; +} + +void SimpleLauncherApplet::_run_dialog(GtkMenuItem *, void *self) { + ((SimpleLauncherApplet *)self)->runDialog(); } -bool SimpleLauncherApplet::startApplication(const std::string& application) { - return osso_application_top(myContext, application.c_str(), 0) == OSSO_OK; +void SimpleLauncherApplet::runDialog() { + // We update the items before using them to avoid a small memory leak + // FIXME: deal with the situation in a better way (figure it out first :)) + updateItems(myItems); // User requested 'settings', let's give her the latest stuff :) + + LauncherItems newItems = myItems; + + // TODO: make it nicer... this code is ugly :( + SettingsDialog dialog(myParent, newItems, myTransparent, myIconSize); + + switch (dialog.run()) { + case GTK_RESPONSE_OK: + myItems = newItems; + dialog.updateValues(); // FIXME: hackish :( make it better + + saveConfig(); // save it immediately! + updateWidget(); + break; + + case GTK_RESPONSE_CANCEL: + break; + + default: + ; // FIXME: do I want to do anything in here? + } + + // newItems.clear(); // TODO: do I really need it? } + +// vim:ts=2:sw=2:et