diff options
| author | Didier Roche <didier.roche@canonical.com> | 2010-12-09 19:31:09 +0100 |
|---|---|---|
| committer | Didier Roche <didier.roche@canonical.com> | 2010-12-09 19:31:09 +0100 |
| commit | 491e2f0f05062b3e1032054d573e876ca4f68ddb (patch) | |
| tree | 28741fcc3181bc64447129ed4559947952417ea6 | |
| parent | 431332d7c1baa3cfee23932a5697550625f81218 (diff) | |
| parent | ab13eaf44b4bbaf8b322d8e704b85fbc3a3c59a8 (diff) | |
Import upstream version 3.2.6upstream-3.2.6
(bzr r55.4.36)
64 files changed, 5821 insertions, 3713 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 48586e7ec..e3eaf5f75 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,7 @@ subdirs (libunity services tests tools) set (PROJECT_NAME "unity") set (UNITY_MAJOR 3) set (UNITY_MINOR 2) -set (UNITY_MICRO 2) +set (UNITY_MICRO 6) set (UNITY_VERSION "${UNITY_MAJOR}.${UNITY_MINOR}.${UNITY_MICRO}") set (UNITY_API_VERSION "3.0") @@ -74,7 +74,7 @@ endif (${GETTEXT_FOUND} STREQUAL "TRUE") # # src (Compiz Plugin) # -set (UNITY_PLUGIN_DEPS "nux-0.9;libbamf;dbus-glib-1;dee-1.0;gio-2.0;gio-unix-2.0;dbusmenu-glib;x11;libstartup-notification-1.0;gthread-2.0") +set (UNITY_PLUGIN_DEPS "nux-0.9;libbamf;dbus-glib-1;dee-1.0;gio-2.0;gio-unix-2.0;dbusmenu-glib;x11;libstartup-notification-1.0;gthread-2.0;indicator") find_package (Compiz REQUIRED) include (CompizPlugin) @@ -82,6 +82,7 @@ compiz_plugin (unityshell PKGDEPS ${UNITY_PLUGIN_DEPS} PLUGINDEPS composite opengl CFLAGSADD "-DINSTALLPREFIX='\"${CMAKE_INSTALL_PREFIX}\"' -DPKGDATADIR='\"${CMAKE_INSTALL_PREFIX}/share/unity/3\"' -I${CMAKE_BINARY_DIR}" + LIBRARIES "unity" ) # diff --git a/INSTALL b/INSTALL new file mode 100644 index 000000000..a52b43df9 --- /dev/null +++ b/INSTALL @@ -0,0 +1,180 @@ + Install +-------------------------------------------------------------------------------- + +• Notes + + - libunity is an independant library which has a client side API for talking + to Unity. However it does not depend on the main Unity codebase and the + main Unity codebase does not depend on it. + + - Unity and it's desktop environment modules are all modules of Compiz. We use + a patched version of Compiz which uses the GLib main loop instead of the + custom Compiz main loop. This allows us to use GNOME libraries easily inside + the Unity plugins. + + We are currently working on getting this patch upstreamed, but until then + you will need to build this special version of Compiz. + + - libunity is written in Vala and the rest of Unity in C++/C. + + - Unity depends on a library called Nux (lp:nux) which let's us do OpenGL + layouts quickly and efficiently. + + +• Dependencies + + These are in Debian package name form, but it should be easy enough to + translate them to other systems: + + libglib2.0-dev libgdk-pixbuf2.0-dev libcairo2-dev libpng12-dev libglew1.5-dev + libglewmx1.5-dev libxxf86vm-dev libgl1-mesa-dev libsigc++-2.0-dev + libpango1.0-dev doxygen cmake pkg-config valac intltool libgee-dev + libbamf-dev gsettings-desktop-schemas-dev libgconf2-dev libglib2.0-dev + libdbusmenu-glib-dev libgtk2.0-dev libdee-dev libindicator-dev + libboost-dev libboost-serialization-dev libmetacity-dev python-dev cython + + However, as with any project, it's probably best to just run autogen/cmake + and figure out what you need/is missing. If your distro supports grabbing + all the packages needed to build a package, then at least do that for + Compiz, as I'm not going to detail everything it needs here. + + In case your distro isn't packaging all the Ayatana software, these links + might come in handy: + + https://launchpad.net/dee + https://launchpad.net/bamf + https://launchpad.net/libindicator + + Also, although we don't hard depend on them, having a few indicators installed + will make your experience better: + + https://launchpad.net/indicator-appmenu + https://launchpad.net/indicator-application + https://launchpad.net/indicator-network + https://launchpad.net/indicator-sound + https://launchpad.net/indicator-messages + https://launchpad.net/indicator-datetime + https://launchpad.net/indicator-me + https://launchpad.net/indicator-session + +• Build Compiz GLib + + This is taken from http://wiki.ubuntu.com/Unity/InstallationGuideFromSource and + was originally authored by Sam: + + core: + + git clone git://git.compiz.org/users/dbo/compiz-with-glib-mainloop + cd compiz-with-glib-mainloop + mkdir build + cd build + cmake .. -DCMAKE_INSTALL_PREFIX=/opt/unity + make + sudo make findcompiz_install + sudo make install + + exporting paths: + + export PKG_CONFIG_PATH=/opt/unity/lib/pkgconfig:${PKG_CONFIG_PATH} + export LD_LIBRARY_PATH=/opt/unity/lib:${LD_LIBRARY_PATH} + export LD_RUN_PATH=/opt/unity/lib:${LD_RUN_PATH} + + libcompizconfig: + + git clone git://git.compiz.org/compiz/compizconfig/libcompizconfig + cd libcompizconfig + mkdir build + cd build + cmake .. -DCMAKE_INSTALL_PREFIX=/opt/unity + make + sudo make install + + compizconfig-python: + + git clone git://git.compiz.org/compiz/compizconfig/compizconfig-python + cd compizconfig-python + python setup.py install --prefix=/opt/unity + + ccsm: + + git clone git://git.compiz.org/compiz/compizconfig/ccsm + cd ccsm + python setup.py install --prefix=/opt/unity + + plugins-main: + + git clone git://git.compiz.org/compiz/plugins-main + cd plugins-main + git submodule init + git pull origin master + git submodule update + mkdir build + cd build + cmake .. -DCMAKE_INSTALL_PREFIX=/opt/unity + make + sudo make install + + plugins-extra: + + git clone git://git.compiz.org/compiz/plugins-extra + cd plugins-extra + git submodule init + git pull origin master + git submodule update + mkdir build + cd build + cmake .. -DCMAKE_INSTALL_PREFIX=/opt/unity + make + sudo make install + + +• Build Nux + + bzr branch lp:nux + cd nux + ./autogen.sh --disable-documentation --prefix=/opt/unity + make + sudo make install + + +• Build Unity + + bzr branch lp:unity + cd unity + mkdir build; cd build + cmake .. -DCMAKE_BUILD_TYPE=Debug -DCOMPIZ_PLUGIN_INSTALL_TYPE=package -DCMAKE_INSTALL_PREFIX=/opt/unity + make + sudo make install + +• Cleanup + + unset PKG_CONFIG_PATH + unset LD_LIBRARY_PATH + unset LD_RUN_PATH + + +• Testing + + add this to your /home/$USER/.bashrc + + function compiz-unity-setup-env + { + export PATH=/opt/unity/bin:${PATH} + export PYTHONPATH=/opt/unity/lib/python2.6/site-packages + } + + Logout, login, then in a terminal do + + $ compiz-unity-setup-env + $ compiz --replace cpp & + $ ccsm + + And then use the CompizConfig Settings Window to search for and enable the Unity plugin! + + +• Bugs + + If you find bugs in this installation guide or in Unity itself, please report them at + https://launchpad.net/unity/+filebug + + @@ -3,12 +3,15 @@ • Installation + Please see INSTALL or http://wiki.ubuntu.com/Unity/InstallationGuideFromSource + • Tests - You can run `make check` in the build directory to run all GTester tests - In the build directory, ./tests/test-panel will start the panel in standalone mode, which is great for testing + • Environmental Variables PANEL_USE_LOCAL_SERVICE=${anything} @@ -16,6 +19,6 @@ D-Bus activation. This is used for testing how the panel reacts when it starts before the service does. -• Code Style -astyle -s2 -b -S -N -w -Y -M80 -p -H -d -j -k3 -n -z2 +• Code Style + astyle -s2 -b -S -N -w -Y -M80 -p -H -d -j -k3 -n -z2 diff --git a/libunity/CMakeLists.txt b/libunity/CMakeLists.txt index 5e59ba7d1..e04fafa07 100644 --- a/libunity/CMakeLists.txt +++ b/libunity/CMakeLists.txt @@ -50,6 +50,7 @@ find_package (Vala) vala_precompile (VALA_C unity-place-activation.vala unity-place-browser.vala unity-place.vala + perf-logger.vala PACKAGES gtk+-2.0 gio-2.0 glib-2.0 gobject-2.0 gee-1.0 dbus-glib-1 gio-unix-2.0 OPTIONS --thread CUSTOM_VAPIS ../vapi/dee-1.0.vapi ../vapi/config.vapi diff --git a/libunity/perf-logger-utility.h b/libunity/perf-logger-utility.h new file mode 100644 index 000000000..aee02abea --- /dev/null +++ b/libunity/perf-logger-utility.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2009-2010 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 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, see <http://www.gnu.org/licenses/>. + * + * Authored by Gordon Allott <gord.allott@canonical.com> + * + */ +#ifndef _PERF_LOGGER_H_ +#define _PERF_LOGGER_H_ + +#include <libunity/unity.h> + +#define START_FUNCTION() G_STMT_START { \ + perf_timeline_logger_start_process (perf_timeline_logger_get_default(), G_STRFUNC);\ + } G_STMT_END +#define LOGGER_START_PROCESS(process) { perf_timeline_logger_start_process (perf_timeline_logger_get_default(), process);} + +#define END_FUNCTION() G_STMT_START { \ + perf_timeline_logger_end_process (perf_timeline_logger_get_default(), G_STRFUNC);\ + } G_STMT_END +#define LOGGER_END_PROCESS(process) { perf_timeline_logger_end_process (perf_timeline_logger_get_default(), process);} + +#endif /* PERF_LOGGER_H */ diff --git a/unity-private/testing/perf-logger.vala b/libunity/perf-logger.vala index 7c66f7db0..5eeca40e3 100644 --- a/unity-private/testing/perf-logger.vala +++ b/libunity/perf-logger.vala @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Canonical Ltd + * Copyright (C) 2009-2010 Canonical Ltd * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as @@ -17,9 +17,8 @@ * */ -namespace Unity +namespace Perf { - public class ProcessInfo { public ProcessInfo (string name) @@ -32,82 +31,86 @@ namespace Unity public double start; public double end; } - + public static TimelineLogger? timeline_singleton; - public static bool is_logging; - + public static bool is_logging; + public class TimelineLogger : Object { private Timer global_timer; private Gee.HashMap<string, ProcessInfo> process_map; - - public static unowned Unity.TimelineLogger get_default () + + public static unowned Perf.TimelineLogger get_default () { - if (Unity.timeline_singleton == null) + if (Perf.timeline_singleton == null) { - Unity.timeline_singleton = new Unity.TimelineLogger (); + Perf.timeline_singleton = new Perf.TimelineLogger (); } - - return Unity.timeline_singleton; + + return Perf.timeline_singleton; } - + construct { this.process_map = new Gee.HashMap<string, ProcessInfo> (); - this.global_timer = new Timer (); + this.global_timer = new Timer (); this.global_timer.start (); } - + public void start_process (string name) { + debug ("shoop de whoop"); if (name in this.process_map.keys) { warning ("already started process: %s", name); return; } - + var info = new ProcessInfo (name); this.process_map[name] = info; info.start = this.global_timer.elapsed (); } - + public void end_process (string name) { + debug ("shonk le donk"); double end_time = this.global_timer.elapsed (); - + print ("the end time is %f", end_time); + if (name in this.process_map.keys) { this.process_map[name].end = end_time; } - else + else { warning ("process %s not started", name); } } - + public void write_log (string filename) { debug ("Writing performance log file: %s...", filename); var log_file = File.new_for_path (filename); FileOutputStream file_stream; - try + try { if (!log_file.query_exists (null)) { file_stream = log_file.create (FileCreateFlags.NONE, null); } - else + else { file_stream = log_file.replace (null, false, FileCreateFlags.NONE, null); } - + var output_stream = new DataOutputStream (file_stream); - + foreach (ProcessInfo info in this.process_map.values) { - string outline = "%s, %f, %f\n".printf(info.name, info.start, info.end); - output_stream.put_string (outline, null); + string name = info.name.replace (",", ";"); + string outline = "%s, %f, %f\n".printf(name, info.start, info.end); + output_stream.put_string (outline, null); } - + file_stream.close (null); } catch (Error e) { diff --git a/po/unity.pot b/po/unity.pot index 1bf78a1c5..283b0ced6 100644 --- a/po/unity.pot +++ b/po/unity.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: ayatana-dev@lists.launchpad.net\n" -"POT-Creation-Date: 2010-11-28 20:25-0500\n" +"POT-Creation-Date: 2010-12-07 14:34-0500\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" diff --git a/resources/focused_indicator.png b/resources/focused_indicator.png Binary files differindex 42fdad3b2..cf70e5aa2 100644 --- a/resources/focused_indicator.png +++ b/resources/focused_indicator.png diff --git a/resources/round_outline_54x54.png b/resources/round_outline_54x54.png Binary files differindex 1250c9de4..b6bb3b61c 100644 --- a/resources/round_outline_54x54.png +++ b/resources/round_outline_54x54.png diff --git a/resources/running_indicator.png b/resources/running_indicator.png Binary files differindex 3169ec967..ab6aab485 100644 --- a/resources/running_indicator.png +++ b/resources/running_indicator.png diff --git a/services/panel-main.c b/services/panel-main.c index 339310326..38008587f 100644 --- a/services/panel-main.c +++ b/services/panel-main.c @@ -73,6 +73,10 @@ static const gchar introspection_xml[] = " <arg type='i' name='y' />" " </signal>" "" + " <signal name='EntryActivateRequest'>" + " <arg type='s' name='entry_id' />" + " </signal>" + "" " </interface>" "</node>"; @@ -137,8 +141,6 @@ handle_method_call (GDBusConnection *connection, gint32 button; g_variant_get (parameters, "(suiii)", &entry_id, ×tamp, &x, &y, &button, NULL); - g_debug ("button: %u", button); - panel_service_show_entry (service, entry_id, timestamp, x, y, button); g_dbus_method_invocation_return_value (invocation, NULL); @@ -211,6 +213,27 @@ on_service_active_menu_pointer_motion (PanelService *service, } static void +on_service_entry_activate_request (PanelService *service, + const gchar *entry_id, + GDBusConnection *connection) +{ + GError *error = NULL; + g_dbus_connection_emit_signal (connection, + S_NAME, + S_PATH, + S_IFACE, + "EntryActivateRequest", + g_variant_new ("(s)", entry_id), + &error); + + if (error) + { + g_warning ("Unable to emit EntryActivateRequest signal: %s", error->message); + g_error_free (error); + } +} + +static void on_bus_acquired (GDBusConnection *connection, const gchar *name, gpointer user_data) @@ -231,6 +254,8 @@ on_bus_acquired (GDBusConnection *connection, G_CALLBACK (on_service_entry_activated), connection); g_signal_connect (service, "active-menu-pointer-motion", G_CALLBACK (on_service_active_menu_pointer_motion), connection); + g_signal_connect (service, "entry-activate-request", + G_CALLBACK (on_service_entry_activate_request), connection); g_debug ("%s", G_STRFUNC); g_assert (reg_id > 0); diff --git a/services/panel-service.c b/services/panel-service.c index 060aaf06f..290d180fd 100644 --- a/services/panel-service.c +++ b/services/panel-service.c @@ -46,8 +46,10 @@ struct _PanelServicePrivate guint initial_sync_id; gint32 timeouts[N_TIMEOUT_SLOTS]; + IndicatorObjectEntry *last_entry; GtkMenu *last_menu; guint32 last_menu_id; + guint32 last_menu_move_id; gint32 last_x; gint32 last_y; guint32 last_menu_button; @@ -64,6 +66,7 @@ enum ENTRY_ACTIVATED = 0, RE_SYNC, ACTIVE_MENU_POINTER_MOTION, + ENTRY_ACTIVATE_REQUEST, LAST_SIGNAL }; @@ -79,8 +82,9 @@ static guint32 _service_signals[LAST_SIGNAL] = { 0 }; static gchar * indicator_order[] = { "libappmenu.so", "libapplication.so", - "libnetwork.so", "libsoundmenu.so", + "libnetwork.so", + "libnetworkmenu.so", "libmessaging.so", "libdatetime.so", "libme.so", @@ -167,6 +171,16 @@ panel_service_class_init (PanelServiceClass *klass) g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); + _service_signals[ENTRY_ACTIVATE_REQUEST] = + g_signal_new ("entry-activate-request", + G_OBJECT_CLASS_TYPE (obj_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, G_TYPE_STRING); + + g_type_class_add_private (obj_class, sizeof (PanelServicePrivate)); } @@ -476,6 +490,23 @@ on_entry_moved (IndicatorObject *object, } static void +on_indicator_menu_show (IndicatorObject *object, + IndicatorObjectEntry *entry, + guint32 timestamp, + PanelService *self) +{ + gchar *entry_id; + + g_return_if_fail (PANEL_IS_SERVICE (self)); + + entry_id = g_strdup_printf ("%p", entry); + + g_signal_emit (self, _service_signals[ENTRY_ACTIVATE_REQUEST], 0, entry_id); + + g_free (entry_id); +} + +static void load_indicator (PanelService *self, IndicatorObject *object, const gchar *_name) { PanelServicePrivate *priv = self->priv; @@ -497,6 +528,8 @@ load_indicator (PanelService *self, IndicatorObject *object, const gchar *_name) G_CALLBACK (on_entry_removed), self); g_signal_connect (object, INDICATOR_OBJECT_SIGNAL_ENTRY_MOVED, G_CALLBACK (on_entry_moved), self); + g_signal_connect (object, INDICATOR_OBJECT_SIGNAL_MENU_SHOW, + G_CALLBACK (on_indicator_menu_show), self); entries = indicator_object_get_entries (object); for (entry = entries; entry != NULL; entry = entry->next) @@ -741,8 +774,11 @@ on_active_menu_hidden (GtkMenu *menu, PanelService *self) priv->last_menu_button = 0; g_signal_handler_disconnect (priv->last_menu, priv->last_menu_id); + g_signal_handler_disconnect (priv->last_menu, priv->last_menu_move_id); priv->last_menu = NULL; priv->last_menu_id = 0; + priv->last_menu_move_id = 0; + priv->last_entry = NULL; g_signal_emit (self, _service_signals[ENTRY_ACTIVATED], 0, ""); } @@ -804,6 +840,111 @@ panel_service_sync_one (PanelService *self, const gchar *indicator_id) return g_variant_builder_end (&b); } +static void +activate_next_prev_menu (PanelService *self, + IndicatorObject *object, + IndicatorObjectEntry *entry, + GtkMenuDirectionType direction) +{ + PanelServicePrivate *priv = self->priv; + GSList *indicators = priv->indicators; + GList *entries; + gint n_entries; + IndicatorObjectEntry *new_entry; + gchar *id; + + entries = indicator_object_get_entries (object); + n_entries = g_list_length (entries); + if (n_entries == 1 + || (g_list_index (entries, entry) == 0 && direction == GTK_MENU_DIR_PARENT) + || (g_list_index (entries, entry) == n_entries - 1 && direction == GTK_MENU_DIR_CHILD)) + { + int n_indicators; + IndicatorObject *new_object; + GList *new_entries; + + n_indicators = g_slist_length (priv->indicators); + + if (g_slist_index (indicators, object) == 0 && direction == GTK_MENU_DIR_PARENT) + { + new_object = g_slist_nth_data (indicators, n_indicators - 1); + } + else if (g_slist_index (indicators, object) == n_indicators -1 && direction == GTK_MENU_DIR_CHILD) + { + new_object = g_slist_nth_data (indicators, 0); + } + else + { + gint cur_object_index = g_slist_index (indicators, object); + gint new_object_index = cur_object_index + (direction == GTK_MENU_DIR_CHILD ? 1 : -1); + new_object = g_slist_nth_data (indicators, new_object_index); + } + + new_entries = indicator_object_get_entries (new_object); + new_entry = g_list_nth_data (new_entries, direction == GTK_MENU_DIR_PARENT ? g_list_length (new_entries) - 1 : 0); + + g_list_free (new_entries); + } + else + { + new_entry = g_list_nth_data (entries, g_list_index (entries, entry) + (direction == GTK_MENU_DIR_CHILD ? 1 : -1)); + } + + id = g_strdup_printf ("%p", new_entry); + g_signal_emit (self, _service_signals[ENTRY_ACTIVATE_REQUEST], 0, id); + + g_free (id); + g_list_free (entries); +} + +static void +on_active_menu_move_current (GtkMenu *menu, + GtkMenuDirectionType direction, + PanelService *self) +{ + PanelServicePrivate *priv; + IndicatorObject *object; + + g_return_if_fail (PANEL_IS_SERVICE (self)); + priv = self->priv; + + /* Not interested in up or down */ + if (direction == GTK_MENU_DIR_NEXT + || direction == GTK_MENU_DIR_PREV) + return; + + /* We don't want to distrupt going into submenus */ + if (direction == GTK_MENU_DIR_CHILD) + { + GList *children, *c; + children = gtk_container_get_children (GTK_CONTAINER (menu)); + for (c = children; c; c = c->next) + { + GtkWidget *item = (GtkWidget *)c->data; + + if (GTK_IS_MENU_ITEM (item) + && gtk_widget_get_state (item) == GTK_STATE_PRELIGHT + && gtk_menu_item_get_submenu (GTK_MENU_ITEM (item))) + { + /* Skip direction due to there being a submenu, + * and we don't want to inhibit going into that */ + return; + } + } + g_list_free (children); + } + + /* Find the next/prev indicator */ + object = g_hash_table_lookup (priv->entry2indicator_hash, priv->last_entry); + if (object == NULL) + { + g_warning ("Unable to find IndicatorObject for entry"); + return; + } + + activate_next_prev_menu (self, object, priv->last_entry, direction); +} + void panel_service_show_entry (PanelService *self, const gchar *entry_id, @@ -815,27 +956,37 @@ panel_service_show_entry (PanelService *self, PanelServicePrivate *priv = self->priv; IndicatorObjectEntry *entry = g_hash_table_lookup (priv->id2entry_hash, entry_id); + if (priv->last_entry == entry) + return; + if (GTK_IS_MENU (priv->last_menu)) { priv->last_x = 0; priv->last_y = 0; g_signal_handler_disconnect (priv->last_menu, priv->last_menu_id); + g_signal_handler_disconnect (priv->last_menu, priv->last_menu_move_id); gtk_menu_popdown (GTK_MENU (priv->last_menu)); + priv->last_entry = NULL; priv->last_menu = NULL; priv->last_menu_id = 0; + priv->last_menu_move_id = 0; priv->last_menu_button = 0; } if (entry != NULL && GTK_IS_MENU (entry->menu)) { + priv->last_entry = entry; priv->last_menu = entry->menu; priv->last_x = x; priv->last_y = y; priv->last_menu_button = button; priv->last_menu_id = g_signal_connect (priv->last_menu, "hide", G_CALLBACK (on_active_menu_hidden), self); + priv->last_menu_move_id = g_signal_connect_after (priv->last_menu, "move-current", + G_CALLBACK (on_active_menu_move_current), self); + gtk_menu_popup (priv->last_menu, NULL, NULL, positon_menu, self, 0, CurrentTime); g_signal_emit (self, _service_signals[ENTRY_ACTIVATED], 0, entry_id); diff --git a/src/BamfLauncherIcon.cpp b/src/BamfLauncherIcon.cpp index d64a8aac4..20d2b6af6 100644 --- a/src/BamfLauncherIcon.cpp +++ b/src/BamfLauncherIcon.cpp @@ -25,31 +25,52 @@ #include "FavoriteStore.h" #include <gio/gdesktopappinfo.h> - +#include <libindicator/indicator-desktop-shortcuts.h> #include <core/core.h> #include <core/atoms.h> +struct _ShortcutData +{ + BamfLauncherIcon *self; + IndicatorDesktopShortcuts *shortcuts; + char *nick; +}; +typedef struct _ShortcutData ShortcutData; +static void shortcut_data_destroy (ShortcutData *data) +{ + g_object_unref (data->shortcuts); + g_free (data->nick); + g_slice_free (ShortcutData, data); +} + +static void shortcut_activated (DbusmenuMenuitem* _sender, guint timestamp, gpointer userdata) +{ + ShortcutData *data = (ShortcutData *)userdata; + indicator_desktop_shortcuts_nick_exec (data->shortcuts, data->nick); +} + BamfLauncherIcon::BamfLauncherIcon (Launcher* IconManager, BamfApplication *app, CompScreen *screen) : SimpleLauncherIcon(IconManager) { m_App = app; m_Screen = screen; + _menu_desktop_shortcuts = NULL; char *icon_name = bamf_view_get_icon (BAMF_VIEW (m_App)); SetTooltipText (bamf_view_get_name (BAMF_VIEW (app))); SetIconName (icon_name); SetIconType (LAUNCHER_ICON_TYPE_APPLICATION); - + if (bamf_view_is_sticky (BAMF_VIEW (m_App))) SetQuirk (LAUNCHER_ICON_QUIRK_VISIBLE, true); else SetQuirk (LAUNCHER_ICON_QUIRK_VISIBLE, bamf_view_user_visible (BAMF_VIEW (m_App))); - + SetQuirk (LAUNCHER_ICON_QUIRK_ACTIVE, bamf_view_is_active (BAMF_VIEW (m_App))); SetQuirk (LAUNCHER_ICON_QUIRK_RUNNING, bamf_view_is_running (BAMF_VIEW (m_App))); - + g_free (icon_name); - + g_signal_connect (app, "child-removed", (GCallback) &BamfLauncherIcon::OnChildRemoved, this); g_signal_connect (app, "child-added", (GCallback) &BamfLauncherIcon::OnChildAdded, this); g_signal_connect (app, "urgent-changed", (GCallback) &BamfLauncherIcon::OnUrgentChanged, this); @@ -57,9 +78,9 @@ BamfLauncherIcon::BamfLauncherIcon (Launcher* IconManager, BamfApplication *app, g_signal_connect (app, "active-changed", (GCallback) &BamfLauncherIcon::OnActiveChanged, this); g_signal_connect (app, "user-visible-changed", (GCallback) &BamfLauncherIcon::OnUserVisibleChanged, this); g_signal_connect (app, "closed", (GCallback) &BamfLauncherIcon::OnClosed, this); - + g_object_ref (m_App); - + EnsureWindowState (); UpdateMenus (); } @@ -77,11 +98,39 @@ BamfLauncherIcon::~BamfLauncherIcon() g_object_unref (m_App); } +void +BamfLauncherIcon::AddProperties (GVariantBuilder *builder) +{ + LauncherIcon::AddProperties (builder); + + g_variant_builder_add (builder, "{sv}", "desktop-file", g_variant_new_string (bamf_application_get_desktop_file (m_App))); + + GList *children, *l; + BamfView *view; + + children = bamf_view_get_children (BAMF_VIEW (m_App)); + GVariant* xids[(int) g_list_length (children)]; + + int i = 0; + for (l = children; l; l = l->next) + { + view = (BamfView *) l->data; + + if (BAMF_IS_WINDOW (view)) + { + xids[i++] = g_variant_new_uint32 (bamf_window_get_xid (BAMF_WINDOW (view))); + } + } + g_list_free (children); + g_variant_builder_add (builder, "{sv}", "xids", g_variant_new_array (G_VARIANT_TYPE_UINT32, xids, i)); +} + bool BamfLauncherIcon::IconOwnsWindow (Window w) { GList *children, *l; BamfView *view; + bool owns = false; children = bamf_view_get_children (BAMF_VIEW (m_App)); @@ -92,87 +141,164 @@ BamfLauncherIcon::IconOwnsWindow (Window w) if (BAMF_IS_WINDOW (view)) { guint32 xid = bamf_window_get_xid (BAMF_WINDOW (view)); - + if (xid == w) - return true; + { + owns = true; + break; + } } } - - return false; + + g_list_free (children); + return owns; } void -BamfLauncherIcon::OnMouseClick (int button) +BamfLauncherIcon::OpenInstance () { - if (button != 1) - return; - - BamfView *view; - GList *children, *l; - bool active, running; GDesktopAppInfo *appInfo; - + GError *error = NULL; + + appInfo = g_desktop_app_info_new_from_filename (bamf_application_get_desktop_file (BAMF_APPLICATION (m_App))); + g_app_info_launch (G_APP_INFO (appInfo), NULL, NULL, &error); + g_object_unref (appInfo); + + if (error) + { + g_warning ("%s\n", error->message); + g_error_free (error); + } + + UpdateQuirkTime (LAUNCHER_ICON_QUIRK_STARTING); +} + +void +BamfLauncherIcon::Focus () +{ + GList *children, *l; + BamfView *view; + children = bamf_view_get_children (BAMF_VIEW (m_App)); - active = bamf_view_is_active (BAMF_VIEW (m_App)); - running = bamf_view_is_running (BAMF_VIEW (m_App)); - - if (!running) + + CompWindowList windows; + + /* get the list of windows */ + for (l = children; l; l = l->next) { - appInfo = g_desktop_app_info_new_from_filename (bamf_application_get_desktop_file (BAMF_APPLICATION (m_App))); - g_app_info_launch (G_APP_INFO (appInfo), NULL, NULL, NULL); - g_object_unref (appInfo); - - UpdateQuirkTime (LAUNCHER_ICON_QUIRK_STARTING); - + view = (BamfView *) l->data; + + if (BAMF_IS_WINDOW (view)) + { + guint32 xid = bamf_window_get_xid (BAMF_WINDOW (view)); + + CompWindow *window = m_Screen->findWindow ((Window) xid); + + if (window) + windows.push_back (window); + } + } + + if (windows.empty ()) return; + + /* sort the list */ + CompWindowList tmp; + CompWindowList::iterator it; + for (it = m_Screen->windows ().begin (); it != m_Screen->windows ().end (); it++) + { + if (std::find (windows.begin (), windows.end (), *it) != windows.end ()) + tmp.push_back (*it); } - - if (active) + windows = tmp; + + + /* filter based on workspace */ + bool any_on_current = false; + + for (it = windows.begin (); it != windows.end (); it++) { - std::list<Window> windowList; - for (l = children; l; l = l->next) + if ((*it)->defaultViewport () == m_Screen->vp ()) { - view = (BamfView *) l->data; - - if (BAMF_IS_WINDOW (view)) - { - guint32 xid = bamf_window_get_xid (BAMF_WINDOW (view)); - - windowList.push_back ((Window) xid); - } + any_on_current = true; + break; } - - if (windowList.size () > 1) + } + + /* activate our windows */ + + if (any_on_current) + { + for (it = windows.begin (); it != windows.end (); it++) { - std::string *match = PluginAdapter::Default ()->MatchStringForXids (&windowList); - PluginAdapter::Default ()->InitiateScale (match); - delete match; + if ((*it)->defaultViewport () == m_Screen->vp ()) + { + (*it)->activate (); + } } } else { - for (l = children; l; l = l->next) + (*(windows.rbegin ()))->activate (); + } + + g_list_free (children); +} + +void +BamfLauncherIcon::Spread () +{ + BamfView *view; + GList *children, *l; + children = bamf_view_get_children (BAMF_VIEW (m_App)); + + std::list<Window> windowList; + for (l = children; l; l = l->next) + { + view = (BamfView *) l->data; + + if (BAMF_IS_WINDOW (view)) { - view = (BamfView *) l->data; - - if (BAMF_IS_WINDOW (view)) - { - guint32 xid = bamf_window_get_xid (BAMF_WINDOW (view)); - - CompWindow *window = m_Screen->findWindow ((Window) xid); - - if (window) - window->activate (); - } + guint32 xid = bamf_window_get_xid (BAMF_WINDOW (view)); + + windowList.push_back ((Window) xid); } } + + if (windowList.size () > 1) + { + std::string *match = PluginAdapter::Default ()->MatchStringForXids (&windowList); + PluginAdapter::Default ()->InitiateScale (match); + delete match; + } + + g_list_free (children); +} + +void +BamfLauncherIcon::OnMouseClick (int button) +{ + if (button != 1) + return; + + bool active, running; + + active = bamf_view_is_active (BAMF_VIEW (m_App)); + running = bamf_view_is_running (BAMF_VIEW (m_App)); + + if (!running) + OpenInstance (); + else if (active) + Spread (); + else + Focus (); } void BamfLauncherIcon::OnClosed (BamfView *view, gpointer data) { BamfLauncherIcon *self = (BamfLauncherIcon *) data; - + if (!bamf_view_is_sticky (BAMF_VIEW (self->m_App))) self->Remove (); } @@ -181,7 +307,7 @@ void BamfLauncherIcon::OnUserVisibleChanged (BamfView *view, gboolean visible, gpointer data) { BamfLauncherIcon *self = (BamfLauncherIcon *) data; - + if (!bamf_view_is_sticky (BAMF_VIEW (self->m_App))) self->SetQuirk (LAUNCHER_ICON_QUIRK_VISIBLE, visible); } @@ -191,7 +317,7 @@ BamfLauncherIcon::OnRunningChanged (BamfView *view, gboolean running, gpointer d { BamfLauncherIcon *self = (BamfLauncherIcon *) data; self->SetQuirk (LAUNCHER_ICON_QUIRK_RUNNING, running); - + if (running) { self->EnsureWindowState (); @@ -218,15 +344,17 @@ BamfLauncherIcon::EnsureWindowState () { GList *children, *l; int count = 0; - + children = bamf_view_get_children (BAMF_VIEW (m_App)); for (l = children; l; l = l->next) { if (BAMF_IS_WINDOW (l->data)) count++; } - + SetRelatedWindows (count); + + g_list_free (children); } void @@ -249,7 +377,8 @@ void BamfLauncherIcon::UpdateMenus () { GList *children, *l; - + IndicatorDesktopShortcuts *desktop_shortcuts; + children = bamf_view_get_children (BAMF_VIEW (m_App)); for (l = children; l; l = l->next) { @@ -258,14 +387,65 @@ BamfLauncherIcon::UpdateMenus () BamfIndicator *indicator = BAMF_INDICATOR (l->data); std::string path = bamf_indicator_get_dbus_menu_path (indicator); - + // we already have this if (_menu_clients.find (path) != _menu_clients.end ()) continue; - + DbusmenuClient *client = dbusmenu_client_new (bamf_indicator_get_remote_address (indicator), path.c_str ()); _menu_clients[path] = client; } + + g_list_free (children); + + // make a client for desktop file actions + if (!DBUSMENU_IS_MENUITEM (_menu_desktop_shortcuts) && + bamf_application_get_desktop_file (m_App) != NULL) + { + + DbusmenuMenuitem *root = dbusmenu_menuitem_new (); + dbusmenu_menuitem_set_root (root, TRUE); + desktop_shortcuts = indicator_desktop_shortcuts_new (bamf_application_get_desktop_file (m_App), + "Unity"); + const gchar **nicks = indicator_desktop_shortcuts_get_nicks (desktop_shortcuts); + + int index = 0; + if (nicks) { + while (((gpointer*) nicks)[index]) { + const char* name; + DbusmenuMenuitem *item; + name = g_strdup (indicator_desktop_shortcuts_nick_get_name (desktop_shortcuts, + nicks[index])); + ShortcutData *data = g_slice_new0 (ShortcutData); + data->self = this; + data->shortcuts = INDICATOR_DESKTOP_SHORTCUTS (g_object_ref (desktop_shortcuts)); + data->nick = g_strdup (nicks[index]); + + item = dbusmenu_menuitem_new (); + dbusmenu_menuitem_property_set (item, DBUSMENU_MENUITEM_PROP_LABEL, name); + dbusmenu_menuitem_property_set_bool (item, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE); + dbusmenu_menuitem_property_set_bool (item, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE); + g_signal_connect_data (item, "item-activated", + (GCallback) shortcut_activated, (gpointer) data, + (GClosureNotify) shortcut_data_destroy, (GConnectFlags)0); + + dbusmenu_menuitem_child_append (root, item); + + index++; + + g_free ((void *)name); + } + } + + _menu_desktop_shortcuts = root; + } + +} + +void +BamfLauncherIcon::OnLaunch (DbusmenuMenuitem *item, int time, BamfLauncherIcon *self) +{ + self->OpenInstance (); } void @@ -284,10 +464,13 @@ BamfLauncherIcon::OnQuit (DbusmenuMenuitem *item, int time, BamfLauncherIcon *se { guint32 xid = bamf_window_get_xid (BAMF_WINDOW (view)); CompWindow *window = self->m_Screen->findWindow ((Window) xid); - - window->close (self->m_Screen->getCurrentTime ()); + + if (window) + window->close (self->m_Screen->getCurrentTime ()); } } + + g_list_free (children); } void @@ -296,86 +479,129 @@ BamfLauncherIcon::OnTogglePin (DbusmenuMenuitem *item, int time, BamfLauncherIco BamfView *view = BAMF_VIEW (self->m_App); bool sticky = bamf_view_is_sticky (view); const gchar *desktop_file = bamf_application_get_desktop_file (self->m_App); - + if (sticky) { bamf_view_set_sticky (view, false); if (bamf_view_is_closed (view)) self->Remove (); - + if (desktop_file && strlen (desktop_file) > 0) FavoriteStore::GetDefault ()->RemoveFavorite (desktop_file); } else { bamf_view_set_sticky (view, true); - + if (desktop_file && strlen (desktop_file) > 0) FavoriteStore::GetDefault ()->AddFavorite (desktop_file, -1); //self->SortPriority ()); } } -std::list<DbusmenuMenuitem *> -BamfLauncherIcon::GetMenus () +void +BamfLauncherIcon::EnsureMenuItemsReady () { - std::map<std::string, DbusmenuClient *>::iterator it; - std::list<DbusmenuMenuitem *> result; DbusmenuMenuitem *menu_item; - - for (it = _menu_clients.begin (); it != _menu_clients.end (); it++) + + /* Launch */ + if (_menu_items.find ("Launch") == _menu_items.end ()) { - GList * child = NULL; - DbusmenuClient *client = (*it).second; - DbusmenuMenuitem *root = dbusmenu_client_get_root (client); - - for (child = dbusmenu_menuitem_get_children(root); child != NULL; child = g_list_next(child)) - { - DbusmenuMenuitem *item = (DbusmenuMenuitem *) child->data; - - if (!item) - continue; - - result.push_back (item); - } + menu_item = dbusmenu_menuitem_new (); + g_object_ref (menu_item); + + dbusmenu_menuitem_property_set (menu_item, DBUSMENU_MENUITEM_PROP_LABEL, "Open New Window"); + dbusmenu_menuitem_property_set_bool (menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true); + + g_signal_connect (menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, (GCallback) &BamfLauncherIcon::OnLaunch, this); + + _menu_items["Launch"] = menu_item; } - + + /* Pin */ if (_menu_items.find ("Pin") == _menu_items.end ()) { menu_item = dbusmenu_menuitem_new (); g_object_ref (menu_item); - + dbusmenu_menuitem_property_set (menu_item, DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE, DBUSMENU_MENUITEM_TOGGLE_CHECK); - dbusmenu_menuitem_property_set (menu_item, DBUSMENU_MENUITEM_PROP_LABEL, "Pin To Launcher"); + dbusmenu_menuitem_property_set (menu_item, DBUSMENU_MENUITEM_PROP_LABEL, "Keep In Launcher"); dbusmenu_menuitem_property_set_bool (menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true); - + g_signal_connect (menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, (GCallback) &BamfLauncherIcon::OnTogglePin, this); - + _menu_items["Pin"] = menu_item; } - - int checked = !bamf_view_is_sticky (BAMF_VIEW (m_App)) ? + int checked = !bamf_view_is_sticky (BAMF_VIEW (m_App)) ? DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED : DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED; - - dbusmenu_menuitem_property_set_int (_menu_items["Pin"], - DBUSMENU_MENUITEM_PROP_TOGGLE_STATE, + + dbusmenu_menuitem_property_set_int (_menu_items["Pin"], + DBUSMENU_MENUITEM_PROP_TOGGLE_STATE, checked); - result.push_back (_menu_items["Pin"]); - + + + /* Quit */ if (_menu_items.find ("Quit") == _menu_items.end ()) { menu_item = dbusmenu_menuitem_new (); g_object_ref (menu_item); - + dbusmenu_menuitem_property_set (menu_item, DBUSMENU_MENUITEM_PROP_LABEL, "Quit"); dbusmenu_menuitem_property_set_bool (menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true); - + g_signal_connect (menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, (GCallback) &BamfLauncherIcon::OnQuit, this); - + _menu_items["Quit"] = menu_item; } - - result.push_back (_menu_items["Quit"]); - +} + +std::list<DbusmenuMenuitem *> +BamfLauncherIcon::GetMenus () +{ + std::map<std::string, DbusmenuClient *>::iterator it; + std::list<DbusmenuMenuitem *> result; + + for (it = _menu_clients.begin (); it != _menu_clients.end (); it++) + { + GList * child = NULL; + DbusmenuClient *client = (*it).second; + DbusmenuMenuitem *root = dbusmenu_client_get_root (client); + + for (child = dbusmenu_menuitem_get_children(root); child != NULL; child = g_list_next(child)) + { + DbusmenuMenuitem *item = (DbusmenuMenuitem *) child->data; + + if (!item) + continue; + + result.push_back (item); + } + } + + if (DBUSMENU_IS_MENUITEM (_menu_desktop_shortcuts)) + { + GList * child = NULL; + DbusmenuMenuitem *root = _menu_desktop_shortcuts; + + for (child = dbusmenu_menuitem_get_children(root); child != NULL; child = g_list_next(child)) + { + DbusmenuMenuitem *item = (DbusmenuMenuitem *) child->data; + + if (!item) + continue; + + result.push_back (item); + } + + } + + EnsureMenuItemsReady (); + + result.push_back (_menu_items["Launch"]); + result.push_back (_menu_items["Pin"]); + + if (bamf_view_is_running (BAMF_VIEW (m_App))) + result.push_back (_menu_items["Quit"]); + return result; } @@ -401,15 +627,17 @@ BamfLauncherIcon::UpdateIconGeometries (nux::Point3 center) if (BAMF_IS_WINDOW (view)) { guint32 xid = bamf_window_get_xid (BAMF_WINDOW (view)); - + XChangeProperty (m_Screen->dpy (), xid, Atoms::wmIconGeometry, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) data, 4); } } + + g_list_free (children); } -void +void BamfLauncherIcon::OnCenterStabilized (nux::Point3 center) { UpdateIconGeometries (center); diff --git a/src/BamfLauncherIcon.h b/src/BamfLauncherIcon.h index 22ea7c656..0dd30847e 100644 --- a/src/BamfLauncherIcon.h +++ b/src/BamfLauncherIcon.h @@ -37,26 +37,36 @@ class BamfLauncherIcon : public SimpleLauncherIcon public: BamfLauncherIcon(Launcher* IconManager, BamfApplication *app, CompScreen *screen); ~BamfLauncherIcon(); - - + + protected: void OnMouseClick (int button); std::list<DbusmenuMenuitem *> GetMenus (); - + void UpdateIconGeometries (nux::Point3 center); void OnCenterStabilized (nux::Point3 center); - + bool IconOwnsWindow (Window w); + void AddProperties (GVariantBuilder *builder); + private: BamfApplication *m_App; CompScreen *m_Screen; std::map<std::string, DbusmenuClient *> _menu_clients; std::map<std::string, DbusmenuMenuitem *> _menu_items; - + DbusmenuMenuitem *_menu_desktop_shortcuts; + void EnsureWindowState (); + void UpdateMenus (); - + + void OpenInstance (); + void Focus (); + void Spread (); + + void EnsureMenuItemsReady (); + static void OnClosed (BamfView *view, gpointer data); static void OnUserVisibleChanged (BamfView *view, gboolean visible, gpointer data); static void OnActiveChanged (BamfView *view, gboolean active, gpointer data); @@ -64,7 +74,8 @@ private: static void OnUrgentChanged (BamfView *view, gboolean urgent, gpointer data); static void OnChildAdded (BamfView *view, BamfView *child, gpointer data); static void OnChildRemoved (BamfView *view, BamfView *child, gpointer data); - + + static void OnLaunch (DbusmenuMenuitem *item, int time, BamfLauncherIcon *self); static void OnQuit (DbusmenuMenuitem *item, int time, BamfLauncherIcon *self); static void OnTogglePin (DbusmenuMenuitem *item, int time, BamfLauncherIcon *self); }; diff --git a/src/IndicatorObjectFactory.h b/src/IndicatorObjectFactory.h index 1a9a9b7bc..c267a5b2e 100644 --- a/src/IndicatorObjectFactory.h +++ b/src/IndicatorObjectFactory.h @@ -37,10 +37,14 @@ public: // Indicators (probably though a bunch of removed/added events) virtual void ForceRefresh () = 0; + // For adding factory-specific properties + virtual void AddProperties (GVariantBuilder *builder) = 0; + // Signals sigc::signal<void, IndicatorObjectProxy *> OnObjectAdded; sigc::signal<void, IndicatorObjectProxy *> OnObjectRemoved; sigc::signal<void, int, int> OnMenuPointerMoved; + sigc::signal<void, const char *> OnEntryActivateRequest; protected: std::vector<IndicatorObjectProxy *>_indicators; diff --git a/src/IndicatorObjectFactoryRemote.cpp b/src/IndicatorObjectFactoryRemote.cpp index 229fe5e25..b45efc13e 100644 --- a/src/IndicatorObjectFactoryRemote.cpp +++ b/src/IndicatorObjectFactoryRemote.cpp @@ -230,6 +230,12 @@ IndicatorObjectFactoryRemote::OnEntryActivated (const char *entry_id) } } +void +IndicatorObjectFactoryRemote::OnEntryActivateRequestReceived (const gchar *entry_id) +{ + OnEntryActivateRequest.emit (entry_id); +} + IndicatorObjectProxyRemote * IndicatorObjectFactoryRemote::IndicatorForID (const char *id) { @@ -320,6 +326,27 @@ IndicatorObjectFactoryRemote::Sync (GVariant *args) g_variant_iter_free (iter); } +void +IndicatorObjectFactoryRemote::AddProperties (GVariantBuilder *builder) +{ + gchar *name = NULL; + gchar *uname = NULL; + + g_object_get (_proxy, + "g-name", &name, + "g-name-owner", &uname, + NULL); + + g_variant_builder_add (builder, "{sv}", "backend", g_variant_new_string ("remote")); + g_variant_builder_add (builder, "{sv}", "service-name", g_variant_new_string (name)); + g_variant_builder_add (builder, "{sv}", "service-unique-name", g_variant_new_string (uname)); + g_variant_builder_add (builder, "{sv}", "using-local-service", g_variant_new_boolean (g_getenv ("PANEL_USE_LOCAL_SERVICE") == NULL ? FALSE : TRUE)); + + g_free (name); + g_free (uname); +} + + // // C callbacks, they just link to class methods and aren't interesting // @@ -415,6 +442,10 @@ on_proxy_signal_received (GDBusProxy *proxy, { remote->OnEntryActivated (g_variant_get_string (g_variant_get_child_value (parameters, 0), NULL)); } + else if (g_strcmp0 (signal_name, "EntryActivateRequest") == 0) + { + remote->OnEntryActivateRequestReceived (g_variant_get_string (g_variant_get_child_value (parameters, 0), NULL)); + } else if (g_strcmp0 (signal_name, "ReSync") == 0) { const gchar *id = g_variant_get_string (g_variant_get_child_value (parameters, 0), NULL); diff --git a/src/IndicatorObjectFactoryRemote.h b/src/IndicatorObjectFactoryRemote.h index 0097d2d70..f32bc3fe5 100644 --- a/src/IndicatorObjectFactoryRemote.h +++ b/src/IndicatorObjectFactoryRemote.h @@ -42,6 +42,9 @@ public: void OnEntryActivated (const char *entry_id); void OnShowMenuRequestReceived (const char *id, int x, int y, guint timestamp, guint32 button); void Sync (GVariant *args); + void OnEntryActivateRequestReceived (const char *entry_id); + + void AddProperties (GVariantBuilder *builder); private: IndicatorObjectProxyRemote* IndicatorForID (const char *id); diff --git a/src/Introspectable.cpp b/src/Introspectable.cpp index c64e08a50..a0d39e820 100644 --- a/src/Introspectable.cpp +++ b/src/Introspectable.cpp @@ -21,31 +21,39 @@ GVariant* Introspectable::Introspect () { - GVariant *result; - GVariant *childResults; GVariantBuilder *builder; + GVariant *result; + GVariantBuilder *child_builder; + gint n_children = 0; builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); + + AddProperties (builder); + + child_builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); + for (std::list<Introspectable *>::iterator it = _children.begin (); it != _children.end (); it++) { - g_variant_builder_add (builder, "{sv}", (*it)->GetName (), (*it)->Introspect () ); + if ((*it)->GetName ()) + { + g_variant_builder_add (child_builder, "{sv}", (*it)->GetName (), (*it)->Introspect () ); + n_children++; + } } - AddProperties (builder); - childResults = g_variant_new ("(a{sv})", builder); - g_variant_builder_unref (builder); + if (n_children > 0) + { + GVariant *child_results; - if (_children.size () > 0) - { - builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}") ); - g_variant_builder_add (builder, "{sv}", GetName (), childResults); - result = g_variant_new ("(a{sv})", builder); - g_variant_builder_unref (builder); + child_results = g_variant_new ("(a{sv})", child_builder); + g_variant_builder_add (builder, "{sv}", GetChildsName (), child_results); + } + g_variant_builder_unref (child_builder); - return result; - } + result = g_variant_new ("(a{sv})", builder); + g_variant_builder_unref (builder); - return childResults; + return result; } void @@ -58,4 +66,10 @@ void Introspectable::RemoveChild (Introspectable *child) { _children.remove (child); -} \ No newline at end of file +} + +const gchar * +Introspectable::GetChildsName () +{ + return GetName (); +} diff --git a/src/Introspectable.h b/src/Introspectable.h index c2182025b..5c58b2a7b 100644 --- a/src/Introspectable.h +++ b/src/Introspectable.h @@ -31,6 +31,7 @@ public: protected: virtual const gchar *GetName () = 0; + virtual const gchar *GetChildsName (); virtual void AddProperties (GVariantBuilder *builder) = 0; /* * AddProperties should be implemented as such ... @@ -51,4 +52,4 @@ private: std::list<Introspectable *> _children; }; -#endif \ No newline at end of file +#endif diff --git a/src/IntrospectionDBusInterface.cpp b/src/IntrospectionDBusInterface.cpp index 7e8a1693b..423529e0f 100644 --- a/src/IntrospectionDBusInterface.cpp +++ b/src/IntrospectionDBusInterface.cpp @@ -18,7 +18,7 @@ #include "IntrospectionDBusInterface.h" -#define UNITY_STATE_DEBUG_BUS_NAME "com.canonical.Unity.Debug" +#define UNITY_STATE_DEBUG_BUS_NAME "com.canonical.Unity" void DBusMethodCall (GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant*, @@ -220,4 +220,4 @@ IntrospectionDBusInterface::BuildFakeReturn () gchar *s = g_variant_print (result, TRUE); g_free (s); return result; -} \ No newline at end of file +} diff --git a/src/Launcher.cpp b/src/Launcher.cpp index 9067b5fa6..e0058c602 100644 --- a/src/Launcher.cpp +++ b/src/Launcher.cpp @@ -1,1867 +1,1973 @@ -/* - * Copyright (C) 2010 Canonical Ltd - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3 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, see <http://www.gnu.org/licenses/>. - * - * Authored by: Jason Smith <jason.smith@canonical.com> - * Authored by: Jay Taoko <jay.taoko@canonical.com> - */ - -#include <math.h> - -#include "Nux/Nux.h" -#include "Nux/VScrollBar.h" -#include "Nux/HLayout.h" -#include "Nux/VLayout.h" -#include "Nux/MenuPage.h" - -#include "NuxGraphics/NuxGraphics.h" -#include "NuxGraphics/GpuDevice.h" -#include "NuxGraphics/GLTextureResourceManager.h" - -#include "Nux/BaseWindow.h" -#include "Nux/WindowCompositor.h" - -#include "Launcher.h" -#include "LauncherIcon.h" -#include "LauncherModel.h" -#include "QuicklistView.h" - -#define ANIM_DURATION_SHORT 125 -#define ANIM_DURATION 200 -#define ANIM_DURATION_LONG 350 - -#define URGENT_BLINKS 3 - -#define MAX_STARTING_BLINKS 5 -#define STARTING_BLINK_LAMBDA 3 - -#define BACKLIGHT_STRENGTH 0.9f - -int -TimeDelta (struct timespec *x, struct timespec *y) -{ - return ((x->tv_sec - y->tv_sec) * 1000) + ((x->tv_nsec - y->tv_nsec) / 1000000); -} - -static bool USE_ARB_SHADERS = true; -/* - Use this shader to pass vertices in screen coordinates in the C++ code and compute use - the fragment shader to perform the texture perspective correct division. - This shader assume the following: - - the projection matrix is orthogonal: glOrtho(0, ScreenWidth, ScreenWidth, 0, Near, Far) - - vertices x and y are in screen coordinates: Vertex(x_screen, y_screen, 0, 1.0) - - the vertices w coordinates has been computed 'manually' - - vertices uv textture coordinates are passed to the shader as: (u/w, v/w, 0, 1/w) - - The texture coordinates s=u/w, t=v/w and q=1w are interpolated linearly in screen coordinates. - In the fragment shader we get the texture coordinates used for the sampling by dividing - s and t resulting from the interpolation by q. - - */ - -nux::NString gPerspectiveCorrectShader = TEXT ( -"[Vertex Shader] \n\ -#version 120 \n\ -uniform mat4 ViewProjectionMatrix; \n\ - \n\ -attribute vec4 iColor; \n\ -attribute vec4 iTexCoord0; \n\ -attribute vec4 iVertex; \n\ - \n\ -varying vec4 varyTexCoord0; \n\ -varying vec4 varyVertexColor; \n\ - \n\ -void main() \n\ -{ \n\ - varyTexCoord0 = iTexCoord0; \n\ - varyVertexColor = iColor; \n\ - gl_Position = ViewProjectionMatrix * iVertex; \n\ -} \n\ - \n\ -[Fragment Shader] \n\ -#version 120 \n\ -#extension GL_ARB_texture_rectangle : enable \n\ - \n\ -varying vec4 varyTexCoord0; \n\ -varying vec4 varyVertexColor; \n\ - \n\ -uniform sampler2D TextureObject0; \n\ -uniform vec4 color0; \n\ -vec4 SampleTexture(sampler2D TexObject, vec4 TexCoord) \n\ -{ \n\ - return texture2D(TexObject, TexCoord.st); \n\ -} \n\ - \n\ -void main() \n\ -{ \n\ - vec4 tex = varyTexCoord0; \n\ - tex.s = tex.s/varyTexCoord0.w; \n\ - tex.t = tex.t/varyTexCoord0.w; \n\ - \n\ - vec4 texel = SampleTexture(TextureObject0, tex); \n\ - gl_FragColor = texel*varyVertexColor; \n\ -} \n\ -"); - -nux::NString PerspectiveCorrectVtx = TEXT ( - "!!ARBvp1.0 \n\ - ATTRIB iPos = vertex.position; \n\ - ATTRIB iColor = vertex.attrib[3]; \n\ - PARAM mvp[4] = {state.matrix.mvp}; \n\ - OUTPUT oPos = result.position; \n\ - OUTPUT oColor = result.color; \n\ - OUTPUT oTexCoord0 = result.texcoord[0]; \n\ - # Transform the vertex to clip coordinates. \n\ - DP4 oPos.x, mvp[0], iPos; \n\ - DP4 oPos.y, mvp[1], iPos; \n\ - DP4 oPos.z, mvp[2], iPos; \n\ - DP4 oPos.w, mvp[3], iPos; \n\ - MOV oColor, iColor; \n\ - MOV oTexCoord0, vertex.attrib[8]; \n\ - END"); - - - -nux::NString PerspectiveCorrectTexFrg = TEXT ( - "!!ARBfp1.0 \n\ - PARAM color0 = program.local[0]; \n\ - TEMP temp; \n\ - TEMP pcoord; \n\ - TEMP tex0; \n\ - TEMP temp1; \n\ - TEMP recip; \n\ - MOV pcoord, fragment.texcoord[0].w; \n\ - RCP temp, fragment.texcoord[0].w; \n\ - MUL pcoord.xy, fragment.texcoord[0], temp; \n\ - TEX tex0, pcoord, texture[0], 2D; \n\ - MUL result.color, color0, tex0; \n\ - END"); - -nux::NString PerspectiveCorrectTexRectFrg = TEXT ( - "!!ARBfp1.0 \n\ - PARAM color0 = program.local[0]; \n\ - TEMP temp; \n\ - TEMP pcoord; \n\ - TEMP tex0; \n\ - MOV pcoord, fragment.texcoord[0].w; \n\ - RCP temp, fragment.texcoord[0].w; \n\ - MUL pcoord.xy, fragment.texcoord[0], temp; \n\ - TEX tex0, pcoord, texture[0], RECT; \n\ - MUL result.color, color0, tex0; \n\ - END"); - -static void GetInverseScreenPerspectiveMatrix(nux::Matrix4& ViewMatrix, nux::Matrix4& PerspectiveMatrix, - int ViewportWidth, - int ViewportHeight, - float NearClipPlane, - float FarClipPlane, - float Fovy); - -Launcher::Launcher(nux::BaseWindow *parent, NUX_FILE_LINE_DECL) -: View(NUX_FILE_LINE_PARAM) -, m_ContentOffsetY(0) -, m_RunningIndicator(0) -, m_ActiveIndicator(0) -, m_BackgroundLayer(0) -, _model (0) -{ - _parent = parent; - _active_quicklist = 0; - - m_Layout = new nux::HLayout(NUX_TRACKER_LOCATION); - - OnMouseDown.connect(sigc::mem_fun(this, &Launcher::RecvMouseDown)); - OnMouseUp.connect(sigc::mem_fun(this, &Launcher::RecvMouseUp)); - OnMouseDrag.connect(sigc::mem_fun(this, &Launcher::RecvMouseDrag)); - OnMouseEnter.connect(sigc::mem_fun(this, &Launcher::RecvMouseEnter)); - OnMouseLeave.connect(sigc::mem_fun(this, &Launcher::RecvMouseLeave)); - OnMouseMove.connect(sigc::mem_fun(this, &Launcher::RecvMouseMove)); - OnMouseWheel.connect(sigc::mem_fun(this, &Launcher::RecvMouseWheel)); - - m_ActiveTooltipIcon = NULL; - m_ActiveMenuIcon = NULL; - - SetCompositionLayout(m_Layout); - - if(!USE_ARB_SHADERS) - { - _shader_program_uv_persp_correction = nux::GetThreadGLDeviceFactory()->CreateShaderProgram(); - _shader_program_uv_persp_correction->LoadIShader(gPerspectiveCorrectShader.GetTCharPtr()); - _shader_program_uv_persp_correction->Link(); - } - else - { - _AsmShaderProg = nux::GetThreadGLDeviceFactory()->CreateAsmShaderProgram(); - _AsmShaderProg->LoadVertexShader (TCHAR_TO_ANSI (*PerspectiveCorrectVtx) ); - - if ((nux::GetThreadGLDeviceFactory()->SUPPORT_GL_ARB_TEXTURE_NON_POWER_OF_TWO() == false) && - (nux::GetThreadGLDeviceFactory()->SUPPORT_GL_EXT_TEXTURE_RECTANGLE () || nux::GetThreadGLDeviceFactory()->SUPPORT_GL_ARB_TEXTURE_RECTANGLE ())) - { - // No support for non power of two textures but support for rectangle textures - _AsmShaderProg->LoadPixelShader (TCHAR_TO_ANSI (*PerspectiveCorrectTexRectFrg) ); - } - else - { - _AsmShaderProg->LoadPixelShader (TCHAR_TO_ANSI (*PerspectiveCorrectTexFrg) ); - } - - _AsmShaderProg->Link(); - } - - _folded_angle = 1.0f; - _neg_folded_angle = -1.0f; - _space_between_icons = 5; - _launcher_top_y = 0; - _launcher_bottom_y = 0; - _folded_z_distance = 10.0f; - _launcher_state = LAUNCHER_FOLDED; - _launcher_action_state = ACTION_NONE; - _icon_under_mouse = NULL; - _icon_mouse_down = NULL; - _icon_image_size = 48; - _icon_glow_size = 62; - _icon_image_size_delta = 6; - _icon_size = _icon_image_size + _icon_image_size_delta; - - _icon_bkg_texture = nux::CreateTextureFromFile (PKGDATADIR"/round_corner_54x54.png"); - _icon_outline_texture = nux::CreateTextureFromFile (PKGDATADIR"/round_outline_54x54.png"); - _icon_shine_texture = nux::CreateTextureFromFile (PKGDATADIR"/round_shine_54x54.png"); - _icon_glow_texture = nux::CreateTextureFromFile (PKGDATADIR"/round_glow_62x62.png"); - _icon_2indicator = nux::CreateTextureFromFile (PKGDATADIR"/2indicate_54x54.png"); - _icon_3indicator = nux::CreateTextureFromFile (PKGDATADIR"/3indicate_54x54.png"); - _icon_4indicator = nux::CreateTextureFromFile (PKGDATADIR"/4indicate_54x54.png"); - - _enter_y = 0; - _dnd_security = 15; - _dnd_delta = 0; - _anim_handle = 0; - _autohide_handle = 0; - _floating = false; - _hovered = false; - _autohide = false; - _hidden = false; - _mouse_inside_launcher = false; - - // 0 out timers to avoid wonky startups - _enter_time.tv_sec = 0; - _enter_time.tv_nsec = 0; - _exit_time.tv_sec = 0; - _exit_time.tv_nsec = 0; - _drag_end_time.tv_sec = 0; - _drag_end_time.tv_nsec = 0; - _autohide_time.tv_sec = 0; - _autohide_time.tv_nsec = 0; -} - -Launcher::~Launcher() -{ - -} - -/* Render Layout Logic */ - -float Launcher::GetHoverProgress () -{ - struct timespec current; - clock_gettime (CLOCK_MONOTONIC, ¤t); - - if (_hovered) - return CLAMP ((float) (TimeDelta (¤t, &_enter_time)) / (float) ANIM_DURATION, 0.0f, 1.0f); - else - return 1.0f - CLAMP ((float) (TimeDelta (¤t, &_exit_time)) / (float) ANIM_DURATION, 0.0f, 1.0f); -} - -float Launcher::DnDExitProgress () -{ - struct timespec current; - clock_gettime (CLOCK_MONOTONIC, ¤t); - - return 1.0f - CLAMP ((float) (TimeDelta (¤t, &_drag_end_time)) / (float) ANIM_DURATION_LONG, 0.0f, 1.0f); -} - -float Launcher::AutohideProgress () -{ - if (!_autohide) - return 0.0f; - - struct timespec current; - clock_gettime (CLOCK_MONOTONIC, ¤t); - - if (_hidden) - return CLAMP ((float) (TimeDelta (¤t, &_autohide_time)) / (float) ANIM_DURATION_SHORT, 0.0f, 1.0f); - else - return 1.0f - CLAMP ((float) (TimeDelta (¤t, &_autohide_time)) / (float) ANIM_DURATION_SHORT, 0.0f, 1.0f); -} - -gboolean Launcher::AnimationTimeout (gpointer data) -{ - Launcher *self = (Launcher*) data; - - self->NeedRedraw (); - - if (self->AnimationInProgress ()) - return true; - - // zero out handle so we know we are done - self->_anim_handle = 0; - return false; -} - -void Launcher::EnsureAnimation () -{ - if (_anim_handle) - return; - - NeedRedraw (); - - if (AnimationInProgress ()) - _anim_handle = g_timeout_add (1000 / 60 - 1, &Launcher::AnimationTimeout, this); -} - -bool Launcher::IconNeedsAnimation (LauncherIcon *icon, struct timespec current) -{ - struct timespec time = icon->GetQuirkTime (LAUNCHER_ICON_QUIRK_VISIBLE); - if (TimeDelta (¤t, &time) < ANIM_DURATION_SHORT) - return true; - - time = icon->GetQuirkTime (LAUNCHER_ICON_QUIRK_RUNNING); - if (TimeDelta (¤t, &time) < ANIM_DURATION_SHORT) - return true; - - time = icon->GetQuirkTime (LAUNCHER_ICON_QUIRK_STARTING); - if (TimeDelta (¤t, &time) < (ANIM_DURATION_LONG * MAX_STARTING_BLINKS * STARTING_BLINK_LAMBDA * 2)) - return true; - - time = icon->GetQuirkTime (LAUNCHER_ICON_QUIRK_URGENT); - if (TimeDelta (¤t, &time) < (ANIM_DURATION_LONG * URGENT_BLINKS * 2)) - return true; - - time = icon->GetQuirkTime (LAUNCHER_ICON_QUIRK_PRESENTED); - if (TimeDelta (¤t, &time) < ANIM_DURATION) - return true; - - time = icon->GetQuirkTime (LAUNCHER_ICON_QUIRK_SHIMMER); - if (TimeDelta (¤t, &time) < ANIM_DURATION_LONG) - return true; - - return false; -} - -bool Launcher::AnimationInProgress () -{ - // performance here can be improved by caching the longer remaining animation found and short circuiting to that each time - // this way extra checks may be avoided - - // short circuit to avoid unneeded calculations - struct timespec current; - clock_gettime (CLOCK_MONOTONIC, ¤t); - - // hover in animation - if (TimeDelta (¤t, &_enter_time) < ANIM_DURATION) - return true; - - // hover out animation - if (TimeDelta (¤t, &_exit_time) < ANIM_DURATION) - return true; - - // drag end animation - if (TimeDelta (¤t, &_drag_end_time) < ANIM_DURATION_LONG) - return true; - - if (TimeDelta (¤t, &_autohide_time) < ANIM_DURATION_SHORT) - return true; - - // animations happening on specific icons - LauncherModel::iterator it; - for (it = _model->begin (); it != _model->end (); it++) - if (IconNeedsAnimation (*it, current)) - return true; - - return false; -} - -void Launcher::SetTimeStruct (struct timespec *timer, struct timespec *sister, int sister_relation) -{ - struct timespec current; - clock_gettime (CLOCK_MONOTONIC, ¤t); - - if (sister) - { - int diff = TimeDelta (¤t, sister); - - if (diff < sister_relation) - { - int remove = sister_relation - diff; - current.tv_sec -= remove / 1000; - remove = remove % 1000; - - if (remove > current.tv_nsec / 1000000) - { - current.tv_sec--; - current.tv_nsec += 1000000000; - } - current.tv_nsec -= remove * 1000000; - } - } - - timer->tv_sec = current.tv_sec; - timer->tv_nsec = current.tv_nsec; -} - -float IconVisibleProgress (LauncherIcon *icon, struct timespec current) -{ - if (icon->GetQuirk (LAUNCHER_ICON_QUIRK_VISIBLE)) - { - struct timespec icon_visible_time = icon->GetQuirkTime (LAUNCHER_ICON_QUIRK_VISIBLE); - int enter_ms = TimeDelta (¤t, &icon_visible_time); - return CLAMP ((float) enter_ms / (float) ANIM_DURATION_SHORT, 0.0f, 1.0f); - } - else - { - struct timespec icon_hide_time = icon->GetQuirkTime (LAUNCHER_ICON_QUIRK_VISIBLE); - int hide_ms = TimeDelta (¤t, &icon_hide_time); - return 1.0f - CLAMP ((float) hide_ms / (float) ANIM_DURATION_SHORT, 0.0f, 1.0f); - } -} - -void Launcher::SetDndDelta (float x, float y, nux::Geometry geo, struct timespec current) -{ - LauncherIcon *anchor = 0; - LauncherModel::iterator it; - anchor = MouseIconIntersection (x, _enter_y); - - if (anchor) - { - float position = y; - for (it = _model->begin (); it != _model->end (); it++) - { - if (*it == anchor) - { - position += _icon_size / 2; - _dnd_delta = _enter_y - position; - - if (position + _icon_size / 2 + _dnd_delta > geo.height) - _dnd_delta -= (position + _icon_size / 2 + _dnd_delta) - geo.height; - - break; - } - position += (_icon_size + _space_between_icons) * IconVisibleProgress (*it, current); - } - } -} - -float Launcher::IconPresentProgress (LauncherIcon *icon, struct timespec current) -{ - struct timespec icon_present_time = icon->GetQuirkTime (LAUNCHER_ICON_QUIRK_PRESENTED); - int ms = TimeDelta (¤t, &icon_present_time); - float result = CLAMP ((float) ms / (float) ANIM_DURATION, 0.0f, 1.0f); - - if (icon->GetQuirk (LAUNCHER_ICON_QUIRK_PRESENTED)) - return result; - else - return 1.0f - result; -} - -float Launcher::IconUrgentProgress (LauncherIcon *icon, struct timespec current) -{ - struct timespec urgent_time = icon->GetQuirkTime (LAUNCHER_ICON_QUIRK_URGENT); - int urgent_ms = TimeDelta (¤t, &urgent_time); - float result = CLAMP ((float) urgent_ms / (float) (ANIM_DURATION_LONG * URGENT_BLINKS * 2), 0.0f, 1.0f); - - if (icon->GetQuirk (LAUNCHER_ICON_QUIRK_URGENT)) - return result; - else - return 1.0f - result; -} - -float Launcher::IconShimmerProgress (LauncherIcon *icon, struct timespec current) -{ - struct timespec shimmer_time = icon->GetQuirkTime (LAUNCHER_ICON_QUIRK_SHIMMER); - int shimmer_ms = TimeDelta (¤t, &shimmer_time); - return CLAMP ((float) shimmer_ms / (float) ANIM_DURATION_LONG, 0.0f, 1.0f); -} - -float Launcher::IconUrgentPulseValue (LauncherIcon *icon, struct timespec current) -{ - if (!icon->GetQuirk (LAUNCHER_ICON_QUIRK_URGENT)) - return 1.0f; // we are full on in a normal condition - - double urgent_progress = (double) IconUrgentProgress (icon, current); - return 0.5f + (float) (std::cos (M_PI * (float) (URGENT_BLINKS * 2) * urgent_progress)) * 0.5f; -} - -float Launcher::IconStartingPulseValue (LauncherIcon *icon, struct timespec current) -{ - struct timespec starting_time = icon->GetQuirkTime (LAUNCHER_ICON_QUIRK_STARTING); - int starting_ms = TimeDelta (¤t, &starting_time); - double starting_progress = (double) CLAMP ((float) starting_ms / (float) (ANIM_DURATION_LONG * MAX_STARTING_BLINKS * STARTING_BLINK_LAMBDA * 2), 0.0f, 1.0f); - - return 1.0f - (0.5f + (float) (std::cos (M_PI * (float) (MAX_STARTING_BLINKS * 2) * starting_progress)) * 0.5f); -} - -float Launcher::IconBackgroundIntensity (LauncherIcon *icon, struct timespec current) -{ - float result = 0.0f; - struct timespec running_time = icon->GetQuirkTime (LAUNCHER_ICON_QUIRK_RUNNING); - int running_ms = TimeDelta (¤t, &running_time); - float running_progress = CLAMP ((float) running_ms / (float) ANIM_DURATION_SHORT, 0.0f, 1.0f); - - // After we finish a fade in from running, we can reset the quirk - if (icon->GetQuirk (LAUNCHER_ICON_QUIRK_RUNNING) && running_progress == 1.0f) - icon->ResetQuirkTime (LAUNCHER_ICON_QUIRK_STARTING); - - result = IconStartingPulseValue (icon, current) * BACKLIGHT_STRENGTH; - - if (icon->GetQuirk (LAUNCHER_ICON_QUIRK_RUNNING)) - { - // running progress fades in whatever the pulsing did not fill in already - result += running_progress * (BACKLIGHT_STRENGTH - result); - - // urgent serves to bring the total down only - if (icon->GetQuirk (LAUNCHER_ICON_QUIRK_URGENT)) - result *= 0.2f + 0.8f * IconUrgentPulseValue (icon, current); - } - else - { - // modestly evil - result += BACKLIGHT_STRENGTH - running_progress * BACKLIGHT_STRENGTH; - } - - return result; -} - -void Launcher::SetupRenderArg (LauncherIcon *icon, struct timespec current, RenderArg &arg) -{ - arg.icon = icon; - arg.alpha = 1.0f; - arg.running_arrow = false; - arg.active_arrow = icon->GetQuirk (LAUNCHER_ICON_QUIRK_ACTIVE); - arg.folding_rads = 0.0f; - arg.skip = false; - - arg.window_indicators = MIN (4, icon->RelatedWindows ()); - - // we dont need to show strays - if (arg.window_indicators == 1 || !icon->GetQuirk (LAUNCHER_ICON_QUIRK_RUNNING)) - arg.window_indicators = 0; - - arg.backlight_intensity = IconBackgroundIntensity (icon, current); - arg.shimmer_progress = IconShimmerProgress (icon, current); - - float urgent_progress = IconUrgentProgress (icon, current); - urgent_progress = CLAMP (urgent_progress * 3, 0.0f, 1.0f); // we want to go 3x faster than the urgent normal cycle - arg.glow_intensity = urgent_progress; -} - -void Launcher::RenderArgs (std::list<Launcher::RenderArg> &launcher_args, - std::list<Launcher::RenderArg> &shelf_args, - nux::Geometry &box_geo, nux::Geometry &shelf_geo) -{ - nux::Geometry geo = GetGeometry (); - LauncherModel::iterator it; - nux::Point3 center; - float hover_progress = GetHoverProgress (); - float folded_z_distance = _folded_z_distance * (1.0f - hover_progress); - float animation_neg_rads = _neg_folded_angle * (1.0f - hover_progress); - int vertical_offset = _parent->GetGeometry ().y; - struct timespec current; - clock_gettime (CLOCK_MONOTONIC, ¤t); - - float folding_constant = 0.25f; - float folding_not_constant = folding_constant + ((1.0f - folding_constant) * hover_progress); - - int folded_size = (int) (_icon_size * folding_not_constant); - int folded_spacing = (int) (_space_between_icons * folding_not_constant); - - center.x = geo.width / 2; - center.y = _space_between_icons; - center.z = 0; - - // compute required height of shelf - float shelf_sum = 0.0f; - for (it = _model->shelf_begin (); it != _model->shelf_end (); it++) - { - float height = (_icon_size + _space_between_icons) * IconVisibleProgress (*it, current); - shelf_sum += height; - } - - // add bottom padding - if (shelf_sum > 0.0f) - shelf_sum += _space_between_icons; - - int launcher_height = geo.height - shelf_sum; - - // compute required height of launcher AND folding threshold - float sum = 0.0f + center.y; - int folding_threshold = launcher_height - _icon_size / 2.5f; - for (it = _model->begin (); it != _model->end (); it++) - { - float height = (_icon_size + _space_between_icons) * IconVisibleProgress (*it, current); - sum += height; - - // magic constant must some day be explained, for now suffice to say this constant prevents the bottom from "marching"; - float magic_constant = 1.2f; - - float present_progress = IconPresentProgress (*it, current); - folding_threshold -= CLAMP (sum - launcher_height, 0.0f, height * magic_constant) * (folding_constant + (1.0f - folding_constant) * present_progress); - } - - // this happens on hover, basically its a flag and a value in one, we translate this into a dnd offset - if (_enter_y != 0 && _enter_y + _icon_size / 2 > folding_threshold) - SetDndDelta (center.x, center.y, nux::Geometry (geo.x, geo.y, geo.width, geo.height - shelf_sum), current); - - _enter_y = 0; - - if (hover_progress > 0.0f && _dnd_delta != 0) - { - int delta_y = _dnd_delta; - - // logically dnd exit only restores to the clamped ranges - // hover_progress restores to 0 - - if (_launcher_action_state != ACTION_DRAG_LAUNCHER) - { - float dnd_progress = DnDExitProgress (); - - float max = 0.0f; - float min = MIN (0.0f, launcher_height - sum); - - if (_dnd_delta > max) - delta_y = max + (delta_y - max) * dnd_progress; - else if (_dnd_delta < min) - delta_y = min + (delta_y - min) * dnd_progress; - - if (dnd_progress == 0.0f) - _dnd_delta = (int) delta_y; - } - - delta_y *= hover_progress; - center.y += delta_y; - } - else - { - _dnd_delta = 0; - } - - float autohide_progress = AutohideProgress (); - float autohide_offset = 0.0f; - if (_autohide && autohide_progress > 0.0f) - { - autohide_offset -= geo.width * autohide_progress; - } - - // Inform the painter where to paint the box - box_geo = geo; - - if (_floating) - box_geo.height = sum + shelf_sum + _space_between_icons; - - if (_autohide) - box_geo.x += autohide_offset; - - shelf_geo = nux::Geometry (box_geo.x, box_geo.height - shelf_sum, box_geo.width, shelf_sum); - - // The functional position we wish to represent for these icons is not smooth. Rather than introducing - // special casing to represent this, we use MIN/MAX functions. This helps ensure that even though our - // function is not smooth it is continuous, which is more important for our visual representation (icons - // wont start jumping around). As a general rule ANY if () statements that modify center.y should be seen - // as bugs. - for (it = _model->begin (); it != _model->end (); it++) - { - RenderArg arg; - LauncherIcon *icon = *it; - - SetupRenderArg (icon, current, arg); - - // reset z - center.z = 0; - - float size_modifier = IconVisibleProgress (icon, current); - if (size_modifier < 1.0f) - { - arg.alpha = size_modifier; - center.z = 300.0f * (1.0f - size_modifier); - } - - if (size_modifier <= 0.0f) - { - arg.skip = true; - continue; - } - - // goes for 0.0f when fully unfolded, to 1.0f folded - float folding_progress = CLAMP ((center.y + _icon_size - folding_threshold) / (float) _icon_size, 0.0f, 1.0f); - float present_progress = IconPresentProgress (icon, current); - - folding_progress *= 1.0f - present_progress; - - float half_size = (folded_size / 2.0f) + (_icon_size / 2.0f - folded_size / 2.0f) * (1.0f - folding_progress); - - float icon_hide_offset = autohide_offset; - - if (icon->PresentUrgency () == 1) - icon_hide_offset *= 0.5f + 0.5f * (1.0f - present_progress); - else if (icon->PresentUrgency () >= 2) - icon_hide_offset *= 1.0f - present_progress; - - // icon is crossing threshold, start folding - center.z += folded_z_distance * folding_progress; - arg.folding_rads = animation_neg_rads * folding_progress; - - center.y += half_size * size_modifier; // move to center - arg.center = nux::Point3 (center.x + icon_hide_offset, center.y, center.z); // copy center - icon->SetCenter (nux::Point3 (center.x, center.y + vertical_offset, center.z)); - center.y += half_size * size_modifier; // move to end - - float spacing_overlap = CLAMP ((float) (center.y + (_space_between_icons * size_modifier) - folding_threshold) / (float) _icon_size, 0.0f, 1.0f); - //add spacing - center.y += (_space_between_icons * (1.0f - spacing_overlap) + folded_spacing * spacing_overlap) * size_modifier; - - launcher_args.push_back (arg); - } - - center.y = (box_geo.y + box_geo.height) - shelf_sum + _space_between_icons; - - // Place shelf icons - for (it = _model->shelf_begin (); it != _model->shelf_end (); it++) - { - RenderArg arg; - LauncherIcon *icon = *it; - - SetupRenderArg (icon, current, arg); - - // reset z - center.z = 0; - - float size_modifier = IconVisibleProgress (icon, current); - if (size_modifier < 1.0f) - { - arg.alpha = size_modifier; - center.z = 300.0f * (1.0f - size_modifier); - } - - if (size_modifier <= 0.0f) - { - arg.skip = true; - continue; - } - - float half_size = _icon_size / 2.0f; - - center.y += half_size * size_modifier; // move to center - arg.center = nux::Point3 (center.x + autohide_offset, center.y, center.z); // copy center - icon->SetCenter (nux::Point3 (center.x, center.y + vertical_offset, center.z)); - center.y += half_size * size_modifier; // move to end - center.y += _space_between_icons * size_modifier; - - shelf_args.push_back (arg); - } -} - -/* End Render Layout Logic */ - -void Launcher::SetHidden (bool hidden) -{ - if (hidden == _hidden) - return; - - _hidden = hidden; - SetTimeStruct (&_autohide_time, &_autohide_time, ANIM_DURATION); - - _parent->EnableInputWindow(!hidden); - - EnsureAnimation (); -} - -gboolean Launcher::OnAutohideTimeout (gpointer data) -{ - Launcher *self = (Launcher*) data; - - if (self->_hovered || self->_hidden) - return false; - - self->SetHidden (true); - - self->_autohide_handle = 0; - return false; -} - -void Launcher::OnTriggerMouseEnter (int x, int y, unsigned long button_flags, unsigned long key_flags) -{ - if (!_autohide || !_hidden) - return; - - SetHidden (false); -} - -void Launcher::SetupAutohideTimer () -{ - if (_autohide) - { - if (_autohide_handle > 0) - g_source_remove (_autohide_handle); - _autohide_handle = g_timeout_add (1000, &Launcher::OnAutohideTimeout, this); - } -} - -void Launcher::OnTriggerMouseLeave (int x, int y, unsigned long button_flags, unsigned long key_flags) -{ - SetupAutohideTimer (); -} - -bool Launcher::AutohideEnabled () -{ - return _autohide; -} - -gboolean Launcher::StrutHack (gpointer data) -{ - Launcher *self = (Launcher *) data; - self->_parent->InputWindowEnableStruts(false); - self->_parent->InputWindowEnableStruts(true); - - return false; -} - -void Launcher::SetAutohide (bool autohide, nux::View *trigger) -{ - if (_autohide == autohide) - return; - - if (autohide) - { - _parent->InputWindowEnableStruts(false); - _autohide_trigger = trigger; - _autohide_trigger->OnMouseEnter.connect (sigc::mem_fun(this, &Launcher::OnTriggerMouseEnter)); - _autohide_trigger->OnMouseLeave.connect (sigc::mem_fun(this, &Launcher::OnTriggerMouseLeave)); - } - else - { - _parent->EnableInputWindow(true); - g_timeout_add (1000, &Launcher::StrutHack, this); - _parent->InputWindowEnableStruts(true); - } - - _autohide = autohide; - EnsureAnimation (); -} - -void Launcher::SetFloating (bool floating) -{ - if (_floating == floating) - return; - - _floating = floating; - EnsureAnimation (); -} - -void Launcher::SetHover () -{ - if (_hovered) - return; - - _enter_y = (int) _mouse_position.y; - - if (_last_shelf_area.y - _enter_y < 5 && _last_shelf_area.y - _enter_y >= 0) - _enter_y = _last_shelf_area.y - 5; - - _hovered = true; - SetTimeStruct (&_enter_time, &_exit_time, ANIM_DURATION); -} - -void Launcher::UnsetHover () -{ - if (!_hovered) - return; - - _hovered = false; - SetTimeStruct (&_exit_time, &_enter_time, ANIM_DURATION); - SetupAutohideTimer (); -} - -void Launcher::SetIconSize(int tile_size, int icon_size) -{ - nux::Geometry geo = _parent->GetGeometry (); - - _icon_size = tile_size; - _icon_image_size = icon_size; - _icon_image_size_delta = tile_size - icon_size; - - // recreate tile textures - - _parent->SetGeometry (nux::Geometry (geo.x, geo.y, tile_size + 12, geo.height)); -} - -void Launcher::OnIconAdded (void *icon_pointer) -{ - LauncherIcon *icon = (LauncherIcon *) icon_pointer; - icon->Reference (); - EnsureAnimation(); - - // How to free these properly? - icon->_xform_coords["HitArea"] = new nux::Vector4[4]; - icon->_xform_coords["Image"] = new nux::Vector4[4]; - icon->_xform_coords["Tile"] = new nux::Vector4[4]; - icon->_xform_coords["Glow"] = new nux::Vector4[4]; - - // needs to be disconnected - icon->needs_redraw.connect (sigc::mem_fun(this, &Launcher::OnIconNeedsRedraw)); -} - -void Launcher::OnIconRemoved (void *icon_pointer) -{ - LauncherIcon *icon = (LauncherIcon *) icon_pointer; - icon->UnReference (); - - EnsureAnimation(); -} - -void Launcher::OnOrderChanged () -{ - -} - -void Launcher::SetModel (LauncherModel *model) -{ - _model = model; - _model->icon_added.connect (sigc::mem_fun (this, &Launcher::OnIconAdded)); - _model->icon_removed.connect (sigc::mem_fun (this, &Launcher::OnIconRemoved)); - _model->order_changed.connect (sigc::mem_fun (this, &Launcher::OnOrderChanged)); -} - -void Launcher::OnIconNeedsRedraw (void *icon) -{ - EnsureAnimation(); -} - -long Launcher::ProcessEvent(nux::IEvent &ievent, long TraverseInfo, long ProcessEventInfo) -{ - long ret = TraverseInfo; - ret = PostProcessEvent2(ievent, ret, ProcessEventInfo); - return ret; -} - -void Launcher::Draw(nux::GraphicsEngine& GfxContext, bool force_draw) -{ - -} - -void Launcher::RenderIcon(nux::GraphicsEngine& GfxContext, - RenderArg arg, - nux::BaseTexture *icon, - nux::Color bkg_color, - float alpha, - nux::Vector4 xform_coords[], - nux::Geometry geo, - bool render_indicators) -{ - nux::Matrix4 ObjectMatrix; - nux::Matrix4 ViewMatrix; - nux::Matrix4 ProjectionMatrix; - nux::Matrix4 ViewProjectionMatrix; - - if(nux::Abs (arg.folding_rads) < 0.01f) - icon->GetDeviceTexture()->SetFiltering(GL_NEAREST, GL_NEAREST); - else - icon->GetDeviceTexture()->SetFiltering(GL_LINEAR, GL_LINEAR); - - nux::Vector4 v0; - nux::Vector4 v1; - nux::Vector4 v2; - nux::Vector4 v3; - - v0.x = xform_coords[0].x ; - v0.y = xform_coords[0].y ; - v0.z = xform_coords[0].z ; - v0.w = xform_coords[0].w ; - v1.x = xform_coords[1].x ; - v1.y = xform_coords[1].y ; - v1.z = xform_coords[1].z ; - v1.w = xform_coords[1].w ; - v2.x = xform_coords[2].x ; - v2.y = xform_coords[2].y ; - v2.z = xform_coords[2].z ; - v2.w = xform_coords[2].w ; - v3.x = xform_coords[3].x ; - v3.y = xform_coords[3].y ; - v3.z = xform_coords[3].z ; - v3.w = xform_coords[3].w ; - - float s0, t0, s1, t1, s2, t2, s3, t3; - nux::Color color = nux::Color::White; - - if (icon->Type ().IsDerivedFromType(nux::TextureRectangle::StaticObjectType)) - { - s0 = 0.0f; t0 = 0.0f; - s1 = 0.0f; t1 = icon->GetHeight(); - s2 = icon->GetWidth(); t2 = icon->GetHeight(); - s3 = icon->GetWidth(); t3 = 0.0f; - } - else - { - s0 = 0.0f; t0 = 0.0f; - s1 = 0.0f; t1 = 1.0f; - s2 = 1.0f; t2 = 1.0f; - s3 = 1.0f; t3 = 0.0f; - } - - float VtxBuffer[] = - {// Perspective correct - v0.x, v0.y, 0.0f, 1.0f, s0/v0.w, t0/v0.w, 0.0f, 1.0f/v0.w, color.R(), color.G(), color.B(), color.A(), - v1.x, v1.y, 0.0f, 1.0f, s1/v1.w, t1/v1.w, 0.0f, 1.0f/v1.w, color.R(), color.G(), color.B(), color.A(), - v2.x, v2.y, 0.0f, 1.0f, s2/v2.w, t2/v2.w, 0.0f, 1.0f/v2.w, color.R(), color.G(), color.B(), color.A(), - v3.x, v3.y, 0.0f, 1.0f, s3/v3.w, t3/v3.w, 0.0f, 1.0f/v3.w, color.R(), color.G(), color.B(), color.A(), - }; - - CHECKGL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0)); - CHECKGL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0)); - - int TextureObjectLocation; - int VertexLocation; - int TextureCoord0Location; - int VertexColorLocation; - int FragmentColor; - - if(!USE_ARB_SHADERS) - { - _shader_program_uv_persp_correction->Begin(); - - TextureObjectLocation = _shader_program_uv_persp_correction->GetUniformLocationARB("TextureObject0"); - VertexLocation = _shader_program_uv_persp_correction->GetAttributeLocation("iVertex"); - TextureCoord0Location = _shader_program_uv_persp_correction->GetAttributeLocation("iTexCoord0"); - VertexColorLocation = _shader_program_uv_persp_correction->GetAttributeLocation("iColor"); - FragmentColor = _shader_program_uv_persp_correction->GetUniformLocationARB ("color"); - - nux::GetGraphicsEngine ().SetTexture(GL_TEXTURE0, icon); - - if(TextureObjectLocation != -1) - CHECKGL( glUniform1iARB (TextureObjectLocation, 0) ); - - int VPMatrixLocation = _shader_program_uv_persp_correction->GetUniformLocationARB("ViewProjectionMatrix"); - if(VPMatrixLocation != -1) - { - nux::Matrix4 mat = nux::GetGraphicsEngine ().GetModelViewProjectionMatrix (); - _shader_program_uv_persp_correction->SetUniformLocMatrix4fv ((GLint)VPMatrixLocation, 1, false, (GLfloat*)&(mat.m)); - } - } - else - { - _AsmShaderProg->Begin(); - - VertexLocation = nux::VTXATTRIB_POSITION; - TextureCoord0Location = nux::VTXATTRIB_TEXCOORD0; - VertexColorLocation = nux::VTXATTRIB_COLOR; - - nux::GetGraphicsEngine().SetTexture(GL_TEXTURE0, icon); - } - - CHECKGL( glEnableVertexAttribArrayARB(VertexLocation) ); - CHECKGL( glVertexAttribPointerARB((GLuint)VertexLocation, 4, GL_FLOAT, GL_FALSE, 48, VtxBuffer) ); - - if(TextureCoord0Location != -1) - { - CHECKGL( glEnableVertexAttribArrayARB(TextureCoord0Location) ); - CHECKGL( glVertexAttribPointerARB((GLuint)TextureCoord0Location, 4, GL_FLOAT, GL_FALSE, 48, VtxBuffer + 4) ); - } - - if(VertexColorLocation != -1) - { - CHECKGL( glEnableVertexAttribArrayARB(VertexColorLocation) ); - CHECKGL( glVertexAttribPointerARB((GLuint)VertexColorLocation, 4, GL_FLOAT, GL_FALSE, 48, VtxBuffer + 8) ); - } - - bkg_color.SetAlpha (bkg_color.A () * alpha); - - if(!USE_ARB_SHADERS) - { - CHECKGL ( glUniform4fARB (FragmentColor, bkg_color.R(), bkg_color.G(), bkg_color.B(), bkg_color.A() ) ); - nux::GetGraphicsEngine ().SetTexture(GL_TEXTURE0, icon); - CHECKGL( glDrawArrays(GL_QUADS, 0, 4) ); - } - else - { - CHECKGL ( glProgramLocalParameter4fARB (GL_FRAGMENT_PROGRAM_ARB, 0, bkg_color.R(), bkg_color.G(), bkg_color.B(), bkg_color.A() ) ); - nux::GetGraphicsEngine ().SetTexture(GL_TEXTURE0, icon); - CHECKGL( glDrawArrays(GL_QUADS, 0, 4) ); - } - - if(VertexLocation != -1) - CHECKGL( glDisableVertexAttribArrayARB(VertexLocation) ); - if(TextureCoord0Location != -1) - CHECKGL( glDisableVertexAttribArrayARB(TextureCoord0Location) ); - if(VertexColorLocation != -1) - CHECKGL( glDisableVertexAttribArrayARB(VertexColorLocation) ); - - if(!USE_ARB_SHADERS) - { - _shader_program_uv_persp_correction->End(); - } - else - { - _AsmShaderProg->End(); - } - - int markerCenter = (v1.y + v0.y) / 2; - - if (arg.running_arrow && render_indicators) - { - if (!m_RunningIndicator) - { - GdkPixbuf *pbuf = gdk_pixbuf_new_from_file (PKGDATADIR"/running_indicator.png", NULL); - m_RunningIndicator = nux::CreateTextureFromPixbuf (pbuf); - g_object_unref (pbuf); - } - gPainter.Draw2DTexture (GfxContext, m_RunningIndicator, geo.x, markerCenter - (m_ActiveIndicator->GetHeight () / 2)); - } - - if (arg.active_arrow && render_indicators) - { - if (!m_ActiveIndicator) - { - GdkPixbuf *pbuf = gdk_pixbuf_new_from_file (PKGDATADIR"/focused_indicator.png", NULL); - m_ActiveIndicator = nux::CreateTextureFromPixbuf (pbuf); - g_object_unref (pbuf); - } - gPainter.Draw2DTexture (GfxContext, m_ActiveIndicator, (geo.x + geo.width) - m_ActiveIndicator->GetWidth (), markerCenter - (m_ActiveIndicator->GetHeight () / 2)); - } -} - -void Launcher::DrawRenderArg (nux::GraphicsEngine& GfxContext, RenderArg arg, nux::Geometry geo) -{ - GfxContext.GetRenderStates ().SetSeparateBlend (true, - GL_SRC_ALPHA, - GL_ONE_MINUS_SRC_ALPHA, - GL_ONE_MINUS_DST_ALPHA, - GL_ONE); - - GfxContext.GetRenderStates ().SetColorMask (true, true, true, true); - - if (arg.backlight_intensity < 1.0f) - { - RenderIcon(GfxContext, - arg, - _icon_outline_texture, - nux::Color(0xFF6D6D6D), - 1.0f - arg.backlight_intensity, - arg.icon->_xform_coords["Tile"], - geo, - false); - } - - if (arg.backlight_intensity > 0.0f) - { - RenderIcon(GfxContext, - arg, - _icon_bkg_texture, - arg.icon->BackgroundColor (), - arg.backlight_intensity, - arg.icon->_xform_coords["Tile"], - geo, - false); - } - - GfxContext.GetRenderStates ().SetSeparateBlend (true, - GL_SRC_ALPHA, - GL_ONE_MINUS_SRC_ALPHA, - GL_ONE_MINUS_DST_ALPHA, - GL_ONE); - GfxContext.GetRenderStates ().SetColorMask (true, true, true, true); - - RenderIcon (GfxContext, - arg, - arg.icon->TextureForSize (_icon_image_size), - nux::Color::White, - arg.alpha, - arg.icon->_xform_coords["Image"], - geo, - true); - - if (arg.backlight_intensity > 0.0f) - { - RenderIcon(GfxContext, - arg, - _icon_shine_texture, - nux::Color::White, - arg.backlight_intensity, - arg.icon->_xform_coords["Tile"], - geo, - false); - } - - switch (arg.window_indicators) - { - case 2: - RenderIcon(GfxContext, - arg, - _icon_2indicator, - nux::Color::White, - 1.0f, - arg.icon->_xform_coords["Tile"], - geo, - false); - break; - case 3: - RenderIcon(GfxContext, - arg, - _icon_3indicator, - nux::Color::White, - 1.0f, - arg.icon->_xform_coords["Tile"], - geo, - false); - break; - case 4: - RenderIcon(GfxContext, - arg, - _icon_4indicator, - nux::Color::White, - 1.0f, - arg.icon->_xform_coords["Tile"], - geo, - false); - break; - } - - if (arg.glow_intensity > 0.0f) - { - RenderIcon(GfxContext, - arg, - _icon_glow_texture, - arg.icon->GlowColor (), - arg.glow_intensity, - arg.icon->_xform_coords["Glow"], - geo, - false); - } - - if (arg.shimmer_progress > 0.0f && arg.shimmer_progress < 1.0f) - { - nux::Geometry base = GetGeometry (); - int x1 = base.x + base.width; - int x2 = base.x + base.width; - float shimmer_constant = 1.9f; - - x1 -= geo.width * arg.shimmer_progress * shimmer_constant; - GfxContext.PushClippingRectangle(nux::Geometry (x1, geo.y, x2 - x1, geo.height)); - - float fade_out = 1.0f - CLAMP (((x2 - x1) - geo.width) / (geo.width * (shimmer_constant - 1.0f)), 0.0f, 1.0f); - - RenderIcon(GfxContext, - arg, - _icon_glow_texture, - arg.icon->GlowColor (), - fade_out, - arg.icon->_xform_coords["Glow"], - geo, - false); - - GfxContext.PopClippingRectangle(); - } -} - -void Launcher::DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw) -{ - nux::Geometry base = GetGeometry(); - GfxContext.PushClippingRectangle(base); - nux::Geometry bkg_box; - nux::Geometry shelf_box; - std::list<Launcher::RenderArg> args; - std::list<Launcher::RenderArg> shelf_args; - - nux::ROPConfig ROP; - ROP.Blend = false; - ROP.SrcBlend = GL_SRC_ALPHA; - ROP.DstBlend = GL_ONE_MINUS_SRC_ALPHA; - - RenderArgs (args, shelf_args, bkg_box, shelf_box); - _last_shelf_area = shelf_box; - - // clear region - gPainter.PushDrawColorLayer(GfxContext, base, nux::Color(0x00000000), true, ROP); - - // clip vertically but not horizontally - GfxContext.PushClippingRectangle(nux::Geometry (base.x, bkg_box.y, base.width, bkg_box.height)); - GfxContext.GetRenderStates ().SetSeparateBlend (true, - GL_SRC_ALPHA, - GL_ONE_MINUS_SRC_ALPHA, - GL_ONE_MINUS_DST_ALPHA, - GL_ONE); - - gPainter.Paint2DQuadColor (GfxContext, bkg_box, nux::Color(0xAA000000)); - - UpdateIconXForm (args); - UpdateIconXForm (shelf_args); - EventLogic (); - - /* drag launcher */ - std::list<Launcher::RenderArg>::reverse_iterator rev_it; - for (rev_it = args.rbegin (); rev_it != args.rend (); rev_it++) - { - if ((*rev_it).folding_rads >= 0.0f || (*rev_it).skip) - continue; - - DrawRenderArg (GfxContext, *rev_it, bkg_box); - } - - std::list<Launcher::RenderArg>::iterator it; - for (it = args.begin(); it != args.end(); it++) - { - if ((*it).folding_rads < 0.0f || (*it).skip) - continue; - - DrawRenderArg (GfxContext, *it, bkg_box); - } - - /* draw shelf */ - nux::Color shelf_color = nux::Color (0xCC000000); - nux::Color shelf_zero = nux::Color (0x00000000); - int shelf_shadow_height = 35; - - nux::Geometry shelf_shadow = nux::Geometry (shelf_box.x, shelf_box.y - shelf_shadow_height, shelf_box.width, shelf_shadow_height); - gPainter.Paint2DQuadColor (GfxContext, shelf_shadow, shelf_zero, shelf_color, shelf_color, shelf_zero); - gPainter.Paint2DQuadColor (GfxContext, shelf_box, shelf_color); - - for (it = shelf_args.begin(); it != shelf_args.end(); it++) - { - if ((*it).skip) - continue; - - DrawRenderArg (GfxContext, *it, bkg_box); - } - - gPainter.Paint2DQuadColor (GfxContext, nux::Geometry (bkg_box.x + bkg_box.width - 1, bkg_box.y, 1, bkg_box.height), nux::Color(0x60FFFFFF)); - - GfxContext.GetRenderStates().SetColorMask (true, true, true, true); - GfxContext.GetRenderStates ().SetSeparateBlend (false, - GL_SRC_ALPHA, - GL_ONE_MINUS_SRC_ALPHA, - GL_SRC_ALPHA, - GL_ONE_MINUS_SRC_ALPHA); - - gPainter.PopBackground(); - GfxContext.PopClippingRectangle(); - GfxContext.PopClippingRectangle(); -} - -void Launcher::PostDraw(nux::GraphicsEngine& GfxContext, bool force_draw) -{ -} - -void Launcher::PreLayoutManagement() -{ - View::PreLayoutManagement(); - if(m_CompositionLayout) - { - m_CompositionLayout->SetGeometry(GetGeometry()); - } -} - -long Launcher::PostLayoutManagement(long LayoutResult) -{ - View::PostLayoutManagement(LayoutResult); - - _mouse_position = nux::Point2 (0, 0); - - return nux::eCompliantHeight | nux::eCompliantWidth; -} - -void Launcher::PositionChildLayout(float offsetX, float offsetY) -{ -} - -bool Launcher::TooltipNotify(LauncherIcon* Icon) -{ - if(GetActiveMenuIcon()) - return false; - return true; -} - -bool Launcher::MenuNotify(LauncherIcon* Icon) -{ - - - return true; -} - -void Launcher::NotifyMenuTermination(LauncherIcon* Icon) -{ -} - -void Launcher::RecvMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags) -{ - _mouse_position = nux::Point2 (x, y); - - MouseDownLogic (x, y, button_flags, key_flags); - EnsureAnimation (); -} - -void Launcher::RecvMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags) -{ - _mouse_position = nux::Point2 (x, y); - nux::Geometry geo = GetGeometry (); - - if (_launcher_action_state == ACTION_DRAG_LAUNCHER && !geo.IsInside(nux::Point(x, y))) - { - // we are no longer hovered - UnsetHover (); - } - - MouseUpLogic (x, y, button_flags, key_flags); - _launcher_action_state = ACTION_NONE; - EnsureAnimation (); -} - -void Launcher::RecvMouseDrag(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags) -{ - _mouse_position = nux::Point2 (x, y); - - _dnd_delta += dy; - - if (nux::Abs (_dnd_delta) < 15 && _launcher_action_state != ACTION_DRAG_LAUNCHER) - return; - - if (_icon_under_mouse) - { - _icon_under_mouse->MouseLeave.emit (); - _icon_under_mouse->_mouse_inside = false; - _icon_under_mouse = 0; - } - - _launcher_action_state = ACTION_DRAG_LAUNCHER; - EnsureAnimation (); -} - -void Launcher::RecvMouseEnter(int x, int y, unsigned long button_flags, unsigned long key_flags) -{ - _mouse_position = nux::Point2 (x, y); - _mouse_inside_launcher = true; - - if (!_last_shelf_area.IsInside (nux::Point (x, y))) - SetHover (); - - EventLogic (); - EnsureAnimation (); -} - -void Launcher::RecvMouseLeave(int x, int y, unsigned long button_flags, unsigned long key_flags) -{ - _mouse_position = nux::Point2 (x, y); - _mouse_inside_launcher = false; - - if (_launcher_action_state != ACTION_DRAG_LAUNCHER) - UnsetHover (); - - EventLogic (); - EnsureAnimation (); -} - -void Launcher::RecvMouseMove(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags) -{ - _mouse_position = nux::Point2 (x, y); - - if (!_last_shelf_area.IsInside (nux::Point (x, y))) - { - SetHover (); - EnsureAnimation (); - } - // Every time the mouse moves, we check if it is inside an icon... - - EventLogic (); -} - -void Launcher::RecvMouseWheel(int x, int y, int wheel_delta, unsigned long button_flags, unsigned long key_flags) -{ -} - -const gchar* Launcher::GetName () -{ - return "Launcher"; -} - -void Launcher::AddProperties (GVariantBuilder *builder) -{ -} - -void Launcher::EventLogic () -{ - if (_launcher_action_state == ACTION_DRAG_LAUNCHER) - return; - - LauncherIcon* launcher_icon = 0; - - if (_mouse_inside_launcher) - launcher_icon = MouseIconIntersection (_mouse_position.x, _mouse_position.y); - - if (_icon_under_mouse && (_icon_under_mouse != launcher_icon)) - { - _icon_under_mouse->MouseLeave.emit (); - _icon_under_mouse->_mouse_inside = false; - _icon_under_mouse = 0; - } - - if (launcher_icon && (_icon_under_mouse != launcher_icon)) - { - launcher_icon->MouseEnter.emit (); - launcher_icon->_mouse_inside = true; - _icon_under_mouse = launcher_icon; - } -} - -void Launcher::MouseDownLogic (int x, int y, unsigned long button_flags, unsigned long key_flags) -{ - LauncherIcon* launcher_icon = 0; - launcher_icon = MouseIconIntersection (_mouse_position.x, _mouse_position.y); - - if (launcher_icon) - { - _icon_mouse_down = launcher_icon; - launcher_icon->MouseDown.emit (nux::GetEventButton (button_flags)); - } -} - -void Launcher::MouseUpLogic (int x, int y, unsigned long button_flags, unsigned long key_flags) -{ - LauncherIcon* launcher_icon = 0; - launcher_icon = MouseIconIntersection (_mouse_position.x, _mouse_position.y); - - if (_icon_mouse_down && (_icon_mouse_down == launcher_icon)) - { - _icon_mouse_down->MouseUp.emit (nux::GetEventButton (button_flags)); - - if (_launcher_action_state != ACTION_DRAG_LAUNCHER) - _icon_mouse_down->MouseClick.emit (nux::GetEventButton (button_flags)); - } - - if (launcher_icon && (_icon_mouse_down != launcher_icon)) - { - launcher_icon->MouseUp.emit (nux::GetEventButton (button_flags)); - } - - if (_launcher_action_state == ACTION_DRAG_LAUNCHER) - { - SetTimeStruct (&_drag_end_time); - } - - _icon_mouse_down = 0; -} - -LauncherIcon* Launcher::MouseIconIntersection (int x, int y) -{ - LauncherModel::iterator it; - LauncherModel::reverse_iterator rev_it; - // We are looking for the icon at screen coordinates x, y; - nux::Point2 mouse_position(x, y); - int inside = 0; - - for (it = _model->shelf_begin(); it != _model->shelf_end (); it++) - { - if (!(*it)->GetQuirk (LAUNCHER_ICON_QUIRK_VISIBLE)) - continue; - - nux::Point2 screen_coord [4]; - for (int i = 0; i < 4; i++) - { - screen_coord [i].x = (*it)->_xform_coords["HitArea"] [i].x; - screen_coord [i].y = (*it)->_xform_coords["HitArea"] [i].y; - } - inside = PointInside2DPolygon (screen_coord, 4, mouse_position, 1); - if (inside) - return (*it); - } - - // Because of the way icons fold and stack on one another, we must proceed in 2 steps. - for (rev_it = _model->rbegin (); rev_it != _model->rend (); rev_it++) - { - if ((*rev_it)->_folding_angle < 0.0f || !(*rev_it)->GetQuirk (LAUNCHER_ICON_QUIRK_VISIBLE)) - continue; - - nux::Point2 screen_coord [4]; - for (int i = 0; i < 4; i++) - { - screen_coord [i].x = (*rev_it)->_xform_coords["HitArea"] [i].x; - screen_coord [i].y = (*rev_it)->_xform_coords["HitArea"] [i].y; - } - inside = PointInside2DPolygon (screen_coord, 4, mouse_position, 1); - if (inside) - return (*rev_it); - } - - for (it = _model->begin(); it != _model->end (); it++) - { - if ((*it)->_folding_angle >= 0.0f || !(*it)->GetQuirk (LAUNCHER_ICON_QUIRK_VISIBLE)) - continue; - - nux::Point2 screen_coord [4]; - for (int i = 0; i < 4; i++) - { - screen_coord [i].x = (*it)->_xform_coords["HitArea"] [i].x; - screen_coord [i].y = (*it)->_xform_coords["HitArea"] [i].y; - } - inside = PointInside2DPolygon (screen_coord, 4, mouse_position, 1); - if (inside) - return (*it); - } - - return 0; -} - -void Launcher::SetIconXForm (LauncherIcon *icon, nux::Matrix4 ViewProjectionMatrix, nux::Geometry geo, - float x, float y, float w, float h, float z, std::string name) -{ - nux::Vector4 v0 = nux::Vector4(x, y, z, 1.0f); - nux::Vector4 v1 = nux::Vector4(x, y+h, z, 1.0f); - nux::Vector4 v2 = nux::Vector4(x+w, y+h, z, 1.0f); - nux::Vector4 v3 = nux::Vector4(x+w, y, z, 1.0f); - - v0 = ViewProjectionMatrix * v0; - v1 = ViewProjectionMatrix * v1; - v2 = ViewProjectionMatrix * v2; - v3 = ViewProjectionMatrix * v3; - - v0.divide_xyz_by_w(); - v1.divide_xyz_by_w(); - v2.divide_xyz_by_w(); - v3.divide_xyz_by_w(); - - // normalize to the viewport coordinates and translate to the correct location - v0.x = geo.width *(v0.x + 1.0f)/2.0f - geo.width/2.0f + x + w/2.0f; - v0.y = -geo.height*(v0.y - 1.0f)/2.0f - geo.height/2.0f + y + h/2.0f; - v1.x = geo.width *(v1.x + 1.0f)/2.0f - geo.width/2.0f + x + w/2.0f;; - v1.y = -geo.height*(v1.y - 1.0f)/2.0f - geo.height/2.0f + y + h/2.0f; - v2.x = geo.width *(v2.x + 1.0f)/2.0f - geo.width/2.0f + x + w/2.0f; - v2.y = -geo.height*(v2.y - 1.0f)/2.0f - geo.height/2.0f + y + h/2.0f; - v3.x = geo.width *(v3.x + 1.0f)/2.0f - geo.width/2.0f + x + w/2.0f; - v3.y = -geo.height*(v3.y - 1.0f)/2.0f - geo.height/2.0f + y + h/2.0f; - - - nux::Vector4* vectors = icon->_xform_coords[name]; - - vectors[0].x = v0.x; - vectors[0].y = v0.y; - vectors[0].z = v0.z; - vectors[0].w = v0.w; - vectors[1].x = v1.x; - vectors[1].y = v1.y; - vectors[1].z = v1.z; - vectors[1].w = v1.w; - vectors[2].x = v2.x; - vectors[2].y = v2.y; - vectors[2].z = v2.z; - vectors[2].w = v2.w; - vectors[3].x = v3.x; - vectors[3].y = v3.y; - vectors[3].z = v3.z; - vectors[3].w = v3.w; -} - -void Launcher::UpdateIconXForm (std::list<Launcher::RenderArg> args) -{ - nux::Geometry geo = GetGeometry (); - nux::Matrix4 ObjectMatrix; - nux::Matrix4 ViewMatrix; - nux::Matrix4 ProjectionMatrix; - nux::Matrix4 ViewProjectionMatrix; - - GetInverseScreenPerspectiveMatrix(ViewMatrix, ProjectionMatrix, geo.width, geo.height, 0.1f, 1000.0f, DEGTORAD(90)); - - //LauncherModel::iterator it; - std::list<Launcher::RenderArg>::iterator it; - for(it = args.begin(); it != args.end(); it++) - { - if ((*it).skip) - continue; - - LauncherIcon* launcher_icon = (*it).icon; - - // We to store the icon angle in the icons itself. Makes one thing easier afterward. - launcher_icon->_folding_angle = (*it).folding_rads; - - float w = _icon_size; - float h = _icon_size; - float x = (*it).center.x - w/2.0f; // x: top left corner - float y = (*it).center.y - h/2.0f; // y: top left corner - float z = (*it).center.z; - - ObjectMatrix = nux::Matrix4::TRANSLATE(geo.width/2.0f, geo.height/2.0f, z) * // Translate the icon to the center of the viewport - nux::Matrix4::ROTATEX((*it).folding_rads) * // rotate the icon - nux::Matrix4::TRANSLATE(-x - w/2.0f, -y - h/2.0f, -z); // Put the center the icon to (0, 0) - - ViewProjectionMatrix = ProjectionMatrix*ViewMatrix*ObjectMatrix; - - SetIconXForm (launcher_icon, ViewProjectionMatrix, geo, x, y, w, h, z, "Tile"); - - w = _icon_image_size; - h = _icon_image_size; - x = (*it).center.x - _icon_size/2.0f + _icon_image_size_delta/2.0f; - y = (*it).center.y - _icon_size/2.0f + _icon_image_size_delta/2.0f; - z = (*it).center.z; - - SetIconXForm (launcher_icon, ViewProjectionMatrix, geo, x, y, w, h, z, "Image"); - - w = _icon_glow_size; - h = _icon_glow_size; - x = (*it).center.x - _icon_glow_size/2.0f; - y = (*it).center.y - _icon_glow_size/2.0f; - z = (*it).center.z; - - SetIconXForm (launcher_icon, ViewProjectionMatrix, geo, x, y, w, h, z, "Glow"); - - w = geo.width + 2; - h = _icon_size + _space_between_icons; - x = (*it).center.x - w/2.0f; - y = (*it).center.y - h/2.0f; - z = (*it).center.z; - - SetIconXForm (launcher_icon, ViewProjectionMatrix, geo, x, y, w, h, z, "HitArea"); - } -} - -void GetInverseScreenPerspectiveMatrix(nux::Matrix4& ViewMatrix, nux::Matrix4& PerspectiveMatrix, - int ViewportWidth, - int ViewportHeight, - float NearClipPlane, - float FarClipPlane, - float Fovy) -{ -/* - Objective: - Given a perspective matrix defined by (Fovy, AspectRatio, NearPlane, FarPlane), we want to compute - the ModelView matrix that transform a quad defined by its top-left coord (0, 0) and its - bottom-right coord (WindowWidth, WindowHeight) into a full screen quad that covers the entire viewport (one to one). - Any quad that is facing the camera and whose 4 points are on the 4 guiding line of the view frustum (pyramid) - will always cover the entire viewport one to one (when projected on the screen). - So all we have to do is to define a quad with x:[-x_cs, x_cs] and y:[-y_cs, y_cs] and find the z distance in eye space (z_cs) so that - the quad touches the 4 guiding lines of the view frustum. - We consider a well centered projection view (no skewing, no oblique clipping plane, ...) and derive the following equations: - x_cs = AspectRatio*y_cs - y_cs/z_cs = tanf(Fovy/2) ==> z_cs = y_cs*1/tanf(Fovy/2) (this is the absolute value the quad depth value will be -z_cs since we are using OpenGL right hand coord system). - - The quad (in camera space) facing the camera and centered around the camera view axis is defined by the points (-x_cs, y_cs) (top-left) - and the point (x_cs, -y_cs) (bottom-right). If we move that quad along the camera view axis and place it at a distance z_cs of the camera, - then its 4 corners are each on the 4 lines of the view frustum. - - (-x_cs, y_cs) Camera Space - ^ - __________|__________ - | | | - | | | - | |(0, 0) | - |----------|----------|-> - | | | - | | | - |__________|__________| - (x_cs, -y_cs) - - The full-screen quad (in screen space) is defined by the point (0, 0) (top-left) and (WindowWidth, WindowHeight) (bottom-right). - We can choose and arbitrary value y_cs and compute the z_cs position in camera space that will produce a quad in camera space that projects into - the full-screen space. - - (0, 0) Screen Space - _____________________-> - | | | - | | | - | | | - |----------|----------| - | | | - | | | - |__________|__________| - v (WindowWidth, WindowHeight) - - The model view matrix is the succession of transformation that convert the quad (0, 0, WindowWidth, WindowHeight) into - the quad (-x_cs, y_cs, x_cs, -y_cs) - - Screen Space Camera Space - x ----> x_ = x*2*x_cs/WindowWidth - x_cs - y ----> y_ = -y*2*y_cs/WindowHeight + y_cs - z ----> z_ = A*z -y_cs*1/tanf(Fovy/2) - where A is a coefficient that can attenuate the rate of change in depth when the quad moves along the camera axis - - If the following is the projection matrix: - - (a, 0, 0, 0) a = 1/(AspectRatio*tan(Fovy/2)) - (0, b, 0, 0) b = 1/tan(Fovy/2) - (0, 0, c, d) - (0, 0, -1, 0) - - and the camera space vertex is (x_cs, y_cs, z_cs, w_cs) projects to the top left corner of the view port on the screen ((-1, 1) in clip space), then - x_cs*a/(-z_cs) = -1; | z_cs = x_cs*a x_cs*a = -y_cs*b ==> x_cs = y_cs*AspectRatio - | ==> ==> - y_cs*b/(-z_cs) = +1; | z_cs = -y_cs*b z_cs = -y_cs*1/tanf(Fovy/2) -*/ - - - float AspectRatio = (float)ViewportWidth/(float)ViewportHeight; - float CameraToScreenDistance = -1.0f; - float y_cs = -CameraToScreenDistance*tanf(0.5f*Fovy/* *3.1415926/180.0f*/); - float x_cs = y_cs*AspectRatio; - //float CameraToScreenDistance = -y_cs*1.0f/(tanf(0.5f*Fovy/* *3.1415926/180.0f*/)); - - ViewMatrix = nux::Matrix4::TRANSLATE(-x_cs, y_cs, CameraToScreenDistance) * - nux::Matrix4::SCALE(2.0f*x_cs/ViewportWidth, -2.0f*y_cs/ViewportHeight, -2.0f * 3 * y_cs/ViewportHeight /* or -2.0f * x_cs/ViewportWidth*/ ); - - PerspectiveMatrix.Perspective(Fovy, AspectRatio, NearClipPlane, FarClipPlane); - -// // Example usage with the matrices above: -// float W = 300; -// float H = 300; -// // centered quad -// float X = (ViewportWidth - W)/2.0; -// float Y = (ViewportHeight - H)/2.0; -// float Z = 0.0f; -// -// { -// glPushMatrix(); -// // Local Transformation of the object -// glTranslatef(0.0f, 0.0f, ObjectDistanceToCamera); -// glTranslatef(X + W/2.0f, Y + H/2.0f, 0.0f); -// glRotatef(cameraAngleY, 1, 0, 0); -// glRotatef(cameraAngleX, 0, 1, 0); -// glTranslatef(-X - W/2.0f, -Y - H/2.0f, 0.0f); -// -// glBegin(GL_QUADS); -// { -// glNormal3f(0.0f, 0.0f, 1.0f); -// -// glColor4f(1.0f, 0.0f, 0.0f, 1.0f); -// glVertex4f(X, Y, Z, 1.0f); -// -// glColor4f(0.0f, 1.0f, 0.0f, 1.0f); -// glVertex4f(X, Y+H, Z, 1.0f); -// -// glColor4f(0.0f, 0.0f, 1.0f, 1.0f); -// glVertex4f(X+W, Y+H, Z, 1.0f); -// -// glColor4f(0.0f, 1.0f, 1.0f, 1.0f); -// glVertex4f(X+W, Y, Z, 1.0f); -// } -// glEnd(); -} - -void Launcher::SetActiveQuicklist (QuicklistView *quicklist) -{ - // Assert: _active_quicklist should be 0 - _active_quicklist = quicklist; -} - -QuicklistView *Launcher::GetActiveQuicklist () -{ - return _active_quicklist; -} - -void Launcher::CancelActiveQuicklist (QuicklistView *quicklist) -{ - if (_active_quicklist == quicklist) - _active_quicklist = 0; -} - +/* + * Copyright (C) 2010 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 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, see <http://www.gnu.org/licenses/>. + * + * Authored by: Jason Smith <jason.smith@canonical.com> + * Authored by: Jay Taoko <jay.taoko@canonical.com> + */ + +#include <math.h> + +#include "Nux/Nux.h" +#include "Nux/VScrollBar.h" +#include "Nux/HLayout.h" +#include "Nux/VLayout.h" +#include "Nux/MenuPage.h" + +#include "NuxGraphics/NuxGraphics.h" +#include "NuxGraphics/GpuDevice.h" +#include "NuxGraphics/GLTextureResourceManager.h" + +#include "Nux/BaseWindow.h" +#include "Nux/WindowCompositor.h" + +#include "Launcher.h" +#include "LauncherIcon.h" +#include "LauncherModel.h" +#include "QuicklistView.h" + +#define ANIM_DURATION_SHORT 125 +#define ANIM_DURATION 200 +#define ANIM_DURATION_LONG 350 + +#define URGENT_BLINKS 3 + +#define MAX_STARTING_BLINKS 5 +#define STARTING_BLINK_LAMBDA 3 + +#define BACKLIGHT_STRENGTH 0.9f + +int +TimeDelta (struct timespec const *x, struct timespec const *y) +{ + return ((x->tv_sec - y->tv_sec) * 1000) + ((x->tv_nsec - y->tv_nsec) / 1000000); +} + +static bool USE_ARB_SHADERS = true; +/* + Use this shader to pass vertices in screen coordinates in the C++ code and compute use + the fragment shader to perform the texture perspective correct division. + This shader assume the following: + - the projection matrix is orthogonal: glOrtho(0, ScreenWidth, ScreenWidth, 0, Near, Far) + - vertices x and y are in screen coordinates: Vertex(x_screen, y_screen, 0, 1.0) + - the vertices w coordinates has been computed 'manually' + - vertices uv textture coordinates are passed to the shader as: (u/w, v/w, 0, 1/w) + + The texture coordinates s=u/w, t=v/w and q=1w are interpolated linearly in screen coordinates. + In the fragment shader we get the texture coordinates used for the sampling by dividing + s and t resulting from the interpolation by q. + + */ + +nux::NString gPerspectiveCorrectShader = TEXT ( +"[Vertex Shader] \n\ +#version 120 \n\ +uniform mat4 ViewProjectionMatrix; \n\ + \n\ +attribute vec4 iColor; \n\ +attribute vec4 iTexCoord0; \n\ +attribute vec4 iVertex; \n\ + \n\ +varying vec4 varyTexCoord0; \n\ +varying vec4 varyVertexColor; \n\ + \n\ +void main() \n\ +{ \n\ + varyTexCoord0 = iTexCoord0; \n\ + varyVertexColor = iColor; \n\ + gl_Position = ViewProjectionMatrix * iVertex; \n\ +} \n\ + \n\ +[Fragment Shader] \n\ +#version 120 \n\ +#extension GL_ARB_texture_rectangle : enable \n\ + \n\ +varying vec4 varyTexCoord0; \n\ +varying vec4 varyVertexColor; \n\ + \n\ +uniform sampler2D TextureObject0; \n\ +uniform vec4 color0; \n\ +vec4 SampleTexture(sampler2D TexObject, vec4 TexCoord) \n\ +{ \n\ + return texture2D(TexObject, TexCoord.st); \n\ +} \n\ + \n\ +void main() \n\ +{ \n\ + vec4 tex = varyTexCoord0; \n\ + tex.s = tex.s/varyTexCoord0.w; \n\ + tex.t = tex.t/varyTexCoord0.w; \n\ + \n\ + vec4 texel = SampleTexture(TextureObject0, tex); \n\ + gl_FragColor = texel*varyVertexColor; \n\ +} \n\ +"); + +nux::NString PerspectiveCorrectVtx = TEXT ( + "!!ARBvp1.0 \n\ + ATTRIB iPos = vertex.position; \n\ + ATTRIB iColor = vertex.attrib[3]; \n\ + PARAM mvp[4] = {state.matrix.mvp}; \n\ + OUTPUT oPos = result.position; \n\ + OUTPUT oColor = result.color; \n\ + OUTPUT oTexCoord0 = result.texcoord[0]; \n\ + # Transform the vertex to clip coordinates. \n\ + DP4 oPos.x, mvp[0], iPos; \n\ + DP4 oPos.y, mvp[1], iPos; \n\ + DP4 oPos.z, mvp[2], iPos; \n\ + DP4 oPos.w, mvp[3], iPos; \n\ + MOV oColor, iColor; \n\ + MOV oTexCoord0, vertex.attrib[8]; \n\ + END"); + + + +nux::NString PerspectiveCorrectTexFrg = TEXT ( + "!!ARBfp1.0 \n\ + PARAM color0 = program.local[0]; \n\ + TEMP temp; \n\ + TEMP pcoord; \n\ + TEMP tex0; \n\ + TEMP temp1; \n\ + TEMP recip; \n\ + MOV pcoord, fragment.texcoord[0].w; \n\ + RCP temp, fragment.texcoord[0].w; \n\ + MUL pcoord.xy, fragment.texcoord[0], temp; \n\ + TEX tex0, pcoord, texture[0], 2D; \n\ + MUL result.color, color0, tex0; \n\ + END"); + +nux::NString PerspectiveCorrectTexRectFrg = TEXT ( + "!!ARBfp1.0 \n\ + PARAM color0 = program.local[0]; \n\ + TEMP temp; \n\ + TEMP pcoord; \n\ + TEMP tex0; \n\ + MOV pcoord, fragment.texcoord[0].w; \n\ + RCP temp, fragment.texcoord[0].w; \n\ + MUL pcoord.xy, fragment.texcoord[0], temp; \n\ + TEX tex0, pcoord, texture[0], RECT; \n\ + MUL result.color, color0, tex0; \n\ + END"); + +static void GetInverseScreenPerspectiveMatrix(nux::Matrix4& ViewMatrix, nux::Matrix4& PerspectiveMatrix, + int ViewportWidth, + int ViewportHeight, + float NearClipPlane, + float FarClipPlane, + float Fovy); + +Launcher::Launcher(nux::BaseWindow *parent, CompScreen *screen, NUX_FILE_LINE_DECL) +: View(NUX_FILE_LINE_PARAM) +, m_ContentOffsetY(0) +, m_RunningIndicator(0) +, m_ActiveIndicator(0) +, m_BackgroundLayer(0) +, _model (0) +{ + _parent = parent; + _screen = screen; + _active_quicklist = 0; + + m_Layout = new nux::HLayout(NUX_TRACKER_LOCATION); + + OnMouseDown.connect(sigc::mem_fun(this, &Launcher::RecvMouseDown)); + OnMouseUp.connect(sigc::mem_fun(this, &Launcher::RecvMouseUp)); + OnMouseDrag.connect(sigc::mem_fun(this, &Launcher::RecvMouseDrag)); + OnMouseEnter.connect(sigc::mem_fun(this, &Launcher::RecvMouseEnter)); + OnMouseLeave.connect(sigc::mem_fun(this, &Launcher::RecvMouseLeave)); + OnMouseMove.connect(sigc::mem_fun(this, &Launcher::RecvMouseMove)); + OnMouseWheel.connect(sigc::mem_fun(this, &Launcher::RecvMouseWheel)); + + m_ActiveTooltipIcon = NULL; + m_ActiveMenuIcon = NULL; + + SetCompositionLayout(m_Layout); + + if(!USE_ARB_SHADERS) + { + _shader_program_uv_persp_correction = nux::GetThreadGLDeviceFactory()->CreateShaderProgram(); + _shader_program_uv_persp_correction->LoadIShader(gPerspectiveCorrectShader.GetTCharPtr()); + _shader_program_uv_persp_correction->Link(); + } + else + { + _AsmShaderProg = nux::GetThreadGLDeviceFactory()->CreateAsmShaderProgram(); + _AsmShaderProg->LoadVertexShader (TCHAR_TO_ANSI (*PerspectiveCorrectVtx) ); + + if ((nux::GetThreadGLDeviceFactory()->SUPPORT_GL_ARB_TEXTURE_NON_POWER_OF_TWO() == false) && + (nux::GetThreadGLDeviceFactory()->SUPPORT_GL_EXT_TEXTURE_RECTANGLE () || nux::GetThreadGLDeviceFactory()->SUPPORT_GL_ARB_TEXTURE_RECTANGLE ())) + { + // No support for non power of two textures but support for rectangle textures + _AsmShaderProg->LoadPixelShader (TCHAR_TO_ANSI (*PerspectiveCorrectTexRectFrg) ); + } + else + { + _AsmShaderProg->LoadPixelShader (TCHAR_TO_ANSI (*PerspectiveCorrectTexFrg) ); + } + + _AsmShaderProg->Link(); + } + + _folded_angle = 1.0f; + _neg_folded_angle = -1.0f; + _space_between_icons = 5; + _launcher_top_y = 0; + _launcher_bottom_y = 0; + _folded_z_distance = 10.0f; + _launcher_state = LAUNCHER_FOLDED; + _launcher_action_state = ACTION_NONE; + _icon_under_mouse = NULL; + _icon_mouse_down = NULL; + _icon_image_size = 48; + _icon_glow_size = 62; + _icon_image_size_delta = 6; + _icon_size = _icon_image_size + _icon_image_size_delta; + + _icon_bkg_texture = nux::CreateTextureFromFile (PKGDATADIR"/round_corner_54x54.png"); + _icon_outline_texture = nux::CreateTextureFromFile (PKGDATADIR"/round_outline_54x54.png"); + _icon_shine_texture = nux::CreateTextureFromFile (PKGDATADIR"/round_shine_54x54.png"); + _icon_glow_texture = nux::CreateTextureFromFile (PKGDATADIR"/round_glow_62x62.png"); + _icon_2indicator = nux::CreateTextureFromFile (PKGDATADIR"/2indicate_54x54.png"); + _icon_3indicator = nux::CreateTextureFromFile (PKGDATADIR"/3indicate_54x54.png"); + _icon_4indicator = nux::CreateTextureFromFile (PKGDATADIR"/4indicate_54x54.png"); + + _enter_y = 0; + _dnd_security = 15; + _dnd_delta = 0; + _anim_handle = 0; + _autohide_handle = 0; + _floating = false; + _hovered = false; + _autohide = false; + _hidden = false; + _mouse_inside_launcher = false; + _mouse_inside_trigger = false; + _window_over_launcher = false; + + // 0 out timers to avoid wonky startups + _enter_time.tv_sec = 0; + _enter_time.tv_nsec = 0; + _exit_time.tv_sec = 0; + _exit_time.tv_nsec = 0; + _drag_end_time.tv_sec = 0; + _drag_end_time.tv_nsec = 0; + _autohide_time.tv_sec = 0; + _autohide_time.tv_nsec = 0; +} + +Launcher::~Launcher() +{ + +} + +/* Introspection */ +const gchar * +Launcher::GetName () +{ + return "Launcher"; +} + +void +Launcher::AddProperties (GVariantBuilder *builder) +{ + struct timespec current; + clock_gettime (CLOCK_MONOTONIC, ¤t); + + g_variant_builder_add (builder, "{sv}", "hover-progress", g_variant_new_double ((double) GetHoverProgress (current))); + g_variant_builder_add (builder, "{sv}", "dnd-exit-progress", g_variant_new_double ((double) DnDExitProgress (current))); + g_variant_builder_add (builder, "{sv}", "autohide-progress", g_variant_new_double ((double) AutohideProgress (current))); + + g_variant_builder_add (builder, "{sv}", "dnd-delta", g_variant_new_int32 (_dnd_delta)); + g_variant_builder_add (builder, "{sv}", "floating", g_variant_new_boolean (_floating)); + g_variant_builder_add (builder, "{sv}", "hovered", g_variant_new_boolean (_hovered)); + g_variant_builder_add (builder, "{sv}", "autohide", g_variant_new_boolean (_autohide)); + g_variant_builder_add (builder, "{sv}", "hidden", g_variant_new_boolean (_hidden)); + g_variant_builder_add (builder, "{sv}", "autohide", g_variant_new_boolean (_autohide)); + g_variant_builder_add (builder, "{sv}", "mouse-inside-launcher", g_variant_new_boolean (_mouse_inside_launcher)); +} + +/* Render Layout Logic */ + +float Launcher::GetHoverProgress (struct timespec const ¤t) +{ + if (_hovered) + return CLAMP ((float) (TimeDelta (¤t, &_enter_time)) / (float) ANIM_DURATION, 0.0f, 1.0f); + else + return 1.0f - CLAMP ((float) (TimeDelta (¤t, &_exit_time)) / (float) ANIM_DURATION, 0.0f, 1.0f); +} + +float Launcher::DnDExitProgress (struct timespec const ¤t) +{ + return 1.0f - CLAMP ((float) (TimeDelta (¤t, &_drag_end_time)) / (float) ANIM_DURATION_LONG, 0.0f, 1.0f); +} + +float Launcher::AutohideProgress (struct timespec const ¤t) +{ + if (!_autohide) + return 0.0f; + + if (_hidden) + return CLAMP ((float) (TimeDelta (¤t, &_autohide_time)) / (float) ANIM_DURATION_SHORT, 0.0f, 1.0f); + else + return 1.0f - CLAMP ((float) (TimeDelta (¤t, &_autohide_time)) / (float) ANIM_DURATION_SHORT, 0.0f, 1.0f); +} + +gboolean Launcher::AnimationTimeout (gpointer data) +{ + Launcher *self = (Launcher*) data; + + self->NeedRedraw (); + + if (self->AnimationInProgress ()) + return true; + + // zero out handle so we know we are done + self->_anim_handle = 0; + return false; +} + +void Launcher::EnsureAnimation () +{ + if (_anim_handle) + return; + + NeedRedraw (); + + if (AnimationInProgress ()) + _anim_handle = g_timeout_add (1000 / 60 - 1, &Launcher::AnimationTimeout, this); +} + +bool Launcher::IconNeedsAnimation (LauncherIcon *icon, struct timespec const ¤t) +{ + struct timespec time = icon->GetQuirkTime (LAUNCHER_ICON_QUIRK_VISIBLE); + if (TimeDelta (¤t, &time) < ANIM_DURATION_SHORT) + return true; + + time = icon->GetQuirkTime (LAUNCHER_ICON_QUIRK_RUNNING); + if (TimeDelta (¤t, &time) < ANIM_DURATION_SHORT) + return true; + + time = icon->GetQuirkTime (LAUNCHER_ICON_QUIRK_STARTING); + if (TimeDelta (¤t, &time) < (ANIM_DURATION_LONG * MAX_STARTING_BLINKS * STARTING_BLINK_LAMBDA * 2)) + return true; + + time = icon->GetQuirkTime (LAUNCHER_ICON_QUIRK_URGENT); + if (TimeDelta (¤t, &time) < (ANIM_DURATION_LONG * URGENT_BLINKS * 2)) + return true; + + time = icon->GetQuirkTime (LAUNCHER_ICON_QUIRK_PRESENTED); + if (TimeDelta (¤t, &time) < ANIM_DURATION) + return true; + + time = icon->GetQuirkTime (LAUNCHER_ICON_QUIRK_SHIMMER); + if (TimeDelta (¤t, &time) < ANIM_DURATION_LONG) + return true; + + return false; +} + +bool Launcher::AnimationInProgress () +{ + // performance here can be improved by caching the longer remaining animation found and short circuiting to that each time + // this way extra checks may be avoided + + // short circuit to avoid unneeded calculations + struct timespec current; + clock_gettime (CLOCK_MONOTONIC, ¤t); + + // hover in animation + if (TimeDelta (¤t, &_enter_time) < ANIM_DURATION) + return true; + + // hover out animation + if (TimeDelta (¤t, &_exit_time) < ANIM_DURATION) + return true; + + // drag end animation + if (TimeDelta (¤t, &_drag_end_time) < ANIM_DURATION_LONG) + return true; + + if (TimeDelta (¤t, &_autohide_time) < ANIM_DURATION_SHORT) + return true; + + // animations happening on specific icons + LauncherModel::iterator it; + for (it = _model->begin (); it != _model->end (); it++) + if (IconNeedsAnimation (*it, current)) + return true; + + return false; +} + +void Launcher::SetTimeStruct (struct timespec *timer, struct timespec *sister, int sister_relation) +{ + struct timespec current; + clock_gettime (CLOCK_MONOTONIC, ¤t); + + if (sister) + { + int diff = TimeDelta (¤t, sister); + + if (diff < sister_relation) + { + int remove = sister_relation - diff; + current.tv_sec -= remove / 1000; + remove = remove % 1000; + + if (remove > current.tv_nsec / 1000000) + { + current.tv_sec--; + current.tv_nsec += 1000000000; + } + current.tv_nsec -= remove * 1000000; + } + } + + timer->tv_sec = current.tv_sec; + timer->tv_nsec = current.tv_nsec; +} + +float IconVisibleProgress (LauncherIcon *icon, struct timespec const ¤t) +{ + if (icon->GetQuirk (LAUNCHER_ICON_QUIRK_VISIBLE)) + { + struct timespec icon_visible_time = icon->GetQuirkTime (LAUNCHER_ICON_QUIRK_VISIBLE); + int enter_ms = TimeDelta (¤t, &icon_visible_time); + return CLAMP ((float) enter_ms / (float) ANIM_DURATION_SHORT, 0.0f, 1.0f); + } + else + { + struct timespec icon_hide_time = icon->GetQuirkTime (LAUNCHER_ICON_QUIRK_VISIBLE); + int hide_ms = TimeDelta (¤t, &icon_hide_time); + return 1.0f - CLAMP ((float) hide_ms / (float) ANIM_DURATION_SHORT, 0.0f, 1.0f); + } +} + +void Launcher::SetDndDelta (float x, float y, nux::Geometry geo, struct timespec const ¤t) +{ + LauncherIcon *anchor = 0; + LauncherModel::iterator it; + anchor = MouseIconIntersection (x, _enter_y); + + if (anchor) + { + float position = y; + for (it = _model->begin (); it != _model->end (); it++) + { + if (*it == anchor) + { + position += _icon_size / 2; + _dnd_delta = _enter_y - position; + + if (position + _icon_size / 2 + _dnd_delta > geo.height) + _dnd_delta -= (position + _icon_size / 2 + _dnd_delta) - geo.height; + + break; + } + position += (_icon_size + _space_between_icons) * IconVisibleProgress (*it, current); + } + } +} + +float Launcher::IconPresentProgress (LauncherIcon *icon, struct timespec const ¤t) +{ + struct timespec icon_present_time = icon->GetQuirkTime (LAUNCHER_ICON_QUIRK_PRESENTED); + int ms = TimeDelta (¤t, &icon_present_time); + float result = CLAMP ((float) ms / (float) ANIM_DURATION, 0.0f, 1.0f); + + if (icon->GetQuirk (LAUNCHER_ICON_QUIRK_PRESENTED)) + return result; + else + return 1.0f - result; +} + +float Launcher::IconUrgentProgress (LauncherIcon *icon, struct timespec const ¤t) +{ + struct timespec urgent_time = icon->GetQuirkTime (LAUNCHER_ICON_QUIRK_URGENT); + int urgent_ms = TimeDelta (¤t, &urgent_time); + float result = CLAMP ((float) urgent_ms / (float) (ANIM_DURATION_LONG * URGENT_BLINKS * 2), 0.0f, 1.0f); + + if (icon->GetQuirk (LAUNCHER_ICON_QUIRK_URGENT)) + return result; + else + return 1.0f - result; +} + +float Launcher::IconShimmerProgress (LauncherIcon *icon, struct timespec const ¤t) +{ + struct timespec shimmer_time = icon->GetQuirkTime (LAUNCHER_ICON_QUIRK_SHIMMER); + int shimmer_ms = TimeDelta (¤t, &shimmer_time); + return CLAMP ((float) shimmer_ms / (float) ANIM_DURATION_LONG, 0.0f, 1.0f); +} + +float Launcher::IconUrgentPulseValue (LauncherIcon *icon, struct timespec const ¤t) +{ + if (!icon->GetQuirk (LAUNCHER_ICON_QUIRK_URGENT)) + return 1.0f; // we are full on in a normal condition + + double urgent_progress = (double) IconUrgentProgress (icon, current); + return 0.5f + (float) (std::cos (M_PI * (float) (URGENT_BLINKS * 2) * urgent_progress)) * 0.5f; +} + +float Launcher::IconStartingPulseValue (LauncherIcon *icon, struct timespec const ¤t) +{ + struct timespec starting_time = icon->GetQuirkTime (LAUNCHER_ICON_QUIRK_STARTING); + int starting_ms = TimeDelta (¤t, &starting_time); + double starting_progress = (double) CLAMP ((float) starting_ms / (float) (ANIM_DURATION_LONG * MAX_STARTING_BLINKS * STARTING_BLINK_LAMBDA * 2), 0.0f, 1.0f); + + return 1.0f - (0.5f + (float) (std::cos (M_PI * (float) (MAX_STARTING_BLINKS * 2) * starting_progress)) * 0.5f); +} + +float Launcher::IconBackgroundIntensity (LauncherIcon *icon, struct timespec const ¤t) +{ + float result = 0.0f; + struct timespec running_time = icon->GetQuirkTime (LAUNCHER_ICON_QUIRK_RUNNING); + int running_ms = TimeDelta (¤t, &running_time); + float running_progress = CLAMP ((float) running_ms / (float) ANIM_DURATION_SHORT, 0.0f, 1.0f); + + // After we finish a fade in from running, we can reset the quirk + if (icon->GetQuirk (LAUNCHER_ICON_QUIRK_RUNNING) && running_progress == 1.0f) + icon->ResetQuirkTime (LAUNCHER_ICON_QUIRK_STARTING); + + result = IconStartingPulseValue (icon, current) * BACKLIGHT_STRENGTH; + + if (icon->GetQuirk (LAUNCHER_ICON_QUIRK_RUNNING)) + { + // running progress fades in whatever the pulsing did not fill in already + result += running_progress * (BACKLIGHT_STRENGTH - result); + + // urgent serves to bring the total down only + if (icon->GetQuirk (LAUNCHER_ICON_QUIRK_URGENT)) + result *= 0.2f + 0.8f * IconUrgentPulseValue (icon, current); + } + else + { + // modestly evil + result += BACKLIGHT_STRENGTH - running_progress * BACKLIGHT_STRENGTH; + } + + return result; +} + +void Launcher::SetupRenderArg (LauncherIcon *icon, struct timespec const ¤t, RenderArg &arg) +{ + arg.icon = icon; + arg.alpha = 1.0f; + arg.running_arrow = icon->GetQuirk (LAUNCHER_ICON_QUIRK_RUNNING); + arg.active_arrow = icon->GetQuirk (LAUNCHER_ICON_QUIRK_ACTIVE); + arg.running_colored = icon->GetQuirk (LAUNCHER_ICON_QUIRK_URGENT); + arg.active_colored = false; + arg.folding_rads = 0.0f; + arg.skip = false; + + + // we dont need to show strays + if (!icon->GetQuirk (LAUNCHER_ICON_QUIRK_RUNNING)) + arg.window_indicators = 0; + else + arg.window_indicators = MIN (4, icon->RelatedWindows ()); + + arg.backlight_intensity = IconBackgroundIntensity (icon, current); + arg.shimmer_progress = IconShimmerProgress (icon, current); + + float urgent_progress = IconUrgentProgress (icon, current); + urgent_progress = CLAMP (urgent_progress * 3, 0.0f, 1.0f); // we want to go 3x faster than the urgent normal cycle + arg.glow_intensity = urgent_progress; +} + +float Launcher::DragLimiter (float x) +{ + float result = (1 - std::pow (159.0 / 160, std::abs (x))) * 160; + + if (x >= 0.0f) + return result; + return -result; +} + +void Launcher::RenderArgs (std::list<Launcher::RenderArg> &launcher_args, + nux::Geometry &box_geo) +{ + nux::Geometry geo = GetGeometry (); + LauncherModel::iterator it; + nux::Point3 center; + struct timespec current; + clock_gettime (CLOCK_MONOTONIC, ¤t); + + float hover_progress = GetHoverProgress (current); + float folded_z_distance = _folded_z_distance * (1.0f - hover_progress); + float animation_neg_rads = _neg_folded_angle * (1.0f - hover_progress); + int vertical_offset = _parent->GetGeometry ().y; + + float folding_constant = 0.25f; + float folding_not_constant = folding_constant + ((1.0f - folding_constant) * hover_progress); + + float folded_size = _icon_size * folding_not_constant; + float folded_spacing = _space_between_icons * folding_not_constant; + + center.x = geo.width / 2; + center.y = _space_between_icons; + center.z = 0; + + int launcher_height = geo.height; + + // compute required height of launcher AND folding threshold + float sum = 0.0f + center.y; + float folding_threshold = launcher_height - _icon_size / 2.5f; + for (it = _model->begin (); it != _model->end (); it++) + { + float height = (_icon_size + _space_between_icons) * IconVisibleProgress (*it, current); + sum += height; + + // magic constant must some day be explained, for now suffice to say this constant prevents the bottom from "marching"; + float magic_constant = 1.2f; + + float present_progress = IconPresentProgress (*it, current); + folding_threshold -= CLAMP (sum - launcher_height, 0.0f, height * magic_constant) * (folding_constant + (1.0f - folding_constant) * present_progress); + } + + // this happens on hover, basically its a flag and a value in one, we translate this into a dnd offset + if (_enter_y != 0 && _enter_y + _icon_size / 2 > folding_threshold) + SetDndDelta (center.x, center.y, nux::Geometry (geo.x, geo.y, geo.width, geo.height), current); + + _enter_y = 0; + + if (hover_progress > 0.0f && _dnd_delta != 0) + { + float delta_y = _dnd_delta; + + // logically dnd exit only restores to the clamped ranges + // hover_progress restores to 0 + float max = 0.0f; + float min = MIN (0.0f, launcher_height - sum); + + if (_dnd_delta > max) + delta_y = max + DragLimiter (delta_y - max); + else if (_dnd_delta < min) + delta_y = min + DragLimiter (delta_y - min); + + if (_launcher_action_state != ACTION_DRAG_LAUNCHER) + { + float dnd_progress = DnDExitProgress (current); + + if (_dnd_delta > max) + delta_y = max + (delta_y - max) * dnd_progress; + else if (_dnd_delta < min) + delta_y = min + (delta_y - min) * dnd_progress; + + if (dnd_progress == 0.0f) + _dnd_delta = (int) delta_y; + } + + delta_y *= hover_progress; + center.y += delta_y; + folding_threshold += delta_y; + } + else + { + _dnd_delta = 0; + } + + float autohide_progress = AutohideProgress (current); + float autohide_offset = 0.0f; + if (_autohide && autohide_progress > 0.0f) + { + autohide_offset -= geo.width * autohide_progress; + } + + // Inform the painter where to paint the box + box_geo = geo; + + if (_autohide) + box_geo.x += autohide_offset; + + // The functional position we wish to represent for these icons is not smooth. Rather than introducing + // special casing to represent this, we use MIN/MAX functions. This helps ensure that even though our + // function is not smooth it is continuous, which is more important for our visual representation (icons + // wont start jumping around). As a general rule ANY if () statements that modify center.y should be seen + // as bugs. + for (it = _model->main_begin (); it != _model->main_end (); it++) + { + RenderArg arg; + LauncherIcon *icon = *it; + + SetupRenderArg (icon, current, arg); + + // reset z + center.z = 0; + + float size_modifier = IconVisibleProgress (icon, current); + if (size_modifier < 1.0f) + { + arg.alpha = size_modifier; + center.z = 300.0f * (1.0f - size_modifier); + } + + if (size_modifier <= 0.0f) + { + arg.skip = true; + continue; + } + + // goes for 0.0f when fully unfolded, to 1.0f folded + float folding_progress = CLAMP ((center.y + _icon_size - folding_threshold) / (float) _icon_size, 0.0f, 1.0f); + float present_progress = IconPresentProgress (icon, current); + + folding_progress *= 1.0f - present_progress; + + float half_size = (folded_size / 2.0f) + (_icon_size / 2.0f - folded_size / 2.0f) * (1.0f - folding_progress); + + float icon_hide_offset = autohide_offset; + + icon_hide_offset *= 1.0f - (present_progress * icon->PresentUrgency ()); + + // icon is crossing threshold, start folding + center.z += folded_z_distance * folding_progress; + arg.folding_rads = animation_neg_rads * folding_progress; + + center.y += half_size * size_modifier; // move to center + arg.center = nux::Point3 (roundf (center.x + icon_hide_offset), roundf (center.y), roundf (center.z)); // copy center + icon->SetCenter (nux::Point3 (roundf (center.x), roundf (center.y + vertical_offset), roundf (center.z))); + center.y += half_size * size_modifier; // move to end + + float spacing_overlap = CLAMP ((float) (center.y + (_space_between_icons * size_modifier) - folding_threshold) / (float) _icon_size, 0.0f, 1.0f); + //add spacing + center.y += (_space_between_icons * (1.0f - spacing_overlap) + folded_spacing * spacing_overlap) * size_modifier; + + launcher_args.push_back (arg); + } + + // compute maximum height of shelf + float shelf_sum = 0.0f; + for (it = _model->shelf_begin (); it != _model->shelf_end (); it++) + { + float height = (_icon_size + _space_between_icons) * IconVisibleProgress (*it, current); + shelf_sum += height; + } + + // add bottom padding + if (shelf_sum > 0.0f) + shelf_sum += _space_between_icons; + + float shelf_delta = MAX (((launcher_height - shelf_sum) + _space_between_icons) - center.y, 0.0f); + folding_threshold += shelf_delta; + center.y += shelf_delta; + + for (it = _model->shelf_begin (); it != _model->shelf_end (); it++) + { + RenderArg arg; + LauncherIcon *icon = *it; + + SetupRenderArg (icon, current, arg); + + // reset z + center.z = 0; + + float size_modifier = IconVisibleProgress (icon, current); + if (size_modifier < 1.0f) + { + arg.alpha = size_modifier; + center.z = 300.0f * (1.0f - size_modifier); + } + + if (size_modifier <= 0.0f) + { + arg.skip = true; + continue; + } + + // goes for 0.0f when fully unfolded, to 1.0f folded + float folding_progress = CLAMP ((center.y + _icon_size - folding_threshold) / (float) _icon_size, 0.0f, 1.0f); + float present_progress = IconPresentProgress (icon, current); + + folding_progress *= 1.0f - present_progress; + + float half_size = (folded_size / 2.0f) + (_icon_size / 2.0f - folded_size / 2.0f) * (1.0f - folding_progress); + + float icon_hide_offset = autohide_offset; + + icon_hide_offset *= 1.0f - (present_progress * icon->PresentUrgency ()); + + // icon is crossing threshold, start folding + center.z += folded_z_distance * folding_progress; + arg.folding_rads = animation_neg_rads * folding_progress; + + center.y += half_size * size_modifier; // move to center + arg.center = nux::Point3 (roundf (center.x + icon_hide_offset), roundf (center.y), roundf (center.z)); // copy center + icon->SetCenter (nux::Point3 (roundf (center.x), roundf (center.y + vertical_offset), roundf (center.z))); + center.y += half_size * size_modifier; // move to end + + float spacing_overlap = CLAMP ((float) (center.y + (_space_between_icons * size_modifier) - folding_threshold) / (float) _icon_size, 0.0f, 1.0f); + //add spacing + center.y += (_space_between_icons * (1.0f - spacing_overlap) + folded_spacing * spacing_overlap) * size_modifier; + + launcher_args.push_back (arg); + } +} + +/* End Render Layout Logic */ + +void Launcher::SetHidden (bool hidden) +{ + if (hidden == _hidden) + return; + + _hidden = hidden; + SetTimeStruct (&_autohide_time, &_autohide_time, ANIM_DURATION_SHORT); + + _parent->EnableInputWindow(!hidden); + + EnsureAnimation (); +} + +gboolean Launcher::OnAutohideTimeout (gpointer data) +{ + Launcher *self = (Launcher*) data; + + self->EnsureHiddenState (); + self->_autohide_handle = 0; + return false; +} + +void +Launcher::EnsureHiddenState () +{ + if (!_mouse_inside_trigger && !_mouse_inside_launcher && _window_over_launcher) + SetHidden (true); + else + SetHidden (false); +} + +void +Launcher::CheckWindowOverLauncher () +{ + CompWindowList window_list = _screen->windows (); + CompWindowList::iterator it; + nux::Geometry geo = GetGeometry (); + + for (it = window_list.begin (); it != window_list.end (); it++) + { + CompWindow *window = *it; + + if (window->type () != CompWindowTypeNormalMask || window->invisible ()) + continue; + + if (CompRegion (window->inputRect ()).intersects (CompRect (geo.x, geo.y, geo.width, geo.height))) + { + _window_over_launcher = true; + EnsureHiddenState (); + return; + } + } + + _window_over_launcher = false; + EnsureHiddenState (); +} + +void +Launcher::OnWindowMoved (CompWindow *window) +{ + if (_autohide) + CheckWindowOverLauncher (); +} + +void +Launcher::OnWindowResized (CompWindow *window) +{ + if (_autohide) + CheckWindowOverLauncher (); +} + +void +Launcher::OnWindowAppear (CompWindow *window) +{ + if (_autohide) + CheckWindowOverLauncher (); +} +void +Launcher::OnWindowDisappear (CompWindow *window) +{ + if (_autohide) + CheckWindowOverLauncher (); +} + +void Launcher::OnTriggerMouseEnter (int x, int y, unsigned long button_flags, unsigned long key_flags) +{ + _mouse_inside_trigger = true; + EnsureHiddenState (); +} + +void Launcher::SetupAutohideTimer () +{ + if (_autohide) + { + if (_autohide_handle > 0) + g_source_remove (_autohide_handle); + _autohide_handle = g_timeout_add (1000, &Launcher::OnAutohideTimeout, this); + } +} + +void Launcher::OnTriggerMouseLeave (int x, int y, unsigned long button_flags, unsigned long key_flags) +{ + _mouse_inside_trigger = false; + SetupAutohideTimer (); +} + +bool Launcher::AutohideEnabled () +{ + return _autohide; +} + +gboolean Launcher::StrutHack (gpointer data) +{ + Launcher *self = (Launcher *) data; + self->_parent->InputWindowEnableStruts(false); + self->_parent->InputWindowEnableStruts(true); + + return false; +} + +void Launcher::SetAutohide (bool autohide, nux::View *trigger) +{ + if (_autohide == autohide) + return; + + if (autohide) + { + _parent->InputWindowEnableStruts(false); + _autohide_trigger = trigger; + _autohide_trigger->OnMouseEnter.connect (sigc::mem_fun(this, &Launcher::OnTriggerMouseEnter)); + _autohide_trigger->OnMouseLeave.connect (sigc::mem_fun(this, &Launcher::OnTriggerMouseLeave)); + } + else + { + _parent->EnableInputWindow(true); + g_timeout_add (1000, &Launcher::StrutHack, this); + _parent->InputWindowEnableStruts(true); + } + + _autohide = autohide; + EnsureAnimation (); +} + +void Launcher::SetFloating (bool floating) +{ + if (_floating == floating) + return; + + _floating = floating; + EnsureAnimation (); +} + +void Launcher::SetHover () +{ + if (_hovered) + return; + + _enter_y = (int) _mouse_position.y; + + _hovered = true; + SetTimeStruct (&_enter_time, &_exit_time, ANIM_DURATION); +} + +void Launcher::UnsetHover () +{ + if (!_hovered) + return; + + _hovered = false; + SetTimeStruct (&_exit_time, &_enter_time, ANIM_DURATION); + SetupAutohideTimer (); +} + +void Launcher::SetIconSize(int tile_size, int icon_size) +{ + nux::Geometry geo = _parent->GetGeometry (); + + _icon_size = tile_size; + _icon_image_size = icon_size; + _icon_image_size_delta = tile_size - icon_size; + + // recreate tile textures + + _parent->SetGeometry (nux::Geometry (geo.x, geo.y, tile_size + 12, geo.height)); +} + +void Launcher::OnIconAdded (void *icon_pointer) +{ + LauncherIcon *icon = (LauncherIcon *) icon_pointer; + icon->Reference (); + EnsureAnimation(); + + // How to free these properly? + icon->_xform_coords["HitArea"] = new nux::Vector4[4]; + icon->_xform_coords["Image"] = new nux::Vector4[4]; + icon->_xform_coords["Tile"] = new nux::Vector4[4]; + icon->_xform_coords["Glow"] = new nux::Vector4[4]; + + // needs to be disconnected + icon->needs_redraw.connect (sigc::mem_fun(this, &Launcher::OnIconNeedsRedraw)); + + AddChild (icon); +} + +void Launcher::OnIconRemoved (void *icon_pointer) +{ + LauncherIcon *icon = (LauncherIcon *) icon_pointer; + icon->UnReference (); + + EnsureAnimation(); + + RemoveChild (icon); +} + +void Launcher::OnOrderChanged () +{ + EnsureAnimation (); +} + +void Launcher::SetModel (LauncherModel *model) +{ + _model = model; + _model->icon_added.connect (sigc::mem_fun (this, &Launcher::OnIconAdded)); + _model->icon_removed.connect (sigc::mem_fun (this, &Launcher::OnIconRemoved)); + _model->order_changed.connect (sigc::mem_fun (this, &Launcher::OnOrderChanged)); +} + +void Launcher::OnIconNeedsRedraw (void *icon) +{ + EnsureAnimation(); +} + +long Launcher::ProcessEvent(nux::IEvent &ievent, long TraverseInfo, long ProcessEventInfo) +{ + long ret = TraverseInfo; + ret = PostProcessEvent2(ievent, ret, ProcessEventInfo); + return ret; +} + +void Launcher::Draw(nux::GraphicsEngine& GfxContext, bool force_draw) +{ + +} + +void Launcher::RenderIndicators (nux::GraphicsEngine& GfxContext, + RenderArg const &arg, + int running, + int active, + nux::Geometry geo) +{ + int markerCenter = (int) arg.center.y; + + if (running > 0) + { + if (!m_RunningIndicator) + { + GdkPixbuf *pbuf = gdk_pixbuf_new_from_file (PKGDATADIR"/running_indicator.png", NULL); + m_RunningIndicator = nux::CreateTextureFromPixbuf (pbuf); + g_object_unref (pbuf); + } + nux::TexCoordXForm texxform; + + nux::Color color = nux::Color::LightGrey; + + if (arg.running_colored) + color = nux::Color::SkyBlue; + + std::vector<int> markers; + if (running == 1) + { + markers.push_back (markerCenter); + } + else if (running == 2) + { + markers.push_back (markerCenter - 2); + markers.push_back (markerCenter + 2); + } + else + { + markers.push_back (markerCenter - 4); + markers.push_back (markerCenter); + markers.push_back (markerCenter + 4); + } + + std::vector<int>::iterator it; + for (it = markers.begin (); it != markers.end (); it++) + { + int center = *it; + GfxContext.QRP_GLSL_1Tex (geo.x, + center - (m_RunningIndicator->GetHeight () / 2), + (float) m_RunningIndicator->GetWidth(), + (float) m_RunningIndicator->GetHeight(), + m_RunningIndicator->GetDeviceTexture(), + texxform, + color); + } + } + + if (active > 0) + { + if (!m_ActiveIndicator) + { + GdkPixbuf *pbuf = gdk_pixbuf_new_from_file (PKGDATADIR"/focused_indicator.png", NULL); + m_ActiveIndicator = nux::CreateTextureFromPixbuf (pbuf); + g_object_unref (pbuf); + } + nux::TexCoordXForm texxform; + + nux::Color color = nux::Color::LightGrey; + GfxContext.QRP_GLSL_1Tex ((geo.x + geo.width) - m_ActiveIndicator->GetWidth (), + markerCenter - (m_ActiveIndicator->GetHeight () / 2), + (float) m_ActiveIndicator->GetWidth(), + (float) m_ActiveIndicator->GetHeight(), + m_ActiveIndicator->GetDeviceTexture(), + texxform, + color); + } +} + +void Launcher::RenderIcon(nux::GraphicsEngine& GfxContext, + RenderArg const &arg, + nux::BaseTexture *icon, + nux::Color bkg_color, + float alpha, + nux::Vector4 xform_coords[], + nux::Geometry geo) +{ + if (icon == NULL || icon->IsNull ()) + return; + + nux::Matrix4 ObjectMatrix; + nux::Matrix4 ViewMatrix; + nux::Matrix4 ProjectionMatrix; + nux::Matrix4 ViewProjectionMatrix; + + if(nux::Abs (arg.folding_rads) < 0.01f) + icon->GetDeviceTexture()->SetFiltering(GL_NEAREST, GL_NEAREST); + else + icon->GetDeviceTexture()->SetFiltering(GL_LINEAR, GL_LINEAR); + + nux::Vector4 v0; + nux::Vector4 v1; + nux::Vector4 v2; + nux::Vector4 v3; + + v0.x = xform_coords[0].x ; + v0.y = xform_coords[0].y ; + v0.z = xform_coords[0].z ; + v0.w = xform_coords[0].w ; + v1.x = xform_coords[1].x ; + v1.y = xform_coords[1].y ; + v1.z = xform_coords[1].z ; + v1.w = xform_coords[1].w ; + v2.x = xform_coords[2].x ; + v2.y = xform_coords[2].y ; + v2.z = xform_coords[2].z ; + v2.w = xform_coords[2].w ; + v3.x = xform_coords[3].x ; + v3.y = xform_coords[3].y ; + v3.z = xform_coords[3].z ; + v3.w = xform_coords[3].w ; + + float s0, t0, s1, t1, s2, t2, s3, t3; + nux::Color color = nux::Color::White; + + if (icon->Type ().IsDerivedFromType(nux::TextureRectangle::StaticObjectType)) + { + s0 = 0.0f; t0 = 0.0f; + s1 = 0.0f; t1 = icon->GetHeight(); + s2 = icon->GetWidth(); t2 = icon->GetHeight(); + s3 = icon->GetWidth(); t3 = 0.0f; + } + else + { + s0 = 0.0f; t0 = 0.0f; + s1 = 0.0f; t1 = 1.0f; + s2 = 1.0f; t2 = 1.0f; + s3 = 1.0f; t3 = 0.0f; + } + + float VtxBuffer[] = + {// Perspective correct + v0.x, v0.y, 0.0f, 1.0f, s0/v0.w, t0/v0.w, 0.0f, 1.0f/v0.w, color.R(), color.G(), color.B(), color.A(), + v1.x, v1.y, 0.0f, 1.0f, s1/v1.w, t1/v1.w, 0.0f, 1.0f/v1.w, color.R(), color.G(), color.B(), color.A(), + v2.x, v2.y, 0.0f, 1.0f, s2/v2.w, t2/v2.w, 0.0f, 1.0f/v2.w, color.R(), color.G(), color.B(), color.A(), + v3.x, v3.y, 0.0f, 1.0f, s3/v3.w, t3/v3.w, 0.0f, 1.0f/v3.w, color.R(), color.G(), color.B(), color.A(), + }; + + CHECKGL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0)); + CHECKGL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0)); + + int TextureObjectLocation; + int VertexLocation; + int TextureCoord0Location; + int VertexColorLocation; + int FragmentColor; + + if(!USE_ARB_SHADERS) + { + _shader_program_uv_persp_correction->Begin(); + + TextureObjectLocation = _shader_program_uv_persp_correction->GetUniformLocationARB("TextureObject0"); + VertexLocation = _shader_program_uv_persp_correction->GetAttributeLocation("iVertex"); + TextureCoord0Location = _shader_program_uv_persp_correction->GetAttributeLocation("iTexCoord0"); + VertexColorLocation = _shader_program_uv_persp_correction->GetAttributeLocation("iColor"); + FragmentColor = _shader_program_uv_persp_correction->GetUniformLocationARB ("color"); + + nux::GetGraphicsEngine ().SetTexture(GL_TEXTURE0, icon); + + if(TextureObjectLocation != -1) + CHECKGL( glUniform1iARB (TextureObjectLocation, 0) ); + + int VPMatrixLocation = _shader_program_uv_persp_correction->GetUniformLocationARB("ViewProjectionMatrix"); + if(VPMatrixLocation != -1) + { + nux::Matrix4 mat = nux::GetGraphicsEngine ().GetModelViewProjectionMatrix (); + _shader_program_uv_persp_correction->SetUniformLocMatrix4fv ((GLint)VPMatrixLocation, 1, false, (GLfloat*)&(mat.m)); + } + } + else + { + _AsmShaderProg->Begin(); + + VertexLocation = nux::VTXATTRIB_POSITION; + TextureCoord0Location = nux::VTXATTRIB_TEXCOORD0; + VertexColorLocation = nux::VTXATTRIB_COLOR; + + nux::GetGraphicsEngine().SetTexture(GL_TEXTURE0, icon); + } + + CHECKGL( glEnableVertexAttribArrayARB(VertexLocation) ); + CHECKGL( glVertexAttribPointerARB((GLuint)VertexLocation, 4, GL_FLOAT, GL_FALSE, 48, VtxBuffer) ); + + if(TextureCoord0Location != -1) + { + CHECKGL( glEnableVertexAttribArrayARB(TextureCoord0Location) ); + CHECKGL( glVertexAttribPointerARB((GLuint)TextureCoord0Location, 4, GL_FLOAT, GL_FALSE, 48, VtxBuffer + 4) ); + } + + if(VertexColorLocation != -1) + { + CHECKGL( glEnableVertexAttribArrayARB(VertexColorLocation) ); + CHECKGL( glVertexAttribPointerARB((GLuint)VertexColorLocation, 4, GL_FLOAT, GL_FALSE, 48, VtxBuffer + 8) ); + } + + bkg_color.SetAlpha (bkg_color.A () * alpha); + + if(!USE_ARB_SHADERS) + { + CHECKGL ( glUniform4fARB (FragmentColor, bkg_color.R(), bkg_color.G(), bkg_color.B(), bkg_color.A() ) ); + nux::GetGraphicsEngine ().SetTexture(GL_TEXTURE0, icon); + CHECKGL( glDrawArrays(GL_QUADS, 0, 4) ); + } + else + { + CHECKGL ( glProgramLocalParameter4fARB (GL_FRAGMENT_PROGRAM_ARB, 0, bkg_color.R(), bkg_color.G(), bkg_color.B(), bkg_color.A() ) ); + nux::GetGraphicsEngine ().SetTexture(GL_TEXTURE0, icon); + CHECKGL( glDrawArrays(GL_QUADS, 0, 4) ); + } + + if(VertexLocation != -1) + CHECKGL( glDisableVertexAttribArrayARB(VertexLocation) ); + if(TextureCoord0Location != -1) + CHECKGL( glDisableVertexAttribArrayARB(TextureCoord0Location) ); + if(VertexColorLocation != -1) + CHECKGL( glDisableVertexAttribArrayARB(VertexColorLocation) ); + + if(!USE_ARB_SHADERS) + { + _shader_program_uv_persp_correction->End(); + } + else + { + _AsmShaderProg->End(); + } +} + +void Launcher::DrawRenderArg (nux::GraphicsEngine& GfxContext, RenderArg const &arg, nux::Geometry geo) +{ + GfxContext.GetRenderStates ().SetSeparateBlend (true, + GL_SRC_ALPHA, + GL_ONE_MINUS_SRC_ALPHA, + GL_ONE_MINUS_DST_ALPHA, + GL_ONE); + + GfxContext.GetRenderStates ().SetColorMask (true, true, true, true); + + if (arg.backlight_intensity < 1.0f) + { + RenderIcon(GfxContext, + arg, + _icon_outline_texture, + nux::Color(0xAAFFFFFF), + 1.0f - arg.backlight_intensity, + arg.icon->_xform_coords["Tile"], + geo); + } + + if (arg.backlight_intensity > 0.0f) + { + RenderIcon(GfxContext, + arg, + _icon_bkg_texture, + arg.icon->BackgroundColor (), + arg.backlight_intensity, + arg.icon->_xform_coords["Tile"], + geo); + } + + GfxContext.GetRenderStates ().SetSeparateBlend (true, + GL_SRC_ALPHA, + GL_ONE_MINUS_SRC_ALPHA, + GL_ONE_MINUS_DST_ALPHA, + GL_ONE); + GfxContext.GetRenderStates ().SetColorMask (true, true, true, true); + + RenderIcon (GfxContext, + arg, + arg.icon->TextureForSize (_icon_image_size), + nux::Color::White, + arg.alpha, + arg.icon->_xform_coords["Image"], + geo); + + if (arg.backlight_intensity > 0.0f) + { + RenderIcon(GfxContext, + arg, + _icon_shine_texture, + nux::Color::White, + arg.backlight_intensity, + arg.icon->_xform_coords["Tile"], + geo); + } + + if (false) + { + switch (arg.window_indicators) + { + case 2: + RenderIcon(GfxContext, + arg, + _icon_2indicator, + nux::Color::White, + 1.0f, + arg.icon->_xform_coords["Tile"], + geo); + break; + case 3: + RenderIcon(GfxContext, + arg, + _icon_3indicator, + nux::Color::White, + 1.0f, + arg.icon->_xform_coords["Tile"], + geo); + break; + case 4: + RenderIcon(GfxContext, + arg, + _icon_4indicator, + nux::Color::White, + 1.0f, + arg.icon->_xform_coords["Tile"], + geo); + break; + } + } + + if (arg.glow_intensity > 0.0f) + { + RenderIcon(GfxContext, + arg, + _icon_glow_texture, + arg.icon->GlowColor (), + arg.glow_intensity, + arg.icon->_xform_coords["Glow"], + geo); + } + + if (arg.shimmer_progress > 0.0f && arg.shimmer_progress < 1.0f) + { + nux::Geometry base = GetGeometry (); + int x1 = base.x + base.width; + int x2 = base.x + base.width; + float shimmer_constant = 1.9f; + + x1 -= geo.width * arg.shimmer_progress * shimmer_constant; + GfxContext.PushClippingRectangle(nux::Geometry (x1, geo.y, x2 - x1, geo.height)); + + float fade_out = 1.0f - CLAMP (((x2 - x1) - geo.width) / (geo.width * (shimmer_constant - 1.0f)), 0.0f, 1.0f); + + RenderIcon(GfxContext, + arg, + _icon_glow_texture, + arg.icon->GlowColor (), + fade_out, + arg.icon->_xform_coords["Glow"], + geo); + + GfxContext.PopClippingRectangle(); + } + + RenderIndicators (GfxContext, + arg, + arg.running_arrow ? arg.window_indicators : 0, + arg.active_arrow ? 1 : 0, + geo); +} + +void Launcher::DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw) +{ + nux::Geometry base = GetGeometry(); + GfxContext.PushClippingRectangle(base); + nux::Geometry bkg_box; + std::list<Launcher::RenderArg> args; + std::list<Launcher::RenderArg>::reverse_iterator rev_it; + std::list<Launcher::RenderArg>::iterator it; + + nux::ROPConfig ROP; + ROP.Blend = false; + ROP.SrcBlend = GL_SRC_ALPHA; + ROP.DstBlend = GL_ONE_MINUS_SRC_ALPHA; + + RenderArgs (args, bkg_box); + + // clear region + gPainter.PushDrawColorLayer(GfxContext, base, nux::Color(0x00000000), true, ROP); + + // clip vertically but not horizontally + GfxContext.PushClippingRectangle(nux::Geometry (base.x, bkg_box.y, base.width, bkg_box.height)); + GfxContext.GetRenderStates ().SetSeparateBlend (true, + GL_SRC_ALPHA, + GL_ONE_MINUS_SRC_ALPHA, + GL_ONE_MINUS_DST_ALPHA, + GL_ONE); + + gPainter.Paint2DQuadColor (GfxContext, bkg_box, nux::Color(0xAA000000)); + + UpdateIconXForm (args); + EventLogic (); + + /* draw launcher */ + for (rev_it = args.rbegin (); rev_it != args.rend (); rev_it++) + { + if ((*rev_it).folding_rads >= 0.0f || (*rev_it).skip) + continue; + + DrawRenderArg (GfxContext, *rev_it, bkg_box); + } + + for (it = args.begin(); it != args.end(); it++) + { + if ((*it).folding_rads < 0.0f || (*it).skip) + continue; + + DrawRenderArg (GfxContext, *it, bkg_box); + } + + + gPainter.Paint2DQuadColor (GfxContext, nux::Geometry (bkg_box.x + bkg_box.width - 1, bkg_box.y, 1, bkg_box.height), nux::Color(0x60FFFFFF)); + + GfxContext.GetRenderStates().SetColorMask (true, true, true, true); + GfxContext.GetRenderStates ().SetSeparateBlend (false, + GL_SRC_ALPHA, + GL_ONE_MINUS_SRC_ALPHA, + GL_SRC_ALPHA, + GL_ONE_MINUS_SRC_ALPHA); + + gPainter.PopBackground(); + GfxContext.PopClippingRectangle(); + GfxContext.PopClippingRectangle(); +} + +void Launcher::PostDraw(nux::GraphicsEngine& GfxContext, bool force_draw) +{ +} + +void Launcher::PreLayoutManagement() +{ + View::PreLayoutManagement(); + if(m_CompositionLayout) + { + m_CompositionLayout->SetGeometry(GetGeometry()); + } +} + +long Launcher::PostLayoutManagement(long LayoutResult) +{ + View::PostLayoutManagement(LayoutResult); + + _mouse_position = nux::Point2 (0, 0); + + return nux::eCompliantHeight | nux::eCompliantWidth; +} + +void Launcher::PositionChildLayout(float offsetX, float offsetY) +{ +} + +bool Launcher::TooltipNotify(LauncherIcon* Icon) +{ + if(GetActiveMenuIcon()) + return false; + return true; +} + +bool Launcher::MenuNotify(LauncherIcon* Icon) +{ + + + return true; +} + +void Launcher::NotifyMenuTermination(LauncherIcon* Icon) +{ +} + +void Launcher::RecvMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags) +{ + _mouse_position = nux::Point2 (x, y); + + MouseDownLogic (x, y, button_flags, key_flags); + EnsureAnimation (); +} + +void Launcher::RecvMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags) +{ + _mouse_position = nux::Point2 (x, y); + nux::Geometry geo = GetGeometry (); + + if (_launcher_action_state == ACTION_DRAG_LAUNCHER && !geo.IsInside(nux::Point(x, y))) + { + // we are no longer hovered + UnsetHover (); + } + + MouseUpLogic (x, y, button_flags, key_flags); + _launcher_action_state = ACTION_NONE; + EnsureAnimation (); +} + +void Launcher::RecvMouseDrag(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags) +{ + _mouse_position = nux::Point2 (x, y); + + _dnd_delta += dy; + + if (nux::Abs (_dnd_delta) < 15 && _launcher_action_state != ACTION_DRAG_LAUNCHER) + return; + + if (_icon_under_mouse) + { + _icon_under_mouse->MouseLeave.emit (); + _icon_under_mouse->_mouse_inside = false; + _icon_under_mouse = 0; + } + + _launcher_action_state = ACTION_DRAG_LAUNCHER; + EnsureAnimation (); +} + +void Launcher::RecvMouseEnter(int x, int y, unsigned long button_flags, unsigned long key_flags) +{ + _mouse_position = nux::Point2 (x, y); + _mouse_inside_launcher = true; + + SetHover (); + + EventLogic (); + EnsureAnimation (); +} + +void Launcher::RecvMouseLeave(int x, int y, unsigned long button_flags, unsigned long key_flags) +{ + _mouse_position = nux::Point2 (x, y); + _mouse_inside_launcher = false; + + if (_launcher_action_state != ACTION_DRAG_LAUNCHER) + UnsetHover (); + + EventLogic (); + EnsureAnimation (); +} + +void Launcher::RecvMouseMove(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags) +{ + _mouse_position = nux::Point2 (x, y); + + // Every time the mouse moves, we check if it is inside an icon... + EventLogic (); +} + +void Launcher::RecvMouseWheel(int x, int y, int wheel_delta, unsigned long button_flags, unsigned long key_flags) +{ +} + +void Launcher::EventLogic () +{ + if (_launcher_action_state == ACTION_DRAG_LAUNCHER) + return; + + LauncherIcon* launcher_icon = 0; + + if (_mouse_inside_launcher) + launcher_icon = MouseIconIntersection (_mouse_position.x, _mouse_position.y); + + if (_icon_under_mouse && (_icon_under_mouse != launcher_icon)) + { + _icon_under_mouse->MouseLeave.emit (); + _icon_under_mouse->_mouse_inside = false; + _icon_under_mouse = 0; + } + + if (launcher_icon && (_icon_under_mouse != launcher_icon)) + { + launcher_icon->MouseEnter.emit (); + launcher_icon->_mouse_inside = true; + _icon_under_mouse = launcher_icon; + } +} + +void Launcher::MouseDownLogic (int x, int y, unsigned long button_flags, unsigned long key_flags) +{ + LauncherIcon* launcher_icon = 0; + launcher_icon = MouseIconIntersection (_mouse_position.x, _mouse_position.y); + + if (launcher_icon) + { + _icon_mouse_down = launcher_icon; + launcher_icon->MouseDown.emit (nux::GetEventButton (button_flags)); + } +} + +void Launcher::MouseUpLogic (int x, int y, unsigned long button_flags, unsigned long key_flags) +{ + LauncherIcon* launcher_icon = 0; + launcher_icon = MouseIconIntersection (_mouse_position.x, _mouse_position.y); + + if (_icon_mouse_down && (_icon_mouse_down == launcher_icon)) + { + _icon_mouse_down->MouseUp.emit (nux::GetEventButton (button_flags)); + + if (_launcher_action_state != ACTION_DRAG_LAUNCHER) + _icon_mouse_down->MouseClick.emit (nux::GetEventButton (button_flags)); + } + + if (launcher_icon && (_icon_mouse_down != launcher_icon)) + { + launcher_icon->MouseUp.emit (nux::GetEventButton (button_flags)); + } + + if (_launcher_action_state == ACTION_DRAG_LAUNCHER) + { + SetTimeStruct (&_drag_end_time); + } + + _icon_mouse_down = 0; +} + +LauncherIcon* Launcher::MouseIconIntersection (int x, int y) +{ + LauncherModel::iterator it; + LauncherModel::reverse_iterator rev_it; + // We are looking for the icon at screen coordinates x, y; + nux::Point2 mouse_position(x, y); + int inside = 0; + + // Because of the way icons fold and stack on one another, we must proceed in 2 steps. + for (rev_it = _model->rbegin (); rev_it != _model->rend (); rev_it++) + { + if ((*rev_it)->_folding_angle < 0.0f || !(*rev_it)->GetQuirk (LAUNCHER_ICON_QUIRK_VISIBLE)) + continue; + + nux::Point2 screen_coord [4]; + for (int i = 0; i < 4; i++) + { + screen_coord [i].x = (*rev_it)->_xform_coords["HitArea"] [i].x; + screen_coord [i].y = (*rev_it)->_xform_coords["HitArea"] [i].y; + } + inside = PointInside2DPolygon (screen_coord, 4, mouse_position, 1); + if (inside) + return (*rev_it); + } + + for (it = _model->begin(); it != _model->end (); it++) + { + if ((*it)->_folding_angle >= 0.0f || !(*it)->GetQuirk (LAUNCHER_ICON_QUIRK_VISIBLE)) + continue; + + nux::Point2 screen_coord [4]; + for (int i = 0; i < 4; i++) + { + screen_coord [i].x = (*it)->_xform_coords["HitArea"] [i].x; + screen_coord [i].y = (*it)->_xform_coords["HitArea"] [i].y; + } + inside = PointInside2DPolygon (screen_coord, 4, mouse_position, 1); + if (inside) + return (*it); + } + + return 0; +} + +void Launcher::SetIconXForm (LauncherIcon *icon, nux::Matrix4 ViewProjectionMatrix, nux::Geometry geo, + float x, float y, float w, float h, float z, std::string name) +{ + nux::Vector4 v0 = nux::Vector4(x, y, z, 1.0f); + nux::Vector4 v1 = nux::Vector4(x, y+h, z, 1.0f); + nux::Vector4 v2 = nux::Vector4(x+w, y+h, z, 1.0f); + nux::Vector4 v3 = nux::Vector4(x+w, y, z, 1.0f); + + v0 = ViewProjectionMatrix * v0; + v1 = ViewProjectionMatrix * v1; + v2 = ViewProjectionMatrix * v2; + v3 = ViewProjectionMatrix * v3; + + v0.divide_xyz_by_w(); + v1.divide_xyz_by_w(); + v2.divide_xyz_by_w(); + v3.divide_xyz_by_w(); + + // normalize to the viewport coordinates and translate to the correct location + v0.x = geo.width *(v0.x + 1.0f)/2.0f - geo.width/2.0f + x + w/2.0f; + v0.y = -geo.height*(v0.y - 1.0f)/2.0f - geo.height/2.0f + y + h/2.0f; + v1.x = geo.width *(v1.x + 1.0f)/2.0f - geo.width/2.0f + x + w/2.0f;; + v1.y = -geo.height*(v1.y - 1.0f)/2.0f - geo.height/2.0f + y + h/2.0f; + v2.x = geo.width *(v2.x + 1.0f)/2.0f - geo.width/2.0f + x + w/2.0f; + v2.y = -geo.height*(v2.y - 1.0f)/2.0f - geo.height/2.0f + y + h/2.0f; + v3.x = geo.width *(v3.x + 1.0f)/2.0f - geo.width/2.0f + x + w/2.0f; + v3.y = -geo.height*(v3.y - 1.0f)/2.0f - geo.height/2.0f + y + h/2.0f; + + + nux::Vector4* vectors = icon->_xform_coords[name]; + + vectors[0].x = v0.x; + vectors[0].y = v0.y; + vectors[0].z = v0.z; + vectors[0].w = v0.w; + vectors[1].x = v1.x; + vectors[1].y = v1.y; + vectors[1].z = v1.z; + vectors[1].w = v1.w; + vectors[2].x = v2.x; + vectors[2].y = v2.y; + vectors[2].z = v2.z; + vectors[2].w = v2.w; + vectors[3].x = v3.x; + vectors[3].y = v3.y; + vectors[3].z = v3.z; + vectors[3].w = v3.w; +} + +void Launcher::UpdateIconXForm (std::list<Launcher::RenderArg> &args) +{ + nux::Geometry geo = GetGeometry (); + nux::Matrix4 ObjectMatrix; + nux::Matrix4 ViewMatrix; + nux::Matrix4 ProjectionMatrix; + nux::Matrix4 ViewProjectionMatrix; + + GetInverseScreenPerspectiveMatrix(ViewMatrix, ProjectionMatrix, geo.width, geo.height, 0.1f, 1000.0f, DEGTORAD(90)); + + //LauncherModel::iterator it; + std::list<Launcher::RenderArg>::iterator it; + for(it = args.begin(); it != args.end(); it++) + { + if ((*it).skip) + continue; + + LauncherIcon* launcher_icon = (*it).icon; + + // We to store the icon angle in the icons itself. Makes one thing easier afterward. + launcher_icon->_folding_angle = (*it).folding_rads; + + float w = _icon_size; + float h = _icon_size; + float x = (*it).center.x - w/2.0f; // x: top left corner + float y = (*it).center.y - h/2.0f; // y: top left corner + float z = (*it).center.z; + + ObjectMatrix = nux::Matrix4::TRANSLATE(geo.width/2.0f, geo.height/2.0f, z) * // Translate the icon to the center of the viewport + nux::Matrix4::ROTATEX((*it).folding_rads) * // rotate the icon + nux::Matrix4::TRANSLATE(-x - w/2.0f, -y - h/2.0f, -z); // Put the center the icon to (0, 0) + + ViewProjectionMatrix = ProjectionMatrix*ViewMatrix*ObjectMatrix; + + SetIconXForm (launcher_icon, ViewProjectionMatrix, geo, x, y, w, h, z, "Tile"); + + w = _icon_image_size; + h = _icon_image_size; + x = (*it).center.x - _icon_size/2.0f + _icon_image_size_delta/2.0f; + y = (*it).center.y - _icon_size/2.0f + _icon_image_size_delta/2.0f; + z = (*it).center.z; + + SetIconXForm (launcher_icon, ViewProjectionMatrix, geo, x, y, w, h, z, "Image"); + + w = _icon_glow_size; + h = _icon_glow_size; + x = (*it).center.x - _icon_glow_size/2.0f; + y = (*it).center.y - _icon_glow_size/2.0f; + z = (*it).center.z; + + SetIconXForm (launcher_icon, ViewProjectionMatrix, geo, x, y, w, h, z, "Glow"); + + w = geo.width + 2; + h = _icon_size + _space_between_icons; + x = (*it).center.x - w/2.0f; + y = (*it).center.y - h/2.0f; + z = (*it).center.z; + + SetIconXForm (launcher_icon, ViewProjectionMatrix, geo, x, y, w, h, z, "HitArea"); + } +} + +void GetInverseScreenPerspectiveMatrix(nux::Matrix4& ViewMatrix, nux::Matrix4& PerspectiveMatrix, + int ViewportWidth, + int ViewportHeight, + float NearClipPlane, + float FarClipPlane, + float Fovy) +{ +/* + Objective: + Given a perspective matrix defined by (Fovy, AspectRatio, NearPlane, FarPlane), we want to compute + the ModelView matrix that transform a quad defined by its top-left coord (0, 0) and its + bottom-right coord (WindowWidth, WindowHeight) into a full screen quad that covers the entire viewport (one to one). + Any quad that is facing the camera and whose 4 points are on the 4 guiding line of the view frustum (pyramid) + will always cover the entire viewport one to one (when projected on the screen). + So all we have to do is to define a quad with x:[-x_cs, x_cs] and y:[-y_cs, y_cs] and find the z distance in eye space (z_cs) so that + the quad touches the 4 guiding lines of the view frustum. + We consider a well centered projection view (no skewing, no oblique clipping plane, ...) and derive the following equations: + x_cs = AspectRatio*y_cs + y_cs/z_cs = tanf(Fovy/2) ==> z_cs = y_cs*1/tanf(Fovy/2) (this is the absolute value the quad depth value will be -z_cs since we are using OpenGL right hand coord system). + + The quad (in camera space) facing the camera and centered around the camera view axis is defined by the points (-x_cs, y_cs) (top-left) + and the point (x_cs, -y_cs) (bottom-right). If we move that quad along the camera view axis and place it at a distance z_cs of the camera, + then its 4 corners are each on the 4 lines of the view frustum. + + (-x_cs, y_cs) Camera Space + ^ + __________|__________ + | | | + | | | + | |(0, 0) | + |----------|----------|-> + | | | + | | | + |__________|__________| + (x_cs, -y_cs) + + The full-screen quad (in screen space) is defined by the point (0, 0) (top-left) and (WindowWidth, WindowHeight) (bottom-right). + We can choose and arbitrary value y_cs and compute the z_cs position in camera space that will produce a quad in camera space that projects into + the full-screen space. + + (0, 0) Screen Space + _____________________-> + | | | + | | | + | | | + |----------|----------| + | | | + | | | + |__________|__________| + v (WindowWidth, WindowHeight) + + The model view matrix is the succession of transformation that convert the quad (0, 0, WindowWidth, WindowHeight) into + the quad (-x_cs, y_cs, x_cs, -y_cs) + + Screen Space Camera Space + x ----> x_ = x*2*x_cs/WindowWidth - x_cs + y ----> y_ = -y*2*y_cs/WindowHeight + y_cs + z ----> z_ = A*z -y_cs*1/tanf(Fovy/2) + where A is a coefficient that can attenuate the rate of change in depth when the quad moves along the camera axis + + If the following is the projection matrix: + + (a, 0, 0, 0) a = 1/(AspectRatio*tan(Fovy/2)) + (0, b, 0, 0) b = 1/tan(Fovy/2) + (0, 0, c, d) + (0, 0, -1, 0) + + and the camera space vertex is (x_cs, y_cs, z_cs, w_cs) projects to the top left corner of the view port on the screen ((-1, 1) in clip space), then + x_cs*a/(-z_cs) = -1; | z_cs = x_cs*a x_cs*a = -y_cs*b ==> x_cs = y_cs*AspectRatio + | ==> ==> + y_cs*b/(-z_cs) = +1; | z_cs = -y_cs*b z_cs = -y_cs*1/tanf(Fovy/2) +*/ + + + float AspectRatio = (float)ViewportWidth/(float)ViewportHeight; + float CameraToScreenDistance = -1.0f; + float y_cs = -CameraToScreenDistance*tanf(0.5f*Fovy/* *3.1415926/180.0f*/); + float x_cs = y_cs*AspectRatio; + //float CameraToScreenDistance = -y_cs*1.0f/(tanf(0.5f*Fovy/* *3.1415926/180.0f*/)); + + ViewMatrix = nux::Matrix4::TRANSLATE(-x_cs, y_cs, CameraToScreenDistance) * + nux::Matrix4::SCALE(2.0f*x_cs/ViewportWidth, -2.0f*y_cs/ViewportHeight, -2.0f * 3 * y_cs/ViewportHeight /* or -2.0f * x_cs/ViewportWidth*/ ); + + PerspectiveMatrix.Perspective(Fovy, AspectRatio, NearClipPlane, FarClipPlane); + +// // Example usage with the matrices above: +// float W = 300; +// float H = 300; +// // centered quad +// float X = (ViewportWidth - W)/2.0; +// float Y = (ViewportHeight - H)/2.0; +// float Z = 0.0f; +// +// { +// glPushMatrix(); +// // Local Transformation of the object +// glTranslatef(0.0f, 0.0f, ObjectDistanceToCamera); +// glTranslatef(X + W/2.0f, Y + H/2.0f, 0.0f); +// glRotatef(cameraAngleY, 1, 0, 0); +// glRotatef(cameraAngleX, 0, 1, 0); +// glTranslatef(-X - W/2.0f, -Y - H/2.0f, 0.0f); +// +// glBegin(GL_QUADS); +// { +// glNormal3f(0.0f, 0.0f, 1.0f); +// +// glColor4f(1.0f, 0.0f, 0.0f, 1.0f); +// glVertex4f(X, Y, Z, 1.0f); +// +// glColor4f(0.0f, 1.0f, 0.0f, 1.0f); +// glVertex4f(X, Y+H, Z, 1.0f); +// +// glColor4f(0.0f, 0.0f, 1.0f, 1.0f); +// glVertex4f(X+W, Y+H, Z, 1.0f); +// +// glColor4f(0.0f, 1.0f, 1.0f, 1.0f); +// glVertex4f(X+W, Y, Z, 1.0f); +// } +// glEnd(); +} + +void Launcher::SetActiveQuicklist (QuicklistView *quicklist) +{ + // Assert: _active_quicklist should be 0 + _active_quicklist = quicklist; +} + +QuicklistView *Launcher::GetActiveQuicklist () +{ + return _active_quicklist; +} + +void Launcher::CancelActiveQuicklist (QuicklistView *quicklist) +{ + if (_active_quicklist == quicklist) + _active_quicklist = 0; +} + diff --git a/src/Launcher.h b/src/Launcher.h index 2fd3345ef..b55111c2d 100644 --- a/src/Launcher.h +++ b/src/Launcher.h @@ -1,245 +1,264 @@ -/* - * Copyright (C) 2010 Canonical Ltd - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3 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, see <http://www.gnu.org/licenses/>. - * - * Authored by: Jason Smith <jason.smith@canonical.com> - * Authored by: Jay Taoko <jay.taoko@canonical.com> - */ - -#ifndef LAUNCHER_H -#define LAUNCHER_H - -#include <sys/time.h> - -#include <Nux/View.h> -#include <Nux/BaseWindow.h> -#include "Introspectable.h" -#include "LauncherIcon.h" -#include "NuxGraphics/IOpenGLAsmShader.h" -#include "Nux/TimerProc.h" - -class LauncherModel; -class QuicklistView; - -class Launcher : public Introspectable, public nux::View -{ -public: - Launcher(nux::BaseWindow *parent, NUX_FILE_LINE_PROTO); - ~Launcher(); - - virtual long ProcessEvent(nux::IEvent &ievent, long TraverseInfo, long ProcessEventInfo); - virtual void Draw(nux::GraphicsEngine& GfxContext, bool force_draw); - virtual void DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw); - virtual void PostDraw(nux::GraphicsEngine& GfxContext, bool force_draw); - - LauncherIcon* GetActiveTooltipIcon() {return m_ActiveTooltipIcon;} - LauncherIcon* GetActiveMenuIcon() {return m_ActiveMenuIcon;} - - bool TooltipNotify(LauncherIcon* Icon); - bool MenuNotify(LauncherIcon* Icon); - - void SetIconSize(int tile_size, int icon_size); - void NotifyMenuTermination(LauncherIcon* Icon); - - void SetModel (LauncherModel *model); - - void SetFloating (bool floating); - - void SetAutohide (bool autohide, nux::View *show_trigger); - bool AutohideEnabled (); - - virtual void RecvMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags); - virtual void RecvMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags); - virtual void RecvMouseDrag(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags); - virtual void RecvMouseEnter(int x, int y, unsigned long button_flags, unsigned long key_flags); - virtual void RecvMouseLeave(int x, int y, unsigned long button_flags, unsigned long key_flags); - virtual void RecvMouseMove(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags); - virtual void RecvMouseWheel(int x, int y, int wheel_delta, unsigned long button_flags, unsigned long key_flags); - - //! Called by LauncherIcon to signal that a Quicklist is becoming active. - void SetActiveQuicklist (QuicklistView *quicklist); - //! Get the active qicklist - QuicklistView *GetActiveQuicklist (); - //! Called by LauncherIcon to signal that a Quicklist is becoming unactive. - void CancelActiveQuicklist (QuicklistView *quicklist); - -protected: - // Introspectable methods - const gchar* GetName (); - void AddProperties (GVariantBuilder *builder); - -private: - typedef enum - { - LAUNCHER_FOLDED, - LAUNCHER_UNFOLDED - } LauncherState; - - typedef enum - { - ACTION_NONE, - ACTION_DRAG_LAUNCHER, - ACTION_DRAG_ICON, - } LauncherActionState; - - typedef struct - { - LauncherIcon *icon; - nux::Point3 center; - float folding_rads; - float alpha; - float backlight_intensity; - float glow_intensity; - float shimmer_progress; - bool running_arrow; - bool active_arrow; - bool skip; - int window_indicators; - } RenderArg; - - static gboolean AnimationTimeout (gpointer data); - static gboolean OnAutohideTimeout (gpointer data); - static gboolean StrutHack (gpointer data); - - void OnTriggerMouseEnter (int x, int y, unsigned long button_flags, unsigned long key_flags); - void OnTriggerMouseLeave (int x, int y, unsigned long button_flags, unsigned long key_flags); - - bool IconNeedsAnimation (LauncherIcon *icon, struct timespec current); - bool AnimationInProgress (); - void SetTimeStruct (struct timespec *timer, struct timespec *sister = 0, int sister_relation = 0); - - void EnsureAnimation (); - void SetupAutohideTimer (); - - float DnDExitProgress (); - float GetHoverProgress (); - float AutohideProgress (); - float IconPresentProgress (LauncherIcon *icon, struct timespec current); - float IconUrgentProgress (LauncherIcon *icon, struct timespec current); - float IconShimmerProgress (LauncherIcon *icon, struct timespec current); - float IconUrgentPulseValue (LauncherIcon *icon, struct timespec current); - float IconStartingPulseValue (LauncherIcon *icon, struct timespec current); - float IconBackgroundIntensity (LauncherIcon *icon, struct timespec current); - - void SetHover (); - void UnsetHover (); - void SetHidden (bool hidden); - - void SetDndDelta (float x, float y, nux::Geometry geo, struct timespec current); - - void SetupRenderArg (LauncherIcon *icon, struct timespec current, RenderArg &arg); - void RenderArgs (std::list<Launcher::RenderArg> &launcher_args, - std::list<Launcher::RenderArg> &shelf_args, - nux::Geometry &box_geo, nux::Geometry &shelf_geo); - - void DrawRenderArg (nux::GraphicsEngine& GfxContext, RenderArg arg, nux::Geometry geo); - - void OnIconAdded (void *icon_pointer); - void OnIconRemoved (void *icon_pointer); - void OnOrderChanged (); - - void OnIconNeedsRedraw (void *icon); - - void RenderIcon (nux::GraphicsEngine& GfxContext, - RenderArg arg, - nux::BaseTexture *icon, - nux::Color bkg_color, - float alpha, - nux::Vector4 xform_coords[], - nux::Geometry geo, - bool render_indicators); - - void SetIconXForm (LauncherIcon *icon, nux::Matrix4 ViewProjectionMatrix, nux::Geometry geo, - float x, float y, float w, float h, float z, std::string name); - void UpdateIconXForm (std::list<Launcher::RenderArg> args); - - LauncherIcon* MouseIconIntersection (int x, int y); - void EventLogic (); - void MouseDownLogic (int x, int y, unsigned long button_flags, unsigned long key_flags); - void MouseUpLogic (int x, int y, unsigned long button_flags, unsigned long key_flags); - - virtual void PreLayoutManagement(); - virtual long PostLayoutManagement(long LayoutResult); - virtual void PositionChildLayout(float offsetX, float offsetY); - - - nux::HLayout* m_Layout; - int m_ContentOffsetY; - - LauncherIcon* m_ActiveTooltipIcon; - LauncherIcon* m_ActiveMenuIcon; - - - QuicklistView* _active_quicklist; - - bool _hovered; - bool _floating; - bool _autohide; - bool _hidden; - bool _mouse_inside_launcher; - - float _folded_angle; - float _neg_folded_angle; - float _folded_z_distance; - float _launcher_top_y; - float _launcher_bottom_y; - - LauncherState _launcher_state; - LauncherActionState _launcher_action_state; - LauncherIcon* _icon_under_mouse; - LauncherIcon* _icon_mouse_down; - - int _space_between_icons; - int _icon_size; - int _icon_image_size; - int _icon_image_size_delta; - int _icon_glow_size; - int _dnd_delta; - int _dnd_security; - int _enter_y; - - nux::BaseTexture* _icon_bkg_texture; - nux::BaseTexture* _icon_shine_texture; - nux::BaseTexture* _icon_outline_texture; - nux::BaseTexture* _icon_glow_texture; - nux::BaseTexture* _icon_2indicator; - nux::BaseTexture* _icon_3indicator; - nux::BaseTexture* _icon_4indicator; - - guint _anim_handle; - guint _autohide_handle; - - nux::Matrix4 _view_matrix; - nux::Matrix4 _projection_matrix; - nux::Point2 _mouse_position; - nux::IntrusiveSP<nux::IOpenGLShaderProgram> _shader_program_uv_persp_correction; - nux::IntrusiveSP<nux::IOpenGLAsmShaderProgram> _AsmShaderProg; - nux::BaseTexture* m_RunningIndicator; - nux::BaseTexture* m_ActiveIndicator; - nux::AbstractPaintLayer* m_BackgroundLayer; - nux::BaseWindow* _parent; - nux::View* _autohide_trigger; - nux::Geometry _last_shelf_area; - LauncherModel* _model; - - /* event times */ - struct timespec _enter_time; - struct timespec _exit_time; - struct timespec _drag_end_time; - struct timespec _autohide_time; -}; - -#endif // LAUNCHER_H - - +/* + * Copyright (C) 2010 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 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, see <http://www.gnu.org/licenses/>. + * + * Authored by: Jason Smith <jason.smith@canonical.com> + * Authored by: Jay Taoko <jay.taoko@canonical.com> + */ + +#ifndef LAUNCHER_H +#define LAUNCHER_H + +#include <sys/time.h> +#include <core/core.h> + +#include <Nux/View.h> +#include <Nux/BaseWindow.h> +#include "Introspectable.h" +#include "LauncherIcon.h" +#include "NuxGraphics/IOpenGLAsmShader.h" +#include "Nux/TimerProc.h" + +class LauncherModel; +class QuicklistView; + +class Launcher : public Introspectable, public nux::View +{ +public: + Launcher(nux::BaseWindow *parent, CompScreen *screen, NUX_FILE_LINE_PROTO); + ~Launcher(); + + virtual long ProcessEvent(nux::IEvent &ievent, long TraverseInfo, long ProcessEventInfo); + virtual void Draw(nux::GraphicsEngine& GfxContext, bool force_draw); + virtual void DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw); + virtual void PostDraw(nux::GraphicsEngine& GfxContext, bool force_draw); + + LauncherIcon* GetActiveTooltipIcon() {return m_ActiveTooltipIcon;} + LauncherIcon* GetActiveMenuIcon() {return m_ActiveMenuIcon;} + + bool TooltipNotify(LauncherIcon* Icon); + bool MenuNotify(LauncherIcon* Icon); + + void SetIconSize(int tile_size, int icon_size); + void NotifyMenuTermination(LauncherIcon* Icon); + + void SetModel (LauncherModel *model); + + void SetFloating (bool floating); + + void SetAutohide (bool autohide, nux::View *show_trigger); + bool AutohideEnabled (); + + void OnWindowMoved (CompWindow *window); + void OnWindowResized (CompWindow *window); + void OnWindowAppear (CompWindow *window); + void OnWindowDisappear (CompWindow *window); + + virtual void RecvMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags); + virtual void RecvMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags); + virtual void RecvMouseDrag(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags); + virtual void RecvMouseEnter(int x, int y, unsigned long button_flags, unsigned long key_flags); + virtual void RecvMouseLeave(int x, int y, unsigned long button_flags, unsigned long key_flags); + virtual void RecvMouseMove(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags); + virtual void RecvMouseWheel(int x, int y, int wheel_delta, unsigned long button_flags, unsigned long key_flags); + + //! Called by LauncherIcon to signal that a Quicklist is becoming active. + void SetActiveQuicklist (QuicklistView *quicklist); + //! Get the active qicklist + QuicklistView *GetActiveQuicklist (); + //! Called by LauncherIcon to signal that a Quicklist is becoming unactive. + void CancelActiveQuicklist (QuicklistView *quicklist); + +protected: + // Introspectable methods + const gchar* GetName (); + void AddProperties (GVariantBuilder *builder); + +private: + typedef enum + { + LAUNCHER_FOLDED, + LAUNCHER_UNFOLDED + } LauncherState; + + typedef enum + { + ACTION_NONE, + ACTION_DRAG_LAUNCHER, + ACTION_DRAG_ICON, + } LauncherActionState; + + typedef struct + { + LauncherIcon *icon; + nux::Point3 center; + float folding_rads; + float alpha; + float backlight_intensity; + float glow_intensity; + float shimmer_progress; + bool running_arrow; + bool running_colored; + bool active_arrow; + bool active_colored; + bool skip; + int window_indicators; + } RenderArg; + + static gboolean AnimationTimeout (gpointer data); + static gboolean OnAutohideTimeout (gpointer data); + static gboolean StrutHack (gpointer data); + + void OnTriggerMouseEnter (int x, int y, unsigned long button_flags, unsigned long key_flags); + void OnTriggerMouseLeave (int x, int y, unsigned long button_flags, unsigned long key_flags); + + bool IconNeedsAnimation (LauncherIcon *icon, struct timespec const ¤t); + bool AnimationInProgress (); + void SetTimeStruct (struct timespec *timer, struct timespec *sister = 0, int sister_relation = 0); + + void EnsureHiddenState (); + void EnsureAnimation (); + void SetupAutohideTimer (); + + void CheckWindowOverLauncher (); + + float DnDExitProgress (struct timespec const ¤t); + float GetHoverProgress (struct timespec const ¤t); + float AutohideProgress (struct timespec const ¤t); + float IconPresentProgress (LauncherIcon *icon, struct timespec const ¤t); + float IconUrgentProgress (LauncherIcon *icon, struct timespec const ¤t); + float IconShimmerProgress (LauncherIcon *icon, struct timespec const ¤t); + float IconUrgentPulseValue (LauncherIcon *icon, struct timespec const ¤t); + float IconStartingPulseValue (LauncherIcon *icon, struct timespec const ¤t); + float IconBackgroundIntensity (LauncherIcon *icon, struct timespec const ¤t); + + void SetHover (); + void UnsetHover (); + void SetHidden (bool hidden); + + void SetDndDelta (float x, float y, nux::Geometry geo, struct timespec const ¤t); + float DragLimiter (float x); + + void SetupRenderArg (LauncherIcon *icon, struct timespec const ¤t, RenderArg &arg); + void RenderArgs (std::list<Launcher::RenderArg> &launcher_args, + nux::Geometry &box_geo); + + void DrawRenderArg (nux::GraphicsEngine& GfxContext, RenderArg const &arg, nux::Geometry geo); + + void OnIconAdded (void *icon_pointer); + void OnIconRemoved (void *icon_pointer); + void OnOrderChanged (); + + void OnIconNeedsRedraw (void *icon); + + void RenderIndicators (nux::GraphicsEngine& GfxContext, + RenderArg const &arg, + int running, + int active, + nux::Geometry geo); + + void RenderIcon (nux::GraphicsEngine& GfxContext, + RenderArg const &arg, + nux::BaseTexture *icon, + nux::Color bkg_color, + float alpha, + nux::Vector4 xform_coords[], + nux::Geometry geo); + + void SetIconXForm (LauncherIcon *icon, nux::Matrix4 ViewProjectionMatrix, nux::Geometry geo, + float x, float y, float w, float h, float z, std::string name); + void UpdateIconXForm (std::list<Launcher::RenderArg> &args); + + LauncherIcon* MouseIconIntersection (int x, int y); + void EventLogic (); + void MouseDownLogic (int x, int y, unsigned long button_flags, unsigned long key_flags); + void MouseUpLogic (int x, int y, unsigned long button_flags, unsigned long key_flags); + + virtual void PreLayoutManagement(); + virtual long PostLayoutManagement(long LayoutResult); + virtual void PositionChildLayout(float offsetX, float offsetY); + + + nux::HLayout* m_Layout; + int m_ContentOffsetY; + + LauncherIcon* m_ActiveTooltipIcon; + LauncherIcon* m_ActiveMenuIcon; + + + QuicklistView* _active_quicklist; + + bool _hovered; + bool _floating; + bool _autohide; + bool _hidden; + bool _mouse_inside_launcher; + bool _mouse_inside_trigger; + bool _window_over_launcher; + + float _folded_angle; + float _neg_folded_angle; + float _folded_z_distance; + float _launcher_top_y; + float _launcher_bottom_y; + + LauncherState _launcher_state; + LauncherActionState _launcher_action_state; + LauncherIcon* _icon_under_mouse; + LauncherIcon* _icon_mouse_down; + + int _space_between_icons; + int _icon_size; + int _icon_image_size; + int _icon_image_size_delta; + int _icon_glow_size; + int _dnd_delta; + int _dnd_security; + int _enter_y; + + nux::BaseTexture* _icon_bkg_texture; + nux::BaseTexture* _icon_shine_texture; + nux::BaseTexture* _icon_outline_texture; + nux::BaseTexture* _icon_glow_texture; + nux::BaseTexture* _icon_2indicator; + nux::BaseTexture* _icon_3indicator; + nux::BaseTexture* _icon_4indicator; + + guint _anim_handle; + guint _autohide_handle; + + nux::Matrix4 _view_matrix; + nux::Matrix4 _projection_matrix; + nux::Point2 _mouse_position; + nux::IntrusiveSP<nux::IOpenGLShaderProgram> _shader_program_uv_persp_correction; + nux::IntrusiveSP<nux::IOpenGLAsmShaderProgram> _AsmShaderProg; + nux::BaseTexture* m_RunningIndicator; + nux::BaseTexture* m_ActiveIndicator; + nux::AbstractPaintLayer* m_BackgroundLayer; + nux::BaseWindow* _parent; + nux::View* _autohide_trigger; + LauncherModel* _model; + + CompScreen* _screen; + + /* event times */ + struct timespec _enter_time; + struct timespec _exit_time; + struct timespec _drag_end_time; + struct timespec _autohide_time; +}; + +#endif // LAUNCHER_H + + diff --git a/src/LauncherController.cpp b/src/LauncherController.cpp index 5d5996661..43d45675e 100644 --- a/src/LauncherController.cpp +++ b/src/LauncherController.cpp @@ -72,8 +72,11 @@ LauncherController::PresentIconOwningWindow (Window window) } } - owner->Present (2, 600); - owner->UpdateQuirkTimeDelayed (300, LAUNCHER_ICON_QUIRK_SHIMMER); + if (owner) + { + owner->Present (0.5f, 600); + owner->UpdateQuirkTimeDelayed (300, LAUNCHER_ICON_QUIRK_SHIMMER); + } } void @@ -177,6 +180,8 @@ LauncherController::CreateFavorite (const char *file_path) BamfLauncherIcon *icon; app = bamf_matcher_get_application_for_desktop_file (_matcher, file_path, true); + if (!app) + return NULL; if (g_object_get_qdata (G_OBJECT (app), g_quark_from_static_string ("unity-seen"))) { diff --git a/src/LauncherIcon.cpp b/src/LauncherIcon.cpp index 0cbe5f36a..d78eace30 100755..100644 --- a/src/LauncherIcon.cpp +++ b/src/LauncherIcon.cpp @@ -1,555 +1,620 @@ -/* - * Copyright (C) 2010 Canonical Ltd - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3 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, see <http://www.gnu.org/licenses/>. - * - * Authored by: Jason Smith <jason.smith@canonical.com> - */ - -#include <sys/time.h> - -#include "Nux/Nux.h" -#include "Nux/VScrollBar.h" -#include "Nux/HLayout.h" -#include "Nux/VLayout.h" -#include "Nux/MenuPage.h" -#include "Nux/WindowCompositor.h" -#include "Nux/BaseWindow.h" -#include "Nux/MenuPage.h" -#include "NuxCore/Color.h" - -#include "LauncherIcon.h" -#include "Launcher.h" - -#include "QuicklistMenuItem.h" -#include "QuicklistMenuItemLabel.h" -#include "QuicklistMenuItemSeparator.h" -#include "QuicklistMenuItemCheckmark.h" -#include "QuicklistMenuItemRadio.h" - -#define DEFAULT_ICON "application-default-icon" - -nux::Tooltip *LauncherIcon::_current_tooltip = 0; -QuicklistView *LauncherIcon::_current_quicklist = 0; - -LauncherIcon::LauncherIcon(Launcher* launcher) -{ - _folding_angle = 0; - _launcher = launcher; - m_TooltipText = "blank"; - - for (int i = 0; i < LAUNCHER_ICON_QUIRK_LAST; i++) - { - _quirks[i] = 0; - _quirk_times[i].tv_sec = 0; - _quirk_times[i].tv_nsec = 0; - } - - _related_windows = 0; - - _background_color = nux::Color::White; - _glow_color = nux::Color::White; - - _mouse_inside = false; - _tooltip = new nux::Tooltip (); - _icon_type = LAUNCHER_ICON_TYPE_NONE; - _sort_priority = 0; - - _quicklist = new QuicklistView (); - _quicklist->sigVisible.connect (sigc::mem_fun (this, &LauncherIcon::RecvShowQuicklist)); - _quicklist->sigHidden.connect (sigc::mem_fun (this, &LauncherIcon::RecvHideQuicklist)); - _quicklist_is_initialized = false; - - MouseEnter.connect (sigc::mem_fun(this, &LauncherIcon::RecvMouseEnter)); - MouseLeave.connect (sigc::mem_fun(this, &LauncherIcon::RecvMouseLeave)); - MouseDown.connect (sigc::mem_fun(this, &LauncherIcon::RecvMouseDown)); - MouseUp.connect (sigc::mem_fun(this, &LauncherIcon::RecvMouseUp)); - -} - -LauncherIcon::~LauncherIcon() -{ - if (_present_time_handle) - g_source_remove (_present_time_handle); - _present_time_handle = 0; - - if (_center_stabilize_handle) - g_source_remove (_center_stabilize_handle); - _center_stabilize_handle = 0; -} - -nux::Color LauncherIcon::BackgroundColor () -{ - return _background_color; -} - -nux::Color LauncherIcon::GlowColor () -{ - return _glow_color; -} - -nux::BaseTexture * LauncherIcon::TextureForSize (int size) -{ - nux::BaseTexture * result = GetTextureForSize (size); - return result; -} - -void LauncherIcon::ColorForIcon (GdkPixbuf *pixbuf, nux::Color &background, nux::Color &glow) -{ - unsigned int width = gdk_pixbuf_get_width (pixbuf); - unsigned int height = gdk_pixbuf_get_height (pixbuf); - unsigned int row_bytes = gdk_pixbuf_get_rowstride (pixbuf); - - long int rtotal = 0, gtotal = 0, btotal = 0; - float total = 0.0f; - - - guchar *img = gdk_pixbuf_get_pixels (pixbuf); - - for (unsigned int i = 0; i < width; i++) - { - for (unsigned int j = 0; j < height; j++) - { - guchar *pixels = img + ( j * row_bytes + i * 4); - guchar r = *(pixels + 0); - guchar g = *(pixels + 1); - guchar b = *(pixels + 2); - guchar a = *(pixels + 3); - - float saturation = (MAX (r, MAX (g, b)) - MIN (r, MIN (g, b))) / 255.0f; - float relevance = .1 + .9 * (a / 255.0f) * saturation; - - rtotal += (guchar) (r * relevance); - gtotal += (guchar) (g * relevance); - btotal += (guchar) (b * relevance); - - total += relevance * 255; - } - } - - float r, g, b, h, s, v; - r = rtotal / total; - g = gtotal / total; - b = btotal / total; - - nux::RGBtoHSV (r, g, b, h, s, v); - - if (s > .15f) - s = 0.4f; - v = .85f; - - nux::HSVtoRGB (r, g, b, h, s, v); - background = nux::Color (r, g, b); - - v = 1.0f; - nux::HSVtoRGB (r, g, b, h, s, v); - glow = nux::Color (r, g, b); -} - -nux::BaseTexture * LauncherIcon::TextureFromGtkTheme (const char *icon_name, int size) -{ - GdkPixbuf *pbuf; - GtkIconTheme *theme; - GtkIconInfo *info; - nux::BaseTexture *result; - GError *error = NULL; - - theme = gtk_icon_theme_get_default (); - - if (!icon_name) - icon_name = g_strdup (DEFAULT_ICON); - - info = gtk_icon_theme_lookup_icon (theme, - icon_name, - size, - (GtkIconLookupFlags) 0); - if (!info) - { - info = gtk_icon_theme_lookup_icon (theme, - DEFAULT_ICON, - size, - (GtkIconLookupFlags) 0); - } - - if (gtk_icon_info_get_filename (info) == NULL) - { - info = gtk_icon_theme_lookup_icon (theme, - DEFAULT_ICON, - size, - (GtkIconLookupFlags) 0); - } - - pbuf = gtk_icon_info_load_icon (info, &error); - - if (GDK_IS_PIXBUF (pbuf)) - { - result = nux::CreateTextureFromPixbuf (pbuf); - ColorForIcon (pbuf, _background_color, _glow_color); - - g_object_unref (pbuf); - } - else - { - g_warning ("Unable to load '%s' from icon theme: %s", - icon_name, - error ? error->message : "unknown"); - - if (g_strcmp0 (icon_name, "folder") == 0) - return NULL; - else - return TextureFromGtkTheme ("folder", size); - } - - return result; -} - -void LauncherIcon::SetTooltipText(const TCHAR* text) -{ - m_TooltipText = text; - _tooltip->SetText (m_TooltipText); -} - -nux::NString LauncherIcon::GetTooltipText() -{ - return m_TooltipText; -} - -void -LauncherIcon::RecvMouseEnter () -{ - if (_launcher->GetActiveQuicklist ()) - { - // A quicklist is active - return; - } - - int tip_x = _launcher->GetBaseWidth () + 1; //icon_x + icon_w; - int tip_y = _center.y; - - _tooltip->ShowTooltipWithTipAt (tip_x, tip_y); - - if (!_quicklist->IsVisible ()) - { - _tooltip->ShowWindow (true); - } -} - -void LauncherIcon::RecvMouseLeave () -{ - _tooltip->ShowWindow (false); -} - -void LauncherIcon::RecvMouseDown (int button) -{ - if (button == 3) - { - if (_launcher->GetActiveQuicklist () == _quicklist) - { - // this quicklist is already active - return; - } - - if (_launcher->GetActiveQuicklist ()) - { - // Hide the active quicklist. This will prevent it from Ungrabing the pointer in - // QuicklistView::RecvMouseDownOutsideOfQuicklist or void QuicklistView::RecvMouseClick. - // So the new quicklist that is about to be set as active will keep the grab of the pointer. - // Also disable theinput window. - _launcher->GetActiveQuicklist ()->EnableInputWindow (false); - _launcher->GetActiveQuicklist ()->CaptureMouseDownAnyWhereElse (false); - // This call must be last, because after, _launcher->GetActiveQuicklist () will return Null. - // the launcher listen to the sigHidden signal emitted by the BaseWindow when it becomes invisible - // and it set the active window to Null. - _launcher->GetActiveQuicklist ()->ShowWindow (false); - } - - _tooltip->ShowWindow (false); - - _quicklist->RemoveAllMenuItem (); - - std::list<DbusmenuMenuitem *> menus = Menus (); - if (menus.empty ()) - return; - - std::list<DbusmenuMenuitem *>::iterator it; - for (it = menus.begin (); it != menus.end (); it++) - { - DbusmenuMenuitem *menu_item = *it; - - const gchar* type = dbusmenu_menuitem_property_get (menu_item, DBUSMENU_MENUITEM_PROP_TYPE); - const gchar* toggle_type = dbusmenu_menuitem_property_get (menu_item, DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE); - - if (g_strcmp0 (type, DBUSMENU_CLIENT_TYPES_SEPARATOR) == 0) - { - QuicklistMenuItemSeparator* item = new QuicklistMenuItemSeparator (menu_item, NUX_TRACKER_LOCATION); - _quicklist->AddMenuItem (item); - } - else if (g_strcmp0 (toggle_type, DBUSMENU_MENUITEM_TOGGLE_CHECK) == 0) - { - QuicklistMenuItemCheckmark* item = new QuicklistMenuItemCheckmark (menu_item, NUX_TRACKER_LOCATION); - _quicklist->AddMenuItem (item); - } - else if (g_strcmp0 (toggle_type, DBUSMENU_MENUITEM_TOGGLE_RADIO) == 0) - { - QuicklistMenuItemRadio* item = new QuicklistMenuItemRadio (menu_item, NUX_TRACKER_LOCATION); - _quicklist->AddMenuItem (item); - } - else //(g_strcmp0 (type, DBUSMENU_MENUITEM_PROP_LABEL) == 0) - { - QuicklistMenuItemLabel* item = new QuicklistMenuItemLabel (menu_item, NUX_TRACKER_LOCATION); - _quicklist->AddMenuItem (item); - } - } - - int tip_x = _launcher->GetBaseWidth () + 1; //icon_x + icon_w; - int tip_y = _center.y; - _quicklist->ShowQuicklistWithTipAt (tip_x, tip_y); - - _quicklist->EnableInputWindow (true, 1); - _quicklist->GrabPointer (); - - nux::GetWindowCompositor ().SetAlwaysOnFrontWindow (_quicklist); - - _quicklist->NeedRedraw (); - } -} - -void LauncherIcon::RecvMouseUp (int button) -{ - if (button == 3) - { - if (_quicklist->IsVisible ()) - _quicklist->CaptureMouseDownAnyWhereElse (true); - } -} - -void LauncherIcon::RecvShowQuicklist (nux::BaseWindow *quicklist) -{ - _launcher->SetActiveQuicklist (_quicklist); -} - -void LauncherIcon::RecvHideQuicklist (nux::BaseWindow *quicklist) -{ - _launcher->CancelActiveQuicklist (_quicklist); -} - -void LauncherIcon::HideTooltip () -{ - _tooltip->ShowWindow (false); -} - -gboolean -LauncherIcon::OnCenterTimeout (gpointer data) -{ - LauncherIcon *self = (LauncherIcon*)data; - - if (self->_last_stable != self->_center) - { - self->OnCenterStabilized (self->_center); - self->_last_stable = self->_center; - } - - self->_center_stabilize_handle = 0; - return false; -} - -void -LauncherIcon::SetCenter (nux::Point3 center) -{ - _center = center; - - int tip_x = _launcher->GetBaseWidth () + 1; //icon_x + icon_w; - int tip_y = _center.y; - - if (_quicklist->IsVisible ()) - _quicklist->ShowQuicklistWithTipAt (tip_x, tip_y); - else if (_tooltip->IsVisible ()) - _tooltip->ShowTooltipWithTipAt (tip_x, tip_y); - - if (_center_stabilize_handle) - g_source_remove (_center_stabilize_handle); - - _center_stabilize_handle = g_timeout_add (500, &LauncherIcon::OnCenterTimeout, this); -} - -nux::Point3 -LauncherIcon::GetCenter () -{ - return _center; -} - -gboolean -LauncherIcon::OnPresentTimeout (gpointer data) -{ - LauncherIcon *self = (LauncherIcon*) data; - if (!self->GetQuirk (LAUNCHER_ICON_QUIRK_PRESENTED)) - return false; - - self->_present_time_handle = 0; - self->Unpresent (); - - return false; -} - -int LauncherIcon::PresentUrgency () -{ - return _present_urgency; -} - -void -LauncherIcon::Present (int present_urgency, int length) -{ - if (GetQuirk (LAUNCHER_ICON_QUIRK_PRESENTED)) - return; - - if (length >= 0) - _present_time_handle = g_timeout_add (length, &LauncherIcon::OnPresentTimeout, this); - - _present_urgency = present_urgency; - SetQuirk (LAUNCHER_ICON_QUIRK_PRESENTED, true); -} - -void -LauncherIcon::Unpresent () -{ - if (!GetQuirk (LAUNCHER_ICON_QUIRK_PRESENTED)) - return; - - if (_present_time_handle > 0) - g_source_remove (_present_time_handle); - - SetQuirk (LAUNCHER_ICON_QUIRK_PRESENTED, false); -} - -void -LauncherIcon::SetRelatedWindows (int windows) -{ - if (_related_windows == windows) - return; - - _related_windows = windows; - needs_redraw.emit (this); -} - -void -LauncherIcon::Remove () -{ - SetQuirk (LAUNCHER_ICON_QUIRK_VISIBLE, false); - remove.emit (this); -} - -void -LauncherIcon::SetIconType (LauncherIconType type) -{ - _icon_type = type; -} - -void -LauncherIcon::SetSortPriority (int priority) -{ - _sort_priority = priority; -} - -int -LauncherIcon::SortPriority () -{ - return _sort_priority; -} - -LauncherIconType -LauncherIcon::Type () -{ - return _icon_type; -} - -bool -LauncherIcon::GetQuirk (LauncherIconQuirk quirk) -{ - return _quirks[quirk]; -} - -void -LauncherIcon::SetQuirk (LauncherIconQuirk quirk, bool value) -{ - if (_quirks[quirk] == value) - return; - - _quirks[quirk] = value; - clock_gettime (CLOCK_MONOTONIC, &(_quirk_times[quirk])); - needs_redraw.emit (this); - - // Present on urgent as a general policy - if (quirk == LAUNCHER_ICON_QUIRK_VISIBLE && value) - Present (0, 1500); - if (quirk == LAUNCHER_ICON_QUIRK_URGENT && value) - Present (1, 1500); -} - -gboolean -LauncherIcon::OnDelayedUpdateTimeout (gpointer data) -{ - DelayedUpdateArg *arg = (DelayedUpdateArg *) data; - LauncherIcon *self = arg->self; - - clock_gettime (CLOCK_MONOTONIC, &(self->_quirk_times[arg->quirk])); - self->needs_redraw.emit (self); - - return false; -} - -void -LauncherIcon::UpdateQuirkTimeDelayed (guint ms, LauncherIconQuirk quirk) -{ - DelayedUpdateArg *arg = new DelayedUpdateArg (); - arg->self = this; - arg->quirk = quirk; - - g_timeout_add (ms, &LauncherIcon::OnDelayedUpdateTimeout, arg); -} - -void -LauncherIcon::UpdateQuirkTime (LauncherIconQuirk quirk) -{ - clock_gettime (CLOCK_MONOTONIC, &(_quirk_times[quirk])); - needs_redraw.emit (this); -} - -void -LauncherIcon::ResetQuirkTime (LauncherIconQuirk quirk) -{ - _quirk_times[quirk].tv_sec = 0; - _quirk_times[quirk].tv_nsec = 0; -} - -struct timespec -LauncherIcon::GetQuirkTime (LauncherIconQuirk quirk) -{ - return _quirk_times[quirk]; -} - -int -LauncherIcon::RelatedWindows () -{ - return _related_windows; -} - -std::list<DbusmenuMenuitem *> LauncherIcon::Menus () -{ - return GetMenus (); -} - -std::list<DbusmenuMenuitem *> LauncherIcon::GetMenus () -{ - std::list<DbusmenuMenuitem *> result; - return result; -} +/* + * Copyright (C) 2010 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 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, see <http://www.gnu.org/licenses/>. + * + * Authored by: Jason Smith <jason.smith@canonical.com> + */ + +#include <sys/time.h> + +#include "Nux/Nux.h" +#include "Nux/VScrollBar.h" +#include "Nux/HLayout.h" +#include "Nux/VLayout.h" +#include "Nux/MenuPage.h" +#include "Nux/WindowCompositor.h" +#include "Nux/BaseWindow.h" +#include "Nux/MenuPage.h" +#include "NuxCore/Color.h" + +#include "LauncherIcon.h" +#include "Launcher.h" + +#include "QuicklistMenuItem.h" +#include "QuicklistMenuItemLabel.h" +#include "QuicklistMenuItemSeparator.h" +#include "QuicklistMenuItemCheckmark.h" +#include "QuicklistMenuItemRadio.h" + +#define DEFAULT_ICON "application-default-icon" + +nux::Tooltip *LauncherIcon::_current_tooltip = 0; +QuicklistView *LauncherIcon::_current_quicklist = 0; + +LauncherIcon::LauncherIcon(Launcher* launcher) +{ + _folding_angle = 0; + _launcher = launcher; + m_TooltipText = "blank"; + + for (int i = 0; i < LAUNCHER_ICON_QUIRK_LAST; i++) + { + _quirks[i] = 0; + _quirk_times[i].tv_sec = 0; + _quirk_times[i].tv_nsec = 0; + } + + _related_windows = 0; + + _background_color = nux::Color::White; + _glow_color = nux::Color::White; + + _mouse_inside = false; + _tooltip = new nux::Tooltip (); + _icon_type = LAUNCHER_ICON_TYPE_NONE; + _sort_priority = 0; + + _quicklist = new QuicklistView (); + _quicklist->sigVisible.connect (sigc::mem_fun (this, &LauncherIcon::RecvShowQuicklist)); + _quicklist->sigHidden.connect (sigc::mem_fun (this, &LauncherIcon::RecvHideQuicklist)); + _quicklist_is_initialized = false; + + // Add to introspection + AddChild (_quicklist); + AddChild (_tooltip); + + MouseEnter.connect (sigc::mem_fun(this, &LauncherIcon::RecvMouseEnter)); + MouseLeave.connect (sigc::mem_fun(this, &LauncherIcon::RecvMouseLeave)); + MouseDown.connect (sigc::mem_fun(this, &LauncherIcon::RecvMouseDown)); + MouseUp.connect (sigc::mem_fun(this, &LauncherIcon::RecvMouseUp)); + +} + +LauncherIcon::~LauncherIcon() +{ + // Remove from introspection + RemoveChild (_quicklist); + RemoveChild (_tooltip); + + if (_present_time_handle) + g_source_remove (_present_time_handle); + _present_time_handle = 0; + + if (_center_stabilize_handle) + g_source_remove (_center_stabilize_handle); + _center_stabilize_handle = 0; +} + +const gchar * +LauncherIcon::GetName () +{ + return "LauncherIcon"; +} + +void +LauncherIcon::AddProperties (GVariantBuilder *builder) +{ + g_variant_builder_add (builder, "{sv}", "x", _center.x); + g_variant_builder_add (builder, "{sv}", "y", _center.y); + g_variant_builder_add (builder, "{sv}", "z", _center.z); + g_variant_builder_add (builder, "{sv}", "related-windows", g_variant_new_int32 (_related_windows)); + g_variant_builder_add (builder, "{sv}", "icon-type", g_variant_new_int32 (_icon_type)); + g_variant_builder_add (builder, "{sv}", "tooltip-text", g_variant_new_string (m_TooltipText.GetTCharPtr ())); + + g_variant_builder_add (builder, "{sv}", "sort-priority", g_variant_new_int32 (_sort_priority)); + g_variant_builder_add (builder, "{sv}", "quirk-active", g_variant_new_boolean (GetQuirk (LAUNCHER_ICON_QUIRK_ACTIVE))); + g_variant_builder_add (builder, "{sv}", "quirk-visible", g_variant_new_boolean (GetQuirk (LAUNCHER_ICON_QUIRK_VISIBLE))); + g_variant_builder_add (builder, "{sv}", "quirk-urgent", g_variant_new_boolean (GetQuirk (LAUNCHER_ICON_QUIRK_URGENT))); + g_variant_builder_add (builder, "{sv}", "quirk-running", g_variant_new_boolean (GetQuirk (LAUNCHER_ICON_QUIRK_RUNNING))); + g_variant_builder_add (builder, "{sv}", "quirk-presented", g_variant_new_boolean (GetQuirk (LAUNCHER_ICON_QUIRK_PRESENTED))); +} + +nux::Color LauncherIcon::BackgroundColor () +{ + return _background_color; +} + +nux::Color LauncherIcon::GlowColor () +{ + return _glow_color; +} + +nux::BaseTexture * LauncherIcon::TextureForSize (int size) +{ + nux::BaseTexture * result = GetTextureForSize (size); + return result; +} + +void LauncherIcon::ColorForIcon (GdkPixbuf *pixbuf, nux::Color &background, nux::Color &glow) +{ + unsigned int width = gdk_pixbuf_get_width (pixbuf); + unsigned int height = gdk_pixbuf_get_height (pixbuf); + unsigned int row_bytes = gdk_pixbuf_get_rowstride (pixbuf); + + long int rtotal = 0, gtotal = 0, btotal = 0; + float total = 0.0f; + + + guchar *img = gdk_pixbuf_get_pixels (pixbuf); + + for (unsigned int i = 0; i < width; i++) + { + for (unsigned int j = 0; j < height; j++) + { + guchar *pixels = img + ( j * row_bytes + i * 4); + guchar r = *(pixels + 0); + guchar g = *(pixels + 1); + guchar b = *(pixels + 2); + guchar a = *(pixels + 3); + + float saturation = (MAX (r, MAX (g, b)) - MIN (r, MIN (g, b))) / 255.0f; + float relevance = .1 + .9 * (a / 255.0f) * saturation; + + rtotal += (guchar) (r * relevance); + gtotal += (guchar) (g * relevance); + btotal += (guchar) (b * relevance); + + total += relevance * 255; + } + } + + float r, g, b, h, s, v; + r = rtotal / total; + g = gtotal / total; + b = btotal / total; + + nux::RGBtoHSV (r, g, b, h, s, v); + + if (s > .15f) + s = 0.4f; + v = .85f; + + nux::HSVtoRGB (r, g, b, h, s, v); + background = nux::Color (r, g, b); + + v = 1.0f; + nux::HSVtoRGB (r, g, b, h, s, v); + glow = nux::Color (r, g, b); +} + +nux::BaseTexture * LauncherIcon::TextureFromGtkTheme (const char *icon_name, int size) +{ + GdkPixbuf *pbuf; + GtkIconTheme *theme; + GtkIconInfo *info; + nux::BaseTexture *result; + GError *error = NULL; + + theme = gtk_icon_theme_get_default (); + + if (!icon_name) + icon_name = g_strdup (DEFAULT_ICON); + + info = gtk_icon_theme_lookup_icon (theme, + icon_name, + size, + (GtkIconLookupFlags) 0); + if (!info) + { + info = gtk_icon_theme_lookup_icon (theme, + DEFAULT_ICON, + size, + (GtkIconLookupFlags) 0); + } + + if (gtk_icon_info_get_filename (info) == NULL) + { + info = gtk_icon_theme_lookup_icon (theme, + DEFAULT_ICON, + size, + (GtkIconLookupFlags) 0); + } + + pbuf = gtk_icon_info_load_icon (info, &error); + + if (GDK_IS_PIXBUF (pbuf)) + { + result = nux::CreateTextureFromPixbuf (pbuf); + ColorForIcon (pbuf, _background_color, _glow_color); + + g_object_unref (pbuf); + } + else + { + g_warning ("Unable to load '%s' from icon theme: %s", + icon_name, + error ? error->message : "unknown"); + g_error_free (error); + + if (g_strcmp0 (icon_name, "folder") == 0) + return NULL; + else + return TextureFromGtkTheme ("folder", size); + } + + return result; +} + +nux::BaseTexture * LauncherIcon::TextureFromPath (const char *icon_name, int size) +{ + + GdkPixbuf *pbuf; + nux::BaseTexture *result; + GError *error = NULL; + + if (!icon_name) + return TextureFromGtkTheme (DEFAULT_ICON, size); + + pbuf = gdk_pixbuf_new_from_file_at_size (icon_name, size, size, &error); + + if (GDK_IS_PIXBUF (pbuf)) + { + result = nux::CreateTextureFromPixbuf (pbuf); + ColorForIcon (pbuf, _background_color, _glow_color); + + g_object_unref (pbuf); + } + else + { + g_warning ("Unable to load '%s' icon: %s", + icon_name, + error->message); + g_error_free (error); + + return TextureFromGtkTheme (DEFAULT_ICON, size); + } + + return result; +} + +void LauncherIcon::SetTooltipText(const TCHAR* text) +{ + m_TooltipText = text; + _tooltip->SetText (m_TooltipText); +} + +nux::NString LauncherIcon::GetTooltipText() +{ + return m_TooltipText; +} + +void +LauncherIcon::RecvMouseEnter () +{ + if (_launcher->GetActiveQuicklist ()) + { + // A quicklist is active + return; + } + + int tip_x = _launcher->GetBaseWidth () + 1; //icon_x + icon_w; + int tip_y = _center.y; + + _tooltip->ShowTooltipWithTipAt (tip_x, tip_y); + + if (!_quicklist->IsVisible ()) + { + _tooltip->ShowWindow (true); + } +} + +void LauncherIcon::RecvMouseLeave () +{ + _tooltip->ShowWindow (false); +} + +void LauncherIcon::RecvMouseDown (int button) +{ + if (button == 3) + { + if (_launcher->GetActiveQuicklist () == _quicklist) + { + // this quicklist is already active + return; + } + + if (_launcher->GetActiveQuicklist ()) + { + // Hide the active quicklist. This will prevent it from Ungrabing the pointer in + // QuicklistView::RecvMouseDownOutsideOfQuicklist or void QuicklistView::RecvMouseClick. + // So the new quicklist that is about to be set as active will keep the grab of the pointer. + // Also disable theinput window. + _launcher->GetActiveQuicklist ()->EnableInputWindow (false); + _launcher->GetActiveQuicklist ()->CaptureMouseDownAnyWhereElse (false); + // This call must be last, because after, _launcher->GetActiveQuicklist () will return Null. + // the launcher listen to the sigHidden signal emitted by the BaseWindow when it becomes invisible + // and it set the active window to Null. + _launcher->GetActiveQuicklist ()->ShowWindow (false); + } + + _tooltip->ShowWindow (false); + + _quicklist->RemoveAllMenuItem (); + + std::list<DbusmenuMenuitem *> menus = Menus (); + if (menus.empty ()) + return; + + std::list<DbusmenuMenuitem *>::iterator it; + for (it = menus.begin (); it != menus.end (); it++) + { + DbusmenuMenuitem *menu_item = *it; + + const gchar* type = dbusmenu_menuitem_property_get (menu_item, DBUSMENU_MENUITEM_PROP_TYPE); + const gchar* toggle_type = dbusmenu_menuitem_property_get (menu_item, DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE); + + if (g_strcmp0 (type, DBUSMENU_CLIENT_TYPES_SEPARATOR) == 0) + { + QuicklistMenuItemSeparator* item = new QuicklistMenuItemSeparator (menu_item, NUX_TRACKER_LOCATION); + _quicklist->AddMenuItem (item); + } + else if (g_strcmp0 (toggle_type, DBUSMENU_MENUITEM_TOGGLE_CHECK) == 0) + { + QuicklistMenuItemCheckmark* item = new QuicklistMenuItemCheckmark (menu_item, NUX_TRACKER_LOCATION); + _quicklist->AddMenuItem (item); + } + else if (g_strcmp0 (toggle_type, DBUSMENU_MENUITEM_TOGGLE_RADIO) == 0) + { + QuicklistMenuItemRadio* item = new QuicklistMenuItemRadio (menu_item, NUX_TRACKER_LOCATION); + _quicklist->AddMenuItem (item); + } + else //(g_strcmp0 (type, DBUSMENU_MENUITEM_PROP_LABEL) == 0) + { + QuicklistMenuItemLabel* item = new QuicklistMenuItemLabel (menu_item, NUX_TRACKER_LOCATION); + _quicklist->AddMenuItem (item); + } + } + + int tip_x = _launcher->GetBaseWidth () + 1; //icon_x + icon_w; + int tip_y = _center.y; + _quicklist->ShowQuicklistWithTipAt (tip_x, tip_y); + + _quicklist->EnableInputWindow (true, 1); + _quicklist->GrabPointer (); + + nux::GetWindowCompositor ().SetAlwaysOnFrontWindow (_quicklist); + + _quicklist->NeedRedraw (); + } +} + +void LauncherIcon::RecvMouseUp (int button) +{ + if (button == 3) + { + if (_quicklist->IsVisible ()) + _quicklist->CaptureMouseDownAnyWhereElse (true); + } +} + +void LauncherIcon::RecvShowQuicklist (nux::BaseWindow *quicklist) +{ + _launcher->SetActiveQuicklist (_quicklist); +} + +void LauncherIcon::RecvHideQuicklist (nux::BaseWindow *quicklist) +{ + _launcher->CancelActiveQuicklist (_quicklist); +} + +void LauncherIcon::HideTooltip () +{ + _tooltip->ShowWindow (false); +} + +gboolean +LauncherIcon::OnCenterTimeout (gpointer data) +{ + LauncherIcon *self = (LauncherIcon*)data; + + if (self->_last_stable != self->_center) + { + self->OnCenterStabilized (self->_center); + self->_last_stable = self->_center; + } + + self->_center_stabilize_handle = 0; + return false; +} + +void +LauncherIcon::SetCenter (nux::Point3 center) +{ + _center = center; + + int tip_x = _launcher->GetBaseWidth () + 1; //icon_x + icon_w; + int tip_y = _center.y; + + if (_quicklist->IsVisible ()) + _quicklist->ShowQuicklistWithTipAt (tip_x, tip_y); + else if (_tooltip->IsVisible ()) + _tooltip->ShowTooltipWithTipAt (tip_x, tip_y); + + if (_center_stabilize_handle) + g_source_remove (_center_stabilize_handle); + + _center_stabilize_handle = g_timeout_add (500, &LauncherIcon::OnCenterTimeout, this); +} + +nux::Point3 +LauncherIcon::GetCenter () +{ + return _center; +} + +gboolean +LauncherIcon::OnPresentTimeout (gpointer data) +{ + LauncherIcon *self = (LauncherIcon*) data; + if (!self->GetQuirk (LAUNCHER_ICON_QUIRK_PRESENTED)) + return false; + + self->_present_time_handle = 0; + self->Unpresent (); + + return false; +} + +float LauncherIcon::PresentUrgency () +{ + return _present_urgency; +} + +void +LauncherIcon::Present (float present_urgency, int length) +{ + if (GetQuirk (LAUNCHER_ICON_QUIRK_PRESENTED)) + return; + + if (length >= 0) + _present_time_handle = g_timeout_add (length, &LauncherIcon::OnPresentTimeout, this); + + _present_urgency = CLAMP (present_urgency, 0.0f, 1.0f); + SetQuirk (LAUNCHER_ICON_QUIRK_PRESENTED, true); +} + +void +LauncherIcon::Unpresent () +{ + if (!GetQuirk (LAUNCHER_ICON_QUIRK_PRESENTED)) + return; + + if (_present_time_handle > 0) + g_source_remove (_present_time_handle); + + SetQuirk (LAUNCHER_ICON_QUIRK_PRESENTED, false); +} + +void +LauncherIcon::SetRelatedWindows (int windows) +{ + if (_related_windows == windows) + return; + + _related_windows = windows; + needs_redraw.emit (this); +} + +void +LauncherIcon::Remove () +{ + SetQuirk (LAUNCHER_ICON_QUIRK_VISIBLE, false); + remove.emit (this); +} + +void +LauncherIcon::SetIconType (LauncherIconType type) +{ + _icon_type = type; +} + +void +LauncherIcon::SetSortPriority (int priority) +{ + _sort_priority = priority; +} + +int +LauncherIcon::SortPriority () +{ + return _sort_priority; +} + +LauncherIconType +LauncherIcon::Type () +{ + return _icon_type; +} + +bool +LauncherIcon::GetQuirk (LauncherIconQuirk quirk) +{ + return _quirks[quirk]; +} + +void +LauncherIcon::SetQuirk (LauncherIconQuirk quirk, bool value) +{ + if (_quirks[quirk] == value) + return; + + _quirks[quirk] = value; + clock_gettime (CLOCK_MONOTONIC, &(_quirk_times[quirk])); + needs_redraw.emit (this); + + // Present on urgent as a general policy + if (quirk == LAUNCHER_ICON_QUIRK_VISIBLE && value) + Present (0.5f, 1500); + if (quirk == LAUNCHER_ICON_QUIRK_URGENT && value) + Present (0.5f, 1500); +} + +gboolean +LauncherIcon::OnDelayedUpdateTimeout (gpointer data) +{ + DelayedUpdateArg *arg = (DelayedUpdateArg *) data; + LauncherIcon *self = arg->self; + + clock_gettime (CLOCK_MONOTONIC, &(self->_quirk_times[arg->quirk])); + self->needs_redraw.emit (self); + + return false; +} + +void +LauncherIcon::UpdateQuirkTimeDelayed (guint ms, LauncherIconQuirk quirk) +{ + DelayedUpdateArg *arg = new DelayedUpdateArg (); + arg->self = this; + arg->quirk = quirk; + + g_timeout_add (ms, &LauncherIcon::OnDelayedUpdateTimeout, arg); +} + +void +LauncherIcon::UpdateQuirkTime (LauncherIconQuirk quirk) +{ + clock_gettime (CLOCK_MONOTONIC, &(_quirk_times[quirk])); + needs_redraw.emit (this); +} + +void +LauncherIcon::ResetQuirkTime (LauncherIconQuirk quirk) +{ + _quirk_times[quirk].tv_sec = 0; + _quirk_times[quirk].tv_nsec = 0; +} + +struct timespec +LauncherIcon::GetQuirkTime (LauncherIconQuirk quirk) +{ + return _quirk_times[quirk]; +} + +int +LauncherIcon::RelatedWindows () +{ + return _related_windows; +} + +std::list<DbusmenuMenuitem *> LauncherIcon::Menus () +{ + return GetMenus (); +} + +std::list<DbusmenuMenuitem *> LauncherIcon::GetMenus () +{ + std::list<DbusmenuMenuitem *> result; + return result; +} diff --git a/src/LauncherIcon.h b/src/LauncherIcon.h index 2163f53bc..145775dc5 100644 --- a/src/LauncherIcon.h +++ b/src/LauncherIcon.h @@ -1,196 +1,201 @@ -/* - * Copyright (C) 2010 Canonical Ltd - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3 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, see <http://www.gnu.org/licenses/>. - * - * Authored by: Jason Smith <jason.smith@canonical.com> - * - */ - -#ifndef LAUNCHERICON_H -#define LAUNCHERICON_H - -#include <Nux/Nux.h> -#include <Nux/BaseWindow.h> -#include <NuxCore/Math/MathInc.h> - -#include <sigc++/trackable.h> -#include <sigc++/signal.h> -#include <sigc++/functors/ptr_fun.h> -#include <sigc++/functors/mem_fun.h> - -#include <gtk/gtk.h> -#include <libdbusmenu-glib/client.h> -#include <libdbusmenu-glib/menuitem.h> - -#include "Tooltip.h" -#include "QuicklistView.h" - -class Launcher; -class QuicklistView; - -typedef enum -{ - LAUNCHER_ICON_TYPE_NONE, - LAUNCHER_ICON_TYPE_BEGIN, - LAUNCHER_ICON_TYPE_FAVORITE, - LAUNCHER_ICON_TYPE_APPLICATION, - LAUNCHER_ICON_TYPE_PLACE, - LAUNCHER_ICON_TYPE_DEVICE, - LAUNCHER_ICON_TYPE_TRASH, - LAUNCHER_ICON_TYPE_END, -} LauncherIconType; - -typedef enum -{ - LAUNCHER_ICON_QUIRK_VISIBLE, - LAUNCHER_ICON_QUIRK_ACTIVE, - LAUNCHER_ICON_QUIRK_RUNNING, - LAUNCHER_ICON_QUIRK_URGENT, - LAUNCHER_ICON_QUIRK_PRESENTED, - LAUNCHER_ICON_QUIRK_STARTING, - LAUNCHER_ICON_QUIRK_SHIMMER, - - LAUNCHER_ICON_QUIRK_LAST, -} LauncherIconQuirk; - -class LauncherIcon : public nux::InitiallyUnownedObject, public sigc::trackable -{ -public: - LauncherIcon(Launcher* launcher); - ~LauncherIcon(); - - void SetTooltipText (const TCHAR* text); - - nux::NString GetTooltipText (); - - void RecvMouseEnter (); - void RecvMouseLeave (); - void RecvMouseDown (int button); - void RecvMouseUp (int button); - - void RecvShowQuicklist (nux::BaseWindow *quicklist); - void RecvHideQuicklist (nux::BaseWindow *quicklist); - - void HideTooltip (); - - void SetCenter (nux::Point3 center); - nux::Point3 GetCenter (); - - int SortPriority (); - - int RelatedWindows (); - int PresentUrgency (); - - bool GetQuirk (LauncherIconQuirk quirk); - struct timespec GetQuirkTime (LauncherIconQuirk quirk); - - LauncherIconType Type (); - - nux::Color BackgroundColor (); - nux::Color GlowColor (); - - nux::BaseTexture * TextureForSize (int size); - - std::list<DbusmenuMenuitem *> Menus (); - - - sigc::signal<void, int> MouseDown; - sigc::signal<void, int> MouseUp; - sigc::signal<void> MouseEnter; - sigc::signal<void> MouseLeave; - sigc::signal<void, int> MouseClick; - - sigc::signal<void, void *> show; - sigc::signal<void, void *> hide; - sigc::signal<void, void *> remove; - sigc::signal<void, void *> needs_redraw; -protected: - void SetQuirk (LauncherIconQuirk quirk, bool value); - - void UpdateQuirkTimeDelayed (guint ms, LauncherIconQuirk quirk); - void UpdateQuirkTime (LauncherIconQuirk quirk); - void ResetQuirkTime (LauncherIconQuirk quirk); - - void SetRelatedWindows (int windows); - void Remove (); - - - void Present (int urgency, int length); - void Unpresent (); - - void SetIconType (LauncherIconType type); - void SetSortPriority (int priority); - - virtual std::list<DbusmenuMenuitem *> GetMenus (); - virtual nux::BaseTexture * GetTextureForSize (int size) = 0; - - virtual void OnCenterStabilized (nux::Point3 center) {}; - virtual bool IconOwnsWindow (Window w) { return false; } - - nux::BaseTexture * TextureFromGtkTheme (const char *name, int size); - - nux::NString m_TooltipText; - //! the window this icon belong too. - nux::BaseWindow* m_Window; - Launcher* _launcher; - - std::map<std::string, nux::Vector4*> _xform_coords; - bool _mouse_inside; - float _folding_angle; - - nux::Tooltip *_tooltip; - QuicklistView *_quicklist; - - static nux::Tooltip *_current_tooltip; - static QuicklistView *_current_quicklist; - - - friend class Launcher; - friend class LauncherController; - -private: - typedef struct - { - LauncherIcon *self; - LauncherIconQuirk quirk; - } DelayedUpdateArg; - - static void ChildRealized (DbusmenuMenuitem *newitem, QuicklistView *quicklist); - static void RootChanged (DbusmenuClient * client, DbusmenuMenuitem *newroot, QuicklistView *quicklist); - static gboolean OnPresentTimeout (gpointer data); - static gboolean OnCenterTimeout (gpointer data); - static gboolean OnDelayedUpdateTimeout (gpointer data); - - void ColorForIcon (GdkPixbuf *pixbuf, nux::Color &background, nux::Color &glow); - - nux::Color _background_color; - nux::Color _glow_color; - int _sort_priority; - int _related_windows; - int _present_urgency; - guint _present_time_handle; - guint _center_stabilize_handle; - bool _quicklist_is_initialized; - - nux::Point3 _center; - nux::Point3 _last_stable; - LauncherIconType _icon_type; - - bool _quirks[LAUNCHER_ICON_QUIRK_LAST]; - struct timespec _quirk_times[LAUNCHER_ICON_QUIRK_LAST]; - -}; - -#endif // LAUNCHERICON_H - +/* + * Copyright (C) 2010 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 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, see <http://www.gnu.org/licenses/>. + * + * Authored by: Jason Smith <jason.smith@canonical.com> + * + */ + +#ifndef LAUNCHERICON_H +#define LAUNCHERICON_H + +#include <Nux/Nux.h> +#include <Nux/BaseWindow.h> +#include <NuxCore/Math/MathInc.h> + +#include <sigc++/trackable.h> +#include <sigc++/signal.h> +#include <sigc++/functors/ptr_fun.h> +#include <sigc++/functors/mem_fun.h> + +#include <gtk/gtk.h> +#include <libdbusmenu-glib/client.h> +#include <libdbusmenu-glib/menuitem.h> + +#include "Tooltip.h" +#include "QuicklistView.h" +#include "Introspectable.h" + +class Launcher; +class QuicklistView; + +typedef enum +{ + LAUNCHER_ICON_TYPE_NONE, + LAUNCHER_ICON_TYPE_BEGIN, + LAUNCHER_ICON_TYPE_FAVORITE, + LAUNCHER_ICON_TYPE_APPLICATION, + LAUNCHER_ICON_TYPE_PLACE, + LAUNCHER_ICON_TYPE_DEVICE, + LAUNCHER_ICON_TYPE_TRASH, + LAUNCHER_ICON_TYPE_END, +} LauncherIconType; + +typedef enum +{ + LAUNCHER_ICON_QUIRK_VISIBLE, + LAUNCHER_ICON_QUIRK_ACTIVE, + LAUNCHER_ICON_QUIRK_RUNNING, + LAUNCHER_ICON_QUIRK_URGENT, + LAUNCHER_ICON_QUIRK_PRESENTED, + LAUNCHER_ICON_QUIRK_STARTING, + LAUNCHER_ICON_QUIRK_SHIMMER, + + LAUNCHER_ICON_QUIRK_LAST, +} LauncherIconQuirk; + +class LauncherIcon : public Introspectable, public nux::InitiallyUnownedObject, public sigc::trackable +{ +public: + LauncherIcon(Launcher* launcher); + ~LauncherIcon(); + + void SetTooltipText (const TCHAR* text); + + nux::NString GetTooltipText (); + + void RecvMouseEnter (); + void RecvMouseLeave (); + void RecvMouseDown (int button); + void RecvMouseUp (int button); + + void RecvShowQuicklist (nux::BaseWindow *quicklist); + void RecvHideQuicklist (nux::BaseWindow *quicklist); + + void HideTooltip (); + + void SetCenter (nux::Point3 center); + nux::Point3 GetCenter (); + + int SortPriority (); + + int RelatedWindows (); + float PresentUrgency (); + + bool GetQuirk (LauncherIconQuirk quirk); + struct timespec GetQuirkTime (LauncherIconQuirk quirk); + + LauncherIconType Type (); + + nux::Color BackgroundColor (); + nux::Color GlowColor (); + + nux::BaseTexture * TextureForSize (int size); + + std::list<DbusmenuMenuitem *> Menus (); + + + sigc::signal<void, int> MouseDown; + sigc::signal<void, int> MouseUp; + sigc::signal<void> MouseEnter; + sigc::signal<void> MouseLeave; + sigc::signal<void, int> MouseClick; + + sigc::signal<void, void *> show; + sigc::signal<void, void *> hide; + sigc::signal<void, void *> remove; + sigc::signal<void, void *> needs_redraw; +protected: + const gchar * GetName (); + void AddProperties (GVariantBuilder *builder); + + void SetQuirk (LauncherIconQuirk quirk, bool value); + + void UpdateQuirkTimeDelayed (guint ms, LauncherIconQuirk quirk); + void UpdateQuirkTime (LauncherIconQuirk quirk); + void ResetQuirkTime (LauncherIconQuirk quirk); + + void SetRelatedWindows (int windows); + void Remove (); + + + void Present (float urgency, int length); + void Unpresent (); + + void SetIconType (LauncherIconType type); + void SetSortPriority (int priority); + + virtual std::list<DbusmenuMenuitem *> GetMenus (); + virtual nux::BaseTexture * GetTextureForSize (int size) = 0; + + virtual void OnCenterStabilized (nux::Point3 center) {}; + virtual bool IconOwnsWindow (Window w) { return false; } + + nux::BaseTexture * TextureFromGtkTheme (const char *name, int size); + nux::BaseTexture * TextureFromPath (const char *name, int size); + + nux::NString m_TooltipText; + //! the window this icon belong too. + nux::BaseWindow* m_Window; + Launcher* _launcher; + + std::map<std::string, nux::Vector4*> _xform_coords; + bool _mouse_inside; + float _folding_angle; + + nux::Tooltip *_tooltip; + QuicklistView *_quicklist; + + static nux::Tooltip *_current_tooltip; + static QuicklistView *_current_quicklist; + + + friend class Launcher; + friend class LauncherController; + +private: + typedef struct + { + LauncherIcon *self; + LauncherIconQuirk quirk; + } DelayedUpdateArg; + + static void ChildRealized (DbusmenuMenuitem *newitem, QuicklistView *quicklist); + static void RootChanged (DbusmenuClient * client, DbusmenuMenuitem *newroot, QuicklistView *quicklist); + static gboolean OnPresentTimeout (gpointer data); + static gboolean OnCenterTimeout (gpointer data); + static gboolean OnDelayedUpdateTimeout (gpointer data); + + void ColorForIcon (GdkPixbuf *pixbuf, nux::Color &background, nux::Color &glow); + + nux::Color _background_color; + nux::Color _glow_color; + int _sort_priority; + int _related_windows; + float _present_urgency; + guint _present_time_handle; + guint _center_stabilize_handle; + bool _quicklist_is_initialized; + + nux::Point3 _center; + nux::Point3 _last_stable; + LauncherIconType _icon_type; + + bool _quirks[LAUNCHER_ICON_QUIRK_LAST]; + struct timespec _quirk_times[LAUNCHER_ICON_QUIRK_LAST]; + +}; + +#endif // LAUNCHERICON_H + diff --git a/src/LauncherModel.cpp b/src/LauncherModel.cpp index 160bad425..c109bd519 100644 --- a/src/LauncherModel.cpp +++ b/src/LauncherModel.cpp @@ -39,6 +39,20 @@ bool LauncherModel::IconShouldShelf (LauncherIcon *icon) return icon->Type () == LAUNCHER_ICON_TYPE_TRASH; } +void +LauncherModel::Populate () +{ + _inner.clear (); + + iterator it; + + for (it = main_begin (); it != main_end (); it++) + _inner.push_back (*it); + + for (it = shelf_begin (); it != shelf_end (); it++) + _inner.push_back (*it); +} + void LauncherModel::AddIcon (LauncherIcon *icon) { @@ -47,8 +61,10 @@ LauncherModel::AddIcon (LauncherIcon *icon) if (IconShouldShelf (icon)) _inner_shelf.push_front (icon); else - _inner_launcher.push_front (icon); - + _inner_main.push_front (icon); + + Populate (); + icon_added.emit (icon); icon->remove.connect (sigc::mem_fun (this, &LauncherModel::OnIconRemove)); } @@ -58,16 +74,13 @@ LauncherModel::RemoveIcon (LauncherIcon *icon) { size_t size; - size = _inner_shelf.size (); _inner_shelf.remove (icon); - - if (size != _inner_shelf.size ()) - icon_removed.emit (icon); + _inner_main.remove (icon); - size = _inner_launcher.size (); - _inner_launcher.remove (icon); + size = _inner.size (); + _inner.remove (icon); - if (size != _inner_launcher.size ()) + if (size != _inner.size ()) icon_removed.emit (icon); icon->UnReference (); @@ -97,38 +110,64 @@ LauncherModel::OnIconRemove (void *icon_pointer) void LauncherModel::Sort (SortFunc func) { - _inner_launcher.sort (func); - _inner_shelf.sort (func); + _inner.sort (func); + _inner_main.sort (func); + + Populate (); } int LauncherModel::Size () { - return _inner_shelf.size () + _inner_launcher.size (); + return _inner.size (); } LauncherModel::iterator LauncherModel::begin () { - return _inner_launcher.begin (); + return _inner.begin (); } LauncherModel::iterator LauncherModel::end () { - return _inner_launcher.end (); + return _inner.end (); } LauncherModel::reverse_iterator LauncherModel::rbegin () { - return _inner_launcher.rbegin (); + return _inner.rbegin (); } LauncherModel::reverse_iterator LauncherModel::rend () { - return _inner_launcher.rend (); + return _inner.rend (); +} + +LauncherModel::iterator +LauncherModel::main_begin () +{ + return _inner_main.begin (); +} + +LauncherModel::iterator +LauncherModel::main_end () +{ + return _inner_main.end (); +} + +LauncherModel::reverse_iterator +LauncherModel::main_rbegin () +{ + return _inner_main.rbegin (); +} + +LauncherModel::reverse_iterator +LauncherModel::main_rend () +{ + return _inner_main.rend (); } LauncherModel::iterator diff --git a/src/LauncherModel.h b/src/LauncherModel.h index 6a8e90bc9..6da1b3fda 100644 --- a/src/LauncherModel.h +++ b/src/LauncherModel.h @@ -47,6 +47,11 @@ public: reverse_iterator rbegin (); reverse_iterator rend (); + iterator main_begin (); + iterator main_end (); + reverse_iterator main_rbegin (); + reverse_iterator main_rend (); + iterator shelf_begin (); iterator shelf_end (); reverse_iterator shelf_rbegin (); @@ -57,8 +62,11 @@ public: sigc::signal<void> order_changed; private: - Base _inner_launcher; + Base _inner; Base _inner_shelf; + Base _inner_main; + + void Populate (); bool IconShouldShelf (LauncherIcon *icon); diff --git a/src/PanelHomeButton.cpp b/src/PanelHomeButton.cpp index 9fe30194f..154a5972d 100644 --- a/src/PanelHomeButton.cpp +++ b/src/PanelHomeButton.cpp @@ -140,3 +140,21 @@ PanelHomeButton::RecvMouseClick (int x, g_object_unref (context); } } + +const gchar* +PanelHomeButton::GetName () +{ + return "HomeButton"; +} + +void +PanelHomeButton::AddProperties (GVariantBuilder *builder) +{ + nux::Geometry geo = GetGeometry (); + + g_variant_builder_add (builder, "{sv}", "x", g_variant_new_int32 (geo.x)); + g_variant_builder_add (builder, "{sv}", "y", g_variant_new_int32 (geo.y)); + g_variant_builder_add (builder, "{sv}", "width", g_variant_new_int32 (geo.width)); + g_variant_builder_add (builder, "{sv}", "height", g_variant_new_int32 (geo.height)); + g_variant_builder_add (builder, "{sv}", "have-pixbuf", g_variant_new_boolean (GDK_IS_PIXBUF (_pixbuf))); +} diff --git a/src/PanelHomeButton.h b/src/PanelHomeButton.h index 61138de0c..03de813f6 100644 --- a/src/PanelHomeButton.h +++ b/src/PanelHomeButton.h @@ -24,7 +24,9 @@ #include <NuxImage/CairoGraphics.h> #include <NuxGraphics/GraphicsEngine.h> -class PanelHomeButton : public nux::TextureArea +#include "Introspectable.h" + +class PanelHomeButton : public nux::TextureArea, public Introspectable { public: PanelHomeButton (); @@ -32,6 +34,10 @@ public: void RecvMouseClick (int x, int y, unsigned long button_flags, unsigned long key_flags); +protected: + const gchar* GetName (); + void AddProperties (GVariantBuilder *builder); + private: void Refresh (); diff --git a/src/PanelIndicatorObjectEntryView.cpp b/src/PanelIndicatorObjectEntryView.cpp index 302cbd5ec..cd9a8ceee 100644 --- a/src/PanelIndicatorObjectEntryView.cpp +++ b/src/PanelIndicatorObjectEntryView.cpp @@ -63,13 +63,22 @@ PanelIndicatorObjectEntryView::OnMouseDown (int x, int y, long button_flags, lon if ((_proxy->label_visible && _proxy->label_sensitive) || (_proxy->icon_visible && _proxy->icon_sensitive)) { - _proxy->ShowMenu (GetGeometry ().x, + _proxy->ShowMenu (GetGeometry ().x + 1, //cairo translation PANEL_HEIGHT, time (NULL), nux::GetEventButton (button_flags)); } } +void +PanelIndicatorObjectEntryView::Activate () +{ + _proxy->ShowMenu (GetGeometry ().x + 1, //cairo translation FIXME: Make this into one function + PANEL_HEIGHT, + time (NULL), + 1); +} + static char * fix_string (const char *string) { @@ -253,8 +262,8 @@ draw_menu_bg (cairo_t *cr, int width, int height) int radius = 4; double x = 0; double y = 0; - double xos = 1.5; - double yos = 1.5; + double xos = 0.5; + double yos = 0.5; /* FIXME */ double mpi = 3.14159265358979323846; @@ -301,3 +310,34 @@ draw_menu_bg (cairo_t *cr, int width, int height) cairo_stroke (cr); cairo_pattern_destroy (pat); } + +const gchar * +PanelIndicatorObjectEntryView::GetName () +{ + const gchar *name = _proxy->GetId (); + + if (g_strcmp0 (name, "|") == 0) + return NULL; + else + return name; +} + +void +PanelIndicatorObjectEntryView::AddProperties (GVariantBuilder *builder) +{ + nux::Geometry geo = GetGeometry (); + + g_variant_builder_add (builder, "{sv}", "x", g_variant_new_int32 (geo.x)); + g_variant_builder_add (builder, "{sv}", "y", g_variant_new_int32 (geo.y)); + g_variant_builder_add (builder, "{sv}", "width", g_variant_new_int32 (geo.width)); + g_variant_builder_add (builder, "{sv}", "height", g_variant_new_int32 (geo.height)); + + g_variant_builder_add (builder, "{sv}", "label", g_variant_new_string (_proxy->GetLabel ())); + g_variant_builder_add (builder, "{sv}", "label_sensitive", g_variant_new_boolean (_proxy->label_sensitive)); + g_variant_builder_add (builder, "{sv}", "label_visible", g_variant_new_boolean (_proxy->label_visible)); + + g_variant_builder_add (builder, "{sv}", "icon_sensitive", g_variant_new_boolean (_proxy->icon_sensitive)); + g_variant_builder_add (builder, "{sv}", "icon_visible", g_variant_new_boolean (_proxy->icon_visible)); + + g_variant_builder_add (builder, "{sv}", "active", g_variant_new_boolean (_proxy->GetActive ())); +} diff --git a/src/PanelIndicatorObjectEntryView.h b/src/PanelIndicatorObjectEntryView.h index 26e9b1abd..58c9c3606 100644 --- a/src/PanelIndicatorObjectEntryView.h +++ b/src/PanelIndicatorObjectEntryView.h @@ -26,7 +26,9 @@ #include "IndicatorObjectEntryProxy.h" -class PanelIndicatorObjectEntryView : public nux::TextureArea +#include "Introspectable.h" + +class PanelIndicatorObjectEntryView : public nux::TextureArea, public Introspectable { public: PanelIndicatorObjectEntryView (IndicatorObjectEntryProxy *proxy); @@ -34,6 +36,10 @@ public: void Refresh (); void OnMouseDown (int x, int y, long button_flags, long key_flags); + void Activate (); + + const gchar * GetName (); + void AddProperties (GVariantBuilder *builder); public: IndicatorObjectEntryProxy *_proxy; diff --git a/src/PanelIndicatorObjectView.cpp b/src/PanelIndicatorObjectView.cpp index 11620cb4e..52936b710 100644 --- a/src/PanelIndicatorObjectView.cpp +++ b/src/PanelIndicatorObjectView.cpp @@ -80,6 +80,8 @@ PanelIndicatorObjectView::OnEntryAdded (IndicatorObjectEntryProxy *proxy) _entries.push_back (view); + AddChild (view); + this->ComputeChildLayout (); NeedRedraw (); } @@ -100,6 +102,7 @@ PanelIndicatorObjectView::OnEntryRemoved(IndicatorObjectEntryProxy *proxy) PanelIndicatorObjectEntryView *view = static_cast<PanelIndicatorObjectEntryView *> (*it); if (view->_proxy == proxy) { + RemoveChild (view); _entries.erase (it); _layout->RemoveChildObject (view); @@ -110,3 +113,27 @@ PanelIndicatorObjectView::OnEntryRemoved(IndicatorObjectEntryProxy *proxy) this->ComputeChildLayout (); NeedRedraw (); } + +const gchar * +PanelIndicatorObjectView::GetName () +{ + return _proxy->GetName ().c_str (); +} + +const gchar * +PanelIndicatorObjectView::GetChildsName () +{ + return "entries"; +} + +void +PanelIndicatorObjectView::AddProperties (GVariantBuilder *builder) +{ + nux::Geometry geo = GetGeometry (); + + /* Now some props from ourselves */ + g_variant_builder_add (builder, "{sv}", "x", g_variant_new_int32 (geo.x)); + g_variant_builder_add (builder, "{sv}", "y", g_variant_new_int32 (geo.y)); + g_variant_builder_add (builder, "{sv}", "width", g_variant_new_int32 (geo.width)); + g_variant_builder_add (builder, "{sv}", "height", g_variant_new_int32 (geo.height)); +} diff --git a/src/PanelIndicatorObjectView.h b/src/PanelIndicatorObjectView.h index 6d223198a..cc23dbc73 100644 --- a/src/PanelIndicatorObjectView.h +++ b/src/PanelIndicatorObjectView.h @@ -24,7 +24,9 @@ #include "IndicatorObjectProxy.h" #include "PanelIndicatorObjectEntryView.h" -class PanelIndicatorObjectView : public nux::View +#include "Introspectable.h" + +class PanelIndicatorObjectView : public nux::View, public Introspectable { public: PanelIndicatorObjectView (IndicatorObjectProxy *proxy); @@ -39,6 +41,12 @@ public: void OnEntryRemoved (IndicatorObjectEntryProxy *proxy); nux::HLayout *_layout; + +protected: + const gchar * GetName (); + const gchar * GetChildsName (); + void AddProperties (GVariantBuilder *builder); + private: IndicatorObjectProxy *_proxy; std::vector<PanelIndicatorObjectEntryView *> _entries; diff --git a/src/PanelView.cpp b/src/PanelView.cpp index 4652c2d20..3809ec815 100644 --- a/src/PanelView.cpp +++ b/src/PanelView.cpp @@ -1,237 +1,290 @@ -/* - * Copyright (C) 2010 Canonical Ltd - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3 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, see <http://www.gnu.org/licenses/>. - * - * Authored by: Neil Jagdish Patel <neil.patel@canonical.com> - */ - -#include <Nux/Nux.h> -#include <Nux/BaseWindow.h> -#include <Nux/HLayout.h> -#include <Nux/Layout.h> -#include <Nux/WindowCompositor.h> - -#include <NuxImage/CairoGraphics.h> -#include <NuxImage/ImageSurface.h> - -#include <NuxGraphics/GLThread.h> -#include <NuxGraphics/RenderingPipe.h> - -#include <glib.h> - -#include "PanelView.h" - -#include "IndicatorObjectFactoryRemote.h" -#include "PanelIndicatorObjectView.h" - -PanelView::PanelView (NUX_FILE_LINE_DECL) -: View (NUX_FILE_LINE_PARAM) -{ - _bg_layer = new nux::ColorLayer (nux::Color (0xff595853), true); - - _layout = new nux::HLayout ("", NUX_TRACKER_LOCATION); - SetCompositionLayout (_layout); - - // Home button - _home_button = new PanelHomeButton (); - _layout->AddView (_home_button, 0, nux::eCenter, nux::eFull); - - _remote = new IndicatorObjectFactoryRemote (); - _remote->OnObjectAdded.connect (sigc::mem_fun (this, &PanelView::OnObjectAdded)); - _remote->OnMenuPointerMoved.connect (sigc::mem_fun (this, &PanelView::OnMenuPointerMoved)); -} - -PanelView::~PanelView () -{ - delete _remote; - delete _bg_layer; -} - -PanelHomeButton * -PanelView::HomeButton () -{ - return _home_button; -} +/* + * Copyright (C) 2010 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 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, see <http://www.gnu.org/licenses/>. + * + * Authored by: Neil Jagdish Patel <neil.patel@canonical.com> + */ + +#include <Nux/Nux.h> +#include <Nux/BaseWindow.h> +#include <Nux/HLayout.h> +#include <Nux/Layout.h> +#include <Nux/WindowCompositor.h> + +#include <NuxImage/CairoGraphics.h> +#include <NuxImage/ImageSurface.h> + +#include <NuxGraphics/GLThread.h> +#include <NuxGraphics/RenderingPipe.h> + +#include <glib.h> + +#include "PanelView.h" + +#include "IndicatorObjectFactoryRemote.h" +#include "PanelIndicatorObjectView.h" + +PanelView::PanelView (NUX_FILE_LINE_DECL) +: View (NUX_FILE_LINE_PARAM) +{ + _bg_layer = new nux::ColorLayer (nux::Color (0xff595853), true); + + _layout = new nux::HLayout ("", NUX_TRACKER_LOCATION); + SetCompositionLayout (_layout); + + // Home button + _home_button = new PanelHomeButton (); + _layout->AddView (_home_button, 0, nux::eCenter, nux::eFull); + + AddChild (_home_button); + + _remote = new IndicatorObjectFactoryRemote (); + _remote->OnObjectAdded.connect (sigc::mem_fun (this, &PanelView::OnObjectAdded)); + _remote->OnMenuPointerMoved.connect (sigc::mem_fun (this, &PanelView::OnMenuPointerMoved)); + _remote->OnEntryActivateRequest.connect (sigc::mem_fun (this, &PanelView::OnEntryActivateRequest)); +} + +PanelView::~PanelView () +{ + delete _remote; + delete _bg_layer; +} + +PanelHomeButton * +PanelView::HomeButton () +{ + return _home_button; +} const gchar* PanelView::GetName () { - return "PanelView"; + return "Panel"; +} + +const gchar * +PanelView::GetChildsName () +{ + return "indicators"; } void PanelView::AddProperties (GVariantBuilder *builder) { + nux::Geometry geo = GetGeometry (); + + /* First add some properties from the backend */ + _remote->AddProperties (builder); + + /* Now some props from ourselves */ + g_variant_builder_add (builder, "{sv}", "x", g_variant_new_int32 (geo.x)); + g_variant_builder_add (builder, "{sv}", "y", g_variant_new_int32 (geo.y)); + g_variant_builder_add (builder, "{sv}", "width", g_variant_new_int32 (geo.width)); + g_variant_builder_add (builder, "{sv}", "height", g_variant_new_int32 (geo.height)); +} + +long +PanelView::ProcessEvent (nux::IEvent &ievent, long TraverseInfo, long ProcessEventInfo) +{ + long ret = TraverseInfo; + ret = _layout->ProcessEvent (ievent, ret, ProcessEventInfo); + return ret; +} + +void +PanelView::Draw (nux::GraphicsEngine& GfxContext, bool force_draw) +{ + GfxContext.PushClippingRectangle (GetGeometry() ); + + gPainter.PushDrawLayer (GfxContext, GetGeometry (), _bg_layer); + + gPainter.PopBackground (); + + GfxContext.PopClippingRectangle (); +} + +void +PanelView::DrawContent (nux::GraphicsEngine &GfxContext, bool force_draw) +{ + GfxContext.PushClippingRectangle (GetGeometry() ); + + gPainter.PushLayer (GfxContext, GetGeometry (), _bg_layer); + + _layout->ProcessDraw (GfxContext, force_draw); + + gPainter.PopBackground (); + GfxContext.PopClippingRectangle(); +} + +void +PanelView::PreLayoutManagement () +{ + nux::View::PreLayoutManagement (); +} + +long +PanelView::PostLayoutManagement (long LayoutResult) +{ + // I'm imagining this is a good as time as any to update the background + UpdateBackground (); + + return nux::View::PostLayoutManagement (LayoutResult); +} + +void +PanelView::UpdateBackground () +{ + nux::Geometry geo = GetGeometry (); + + if (geo.width == _last_width && geo.height == _last_height) + return; + + _last_width = geo.width; + _last_height = geo.height; + + nux::CairoGraphics cairo_graphics(CAIRO_FORMAT_ARGB32, _last_width, _last_height); + cairo_t *cr = cairo_graphics.GetContext(); + cairo_set_line_width (cr, 1); + + cairo_pattern_t *pat = cairo_pattern_create_linear (0, 0, 0, _last_height); + cairo_pattern_add_color_stop_rgb (pat, 0.0f, 89/255.0f, 88/255.0f, 83/255.0f); + cairo_pattern_add_color_stop_rgb (pat, 1.0f, 50/255.0f, 50/255.0f, 45/255.0f); + cairo_set_source (cr, pat); + cairo_rectangle (cr, 0, 0, _last_width, _last_height); + cairo_fill (cr); + cairo_pattern_destroy (pat); + + cairo_destroy (cr); + + nux::NBitmapData* bitmap = cairo_graphics.GetBitmap(); + + nux::BaseTexture* texture2D = nux::GetThreadGLDeviceFactory ()->CreateSystemCapableTexture (); + texture2D->Update(bitmap); + delete bitmap; + + nux::TexCoordXForm texxform; + texxform.SetTexCoordType (nux::TexCoordXForm::OFFSET_COORD); + texxform.SetWrap (nux::TEXWRAP_REPEAT, nux::TEXWRAP_REPEAT); + if (_bg_layer) + delete _bg_layer; + + nux::ROPConfig rop; + rop.Blend = false; // Disable the blending. By default rop.Blend is false. + rop.SrcBlend = GL_SRC_ALPHA; // Set the source blend factor. + rop.DstBlend = GL_ONE_MINUS_SRC_ALPHA; // Set the destination blend factor. + + _bg_layer = new nux::TextureLayer (texture2D->GetDeviceTexture(), + texxform, // The Oject that defines the texture wraping and coordinate transformation. + nux::Color::White, // The color used to modulate the texture. + true, // Write the alpha value of the texture to the destination buffer. + rop // Use the given raster operation to set the blending when the layer is being rendered. + ); + + texture2D->UnReference (); + + NeedRedraw (); +} + +// +// Signals +// +void +PanelView::OnObjectAdded (IndicatorObjectProxy *proxy) +{ + PanelIndicatorObjectView *view = new PanelIndicatorObjectView (proxy); + + // Appmenu is treated differently as it needs to expand + // We could do this in a more special way, but who has the time for special? + _layout->AddView (view, (g_strstr_len (proxy->GetName ().c_str (), -1, "appmenu") != NULL), nux::eCenter, nux::eFull); + _layout->SetContentDistribution (nux::eStackLeft); + + AddChild (view); + + this->ComputeChildLayout (); + NeedRedraw (); +} + +void +PanelView::OnMenuPointerMoved (int x, int y) +{ + nux::Geometry geo = GetGeometry (); + nux::Geometry hgeo = _home_button->GetGeometry (); + + if (x <= (hgeo.x + hgeo.width)) + return; + + if (x >= geo.x && x <= (geo.x + geo.width) + && y >= geo.y && y <= (geo.y + geo.height)) + { + std::list<Area *>::iterator it; + + std::list<Area *> my_children = _layout->GetChildren (); + for (it = my_children.begin(); it != my_children.end(); it++) + { + PanelIndicatorObjectView *view = static_cast<PanelIndicatorObjectView *> (*it); + + if (view->_layout == NULL) + continue; + + geo = view->GetGeometry (); + if (x >= geo.x && x <= (geo.x + geo.width) + && y >= geo.y && y <= (geo.y + geo.height)) + { + std::list<Area *>::iterator it2; + + std::list<Area *> its_children = view->_layout->GetChildren (); + for (it2 = its_children.begin(); it2 != its_children.end(); it2++) + { + PanelIndicatorObjectEntryView *entry = static_cast<PanelIndicatorObjectEntryView *> (*it2); + + geo = entry->GetGeometry (); + if (x >= geo.x && x <= (geo.x + geo.width) + && y >= geo.y && y <= (geo.y + geo.height)) + { + entry->OnMouseDown (x, y, 0, 0); + break; + } + } + break; + } + } + } +} + +void +PanelView::OnEntryActivateRequest (const char *entry_id) +{ + std::list<Area *>::iterator it; + + std::list<Area *> my_children = _layout->GetChildren (); + for (it = my_children.begin(); it != my_children.end(); it++) + { + PanelIndicatorObjectView *view = static_cast<PanelIndicatorObjectView *> (*it); + + if (view->_layout == NULL) + continue; + + std::list<Area *>::iterator it2; + + std::list<Area *> its_children = view->_layout->GetChildren (); + for (it2 = its_children.begin(); it2 != its_children.end(); it2++) + { + PanelIndicatorObjectEntryView *entry = static_cast<PanelIndicatorObjectEntryView *> (*it2); + + if (g_strcmp0 (entry->GetName (), entry_id) == 0) + { + entry->Activate (); + break; + } + } + } } - -long -PanelView::ProcessEvent (nux::IEvent &ievent, long TraverseInfo, long ProcessEventInfo) -{ - long ret = TraverseInfo; - ret = _layout->ProcessEvent (ievent, ret, ProcessEventInfo); - return ret; -} - -void -PanelView::Draw (nux::GraphicsEngine& GfxContext, bool force_draw) -{ - GfxContext.PushClippingRectangle (GetGeometry() ); - - gPainter.PushDrawLayer (GfxContext, GetGeometry (), _bg_layer); - - gPainter.PopBackground (); - - GfxContext.PopClippingRectangle (); -} - -void -PanelView::DrawContent (nux::GraphicsEngine &GfxContext, bool force_draw) -{ - GfxContext.PushClippingRectangle (GetGeometry() ); - - gPainter.PushLayer (GfxContext, GetGeometry (), _bg_layer); - - _layout->ProcessDraw (GfxContext, force_draw); - - gPainter.PopBackground (); - GfxContext.PopClippingRectangle(); -} - -void -PanelView::PreLayoutManagement () -{ - nux::View::PreLayoutManagement (); -} - -long -PanelView::PostLayoutManagement (long LayoutResult) -{ - // I'm imagining this is a good as time as any to update the background - UpdateBackground (); - - return nux::View::PostLayoutManagement (LayoutResult); -} - -void -PanelView::UpdateBackground () -{ - nux::Geometry geo = GetGeometry (); - - if (geo.width == _last_width && geo.height == _last_height) - return; - - _last_width = geo.width; - _last_height = geo.height; - - nux::CairoGraphics cairo_graphics(CAIRO_FORMAT_ARGB32, _last_width, _last_height); - cairo_t *cr = cairo_graphics.GetContext(); - cairo_set_line_width (cr, 1); - - cairo_pattern_t *pat = cairo_pattern_create_linear (0, 0, 0, _last_height); - cairo_pattern_add_color_stop_rgb (pat, 0.0f, 89/255.0f, 88/255.0f, 83/255.0f); - cairo_pattern_add_color_stop_rgb (pat, 1.0f, 50/255.0f, 50/255.0f, 45/255.0f); - cairo_set_source (cr, pat); - cairo_rectangle (cr, 0, 0, _last_width, _last_height); - cairo_fill (cr); - cairo_pattern_destroy (pat); - - cairo_destroy (cr); - - nux::NBitmapData* bitmap = cairo_graphics.GetBitmap(); - - nux::BaseTexture* texture2D = nux::GetThreadGLDeviceFactory ()->CreateSystemCapableTexture (); - texture2D->Update(bitmap); - delete bitmap; - - nux::TexCoordXForm texxform; - texxform.SetTexCoordType (nux::TexCoordXForm::OFFSET_COORD); - texxform.SetWrap (nux::TEXWRAP_REPEAT, nux::TEXWRAP_REPEAT); - if (_bg_layer) - delete _bg_layer; - - nux::ROPConfig rop; - rop.Blend = false; // Disable the blending. By default rop.Blend is false. - rop.SrcBlend = GL_SRC_ALPHA; // Set the source blend factor. - rop.DstBlend = GL_ONE_MINUS_SRC_ALPHA; // Set the destination blend factor. - - _bg_layer = new nux::TextureLayer (texture2D->GetDeviceTexture(), - texxform, // The Oject that defines the texture wraping and coordinate transformation. - nux::Color::White, // The color used to modulate the texture. - true, // Write the alpha value of the texture to the destination buffer. - rop // Use the given raster operation to set the blending when the layer is being rendered. - ); - - texture2D->UnReference (); - - NeedRedraw (); -} - -// -// Signals -// -void -PanelView::OnObjectAdded (IndicatorObjectProxy *proxy) -{ - PanelIndicatorObjectView *view = new PanelIndicatorObjectView (proxy); - - // Appmenu is treated differently as it needs to expand - // We could do this in a more special way, but who has the time for special? - _layout->AddView (view, (g_strstr_len (proxy->GetName ().c_str (), -1, "appmenu") != NULL), nux::eCenter, nux::eFull); - _layout->SetContentDistribution (nux::eStackLeft); - - this->ComputeChildLayout (); - NeedRedraw (); -} - -void -PanelView::OnMenuPointerMoved (int x, int y) -{ - nux::Geometry geo = GetGeometry (); - nux::Geometry hgeo = _home_button->GetGeometry (); - - if (x <= (hgeo.x + hgeo.width)) - return; - - if (x >= geo.x && x <= (geo.x + geo.width) - && y >= geo.y && y <= (geo.y + geo.height)) - { - std::list<Area *>::iterator it; - - std::list<Area *> my_children = _layout->GetChildren (); - for (it = my_children.begin(); it != my_children.end(); it++) - { - PanelIndicatorObjectView *view = static_cast<PanelIndicatorObjectView *> (*it); - - geo = view->GetGeometry (); - if (x >= geo.x && x <= (geo.x + geo.width) - && y >= geo.y && y <= (geo.y + geo.height)) - { - std::list<Area *>::iterator it2; - - std::list<Area *> its_children = view->_layout->GetChildren (); - for (it2 = its_children.begin(); it2 != its_children.end(); it2++) - { - PanelIndicatorObjectEntryView *entry = static_cast<PanelIndicatorObjectEntryView *> (*it2); - - geo = entry->GetGeometry (); - if (x >= geo.x && x <= (geo.x + geo.width) - && y >= geo.y && y <= (geo.y + geo.height)) - { - entry->OnMouseDown (x, y, 0, 0); - break; - } - } - break; - } - } - } -} diff --git a/src/PanelView.h b/src/PanelView.h index c775c36b8..f6afc4f95 100644 --- a/src/PanelView.h +++ b/src/PanelView.h @@ -1,67 +1,69 @@ -/* - * Copyright (C) 2010 Canonical Ltd - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3 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, see <http://www.gnu.org/licenses/>. - * - * Authored by: Neil Jagdish Patel <neil.patel@canonical.com> - */ - -#ifndef PANEL_VIEW_H -#define PANEL_VIEW_H - -#include <Nux/View.h> -#include <Nux/TextureArea.h> -#include <NuxGraphics/GraphicsEngine.h> - -#include "PanelHomeButton.h" -#include "IndicatorObjectFactoryRemote.h" +/* + * Copyright (C) 2010 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 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, see <http://www.gnu.org/licenses/>. + * + * Authored by: Neil Jagdish Patel <neil.patel@canonical.com> + */ + +#ifndef PANEL_VIEW_H +#define PANEL_VIEW_H + +#include <Nux/View.h> +#include <Nux/TextureArea.h> +#include <NuxGraphics/GraphicsEngine.h> + +#include "PanelHomeButton.h" +#include "IndicatorObjectFactoryRemote.h" #include "Introspectable.h" - -class PanelView : public Introspectable, public nux::View -{ -public: - PanelView (NUX_FILE_LINE_PROTO); - ~PanelView (); - - virtual long ProcessEvent (nux::IEvent &ievent, long TraverseInfo, long ProcessEventInfo); - virtual void Draw (nux::GraphicsEngine& GfxContext, bool force_draw); - virtual void DrawContent (nux::GraphicsEngine &GfxContext, bool force_draw); - - virtual void PreLayoutManagement (); - virtual long PostLayoutManagement (long LayoutResult); - - void OnObjectAdded (IndicatorObjectProxy *proxy); - void OnMenuPointerMoved (int x, int y); - + +class PanelView : public Introspectable, public nux::View +{ +public: + PanelView (NUX_FILE_LINE_PROTO); + ~PanelView (); + + virtual long ProcessEvent (nux::IEvent &ievent, long TraverseInfo, long ProcessEventInfo); + virtual void Draw (nux::GraphicsEngine& GfxContext, bool force_draw); + virtual void DrawContent (nux::GraphicsEngine &GfxContext, bool force_draw); + + virtual void PreLayoutManagement (); + virtual long PostLayoutManagement (long LayoutResult); + + void OnObjectAdded (IndicatorObjectProxy *proxy); + void OnMenuPointerMoved (int x, int y); + void OnEntryActivateRequest (const char *entry_id); + PanelHomeButton * HomeButton (); protected: // Introspectable methods - const gchar* GetName (); - void AddProperties (GVariantBuilder *builder); - -private: - void UpdateBackground (); - -private: - IndicatorObjectFactoryRemote *_remote; - - PanelHomeButton *_home_button; - nux::AbstractPaintLayer *_bg_layer; - nux::HLayout *_layout; - - int _last_width; - int _last_height; -}; - -#endif // PANEL_VIEW_H + const gchar * GetName (); + const gchar * GetChildsName (); + void AddProperties (GVariantBuilder *builder); + +private: + void UpdateBackground (); + +private: + IndicatorObjectFactoryRemote *_remote; + + PanelHomeButton *_home_button; + nux::AbstractPaintLayer *_bg_layer; + nux::HLayout *_layout; + + int _last_width; + int _last_height; +}; + +#endif // PANEL_VIEW_H diff --git a/src/QuicklistMenuItem.cpp b/src/QuicklistMenuItem.cpp index cd0963339..ac1b4d615 100644 --- a/src/QuicklistMenuItem.cpp +++ b/src/QuicklistMenuItem.cpp @@ -43,6 +43,7 @@ View (NUX_FILE_LINE_PARAM) g_warning ("Invalid DbusmenuMenuitem in file %s at line %s.", G_STRFUNC, G_STRLOC); } + _name = 0; _text = 0; _color = nux::Color (1.0f, 1.0f, 1.0f, 1.0f); _menuItem = item; @@ -118,6 +119,9 @@ View (NUX_FILE_LINE_PARAM) QuicklistMenuItem::~QuicklistMenuItem () { + if (_name) + g_free (_name); + if (_text) g_free (_text); } @@ -444,3 +448,22 @@ QuicklistMenuItem::DrawText (cairo_t* cr, g_free (fontName); g_object_unref (layout); } + +// Introspection + +const gchar* QuicklistMenuItem::GetName () +{ + return g_strdup (_name); +} + +void QuicklistMenuItem::AddProperties (GVariantBuilder *builder) +{ + g_variant_builder_add (builder, "{sv}", "text", g_variant_new_string (_text)); + g_variant_builder_add (builder, "{sv}", "x", g_variant_new_int32 (GetBaseX ())); + g_variant_builder_add (builder, "{sv}", "y", g_variant_new_int32 (GetBaseY ())); + g_variant_builder_add (builder, "{sv}", "width", g_variant_new_int32 (GetBaseWidth ())); + g_variant_builder_add (builder, "{sv}", "height", g_variant_new_int32 (GetBaseHeight ())); + g_variant_builder_add (builder, "{sv}", "enabled", g_variant_new_boolean (GetEnabled ())); + g_variant_builder_add (builder, "{sv}", "active", g_variant_new_boolean (GetActive ())); + +} diff --git a/src/QuicklistMenuItem.h b/src/QuicklistMenuItem.h index d07b3a61c..bf4b245a4 100755..100644 --- a/src/QuicklistMenuItem.h +++ b/src/QuicklistMenuItem.h @@ -30,6 +30,8 @@ #include <pango/pango.h> #include <pango/pangocairo.h> +#include "Introspectable.h" + #define ITEM_INDENT_ABS 16 #define ITEM_CORNER_RADIUS_ABS 3 #define ITEM_MARGIN 4 @@ -43,7 +45,7 @@ typedef enum MENUITEM_TYPE_RADIO, } QuicklistMenuItemType; -class QuicklistMenuItem : public nux::View +class QuicklistMenuItem : public nux::View, public Introspectable { public: QuicklistMenuItem (DbusmenuMenuitem* item, @@ -86,6 +88,9 @@ class QuicklistMenuItem : public nux::View virtual bool GetActive (); + // Introspection + const gchar* GetName (); + void AddProperties (GVariantBuilder *builder); protected: gchar* _text; @@ -139,6 +144,9 @@ class QuicklistMenuItem : public nux::View int height, nux::Color color); + // Introspection + gchar *_name; + friend class QuicklistView; }; diff --git a/src/QuicklistMenuItemCheckmark.cpp b/src/QuicklistMenuItemCheckmark.cpp index eaa645c58..36dddf298 100755..100644 --- a/src/QuicklistMenuItemCheckmark.cpp +++ b/src/QuicklistMenuItemCheckmark.cpp @@ -39,6 +39,7 @@ QuicklistMenuItemCheckmark::QuicklistMenuItemCheckmark (DbusmenuMenuitem* item, QuicklistMenuItem (item, NUX_FILE_LINE_PARAM) { + _name = g_strdup ("QuicklistMenuItemCheckmark"); Initialize (item); } @@ -49,6 +50,7 @@ QuicklistMenuItem (item, debug, NUX_FILE_LINE_PARAM) { + _name = g_strdup ("QuicklistMenuItemCheckmark"); Initialize (item); } diff --git a/src/QuicklistMenuItemCheckmark.h b/src/QuicklistMenuItemCheckmark.h index f7d46fc91..f7d46fc91 100755..100644 --- a/src/QuicklistMenuItemCheckmark.h +++ b/src/QuicklistMenuItemCheckmark.h diff --git a/src/QuicklistMenuItemLabel.cpp b/src/QuicklistMenuItemLabel.cpp index 52edd0af6..24504edfd 100755..100644 --- a/src/QuicklistMenuItemLabel.cpp +++ b/src/QuicklistMenuItemLabel.cpp @@ -28,6 +28,7 @@ QuicklistMenuItemLabel::QuicklistMenuItemLabel (DbusmenuMenuitem* item, QuicklistMenuItem (item, NUX_FILE_LINE_PARAM) { + _name = g_strdup ("QuicklistMenuItemLabel"); Initialize (item); } @@ -38,6 +39,7 @@ QuicklistMenuItem (item, debug, NUX_FILE_LINE_PARAM) { + _name = g_strdup ("QuicklistMenuItemLabel"); Initialize (item); } diff --git a/src/QuicklistMenuItemLabel.h b/src/QuicklistMenuItemLabel.h index 1c8936a58..1c8936a58 100755..100644 --- a/src/QuicklistMenuItemLabel.h +++ b/src/QuicklistMenuItemLabel.h diff --git a/src/QuicklistMenuItemRadio.cpp b/src/QuicklistMenuItemRadio.cpp index 3566ee07e..29b2cef25 100755..100644 --- a/src/QuicklistMenuItemRadio.cpp +++ b/src/QuicklistMenuItemRadio.cpp @@ -38,6 +38,7 @@ QuicklistMenuItemRadio::QuicklistMenuItemRadio (DbusmenuMenuitem* item, QuicklistMenuItem (item, NUX_FILE_LINE_PARAM) { + _name = g_strdup ("QuicklistMenuItemRadio"); Initialize (item); } @@ -48,6 +49,7 @@ QuicklistMenuItem (item, debug, NUX_FILE_LINE_PARAM) { + _name = g_strdup ("QuicklistMenuItemRadio"); Initialize (item); } @@ -57,14 +59,9 @@ QuicklistMenuItemRadio::Initialize (DbusmenuMenuitem* item) _item_type = MENUITEM_TYPE_LABEL; if (item) - _text = dbusmenu_menuitem_property_get (item, DBUSMENU_MENUITEM_PROP_LABEL); + _text = g_strdup (dbusmenu_menuitem_property_get (item, DBUSMENU_MENUITEM_PROP_LABEL)); else - _text = "QuicklistItem"; - - _normalTexture[0] = NULL; - _normalTexture[1] = NULL; - _prelightTexture[0] = NULL; - _prelightTexture[1] = NULL; + _text = g_strdup ("Radio Button"); int textWidth = 1; int textHeight = 1; @@ -92,6 +89,15 @@ QuicklistMenuItemRadio::~QuicklistMenuItemRadio () void QuicklistMenuItemRadio::PreLayoutManagement () { + _pre_layout_width = GetBaseWidth (); + _pre_layout_height = GetBaseHeight (); + + if (_normalTexture[0] == 0) + { + UpdateTexture (); + } + + QuicklistMenuItem::PreLayoutManagement (); } long @@ -135,7 +141,7 @@ QuicklistMenuItemRadio::Draw (nux::GraphicsEngine& gfxContext, bool forceDraw) { // Check if the texture have been computed. If they haven't, exit the function. - if (_normalTexture[0] == NULL) + if (!_normalTexture[0]) return; nux::IntrusiveSP<nux::IOpenGLBaseTexture> texture; @@ -152,16 +158,41 @@ QuicklistMenuItemRadio::Draw (nux::GraphicsEngine& gfxContext, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - if (GetActive ()) - if (GetEnabled ()) - texture = _prelightTexture[1]->GetDeviceTexture (); - else + if (GetEnabled ()) + { + if (GetActive () && _prelight) + { texture = _prelightTexture[0]->GetDeviceTexture (); - else - if (GetEnabled ()) + } + else if (GetActive ()) + { + texture = _normalTexture[0]->GetDeviceTexture (); + } + + if ((!GetActive ()) && _prelight) + { + texture = _prelightTexture[1]->GetDeviceTexture (); + } + else if (!GetActive ()) + { texture = _normalTexture[1]->GetDeviceTexture (); + } + + _color = nux::Color::White; + } + else + { + if (GetActive ()) + { + texture = _prelightTexture[0]->GetDeviceTexture (); + } else + { texture = _normalTexture[0]->GetDeviceTexture (); + } + + _color = nux::Color::DarkGray; + } gfxContext.QRP_GLSL_1Tex (base.x, base.y, @@ -191,8 +222,9 @@ QuicklistMenuItemRadio::PostDraw (nux::GraphicsEngine& gfxContext, void QuicklistMenuItemRadio::UpdateTexture () { - int width = GetBaseWidth (); - int height = GetBaseHeight (); + nux::Color transparent = nux::Color (0.0f, 0.0f, 0.0f, 0.0f); + int width = GetBaseWidth (); + int height = GetBaseHeight (); _cairoGraphics = new nux::CairoGraphics (CAIRO_FORMAT_ARGB32, width, height); cairo_t *cr = _cairoGraphics->GetContext (); @@ -206,7 +238,7 @@ QuicklistMenuItemRadio::UpdateTexture () cairo_set_source_rgba (cr, 1.0f, 1.0f, 1.0f, 1.0f); cairo_set_line_width (cr, 1.0f); - DrawText (cr, width, height, _textColor); + DrawText (cr, width, height, nux::Color::White); nux::NBitmapData* bitmap = _cairoGraphics->GetBitmap (); @@ -234,7 +266,7 @@ QuicklistMenuItemRadio::UpdateTexture () cairo_fill (cr); cairo_set_source_rgba (cr, 1.0f, 1.0f, 1.0f, 1.0f); - DrawText (cr, width, height, _textColor); + DrawText (cr, width, height, nux::Color::White); bitmap = _cairoGraphics->GetBitmap (); @@ -264,7 +296,7 @@ QuicklistMenuItemRadio::UpdateTexture () cairo_set_source_rgba (cr, 0.0f, 0.0f, 0.0f, 0.0f); - DrawText (cr, width, height, _textColor); + DrawText (cr, width, height, transparent); bitmap = _cairoGraphics->GetBitmap (); @@ -297,7 +329,7 @@ QuicklistMenuItemRadio::UpdateTexture () cairo_arc (cr, x, y, radius, 0.0f * (G_PI / 180.0f), 360.0f * (G_PI / 180.0f)); cairo_fill (cr); - DrawText (cr, width, height, _textColor); + DrawText (cr, width, height, transparent); bitmap = _cairoGraphics->GetBitmap (); diff --git a/src/QuicklistMenuItemRadio.h b/src/QuicklistMenuItemRadio.h index 1b0de505c..1961fdaf8 100755..100644 --- a/src/QuicklistMenuItemRadio.h +++ b/src/QuicklistMenuItemRadio.h @@ -39,6 +39,7 @@ class QuicklistMenuItemRadio : public QuicklistMenuItem ~QuicklistMenuItemRadio (); + protected: void PreLayoutManagement (); long PostLayoutManagement (long layoutResult); @@ -56,19 +57,9 @@ class QuicklistMenuItemRadio : public QuicklistMenuItem void PostDraw (nux::GraphicsEngine& gfxContext, bool forceDraw); - private: - nux::NString _text; - nux::Color _textColor; - int _pre_layout_width; - int _pre_layout_height; - nux::CairoGraphics* _cairoGraphics; - - nux::BaseTexture* _normalTexture[2]; - nux::BaseTexture* _prelightTexture[2]; - void Initialize (DbusmenuMenuitem* item); - void UpdateTexture (); + virtual void UpdateTexture (); virtual int CairoSurfaceWidth (); }; diff --git a/src/QuicklistMenuItemSeparator.cpp b/src/QuicklistMenuItemSeparator.cpp index f519ac9e5..899ccc19a 100755..100644 --- a/src/QuicklistMenuItemSeparator.cpp +++ b/src/QuicklistMenuItemSeparator.cpp @@ -24,6 +24,7 @@ QuicklistMenuItemSeparator::QuicklistMenuItemSeparator (DbusmenuMenuitem* item, QuicklistMenuItem (item, NUX_FILE_LINE_PARAM) { + _name = g_strdup ("QuicklistMenuItemSeparator"); SetMinimumHeight (5); SetBaseSize (64, 5); //_normalTexture = NULL; @@ -38,6 +39,7 @@ QuicklistMenuItem (item, debug, NUX_FILE_LINE_PARAM) { + _name = g_strdup ("QuicklistMenuItemSeparator"); SetMinimumHeight (5); SetBaseSize (64, 5); //_normalTexture = NULL; diff --git a/src/QuicklistMenuItemSeparator.h b/src/QuicklistMenuItemSeparator.h index 31e18d73e..31e18d73e 100755..100644 --- a/src/QuicklistMenuItemSeparator.h +++ b/src/QuicklistMenuItemSeparator.h diff --git a/src/QuicklistView.cpp b/src/QuicklistView.cpp index b344faabe..b1cf1ff01 100644 --- a/src/QuicklistView.cpp +++ b/src/QuicklistView.cpp @@ -35,10 +35,13 @@ #include "QuicklistMenuItemCheckmark.h" #include "QuicklistMenuItemRadio.h" +#include "Introspectable.h" + NUX_IMPLEMENT_OBJECT_TYPE (QuicklistView); QuicklistView::QuicklistView () { + _name = g_strdup ("Quicklist"); _texture_bg = 0; _texture_mask = 0; _texture_outline = 0; @@ -89,10 +92,14 @@ QuicklistView::QuicklistView () OnMouseDrag.connect (sigc::mem_fun (this, &QuicklistView::RecvMouseDrag)); _mouse_down = false; + _enable_quicklist_for_testing = false; } QuicklistView::~QuicklistView () { + if (_name) + g_free (_name); + if (_texture_bg) _texture_bg->UnReference (); @@ -105,11 +112,15 @@ QuicklistView::~QuicklistView () std::list<QuicklistMenuItem*>::iterator it; for (it = _item_list.begin(); it != _item_list.end(); it++) { + // Remove from introspection + RemoveChild (*it); (*it)->UnReference(); } for (it = _default_item_list.begin(); it != _default_item_list.end(); it++) { + // Remove from introspection + RemoveChild (*it); (*it)->UnReference(); } @@ -117,6 +128,12 @@ QuicklistView::~QuicklistView () _item_list.clear (); } +void +QuicklistView::EnableQuicklistForTesting (bool enable_testing) +{ + _enable_quicklist_for_testing = enable_testing; +} + void QuicklistView::ShowQuicklistWithTipAt (int anchor_tip_x, int anchor_tip_y) { int window_width; @@ -183,12 +200,15 @@ long QuicklistView::ProcessEvent (nux::IEvent& ievent, long TraverseInfo, long P _mouse_down = false; if (IsVisible ()) { - CancelItemsPrelightStatus (); - CaptureMouseDownAnyWhereElse (false); - ForceStopFocus (1, 1); - UnGrabPointer (); - EnableInputWindow (false); - ShowWindow (false); + if (!_enable_quicklist_for_testing) + { + CancelItemsPrelightStatus (); + CaptureMouseDownAnyWhereElse (false); + ForceStopFocus (1, 1); + UnGrabPointer (); + EnableInputWindow (false); + ShowWindow (false); + } } return nux::eMouseEventSolved; } @@ -198,17 +218,19 @@ long QuicklistView::ProcessEvent (nux::IEvent& ievent, long TraverseInfo, long P _mouse_down = false; if (IsVisible ()) { - CancelItemsPrelightStatus (); - CaptureMouseDownAnyWhereElse (false); - ForceStopFocus (1, 1); - UnGrabPointer (); - EnableInputWindow (false); - ShowWindow (false); + if (!_enable_quicklist_for_testing) + { + CancelItemsPrelightStatus (); + CaptureMouseDownAnyWhereElse (false); + ForceStopFocus (1, 1); + UnGrabPointer (); + EnableInputWindow (false); + ShowWindow (false); + } } return nux::eMouseEventSolved; } - - + return ret; } @@ -396,12 +418,15 @@ void QuicklistView::RecvItemMouseClick (QuicklistMenuItem* item, int x, int y) // Check if the mouse was released over an item and emit the signal CheckAndEmitItemSignal (x + item->GetBaseX (), y + item->GetBaseY ()); - CancelItemsPrelightStatus (); - CaptureMouseDownAnyWhereElse (false); - ForceStopFocus (1, 1); - UnGrabPointer (); - EnableInputWindow (false); - ShowWindow (false); + if (!_enable_quicklist_for_testing) + { + CancelItemsPrelightStatus (); + CaptureMouseDownAnyWhereElse (false); + ForceStopFocus (1, 1); + UnGrabPointer (); + EnableInputWindow (false); + ShowWindow (false); + } } } @@ -449,14 +474,17 @@ void QuicklistView::RecvItemMouseRelease (QuicklistMenuItem* item, int x, int y) { // Check if the mouse was released over an item and emit the signal CheckAndEmitItemSignal (x + item->GetBaseX (), y + item->GetBaseY ()); - - CancelItemsPrelightStatus (); - CaptureMouseDownAnyWhereElse (false); - ForceStopFocus (1, 1); - UnGrabPointer (); - EnableInputWindow (false); - ShowWindow (false); - } + + if (!_enable_quicklist_for_testing) + { + CancelItemsPrelightStatus (); + CaptureMouseDownAnyWhereElse (false); + ForceStopFocus (1, 1); + UnGrabPointer (); + EnableInputWindow (false); + ShowWindow (false); + } + } } void QuicklistView::CancelItemsPrelightStatus () @@ -542,12 +570,15 @@ void QuicklistView::RecvMouseClick (int x, int y, unsigned long button_flags, un { if (IsVisible ()) { - CancelItemsPrelightStatus (); - CaptureMouseDownAnyWhereElse (false); - ForceStopFocus (1, 1); - UnGrabPointer (); - EnableInputWindow (false); - ShowWindow (false); + if (!_enable_quicklist_for_testing) + { + CancelItemsPrelightStatus (); + CaptureMouseDownAnyWhereElse (false); + ForceStopFocus (1, 1); + UnGrabPointer (); + EnableInputWindow (false); + ShowWindow (false); + } } } @@ -565,12 +596,15 @@ void QuicklistView::RecvMouseDownOutsideOfQuicklist (int x, int y, unsigned long { if (IsVisible ()) { - CancelItemsPrelightStatus (); - CaptureMouseDownAnyWhereElse (false); - ForceStopFocus (1, 1); - UnGrabPointer (); - EnableInputWindow (false); - ShowWindow (false); + if (!_enable_quicklist_for_testing) + { + CancelItemsPrelightStatus (); + CaptureMouseDownAnyWhereElse (false); + ForceStopFocus (1, 1); + UnGrabPointer (); + EnableInputWindow (false); + ShowWindow (false); + } } } @@ -579,11 +613,15 @@ void QuicklistView::RemoveAllMenuItem () std::list<QuicklistMenuItem*>::iterator it; for (it = _item_list.begin(); it != _item_list.end(); it++) { + // Remove from introspection + RemoveChild (*it); (*it)->UnReference(); } for (it = _default_item_list.begin(); it != _default_item_list.end(); it++) { + // Remove from introspection + RemoveChild (*it); (*it)->UnReference(); } @@ -612,6 +650,8 @@ void QuicklistView::AddMenuItem (QuicklistMenuItem* item) _item_layout->AddView(item, 1, nux::eCenter, nux::eFull); _item_list.push_back (item); item->Reference(); + // Add to introspection + AddChild (item); _cairo_text_has_changed = true; nux::GetGraphicsThread ()->AddObjectToRefreshList (this); @@ -1263,26 +1303,29 @@ void QuicklistView::UpdateTexture () return; int size_above_anchor = -1; // equal to sise below - - if ((_item_list.size () != 0) || (_default_item_list.size () != 0)) - { - _top_size = 4; - size_above_anchor = _top_size; - int x = _anchorX - _padding; - int y = _anchorY - _anchor_height/2 - _top_size - _corner_radius - _padding; - SetBaseX (x); - SetBaseY (y); - } - else + if (!_enable_quicklist_for_testing) { - _top_size = 0; - size_above_anchor = -1; - int x = _anchorX - _padding; - int y = _anchorY - _anchor_height/2 - _top_size - _corner_radius - _padding; + if ((_item_list.size () != 0) || (_default_item_list.size () != 0)) + { + _top_size = 4; + size_above_anchor = _top_size; + int x = _anchorX - _padding; + int y = _anchorY - _anchor_height/2 - _top_size - _corner_radius - _padding; + + SetBaseX (x); + SetBaseY (y); + } + else + { + _top_size = 0; + size_above_anchor = -1; + int x = _anchorX - _padding; + int y = _anchorY - _anchor_height/2 - _top_size - _corner_radius - _padding; - SetBaseX (x); - SetBaseY (y); + SetBaseX (x); + SetBaseY (y); + } } float blur_coef = 6.0f; @@ -1438,3 +1481,19 @@ void QuicklistView::TestMenuItems (DbusmenuMenuitem* root) } } +// Introspection + +const gchar* QuicklistView::GetName () +{ + return g_strdup (_name); +} + +void QuicklistView::AddProperties (GVariantBuilder *builder) +{ + g_variant_builder_add (builder, "{sv}", "x", g_variant_new_int32 (GetBaseX ())); + g_variant_builder_add (builder, "{sv}", "y", g_variant_new_int32 (GetBaseY ())); + g_variant_builder_add (builder, "{sv}", "width", g_variant_new_int32 (GetBaseWidth ())); + g_variant_builder_add (builder, "{sv}", "height", g_variant_new_int32 (GetBaseHeight ())); + g_variant_builder_add (builder, "{sv}", "active", g_variant_new_boolean (IsVisible ())); +} + diff --git a/src/QuicklistView.h b/src/QuicklistView.h index 08e76d77a..ada4d9706 100755..100644 --- a/src/QuicklistView.h +++ b/src/QuicklistView.h @@ -31,6 +31,8 @@ #include "QuicklistMenuItem.h" +#include "Introspectable.h" + #define ANCHOR_WIDTH 10.0f #define ANCHOR_HEIGHT 18.0f #define HIGH_LIGHT_Y -30.0f @@ -50,7 +52,7 @@ class SpaceLayout; class QuicklistMenuItem; class QuicklistMenuItemLabel; -class QuicklistView : public nux::BaseWindow +class QuicklistView : public nux::BaseWindow, public Introspectable { NUX_DECLARE_OBJECT_TYPE (QuicklistView, nux::BaseWindow); public: @@ -86,6 +88,12 @@ public: void TestMenuItems (DbusmenuMenuitem* root); + // Introspection + const gchar* GetName (); + void AddProperties (GVariantBuilder *builder); + + void EnableQuicklistForTesting (bool enable_testing); + private: void RecvCairoTextChanged (QuicklistMenuItem* item); void RecvCairoTextColorChanged (QuicklistMenuItem* item); @@ -129,7 +137,11 @@ private: int _top_size; // size of the segment from point 13 to 14. See figure in ql_compute_full_mask_path. bool _mouse_down; - + + //iIf true, suppress the Quicklist behaviour that is expected in Unity. + // Keep the Quicklist on screen for testing and automation. + bool _enable_quicklist_for_testing; + cairo_font_options_t* _fontOpts; nux::BaseTexture* _texture_bg; @@ -153,6 +165,10 @@ private: void UpdateTexture (); std::list<QuicklistMenuItem*> _item_list; std::list<QuicklistMenuItem*> _default_item_list; + + // Introspection + gchar *_name; + }; #endif // QUICKLISTVIEW_H diff --git a/src/SimpleLauncherIcon.cpp b/src/SimpleLauncherIcon.cpp index b8b0bffaa..c61d78956 100644 --- a/src/SimpleLauncherIcon.cpp +++ b/src/SimpleLauncherIcon.cpp @@ -25,20 +25,20 @@ SimpleLauncherIcon::SimpleLauncherIcon (Launcher* IconManager) : LauncherIcon(IconManager) { - m_Icon = 0; - m_IconName = 0; - - LauncherIcon::MouseDown.connect (sigc::mem_fun (this, &SimpleLauncherIcon::OnMouseDown)); - LauncherIcon::MouseUp.connect (sigc::mem_fun (this, &SimpleLauncherIcon::OnMouseUp)); - LauncherIcon::MouseClick.connect (sigc::mem_fun (this, &SimpleLauncherIcon::OnMouseClick)); - LauncherIcon::MouseEnter.connect (sigc::mem_fun (this, &SimpleLauncherIcon::OnMouseEnter)); - LauncherIcon::MouseLeave.connect (sigc::mem_fun (this, &SimpleLauncherIcon::OnMouseLeave)); + m_Icon = 0; + m_IconName = 0; + + LauncherIcon::MouseDown.connect (sigc::mem_fun (this, &SimpleLauncherIcon::OnMouseDown)); + LauncherIcon::MouseUp.connect (sigc::mem_fun (this, &SimpleLauncherIcon::OnMouseUp)); + LauncherIcon::MouseClick.connect (sigc::mem_fun (this, &SimpleLauncherIcon::OnMouseClick)); + LauncherIcon::MouseEnter.connect (sigc::mem_fun (this, &SimpleLauncherIcon::OnMouseEnter)); + LauncherIcon::MouseLeave.connect (sigc::mem_fun (this, &SimpleLauncherIcon::OnMouseLeave)); } SimpleLauncherIcon::~SimpleLauncherIcon() { - if (m_Icon) - m_Icon->UnReference (); + if (m_Icon) + m_Icon->UnReference (); } void @@ -69,21 +69,34 @@ SimpleLauncherIcon::OnMouseLeave () nux::BaseTexture * SimpleLauncherIcon::GetTextureForSize (int size) { - if (m_Icon && size == m_Icon->GetHeight ()) - return m_Icon; - - if (m_Icon) - m_Icon->UnReference (); - - if (!m_IconName) - return 0; + if (m_Icon && size == m_Icon->GetHeight ()) + return m_Icon; + if (m_Icon) + m_Icon->UnReference (); + + if (!m_IconName) + return 0; + + if (g_str_has_prefix (m_IconName, "/")) + m_Icon = TextureFromPath (m_IconName, size); + else m_Icon = TextureFromGtkTheme (m_IconName, size); - return m_Icon; + return m_Icon; } void SimpleLauncherIcon::SetIconName (const char *name) { - m_IconName = g_strdup (name); + if (m_IconName) + g_free (m_IconName); + m_IconName = g_strdup (name); + + if (m_Icon) + { + m_Icon->UnReference (); + m_Icon = 0; + } + + needs_redraw.emit (this); } diff --git a/src/Tooltip.cpp b/src/Tooltip.cpp index f19e6faec..fdde92b16 100644 --- a/src/Tooltip.cpp +++ b/src/Tooltip.cpp @@ -38,6 +38,7 @@ namespace nux Tooltip::Tooltip () { + _name = g_strdup ("Tooltip"); _texture_bg = 0; _texture_mask = 0; _texture_outline = 0; @@ -83,6 +84,9 @@ namespace nux Tooltip::~Tooltip () { + if (_name) + g_free (_name); + if (_texture_bg) _texture_bg->UnReference (); @@ -915,4 +919,21 @@ void ctk_surface_blur (cairo_surface_t* surface, this->ComputeChildLayout (); } + // Introspection + + const gchar* Tooltip::GetName () + { + return g_strdup (_name); + } + + void Tooltip::AddProperties (GVariantBuilder *builder) + { + g_variant_builder_add (builder, "{sv}", "text", g_variant_new_string (_labelText.GetTCharPtr ())); + g_variant_builder_add (builder, "{sv}", "x", g_variant_new_int32 (GetBaseX ())); + g_variant_builder_add (builder, "{sv}", "y", g_variant_new_int32 (GetBaseY ())); + g_variant_builder_add (builder, "{sv}", "width", g_variant_new_int32 (GetBaseWidth ())); + g_variant_builder_add (builder, "{sv}", "height", g_variant_new_int32 (GetBaseHeight ())); + g_variant_builder_add (builder, "{sv}", "active", g_variant_new_boolean (IsVisible ())); + } + } // namespace nux diff --git a/src/Tooltip.h b/src/Tooltip.h index 1e3f01c94..fbbc063a3 100644 --- a/src/Tooltip.h +++ b/src/Tooltip.h @@ -31,6 +31,8 @@ #include <pango/pango.h> #include <pango/pangocairo.h> +#include "Introspectable.h" + #if defined(NUX_OS_LINUX) #include <X11/Xlib.h> #endif @@ -55,7 +57,7 @@ namespace nux class HLayout; class SpaceLayout; - class Tooltip : public BaseWindow + class Tooltip : public BaseWindow, public Introspectable { NUX_DECLARE_OBJECT_TYPE (Tooltip, BaseWindow); public: @@ -76,6 +78,11 @@ namespace nux void SetText (NString text); void ShowTooltipWithTipAt (int anchor_tip_x, int anchor_tip_y); + + // Introspection + const gchar* GetName (); + void AddProperties (GVariantBuilder *builder); + private: void RecvCairoTextChanged (StaticCairoText* cairo_text); @@ -119,6 +126,9 @@ namespace nux bool _cairo_text_has_changed; void UpdateTexture (); + + // Introspection + gchar *_name; }; } diff --git a/src/TrashLauncherIcon.cpp b/src/TrashLauncherIcon.cpp index 7f7caac71..24c24ba9b 100644 --- a/src/TrashLauncherIcon.cpp +++ b/src/TrashLauncherIcon.cpp @@ -18,6 +18,8 @@ #include "TrashLauncherIcon.h" +#include <gio/gio.h> + TrashLauncherIcon::TrashLauncherIcon (Launcher* IconManager) : SimpleLauncherIcon(IconManager) { @@ -26,10 +28,23 @@ TrashLauncherIcon::TrashLauncherIcon (Launcher* IconManager) SetQuirk (LAUNCHER_ICON_QUIRK_VISIBLE, true); SetQuirk (LAUNCHER_ICON_QUIRK_RUNNING, false); SetIconType (LAUNCHER_ICON_TYPE_TRASH); + + m_TrashMonitor = g_file_monitor_directory (g_file_new_for_uri("trash:///"), + G_FILE_MONITOR_NONE, + NULL, + NULL); + + g_signal_connect(m_TrashMonitor, + "changed", + G_CALLBACK (&TrashLauncherIcon::OnTrashChanged), + this); + + UpdateTrashIcon (); } TrashLauncherIcon::~TrashLauncherIcon() { + g_object_unref (m_TrashMonitor); } void @@ -38,10 +53,58 @@ TrashLauncherIcon::OnMouseClick (int button) if (button == 1) { GError *error = NULL; - + g_spawn_command_line_async ("xdg-open trash://", &error); - + if (error) g_error_free (error); } } + +void +TrashLauncherIcon::UpdateTrashIcon () +{ + GFile *location; + location = g_file_new_for_uri ("trash:///"); + + g_file_query_info_async (location, + G_FILE_ATTRIBUTE_STANDARD_ICON, + G_FILE_QUERY_INFO_NONE, + 0, + NULL, + &TrashLauncherIcon::UpdateTrashIconCb, + this); + + g_object_unref(location); +} + +void +TrashLauncherIcon::UpdateTrashIconCb (GObject *source, + GAsyncResult *res, + gpointer data) +{ + TrashLauncherIcon *self = (TrashLauncherIcon*) data; + GFileInfo *info; + GIcon *icon; + + info = g_file_query_info_finish (G_FILE (source), res, NULL); + + if (info != NULL) { + icon = g_file_info_get_icon (info); + self->SetIconName (g_icon_to_string (icon)); + + g_object_unref(info); + } +} + +void +TrashLauncherIcon::OnTrashChanged (GFileMonitor *monitor, + GFile *file, + GFile *other_file, + GFileMonitorEvent event_type, + gpointer data) +{ + TrashLauncherIcon *self = (TrashLauncherIcon*) data; + self->UpdateTrashIcon (); +} + diff --git a/src/TrashLauncherIcon.h b/src/TrashLauncherIcon.h index 1680c5502..c07e1a3fe 100644 --- a/src/TrashLauncherIcon.h +++ b/src/TrashLauncherIcon.h @@ -30,6 +30,13 @@ public: protected: void OnMouseClick (int button); + void UpdateTrashIcon (); + +private: + GFileMonitor *m_TrashMonitor; + static void UpdateTrashIconCb (GObject *source, GAsyncResult *res, gpointer data); + static void OnTrashChanged (GFileMonitor *monitor, GFile *file, GFile *other_file, + GFileMonitorEvent event_type, gpointer data); }; diff --git a/src/unity.cpp b/src/unity.cpp index 1260ea090..d60902979 100644 --- a/src/unity.cpp +++ b/src/unity.cpp @@ -39,6 +39,8 @@ #include <core/atoms.h> +#include "../libunity/perf-logger-utility.h" + /* Set up vtable symbols */ COMPIZ_PLUGIN_20090315 (unityshell, UnityPluginVTable); @@ -47,52 +49,52 @@ static UnityScreen *uScreen = 0; void UnityScreen::nuxPrologue () { - /* reset matrices */ - glPushAttrib (GL_VIEWPORT_BIT | GL_ENABLE_BIT | GL_TEXTURE_BIT | GL_COLOR_BUFFER_BIT); - - glMatrixMode (GL_PROJECTION); - glPushMatrix (); - - glMatrixMode (GL_MODELVIEW); - glPushMatrix (); - - glGetError(); + /* reset matrices */ + glPushAttrib (GL_VIEWPORT_BIT | GL_ENABLE_BIT | GL_TEXTURE_BIT | GL_COLOR_BUFFER_BIT); + + glMatrixMode (GL_PROJECTION); + glPushMatrix (); + + glMatrixMode (GL_MODELVIEW); + glPushMatrix (); + + glGetError(); } void UnityScreen::nuxEpilogue () { - (*GL::bindFramebuffer) (GL_FRAMEBUFFER_EXT, 0); + (*GL::bindFramebuffer) (GL_FRAMEBUFFER_EXT, 0); - glMatrixMode (GL_PROJECTION); - glLoadIdentity (); - glMatrixMode (GL_MODELVIEW); - glLoadIdentity (); - glDepthRange (0, 1); - glViewport (-1, -1, 2, 2); - glRasterPos2f (0, 0); + glMatrixMode (GL_PROJECTION); + glLoadIdentity (); + glMatrixMode (GL_MODELVIEW); + glLoadIdentity (); + glDepthRange (0, 1); + glViewport (-1, -1, 2, 2); + glRasterPos2f (0, 0); - gScreen->resetRasterPos (); + gScreen->resetRasterPos (); - glMatrixMode (GL_PROJECTION); - glPopMatrix (); - glMatrixMode (GL_MODELVIEW); - glPopMatrix (); + glMatrixMode (GL_PROJECTION); + glPopMatrix (); + glMatrixMode (GL_MODELVIEW); + glPopMatrix (); - glDrawBuffer (GL_BACK); - glReadBuffer (GL_BACK); + glDrawBuffer (GL_BACK); + glReadBuffer (GL_BACK); - glPopAttrib (); + glPopAttrib (); } void UnityScreen::paintDisplay (const CompRegion ®ion) { - nuxPrologue (); - wt->RenderInterfaceFromForeignCmd (); - nuxEpilogue (); + nuxPrologue (); + wt->RenderInterfaceFromForeignCmd (); + nuxEpilogue (); - doShellRepaint = false; + doShellRepaint = false; } /* called whenever we need to repaint parts of the screen */ @@ -103,18 +105,18 @@ UnityScreen::glPaintOutput (const GLScreenPaintAttrib &attrib, CompOutput *output, unsigned int mask) { - bool ret; + bool ret; - doShellRepaint = true; - allowWindowPaint = true; + doShellRepaint = true; + allowWindowPaint = true; - /* glPaintOutput is part of the opengl plugin, so we need the GLScreen base class. */ - ret = gScreen->glPaintOutput (attrib, transform, region, output, mask); + /* glPaintOutput is part of the opengl plugin, so we need the GLScreen base class. */ + ret = gScreen->glPaintOutput (attrib, transform, region, output, mask); - if (doShellRepaint) - paintDisplay (region); + if (doShellRepaint) + paintDisplay (region); - return ret; + return ret; } /* called whenever a plugin needs to paint the entire scene @@ -127,96 +129,96 @@ UnityScreen::glPaintTransformedOutput (const GLScreenPaintAttrib &attrib, CompOutput *output, unsigned int mask) { - allowWindowPaint = false; - gScreen->glPaintOutput (attrib, transform, region, output, mask); + allowWindowPaint = false; + gScreen->glPaintOutput (attrib, transform, region, output, mask); } /* Grab changed nux regions and add damage rects for them */ void UnityScreen::damageNuxRegions () { - CompRegion region; - std::vector<nux::Geometry>::iterator it; - std::vector<nux::Geometry> dirty = wt->GetDrawList (); - nux::Geometry geo; - - for (it = dirty.begin (); it != dirty.end (); it++) - { - geo = *it; - cScreen->damageRegion (CompRegion (geo.x, geo.y, geo.width, geo.height)); - } - - geo = wt->GetWindowCompositor ().GetTooltipMainWindowGeometry(); + CompRegion region; + std::vector<nux::Geometry>::iterator it; + std::vector<nux::Geometry> dirty = wt->GetDrawList (); + nux::Geometry geo; + + for (it = dirty.begin (); it != dirty.end (); it++) + { + geo = *it; cScreen->damageRegion (CompRegion (geo.x, geo.y, geo.width, geo.height)); - cScreen->damageRegion (CompRegion (lastTooltipArea.x, lastTooltipArea.y, lastTooltipArea.width, lastTooltipArea.height)); - - lastTooltipArea = geo; - - wt->ClearDrawList (); + } + + geo = wt->GetWindowCompositor ().GetTooltipMainWindowGeometry(); + cScreen->damageRegion (CompRegion (geo.x, geo.y, geo.width, geo.height)); + cScreen->damageRegion (CompRegion (lastTooltipArea.x, lastTooltipArea.y, lastTooltipArea.width, lastTooltipArea.height)); + + lastTooltipArea = geo; + + wt->ClearDrawList (); } /* handle X Events */ void UnityScreen::handleEvent (XEvent *event) { - screen->handleEvent (event); + screen->handleEvent (event); - if (screen->otherGrabExist ("deco", "move", NULL)) - { - wt->ProcessForeignEvent (event, NULL); - } -} + if (screen->otherGrabExist ("deco", "move", NULL)) + { + wt->ProcessForeignEvent (event, NULL); + } +} gboolean UnityScreen::initPluginActions (gpointer data) { - CompPlugin *p; + CompPlugin *p; - p = CompPlugin::find ("expo"); + p = CompPlugin::find ("expo"); - if (p) + if (p) + { + foreach (CompOption &option, p->vTable->getOptions ()) { - foreach (CompOption &option, p->vTable->getOptions ()) - { - if (option.name () == "expo_key") - { - CompAction *action = &option.value ().action (); - PluginAdapter::Default ()->SetExpoAction (action); - break; - } - } + if (option.name () == "expo_key") + { + CompAction *action = &option.value ().action (); + PluginAdapter::Default ()->SetExpoAction (action); + break; + } } + } - p = CompPlugin::find ("scale"); + p = CompPlugin::find ("scale"); - if (p) + if (p) + { + foreach (CompOption &option, p->vTable->getOptions ()) { - foreach (CompOption &option, p->vTable->getOptions ()) - { - if (option.name () == "initiate_all_key") - { - CompAction *action = &option.value ().action (); - PluginAdapter::Default ()->SetScaleAction (action); - break; - } - } + if (option.name () == "initiate_all_key") + { + CompAction *action = &option.value ().action (); + PluginAdapter::Default ()->SetScaleAction (action); + break; + } } + } - return FALSE; + return FALSE; } /* Set up expo and scale actions on the launcher */ bool UnityScreen::initPluginForScreen (CompPlugin *p) { - if (p->vTable->name () == "expo" || - p->vTable->name () == "scale") - { - initPluginActions ((void *) this); - } + if (p->vTable->name () == "expo" || + p->vTable->name () == "scale") + { + initPluginActions ((void *) this); + } - return screen->initPluginForScreen (p); + return screen->initPluginForScreen (p); } void @@ -227,23 +229,28 @@ UnityScreen::AddProperties (GVariantBuilder *builder) const gchar* UnityScreen::GetName () { - return "Unity"; + return "Unity"; } -bool -UnityWindow::glPaint (const GLWindowPaintAttrib &attrib, const GLMatrix &matrix, - const CompRegion ®ion, unsigned int mask) +const CompWindowList & +UnityScreen::getWindowPaintList () { + CompWindowList &pl = _withRemovedNuxWindows = cScreen->getWindowPaintList (); + CompWindowList::iterator it = pl.end (); const std::list <Window> &xwns = nux::XInputWindow::NativeHandleList (); - GLWindowPaintAttrib new_tribs (attrib); - if (std::find (xwns.begin (), xwns.end (), window->id ()) != xwns.end ()) + while (it != pl.begin ()) { - new_tribs.opacity = 0; - } + it--; + if (std::find (xwns.begin (), xwns.end (), (*it)->id ()) != xwns.end ()) + { + CompWindowList::iterator pit = it; + pl.erase (pit); + } + } - return gWindow->glPaint (new_tribs, matrix, region, mask); + return pl; } /* handle window painting in an opengl context @@ -253,66 +260,110 @@ UnityWindow::glPaint (const GLWindowPaintAttrib &attrib, const GLMatrix &matrix, * stacked on top of one of the nux input windows * and if so paint nux and stop us from painting * other windows or on top of the whole screen */ -bool +bool UnityWindow::glDraw (const GLMatrix &matrix, GLFragment::Attrib &attrib, const CompRegion ®ion, unsigned int mask) { - if (uScreen->doShellRepaint && uScreen->allowWindowPaint) + if (uScreen->doShellRepaint && uScreen->allowWindowPaint) + { + const std::list <Window> &xwns = nux::XInputWindow::NativeHandleList (); + + for (CompWindow *w = window; w && uScreen->doShellRepaint; w = w->prev) { - const std::list <Window> &xwns = nux::XInputWindow::NativeHandleList (); - - for (CompWindow *w = window; w && uScreen->doShellRepaint; w = w->prev) - { - if (std::find (xwns.begin (), xwns.end (), w->id ()) != xwns.end ()) - { - uScreen->paintDisplay (region); - } - } + if (std::find (xwns.begin (), xwns.end (), w->id ()) != xwns.end ()) + { + uScreen->paintDisplay (region); + } } + } + + bool ret = gWindow->glDraw (matrix, attrib, region, mask); - bool ret = gWindow->glDraw (matrix, attrib, region, mask); - - return ret; + return ret; } /* Called whenever a window is mapped, unmapped, minimized etc */ void UnityWindow::windowNotify (CompWindowNotify n) { - if (n == CompWindowNotifyMinimize) - uScreen->controller->PresentIconOwningWindow (window->id ()); + switch (n) + { + case CompWindowNotifyMinimize: + uScreen->controller->PresentIconOwningWindow (window->id ()); + uScreen->launcher->OnWindowDisappear (window); + break; + case CompWindowNotifyUnminimize: + uScreen->launcher->OnWindowAppear (window); + break; + case CompWindowNotifyShade: + uScreen->launcher->OnWindowDisappear (window); + break; + case CompWindowNotifyUnshade: + uScreen->launcher->OnWindowAppear (window); + break; + case CompWindowNotifyHide: + uScreen->launcher->OnWindowDisappear (window); + break; + case CompWindowNotifyShow: + uScreen->launcher->OnWindowAppear (window); + break; + case CompWindowNotifyMap: + uScreen->launcher->OnWindowAppear (window); + break; + case CompWindowNotifyUnmap: + uScreen->launcher->OnWindowDisappear (window); + break; + default: + break; + } - window->windowNotify (n); + window->windowNotify (n); +} + +void +UnityWindow::moveNotify (int x, int y, bool immediate) +{ + uScreen->launcher->OnWindowMoved (window); + window->moveNotify (x, y, immediate); +} + +void +UnityWindow::resizeNotify (int x, int y, int w, int h) +{ + uScreen->launcher->OnWindowResized (window); + window->resizeNotify (x, y, w, h); } /* Configure callback for the launcher window */ -void +void UnityScreen::launcherWindowConfigureCallback(int WindowWidth, int WindowHeight, nux::Geometry& geo, void *user_data) { - int OurWindowHeight = WindowHeight - 24; - geo = nux::Geometry(0, 24, geo.width, OurWindowHeight); + int OurWindowHeight = WindowHeight - 24; + geo = nux::Geometry(0, 24, geo.width, OurWindowHeight); } /* Configure callback for the panel window */ -void +void UnityScreen::panelWindowConfigureCallback(int WindowWidth, int WindowHeight, nux::Geometry& geo, void *user_data) { - geo = nux::Geometry(0, 0, WindowWidth, 24); + geo = nux::Geometry(0, 0, WindowWidth, 24); } /* Start up nux after OpenGL is initialized */ -void +void UnityScreen::initUnity(nux::NThread* thread, void* InitData) { - initLauncher(thread, InitData); - - nux::ColorLayer background(nux::Color(0x00000000)); - static_cast<nux::WindowThread*>(thread)->SetWindowBackgroundPaintLayer(&background); + START_FUNCTION (); + initLauncher(thread, InitData); + + nux::ColorLayer background(nux::Color(0x00000000)); + static_cast<nux::WindowThread*>(thread)->SetWindowBackgroundPaintLayer(&background); + END_FUNCTION (); } -void +void UnityScreen::onRedrawRequested () { damageNuxRegions (); @@ -323,18 +374,25 @@ void UnityScreen::optionChanged (CompOption *opt, UnityshellOptions::Options num) { - switch (num) - { - case UnityshellOptions::LauncherAutohide: - launcher->SetAutohide (optionGetLauncherAutohide (), - (nux::View *) panelView->HomeButton ()); - break; - case UnityshellOptions::LauncherFloat: - launcher->SetFloating (optionGetLauncherFloat ()); - break; - default: - break; - } + switch (num) + { + case UnityshellOptions::LauncherAutohide: + launcher->SetAutohide (optionGetLauncherAutohide (), + (nux::View *) panelView->HomeButton ()); + break; + case UnityshellOptions::LauncherFloat: + launcher->SetFloating (optionGetLauncherFloat ()); + break; + default: + break; + } +} + +static gboolean +write_logger_data_to_disk (gpointer data) +{ + perf_timeline_logger_write_log (perf_timeline_logger_get_default (), "/tmp/unity-perf.log"); + return FALSE; } UnityScreen::UnityScreen (CompScreen *screen) : @@ -344,40 +402,43 @@ UnityScreen::UnityScreen (CompScreen *screen) : gScreen (GLScreen::get (screen)), doShellRepaint (false) { - int (*old_handler) (Display *, XErrorEvent *); - old_handler = XSetErrorHandler (NULL); - - g_thread_init (NULL); - dbus_g_thread_init (); - gtk_init (NULL, NULL); - - XSetErrorHandler (old_handler); - - /* Wrap compiz interfaces */ - ScreenInterface::setHandler (screen); - GLScreenInterface::setHandler (gScreen); - - StartupNotifyService::Default ()->SetSnDisplay (screen->snDisplay (), screen->screenNum ()); - - nux::NuxInitialize (0); - wt = nux::CreateFromForeignWindow (cScreen->output (), - glXGetCurrentContext (), - &UnityScreen::initUnity, - this); - - wt->RedrawRequested.connect (sigc::mem_fun (this, &UnityScreen::onRedrawRequested)); - - wt->Run (NULL); - uScreen = this; - - debugger = new IntrospectionDBusInterface (this); - - PluginAdapter::Initialize (screen); - - optionSetLauncherAutohideNotify (boost::bind (&UnityScreen::optionChanged, this, _1, _2)); - optionSetLauncherFloatNotify (boost::bind (&UnityScreen::optionChanged, this, _1, _2)); - - g_timeout_add (0, &UnityScreen::initPluginActions, this); + START_FUNCTION (); + int (*old_handler) (Display *, XErrorEvent *); + old_handler = XSetErrorHandler (NULL); + + g_thread_init (NULL); + dbus_g_thread_init (); + gtk_init (NULL, NULL); + + XSetErrorHandler (old_handler); + + /* Wrap compiz interfaces */ + ScreenInterface::setHandler (screen); + CompositeScreenInterface::setHandler (cScreen); + GLScreenInterface::setHandler (gScreen); + + StartupNotifyService::Default ()->SetSnDisplay (screen->snDisplay (), screen->screenNum ()); + + nux::NuxInitialize (0); + wt = nux::CreateFromForeignWindow (cScreen->output (), + glXGetCurrentContext (), + &UnityScreen::initUnity, + this); + + wt->RedrawRequested.connect (sigc::mem_fun (this, &UnityScreen::onRedrawRequested)); + + wt->Run (NULL); + uScreen = this; + + debugger = new IntrospectionDBusInterface (this); + + PluginAdapter::Initialize (screen); + + optionSetLauncherAutohideNotify (boost::bind (&UnityScreen::optionChanged, this, _1, _2)); + optionSetLauncherFloatNotify (boost::bind (&UnityScreen::optionChanged, this, _1, _2)); + + g_timeout_add (0, &UnityScreen::initPluginActions, this); + END_FUNCTION (); } UnityScreen::~UnityScreen () @@ -387,27 +448,30 @@ UnityScreen::~UnityScreen () /* Can't create windows until after we have initialized everything */ gboolean UnityScreen::strutHackTimeout (gpointer data) { - UnityScreen *self = (UnityScreen*) data; - - if (!self->launcher->AutohideEnabled ()) - { - self->launcherWindow->InputWindowEnableStruts(false); - self->launcherWindow->InputWindowEnableStruts(true); - } - - self->panelWindow->InputWindowEnableStruts(false); - self->panelWindow->InputWindowEnableStruts(true); - - return FALSE; + UnityScreen *self = (UnityScreen*) data; + + if (!self->launcher->AutohideEnabled ()) + { + self->launcherWindow->InputWindowEnableStruts(false); + self->launcherWindow->InputWindowEnableStruts(true); + } + + self->panelWindow->InputWindowEnableStruts(false); + self->panelWindow->InputWindowEnableStruts(true); + + return FALSE; } /* Start up the launcher */ void UnityScreen::initLauncher (nux::NThread* thread, void* InitData) { + START_FUNCTION (); + UnityScreen *self = (UnityScreen*) InitData; - + + LOGGER_START_PROCESS ("initLauncher-Launcher"); self->launcherWindow = new nux::BaseWindow(TEXT("")); - self->launcher = new Launcher(self->launcherWindow); + self->launcher = new Launcher(self->launcherWindow, self->screen); self->AddChild (self->launcher); nux::HLayout* layout = new nux::HLayout(); @@ -428,8 +492,10 @@ void UnityScreen::initLauncher (nux::NThread* thread, void* InitData) self->launcherWindow->InputWindowEnableStruts(true); self->launcher->SetIconSize (54, 48); + LOGGER_END_PROCESS ("initLauncher-Launcher"); /* Setup panel */ + LOGGER_START_PROCESS ("initLauncher-Panel"); self->panelView = new PanelView (); self->AddChild (self->panelView); @@ -448,10 +514,12 @@ void UnityScreen::initLauncher (nux::NThread* thread, void* InitData) self->panelWindow->SetBackgroundColor(nux::Color(0x00000000)); self->panelWindow->SetBlurredBackground(false); self->panelWindow->ShowWindow(true); - self->panelWindow->EnableInputWindow(true); + self->panelWindow->EnableInputWindow(true); self->panelWindow->InputWindowEnableStruts(true); - + LOGGER_END_PROCESS ("initLauncher-Panel"); g_timeout_add (2000, &UnityScreen::strutHackTimeout, self); + + END_FUNCTION (); } /* Window init */ @@ -460,8 +528,8 @@ UnityWindow::UnityWindow (CompWindow *window) : window (window), gWindow (GLWindow::get (window)) { - WindowInterface::setHandler (window); - GLWindowInterface::setHandler (gWindow); + WindowInterface::setHandler (window); + GLWindowInterface::setHandler (gWindow); } UnityWindow::~UnityWindow () @@ -472,13 +540,13 @@ UnityWindow::~UnityWindow () bool UnityPluginVTable::init () { - if (!CompPlugin::checkPluginABI ("core", CORE_ABIVERSION)) - return false; - if (!CompPlugin::checkPluginABI ("composite", COMPIZ_COMPOSITE_ABI)) - return false; - if (!CompPlugin::checkPluginABI ("opengl", COMPIZ_OPENGL_ABI)) - return false; - - return true; + if (!CompPlugin::checkPluginABI ("core", CORE_ABIVERSION)) + return false; + if (!CompPlugin::checkPluginABI ("composite", COMPIZ_COMPOSITE_ABI)) + return false; + if (!CompPlugin::checkPluginABI ("opengl", COMPIZ_OPENGL_ABI)) + return false; + + return true; } diff --git a/src/unity.h b/src/unity.h index 25bf84e87..cec421f57 100644 --- a/src/unity.h +++ b/src/unity.h @@ -84,6 +84,9 @@ class UnityScreen : CompOutput *, unsigned int); + /* Pop our InputOutput windows from the paint list */ + const CompWindowList & getWindowPaintList (); + /* handle X11 events */ void handleEvent (XEvent *); @@ -137,7 +140,9 @@ class UnityScreen : /* handle paint order */ bool doShellRepaint; - bool allowWindowPaint; + bool allowWindowPaint; + bool damaged; + CompWindowList _withRemovedNuxWindows; friend class UnityWindow; }; @@ -157,10 +162,6 @@ class UnityWindow : CompWindow *window; GLWindow *gWindow; - bool - glPaint (const GLWindowPaintAttrib &, const GLMatrix &, - const CompRegion &, unsigned int); - /* basic window draw function */ bool glDraw (const GLMatrix &matrix, @@ -170,6 +171,9 @@ class UnityWindow : void windowNotify (CompWindowNotify n); + void moveNotify (int x, int y, bool immediate); + + void resizeNotify (int x, int y, int w, int h); }; #define EX_SCREEN (screen) \ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 412b208ad..6f55fe1df 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -45,6 +45,7 @@ add_executable (test-unit ../src/FavoriteStore.h ../src/FavoriteStoreGSettings.cpp ../src/FavoriteStoreGSettings.h + ../src/Introspectable.cpp ../src/QuicklistMenuItem.cpp ../src/QuicklistMenuItem.h ../src/QuicklistMenuItemCheckmark.cpp @@ -76,10 +77,32 @@ add_executable (test-panel ../src/IndicatorObjectProxyRemote.h ../src/IndicatorObjectEntryProxyRemote.cpp ../src/IndicatorObjectEntryProxyRemote.h + ../src/Introspectable.cpp + ../src/Introspectable.h ../src/PanelHomeButton.cpp ../src/PanelHomeButton.h ) +add_executable (test-quicklist + ui/TestQuicklist.cpp + ui/EventFaker.cpp + ui/EventFaker.h + ../src/Introspectable.cpp + ../src/Introspectable.h + ../src/QuicklistMenuItem.cpp + ../src/QuicklistMenuItem.h + ../src/QuicklistMenuItemCheckmark.cpp + ../src/QuicklistMenuItemCheckmark.h + ../src/QuicklistMenuItemLabel.cpp + ../src/QuicklistMenuItemLabel.h + ../src/QuicklistMenuItemRadio.cpp + ../src/QuicklistMenuItemRadio.h + ../src/QuicklistMenuItemSeparator.cpp + ../src/QuicklistMenuItemSeparator.h + ../src/QuicklistView.cpp + ../src/QuicklistView.h + ) + # # check target # diff --git a/tests/ui/EventFaker.cpp b/tests/ui/EventFaker.cpp new file mode 100644 index 000000000..dca74a362 --- /dev/null +++ b/tests/ui/EventFaker.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2010 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 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, see <http://www.gnu.org/licenses/>. + * + * Authored by: Mirco Müller <mirco.mueller@canonical.com> + */ + +#include "EventFaker.h" + +#include "NuxGraphics/GLWindowManager.h" +#include <X11/Xlib.h> + +EventFaker::EventFaker (nux::WindowThread* thread) +{ + _thread = thread; +} + +EventFaker::~EventFaker () +{ +} + +void +EventFaker::SendClick (nux::View* view) +{ + Display* display = NULL; + int x = 0; + int y = 0; + + // sanity check + if (!view) + return; + + display = nux::GetThreadGLWindow()->GetX11Display (); + + // get a point inside the view + x = view->GetBaseX () + 1; + y = view->GetBaseY () + 1; + + // assemble a button-click event + XButtonEvent buttonEvent = { + ButtonRelease, + 0, + False, + display, + 0, + 0, + 0, + CurrentTime, + x, y, + x, y, + 0, + Button1, + True + }; + + // send that button-click to the "thread" + doEvent (view, (XEvent*) &buttonEvent); +} + +void +EventFaker::doEvent (nux::View* view, + XEvent* event) +{ + Display* display = NULL; + + // sanity check + if (!view || !event) + return; + + display = nux::GetThreadGLWindow()->GetX11Display (); + XUngrabPointer (display, CurrentTime); + XFlush (display); + + _thread->ProcessForeignEvent (event, NULL); + + while (g_main_context_pending (NULL)) + g_main_context_iteration (NULL, false); +} diff --git a/tests/ui/EventFaker.h b/tests/ui/EventFaker.h new file mode 100644 index 000000000..26eef4917 --- /dev/null +++ b/tests/ui/EventFaker.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2010 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 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, see <http://www.gnu.org/licenses/>. + * + * Authored by: Mirco Müller <mirco.mueller@canonical.com> + */ + +#ifndef EVENT_FAKER_H +#define EVENT_FAKER_H + +#include "Nux/Nux.h" +#include "Nux/WindowThread.h" + +class EventFaker +{ + public: + EventFaker (nux::WindowThread* thread); + ~EventFaker (); + + void SendClick (nux::View* view); + + void doEvent (nux::View* view, + XEvent* event); + + private: + nux::WindowThread* _thread; +}; + +#endif // EVENT_FAKER_H diff --git a/tests/ui/TestQuicklist.cpp b/tests/ui/TestQuicklist.cpp new file mode 100644 index 000000000..bcf08a6be --- /dev/null +++ b/tests/ui/TestQuicklist.cpp @@ -0,0 +1,305 @@ +/* + * Copyright (C) 2010 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 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, see <http://www.gnu.org/licenses/>. + * + * Authored by: Mirco Müller <mirco.mueller@canonical.com> + */ + +#include <glib.h> +#include <gtk/gtk.h> +#include <dbus/dbus-glib.h> + +#include "Nux/Nux.h" +#include "Nux/VLayout.h" +#include "Nux/WindowThread.h" + +#include "QuicklistView.h" +#include "QuicklistMenuItem.h" +#include "QuicklistMenuItemLabel.h" +#include "QuicklistMenuItemSeparator.h" +#include "QuicklistMenuItemCheckmark.h" +#include "QuicklistMenuItemRadio.h" + +#include "EventFaker.h" +#include <X11/Xlib.h> + +#define WIN_WIDTH 400 +#define WIN_HEIGHT 300 + +gboolean gResult[3] = {false, false, false}; + +QuicklistView* gQuicklist = NULL; +QuicklistMenuItemCheckmark* gCheckmark = NULL; +QuicklistMenuItemRadio* gRadio = NULL; +QuicklistMenuItemLabel* gLabel = NULL; + +void +activatedCallback (DbusmenuMenuitem* item, + int time, + gpointer data) +{ + gboolean* result = (gboolean*) data; + + *result = true; + + g_print ("Quicklist-item activated\n"); +} + +QuicklistMenuItemCheckmark* +createCheckmarkItem () +{ + DbusmenuMenuitem* item = NULL; + QuicklistMenuItemCheckmark* checkmark = NULL; + + item = dbusmenu_menuitem_new (); + + dbusmenu_menuitem_property_set (item, + DBUSMENU_MENUITEM_PROP_LABEL, + "Unchecked"); + + dbusmenu_menuitem_property_set (item, + DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE, + DBUSMENU_MENUITEM_TOGGLE_CHECK); + + dbusmenu_menuitem_property_set_bool (item, + DBUSMENU_MENUITEM_PROP_ENABLED, + true); + + dbusmenu_menuitem_property_set_int (item, + DBUSMENU_MENUITEM_PROP_TOGGLE_STATE, + DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED); + + checkmark = new QuicklistMenuItemCheckmark (item, true); + + g_signal_connect (item, + DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, + G_CALLBACK (activatedCallback), + &gResult[0]); + + return checkmark; +} + +QuicklistMenuItemRadio* +createRadioItem () +{ + DbusmenuMenuitem* item = NULL; + QuicklistMenuItemRadio* radio = NULL; + + item = dbusmenu_menuitem_new (); + + dbusmenu_menuitem_property_set (item, + DBUSMENU_MENUITEM_PROP_LABEL, + "Radio Active"); + + dbusmenu_menuitem_property_set (item, + DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE, + DBUSMENU_MENUITEM_TOGGLE_RADIO); + + dbusmenu_menuitem_property_set_bool (item, + DBUSMENU_MENUITEM_PROP_ENABLED, + true); + + dbusmenu_menuitem_property_set_int (item, + DBUSMENU_MENUITEM_PROP_TOGGLE_STATE, + DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED); + + radio = new QuicklistMenuItemRadio (item, true); + + g_signal_connect (item, + DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, + G_CALLBACK (activatedCallback), + &gResult[1]); + + return radio; +} + +QuicklistMenuItemLabel* +createLabelItem () +{ + DbusmenuMenuitem* item = NULL; + QuicklistMenuItemLabel* label = NULL; + + item = dbusmenu_menuitem_new (); + + dbusmenu_menuitem_property_set (item, + DBUSMENU_MENUITEM_PROP_LABEL, + "A Label"); + + dbusmenu_menuitem_property_set_bool (item, + DBUSMENU_MENUITEM_PROP_ENABLED, + true); + + label = new QuicklistMenuItemLabel (item, true); + + g_signal_connect (item, + DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, + G_CALLBACK (activatedCallback), + &gResult[2]); + + return label; +} + +void +ThreadWidgetInit (nux::NThread* thread, + void* initData) +{ + gQuicklist = new QuicklistView (); + gQuicklist->Reference (); + + gCheckmark = createCheckmarkItem (); + gQuicklist->AddMenuItem (gCheckmark); + gRadio = createRadioItem (); + gQuicklist->AddMenuItem (gRadio); + gLabel = createLabelItem (); + gQuicklist->AddMenuItem (gLabel); + + gQuicklist->EnableQuicklistForTesting (true); + + gQuicklist->SetBaseXY (0, 0); + gQuicklist->ShowWindow (true); +} + +void +ControlThread (nux::NThread* thread, + void* data) +{ + // sleep for 3 seconds + nux::SleepForMilliseconds (3000); + printf ("ControlThread successfully started\n"); + + nux::WindowThread* mainWindowThread = NUX_STATIC_CAST (nux::WindowThread*, + data); + + mainWindowThread->SetFakeEventMode (true); + Display* display = mainWindowThread->GetWindow ().GetX11Display (); + + // assemble first button-click event + XEvent buttonPressEvent; + buttonPressEvent.xbutton.type = ButtonPress; + buttonPressEvent.xbutton.serial = 0; + buttonPressEvent.xbutton.send_event = False; + buttonPressEvent.xbutton.display = display; + buttonPressEvent.xbutton.window = 0; + buttonPressEvent.xbutton.root = 0; + buttonPressEvent.xbutton.subwindow = 0; + buttonPressEvent.xbutton.time = CurrentTime; + buttonPressEvent.xbutton.x = 50; + buttonPressEvent.xbutton.y = 30; + buttonPressEvent.xbutton.x_root = 0; + buttonPressEvent.xbutton.y_root = 0; + buttonPressEvent.xbutton.state = 0; + buttonPressEvent.xbutton.button = Button1; + buttonPressEvent.xbutton.same_screen = True; + + mainWindowThread->PumpFakeEventIntoPipe (mainWindowThread, + (XEvent*) &buttonPressEvent); + + while (!mainWindowThread->ReadyForNextFakeEvent ()) + nux::SleepForMilliseconds (10); + + XEvent buttonReleaseEvent; + buttonReleaseEvent.xbutton.type = ButtonRelease; + buttonReleaseEvent.xbutton.serial = 0; + buttonReleaseEvent.xbutton.send_event = False; + buttonReleaseEvent.xbutton.display = display; + buttonReleaseEvent.xbutton.window = 0; + buttonReleaseEvent.xbutton.root = 0; + buttonReleaseEvent.xbutton.subwindow = 0; + buttonReleaseEvent.xbutton.time = CurrentTime; + buttonReleaseEvent.xbutton.x = 50; + buttonReleaseEvent.xbutton.y = 30; + buttonReleaseEvent.xbutton.x_root = 0; + buttonReleaseEvent.xbutton.y_root = 0; + buttonReleaseEvent.xbutton.state = 0; + buttonReleaseEvent.xbutton.button = Button1; + buttonReleaseEvent.xbutton.same_screen = True; + + mainWindowThread->PumpFakeEventIntoPipe (mainWindowThread, + (XEvent*) &buttonReleaseEvent); + + while (!mainWindowThread->ReadyForNextFakeEvent ()) + nux::SleepForMilliseconds (10); + + // assemble second button-click event + buttonPressEvent.xbutton.time = CurrentTime; + buttonPressEvent.xbutton.x = 50; + buttonPressEvent.xbutton.y = 50; + mainWindowThread->PumpFakeEventIntoPipe (mainWindowThread, + (XEvent*) &buttonPressEvent); + while (!mainWindowThread->ReadyForNextFakeEvent ()) + nux::SleepForMilliseconds (10); + + buttonReleaseEvent.xbutton.time = CurrentTime; + buttonReleaseEvent.xbutton.x = 50; + buttonReleaseEvent.xbutton.y = 50; + mainWindowThread->PumpFakeEventIntoPipe (mainWindowThread, + (XEvent*) &buttonReleaseEvent); + while (!mainWindowThread->ReadyForNextFakeEvent ()) + nux::SleepForMilliseconds (10); + + // assemble third button-click event + buttonPressEvent.xbutton.time = CurrentTime; + buttonPressEvent.xbutton.x = 50; + buttonPressEvent.xbutton.y = 70; + mainWindowThread->PumpFakeEventIntoPipe (mainWindowThread, + (XEvent*) &buttonPressEvent); + while (!mainWindowThread->ReadyForNextFakeEvent ()) + nux::SleepForMilliseconds (10); + + buttonReleaseEvent.xbutton.time = CurrentTime; + buttonReleaseEvent.xbutton.x = 50; + buttonReleaseEvent.xbutton.y = 70; + mainWindowThread->PumpFakeEventIntoPipe (mainWindowThread, + (XEvent*) &buttonReleaseEvent); + while (!mainWindowThread->ReadyForNextFakeEvent ()) + nux::SleepForMilliseconds (10); + + mainWindowThread->SetFakeEventMode (false); +} + +int +main (int argc, char **argv) +{ + nux::WindowThread* wt = NULL; + nux::SystemThread* st = NULL; + + g_type_init (); + g_thread_init (NULL); + gtk_init (&argc, &argv); + dbus_g_thread_init (); + nux::NuxInitialize (0); + + wt = nux::CreateGUIThread (TEXT ("Unity Quicklist"), + WIN_WIDTH, + WIN_HEIGHT, + 0, + &ThreadWidgetInit, + NULL); + + st = nux::CreateSystemThread (NULL, ControlThread, wt); + if (st) + st->Start (NULL); + + wt->Run (NULL); + + gQuicklist->UnReference (); + delete st; + delete wt; + + g_assert_cmpint (gResult[0], ==, true); + g_assert_cmpint (gResult[1], ==, true); + g_assert_cmpint (gResult[2], ==, true); + + return 0; +} diff --git a/tests/unit/TestPanelService.cpp b/tests/unit/TestPanelService.cpp index 7136d4056..55206bae6 100644 --- a/tests/unit/TestPanelService.cpp +++ b/tests/unit/TestPanelService.cpp @@ -157,6 +157,14 @@ test_object_add_entry (TestObject *self, return entry; } +void +test_object_show_entry (TestObject *self, + IndicatorObjectEntry *entry, + guint timestamp) +{ + g_signal_emit (self, INDICATOR_OBJECT_SIGNAL_MENU_SHOW_ID, 0, entry, timestamp); +} + //----------------------- /TESTING INDICATOR STUFF ---------------------------- //------------------------ USEFUL FUNCTIONS ----------------------------------- @@ -243,6 +251,7 @@ static void TestAllocation (void); static void TestIndicatorLoading (void); static void TestEmptyIndicatorObject (void); static void TestEntryAddition (void); +static void TestEntryActivateRequest (void); void TestPanelServiceCreateSuite () @@ -253,6 +262,7 @@ TestPanelServiceCreateSuite () g_test_add_func (_DOMAIN"/IndicatorLoading", TestIndicatorLoading); g_test_add_func (_DOMAIN"/EmptyIndicatorObject", TestEmptyIndicatorObject); g_test_add_func (_DOMAIN"/EntryAddition", TestEntryAddition); + g_test_add_func (_DOMAIN"/EntryActivateRequest", TestEntryActivateRequest); } static void @@ -351,3 +361,41 @@ TestEntryAddition () g_object_unref (object); g_object_unref (service); } + +static void +OnEntryActivateRequest (IndicatorObject *object, + const gchar *entry_id, + const gchar *entry_id_should_be) +{ + g_assert_cmpstr (entry_id, ==, entry_id_should_be); +} + +static void +TestEntryActivateRequest () +{ + PanelService *service; + TestObject *object; + GList *objects = NULL; + IndicatorObjectEntry *entry; + gchar *id; + + object = (TestObject *)test_object_new (); + entry = test_object_add_entry (object, "Hello", "gtk-apply"); + id = g_strdup_printf ("%p", entry); + g_assert (INDICATOR_IS_OBJECT (object)); + objects = g_list_append (objects, object); + + service = panel_service_get_default_with_indicators (objects); + g_assert (PANEL_IS_SERVICE (service)); + + g_signal_connect (service, "entry-activate-request", + G_CALLBACK (OnEntryActivateRequest), + id); + + test_object_show_entry (object, entry, 1234); + + g_free (id); + g_list_free (objects); + g_object_unref (object); + g_object_unref (service); +} diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index cec32fdb0..523e56f65 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -1,5 +1,9 @@ # # Some unity tools # -install(FILES migrate_favorites.py PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/unity/) +install(FILES makebootchart.py migrate_favorites.py PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/unity/) + +configure_file (${CMAKE_CURRENT_SOURCE_DIR}/unity.cmake ${CMAKE_BINARY_DIR}/bin/unity) +install(FILES ${CMAKE_BINARY_DIR}/bin/unity PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ +GROUP_EXECUTE WORLD_READ WORLD_EXECUTE DESTINATION bin) diff --git a/tools/makebootchart.py b/tools/makebootchart.py index 8ec9bf2a6..891549470 100755 --- a/tools/makebootchart.py +++ b/tools/makebootchart.py @@ -24,8 +24,8 @@ import csv import math import random from string import Template -from socket import gethostname -from datetime import datetime +from socket import gethostname +from datetime import datetime import re import subprocess @@ -39,22 +39,22 @@ def sort_by_domain (x, y): if x["start"] - y["start"] < 0: return -1 else: - return +1 - + return +1 + def gatherinfo (filename): date = datetime.fromtimestamp(os.path.getmtime(filename)) - + cpufile = open ("/proc/cpuinfo") cpuinfo = cpufile.read (10024) cpure = re.search (r"^model name\s*: (.*$)", cpuinfo, re.MULTILINE) cpu = cpure.group(1) - + gpu_prog = subprocess.Popen("glxinfo", stdout=subprocess.PIPE) - gpu_prog.wait () + gpu_prog.wait () gpuinfo = gpu_prog.stdout.read (10024) gpure = re.search (r"^OpenGL renderer string: (.*$)", gpuinfo, re.MULTILINE) gpu = gpure.group (1) - + return {"hostname":gethostname(), "date": date.strftime("%A, %d. %B %Y %I:%M%p"), "uname": " ".join (os.uname ()), @@ -67,14 +67,14 @@ width_multiplier = 1000 bar_height = 16 def draw_bg_graph (ctx, seconds, height): - + total_width = seconds * width_multiplier ctx.set_source_rgba (0.0, 0.0, 0.0, 0.25) - + ctx.move_to (0, 0) ctx.line_to (total_width, 0) ctx.stroke () - + per_ten = 0 for pos in xrange (0, int(total_width), int (0.01 * width_multiplier)): ctx.set_line_width (1) @@ -90,67 +90,67 @@ def draw_bg_graph (ctx, seconds, height): ctx.move_to (pos, 0) ctx.line_to (pos, height) ctx.stroke () - + per_ten += 1 per_ten %= 10 def build_graph (data, filename, info): - + padding_left = 6 padding_right = 100 padding_top = 6 padding_bottom = 6 - + total_size = 0.0 for item in data: if item['end'] > total_size: total_size = item['end'] - + width = total_size * width_multiplier + padding_left + padding_right height = (len(data) * (bar_height)) + 80 + padding_bottom + padding_top - surface = cairo.SVGSurface(filename, width, height) - + surface = cairo.SVGSurface(filename, max (width, 800), max (height, 600)) + ctx = cairo.Context (surface) #fill background ctx.set_source_rgb (1, 1, 1) - ctx.rectangle (0, 0, width, height) + ctx.rectangle (0, 0, max (width, 800), max (height, 600)) ctx.fill () - + #print header info['total_time'] = "%s secs" % total_size sheader = header.substitute(info) - + ctx.translate (padding_left, padding_top) ctx.set_source_rgb (0, 0, 0) for line in sheader.split("\n"): ctx.translate (0, 12) ctx.show_text (line) ctx.fill () - - ctx.translate (0, 12) - - draw_bg_graph (ctx, total_size, len (data) * bar_height + 16) - + + ctx.translate (6, 12) + + draw_bg_graph (ctx, total_size + 0.5, max (len (data) * bar_height + 64, 500)) + ctx.set_line_width (1) for item in data: x = item['start'] * width_multiplier x1 = (item['end'] - item['start']) * width_multiplier ctx.translate (x, 0) - + ctx.set_source_rgba (0.35, 0.65, 0.8, 0.5) ctx.rectangle (0, 0, x1, 16) ctx.fill () - + ctx.set_source_rgba (0.35, 0.65, 0.8, 1.0) ctx.rectangle (0, 0, x1, 16) ctx.stroke () - + ctx.translate (8, 10) ctx.set_source_rgb (0.0, 0.0, 0.0) - ctx.show_text ("%s %.2f seconds" % (item['name'], round (item["end"] - item["start"], 2))) + ctx.show_text ("%s %.4f seconds" % (item['name'], item["end"] - item["start"])) ctx.fill() - + ctx.translate (-x-8, 6) def build_data_structure (input): @@ -162,13 +162,13 @@ def build_data_structure (input): start = float(row[1]) end = float(row[2]) structure.append ({"name": name, "start": start, "end": end}) - + structure.sort (sort_by_domain) return structure - + def usage(): - print "use --input=filename.log and --output=filename.svg :)" + print "use --input=filename.log and --output=filename.svg :)" def main(): @@ -179,7 +179,7 @@ def main(): print str(err) # will print something like "option -a not recognized" usage() sys.exit(2) - + output = None input = None for o, a in opts: @@ -196,7 +196,7 @@ def main(): if (not output or not input): usage() sys.exit() - + data = build_data_structure (input) info = gatherinfo (input) build_graph (data, output, info) diff --git a/tools/migrate_favorites.py b/tools/migrate_favorites.py index f29689fb2..ab0e62b47 100755 --- a/tools/migrate_favorites.py +++ b/tools/migrate_favorites.py @@ -7,6 +7,7 @@ # under the terms of the GNU General Public License version 3, as published # by the Free Software Foundation. +import datetime import gconf import glob import gobject @@ -17,12 +18,34 @@ from xdg import BaseDirectory LAST_MIGRATION = '3.2.0' +def get_log_file(): + ''' open the log file and return it ''' + + data_path = "%s/unity" % BaseDirectory.xdg_data_home + if not os.path.isdir(data_path): + os.mkdir(data_path) + try: + return open("%s/migration_script.log" % data_path, "a") + except IOError: + return None + +def migrating_chapter_log(name, apps_list, migration_list, log_file): + '''Log migration of new launchers''' + + log(" Migration for %s.\n Current app list is: %s\n Candidates are: %s" % (name, apps_list, migration_list), log_file) + + +def log(message, log_file): + ''' log if log_file present''' + if log_file: + log_file.write("%s\n" % message) + def get_desktop_dir(): ''' no python binding from xdg to get the desktop directory? ''' possible_desktop_folder = None try: - for line in file(os.path.expanduser('~/.config/user-dirs.dirs')): + for line in file('%s/user-dirs.dirs' % BaseDirectory.xdg_config_home): values = line.split('=') if values[0] == 'XDG_DESKTOP_DIR': try: @@ -38,13 +61,16 @@ def get_desktop_dir(): pass return os.path.expanduser('~/Desktop') -def register_new_app(launcher_location, apps_list): +def register_new_app(launcher_location, apps_list, log_file): ''' append a new app with full desktop path if valid, take care of dups ''' # default distribution launcher don't go into that function (as don't have an aboslute path) entry = "" if os.path.exists(launcher_location): + log(" == %s: exists" % launcher_location, log_file) # try to strip the full path we had in unity mutter if it's part of a xdg path: + # or try to get that for other desktop file based on name. + candidate_desktop_filename = launcher_location.split("/")[-1] for xdg_dir in BaseDirectory.xdg_data_dirs: xdg_app_dir = os.path.join(xdg_dir, "applications", "") if launcher_location.startswith(xdg_app_dir): @@ -53,10 +79,21 @@ def register_new_app(launcher_location, apps_list): if not '/' in candidate_desktop_file: entry = candidate_desktop_file break + # second chance: try to see if the desktop filename is in xdg path and so, assume it's a match + if os.path.exists("%s/%s" % (xdg_app_dir, candidate_desktop_filename)): + entry = candidate_desktop_filename + break + if not entry: entry = launcher_location + log(" %s: real entry is %s" % (launcher_location, entry), log_file) if entry not in apps_list: + log(" --- adding %s as not in app_list" % entry, log_file) apps_list.append(entry) + else: + log(" --- NOT adding %s as already in app_list" % entry, log_file) + else: + log(" == %s: doesn't exist" % launcher_location, log_file) return apps_list @@ -76,11 +113,16 @@ client = gconf.client_get_default() defaults_call = subprocess.Popen(["gsettings", "get", "com.canonical.Unity.Launcher", "favorites"], stdout=subprocess.PIPE) apps_list = [elem.strip()[1:-1] for elem in defaults_call.communicate()[0].strip()[1:-1].split(',')] +log_file = get_log_file() +log("Migration script called on %s\n" % str(datetime.datetime.now()), log_file) + # first migration to unity compiz if migration_level < '3.2.0': + log("======= Migration to 3.2.0 =======\n", log_file) unity_mutter_favorites_list = client.get_list('/desktop/unity/launcher/favorites/favorites_list', gconf.VALUE_STRING) unity_mutter_launcher_ordered = {} + migrating_chapter_log("unity mutter", apps_list, unity_mutter_favorites_list, log_file) for candidate in unity_mutter_favorites_list: candidate_path = '/desktop/unity/launcher/favorites/%s' % candidate if (client.get_string('%s/type' % candidate_path) == 'application'): @@ -90,21 +132,23 @@ if migration_level < '3.2.0': # try to preserve the order, will be done in a second loop unity_mutter_launcher_ordered[position] = launcher_location for launcher_location in unity_mutter_launcher_ordered: - apps_list = register_new_app(launcher_location, apps_list) + apps_list = register_new_app(launcher_location, apps_list, log_file) # import netbook-launcher favorites and convert them lucid_favorites_list = client.get_list('/apps/netbook-launcher/favorites/favorites_list', gconf.VALUE_STRING) + migrating_chapter_log("netbook-launcher favorites", apps_list, lucid_favorites_list, log_file) for candidate in lucid_favorites_list: candidate_path = '/apps/netbook-launcher/favorites/%s' % candidate if (client.get_string('%s/type' % candidate_path) == 'application'): launcher_location = client.get_string('%s/desktop_file' % candidate_path) if launcher_location: - apps_list = register_new_app(launcher_location, apps_list) + apps_list = register_new_app(launcher_location, apps_list, log_file) # get GNOME panel favorites and convert them panel_list = client.get_list('/apps/panel/general/toplevel_id_list', gconf.VALUE_STRING) candidate_objects = client.get_list('/apps/panel/general/object_id_list', gconf.VALUE_STRING) + migrating_chapter_log("gnome-panel items", apps_list, candidate_objects, log_file) for candidate in candidate_objects: candidate_path = '/apps/panel/objects/%s' % candidate if (client.get_string('%s/object_type' % candidate_path) == 'launcher-object' @@ -113,14 +157,16 @@ if migration_level < '3.2.0': if launcher_location: if not launcher_location.startswith('/'): launcher_location = os.path.expanduser('~/.gnome2/panel2.d/default/launchers/%s' % launcher_location) - apps_list = register_new_app(launcher_location, apps_list) + apps_list = register_new_app(launcher_location, apps_list, log_file) # get GNOME desktop launchers desktop_dir = get_desktop_dir() + desktop_items = glob.glob('%s/*.desktop' % desktop_dir) + migrating_chapter_log("deskop items in %s" % desktop_dir, apps_list, desktop_items, log_file) for launcher_location in glob.glob('%s/*.desktop' % desktop_dir): # blacklist ubiquity as will have two ubiquity in the netbook live session then if not "ubiquity" in launcher_location: - apps_list = register_new_app(launcher_location, apps_list) + apps_list = register_new_app(launcher_location, apps_list, log_file) # Now write to gsettings! #print apps_list @@ -128,6 +174,9 @@ if migration_level < '3.2.0': if return_code != 0: print "Settings fail to transition to new unity compiz" + log("Settings fail to transition to new unity compiz\n\n", log_file) + if log_file: + log_file.close() sys.exit(1) # some autumn cleanage (gconf binding for recursive_unset seems broken) @@ -135,6 +184,10 @@ if migration_level < '3.2.0': subprocess.call(["gconftool-2", "--recursive-unset", "/desktop/unity"]) print "Settings successfully transitionned to new unity compiz" +log("Migration script ended sucessfully\n\n", log_file) +if log_file: + log_file.close() + # stamp that all went well subprocess.call(["gsettings", "set", "com.canonical.Unity.Launcher", "favorite-migration", "\'%s\'" % LAST_MIGRATION]) sys.exit(0) diff --git a/tools/unity.cmake b/tools/unity.cmake new file mode 100755 index 000000000..5c5ccc352 --- /dev/null +++ b/tools/unity.cmake @@ -0,0 +1,127 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright (C) 2010 Canonical +# +# Authors: +# Didier Roche <didrocks@ubuntu.com> +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation; version 3. +# +# This program is distributed in the hope that it will be useful, but WITHOUTa +# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA + +import gconf +from optparse import OptionParser +import os +import signal +import subprocess +import sys +import time + + +def set_unity_env (): + '''set variable environnement for unity to run''' + + os.environ['COMPIZ_CONFIG_PROFILE'] = 'ubuntu' + + if not 'DISPLAY' in os.environ: + # take an optimistic chance and warn about it :) + print "WARNING: no DISPLAY variable set, setting it to :0" + os.environ['DISPLAY'] = ':0' + +def reset_unity_compiz_profile (): + '''reset the compiz/unity profile to a vanilla one''' + + client = gconf.client_get_default() + + # get current compiz profile to know if we need to switch or not + # as compiz is setting that as a default key schema each time you + # change the profile, the key isn't straightforward to get and set + # as compiz set a new schema instead of a value.. + current_profile_schema = client.get_schema("/apps/compizconfig-1/current_profile") + current_profile_gconfvalue = client.get_schema("/apps/compizconfig-1/current_profile").get_default_value() + if current_profile_gconfvalue.get_string() == 'unity': + print "WARNING: Unity currently default profile, so switching to metacity while resetting the values" + subprocess.Popen(["metacity", "--replace"]) #TODO: check if compiz is indeed running + # wait for compiz to stop + time.sleep(2) + current_profile_gconfvalue.set_string('fooo') + current_profile_schema.set_default_value(current_profile_gconfvalue) + client.set_schema("/apps/compizconfig-1/current_profile", current_profile_schema) + # the python binding doesn't recursive-unset right + subprocess.Popen(["gconftool-2", "--recursive-unset", "/apps/compiz-1"]).communicate() + subprocess.Popen(["gconftool-2", "--recursive-unset", "/apps/compizconfig-1/profiles/unity"]).communicate() + + +def process_and_start_unity (verbose, debug, compiz_args, log_file): + '''launch unity under compiz (replace the current shell in any case)''' + + cli = [] + + if debug: + # we can do more check later as if it's in PATH... + if not os.path.isfile('/usr/bin/gdb'): + print("ERROR: you don't have gdb in your system. Please install it to run in advanced debug mode.") + sys.exit(1) + elif 'DESKTOP_SESSION' in os.environ: + print("ERROR: it seems you are under a graphical environment. That's incompatible with executing advanced-debug option. You should be in a tty.") + sys.exit(1) + else: + cli.extend(['gdb', '--args']) + + cli.extend(['compiz', '--replace']) + if options.verbose: + cli.append("--debug") + if args: + cli.extend(compiz_args) + + if log_file: + cli.extend(['2>&1', '|', 'tee', log_file]) + + # shell = True as it's the simpest way to | tee. + # In this case, we need a string and not a list + # FIXME: still some bug with 2>&1 not showing everything before wait() + return subprocess.Popen(" ".join(cli), env=dict(os.environ), shell=True) + + +def run_unity (verbose, debug, compiz_args, log_file): + '''run the unity shell and handle Ctrl + C''' + + try: + unity_instance = process_and_start_unity (verbose, debug, compiz_args, log_file) + unity_instance.wait() + except KeyboardInterrupt, e: + try: + os.kill(unity_instance.pid, signal.SIGKILL) + except: + pass + unity_instance.wait() + sys.exit(unity_instance.returncode) + +if __name__ == '__main__': + usage = "usage: %prog [options]" + parser = OptionParser(version= "%prog @UNITY_VERSION@", usage=usage) + + parser.add_option("--advanced-debug", action="store_true", + help="Run unity under debugging to help debugging an issue. /!\ Only if devs ask for it.") + parser.add_option("--log", action="store", + help="Store log under filename.") + parser.add_option("--reset", action="store_true", + help="Reset the unity profile in compiz and restart it.") + parser.add_option("-v", "--verbose", action="store_true", + help="Get additional debug output from unity.") + (options, args) = parser.parse_args() + + set_unity_env() + if options.reset: + reset_unity_compiz_profile () + + run_unity (options.verbose, options.advanced_debug, args, options.log) diff --git a/unityshell.xml.in b/unityshell.xml.in index 10348ae4f..4da8b8931 100644 --- a/unityshell.xml.in +++ b/unityshell.xml.in @@ -32,6 +32,7 @@ </relation> <requirement> <plugin>opengl</plugin> + <plugin>wall</plugin> </requirement> </deps> <options> |
