Merge lp:~canonical-dx-team/unity/unity.add-multiple-plugins-to-buildsystem into lp:unity

Proposed by Sam Spilsbury
Status: Rejected
Rejected by: Didier Roche-Tolomelli
Proposed branch: lp:~canonical-dx-team/unity/unity.add-multiple-plugins-to-buildsystem
Merge into: lp:unity
Diff against target: 29974 lines (+14576/-14682)
134 files modified
CMakeLists.txt (+13/-9)
plugins/CMakeLists.txt (+10/-0)
plugins/unityshell/CMakeLists.txt (+11/-0)
plugins/unityshell/src/BamfLauncherIcon.cpp (+662/-0)
plugins/unityshell/src/BamfLauncherIcon.h (+86/-0)
plugins/unityshell/src/FavoriteStore.cpp (+43/-0)
plugins/unityshell/src/FavoriteStore.h (+73/-0)
plugins/unityshell/src/FavoriteStoreGSettings.cpp (+375/-0)
plugins/unityshell/src/FavoriteStoreGSettings.h (+55/-0)
plugins/unityshell/src/IndicatorObjectEntryProxy.h (+48/-0)
plugins/unityshell/src/IndicatorObjectEntryProxyRemote.cpp (+157/-0)
plugins/unityshell/src/IndicatorObjectEntryProxyRemote.h (+72/-0)
plugins/unityshell/src/IndicatorObjectFactory.h (+53/-0)
plugins/unityshell/src/IndicatorObjectFactoryRemote.cpp (+494/-0)
plugins/unityshell/src/IndicatorObjectFactoryRemote.h (+55/-0)
plugins/unityshell/src/IndicatorObjectProxy.h (+48/-0)
plugins/unityshell/src/IndicatorObjectProxyRemote.cpp (+145/-0)
plugins/unityshell/src/IndicatorObjectProxyRemote.h (+60/-0)
plugins/unityshell/src/Introspectable.cpp (+75/-0)
plugins/unityshell/src/Introspectable.h (+55/-0)
plugins/unityshell/src/IntrospectionDBusInterface.cpp (+223/-0)
plugins/unityshell/src/IntrospectionDBusInterface.h (+54/-0)
plugins/unityshell/src/Launcher.cpp (+2075/-0)
plugins/unityshell/src/Launcher.h (+287/-0)
plugins/unityshell/src/LauncherController.cpp (+296/-0)
plugins/unityshell/src/LauncherController.h (+81/-0)
plugins/unityshell/src/LauncherDragWindow.cpp (+64/-0)
plugins/unityshell/src/LauncherDragWindow.h (+51/-0)
plugins/unityshell/src/LauncherIcon.cpp (+585/-0)
plugins/unityshell/src/LauncherIcon.h (+197/-0)
plugins/unityshell/src/LauncherModel.cpp (+197/-0)
plugins/unityshell/src/LauncherModel.h (+76/-0)
plugins/unityshell/src/PanelHomeButton.cpp (+160/-0)
plugins/unityshell/src/PanelHomeButton.h (+49/-0)
plugins/unityshell/src/PanelIndicatorObjectEntryView.cpp (+343/-0)
plugins/unityshell/src/PanelIndicatorObjectEntryView.h (+50/-0)
plugins/unityshell/src/PanelIndicatorObjectView.cpp (+139/-0)
plugins/unityshell/src/PanelIndicatorObjectView.h (+55/-0)
plugins/unityshell/src/PanelView.cpp (+290/-0)
plugins/unityshell/src/PanelView.h (+69/-0)
plugins/unityshell/src/PluginAdapter.cpp (+134/-0)
plugins/unityshell/src/PluginAdapter.h (+57/-0)
plugins/unityshell/src/QuicklistManager.cpp (+109/-0)
plugins/unityshell/src/QuicklistManager.h (+52/-0)
plugins/unityshell/src/QuicklistMenuItem.cpp (+469/-0)
plugins/unityshell/src/QuicklistMenuItem.h (+153/-0)
plugins/unityshell/src/QuicklistMenuItemCheckmark.cpp (+380/-0)
plugins/unityshell/src/QuicklistMenuItemCheckmark.h (+63/-0)
plugins/unityshell/src/QuicklistMenuItemLabel.cpp (+262/-0)
plugins/unityshell/src/QuicklistMenuItemLabel.h (+63/-0)
plugins/unityshell/src/QuicklistMenuItemRadio.cpp (+352/-0)
plugins/unityshell/src/QuicklistMenuItemRadio.h (+66/-0)
plugins/unityshell/src/QuicklistMenuItemSeparator.cpp (+186/-0)
plugins/unityshell/src/QuicklistMenuItemSeparator.h (+63/-0)
plugins/unityshell/src/QuicklistView.cpp (+1467/-0)
plugins/unityshell/src/QuicklistView.h (+178/-0)
plugins/unityshell/src/SimpleLauncherIcon.cpp (+102/-0)
plugins/unityshell/src/SimpleLauncherIcon.h (+51/-0)
plugins/unityshell/src/StartupNotifyService.cpp (+70/-0)
plugins/unityshell/src/StartupNotifyService.h (+53/-0)
plugins/unityshell/src/StaticCairoText.cpp (+324/-0)
plugins/unityshell/src/StaticCairoText.h (+96/-0)
plugins/unityshell/src/Tooltip.cpp (+939/-0)
plugins/unityshell/src/Tooltip.h (+136/-0)
plugins/unityshell/src/TrashLauncherIcon.cpp (+110/-0)
plugins/unityshell/src/TrashLauncherIcon.h (+43/-0)
plugins/unityshell/src/unity.cpp (+552/-0)
plugins/unityshell/unityshell.xml.in (+51/-0)
src/BamfLauncherIcon.cpp (+0/-662)
src/BamfLauncherIcon.h (+0/-86)
src/FavoriteStore.cpp (+0/-43)
src/FavoriteStore.h (+0/-73)
src/FavoriteStoreGSettings.cpp (+0/-375)
src/FavoriteStoreGSettings.h (+0/-55)
src/IndicatorObjectEntryProxy.h (+0/-48)
src/IndicatorObjectEntryProxyRemote.cpp (+0/-157)
src/IndicatorObjectEntryProxyRemote.h (+0/-72)
src/IndicatorObjectFactory.h (+0/-53)
src/IndicatorObjectFactoryRemote.cpp (+0/-494)
src/IndicatorObjectFactoryRemote.h (+0/-55)
src/IndicatorObjectProxy.h (+0/-48)
src/IndicatorObjectProxyRemote.cpp (+0/-145)
src/IndicatorObjectProxyRemote.h (+0/-60)
src/Introspectable.cpp (+0/-75)
src/Introspectable.h (+0/-55)
src/IntrospectionDBusInterface.cpp (+0/-223)
src/IntrospectionDBusInterface.h (+0/-54)
src/Launcher.cpp (+0/-2075)
src/Launcher.h (+0/-287)
src/LauncherController.cpp (+0/-296)
src/LauncherController.h (+0/-81)
src/LauncherDragWindow.cpp (+0/-64)
src/LauncherDragWindow.h (+0/-51)
src/LauncherIcon.cpp (+0/-585)
src/LauncherIcon.h (+0/-197)
src/LauncherModel.cpp (+0/-197)
src/LauncherModel.h (+0/-76)
src/PanelHomeButton.cpp (+0/-160)
src/PanelHomeButton.h (+0/-49)
src/PanelIndicatorObjectEntryView.cpp (+0/-343)
src/PanelIndicatorObjectEntryView.h (+0/-50)
src/PanelIndicatorObjectView.cpp (+0/-139)
src/PanelIndicatorObjectView.h (+0/-55)
src/PanelView.cpp (+0/-290)
src/PanelView.h (+0/-69)
src/PluginAdapter.cpp (+0/-134)
src/PluginAdapter.h (+0/-57)
src/QuicklistManager.cpp (+0/-109)
src/QuicklistManager.h (+0/-52)
src/QuicklistMenuItem.cpp (+0/-469)
src/QuicklistMenuItem.h (+0/-153)
src/QuicklistMenuItemCheckmark.cpp (+0/-380)
src/QuicklistMenuItemCheckmark.h (+0/-63)
src/QuicklistMenuItemLabel.cpp (+0/-262)
src/QuicklistMenuItemLabel.h (+0/-63)
src/QuicklistMenuItemRadio.cpp (+0/-352)
src/QuicklistMenuItemRadio.h (+0/-66)
src/QuicklistMenuItemSeparator.cpp (+0/-186)
src/QuicklistMenuItemSeparator.h (+0/-63)
src/QuicklistView.cpp (+0/-1467)
src/QuicklistView.h (+0/-178)
src/SimpleLauncherIcon.cpp (+0/-102)
src/SimpleLauncherIcon.h (+0/-51)
src/StartupNotifyService.cpp (+0/-70)
src/StartupNotifyService.h (+0/-53)
src/StaticCairoText.cpp (+0/-324)
src/StaticCairoText.h (+0/-96)
src/Tooltip.cpp (+0/-939)
src/Tooltip.h (+0/-136)
src/TrashLauncherIcon.cpp (+0/-110)
src/TrashLauncherIcon.h (+0/-43)
src/unity.cpp (+0/-552)
src/unity.h (+0/-195)
tests/CMakeLists.txt (+64/-51)
To merge this branch: bzr merge lp:~canonical-dx-team/unity/unity.add-multiple-plugins-to-buildsystem
Reviewer Review Type Date Requested Status
Neil J. Patel (community) Needs Fixing
Review via email: mp+43509@code.launchpad.net

Description of the change

Allows us to drop more plugins into the package

To post a comment you must log in.
Revision history for this message
Mikkel Kamstrup Erlandsen (kamstrup) wrote :

By looking at the diff it appears you've used plain bzr rm/add to move
the files instead of bzr mv? The latter will preserve the annotation
history for the future afaik.

Revision history for this message
Neil J. Patel (njpatel) wrote :

Agreed with Mikkel, though the new bits look good, please re-do using bzr mv to not break the file id's and packaging.

review: Needs Fixing
Revision history for this message
Didier Roche-Tolomelli (didrocks) wrote :

I think this fix is totally deprecated with the current code :)

Unmerged revisions

703. By Sam Spilsbury

Fixed up the unityshell build

702. By Sam Spilsbury

Add the ability to build plugins separately as part of the unity package.

Removed:
 * src/ (We don't need to support a single plugin build)
Added:
 * plugins/
   - Drop whatever plugins we want to build in here
   - CMakeLists.txt will pick up these plugins
Changed:
 * tests/
   - At the moment we need to hardcode ../plugins/unityshell/src for linking

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2010-12-09 18:02:17 +0000
3+++ CMakeLists.txt 2010-12-13 12:41:23 +0000
4@@ -72,18 +72,22 @@
5 endif (${GETTEXT_FOUND} STREQUAL "TRUE")
6
7 #
8-# src (Compiz Plugin)
9+# Compiz Plugins
10 #
11-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")
12
13 find_package (Compiz REQUIRED)
14-include (CompizPlugin)
15-compiz_plugin (unityshell
16- PKGDEPS ${UNITY_PLUGIN_DEPS}
17- PLUGINDEPS composite opengl
18- CFLAGSADD "-DINSTALLPREFIX='\"${CMAKE_INSTALL_PREFIX}\"' -DPKGDATADIR='\"${CMAKE_INSTALL_PREFIX}/share/unity/3\"' -I${CMAKE_BINARY_DIR}"
19- LIBRARIES "unity"
20- )
21+
22+include (CompizCommon)
23+include (CompizPackage)
24+
25+compiz_add_plugins_in_folder ("${CMAKE_SOURCE_DIR}/plugins")
26+
27+compiz_print_configure_header ("Compiz Elements Plugins")
28+compiz_print_plugin_stats ("${CMAKE_SOURCE_DIR}/plugins")
29+compiz_print_configure_footer ()
30+
31+compiz_package_generation ("Compiz Unity Plugins")
32+compiz_add_uninstall ()
33
34 #
35 # GSettings Schema
36
37=== added directory 'plugins'
38=== added file 'plugins/CMakeLists.txt'
39--- plugins/CMakeLists.txt 1970-01-01 00:00:00 +0000
40+++ plugins/CMakeLists.txt 2010-12-13 12:41:23 +0000
41@@ -0,0 +1,10 @@
42+find_package (Compiz REQUIRED)
43+
44+include (CompizCommon)
45+include (CompizPackage)
46+
47+compiz_add_plugins_in_folder ("${CMAKE_CURENT_SOURCE_DIR}")
48+
49+compiz_print_configure_header ("Unity")
50+compiz_print_plugin_stats ("${CMAKE_CURRENT_SOURCE_DIR}")
51+compiz_print_configure_footer ()
52
53=== added directory 'plugins/unityshell'
54=== added file 'plugins/unityshell/CMakeLists.txt'
55--- plugins/unityshell/CMakeLists.txt 1970-01-01 00:00:00 +0000
56+++ plugins/unityshell/CMakeLists.txt 2010-12-13 12:41:23 +0000
57@@ -0,0 +1,11 @@
58+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")
59+
60+find_package (Compiz REQUIRED)
61+include (CompizPlugin)
62+
63+compiz_plugin (unityshell
64+ PKGDEPS ${UNITY_PLUGIN_DEPS}
65+ PLUGINDEPS composite opengl
66+ CFLAGSADD "-DINSTALLPREFIX='\"${CMAKE_INSTALL_PREFIX}\"' -DPKGDATADIR='\"${CMAKE_INSTALL_PREFIX}/share/unity/3\"' -I${CMAKE_BINARY_DIR}"
67+ LIBRARIES "unity"
68+ )
69
70=== added directory 'plugins/unityshell/src'
71=== added file 'plugins/unityshell/src/BamfLauncherIcon.cpp'
72--- plugins/unityshell/src/BamfLauncherIcon.cpp 1970-01-01 00:00:00 +0000
73+++ plugins/unityshell/src/BamfLauncherIcon.cpp 2010-12-13 12:41:23 +0000
74@@ -0,0 +1,662 @@
75+/*
76+ * Copyright (C) 2010 Canonical Ltd
77+ *
78+ * This program is free software: you can redistribute it and/or modify
79+ * it under the terms of the GNU General Public License version 3 as
80+ * published by the Free Software Foundation.
81+ *
82+ * This program is distributed in the hope that it will be useful,
83+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
84+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
85+ * GNU General Public License for more details.
86+ *
87+ * You should have received a copy of the GNU General Public License
88+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
89+ *
90+ * Authored by: Jason Smith <jason.smith@canonical.com>
91+ */
92+
93+#include "Nux/Nux.h"
94+#include "Nux/BaseWindow.h"
95+
96+#include "BamfLauncherIcon.h"
97+#include "Launcher.h"
98+#include "PluginAdapter.h"
99+#include "FavoriteStore.h"
100+
101+#include <gio/gdesktopappinfo.h>
102+#include <libindicator/indicator-desktop-shortcuts.h>
103+#include <core/core.h>
104+#include <core/atoms.h>
105+
106+struct _ShortcutData
107+{
108+ BamfLauncherIcon *self;
109+ IndicatorDesktopShortcuts *shortcuts;
110+ char *nick;
111+};
112+typedef struct _ShortcutData ShortcutData;
113+static void shortcut_data_destroy (ShortcutData *data)
114+{
115+ g_object_unref (data->shortcuts);
116+ g_free (data->nick);
117+ g_slice_free (ShortcutData, data);
118+}
119+
120+static void shortcut_activated (DbusmenuMenuitem* _sender, guint timestamp, gpointer userdata)
121+{
122+ ShortcutData *data = (ShortcutData *)userdata;
123+ indicator_desktop_shortcuts_nick_exec (data->shortcuts, data->nick);
124+}
125+
126+BamfLauncherIcon::BamfLauncherIcon (Launcher* IconManager, BamfApplication *app, CompScreen *screen)
127+: SimpleLauncherIcon(IconManager)
128+{
129+ m_App = app;
130+ m_Screen = screen;
131+ _menu_desktop_shortcuts = NULL;
132+ char *icon_name = bamf_view_get_icon (BAMF_VIEW (m_App));
133+
134+ SetTooltipText (bamf_view_get_name (BAMF_VIEW (app)));
135+ SetIconName (icon_name);
136+ SetIconType (LAUNCHER_ICON_TYPE_APPLICATION);
137+
138+ if (bamf_view_is_sticky (BAMF_VIEW (m_App)))
139+ SetQuirk (LAUNCHER_ICON_QUIRK_VISIBLE, true);
140+ else
141+ SetQuirk (LAUNCHER_ICON_QUIRK_VISIBLE, bamf_view_user_visible (BAMF_VIEW (m_App)));
142+
143+ SetQuirk (LAUNCHER_ICON_QUIRK_ACTIVE, bamf_view_is_active (BAMF_VIEW (m_App)));
144+ SetQuirk (LAUNCHER_ICON_QUIRK_RUNNING, bamf_view_is_running (BAMF_VIEW (m_App)));
145+
146+ g_free (icon_name);
147+
148+ g_signal_connect (app, "child-removed", (GCallback) &BamfLauncherIcon::OnChildRemoved, this);
149+ g_signal_connect (app, "child-added", (GCallback) &BamfLauncherIcon::OnChildAdded, this);
150+ g_signal_connect (app, "urgent-changed", (GCallback) &BamfLauncherIcon::OnUrgentChanged, this);
151+ g_signal_connect (app, "running-changed", (GCallback) &BamfLauncherIcon::OnRunningChanged, this);
152+ g_signal_connect (app, "active-changed", (GCallback) &BamfLauncherIcon::OnActiveChanged, this);
153+ g_signal_connect (app, "user-visible-changed", (GCallback) &BamfLauncherIcon::OnUserVisibleChanged, this);
154+ g_signal_connect (app, "closed", (GCallback) &BamfLauncherIcon::OnClosed, this);
155+
156+ g_object_ref (m_App);
157+
158+ EnsureWindowState ();
159+ UpdateMenus ();
160+}
161+
162+BamfLauncherIcon::~BamfLauncherIcon()
163+{
164+ g_signal_handlers_disconnect_by_func (m_App, (void *) &BamfLauncherIcon::OnChildRemoved, this);
165+ g_signal_handlers_disconnect_by_func (m_App, (void *) &BamfLauncherIcon::OnChildAdded, this);
166+ g_signal_handlers_disconnect_by_func (m_App, (void *) &BamfLauncherIcon::OnUrgentChanged, this);
167+ g_signal_handlers_disconnect_by_func (m_App, (void *) &BamfLauncherIcon::OnRunningChanged, this);
168+ g_signal_handlers_disconnect_by_func (m_App, (void *) &BamfLauncherIcon::OnActiveChanged, this);
169+ g_signal_handlers_disconnect_by_func (m_App, (void *) &BamfLauncherIcon::OnUserVisibleChanged, this);
170+ g_signal_handlers_disconnect_by_func (m_App, (void *) &BamfLauncherIcon::OnClosed, this);
171+
172+ g_object_unref (m_App);
173+}
174+
175+bool
176+BamfLauncherIcon::IsSticky ()
177+{
178+ return bamf_view_is_sticky (BAMF_VIEW (m_App));
179+}
180+
181+const char*
182+BamfLauncherIcon::DesktopFile ()
183+{
184+ return bamf_application_get_desktop_file (m_App);
185+}
186+
187+void
188+BamfLauncherIcon::AddProperties (GVariantBuilder *builder)
189+{
190+ LauncherIcon::AddProperties (builder);
191+
192+ g_variant_builder_add (builder, "{sv}", "desktop-file", g_variant_new_string (bamf_application_get_desktop_file (m_App)));
193+
194+ GList *children, *l;
195+ BamfView *view;
196+
197+ children = bamf_view_get_children (BAMF_VIEW (m_App));
198+ GVariant* xids[(int) g_list_length (children)];
199+
200+ int i = 0;
201+ for (l = children; l; l = l->next)
202+ {
203+ view = (BamfView *) l->data;
204+
205+ if (BAMF_IS_WINDOW (view))
206+ {
207+ xids[i++] = g_variant_new_uint32 (bamf_window_get_xid (BAMF_WINDOW (view)));
208+ }
209+ }
210+ g_list_free (children);
211+ g_variant_builder_add (builder, "{sv}", "xids", g_variant_new_array (G_VARIANT_TYPE_UINT32, xids, i));
212+}
213+
214+bool
215+BamfLauncherIcon::IconOwnsWindow (Window w)
216+{
217+ GList *children, *l;
218+ BamfView *view;
219+ bool owns = false;
220+
221+ children = bamf_view_get_children (BAMF_VIEW (m_App));
222+
223+ for (l = children; l; l = l->next)
224+ {
225+ view = (BamfView *) l->data;
226+
227+ if (BAMF_IS_WINDOW (view))
228+ {
229+ guint32 xid = bamf_window_get_xid (BAMF_WINDOW (view));
230+
231+ if (xid == w)
232+ {
233+ owns = true;
234+ break;
235+ }
236+ }
237+ }
238+
239+ g_list_free (children);
240+ return owns;
241+}
242+
243+void
244+BamfLauncherIcon::OpenInstance ()
245+{
246+ GDesktopAppInfo *appInfo;
247+ GError *error = NULL;
248+
249+ appInfo = g_desktop_app_info_new_from_filename (bamf_application_get_desktop_file (BAMF_APPLICATION (m_App)));
250+ g_app_info_launch (G_APP_INFO (appInfo), NULL, NULL, &error);
251+ g_object_unref (appInfo);
252+
253+ if (error)
254+ {
255+ g_warning ("%s\n", error->message);
256+ g_error_free (error);
257+ }
258+
259+ UpdateQuirkTime (LAUNCHER_ICON_QUIRK_STARTING);
260+}
261+
262+void
263+BamfLauncherIcon::Focus ()
264+{
265+ GList *children, *l;
266+ BamfView *view;
267+
268+ children = bamf_view_get_children (BAMF_VIEW (m_App));
269+
270+ CompWindowList windows;
271+
272+ /* get the list of windows */
273+ for (l = children; l; l = l->next)
274+ {
275+ view = (BamfView *) l->data;
276+
277+ if (BAMF_IS_WINDOW (view))
278+ {
279+ guint32 xid = bamf_window_get_xid (BAMF_WINDOW (view));
280+
281+ CompWindow *window = m_Screen->findWindow ((Window) xid);
282+
283+ if (window)
284+ windows.push_back (window);
285+ }
286+ }
287+
288+ if (windows.empty ())
289+ return;
290+
291+ /* sort the list */
292+ CompWindowList tmp;
293+ CompWindowList::iterator it;
294+ for (it = m_Screen->windows ().begin (); it != m_Screen->windows ().end (); it++)
295+ {
296+ if (std::find (windows.begin (), windows.end (), *it) != windows.end ())
297+ tmp.push_back (*it);
298+ }
299+ windows = tmp;
300+
301+
302+ /* filter based on workspace */
303+ bool any_on_current = false;
304+
305+ for (it = windows.begin (); it != windows.end (); it++)
306+ {
307+ if ((*it)->defaultViewport () == m_Screen->vp ())
308+ {
309+ any_on_current = true;
310+ break;
311+ }
312+ }
313+
314+ /* activate our windows */
315+
316+ if (any_on_current)
317+ {
318+ for (it = windows.begin (); it != windows.end (); it++)
319+ {
320+ if ((*it)->defaultViewport () == m_Screen->vp ())
321+ {
322+ (*it)->activate ();
323+ }
324+ }
325+ }
326+ else
327+ {
328+ (*(windows.rbegin ()))->activate ();
329+ }
330+
331+ g_list_free (children);
332+}
333+
334+void
335+BamfLauncherIcon::Spread ()
336+{
337+ BamfView *view;
338+ GList *children, *l;
339+ children = bamf_view_get_children (BAMF_VIEW (m_App));
340+
341+ std::list<Window> windowList;
342+ for (l = children; l; l = l->next)
343+ {
344+ view = (BamfView *) l->data;
345+
346+ if (BAMF_IS_WINDOW (view))
347+ {
348+ guint32 xid = bamf_window_get_xid (BAMF_WINDOW (view));
349+
350+ windowList.push_back ((Window) xid);
351+ }
352+ }
353+
354+ if (windowList.size () > 1)
355+ {
356+ std::string *match = PluginAdapter::Default ()->MatchStringForXids (&windowList);
357+ PluginAdapter::Default ()->InitiateScale (match);
358+ delete match;
359+ }
360+
361+ g_list_free (children);
362+}
363+
364+void
365+BamfLauncherIcon::OnMouseClick (int button)
366+{
367+ if (button != 1)
368+ return;
369+
370+ bool active, running;
371+
372+ active = bamf_view_is_active (BAMF_VIEW (m_App));
373+ running = bamf_view_is_running (BAMF_VIEW (m_App));
374+
375+ if (!running)
376+ {
377+ if (GetQuirk (LAUNCHER_ICON_QUIRK_STARTING))
378+ return;
379+ SetQuirk (LAUNCHER_ICON_QUIRK_STARTING, true);
380+ OpenInstance ();
381+ return;
382+ }
383+ else if (active)
384+ Spread ();
385+ else
386+ Focus ();
387+}
388+
389+void
390+BamfLauncherIcon::OnClosed (BamfView *view, gpointer data)
391+{
392+ BamfLauncherIcon *self = (BamfLauncherIcon *) data;
393+
394+ if (!bamf_view_is_sticky (BAMF_VIEW (self->m_App)))
395+ self->Remove ();
396+}
397+
398+void
399+BamfLauncherIcon::OnUserVisibleChanged (BamfView *view, gboolean visible, gpointer data)
400+{
401+ BamfLauncherIcon *self = (BamfLauncherIcon *) data;
402+
403+ if (!bamf_view_is_sticky (BAMF_VIEW (self->m_App)))
404+ self->SetQuirk (LAUNCHER_ICON_QUIRK_VISIBLE, visible);
405+}
406+
407+void
408+BamfLauncherIcon::OnRunningChanged (BamfView *view, gboolean running, gpointer data)
409+{
410+ BamfLauncherIcon *self = (BamfLauncherIcon *) data;
411+ self->SetQuirk (LAUNCHER_ICON_QUIRK_RUNNING, running);
412+
413+ if (running)
414+ {
415+ self->EnsureWindowState ();
416+ self->UpdateIconGeometries (self->GetCenter ());
417+ }
418+}
419+
420+void
421+BamfLauncherIcon::OnActiveChanged (BamfView *view, gboolean active, gpointer data)
422+{
423+ BamfLauncherIcon *self = (BamfLauncherIcon *) data;
424+ self->SetQuirk (LAUNCHER_ICON_QUIRK_ACTIVE, active);
425+}
426+
427+void
428+BamfLauncherIcon::OnUrgentChanged (BamfView *view, gboolean urgent, gpointer data)
429+{
430+ BamfLauncherIcon *self = (BamfLauncherIcon *) data;
431+ self->SetQuirk (LAUNCHER_ICON_QUIRK_URGENT, urgent);
432+}
433+
434+void
435+BamfLauncherIcon::EnsureWindowState ()
436+{
437+ GList *children, *l;
438+ int count = 0;
439+
440+ children = bamf_view_get_children (BAMF_VIEW (m_App));
441+ for (l = children; l; l = l->next)
442+ {
443+ if (BAMF_IS_WINDOW (l->data))
444+ count++;
445+ }
446+
447+ SetRelatedWindows (count);
448+
449+ g_list_free (children);
450+}
451+
452+void
453+BamfLauncherIcon::OnChildAdded (BamfView *view, BamfView *child, gpointer data)
454+{
455+ BamfLauncherIcon *self = (BamfLauncherIcon*) data;
456+ self->EnsureWindowState ();
457+ self->UpdateMenus ();
458+ self->UpdateIconGeometries (self->GetCenter ());
459+}
460+
461+void
462+BamfLauncherIcon::OnChildRemoved (BamfView *view, BamfView *child, gpointer data)
463+{
464+ BamfLauncherIcon *self = (BamfLauncherIcon*) data;
465+ self->EnsureWindowState ();
466+}
467+
468+void
469+BamfLauncherIcon::UpdateMenus ()
470+{
471+ GList *children, *l;
472+ IndicatorDesktopShortcuts *desktop_shortcuts;
473+
474+ children = bamf_view_get_children (BAMF_VIEW (m_App));
475+ for (l = children; l; l = l->next)
476+ {
477+ if (!BAMF_IS_INDICATOR (l->data))
478+ continue;
479+
480+ BamfIndicator *indicator = BAMF_INDICATOR (l->data);
481+ std::string path = bamf_indicator_get_dbus_menu_path (indicator);
482+
483+ // we already have this
484+ if (_menu_clients.find (path) != _menu_clients.end ())
485+ continue;
486+
487+ DbusmenuClient *client = dbusmenu_client_new (bamf_indicator_get_remote_address (indicator), path.c_str ());
488+ _menu_clients[path] = client;
489+ }
490+
491+ g_list_free (children);
492+
493+ // make a client for desktop file actions
494+ if (!DBUSMENU_IS_MENUITEM (_menu_desktop_shortcuts) &&
495+ bamf_application_get_desktop_file (m_App) != NULL)
496+ {
497+
498+ DbusmenuMenuitem *root = dbusmenu_menuitem_new ();
499+ dbusmenu_menuitem_set_root (root, TRUE);
500+ desktop_shortcuts = indicator_desktop_shortcuts_new (bamf_application_get_desktop_file (m_App),
501+ "Unity");
502+ const gchar **nicks = indicator_desktop_shortcuts_get_nicks (desktop_shortcuts);
503+
504+ int index = 0;
505+ if (nicks) {
506+ while (((gpointer*) nicks)[index]) {
507+ const char* name;
508+ DbusmenuMenuitem *item;
509+ name = g_strdup (indicator_desktop_shortcuts_nick_get_name (desktop_shortcuts,
510+ nicks[index]));
511+ ShortcutData *data = g_slice_new0 (ShortcutData);
512+ data->self = this;
513+ data->shortcuts = INDICATOR_DESKTOP_SHORTCUTS (g_object_ref (desktop_shortcuts));
514+ data->nick = g_strdup (nicks[index]);
515+
516+ item = dbusmenu_menuitem_new ();
517+ dbusmenu_menuitem_property_set (item, DBUSMENU_MENUITEM_PROP_LABEL, name);
518+ dbusmenu_menuitem_property_set_bool (item, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
519+ dbusmenu_menuitem_property_set_bool (item, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
520+ g_signal_connect_data (item, "item-activated",
521+ (GCallback) shortcut_activated, (gpointer) data,
522+ (GClosureNotify) shortcut_data_destroy, (GConnectFlags)0);
523+
524+ dbusmenu_menuitem_child_append (root, item);
525+
526+ index++;
527+
528+ g_free ((void *)name);
529+ }
530+ }
531+
532+ _menu_desktop_shortcuts = root;
533+ }
534+
535+}
536+
537+void
538+BamfLauncherIcon::OnLaunch (DbusmenuMenuitem *item, int time, BamfLauncherIcon *self)
539+{
540+ self->OpenInstance ();
541+}
542+
543+void
544+BamfLauncherIcon::OnQuit (DbusmenuMenuitem *item, int time, BamfLauncherIcon *self)
545+{
546+ GList *children, *l;
547+ BamfView *view;
548+
549+ children = bamf_view_get_children (BAMF_VIEW (self->m_App));
550+
551+ for (l = children; l; l = l->next)
552+ {
553+ view = (BamfView *) l->data;
554+
555+ if (BAMF_IS_WINDOW (view))
556+ {
557+ guint32 xid = bamf_window_get_xid (BAMF_WINDOW (view));
558+ CompWindow *window = self->m_Screen->findWindow ((Window) xid);
559+
560+ if (window)
561+ window->close (self->m_Screen->getCurrentTime ());
562+ }
563+ }
564+
565+ g_list_free (children);
566+}
567+
568+void
569+BamfLauncherIcon::OnTogglePin (DbusmenuMenuitem *item, int time, BamfLauncherIcon *self)
570+{
571+ BamfView *view = BAMF_VIEW (self->m_App);
572+ bool sticky = bamf_view_is_sticky (view);
573+ const gchar *desktop_file = bamf_application_get_desktop_file (self->m_App);
574+
575+ if (sticky)
576+ {
577+ bamf_view_set_sticky (view, false);
578+ if (bamf_view_is_closed (view))
579+ self->Remove ();
580+
581+ if (desktop_file && strlen (desktop_file) > 0)
582+ FavoriteStore::GetDefault ()->RemoveFavorite (desktop_file);
583+ }
584+ else
585+ {
586+ bamf_view_set_sticky (view, true);
587+
588+ if (desktop_file && strlen (desktop_file) > 0)
589+ FavoriteStore::GetDefault ()->AddFavorite (desktop_file, -1); //self->SortPriority ());
590+ }
591+}
592+
593+void
594+BamfLauncherIcon::EnsureMenuItemsReady ()
595+{
596+ DbusmenuMenuitem *menu_item;
597+
598+ /* Launch */
599+ if (_menu_items.find ("Launch") == _menu_items.end ())
600+ {
601+ menu_item = dbusmenu_menuitem_new ();
602+ g_object_ref (menu_item);
603+
604+ dbusmenu_menuitem_property_set (menu_item, DBUSMENU_MENUITEM_PROP_LABEL, "Open New Window");
605+ dbusmenu_menuitem_property_set_bool (menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
606+
607+ g_signal_connect (menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, (GCallback) &BamfLauncherIcon::OnLaunch, this);
608+
609+ _menu_items["Launch"] = menu_item;
610+ }
611+
612+ /* Pin */
613+ if (_menu_items.find ("Pin") == _menu_items.end ())
614+ {
615+ menu_item = dbusmenu_menuitem_new ();
616+ g_object_ref (menu_item);
617+
618+ dbusmenu_menuitem_property_set (menu_item, DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE, DBUSMENU_MENUITEM_TOGGLE_CHECK);
619+ dbusmenu_menuitem_property_set (menu_item, DBUSMENU_MENUITEM_PROP_LABEL, "Keep In Launcher");
620+ dbusmenu_menuitem_property_set_bool (menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
621+
622+ g_signal_connect (menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, (GCallback) &BamfLauncherIcon::OnTogglePin, this);
623+
624+ _menu_items["Pin"] = menu_item;
625+ }
626+ int checked = !bamf_view_is_sticky (BAMF_VIEW (m_App)) ?
627+ DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED : DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED;
628+
629+ dbusmenu_menuitem_property_set_int (_menu_items["Pin"],
630+ DBUSMENU_MENUITEM_PROP_TOGGLE_STATE,
631+ checked);
632+
633+
634+ /* Quit */
635+ if (_menu_items.find ("Quit") == _menu_items.end ())
636+ {
637+ menu_item = dbusmenu_menuitem_new ();
638+ g_object_ref (menu_item);
639+
640+ dbusmenu_menuitem_property_set (menu_item, DBUSMENU_MENUITEM_PROP_LABEL, "Quit");
641+ dbusmenu_menuitem_property_set_bool (menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
642+
643+ g_signal_connect (menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, (GCallback) &BamfLauncherIcon::OnQuit, this);
644+
645+ _menu_items["Quit"] = menu_item;
646+ }
647+}
648+
649+std::list<DbusmenuMenuitem *>
650+BamfLauncherIcon::GetMenus ()
651+{
652+ std::map<std::string, DbusmenuClient *>::iterator it;
653+ std::list<DbusmenuMenuitem *> result;
654+
655+ for (it = _menu_clients.begin (); it != _menu_clients.end (); it++)
656+ {
657+ GList * child = NULL;
658+ DbusmenuClient *client = (*it).second;
659+ DbusmenuMenuitem *root = dbusmenu_client_get_root (client);
660+
661+ for (child = dbusmenu_menuitem_get_children(root); child != NULL; child = g_list_next(child))
662+ {
663+ DbusmenuMenuitem *item = (DbusmenuMenuitem *) child->data;
664+
665+ if (!item)
666+ continue;
667+
668+ result.push_back (item);
669+ }
670+ }
671+
672+ if (DBUSMENU_IS_MENUITEM (_menu_desktop_shortcuts))
673+ {
674+ GList * child = NULL;
675+ DbusmenuMenuitem *root = _menu_desktop_shortcuts;
676+
677+ for (child = dbusmenu_menuitem_get_children(root); child != NULL; child = g_list_next(child))
678+ {
679+ DbusmenuMenuitem *item = (DbusmenuMenuitem *) child->data;
680+
681+ if (!item)
682+ continue;
683+
684+ result.push_back (item);
685+ }
686+
687+ }
688+
689+ EnsureMenuItemsReady ();
690+
691+ result.push_back (_menu_items["Launch"]);
692+ result.push_back (_menu_items["Pin"]);
693+
694+ if (bamf_view_is_running (BAMF_VIEW (m_App)))
695+ result.push_back (_menu_items["Quit"]);
696+
697+ return result;
698+}
699+
700+
701+void
702+BamfLauncherIcon::UpdateIconGeometries (nux::Point3 center)
703+{
704+ GList *children, *l;
705+ BamfView *view;
706+ long data[4];
707+
708+ data[0] = center.x - 24;
709+ data[1] = center.y - 24;
710+ data[2] = 48;
711+ data[3] = 48;
712+
713+ children = bamf_view_get_children (BAMF_VIEW (m_App));
714+
715+ for (l = children; l; l = l->next)
716+ {
717+ view = (BamfView *) l->data;
718+
719+ if (BAMF_IS_WINDOW (view))
720+ {
721+ guint32 xid = bamf_window_get_xid (BAMF_WINDOW (view));
722+
723+ XChangeProperty (m_Screen->dpy (), xid, Atoms::wmIconGeometry,
724+ XA_CARDINAL, 32, PropModeReplace,
725+ (unsigned char *) data, 4);
726+ }
727+ }
728+
729+ g_list_free (children);
730+}
731+
732+void
733+BamfLauncherIcon::OnCenterStabilized (nux::Point3 center)
734+{
735+ UpdateIconGeometries (center);
736+}
737
738=== added file 'plugins/unityshell/src/BamfLauncherIcon.h'
739--- plugins/unityshell/src/BamfLauncherIcon.h 1970-01-01 00:00:00 +0000
740+++ plugins/unityshell/src/BamfLauncherIcon.h 2010-12-13 12:41:23 +0000
741@@ -0,0 +1,86 @@
742+/*
743+ * Copyright (C) 2010 Canonical Ltd
744+ *
745+ * This program is free software: you can redistribute it and/or modify
746+ * it under the terms of the GNU General Public License version 3 as
747+ * published by the Free Software Foundation.
748+ *
749+ * This program is distributed in the hope that it will be useful,
750+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
751+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
752+ * GNU General Public License for more details.
753+ *
754+ * You should have received a copy of the GNU General Public License
755+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
756+ *
757+ * Authored by: Jason Smith <jason.smith@canonical.com>
758+ */
759+
760+#ifndef BAMFLAUNCHERICON_H
761+#define BAMFLAUNCHERICON_H
762+
763+/* Compiz */
764+#include <core/core.h>
765+
766+#include <Nux/BaseWindow.h>
767+#include <NuxCore/Math/MathInc.h>
768+#include <gdk-pixbuf/gdk-pixbuf.h>
769+#include <libbamf/libbamf.h>
770+#include <sigc++/sigc++.h>
771+
772+#include "SimpleLauncherIcon.h"
773+
774+class Launcher;
775+
776+class BamfLauncherIcon : public SimpleLauncherIcon
777+{
778+public:
779+ BamfLauncherIcon(Launcher* IconManager, BamfApplication *app, CompScreen *screen);
780+ virtual ~BamfLauncherIcon();
781+
782+ const char* DesktopFile ();
783+ bool IsSticky ();
784+
785+protected:
786+ void OnMouseClick (int button);
787+ std::list<DbusmenuMenuitem *> GetMenus ();
788+
789+ void UpdateIconGeometries (nux::Point3 center);
790+ void OnCenterStabilized (nux::Point3 center);
791+
792+ bool IconOwnsWindow (Window w);
793+
794+ void AddProperties (GVariantBuilder *builder);
795+
796+private:
797+ BamfApplication *m_App;
798+ CompScreen *m_Screen;
799+ std::map<std::string, DbusmenuClient *> _menu_clients;
800+ std::map<std::string, DbusmenuMenuitem *> _menu_items;
801+ DbusmenuMenuitem *_menu_desktop_shortcuts;
802+
803+ void EnsureWindowState ();
804+
805+ void UpdateMenus ();
806+
807+ void OpenInstance ();
808+ void Focus ();
809+ void Spread ();
810+
811+ void EnsureMenuItemsReady ();
812+
813+ static void OnClosed (BamfView *view, gpointer data);
814+ static void OnUserVisibleChanged (BamfView *view, gboolean visible, gpointer data);
815+ static void OnActiveChanged (BamfView *view, gboolean active, gpointer data);
816+ static void OnRunningChanged (BamfView *view, gboolean running, gpointer data);
817+ static void OnUrgentChanged (BamfView *view, gboolean urgent, gpointer data);
818+ static void OnChildAdded (BamfView *view, BamfView *child, gpointer data);
819+ static void OnChildRemoved (BamfView *view, BamfView *child, gpointer data);
820+
821+ static void OnLaunch (DbusmenuMenuitem *item, int time, BamfLauncherIcon *self);
822+ static void OnQuit (DbusmenuMenuitem *item, int time, BamfLauncherIcon *self);
823+ static void OnTogglePin (DbusmenuMenuitem *item, int time, BamfLauncherIcon *self);
824+};
825+
826+#endif // BAMFLAUNCHERICON_H
827+
828
829=== added file 'plugins/unityshell/src/FavoriteStore.cpp'
830--- plugins/unityshell/src/FavoriteStore.cpp 1970-01-01 00:00:00 +0000
831+++ plugins/unityshell/src/FavoriteStore.cpp 2010-12-13 12:41:23 +0000
832@@ -0,0 +1,43 @@
833+/*
834+* Copyright (C) 2010 Canonical Ltd
835+*
836+* This program is free software: you can redistribute it and/or modify
837+* it under the terms of the GNU General Public License version 3 as
838+* published by the Free Software Foundation.
839+*
840+* This program is distributed in the hope that it will be useful,
841+* but WITHOUT ANY WARRANTY; without even the implied warranty of
842+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
843+* GNU General Public License for more details.
844+*
845+* You should have received a copy of the GNU General Public License
846+* along with this program. If not, see <http://www.gnu.org/licenses/>.
847+*
848+* Authored by: Neil Jagdish Patel <neil.patel@canonical.com>
849+*/
850+
851+#include "FavoriteStoreGSettings.h"
852+
853+static FavoriteStore *m_store = NULL;
854+
855+FavoriteStore::FavoriteStore ()
856+{
857+
858+}
859+
860+FavoriteStore::~FavoriteStore ()
861+{
862+
863+}
864+
865+FavoriteStore *
866+FavoriteStore::GetDefault ()
867+{
868+ if (m_store)
869+ m_store->Reference ();
870+ else
871+ m_store = new FavoriteStoreGSettings ();
872+
873+ return m_store;
874+}
875+
876
877=== added file 'plugins/unityshell/src/FavoriteStore.h'
878--- plugins/unityshell/src/FavoriteStore.h 1970-01-01 00:00:00 +0000
879+++ plugins/unityshell/src/FavoriteStore.h 2010-12-13 12:41:23 +0000
880@@ -0,0 +1,73 @@
881+/*
882+* Copyright (C) 2010 Canonical Ltd
883+*
884+* This program is free software: you can redistribute it and/or modify
885+* it under the terms of the GNU General Public License version 3 as
886+* published by the Free Software Foundation.
887+*
888+* This program is distributed in the hope that it will be useful,
889+* but WITHOUT ANY WARRANTY; without even the implied warranty of
890+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
891+* GNU General Public License for more details.
892+*
893+* You should have received a copy of the GNU General Public License
894+* along with this program. If not, see <http://www.gnu.org/licenses/>.
895+*
896+* Authored by: Neil Jagdish Patel <neil.patel@canonical.com>
897+*/
898+
899+#ifndef FAVORITE_STORE_H
900+#define FAVORITE_STORE_H
901+
902+#include <NuxCore/NuxCore.h>
903+#include <NuxCore/ObjectType.h>
904+#include <NuxCore/Object.h>
905+#include <string>
906+#include <sigc++/signal.h>
907+
908+#include <glib.h>
909+
910+// An abstract object that facilitates getting and modifying the list of favorites
911+// Use GetDefault () to get the correct store for the session
912+
913+class FavoriteStore : public nux::Object
914+{
915+public:
916+ FavoriteStore ();
917+ ~FavoriteStore ();
918+
919+ // Returns a referenced FavoriteStore, make sure to UnReference () it
920+ static FavoriteStore * GetDefault ();
921+
922+ // Methods
923+
924+ // Get's a GSList of char * desktop paths
925+ // DO NOT FREE
926+ // DO NOT RELY ON THE CHAR *, STRDUP THEM
927+ virtual GSList * GetFavorites () = 0;
928+
929+ // These will NOT emit the relevant signals, so bare that in mind
930+ // i.e. don't hope that you can add stuff and hook the view up to
931+ // favorite_added events to update the view. The signals only emit if
932+ // there has been a change on the GSettings object from an external
933+ // source
934+ virtual void AddFavorite (const char *desktop_path, gint position) = 0;
935+ virtual void RemoveFavorite (const char *desktop_path) = 0;
936+ virtual void MoveFavorite (const char *desktop_path, gint position) = 0;
937+ virtual void SetFavorites (std::list<const char*> desktop_paths) = 0;
938+
939+ // Signals
940+ // Therse only emit if something has changed the GSettings object externally
941+
942+ //desktop_path, position
943+ sigc::signal<void, const char *, guint32> favorite_added;
944+
945+ //desktop_path
946+ sigc::signal<void, const char *> favorite_removed;
947+
948+ sigc::signal<void> reordered;
949+
950+private:
951+};
952+
953+#endif // FAVORITE_STORE_H
954
955=== added file 'plugins/unityshell/src/FavoriteStoreGSettings.cpp'
956--- plugins/unityshell/src/FavoriteStoreGSettings.cpp 1970-01-01 00:00:00 +0000
957+++ plugins/unityshell/src/FavoriteStoreGSettings.cpp 2010-12-13 12:41:23 +0000
958@@ -0,0 +1,375 @@
959+/*
960+* Copyright (C) 2010 Canonical Ltd
961+*
962+* This program is free software: you can redistribute it and/or modify
963+* it under the terms of the GNU General Public License version 3 as
964+* published by the Free Software Foundation.
965+*
966+* This program is distributed in the hope that it will be useful,
967+* but WITHOUT ANY WARRANTY; without even the implied warranty of
968+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
969+* GNU General Public License for more details.
970+*
971+* You should have received a copy of the GNU General Public License
972+* along with this program. If not, see <http://www.gnu.org/licenses/>.
973+*
974+* Authored by: Neil Jagdish Patel <neil.patel@canonical.com>
975+*/
976+
977+#include "config.h"
978+
979+#include <gio/gdesktopappinfo.h>
980+
981+#include "FavoriteStoreGSettings.h"
982+
983+#define SETTINGS_NAME "com.canonical.Unity.Launcher"
984+
985+#define LATEST_SETTINGS_MIGRATION "3.2.0"
986+
987+static void on_settings_updated (GSettings *settings, const gchar *key, FavoriteStoreGSettings *self);
988+
989+FavoriteStoreGSettings::FavoriteStoreGSettings ()
990+{
991+ m_settings = g_settings_new (SETTINGS_NAME);
992+
993+ Init ();
994+}
995+
996+FavoriteStoreGSettings::FavoriteStoreGSettings (GSettingsBackend *backend)
997+{
998+ m_settings = g_settings_new_with_backend (SETTINGS_NAME, backend);
999+
1000+ Init ();
1001+}
1002+
1003+void
1004+FavoriteStoreGSettings::Init ()
1005+{
1006+ gchar *latest_migration_update;
1007+
1008+ m_favorites = NULL;
1009+ m_ignore_signals = false;
1010+
1011+ /* migrate the favorites if needed and ignore errors */
1012+ latest_migration_update = g_settings_get_string (m_settings, "favorite-migration");
1013+ if (g_strcmp0 (latest_migration_update, LATEST_SETTINGS_MIGRATION) < 0)
1014+ {
1015+ GError *error = NULL;
1016+ char *cmd = g_strdup_printf ("%s/lib/unity/migrate_favorites.py", PREFIXDIR);
1017+ char *output = NULL;
1018+
1019+ g_spawn_command_line_sync (cmd, &output, NULL, NULL, &error);
1020+ if (error)
1021+ {
1022+ printf ("WARNING: Unable to run the migrate favorites tools successfully: %s.\nThe output was:%s\n", error->message,output);
1023+ g_error_free (error);
1024+ }
1025+ g_free (output);
1026+ g_free (cmd);
1027+ }
1028+ g_free (latest_migration_update);
1029+
1030+ g_signal_connect (m_settings, "changed",
1031+ G_CALLBACK (on_settings_updated), this);
1032+
1033+ Refresh ();
1034+}
1035+
1036+FavoriteStoreGSettings::~FavoriteStoreGSettings ()
1037+{
1038+ g_slist_foreach (m_favorites, (GFunc)g_free, NULL);
1039+ g_slist_free (m_favorites);
1040+ g_object_unref (m_settings);
1041+}
1042+
1043+void
1044+FavoriteStoreGSettings::Refresh ()
1045+{
1046+ int i = 0;
1047+ gchar **favs;
1048+
1049+ g_slist_foreach (m_favorites, (GFunc)g_free, NULL);
1050+ g_slist_free (m_favorites);
1051+ m_favorites = NULL;
1052+
1053+ favs = g_settings_get_strv (m_settings, "favorites");
1054+
1055+ while (favs[i] != NULL)
1056+ {
1057+ /*
1058+ * We will be storing either full /path/to/desktop/files or foo.desktop id's
1059+ */
1060+ if (favs[i][0] == '/')
1061+ {
1062+ if (g_file_test (favs[i], G_FILE_TEST_EXISTS))
1063+ {
1064+ m_favorites = g_slist_append (m_favorites, g_strdup (favs[i]));
1065+ }
1066+ else
1067+ {
1068+ g_warning ("Unable to load desktop file: %s", favs[i]);
1069+ }
1070+ }
1071+ else
1072+ {
1073+ GDesktopAppInfo *info;
1074+
1075+ info = g_desktop_app_info_new (favs[i]);
1076+
1077+ if (info == NULL || g_desktop_app_info_get_filename (info) == NULL)
1078+ {
1079+ g_warning ("Unable to load GDesktopAppInfo for '%s'", favs[i]);
1080+
1081+ i++;
1082+ continue;
1083+ }
1084+
1085+ m_favorites = g_slist_append (m_favorites, g_strdup (g_desktop_app_info_get_filename (info)));
1086+
1087+ g_object_unref (info);
1088+ }
1089+
1090+ i++;
1091+ }
1092+
1093+ g_strfreev (favs);
1094+}
1095+
1096+GSList *
1097+FavoriteStoreGSettings::GetFavorites ()
1098+{
1099+ return m_favorites;
1100+}
1101+
1102+static gchar *
1103+get_basename_or_path (const gchar *desktop_path)
1104+{
1105+ const gchar * const * dirs;
1106+ const gchar * dir;
1107+ gint i = 0;
1108+
1109+ dirs = g_get_system_data_dirs ();
1110+
1111+ /* We check to see if the desktop file belongs to one of the system data
1112+ * directories. If so, then we store it's desktop id, otherwise we store
1113+ * it's full path. We're clever like that.
1114+ */
1115+ while ((dir = dirs[i]))
1116+ {
1117+ if (g_str_has_prefix (desktop_path, dir))
1118+ {
1119+ return g_path_get_basename (desktop_path);
1120+ }
1121+ i++;
1122+ }
1123+
1124+ return g_strdup (desktop_path);
1125+}
1126+
1127+void
1128+FavoriteStoreGSettings::AddFavorite (const char *desktop_path,
1129+ gint position)
1130+{
1131+ int n_total_favs;
1132+ GSList *f;
1133+ gint i = 0;
1134+
1135+ g_return_if_fail (desktop_path);
1136+ g_return_if_fail (position < (gint)g_slist_length (m_favorites));
1137+
1138+ n_total_favs = g_slist_length (m_favorites) + 1;
1139+
1140+ char *favs[n_total_favs + 1];
1141+ favs[n_total_favs] = NULL;
1142+
1143+ for (f = m_favorites; f; f = f->next)
1144+ {
1145+ if (i == position)
1146+ {
1147+ favs[i] = get_basename_or_path (desktop_path);
1148+ i++;
1149+ }
1150+
1151+ favs[i] = get_basename_or_path ((char *)f->data);
1152+
1153+ i++;
1154+ }
1155+
1156+ /* Add it to the end of the list */
1157+ if (position == -1)
1158+ {
1159+ favs[i] = get_basename_or_path (desktop_path);
1160+ }
1161+
1162+ m_ignore_signals = true;
1163+ if (!g_settings_set_strv (m_settings, "favorites", favs))
1164+ g_warning ("Unable to add a new favorite '%s' at position '%u'", desktop_path, position);
1165+ m_ignore_signals = false;
1166+
1167+ i = 0;
1168+ while (favs[i] != NULL)
1169+ {
1170+ g_free (favs[i]);
1171+ favs[i] = NULL;
1172+ i++;
1173+ }
1174+
1175+ Refresh ();
1176+}
1177+
1178+void
1179+FavoriteStoreGSettings::RemoveFavorite (const char *desktop_path)
1180+{
1181+ int n_total_favs;
1182+ GSList *f;
1183+ int i = 0;
1184+ bool found = false;
1185+
1186+ g_return_if_fail (desktop_path);
1187+ g_return_if_fail (desktop_path[0] == '/');
1188+
1189+ n_total_favs = g_slist_length (m_favorites) - 1;
1190+
1191+ char *favs[n_total_favs + 1];
1192+ favs[n_total_favs] = NULL;
1193+
1194+ for (f = m_favorites; f; f = f->next)
1195+ {
1196+ if (g_strcmp0 ((char *)f->data, desktop_path) != 0)
1197+ {
1198+ favs[i] = get_basename_or_path ((char *)f->data);
1199+ i++;
1200+ }
1201+ else
1202+ {
1203+ found = true;
1204+ }
1205+ }
1206+
1207+ if (!found)
1208+ {
1209+ g_warning ("Unable to remove favorite '%s': Does not exist in favorites",
1210+ desktop_path);
1211+ }
1212+
1213+ m_ignore_signals = true;
1214+ if (!g_settings_set_strv (m_settings, "favorites", favs))
1215+ g_warning ("Unable to remove favorite '%s'", desktop_path);
1216+ m_ignore_signals = false;
1217+
1218+ i = 0;
1219+ while (favs[i] != NULL)
1220+ {
1221+ g_free (favs[i]);
1222+ favs[i] = NULL;
1223+ i++;
1224+ }
1225+
1226+ Refresh ();
1227+}
1228+
1229+void
1230+FavoriteStoreGSettings::MoveFavorite (const char *desktop_path,
1231+ gint position)
1232+{
1233+ int n_total_favs;
1234+ GSList *f;
1235+ gint i = 0;
1236+
1237+ g_return_if_fail (desktop_path);
1238+ g_return_if_fail (position < (gint)g_slist_length (m_favorites));
1239+
1240+ n_total_favs = g_slist_length (m_favorites);
1241+
1242+ char *favs[n_total_favs + 1];
1243+ favs[n_total_favs] = NULL;
1244+
1245+ for (f = m_favorites; f; f = f->next)
1246+ {
1247+ if (i == position)
1248+ {
1249+ favs[i] = get_basename_or_path (desktop_path);
1250+ i++;
1251+ }
1252+
1253+ if (g_strcmp0 (desktop_path, (char *)f->data) != 0)
1254+ {
1255+ favs[i] = get_basename_or_path ((char *)f->data);
1256+ i++;
1257+ }
1258+ }
1259+
1260+ /* Add it to the end of the list */
1261+ if (position == -1)
1262+ {
1263+ favs[i] = get_basename_or_path (desktop_path);
1264+ i++;
1265+ }
1266+ favs[i] = NULL;
1267+
1268+ m_ignore_signals = true;
1269+ if (!g_settings_set_strv (m_settings, "favorites", favs))
1270+ g_warning ("Unable to add a new favorite '%s' at position '%u'", desktop_path, position);
1271+ m_ignore_signals = false;
1272+
1273+ i = 0;
1274+ while (favs[i] != NULL)
1275+ {
1276+ g_free (favs[i]);
1277+ favs[i] = NULL;
1278+ i++;
1279+ }
1280+
1281+ Refresh ();
1282+}
1283+
1284+void
1285+FavoriteStoreGSettings::SetFavorites (std::list<const char *> desktop_paths)
1286+{
1287+ char *favs[desktop_paths.size () + 1];
1288+ favs[desktop_paths.size ()] = NULL;
1289+
1290+ int i = 0;
1291+ std::list<const char*>::iterator it;
1292+ for (it = desktop_paths.begin (); it != desktop_paths.end (); it++)
1293+ {
1294+ favs[i] = get_basename_or_path (*it);
1295+ i++;
1296+ }
1297+
1298+ m_ignore_signals = true;
1299+ if (!g_settings_set_strv (m_settings, "favorites", favs))
1300+ g_warning ("Unable to set favorites from list");
1301+ m_ignore_signals = false;
1302+
1303+ i = 0;
1304+ while (favs[i] != NULL)
1305+ {
1306+ g_free (favs[i]);
1307+ favs[i] = NULL;
1308+ i++;
1309+ }
1310+
1311+ Refresh ();
1312+}
1313+
1314+void
1315+FavoriteStoreGSettings::Changed (const gchar *key)
1316+{
1317+ if (m_ignore_signals)
1318+ return;
1319+
1320+ g_print ("Changed: %s\n", key);
1321+}
1322+
1323+/*
1324+ * These are just callbacks chaining to real class functions
1325+ */
1326+static void
1327+on_settings_updated (GSettings *settings, const gchar *key, FavoriteStoreGSettings *self)
1328+{
1329+ g_return_if_fail (key != NULL);
1330+ g_return_if_fail (self != NULL);
1331+
1332+ self->Changed (key);
1333+}
1334
1335=== added file 'plugins/unityshell/src/FavoriteStoreGSettings.h'
1336--- plugins/unityshell/src/FavoriteStoreGSettings.h 1970-01-01 00:00:00 +0000
1337+++ plugins/unityshell/src/FavoriteStoreGSettings.h 2010-12-13 12:41:23 +0000
1338@@ -0,0 +1,55 @@
1339+/*
1340+* Copyright (C) 2010 Canonical Ltd
1341+*
1342+* This program is free software: you can redistribute it and/or modify
1343+* it under the terms of the GNU General Public License version 3 as
1344+* published by the Free Software Foundation.
1345+*
1346+* This program is distributed in the hope that it will be useful,
1347+* but WITHOUT ANY WARRANTY; without even the implied warranty of
1348+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1349+* GNU General Public License for more details.
1350+*
1351+* You should have received a copy of the GNU General Public License
1352+* along with this program. If not, see <http://www.gnu.org/licenses/>.
1353+*
1354+* Authored by: Neil Jagdish Patel <neil.patel@canonical.com>
1355+*/
1356+
1357+#ifndef FAVORITE_STORE_GSETTINGS_H
1358+#define FAVORITE_STORE_GSETTINGS_H
1359+
1360+#include <gio/gio.h>
1361+
1362+#include "FavoriteStore.h"
1363+
1364+// An abstract object that facilitates getting and modifying the list of favorites
1365+// Use GetDefault () to get the correct store for the session
1366+
1367+class FavoriteStoreGSettings : public FavoriteStore
1368+{
1369+public:
1370+
1371+ FavoriteStoreGSettings ();
1372+ FavoriteStoreGSettings (GSettingsBackend *backend);
1373+ ~FavoriteStoreGSettings ();
1374+
1375+ //Methods
1376+ GSList * GetFavorites ();
1377+ void AddFavorite (const char *desktop_path, gint position);
1378+ void RemoveFavorite (const char *desktop_path);
1379+ void MoveFavorite (const char *desktop_path, gint position);
1380+ void SetFavorites (std::list<const char *> desktop_paths);
1381+
1382+ void Changed (const char *key);
1383+
1384+private:
1385+ void Init ();
1386+ void Refresh ();
1387+
1388+ GSList *m_favorites;
1389+ GSettings *m_settings;
1390+ bool m_ignore_signals;
1391+};
1392+
1393+#endif // FAVORITE_STORE_GSETTINGS_H
1394
1395=== added file 'plugins/unityshell/src/IndicatorObjectEntryProxy.h'
1396--- plugins/unityshell/src/IndicatorObjectEntryProxy.h 1970-01-01 00:00:00 +0000
1397+++ plugins/unityshell/src/IndicatorObjectEntryProxy.h 2010-12-13 12:41:23 +0000
1398@@ -0,0 +1,48 @@
1399+/*
1400+ * Copyright (C) 2010 Canonical Ltd
1401+ *
1402+ * This program is free software: you can redistribute it and/or modify
1403+ * it under the terms of the GNU General Public License version 3 as
1404+ * published by the Free Software Foundation.
1405+ *
1406+ * This program is distributed in the hope that it will be useful,
1407+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1408+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1409+ * GNU General Public License for more details.
1410+ *
1411+ * You should have received a copy of the GNU General Public License
1412+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1413+ *
1414+ * Authored by: Neil Jagdish Patel <neil.patel@canonical.com>
1415+ */
1416+
1417+#ifndef INDICATOR_OBJECT_ENTRY_PROXY_H
1418+#define INDICATOR_OBJECT_ENTRY_PROXY_H
1419+
1420+#include <string>
1421+#include <sigc++/signal.h>
1422+#include <sigc++/sigc++.h>
1423+#include <gdk/gdk.h>
1424+
1425+class IndicatorObjectEntryProxy : public sigc::trackable
1426+{
1427+public:
1428+
1429+ virtual const char * GetId () = 0;
1430+ virtual const char * GetLabel () = 0;
1431+ virtual GdkPixbuf * GetPixbuf () = 0;
1432+ virtual void SetActive (bool active) = 0;
1433+ virtual bool GetActive () = 0;
1434+ virtual void ShowMenu (int x, int y, guint32 timestamp, guint32 button) = 0;
1435+
1436+ // Signals
1437+ sigc::signal<void> Updated;
1438+
1439+public:
1440+ bool label_visible;
1441+ bool label_sensitive;
1442+ bool icon_visible;
1443+ bool icon_sensitive;
1444+};
1445+
1446+#endif // INDICATOR_OBJECT_ENTRY_PROXY_H
1447
1448=== added file 'plugins/unityshell/src/IndicatorObjectEntryProxyRemote.cpp'
1449--- plugins/unityshell/src/IndicatorObjectEntryProxyRemote.cpp 1970-01-01 00:00:00 +0000
1450+++ plugins/unityshell/src/IndicatorObjectEntryProxyRemote.cpp 2010-12-13 12:41:23 +0000
1451@@ -0,0 +1,157 @@
1452+/*
1453+* Copyright (C) 2010 Canonical Ltd
1454+*
1455+* This program is free software: you can redistribute it and/or modify
1456+* it under the terms of the GNU General Public License version 3 as
1457+* published by the Free Software Foundation.
1458+*
1459+* This program is distributed in the hope that it will be useful,
1460+* but WITHOUT ANY WARRANTY; without even the implied warranty of
1461+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1462+* GNU General Public License for more details.
1463+*
1464+* You should have received a copy of the GNU General Public License
1465+* along with this program. If not, see <http://www.gnu.org/licenses/>.
1466+*
1467+* Authored by: Neil Jagdish Patel <neil.patel@canonical.com>
1468+*/
1469+
1470+#include "IndicatorObjectEntryProxyRemote.h"
1471+
1472+#include <gtk/gtk.h>
1473+
1474+IndicatorObjectEntryProxyRemote::IndicatorObjectEntryProxyRemote ()
1475+: _dirty (false),
1476+ _active (false),
1477+ _id (NULL),
1478+ _label (NULL),
1479+ _image_type (0),
1480+ _image_data (NULL)
1481+{
1482+ label_visible = false;
1483+ label_sensitive = true;
1484+ icon_visible = false;
1485+ icon_sensitive = true;
1486+}
1487+
1488+
1489+IndicatorObjectEntryProxyRemote::~IndicatorObjectEntryProxyRemote ()
1490+{
1491+ g_free (_id);
1492+ g_free (_label);
1493+ g_free (_image_data);
1494+}
1495+
1496+const char *
1497+IndicatorObjectEntryProxyRemote::GetLabel ()
1498+{
1499+ return _label;
1500+}
1501+
1502+GdkPixbuf *
1503+IndicatorObjectEntryProxyRemote::GetPixbuf ()
1504+{
1505+ GdkPixbuf *ret = NULL;
1506+
1507+ if (_image_type == GTK_IMAGE_PIXBUF)
1508+ {
1509+ guchar *decoded;
1510+ GInputStream *stream;
1511+ gsize len = 0;
1512+
1513+ decoded = g_base64_decode (_image_data, &len);
1514+ stream = g_memory_input_stream_new_from_data (decoded, len, NULL);
1515+
1516+ ret = gdk_pixbuf_new_from_stream (stream, NULL, NULL);
1517+
1518+ g_free (decoded);
1519+ g_input_stream_close (stream, NULL, NULL);
1520+ }
1521+ else if (_image_type == GTK_IMAGE_STOCK
1522+ || _image_type == GTK_IMAGE_ICON_NAME)
1523+ {
1524+ ret = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
1525+ _image_data,
1526+ 22,
1527+ (GtkIconLookupFlags)0,
1528+ NULL);
1529+ }
1530+ else if (_image_type == GTK_IMAGE_GICON)
1531+ {
1532+ GtkIconInfo *info;
1533+ GIcon *icon;
1534+
1535+ icon = g_icon_new_for_string (_image_data, NULL);
1536+ info = gtk_icon_theme_lookup_by_gicon (gtk_icon_theme_get_default (),
1537+ icon,
1538+ 22,
1539+ (GtkIconLookupFlags)0);
1540+ if (info)
1541+ ret = gtk_icon_info_load_icon (info, NULL);
1542+
1543+ gtk_icon_info_free (info);
1544+ g_object_unref (icon);
1545+ }
1546+
1547+ return ret;
1548+}
1549+
1550+void
1551+IndicatorObjectEntryProxyRemote::SetActive (bool active)
1552+{
1553+ if (_active == active)
1554+ return;
1555+
1556+ _active = active;
1557+
1558+ Updated.emit ();
1559+}
1560+
1561+bool
1562+IndicatorObjectEntryProxyRemote::GetActive ()
1563+{
1564+ return _active;
1565+}
1566+
1567+void
1568+IndicatorObjectEntryProxyRemote::Refresh (const char *__id,
1569+ const char *__label,
1570+ bool __label_sensitive,
1571+ bool __label_visible,
1572+ guint32 __image_type,
1573+ const char *__image_data,
1574+ bool __image_sensitive,
1575+ bool __image_visible)
1576+{
1577+ g_free (_id);
1578+ g_free (_label);
1579+ g_free (_image_data);
1580+
1581+ _id = NULL;
1582+ _label = NULL;
1583+ _image_data = NULL;
1584+
1585+ _id = g_strdup (__id);
1586+ _label = g_strdup (__label);
1587+ label_sensitive = __label_sensitive;
1588+ label_visible = __label_visible;
1589+ _image_type = __image_type;
1590+ if (_image_type)
1591+ _image_data = g_strdup (__image_data);
1592+ icon_sensitive = __image_sensitive;
1593+ icon_visible = __image_visible;
1594+
1595+ Updated.emit ();
1596+}
1597+
1598+const char *
1599+IndicatorObjectEntryProxyRemote::GetId ()
1600+{
1601+ return _id;
1602+}
1603+
1604+void
1605+IndicatorObjectEntryProxyRemote::ShowMenu (int x, int y, guint32 timestamp, guint32 button)
1606+{
1607+ OnShowMenuRequest.emit (_id, x, y, timestamp, button);
1608+}
1609
1610=== added file 'plugins/unityshell/src/IndicatorObjectEntryProxyRemote.h'
1611--- plugins/unityshell/src/IndicatorObjectEntryProxyRemote.h 1970-01-01 00:00:00 +0000
1612+++ plugins/unityshell/src/IndicatorObjectEntryProxyRemote.h 2010-12-13 12:41:23 +0000
1613@@ -0,0 +1,72 @@
1614+/*
1615+* Copyright (C) 2010 Canonical Ltd
1616+*
1617+* This program is free software: you can redistribute it and/or modify
1618+* it under the terms of the GNU General Public License version 3 as
1619+* published by the Free Software Foundation.
1620+*
1621+* This program is distributed in the hope that it will be useful,
1622+* but WITHOUT ANY WARRANTY; without even the implied warranty of
1623+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1624+* GNU General Public License for more details.
1625+*
1626+* You should have received a copy of the GNU General Public License
1627+* along with this program. If not, see <http://www.gnu.org/licenses/>.
1628+*
1629+* Authored by: Neil Jagdish Patel <neil.patel@canonical.com>
1630+*/
1631+
1632+#ifndef INDICATOR_OBJECT_ENTRY_PROXY_REMOTE_H
1633+#define INDICATOR_OBJECT_ENTRY_PROXY_REMOTE_H
1634+
1635+#include <string>
1636+#include <gio/gio.h>
1637+
1638+#include "IndicatorObjectEntryProxy.h"
1639+
1640+// Represents an IndicatorObjectEntry over DBus through the panel service
1641+// Basically wraps the DeeModelIter, trying to keep as much info inside
1642+// that as possible to avoid duplication
1643+
1644+class IndicatorObjectEntryProxyRemote : public IndicatorObjectEntryProxy
1645+{
1646+public:
1647+
1648+ IndicatorObjectEntryProxyRemote ();
1649+ ~IndicatorObjectEntryProxyRemote ();
1650+
1651+ virtual const char * GetId ();
1652+
1653+ virtual const char * GetLabel ();
1654+
1655+ // Call g_object_unref on the returned pixbuf
1656+ virtual GdkPixbuf * GetPixbuf ();
1657+
1658+ virtual void SetActive (bool active);
1659+ virtual bool GetActive ();
1660+
1661+ virtual void ShowMenu (int x, int y, guint32 timestamp, guint32 button);
1662+
1663+ void Refresh (const char *__id,
1664+ const char *__label,
1665+ bool __label_sensitive,
1666+ bool __label_visible,
1667+ guint32 __image_type,
1668+ const char *__image_data,
1669+ bool __image_sensitive,
1670+ bool __image_visible);
1671+
1672+ // Signals
1673+ sigc::signal<void, const char *, int, int, guint32, guint32> OnShowMenuRequest;
1674+
1675+public:
1676+ bool _dirty;
1677+ bool _active;
1678+
1679+ char *_id;
1680+ char *_label;
1681+ guint32 _image_type;
1682+ char *_image_data;
1683+};
1684+
1685+#endif // INDICATOR_OBJECT_ENTRY_PROXY_REMOTE_H
1686
1687=== added file 'plugins/unityshell/src/IndicatorObjectFactory.h'
1688--- plugins/unityshell/src/IndicatorObjectFactory.h 1970-01-01 00:00:00 +0000
1689+++ plugins/unityshell/src/IndicatorObjectFactory.h 2010-12-13 12:41:23 +0000
1690@@ -0,0 +1,53 @@
1691+/*
1692+ * Copyright (C) 2010 Canonical Ltd
1693+ *
1694+ * This program is free software: you can redistribute it and/or modify
1695+ * it under the terms of the GNU General Public License version 3 as
1696+ * published by the Free Software Foundation.
1697+ *
1698+ * This program is distributed in the hope that it will be useful,
1699+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1700+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1701+ * GNU General Public License for more details.
1702+ *
1703+ * You should have received a copy of the GNU General Public License
1704+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1705+ *
1706+ * Authored by: Neil Jagdish Patel <neil.patel@canonical.com>
1707+ */
1708+
1709+#ifndef INDICATOR_OBJECT_FACTORY_H
1710+#define INDICATOR_OBJECT_FACTORY_H
1711+
1712+#include <string>
1713+#include <vector>
1714+#include <sigc++/signal.h>
1715+#include <sigc++/trackable.h>
1716+#include "IndicatorObjectProxy.h"
1717+
1718+class IndicatorObjectFactory : public sigc::trackable
1719+{
1720+public:
1721+
1722+ // This could be empty, if the loading of Indicators is async, so you
1723+ // should be listening to the signals too
1724+ virtual std::vector<IndicatorObjectProxy *>& GetIndicatorObjects () = 0;
1725+
1726+ // If the implementation supports it, you'll get a refreshed list of
1727+ // Indicators (probably though a bunch of removed/added events)
1728+ virtual void ForceRefresh () = 0;
1729+
1730+ // For adding factory-specific properties
1731+ virtual void AddProperties (GVariantBuilder *builder) = 0;
1732+
1733+ // Signals
1734+ sigc::signal<void, IndicatorObjectProxy *> OnObjectAdded;
1735+ sigc::signal<void, IndicatorObjectProxy *> OnObjectRemoved;
1736+ sigc::signal<void, int, int> OnMenuPointerMoved;
1737+ sigc::signal<void, const char *> OnEntryActivateRequest;
1738+
1739+protected:
1740+ std::vector<IndicatorObjectProxy *>_indicators;
1741+};
1742+
1743+#endif // INDICATOR_OBJECT_FACTORY_H
1744
1745=== added file 'plugins/unityshell/src/IndicatorObjectFactoryRemote.cpp'
1746--- plugins/unityshell/src/IndicatorObjectFactoryRemote.cpp 1970-01-01 00:00:00 +0000
1747+++ plugins/unityshell/src/IndicatorObjectFactoryRemote.cpp 2010-12-13 12:41:23 +0000
1748@@ -0,0 +1,494 @@
1749+/*
1750+ * Copyright (C) 2010 Canonical Ltd
1751+ *
1752+ * This program is free software: you can redistribute it and/or modify
1753+ * it under the terms of the GNU General Public License version 3 as
1754+ * published by the Free Software Foundation.
1755+ *
1756+ * This program is distributed in the hope that it will be useful,
1757+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1758+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1759+ * GNU General Public License for more details.
1760+ *
1761+ * You should have received a copy of the GNU General Public License
1762+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1763+ *
1764+ * Authored by: Neil Jagdish Patel <neil.patel@canonical.com>
1765+ */
1766+
1767+#include "config.h"
1768+
1769+#include "IndicatorObjectFactoryRemote.h"
1770+
1771+#include "IndicatorObjectProxyRemote.h"
1772+#include "IndicatorObjectEntryProxyRemote.h"
1773+#include "IndicatorObjectEntryProxy.h"
1774+
1775+#include "Nux/Nux.h"
1776+#include "Nux/WindowThread.h"
1777+#include "NuxGraphics/GLWindowManager.h"
1778+#include <X11/Xlib.h>
1779+
1780+#define S_NAME "com.canonical.Unity.Panel.Service"
1781+#define S_PATH "/com/canonical/Unity/Panel/Service"
1782+#define S_IFACE "com.canonical.Unity.Panel.Service"
1783+
1784+typedef struct
1785+{
1786+ GDBusProxy *proxy;
1787+ gchar *entry_id;
1788+ int x;
1789+ int y;
1790+ guint timestamp;
1791+ guint32 button;
1792+
1793+} ShowEntryData;
1794+
1795+
1796+// Forwards
1797+static void on_proxy_ready_cb (GObject *source,
1798+ GAsyncResult *res,
1799+ gpointer data);
1800+
1801+static void on_proxy_signal_received (GDBusProxy *proxy,
1802+ gchar *sender_name,
1803+ gchar *signal_name,
1804+ GVariant *parameters,
1805+ IndicatorObjectFactoryRemote *remote);
1806+
1807+static void on_sync_ready_cb (GObject *source,
1808+ GAsyncResult *res,
1809+ gpointer data);
1810+
1811+static bool run_local_panel_service ();
1812+static bool reconnect_to_service (gpointer data);
1813+
1814+// Public Methods
1815+IndicatorObjectFactoryRemote::IndicatorObjectFactoryRemote ()
1816+{
1817+ if (g_getenv ("PANEL_USE_LOCAL_SERVICE"))
1818+ {
1819+ run_local_panel_service ();
1820+ g_timeout_add_seconds (1, (GSourceFunc)reconnect_to_service, this);
1821+ }
1822+ else
1823+ {
1824+ // We want to grab the Panel Service object. This is async, which is fine
1825+ g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION,
1826+ G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
1827+ NULL,
1828+ S_NAME,
1829+ S_PATH,
1830+ S_IFACE,
1831+ NULL,
1832+ on_proxy_ready_cb,
1833+ this);
1834+ }
1835+}
1836+
1837+IndicatorObjectFactoryRemote::~IndicatorObjectFactoryRemote ()
1838+{
1839+ if (G_IS_OBJECT (_proxy))
1840+ g_object_unref (_proxy);
1841+ _proxy = NULL;
1842+
1843+ std::vector<IndicatorObjectProxy*>::iterator it;
1844+
1845+ for (it = _indicators.begin(); it != _indicators.end(); it++)
1846+ {
1847+ IndicatorObjectProxyRemote *remote = static_cast<IndicatorObjectProxyRemote *> (*it);
1848+ delete remote;
1849+ }
1850+
1851+ _indicators.erase (_indicators.begin (), _indicators.end ());
1852+}
1853+
1854+std::vector<IndicatorObjectProxy *>&
1855+IndicatorObjectFactoryRemote::GetIndicatorObjects ()
1856+{
1857+ return _indicators;
1858+}
1859+
1860+void
1861+IndicatorObjectFactoryRemote::ForceRefresh ()
1862+{
1863+}
1864+
1865+void
1866+IndicatorObjectFactoryRemote::OnRemoteProxyReady (GDBusProxy *proxy)
1867+{
1868+ _proxy = proxy;
1869+
1870+ // Connect to interesting signals
1871+ // FIXME: Add auto-restarting bits here
1872+ g_signal_connect (_proxy, "g-signal",
1873+ G_CALLBACK (on_proxy_signal_received), this);
1874+
1875+ g_dbus_proxy_call (_proxy,
1876+ "Sync",
1877+ NULL,
1878+ G_DBUS_CALL_FLAGS_NONE,
1879+ -1,
1880+ NULL,
1881+ on_sync_ready_cb,
1882+ this);
1883+}
1884+
1885+static gboolean
1886+send_show_entry (ShowEntryData *data)
1887+{
1888+ g_return_val_if_fail (data != NULL, FALSE);
1889+ g_return_val_if_fail (G_IS_DBUS_PROXY (data->proxy), FALSE);
1890+
1891+ /* Re-flush 'cos X is crap like that */
1892+ Display* d = nux::GetThreadGLWindow()->GetX11Display();
1893+ XFlush (d);
1894+
1895+ g_dbus_proxy_call (data->proxy,
1896+ "ShowEntry",
1897+ g_variant_new ("(suiii)",
1898+ data->entry_id,
1899+ 0,
1900+ data->x,
1901+ data->y,
1902+ data->button),
1903+ G_DBUS_CALL_FLAGS_NONE,
1904+ -1,
1905+ NULL,
1906+ NULL,
1907+ NULL);
1908+
1909+ g_free (data->entry_id);
1910+ g_slice_free (ShowEntryData, data);
1911+ return FALSE;
1912+}
1913+
1914+void
1915+IndicatorObjectFactoryRemote::OnShowMenuRequestReceived (const char *entry_id,
1916+ int x,
1917+ int y,
1918+ guint timestamp,
1919+ guint32 button)
1920+{
1921+ Display* d = nux::GetThreadGLWindow()->GetX11Display();
1922+ XUngrabPointer(d, CurrentTime);
1923+ XFlush (d);
1924+
1925+ // We have to do this because on certain systems X won't have time to
1926+ // respond to our request for XUngrabPointer and this will cause the
1927+ // menu not to show
1928+ ShowEntryData *data = g_slice_new0 (ShowEntryData);
1929+ data->proxy = _proxy;
1930+ data->entry_id = g_strdup (entry_id);
1931+ data->x = x;
1932+ data->y = y;
1933+ data->timestamp = timestamp;
1934+ data->button = button;
1935+
1936+ g_timeout_add (0, (GSourceFunc)send_show_entry, data);
1937+
1938+ // --------------------------------------------------------------------------
1939+ // FIXME: This is a workaround until the non-paired events issue is fixed in
1940+ // nux
1941+ XButtonEvent ev = {
1942+ ButtonRelease,
1943+ 0,
1944+ False,
1945+ d,
1946+ 0,
1947+ 0,
1948+ 0,
1949+ CurrentTime,
1950+ x, y,
1951+ x, y,
1952+ 0,
1953+ Button1,
1954+ True
1955+ };
1956+ XEvent *e = (XEvent*)&ev;
1957+ nux::GetGraphicsThread()->ProcessForeignEvent (e, NULL);
1958+ // --------------------------------------------------------------------------
1959+}
1960+
1961+// We need to unset the last active entry and set the new one as active
1962+void
1963+IndicatorObjectFactoryRemote::OnEntryActivated (const char *entry_id)
1964+{
1965+ std::vector<IndicatorObjectProxy*>::iterator it;
1966+
1967+ for (it = _indicators.begin(); it != _indicators.end(); it++)
1968+ {
1969+ IndicatorObjectProxyRemote *object = static_cast<IndicatorObjectProxyRemote *> (*it);
1970+ std::vector<IndicatorObjectEntryProxy*>::iterator it;
1971+
1972+ for (it = object->GetEntries ().begin(); it != object->GetEntries ().end(); it++)
1973+ {
1974+ IndicatorObjectEntryProxyRemote *entry = static_cast<IndicatorObjectEntryProxyRemote *> (*it);
1975+
1976+ entry->SetActive (g_strcmp0 (entry_id, entry->GetId ()) == 0);
1977+ }
1978+ }
1979+}
1980+
1981+void
1982+IndicatorObjectFactoryRemote::OnEntryActivateRequestReceived (const gchar *entry_id)
1983+{
1984+ OnEntryActivateRequest.emit (entry_id);
1985+}
1986+
1987+IndicatorObjectProxyRemote *
1988+IndicatorObjectFactoryRemote::IndicatorForID (const char *id)
1989+{
1990+ IndicatorObjectProxyRemote *remote = NULL;
1991+ std::vector<IndicatorObjectProxy*>::iterator it;
1992+
1993+ for (it = _indicators.begin(); it != _indicators.end(); it++)
1994+ {
1995+ IndicatorObjectProxyRemote *r = static_cast<IndicatorObjectProxyRemote *> (*it);
1996+
1997+ if (g_strcmp0 (id, r->GetName ().c_str ()) == 0)
1998+ {
1999+ remote = r;
2000+ break;
2001+ }
2002+ }
2003+
2004+ if (remote == NULL)
2005+ {
2006+ // Create one
2007+ remote = new IndicatorObjectProxyRemote (id);
2008+ remote->OnShowMenuRequest.connect (sigc::mem_fun (this,
2009+ &IndicatorObjectFactoryRemote::OnShowMenuRequestReceived));
2010+
2011+ _indicators.push_back (remote);
2012+
2013+ OnObjectAdded.emit (remote);
2014+ }
2015+
2016+ return remote;
2017+}
2018+
2019+void
2020+IndicatorObjectFactoryRemote::Sync (GVariant *args)
2021+{
2022+ GVariantIter *iter;
2023+ gchar *indicator_id;
2024+ gchar *entry_id;
2025+ gchar *label;
2026+ gboolean label_sensitive;
2027+ gboolean label_visible;
2028+ guint32 image_type;
2029+ gchar *image_data;
2030+ gboolean image_sensitive;
2031+ gboolean image_visible;
2032+
2033+ IndicatorObjectProxyRemote *current_proxy = NULL;
2034+ gchar *current_proxy_id = NULL;
2035+
2036+ g_variant_get (args, "(a(sssbbusbb))", &iter);
2037+ while (g_variant_iter_loop (iter, "(sssbbusbb)",
2038+ &indicator_id,
2039+ &entry_id,
2040+ &label,
2041+ &label_sensitive,
2042+ &label_visible,
2043+ &image_type,
2044+ &image_data,
2045+ &image_sensitive,
2046+ &image_visible))
2047+ {
2048+ if (g_strcmp0 (current_proxy_id, indicator_id) != 0)
2049+ {
2050+ if (current_proxy)
2051+ current_proxy->EndSync ();
2052+ g_free (current_proxy_id);
2053+
2054+ current_proxy_id = g_strdup (indicator_id);
2055+ current_proxy = IndicatorForID (indicator_id);
2056+ current_proxy->BeginSync ();
2057+ }
2058+
2059+ /* NULL entries (id == "") are just padding */
2060+ if (g_strcmp0 (entry_id, "") != 0)
2061+ current_proxy->AddEntry (entry_id,
2062+ label,
2063+ label_sensitive,
2064+ label_visible,
2065+ image_type,
2066+ image_data,
2067+ image_sensitive,
2068+ image_visible);
2069+ }
2070+ if (current_proxy)
2071+ current_proxy->EndSync ();
2072+
2073+ g_free (current_proxy_id);
2074+ g_variant_iter_free (iter);
2075+}
2076+
2077+void
2078+IndicatorObjectFactoryRemote::AddProperties (GVariantBuilder *builder)
2079+{
2080+ gchar *name = NULL;
2081+ gchar *uname = NULL;
2082+
2083+ g_object_get (_proxy,
2084+ "g-name", &name,
2085+ "g-name-owner", &uname,
2086+ NULL);
2087+
2088+ g_variant_builder_add (builder, "{sv}", "backend", g_variant_new_string ("remote"));
2089+ g_variant_builder_add (builder, "{sv}", "service-name", g_variant_new_string (name));
2090+ g_variant_builder_add (builder, "{sv}", "service-unique-name", g_variant_new_string (uname));
2091+ g_variant_builder_add (builder, "{sv}", "using-local-service", g_variant_new_boolean (g_getenv ("PANEL_USE_LOCAL_SERVICE") == NULL ? FALSE : TRUE));
2092+
2093+ g_free (name);
2094+ g_free (uname);
2095+}
2096+
2097+
2098+//
2099+// C callbacks, they just link to class methods and aren't interesting
2100+//
2101+
2102+static bool
2103+reconnect_to_service (gpointer data)
2104+{
2105+ g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION,
2106+ G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
2107+ NULL,
2108+ S_NAME,
2109+ S_PATH,
2110+ S_IFACE,
2111+ NULL,
2112+ on_proxy_ready_cb,
2113+ data);
2114+
2115+ return false;
2116+}
2117+
2118+static void
2119+on_proxy_ready_cb (GObject *source,
2120+ GAsyncResult *res,
2121+ gpointer data)
2122+{
2123+ IndicatorObjectFactoryRemote *remote = static_cast<IndicatorObjectFactoryRemote *> (data);
2124+ GDBusProxy *proxy;
2125+ GError *error = NULL;
2126+ static bool force_tried = false;
2127+ char *name_owner;
2128+
2129+ proxy = g_dbus_proxy_new_for_bus_finish (res, &error);
2130+ name_owner = g_dbus_proxy_get_name_owner (proxy);
2131+
2132+ if (G_IS_DBUS_PROXY (proxy) && name_owner)
2133+ {
2134+ remote->OnRemoteProxyReady (G_DBUS_PROXY (proxy));
2135+ g_free (name_owner);
2136+ return;
2137+ }
2138+ else
2139+ {
2140+ if (force_tried)
2141+ {
2142+ printf ("\nWARNING: Unable to connect to the unity-panel-service %s\n",
2143+ error ? error->message : "Unknown");
2144+ if (error)
2145+ g_error_free (error);
2146+ }
2147+ else
2148+ {
2149+ force_tried = true;
2150+ run_local_panel_service ();
2151+
2152+ g_timeout_add_seconds (2, (GSourceFunc)reconnect_to_service, remote);
2153+ }
2154+ }
2155+
2156+ g_object_unref (proxy);
2157+}
2158+
2159+static bool
2160+run_local_panel_service ()
2161+{
2162+ GError *error = NULL;
2163+
2164+ // This is obviously hackish, but this part of the code is mostly hackish...
2165+ // Let's attempt to run it from where we expect it to be
2166+ char *cmd = g_strdup_printf ("%s/lib/unity/unity-panel-service", PREFIXDIR);
2167+ printf ("\nWARNING: Couldn't load panel from installed services, so trying to"
2168+ "load panel from known location: %s\n", cmd);
2169+
2170+ g_spawn_command_line_async (cmd, &error);
2171+ g_free (cmd);
2172+
2173+ if (error)
2174+ {
2175+ printf ("\nWARNING: Unable to launch remote service manually: %s\n", error->message);
2176+ g_error_free (error);
2177+ return false;
2178+ }
2179+ return true;
2180+}
2181+
2182+static void
2183+on_proxy_signal_received (GDBusProxy *proxy,
2184+ gchar *sender_name,
2185+ gchar *signal_name,
2186+ GVariant *parameters,
2187+ IndicatorObjectFactoryRemote *remote)
2188+{
2189+ if (g_strcmp0 (signal_name, "EntryActivated") == 0)
2190+ {
2191+ remote->OnEntryActivated (g_variant_get_string (g_variant_get_child_value (parameters, 0), NULL));
2192+ }
2193+ else if (g_strcmp0 (signal_name, "EntryActivateRequest") == 0)
2194+ {
2195+ remote->OnEntryActivateRequestReceived (g_variant_get_string (g_variant_get_child_value (parameters, 0), NULL));
2196+ }
2197+ else if (g_strcmp0 (signal_name, "ReSync") == 0)
2198+ {
2199+ const gchar *id = g_variant_get_string (g_variant_get_child_value (parameters, 0), NULL);
2200+ bool sync_one = !g_strcmp0 (id, "") == 0;
2201+
2202+ g_dbus_proxy_call (proxy,
2203+ sync_one ? "SyncOne" : "Sync",
2204+ sync_one ? g_variant_new ("(s)", id) : NULL,
2205+ G_DBUS_CALL_FLAGS_NONE,
2206+ -1,
2207+ NULL,
2208+ on_sync_ready_cb,
2209+ remote);
2210+ }
2211+ else if (g_strcmp0 (signal_name, "ActiveMenuPointerMotion") == 0)
2212+ {
2213+ int x=0, y=0;
2214+
2215+ g_variant_get (parameters, "(ii)", &x, &y);
2216+
2217+ remote->OnMenuPointerMoved.emit (x, y);
2218+ }
2219+}
2220+
2221+static void
2222+on_sync_ready_cb (GObject *source,
2223+ GAsyncResult *res,
2224+ gpointer data)
2225+{
2226+ IndicatorObjectFactoryRemote *remote = static_cast<IndicatorObjectFactoryRemote *> (data);
2227+ GVariant *args;
2228+ GError *error = NULL;
2229+
2230+ args = g_dbus_proxy_call_finish ((GDBusProxy*)source, res, &error);
2231+
2232+ if (args == NULL)
2233+ {
2234+ g_warning ("Unable to perform Sync() on panel service: %s", error->message);
2235+ g_error_free (error);
2236+ return;
2237+ }
2238+
2239+ remote->Sync (args);
2240+
2241+ g_variant_unref (args);
2242+}
2243
2244=== added file 'plugins/unityshell/src/IndicatorObjectFactoryRemote.h'
2245--- plugins/unityshell/src/IndicatorObjectFactoryRemote.h 1970-01-01 00:00:00 +0000
2246+++ plugins/unityshell/src/IndicatorObjectFactoryRemote.h 2010-12-13 12:41:23 +0000
2247@@ -0,0 +1,55 @@
2248+/*
2249+ * Copyright (C) 2010 Canonical Ltd
2250+ *
2251+ * This program is free software: you can redistribute it and/or modify
2252+ * it under the terms of the GNU General Public License version 3 as
2253+ * published by the Free Software Foundation.
2254+ *
2255+ * This program is distributed in the hope that it will be useful,
2256+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2257+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2258+ * GNU General Public License for more details.
2259+ *
2260+ * You should have received a copy of the GNU General Public License
2261+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2262+ *
2263+ * Authored by: Neil Jagdish Patel <neil.patel@canonical.com>
2264+ */
2265+
2266+#ifndef INDICATOR_OBJECT_FACTORY_REMOTE_H
2267+#define INDICATOR_OBJECT_FACTORY_REMOTE_H
2268+
2269+#include <string>
2270+#include <gio/gio.h>
2271+#include <dee.h>
2272+
2273+#include "IndicatorObjectFactory.h"
2274+#include "IndicatorObjectProxyRemote.h"
2275+
2276+// Connects to the remote panel service (unity-panel-service) and translates
2277+// that into something that the panel can show
2278+class IndicatorObjectFactoryRemote : public IndicatorObjectFactory
2279+{
2280+public:
2281+
2282+ IndicatorObjectFactoryRemote ();
2283+ ~IndicatorObjectFactoryRemote ();
2284+
2285+ virtual std::vector<IndicatorObjectProxy *> &GetIndicatorObjects ();
2286+ virtual void ForceRefresh ();
2287+
2288+ void OnRemoteProxyReady (GDBusProxy *proxy);
2289+ void OnEntryActivated (const char *entry_id);
2290+ void OnShowMenuRequestReceived (const char *id, int x, int y, guint timestamp, guint32 button);
2291+ void Sync (GVariant *args);
2292+ void OnEntryActivateRequestReceived (const char *entry_id);
2293+
2294+ void AddProperties (GVariantBuilder *builder);
2295+
2296+private:
2297+ IndicatorObjectProxyRemote* IndicatorForID (const char *id);
2298+private:
2299+ GDBusProxy *_proxy;
2300+};
2301+
2302+#endif // INDICATOR_OBJECT_FACTORY_REMOTE_H
2303
2304=== added file 'plugins/unityshell/src/IndicatorObjectProxy.h'
2305--- plugins/unityshell/src/IndicatorObjectProxy.h 1970-01-01 00:00:00 +0000
2306+++ plugins/unityshell/src/IndicatorObjectProxy.h 2010-12-13 12:41:23 +0000
2307@@ -0,0 +1,48 @@
2308+/*
2309+ * Copyright (C) 2010 Canonical Ltd
2310+ *
2311+ * This program is free software: you can redistribute it and/or modify
2312+ * it under the terms of the GNU General Public License version 3 as
2313+ * published by the Free Software Foundation.
2314+ *
2315+ * This program is distributed in the hope that it will be useful,
2316+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2317+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2318+ * GNU General Public License for more details.
2319+ *
2320+ * You should have received a copy of the GNU General Public License
2321+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2322+ *
2323+ * Authored by: Neil Jagdish Patel <neil.patel@canonical.com>
2324+ */
2325+
2326+#ifndef INDICATOR_OBJECT_PROXY_H
2327+#define INDICATOR_OBJECT_PROXY_H
2328+
2329+#include <string>
2330+#include <vector>
2331+#include <sigc++/signal.h>
2332+#include <sigc++/sigc++.h>
2333+
2334+#include "IndicatorObjectEntryProxy.h"
2335+
2336+class IndicatorObjectProxy : public sigc::trackable
2337+{
2338+public:
2339+
2340+ // The name of the indicator that this proxy represents
2341+ virtual std::string& GetName () = 0;
2342+
2343+ // The current list of IndicatorObjectEntryProxys
2344+ virtual std::vector<IndicatorObjectEntryProxy *>& GetEntries () = 0;
2345+
2346+ // Signals
2347+ sigc::signal<void, IndicatorObjectEntryProxy *> OnEntryAdded;
2348+ sigc::signal<void, IndicatorObjectEntryProxy *> OnEntryRemoved;
2349+ sigc::signal<void, IndicatorObjectEntryProxy *> OnEntryMoved;
2350+
2351+protected:
2352+ std::vector<IndicatorObjectEntryProxy *> _entries;
2353+};
2354+
2355+#endif // INDICATOR_OBJECT_PROXY_H
2356
2357=== added file 'plugins/unityshell/src/IndicatorObjectProxyRemote.cpp'
2358--- plugins/unityshell/src/IndicatorObjectProxyRemote.cpp 1970-01-01 00:00:00 +0000
2359+++ plugins/unityshell/src/IndicatorObjectProxyRemote.cpp 2010-12-13 12:41:23 +0000
2360@@ -0,0 +1,145 @@
2361+/*
2362+ * Copyright (C) 2010 Canonical Ltd
2363+ *
2364+ * This program is free software: you can redistribute it and/or modify
2365+ * it under the terms of the GNU General Public License version 3 as
2366+ * published by the Free Software Foundation.
2367+ *
2368+ * This program is distributed in the hope that it will be useful,
2369+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2370+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2371+ * GNU General Public License for more details.
2372+ *
2373+ * You should have received a copy of the GNU General Public License
2374+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2375+ *
2376+ * Authored by: Neil Jagdish Patel <neil.patel@canonical.com>
2377+ */
2378+
2379+#include "IndicatorObjectProxyRemote.h"
2380+
2381+#include "IndicatorObjectEntryProxyRemote.h"
2382+
2383+IndicatorObjectProxyRemote::IndicatorObjectProxyRemote (const char *name)
2384+: _name (name)
2385+{
2386+}
2387+
2388+IndicatorObjectProxyRemote::~IndicatorObjectProxyRemote ()
2389+{
2390+ std::vector<IndicatorObjectEntryProxy*>::iterator it;
2391+
2392+ for (it = _entries.begin(); it != _entries.end(); it++)
2393+ {
2394+ IndicatorObjectEntryProxyRemote *remote = static_cast<IndicatorObjectEntryProxyRemote *> (*it);
2395+ delete remote;
2396+ }
2397+
2398+ _entries.erase (_entries.begin (), _entries.end ());
2399+}
2400+
2401+std::string&
2402+IndicatorObjectProxyRemote::GetName ()
2403+{
2404+ return _name;
2405+}
2406+
2407+std::vector<IndicatorObjectEntryProxy *>&
2408+IndicatorObjectProxyRemote::GetEntries ()
2409+{
2410+ return _entries;
2411+}
2412+
2413+
2414+void
2415+IndicatorObjectProxyRemote::BeginSync ()
2416+{
2417+ std::vector<IndicatorObjectEntryProxy*>::iterator it;
2418+
2419+ for (it = _entries.begin(); it != _entries.end(); it++)
2420+ {
2421+ IndicatorObjectEntryProxyRemote *remote = static_cast<IndicatorObjectEntryProxyRemote *> (*it);
2422+ remote->_dirty = true;
2423+ }
2424+}
2425+
2426+void
2427+IndicatorObjectProxyRemote::AddEntry (const gchar *entry_id,
2428+ const gchar *label,
2429+ bool label_sensitive,
2430+ bool label_visible,
2431+ guint32 image_type,
2432+ const gchar *image_data,
2433+ bool image_sensitive,
2434+ bool image_visible)
2435+{
2436+ IndicatorObjectEntryProxyRemote *remote = NULL;
2437+ std::vector<IndicatorObjectEntryProxy*>::iterator it;
2438+
2439+ for (it = _entries.begin(); it != _entries.end(); it++)
2440+ {
2441+ IndicatorObjectEntryProxyRemote *r = static_cast<IndicatorObjectEntryProxyRemote *> (*it);
2442+ if (r->_dirty == true)
2443+ {
2444+ remote = r;
2445+ break;
2446+ }
2447+ }
2448+
2449+ /* Create a new one */
2450+ if (remote == NULL)
2451+ {
2452+ remote = new IndicatorObjectEntryProxyRemote ();
2453+ remote->OnShowMenuRequest.connect (sigc::mem_fun (this,
2454+ &IndicatorObjectProxyRemote::OnShowMenuRequestReceived));
2455+ _entries.push_back (remote);
2456+ }
2457+
2458+ remote->Refresh (entry_id,
2459+ label,
2460+ label_sensitive,
2461+ label_visible,
2462+ image_type,
2463+ image_data,
2464+ image_sensitive,
2465+ image_visible);
2466+ if (remote->_dirty)
2467+ remote->_dirty = false;
2468+ else
2469+ OnEntryAdded.emit (remote);
2470+}
2471+
2472+void
2473+IndicatorObjectProxyRemote::EndSync ()
2474+{
2475+ std::vector<IndicatorObjectEntryProxy*>::iterator it;
2476+
2477+ for (it = _entries.begin(); it != _entries.end(); it++)
2478+ {
2479+ IndicatorObjectEntryProxyRemote *remote = static_cast<IndicatorObjectEntryProxyRemote *> (*it);
2480+ if (remote->_dirty == true)
2481+ {
2482+ /* We don't get rid of the entries as there's no real need to, and it saves us
2483+ * having to do a bunch of object creation everytime the menu changes
2484+ */
2485+ remote->Refresh ("|",
2486+ "",
2487+ false,
2488+ false,
2489+ 0,
2490+ "",
2491+ false,
2492+ false);
2493+ }
2494+ }
2495+}
2496+
2497+void
2498+IndicatorObjectProxyRemote::OnShowMenuRequestReceived (const char *entry_id,
2499+ int x,
2500+ int y,
2501+ guint32 timestamp,
2502+ guint32 button)
2503+{
2504+ OnShowMenuRequest.emit (entry_id, x, y, timestamp, button);
2505+}
2506
2507=== added file 'plugins/unityshell/src/IndicatorObjectProxyRemote.h'
2508--- plugins/unityshell/src/IndicatorObjectProxyRemote.h 1970-01-01 00:00:00 +0000
2509+++ plugins/unityshell/src/IndicatorObjectProxyRemote.h 2010-12-13 12:41:23 +0000
2510@@ -0,0 +1,60 @@
2511+/*
2512+ * Copyright (C) 2010 Canonical Ltd
2513+ *
2514+ * This program is free software: you can redistribute it and/or modify
2515+ * it under the terms of the GNU General Public License version 3 as
2516+ * published by the Free Software Foundation.
2517+ *
2518+ * This program is distributed in the hope that it will be useful,
2519+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2520+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2521+ * GNU General Public License for more details.
2522+ *
2523+ * You should have received a copy of the GNU General Public License
2524+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2525+ *
2526+ * Authored by: Neil Jagdish Patel <neil.patel@canonical.com>
2527+ */
2528+
2529+#ifndef INDICATOR_OBJECT_PROXY_REMOTE_H
2530+#define INDICATOR_OBJECT_PROXY_REMOTE_H
2531+
2532+#include <string>
2533+#include <gio/gio.h>
2534+#include <dee.h>
2535+
2536+#include "IndicatorObjectProxy.h"
2537+
2538+// Represents an IndicatorObject over DBus through the panel service
2539+
2540+class IndicatorObjectProxyRemote : public IndicatorObjectProxy
2541+{
2542+public:
2543+
2544+ IndicatorObjectProxyRemote (const char *name);
2545+ ~IndicatorObjectProxyRemote ();
2546+
2547+ virtual std::string& GetName ();
2548+ virtual std::vector<IndicatorObjectEntryProxy *>& GetEntries ();
2549+
2550+ void BeginSync ();
2551+ void AddEntry (const gchar *entry_id,
2552+ const gchar *label,
2553+ bool label_sensitive,
2554+ bool label_visible,
2555+ guint32 image_type,
2556+ const gchar *image_data,
2557+ bool image_sensitive,
2558+ bool image_visible);
2559+ void EndSync ();
2560+
2561+ void OnShowMenuRequestReceived (const char *id, int x, int y, guint timestamp, guint32 button);
2562+
2563+ // Signals
2564+ sigc::signal<void, const char *, int, int, guint32, guint32> OnShowMenuRequest;
2565+
2566+private:
2567+ std::string _name;
2568+};
2569+
2570+#endif // INDICATOR_OBJECT_PROXY_REMOTE_H
2571
2572=== added file 'plugins/unityshell/src/Introspectable.cpp'
2573--- plugins/unityshell/src/Introspectable.cpp 1970-01-01 00:00:00 +0000
2574+++ plugins/unityshell/src/Introspectable.cpp 2010-12-13 12:41:23 +0000
2575@@ -0,0 +1,75 @@
2576+/*
2577+ * Copyright (C) 2010 Canonical Ltd
2578+ *
2579+ * This program is free software: you can redistribute it and/or modify
2580+ * it under the terms of the GNU General Public License version 3 as
2581+ * published by the Free Software Foundation.
2582+ *
2583+ * This program is distributed in the hope that it will be useful,
2584+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2585+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2586+ * GNU General Public License for more details.
2587+ *
2588+ * You should have received a copy of the GNU General Public License
2589+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2590+ *
2591+ * Authored by: Alex Launi <alex.launi@canonical.com>
2592+ */
2593+
2594+#include "Introspectable.h"
2595+
2596+GVariant*
2597+Introspectable::Introspect ()
2598+{
2599+ GVariantBuilder *builder;
2600+ GVariant *result;
2601+ GVariantBuilder *child_builder;
2602+ gint n_children = 0;
2603+
2604+ builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
2605+
2606+ AddProperties (builder);
2607+
2608+ child_builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
2609+
2610+ for (std::list<Introspectable *>::iterator it = _children.begin (); it != _children.end (); it++)
2611+ {
2612+ if ((*it)->GetName ())
2613+ {
2614+ g_variant_builder_add (child_builder, "{sv}", (*it)->GetName (), (*it)->Introspect () );
2615+ n_children++;
2616+ }
2617+ }
2618+
2619+ if (n_children > 0)
2620+ {
2621+ GVariant *child_results;
2622+
2623+ child_results = g_variant_new ("(a{sv})", child_builder);
2624+ g_variant_builder_add (builder, "{sv}", GetChildsName (), child_results);
2625+ }
2626+ g_variant_builder_unref (child_builder);
2627+
2628+ result = g_variant_new ("(a{sv})", builder);
2629+ g_variant_builder_unref (builder);
2630+
2631+ return result;
2632+}
2633+
2634+void
2635+Introspectable::AddChild (Introspectable *child)
2636+{
2637+ _children.push_back (child);
2638+}
2639+
2640+void
2641+Introspectable::RemoveChild (Introspectable *child)
2642+{
2643+ _children.remove (child);
2644+}
2645+
2646+const gchar *
2647+Introspectable::GetChildsName ()
2648+{
2649+ return GetName ();
2650+}
2651
2652=== added file 'plugins/unityshell/src/Introspectable.h'
2653--- plugins/unityshell/src/Introspectable.h 1970-01-01 00:00:00 +0000
2654+++ plugins/unityshell/src/Introspectable.h 2010-12-13 12:41:23 +0000
2655@@ -0,0 +1,55 @@
2656+/*
2657+ * Copyright (C) 2010 Canonical Ltd
2658+ *
2659+ * This program is free software: you can redistribute it and/or modify
2660+ * it under the terms of the GNU General Public License version 3 as
2661+ * published by the Free Software Foundation.
2662+ *
2663+ * This program is distributed in the hope that it will be useful,
2664+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2665+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2666+ * GNU General Public License for more details.
2667+ *
2668+ * You should have received a copy of the GNU General Public License
2669+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2670+ *
2671+ * Authored by: Alex Launi <alex.launi@canonical.com>
2672+ */
2673+
2674+#ifndef _INTROSPECTABLE_H
2675+#define _INTROSPECTABLE_H 1
2676+
2677+#include <glib.h>
2678+#include <list>
2679+
2680+class Introspectable
2681+{
2682+public:
2683+ GVariant *Introspect ();
2684+ void AddChild (Introspectable *child);
2685+ void RemoveChild (Introspectable *child);
2686+
2687+protected:
2688+ virtual const gchar *GetName () = 0;
2689+ virtual const gchar *GetChildsName ();
2690+ virtual void AddProperties (GVariantBuilder *builder) = 0;
2691+ /*
2692+ * AddProperties should be implemented as such ...
2693+ * void ClassFoo::AddProperties (GVariantBuilder *builder)
2694+ * {
2695+ * g_variant_builder_add (builder, "{sv}", "label", g_variant_new_string ("_File") );
2696+ * g_variant_builder_add (builder, "{sv}", "image", g_variant_new_string ("") );
2697+ * g_variant_builder_add (builder, "{sv}", "visible", g_variant_new_boolean (TRUE) );
2698+ * g_variant_builder_add (builder, "{sv}", "sensitive", g_variant_new_boolean (TRUE) );
2699+ * g_variant_builder_add (builder, "{sv}", "active", g_variant_new_boolean (FALSE) );
2700+ * g_variant_builder_add (builder, "{sv}", "label", g_variant_new_int32 (34) );
2701+ * g_variant_builder_add (builder, "{sv}", "label", g_variant_new_int32 (24) );
2702+ * }
2703+ * That's all. Just add a bunch of key-value properties to the builder.
2704+ */
2705+
2706+private:
2707+ std::list<Introspectable *> _children;
2708+};
2709+
2710+#endif
2711
2712=== added file 'plugins/unityshell/src/IntrospectionDBusInterface.cpp'
2713--- plugins/unityshell/src/IntrospectionDBusInterface.cpp 1970-01-01 00:00:00 +0000
2714+++ plugins/unityshell/src/IntrospectionDBusInterface.cpp 2010-12-13 12:41:23 +0000
2715@@ -0,0 +1,223 @@
2716+/*
2717+ * Copyright (C) 2010 Canonical Ltd
2718+ *
2719+ * This program is free software: you can redistribute it and/or modify
2720+ * it under the terms of the GNU General Public License version 3 as
2721+ * published by the Free Software Foundation.
2722+ *
2723+ * This program is distributed in the hope that it will be useful,
2724+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2725+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2726+ * GNU General Public License for more details.
2727+ *
2728+ * You should have received a copy of the GNU General Public License
2729+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2730+ *
2731+ * Authored by: Alex Launi <alex.launi@canonical.com>
2732+ */
2733+
2734+#include "IntrospectionDBusInterface.h"
2735+
2736+#define UNITY_STATE_DEBUG_BUS_NAME "com.canonical.Unity"
2737+
2738+void DBusMethodCall (GDBusConnection*, const gchar*, const gchar*,
2739+ const gchar*, const gchar*, GVariant*,
2740+ GDBusMethodInvocation*, gpointer);
2741+GVariant* GetState (const gchar*);
2742+
2743+static const GDBusInterfaceVTable si_vtable =
2744+{
2745+ &DBusMethodCall,
2746+ NULL,
2747+ NULL
2748+};
2749+
2750+static const GDBusArgInfo si_getstate_in_args =
2751+{
2752+ -1,
2753+ "piece",
2754+ "s",
2755+ NULL
2756+};
2757+static const GDBusArgInfo *const si_getstate_in_arg_pointers[] = { &si_getstate_in_args, NULL };
2758+
2759+// TODO: this is really a a{sv} or something like that.
2760+static const GDBusArgInfo si_getstate_out_args =
2761+{
2762+ -1,
2763+ "state",
2764+ "a{sv}",
2765+ NULL
2766+};
2767+static const GDBusArgInfo *const si_getstate_out_arg_pointers[] = { &si_getstate_out_args, NULL };
2768+
2769+static const GDBusMethodInfo si_method_info_getstate =
2770+{
2771+ -1,
2772+ "GetState",
2773+ (GDBusArgInfo **) &si_getstate_in_arg_pointers,
2774+ (GDBusArgInfo **) &si_getstate_out_arg_pointers,
2775+ NULL
2776+};
2777+
2778+static const GDBusMethodInfo *const si_method_info_pointers[] = { &si_method_info_getstate, NULL };
2779+
2780+static const GDBusInterfaceInfo si_iface_info =
2781+{
2782+ -1,
2783+ "com.canonical.Unity.Debug.Introspection",
2784+ (GDBusMethodInfo **) &si_method_info_pointers,
2785+ NULL,
2786+ NULL,
2787+ NULL,
2788+};
2789+
2790+static Introspectable *_introspectable;
2791+
2792+IntrospectionDBusInterface::IntrospectionDBusInterface (Introspectable *introspectable)
2793+{
2794+ _introspectable = introspectable;
2795+ _owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
2796+ UNITY_STATE_DEBUG_BUS_NAME,
2797+ G_BUS_NAME_OWNER_FLAGS_NONE,
2798+ &IntrospectionDBusInterface::OnBusAcquired,
2799+ &IntrospectionDBusInterface::OnNameAcquired,
2800+ &IntrospectionDBusInterface::OnNameLost,
2801+ this,
2802+ NULL);
2803+}
2804+
2805+IntrospectionDBusInterface::~IntrospectionDBusInterface ()
2806+{
2807+ g_bus_unown_name (_owner_id);
2808+}
2809+
2810+void
2811+IntrospectionDBusInterface::OnBusAcquired (GDBusConnection *connection, const gchar *name, gpointer data)
2812+{
2813+ GError *error = NULL;
2814+ g_dbus_connection_register_object (connection,
2815+ "/com/canonical/Unity/Debug/Introspection",
2816+ (GDBusInterfaceInfo *) &si_iface_info,
2817+ &si_vtable,
2818+ NULL,
2819+ NULL,
2820+ &error);
2821+ if (error != NULL)
2822+ {
2823+ g_warning ("Could not register Introspection object onto d-bus");
2824+ g_error_free (error);
2825+ }
2826+}
2827+
2828+void
2829+IntrospectionDBusInterface::OnNameAcquired (GDBusConnection *connection, const gchar *name, gpointer data)
2830+{
2831+}
2832+
2833+void
2834+IntrospectionDBusInterface::OnNameLost (GDBusConnection *connection, const gchar *name, gpointer data)
2835+{
2836+}
2837+
2838+void
2839+DBusMethodCall (GDBusConnection *connection,
2840+ const gchar *sender,
2841+ const gchar *objectPath,
2842+ const gchar *ifaceName,
2843+ const gchar *methodName,
2844+ GVariant *parameters,
2845+ GDBusMethodInvocation *invocation,
2846+ gpointer data)
2847+{
2848+ if (g_strcmp0 (methodName, "GetState") == 0)
2849+ {
2850+ GVariant *ret;
2851+ const gchar *input;
2852+ g_variant_get (parameters, "(&s)", &input);
2853+
2854+ ret = GetState (input);
2855+ g_dbus_method_invocation_return_value (invocation, ret);
2856+ g_variant_unref (ret);
2857+ }
2858+ else
2859+ {
2860+ g_dbus_method_invocation_return_dbus_error (invocation, "com.canonical.Unity",
2861+ "Failed to find method");
2862+ }
2863+}
2864+
2865+GVariant*
2866+GetState (const gchar *piece)
2867+{
2868+ return _introspectable->Introspect ();
2869+}
2870+
2871+/* a very contrived example purely for giving QA something purposes */
2872+GVariant*
2873+IntrospectionDBusInterface::BuildFakeReturn ()
2874+{
2875+ GVariantBuilder *builder;
2876+ GVariant *result, *panel_result, *indicators_result, *appmenu_result, *entries_result, *zero_result, *one_result;
2877+
2878+ builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}") );
2879+ g_variant_builder_add (builder, "{sv}", "label", g_variant_new_string ("_File") );
2880+ g_variant_builder_add (builder, "{sv}", "image", g_variant_new_string ("") );
2881+ g_variant_builder_add (builder, "{sv}", "visible", g_variant_new_boolean (TRUE) );
2882+ g_variant_builder_add (builder, "{sv}", "sensitive", g_variant_new_boolean (TRUE) );
2883+ g_variant_builder_add (builder, "{sv}", "active", g_variant_new_boolean (FALSE) );
2884+ g_variant_builder_add (builder, "{sv}", "label", g_variant_new_int32 (34) );
2885+ g_variant_builder_add (builder, "{sv}", "label", g_variant_new_int32 (24) );
2886+ zero_result = g_variant_new ("(a{sv})", builder);
2887+ g_variant_builder_unref (builder);
2888+
2889+ builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}") );
2890+ g_variant_builder_add (builder, "{sv}", "label", g_variant_new_string ("_Edit") );
2891+ g_variant_builder_add (builder, "{sv}", "image", g_variant_new_string ("") );
2892+ g_variant_builder_add (builder, "{sv}", "visible", g_variant_new_boolean (TRUE) );
2893+ g_variant_builder_add (builder, "{sv}", "sensitive", g_variant_new_boolean (TRUE) );
2894+ g_variant_builder_add (builder, "{sv}", "active", g_variant_new_boolean (FALSE) );
2895+ g_variant_builder_add (builder, "{sv}", "label", g_variant_new_int32 (34) );
2896+ g_variant_builder_add (builder, "{sv}", "label", g_variant_new_int32 (24) );
2897+ one_result = g_variant_new ("(a{sv})", builder);
2898+ g_variant_builder_unref (builder);
2899+
2900+ builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}") );
2901+ g_variant_builder_add (builder, "{sv}", "0", zero_result);
2902+ g_variant_builder_add (builder, "{sv}", "1", one_result);
2903+ entries_result = g_variant_new ("(a{sv})", builder);
2904+ g_variant_builder_unref (builder);
2905+
2906+ builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}") );
2907+ g_variant_builder_add (builder, "{sv}", "model-name",
2908+ g_variant_new_string ("com.canonical.Unity.Panel.Service.Indicators.appmenu.324234243") );
2909+ g_variant_builder_add (builder, "{sv}", "entries", entries_result);
2910+ appmenu_result = g_variant_new ("(a{sv})", builder);
2911+ g_variant_builder_unref (builder);
2912+
2913+ builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}") );
2914+ g_variant_builder_add (builder, "{sv}", "appmenu", appmenu_result);
2915+ indicators_result = g_variant_new ("(a{sv})", builder);
2916+ g_variant_builder_unref (builder);
2917+
2918+ builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}") );
2919+ g_variant_builder_add (builder, "{sv}", "backend",
2920+ g_variant_new_string ("/com/canonical/Unity/Panel/Service/324234243") );
2921+ g_variant_builder_add (builder, "{sv}", "launch-type",
2922+ g_variant_new_string ("dbus") );
2923+ g_variant_builder_add (builder, "{sv}", "width", g_variant_new_int32 (1024) );
2924+ g_variant_builder_add (builder, "{sv}", "width", g_variant_new_int32 (32) );
2925+ g_variant_builder_add (builder, "{sv}", "theme", g_variant_new_string ("gtk") );
2926+ g_variant_builder_add (builder, "{sv}", "indicators", indicators_result);
2927+ panel_result = g_variant_new ("(a{sv})", builder);
2928+ g_variant_builder_unref (builder);
2929+
2930+ builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}") );
2931+ g_variant_builder_add (builder, "{sv}", "panel", panel_result);
2932+ result = g_variant_new ("(a{sv})", builder);
2933+ g_variant_builder_unref (builder);
2934+
2935+ gchar *s = g_variant_print (result, TRUE);
2936+ g_free (s);
2937+ return result;
2938+}
2939
2940=== added file 'plugins/unityshell/src/IntrospectionDBusInterface.h'
2941--- plugins/unityshell/src/IntrospectionDBusInterface.h 1970-01-01 00:00:00 +0000
2942+++ plugins/unityshell/src/IntrospectionDBusInterface.h 2010-12-13 12:41:23 +0000
2943@@ -0,0 +1,54 @@
2944+/*
2945+ * Copyright (C) 2010 Canonical Ltd
2946+ *
2947+ * This program is free software: you can redistribute it and/or modify
2948+ * it under the terms of the GNU General Public License version 3 as
2949+ * published by the Free Software Foundation.
2950+ *
2951+ * This program is distributed in the hope that it will be useful,
2952+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2953+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2954+ * GNU General Public License for more details.
2955+ *
2956+ * You should have received a copy of the GNU General Public License
2957+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2958+ *
2959+ * Authored by: Alex Launi <alex.launi@canonical.com>
2960+ */
2961+
2962+#ifndef _STATE_INTROSPECTION_DBUS_INTERFACE_H
2963+#define _STATE_INTROSPECTION_DBUS_INTERFACE_H 1
2964+
2965+#include <glib.h>
2966+#include <gio/gio.h>
2967+#include "Introspectable.h"
2968+
2969+class IntrospectionDBusInterface
2970+{
2971+public:
2972+ IntrospectionDBusInterface (Introspectable *introspectable);
2973+ ~IntrospectionDBusInterface ();
2974+
2975+ /*static void DBusMethodCall (GDBusConnection *connection, const gchar *sender,
2976+ const gchar *objectPath, const gchar *ifaceName,
2977+ const gchar *methodName, GVariant *parameters,
2978+ GDBusMethodInvocation *invocation, gpointer data); */
2979+
2980+private:
2981+ /* methods */
2982+
2983+ static void OnBusAcquired (GDBusConnection *connection, const gchar *name, gpointer data);
2984+
2985+ static void OnNameAcquired (GDBusConnection *connection, const gchar *name, gpointer data);
2986+
2987+ static void OnNameLost (GDBusConnection *connection, const gchar *name, gpointer data);
2988+
2989+ //static GVariant *GetState (const char *piece);
2990+
2991+ static GVariant *BuildFakeReturn ();
2992+
2993+ /* members */
2994+ guint _owner_id;
2995+};
2996+
2997+#endif
2998
2999=== added file 'plugins/unityshell/src/Launcher.cpp'
3000--- plugins/unityshell/src/Launcher.cpp 1970-01-01 00:00:00 +0000
3001+++ plugins/unityshell/src/Launcher.cpp 2010-12-13 12:41:23 +0000
3002@@ -0,0 +1,2075 @@
3003+/*
3004+ * Copyright (C) 2010 Canonical Ltd
3005+ *
3006+ * This program is free software: you can redistribute it and/or modify
3007+ * it under the terms of the GNU General Public License version 3 as
3008+ * published by the Free Software Foundation.
3009+ *
3010+ * This program is distributed in the hope that it will be useful,
3011+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3012+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3013+ * GNU General Public License for more details.
3014+ *
3015+ * You should have received a copy of the GNU General Public License
3016+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3017+ *
3018+ * Authored by: Jason Smith <jason.smith@canonical.com>
3019+ * Authored by: Jay Taoko <jay.taoko@canonical.com>
3020+ */
3021+
3022+#include <math.h>
3023+
3024+#include "Nux/Nux.h"
3025+#include "Nux/VScrollBar.h"
3026+#include "Nux/HLayout.h"
3027+#include "Nux/VLayout.h"
3028+#include "Nux/MenuPage.h"
3029+
3030+#include "NuxGraphics/NuxGraphics.h"
3031+#include "NuxGraphics/GpuDevice.h"
3032+#include "NuxGraphics/GLTextureResourceManager.h"
3033+
3034+#include "Nux/BaseWindow.h"
3035+#include "Nux/WindowCompositor.h"
3036+
3037+#include "Launcher.h"
3038+#include "LauncherIcon.h"
3039+#include "LauncherModel.h"
3040+#include "QuicklistManager.h"
3041+#include "QuicklistView.h"
3042+
3043+#define ANIM_DURATION_SHORT 125
3044+#define ANIM_DURATION 200
3045+#define ANIM_DURATION_LONG 350
3046+
3047+#define URGENT_BLINKS 3
3048+
3049+#define MAX_STARTING_BLINKS 5
3050+#define STARTING_BLINK_LAMBDA 3
3051+
3052+#define BACKLIGHT_STRENGTH 0.9f
3053+
3054+int
3055+TimeDelta (struct timespec const *x, struct timespec const *y)
3056+{
3057+ return ((x->tv_sec - y->tv_sec) * 1000) + ((x->tv_nsec - y->tv_nsec) / 1000000);
3058+}
3059+
3060+static bool USE_ARB_SHADERS = true;
3061+/*
3062+ Use this shader to pass vertices in screen coordinates in the C++ code and compute use
3063+ the fragment shader to perform the texture perspective correct division.
3064+ This shader assume the following:
3065+ - the projection matrix is orthogonal: glOrtho(0, ScreenWidth, ScreenWidth, 0, Near, Far)
3066+ - vertices x and y are in screen coordinates: Vertex(x_screen, y_screen, 0, 1.0)
3067+ - the vertices w coordinates has been computed 'manually'
3068+ - vertices uv textture coordinates are passed to the shader as: (u/w, v/w, 0, 1/w)
3069+
3070+ The texture coordinates s=u/w, t=v/w and q=1w are interpolated linearly in screen coordinates.
3071+ In the fragment shader we get the texture coordinates used for the sampling by dividing
3072+ s and t resulting from the interpolation by q.
3073+
3074+ */
3075+
3076+nux::NString gPerspectiveCorrectShader = TEXT (
3077+"[Vertex Shader] \n\
3078+#version 120 \n\
3079+uniform mat4 ViewProjectionMatrix; \n\
3080+ \n\
3081+attribute vec4 iColor; \n\
3082+attribute vec4 iTexCoord0; \n\
3083+attribute vec4 iVertex; \n\
3084+ \n\
3085+varying vec4 varyTexCoord0; \n\
3086+varying vec4 varyVertexColor; \n\
3087+ \n\
3088+void main() \n\
3089+{ \n\
3090+ varyTexCoord0 = iTexCoord0; \n\
3091+ varyVertexColor = iColor; \n\
3092+ gl_Position = ViewProjectionMatrix * iVertex; \n\
3093+} \n\
3094+ \n\
3095+[Fragment Shader] \n\
3096+#version 120 \n\
3097+#extension GL_ARB_texture_rectangle : enable \n\
3098+ \n\
3099+varying vec4 varyTexCoord0; \n\
3100+varying vec4 varyVertexColor; \n\
3101+ \n\
3102+uniform sampler2D TextureObject0; \n\
3103+uniform vec4 color0; \n\
3104+vec4 SampleTexture(sampler2D TexObject, vec4 TexCoord) \n\
3105+{ \n\
3106+ return texture2D(TexObject, TexCoord.st); \n\
3107+} \n\
3108+ \n\
3109+void main() \n\
3110+{ \n\
3111+ vec4 tex = varyTexCoord0; \n\
3112+ tex.s = tex.s/varyTexCoord0.w; \n\
3113+ tex.t = tex.t/varyTexCoord0.w; \n\
3114+ \n\
3115+ vec4 texel = SampleTexture(TextureObject0, tex); \n\
3116+ gl_FragColor = texel*varyVertexColor; \n\
3117+} \n\
3118+");
3119+
3120+nux::NString PerspectiveCorrectVtx = TEXT (
3121+ "!!ARBvp1.0 \n\
3122+ ATTRIB iPos = vertex.position; \n\
3123+ ATTRIB iColor = vertex.attrib[3]; \n\
3124+ PARAM mvp[4] = {state.matrix.mvp}; \n\
3125+ OUTPUT oPos = result.position; \n\
3126+ OUTPUT oColor = result.color; \n\
3127+ OUTPUT oTexCoord0 = result.texcoord[0]; \n\
3128+ # Transform the vertex to clip coordinates. \n\
3129+ DP4 oPos.x, mvp[0], iPos; \n\
3130+ DP4 oPos.y, mvp[1], iPos; \n\
3131+ DP4 oPos.z, mvp[2], iPos; \n\
3132+ DP4 oPos.w, mvp[3], iPos; \n\
3133+ MOV oColor, iColor; \n\
3134+ MOV oTexCoord0, vertex.attrib[8]; \n\
3135+ END");
3136+
3137+
3138+
3139+nux::NString PerspectiveCorrectTexFrg = TEXT (
3140+ "!!ARBfp1.0 \n\
3141+ PARAM color0 = program.local[0]; \n\
3142+ TEMP temp; \n\
3143+ TEMP pcoord; \n\
3144+ TEMP tex0; \n\
3145+ TEMP temp1; \n\
3146+ TEMP recip; \n\
3147+ MOV pcoord, fragment.texcoord[0].w; \n\
3148+ RCP temp, fragment.texcoord[0].w; \n\
3149+ MUL pcoord.xy, fragment.texcoord[0], temp; \n\
3150+ TEX tex0, pcoord, texture[0], 2D; \n\
3151+ MUL result.color, color0, tex0; \n\
3152+ END");
3153+
3154+nux::NString PerspectiveCorrectTexRectFrg = TEXT (
3155+ "!!ARBfp1.0 \n\
3156+ PARAM color0 = program.local[0]; \n\
3157+ TEMP temp; \n\
3158+ TEMP pcoord; \n\
3159+ TEMP tex0; \n\
3160+ MOV pcoord, fragment.texcoord[0].w; \n\
3161+ RCP temp, fragment.texcoord[0].w; \n\
3162+ MUL pcoord.xy, fragment.texcoord[0], temp; \n\
3163+ TEX tex0, pcoord, texture[0], RECT; \n\
3164+ MUL result.color, color0, tex0; \n\
3165+ END");
3166+
3167+static void GetInverseScreenPerspectiveMatrix(nux::Matrix4& ViewMatrix, nux::Matrix4& PerspectiveMatrix,
3168+ int ViewportWidth,
3169+ int ViewportHeight,
3170+ float NearClipPlane,
3171+ float FarClipPlane,
3172+ float Fovy);
3173+
3174+Launcher::Launcher(nux::BaseWindow *parent, CompScreen *screen, NUX_FILE_LINE_DECL)
3175+: View(NUX_FILE_LINE_PARAM)
3176+, m_ContentOffsetY(0)
3177+, m_RunningIndicator(0)
3178+, m_ActiveIndicator(0)
3179+, m_BackgroundLayer(0)
3180+, _model (0)
3181+{
3182+ _parent = parent;
3183+ _screen = screen;
3184+ _active_quicklist = 0;
3185+
3186+ m_Layout = new nux::HLayout(NUX_TRACKER_LOCATION);
3187+
3188+ OnMouseDown.connect(sigc::mem_fun(this, &Launcher::RecvMouseDown));
3189+ OnMouseUp.connect(sigc::mem_fun(this, &Launcher::RecvMouseUp));
3190+ OnMouseDrag.connect(sigc::mem_fun(this, &Launcher::RecvMouseDrag));
3191+ OnMouseEnter.connect(sigc::mem_fun(this, &Launcher::RecvMouseEnter));
3192+ OnMouseLeave.connect(sigc::mem_fun(this, &Launcher::RecvMouseLeave));
3193+ OnMouseMove.connect(sigc::mem_fun(this, &Launcher::RecvMouseMove));
3194+ OnMouseWheel.connect(sigc::mem_fun(this, &Launcher::RecvMouseWheel));
3195+
3196+ QuicklistManager::Default ()->quicklist_opened.connect (sigc::mem_fun(this, &Launcher::RecvQuicklistOpened));
3197+ QuicklistManager::Default ()->quicklist_closed.connect (sigc::mem_fun(this, &Launcher::RecvQuicklistClosed));
3198+
3199+ m_ActiveTooltipIcon = NULL;
3200+ m_ActiveMenuIcon = NULL;
3201+
3202+ SetCompositionLayout(m_Layout);
3203+
3204+ if(!USE_ARB_SHADERS)
3205+ {
3206+ _shader_program_uv_persp_correction = nux::GetThreadGLDeviceFactory()->CreateShaderProgram();
3207+ _shader_program_uv_persp_correction->LoadIShader(gPerspectiveCorrectShader.GetTCharPtr());
3208+ _shader_program_uv_persp_correction->Link();
3209+ }
3210+ else
3211+ {
3212+ _AsmShaderProg = nux::GetThreadGLDeviceFactory()->CreateAsmShaderProgram();
3213+ _AsmShaderProg->LoadVertexShader (TCHAR_TO_ANSI (*PerspectiveCorrectVtx) );
3214+
3215+ if ((nux::GetThreadGLDeviceFactory()->SUPPORT_GL_ARB_TEXTURE_NON_POWER_OF_TWO() == false) &&
3216+ (nux::GetThreadGLDeviceFactory()->SUPPORT_GL_EXT_TEXTURE_RECTANGLE () || nux::GetThreadGLDeviceFactory()->SUPPORT_GL_ARB_TEXTURE_RECTANGLE ()))
3217+ {
3218+ // No support for non power of two textures but support for rectangle textures
3219+ _AsmShaderProg->LoadPixelShader (TCHAR_TO_ANSI (*PerspectiveCorrectTexRectFrg) );
3220+ }
3221+ else
3222+ {
3223+ _AsmShaderProg->LoadPixelShader (TCHAR_TO_ANSI (*PerspectiveCorrectTexFrg) );
3224+ }
3225+
3226+ _AsmShaderProg->Link();
3227+ }
3228+
3229+ _folded_angle = 1.0f;
3230+ _neg_folded_angle = -1.0f;
3231+ _space_between_icons = 5;
3232+ _launcher_top_y = 0;
3233+ _launcher_bottom_y = 0;
3234+ _folded_z_distance = 10.0f;
3235+ _launcher_state = LAUNCHER_FOLDED;
3236+ _launcher_action_state = ACTION_NONE;
3237+ _icon_under_mouse = NULL;
3238+ _icon_mouse_down = NULL;
3239+ _drag_icon = NULL;
3240+ _drag_icon_under_mouse = NULL;
3241+ _icon_image_size = 48;
3242+ _icon_glow_size = 62;
3243+ _icon_image_size_delta = 6;
3244+ _icon_size = _icon_image_size + _icon_image_size_delta;
3245+
3246+ _icon_bkg_texture = nux::CreateTextureFromFile (PKGDATADIR"/round_corner_54x54.png");
3247+ _icon_outline_texture = nux::CreateTextureFromFile (PKGDATADIR"/round_outline_54x54.png");
3248+ _icon_shine_texture = nux::CreateTextureFromFile (PKGDATADIR"/round_shine_54x54.png");
3249+ _icon_glow_texture = nux::CreateTextureFromFile (PKGDATADIR"/round_glow_62x62.png");
3250+ _icon_2indicator = nux::CreateTextureFromFile (PKGDATADIR"/2indicate_54x54.png");
3251+ _icon_3indicator = nux::CreateTextureFromFile (PKGDATADIR"/3indicate_54x54.png");
3252+ _icon_4indicator = nux::CreateTextureFromFile (PKGDATADIR"/4indicate_54x54.png");
3253+
3254+ _enter_y = 0;
3255+ _dnd_security = 15;
3256+ _launcher_drag_delta = 0;
3257+ _dnd_delta_y = 0;
3258+ _dnd_delta_x = 0;
3259+ _anim_handle = 0;
3260+ _autohide_handle = 0;
3261+ _floating = false;
3262+ _hovered = false;
3263+ _autohide = false;
3264+ _hidden = false;
3265+ _mouse_inside_launcher = false;
3266+ _mouse_inside_trigger = false;
3267+ _window_over_launcher = false;
3268+
3269+ // 0 out timers to avoid wonky startups
3270+ _enter_time.tv_sec = 0;
3271+ _enter_time.tv_nsec = 0;
3272+ _exit_time.tv_sec = 0;
3273+ _exit_time.tv_nsec = 0;
3274+ _drag_end_time.tv_sec = 0;
3275+ _drag_end_time.tv_nsec = 0;
3276+ _drag_start_time.tv_sec = 0;
3277+ _drag_start_time.tv_nsec = 0;
3278+ _autohide_time.tv_sec = 0;
3279+ _autohide_time.tv_nsec = 0;
3280+
3281+ _drag_window = NULL;
3282+}
3283+
3284+Launcher::~Launcher()
3285+{
3286+
3287+}
3288+
3289+/* Introspection */
3290+const gchar *
3291+Launcher::GetName ()
3292+{
3293+ return "Launcher";
3294+}
3295+
3296+void
3297+Launcher::AddProperties (GVariantBuilder *builder)
3298+{
3299+ struct timespec current;
3300+ clock_gettime (CLOCK_MONOTONIC, &current);
3301+
3302+ g_variant_builder_add (builder, "{sv}", "hover-progress", g_variant_new_double ((double) GetHoverProgress (current)));
3303+ g_variant_builder_add (builder, "{sv}", "dnd-exit-progress", g_variant_new_double ((double) DnDExitProgress (current)));
3304+ g_variant_builder_add (builder, "{sv}", "autohide-progress", g_variant_new_double ((double) AutohideProgress (current)));
3305+
3306+ g_variant_builder_add (builder, "{sv}", "dnd-delta", g_variant_new_int32 (_dnd_delta_y));
3307+ g_variant_builder_add (builder, "{sv}", "floating", g_variant_new_boolean (_floating));
3308+ g_variant_builder_add (builder, "{sv}", "hovered", g_variant_new_boolean (_hovered));
3309+ g_variant_builder_add (builder, "{sv}", "autohide", g_variant_new_boolean (_autohide));
3310+ g_variant_builder_add (builder, "{sv}", "hidden", g_variant_new_boolean (_hidden));
3311+ g_variant_builder_add (builder, "{sv}", "autohide", g_variant_new_boolean (_autohide));
3312+ g_variant_builder_add (builder, "{sv}", "mouse-inside-launcher", g_variant_new_boolean (_mouse_inside_launcher));
3313+}
3314+
3315+/* Render Layout Logic */
3316+
3317+float Launcher::GetHoverProgress (struct timespec const &current)
3318+{
3319+ if (_hovered)
3320+ return CLAMP ((float) (TimeDelta (&current, &_enter_time)) / (float) ANIM_DURATION, 0.0f, 1.0f);
3321+ else
3322+ return 1.0f - CLAMP ((float) (TimeDelta (&current, &_exit_time)) / (float) ANIM_DURATION, 0.0f, 1.0f);
3323+}
3324+
3325+float Launcher::DnDExitProgress (struct timespec const &current)
3326+{
3327+ return 1.0f - CLAMP ((float) (TimeDelta (&current, &_drag_end_time)) / (float) ANIM_DURATION_LONG, 0.0f, 1.0f);
3328+}
3329+
3330+float Launcher::DnDStartProgress (struct timespec const &current)
3331+{
3332+ return CLAMP ((float) (TimeDelta (&current, &_drag_start_time)) / (float) ANIM_DURATION, 0.0f, 1.0f);
3333+}
3334+
3335+float Launcher::AutohideProgress (struct timespec const &current)
3336+{
3337+ if (!_autohide)
3338+ return 0.0f;
3339+
3340+ if (_hidden)
3341+ return CLAMP ((float) (TimeDelta (&current, &_autohide_time)) / (float) ANIM_DURATION_SHORT, 0.0f, 1.0f);
3342+ else
3343+ return 1.0f - CLAMP ((float) (TimeDelta (&current, &_autohide_time)) / (float) ANIM_DURATION_SHORT, 0.0f, 1.0f);
3344+}
3345+
3346+gboolean Launcher::AnimationTimeout (gpointer data)
3347+{
3348+ Launcher *self = (Launcher*) data;
3349+
3350+ self->NeedRedraw ();
3351+
3352+ if (self->AnimationInProgress ())
3353+ return true;
3354+
3355+ // zero out handle so we know we are done
3356+ self->_anim_handle = 0;
3357+ return false;
3358+}
3359+
3360+void Launcher::EnsureAnimation ()
3361+{
3362+ if (_anim_handle)
3363+ return;
3364+
3365+ NeedRedraw ();
3366+
3367+ if (AnimationInProgress ())
3368+ _anim_handle = g_timeout_add (1000 / 60 - 1, &Launcher::AnimationTimeout, this);
3369+}
3370+
3371+bool Launcher::IconNeedsAnimation (LauncherIcon *icon, struct timespec const &current)
3372+{
3373+ struct timespec time = icon->GetQuirkTime (LAUNCHER_ICON_QUIRK_VISIBLE);
3374+ if (TimeDelta (&current, &time) < ANIM_DURATION_SHORT)
3375+ return true;
3376+
3377+ time = icon->GetQuirkTime (LAUNCHER_ICON_QUIRK_RUNNING);
3378+ if (TimeDelta (&current, &time) < ANIM_DURATION_SHORT)
3379+ return true;
3380+
3381+ time = icon->GetQuirkTime (LAUNCHER_ICON_QUIRK_STARTING);
3382+ if (TimeDelta (&current, &time) < (ANIM_DURATION_LONG * MAX_STARTING_BLINKS * STARTING_BLINK_LAMBDA * 2))
3383+ return true;
3384+
3385+ time = icon->GetQuirkTime (LAUNCHER_ICON_QUIRK_URGENT);
3386+ if (TimeDelta (&current, &time) < (ANIM_DURATION_LONG * URGENT_BLINKS * 2))
3387+ return true;
3388+
3389+ time = icon->GetQuirkTime (LAUNCHER_ICON_QUIRK_PRESENTED);
3390+ if (TimeDelta (&current, &time) < ANIM_DURATION)
3391+ return true;
3392+
3393+ time = icon->GetQuirkTime (LAUNCHER_ICON_QUIRK_SHIMMER);
3394+ if (TimeDelta (&current, &time) < ANIM_DURATION_LONG)
3395+ return true;
3396+
3397+ return false;
3398+}
3399+
3400+bool Launcher::AnimationInProgress ()
3401+{
3402+ // HACK
3403+ if (_launcher_action_state == ACTION_DRAG_ICON)
3404+ return true;
3405+ // performance here can be improved by caching the longer remaining animation found and short circuiting to that each time
3406+ // this way extra checks may be avoided
3407+
3408+ // short circuit to avoid unneeded calculations
3409+ struct timespec current;
3410+ clock_gettime (CLOCK_MONOTONIC, &current);
3411+
3412+ // hover in animation
3413+ if (TimeDelta (&current, &_enter_time) < ANIM_DURATION)
3414+ return true;
3415+
3416+ // hover out animation
3417+ if (TimeDelta (&current, &_exit_time) < ANIM_DURATION)
3418+ return true;
3419+
3420+ // drag start animation
3421+ if (TimeDelta (&current, &_drag_start_time) < ANIM_DURATION)
3422+ return true;
3423+
3424+ // drag end animation
3425+ if (TimeDelta (&current, &_drag_end_time) < ANIM_DURATION_LONG)
3426+ return true;
3427+
3428+ if (TimeDelta (&current, &_autohide_time) < ANIM_DURATION_SHORT)
3429+ return true;
3430+
3431+ // animations happening on specific icons
3432+ LauncherModel::iterator it;
3433+ for (it = _model->begin (); it != _model->end (); it++)
3434+ if (IconNeedsAnimation (*it, current))
3435+ return true;
3436+
3437+ return false;
3438+}
3439+
3440+void Launcher::SetTimeStruct (struct timespec *timer, struct timespec *sister, int sister_relation)
3441+{
3442+ struct timespec current;
3443+ clock_gettime (CLOCK_MONOTONIC, &current);
3444+
3445+ if (sister)
3446+ {
3447+ int diff = TimeDelta (&current, sister);
3448+
3449+ if (diff < sister_relation)
3450+ {
3451+ int remove = sister_relation - diff;
3452+ current.tv_sec -= remove / 1000;
3453+ remove = remove % 1000;
3454+
3455+ if (remove > current.tv_nsec / 1000000)
3456+ {
3457+ current.tv_sec--;
3458+ current.tv_nsec += 1000000000;
3459+ }
3460+ current.tv_nsec -= remove * 1000000;
3461+ }
3462+ }
3463+
3464+ timer->tv_sec = current.tv_sec;
3465+ timer->tv_nsec = current.tv_nsec;
3466+}
3467+
3468+float IconVisibleProgress (LauncherIcon *icon, struct timespec const &current)
3469+{
3470+ if (icon->GetQuirk (LAUNCHER_ICON_QUIRK_VISIBLE))
3471+ {
3472+ struct timespec icon_visible_time = icon->GetQuirkTime (LAUNCHER_ICON_QUIRK_VISIBLE);
3473+ int enter_ms = TimeDelta (&current, &icon_visible_time);
3474+ return CLAMP ((float) enter_ms / (float) ANIM_DURATION_SHORT, 0.0f, 1.0f);
3475+ }
3476+ else
3477+ {
3478+ struct timespec icon_hide_time = icon->GetQuirkTime (LAUNCHER_ICON_QUIRK_VISIBLE);
3479+ int hide_ms = TimeDelta (&current, &icon_hide_time);
3480+ return 1.0f - CLAMP ((float) hide_ms / (float) ANIM_DURATION_SHORT, 0.0f, 1.0f);
3481+ }
3482+}
3483+
3484+void Launcher::SetDndDelta (float x, float y, nux::Geometry geo, struct timespec const &current)
3485+{
3486+ LauncherIcon *anchor = 0;
3487+ LauncherModel::iterator it;
3488+ anchor = MouseIconIntersection (x, _enter_y);
3489+
3490+ if (anchor)
3491+ {
3492+ float position = y;
3493+ for (it = _model->begin (); it != _model->end (); it++)
3494+ {
3495+ if (*it == anchor)
3496+ {
3497+ position += _icon_size / 2;
3498+ _launcher_drag_delta = _enter_y - position;
3499+
3500+ if (position + _icon_size / 2 + _launcher_drag_delta > geo.height)
3501+ _launcher_drag_delta -= (position + _icon_size / 2 + _launcher_drag_delta) - geo.height;
3502+
3503+ break;
3504+ }
3505+ position += (_icon_size + _space_between_icons) * IconVisibleProgress (*it, current);
3506+ }
3507+ }
3508+}
3509+
3510+float Launcher::IconPresentProgress (LauncherIcon *icon, struct timespec const &current)
3511+{
3512+ struct timespec icon_present_time = icon->GetQuirkTime (LAUNCHER_ICON_QUIRK_PRESENTED);
3513+ int ms = TimeDelta (&current, &icon_present_time);
3514+ float result = CLAMP ((float) ms / (float) ANIM_DURATION, 0.0f, 1.0f);
3515+
3516+ if (icon->GetQuirk (LAUNCHER_ICON_QUIRK_PRESENTED))
3517+ return result;
3518+ else
3519+ return 1.0f - result;
3520+}
3521+
3522+float Launcher::IconUrgentProgress (LauncherIcon *icon, struct timespec const &current)
3523+{
3524+ struct timespec urgent_time = icon->GetQuirkTime (LAUNCHER_ICON_QUIRK_URGENT);
3525+ int urgent_ms = TimeDelta (&current, &urgent_time);
3526+ float result = CLAMP ((float) urgent_ms / (float) (ANIM_DURATION_LONG * URGENT_BLINKS * 2), 0.0f, 1.0f);
3527+
3528+ if (icon->GetQuirk (LAUNCHER_ICON_QUIRK_URGENT))
3529+ return result;
3530+ else
3531+ return 1.0f - result;
3532+}
3533+
3534+float Launcher::IconShimmerProgress (LauncherIcon *icon, struct timespec const &current)
3535+{
3536+ struct timespec shimmer_time = icon->GetQuirkTime (LAUNCHER_ICON_QUIRK_SHIMMER);
3537+ int shimmer_ms = TimeDelta (&current, &shimmer_time);
3538+ return CLAMP ((float) shimmer_ms / (float) ANIM_DURATION_LONG, 0.0f, 1.0f);
3539+}
3540+
3541+float Launcher::IconUrgentPulseValue (LauncherIcon *icon, struct timespec const &current)
3542+{
3543+ if (!icon->GetQuirk (LAUNCHER_ICON_QUIRK_URGENT))
3544+ return 1.0f; // we are full on in a normal condition
3545+
3546+ double urgent_progress = (double) IconUrgentProgress (icon, current);
3547+ return 0.5f + (float) (std::cos (M_PI * (float) (URGENT_BLINKS * 2) * urgent_progress)) * 0.5f;
3548+}
3549+
3550+float Launcher::IconStartingPulseValue (LauncherIcon *icon, struct timespec const &current)
3551+{
3552+ struct timespec starting_time = icon->GetQuirkTime (LAUNCHER_ICON_QUIRK_STARTING);
3553+ int starting_ms = TimeDelta (&current, &starting_time);
3554+ double starting_progress = (double) CLAMP ((float) starting_ms / (float) (ANIM_DURATION_LONG * MAX_STARTING_BLINKS * STARTING_BLINK_LAMBDA * 2), 0.0f, 1.0f);
3555+
3556+ if (starting_progress == 1.0f && !icon->GetQuirk (LAUNCHER_ICON_QUIRK_RUNNING))
3557+ {
3558+ icon->SetQuirk (LAUNCHER_ICON_QUIRK_STARTING, false);
3559+ icon->ResetQuirkTime (LAUNCHER_ICON_QUIRK_STARTING);
3560+ }
3561+
3562+ return 1.0f - (0.5f + (float) (std::cos (M_PI * (float) (MAX_STARTING_BLINKS * 2) * starting_progress)) * 0.5f);
3563+}
3564+
3565+float Launcher::IconBackgroundIntensity (LauncherIcon *icon, struct timespec const &current)
3566+{
3567+ float result = 0.0f;
3568+ struct timespec running_time = icon->GetQuirkTime (LAUNCHER_ICON_QUIRK_RUNNING);
3569+ int running_ms = TimeDelta (&current, &running_time);
3570+ float running_progress = CLAMP ((float) running_ms / (float) ANIM_DURATION_SHORT, 0.0f, 1.0f);
3571+
3572+ // After we finish a fade in from running, we can reset the quirk
3573+ if (running_progress == 1.0f && icon->GetQuirk (LAUNCHER_ICON_QUIRK_RUNNING))
3574+ {
3575+ icon->SetQuirk (LAUNCHER_ICON_QUIRK_STARTING, false);
3576+ icon->ResetQuirkTime (LAUNCHER_ICON_QUIRK_STARTING);
3577+ }
3578+
3579+ result = IconStartingPulseValue (icon, current) * BACKLIGHT_STRENGTH;
3580+
3581+ if (icon->GetQuirk (LAUNCHER_ICON_QUIRK_RUNNING))
3582+ {
3583+ // running progress fades in whatever the pulsing did not fill in already
3584+ result += running_progress * (BACKLIGHT_STRENGTH - result);
3585+
3586+ // urgent serves to bring the total down only
3587+ if (icon->GetQuirk (LAUNCHER_ICON_QUIRK_URGENT))
3588+ result *= 0.2f + 0.8f * IconUrgentPulseValue (icon, current);
3589+ }
3590+ else
3591+ {
3592+ // modestly evil
3593+ result += BACKLIGHT_STRENGTH - running_progress * BACKLIGHT_STRENGTH;
3594+ }
3595+
3596+ return result;
3597+}
3598+
3599+void Launcher::SetupRenderArg (LauncherIcon *icon, struct timespec const &current, RenderArg &arg)
3600+{
3601+ arg.icon = icon;
3602+ arg.alpha = 1.0f;
3603+ arg.running_arrow = icon->GetQuirk (LAUNCHER_ICON_QUIRK_RUNNING);
3604+ arg.active_arrow = icon->GetQuirk (LAUNCHER_ICON_QUIRK_ACTIVE);
3605+ arg.running_colored = icon->GetQuirk (LAUNCHER_ICON_QUIRK_URGENT);
3606+ arg.active_colored = false;
3607+ arg.folding_rads = 0.0f;
3608+ arg.skip = false;
3609+
3610+
3611+ // we dont need to show strays
3612+ if (!icon->GetQuirk (LAUNCHER_ICON_QUIRK_RUNNING))
3613+ arg.window_indicators = 0;
3614+ else
3615+ arg.window_indicators = MIN (4, icon->RelatedWindows ());
3616+
3617+ arg.backlight_intensity = IconBackgroundIntensity (icon, current);
3618+ arg.shimmer_progress = IconShimmerProgress (icon, current);
3619+
3620+ float urgent_progress = IconUrgentProgress (icon, current);
3621+
3622+ if (icon->GetQuirk (LAUNCHER_ICON_QUIRK_URGENT))
3623+ urgent_progress = CLAMP (urgent_progress * 3.0f, 0.0f, 1.0f); // we want to go 3x faster than the urgent normal cycle
3624+ else
3625+ urgent_progress = CLAMP (urgent_progress * 3.0f - 2.0f, 0.0f, 1.0f); // we want to go 3x faster than the urgent normal cycle
3626+ arg.glow_intensity = urgent_progress;
3627+}
3628+
3629+void Launcher::FillRenderArg (LauncherIcon *icon,
3630+ RenderArg &arg,
3631+ nux::Point3 &center,
3632+ float folding_threshold,
3633+ float folded_size,
3634+ float folded_spacing,
3635+ float autohide_offset,
3636+ float folded_z_distance,
3637+ float animation_neg_rads,
3638+ int vertical_offset,
3639+ struct timespec const &current)
3640+{
3641+ SetupRenderArg (icon, current, arg);
3642+
3643+ // reset z
3644+ center.z = 0;
3645+
3646+ float size_modifier = IconVisibleProgress (icon, current);
3647+ if (size_modifier < 1.0f)
3648+ {
3649+ arg.alpha = size_modifier;
3650+ center.z = 300.0f * (1.0f - size_modifier);
3651+ }
3652+
3653+ if (size_modifier <= 0.0f || icon == _drag_icon)
3654+ arg.skip = true;
3655+
3656+ // goes for 0.0f when fully unfolded, to 1.0f folded
3657+ float folding_progress = CLAMP ((center.y + _icon_size - folding_threshold) / (float) _icon_size, 0.0f, 1.0f);
3658+ float present_progress = IconPresentProgress (icon, current);
3659+
3660+ folding_progress *= 1.0f - present_progress;
3661+
3662+ float half_size = (folded_size / 2.0f) + (_icon_size / 2.0f - folded_size / 2.0f) * (1.0f - folding_progress);
3663+
3664+ float icon_hide_offset = autohide_offset;
3665+
3666+ icon_hide_offset *= 1.0f - (present_progress * icon->PresentUrgency ());
3667+
3668+ // icon is crossing threshold, start folding
3669+ center.z += folded_z_distance * folding_progress;
3670+ arg.folding_rads = animation_neg_rads * folding_progress;
3671+
3672+ float spacing_overlap = CLAMP ((float) (center.y + (2.0f * half_size * size_modifier) + (_space_between_icons * size_modifier) - folding_threshold) / (float) _icon_size, 0.0f, 1.0f);
3673+ float spacing = (_space_between_icons * (1.0f - spacing_overlap) + folded_spacing * spacing_overlap) * size_modifier;
3674+
3675+ center.y += half_size * size_modifier; // move to center
3676+ arg.center = nux::Point3 (roundf (center.x + icon_hide_offset), roundf (center.y), roundf (center.z)); // copy center
3677+ icon->SetCenter (nux::Point3 (roundf (center.x), roundf (center.y + vertical_offset), roundf (center.z)));
3678+ center.y += (half_size * size_modifier) + spacing; // move to end
3679+}
3680+
3681+float Launcher::DragLimiter (float x)
3682+{
3683+ float result = (1 - std::pow (159.0 / 160, std::abs (x))) * 160;
3684+
3685+ if (x >= 0.0f)
3686+ return result;
3687+ return -result;
3688+}
3689+
3690+void Launcher::RenderArgs (std::list<Launcher::RenderArg> &launcher_args,
3691+ nux::Geometry &box_geo)
3692+{
3693+ nux::Geometry geo = GetGeometry ();
3694+ LauncherModel::iterator it;
3695+ nux::Point3 center;
3696+ struct timespec current;
3697+ clock_gettime (CLOCK_MONOTONIC, &current);
3698+
3699+ float hover_progress = GetHoverProgress (current);
3700+ float folded_z_distance = _folded_z_distance * (1.0f - hover_progress);
3701+ float animation_neg_rads = _neg_folded_angle * (1.0f - hover_progress);
3702+ int vertical_offset = _parent->GetGeometry ().y;
3703+
3704+ float folding_constant = 0.25f;
3705+ float folding_not_constant = folding_constant + ((1.0f - folding_constant) * hover_progress);
3706+
3707+ float folded_size = _icon_size * folding_not_constant;
3708+ float folded_spacing = _space_between_icons * folding_not_constant;
3709+
3710+ center.x = geo.width / 2;
3711+ center.y = _space_between_icons;
3712+ center.z = 0;
3713+
3714+ int launcher_height = geo.height;
3715+
3716+ // compute required height of launcher AND folding threshold
3717+ float sum = 0.0f + center.y;
3718+ float folding_threshold = launcher_height - _icon_size / 2.5f;
3719+ for (it = _model->begin (); it != _model->end (); it++)
3720+ {
3721+ float height = (_icon_size + _space_between_icons) * IconVisibleProgress (*it, current);
3722+ sum += height;
3723+
3724+ // magic constant must some day be explained, for now suffice to say this constant prevents the bottom from "marching";
3725+ float magic_constant = 1.2f;
3726+
3727+ float present_progress = IconPresentProgress (*it, current);
3728+ folding_threshold -= CLAMP (sum - launcher_height, 0.0f, height * magic_constant) * (folding_constant + (1.0f - folding_constant) * present_progress);
3729+ }
3730+
3731+ // this happens on hover, basically its a flag and a value in one, we translate this into a dnd offset
3732+ if (_enter_y != 0 && _enter_y + _icon_size / 2 > folding_threshold)
3733+ SetDndDelta (center.x, center.y, nux::Geometry (geo.x, geo.y, geo.width, geo.height), current);
3734+
3735+ _enter_y = 0;
3736+
3737+ if (hover_progress > 0.0f && _launcher_drag_delta != 0)
3738+ {
3739+ float delta_y = _launcher_drag_delta;
3740+
3741+ // logically dnd exit only restores to the clamped ranges
3742+ // hover_progress restores to 0
3743+ float max = 0.0f;
3744+ float min = MIN (0.0f, launcher_height - sum);
3745+
3746+ if (_launcher_drag_delta > max)
3747+ delta_y = max + DragLimiter (delta_y - max);
3748+ else if (_launcher_drag_delta < min)
3749+ delta_y = min + DragLimiter (delta_y - min);
3750+
3751+ if (_launcher_action_state != ACTION_DRAG_LAUNCHER)
3752+ {
3753+ float dnd_progress = DnDExitProgress (current);
3754+
3755+ if (_launcher_drag_delta > max)
3756+ delta_y = max + (delta_y - max) * dnd_progress;
3757+ else if (_launcher_drag_delta < min)
3758+ delta_y = min + (delta_y - min) * dnd_progress;
3759+
3760+ if (dnd_progress == 0.0f)
3761+ _launcher_drag_delta = (int) delta_y;
3762+ }
3763+
3764+ delta_y *= hover_progress;
3765+ center.y += delta_y;
3766+ folding_threshold += delta_y;
3767+ }
3768+ else
3769+ {
3770+ _launcher_drag_delta = 0;
3771+ }
3772+
3773+ float autohide_progress = AutohideProgress (current);
3774+ float autohide_offset = 0.0f;
3775+ if (_autohide && autohide_progress > 0.0f)
3776+ {
3777+ autohide_offset -= geo.width * autohide_progress;
3778+ }
3779+
3780+ // Inform the painter where to paint the box
3781+ box_geo = geo;
3782+
3783+ if (_autohide)
3784+ box_geo.x += autohide_offset;
3785+
3786+ // The functional position we wish to represent for these icons is not smooth. Rather than introducing
3787+ // special casing to represent this, we use MIN/MAX functions. This helps ensure that even though our
3788+ // function is not smooth it is continuous, which is more important for our visual representation (icons
3789+ // wont start jumping around). As a general rule ANY if () statements that modify center.y should be seen
3790+ // as bugs.
3791+ for (it = _model->main_begin (); it != _model->main_end (); it++)
3792+ {
3793+ RenderArg arg;
3794+ LauncherIcon *icon = *it;
3795+
3796+ FillRenderArg (icon, arg, center, folding_threshold, folded_size, folded_spacing,
3797+ autohide_offset, folded_z_distance, animation_neg_rads, vertical_offset, current);
3798+
3799+ launcher_args.push_back (arg);
3800+ }
3801+
3802+ // compute maximum height of shelf
3803+ float shelf_sum = 0.0f;
3804+ for (it = _model->shelf_begin (); it != _model->shelf_end (); it++)
3805+ {
3806+ float height = (_icon_size + _space_between_icons) * IconVisibleProgress (*it, current);
3807+ shelf_sum += height;
3808+ }
3809+
3810+ // add bottom padding
3811+ if (shelf_sum > 0.0f)
3812+ shelf_sum += _space_between_icons;
3813+
3814+ float shelf_delta = MAX (((launcher_height - shelf_sum) + _space_between_icons) - center.y, 0.0f);
3815+ folding_threshold += shelf_delta;
3816+ center.y += shelf_delta;
3817+
3818+ for (it = _model->shelf_begin (); it != _model->shelf_end (); it++)
3819+ {
3820+ RenderArg arg;
3821+ LauncherIcon *icon = *it;
3822+
3823+ FillRenderArg (icon, arg, center, folding_threshold, folded_size, folded_spacing,
3824+ autohide_offset, folded_z_distance, animation_neg_rads, vertical_offset, current);
3825+
3826+ launcher_args.push_back (arg);
3827+ }
3828+}
3829+
3830+/* End Render Layout Logic */
3831+
3832+void Launcher::SetHidden (bool hidden)
3833+{
3834+ if (hidden == _hidden)
3835+ return;
3836+
3837+ _hidden = hidden;
3838+ SetTimeStruct (&_autohide_time, &_autohide_time, ANIM_DURATION_SHORT);
3839+
3840+ _parent->EnableInputWindow(!hidden);
3841+
3842+ EnsureAnimation ();
3843+}
3844+
3845+gboolean Launcher::OnAutohideTimeout (gpointer data)
3846+{
3847+ Launcher *self = (Launcher*) data;
3848+
3849+ self->EnsureHiddenState ();
3850+ self->_autohide_handle = 0;
3851+ return false;
3852+}
3853+
3854+void
3855+Launcher::EnsureHiddenState ()
3856+{
3857+ if (!_mouse_inside_trigger &&
3858+ !_mouse_inside_launcher &&
3859+ _launcher_action_state == ACTION_NONE &&
3860+ !QuicklistManager::Default ()->Current() &&
3861+ _window_over_launcher)
3862+ SetHidden (true);
3863+ else
3864+ SetHidden (false);
3865+}
3866+
3867+void
3868+Launcher::CheckWindowOverLauncher ()
3869+{
3870+ CompWindowList window_list = _screen->windows ();
3871+ CompWindowList::iterator it;
3872+ nux::Geometry geo = GetGeometry ();
3873+
3874+ for (it = window_list.begin (); it != window_list.end (); it++)
3875+ {
3876+ CompWindow *window = *it;
3877+
3878+ if (window->type () != CompWindowTypeNormalMask || window->invisible ())
3879+ continue;
3880+
3881+ if (CompRegion (window->inputRect ()).intersects (CompRect (geo.x, geo.y, geo.width, geo.height)))
3882+ {
3883+ _window_over_launcher = true;
3884+ EnsureHiddenState ();
3885+ return;
3886+ }
3887+ }
3888+
3889+ _window_over_launcher = false;
3890+ EnsureHiddenState ();
3891+}
3892+
3893+void
3894+Launcher::OnWindowMoved (CompWindow *window)
3895+{
3896+ if (_autohide)
3897+ CheckWindowOverLauncher ();
3898+}
3899+
3900+void
3901+Launcher::OnWindowResized (CompWindow *window)
3902+{
3903+ if (_autohide)
3904+ CheckWindowOverLauncher ();
3905+}
3906+
3907+void
3908+Launcher::OnWindowAppear (CompWindow *window)
3909+{
3910+ if (_autohide)
3911+ CheckWindowOverLauncher ();
3912+}
3913+void
3914+Launcher::OnWindowDisappear (CompWindow *window)
3915+{
3916+ if (_autohide)
3917+ CheckWindowOverLauncher ();
3918+}
3919+
3920+void Launcher::OnTriggerMouseEnter (int x, int y, unsigned long button_flags, unsigned long key_flags)
3921+{
3922+ _mouse_inside_trigger = true;
3923+ EnsureHiddenState ();
3924+}
3925+
3926+void Launcher::SetupAutohideTimer ()
3927+{
3928+ if (_autohide)
3929+ {
3930+ if (_autohide_handle > 0)
3931+ g_source_remove (_autohide_handle);
3932+ _autohide_handle = g_timeout_add (1000, &Launcher::OnAutohideTimeout, this);
3933+ }
3934+}
3935+
3936+void Launcher::OnTriggerMouseLeave (int x, int y, unsigned long button_flags, unsigned long key_flags)
3937+{
3938+ _mouse_inside_trigger = false;
3939+ SetupAutohideTimer ();
3940+}
3941+
3942+bool Launcher::AutohideEnabled ()
3943+{
3944+ return _autohide;
3945+}
3946+
3947+gboolean Launcher::StrutHack (gpointer data)
3948+{
3949+ Launcher *self = (Launcher *) data;
3950+ self->_parent->InputWindowEnableStruts(false);
3951+ self->_parent->InputWindowEnableStruts(true);
3952+
3953+ return false;
3954+}
3955+
3956+void Launcher::SetAutohide (bool autohide, nux::View *trigger)
3957+{
3958+ if (_autohide == autohide)
3959+ return;
3960+
3961+ if (autohide)
3962+ {
3963+ _parent->InputWindowEnableStruts(false);
3964+ _autohide_trigger = trigger;
3965+ _autohide_trigger->OnMouseEnter.connect (sigc::mem_fun(this, &Launcher::OnTriggerMouseEnter));
3966+ _autohide_trigger->OnMouseLeave.connect (sigc::mem_fun(this, &Launcher::OnTriggerMouseLeave));
3967+ }
3968+ else
3969+ {
3970+ _parent->EnableInputWindow(true);
3971+ g_timeout_add (1000, &Launcher::StrutHack, this);
3972+ _parent->InputWindowEnableStruts(true);
3973+ }
3974+
3975+ _autohide = autohide;
3976+ EnsureAnimation ();
3977+}
3978+
3979+void Launcher::SetFloating (bool floating)
3980+{
3981+ if (_floating == floating)
3982+ return;
3983+
3984+ _floating = floating;
3985+ EnsureAnimation ();
3986+}
3987+
3988+void Launcher::SetHover ()
3989+{
3990+ if (_hovered)
3991+ return;
3992+
3993+ _enter_y = (int) _mouse_position.y;
3994+
3995+ _hovered = true;
3996+ SetTimeStruct (&_enter_time, &_exit_time, ANIM_DURATION);
3997+}
3998+
3999+void Launcher::UnsetHover ()
4000+{
4001+ if (!_hovered)
4002+ return;
4003+
4004+ _hovered = false;
4005+ SetTimeStruct (&_exit_time, &_enter_time, ANIM_DURATION);
4006+ SetupAutohideTimer ();
4007+}
4008+
4009+void Launcher::SetIconSize(int tile_size, int icon_size)
4010+{
4011+ nux::Geometry geo = _parent->GetGeometry ();
4012+
4013+ _icon_size = tile_size;
4014+ _icon_image_size = icon_size;
4015+ _icon_image_size_delta = tile_size - icon_size;
4016+
4017+ // recreate tile textures
4018+
4019+ _parent->SetGeometry (nux::Geometry (geo.x, geo.y, tile_size + 12, geo.height));
4020+}
4021+
4022+void Launcher::OnIconAdded (LauncherIcon *icon)
4023+{
4024+ icon->Reference ();
4025+ EnsureAnimation();
4026+
4027+ // How to free these properly?
4028+ icon->_xform_coords["HitArea"] = new nux::Vector4[4];
4029+ icon->_xform_coords["Image"] = new nux::Vector4[4];
4030+ icon->_xform_coords["Tile"] = new nux::Vector4[4];
4031+ icon->_xform_coords["Glow"] = new nux::Vector4[4];
4032+
4033+ // needs to be disconnected
4034+ icon->needs_redraw.connect (sigc::mem_fun(this, &Launcher::OnIconNeedsRedraw));
4035+
4036+ AddChild (icon);
4037+}
4038+
4039+void Launcher::OnIconRemoved (LauncherIcon *icon)
4040+{
4041+ icon->UnReference ();
4042+ EnsureAnimation();
4043+ RemoveChild (icon);
4044+}
4045+
4046+void Launcher::OnOrderChanged ()
4047+{
4048+ EnsureAnimation ();
4049+}
4050+
4051+void Launcher::SetModel (LauncherModel *model)
4052+{
4053+ _model = model;
4054+ _model->icon_added.connect (sigc::mem_fun (this, &Launcher::OnIconAdded));
4055+ _model->icon_removed.connect (sigc::mem_fun (this, &Launcher::OnIconRemoved));
4056+ _model->order_changed.connect (sigc::mem_fun (this, &Launcher::OnOrderChanged));
4057+}
4058+
4059+void Launcher::OnIconNeedsRedraw (LauncherIcon *icon)
4060+{
4061+ EnsureAnimation();
4062+}
4063+
4064+long Launcher::ProcessEvent(nux::IEvent &ievent, long TraverseInfo, long ProcessEventInfo)
4065+{
4066+ long ret = TraverseInfo;
4067+ ret = PostProcessEvent2(ievent, ret, ProcessEventInfo);
4068+ return ret;
4069+}
4070+
4071+void Launcher::Draw(nux::GraphicsEngine& GfxContext, bool force_draw)
4072+{
4073+
4074+}
4075+
4076+void Launcher::RenderIndicators (nux::GraphicsEngine& GfxContext,
4077+ RenderArg const &arg,
4078+ int running,
4079+ int active,
4080+ nux::Geometry geo)
4081+{
4082+ int markerCenter = (int) arg.center.y;
4083+
4084+ if (running > 0)
4085+ {
4086+ if (!m_RunningIndicator)
4087+ {
4088+ GdkPixbuf *pbuf = gdk_pixbuf_new_from_file (PKGDATADIR"/running_indicator.png", NULL);
4089+ m_RunningIndicator = nux::CreateTextureFromPixbuf (pbuf);
4090+ g_object_unref (pbuf);
4091+ }
4092+ nux::TexCoordXForm texxform;
4093+
4094+ nux::Color color = nux::Color::LightGrey;
4095+
4096+ if (arg.running_colored)
4097+ color = nux::Color::SkyBlue;
4098+
4099+ std::vector<int> markers;
4100+ if (running == 1)
4101+ {
4102+ markers.push_back (markerCenter);
4103+ }
4104+ else if (running == 2)
4105+ {
4106+ markers.push_back (markerCenter - 2);
4107+ markers.push_back (markerCenter + 2);
4108+ }
4109+ else
4110+ {
4111+ markers.push_back (markerCenter - 4);
4112+ markers.push_back (markerCenter);
4113+ markers.push_back (markerCenter + 4);
4114+ }
4115+
4116+ std::vector<int>::iterator it;
4117+ for (it = markers.begin (); it != markers.end (); it++)
4118+ {
4119+ int center = *it;
4120+ GfxContext.QRP_GLSL_1Tex (geo.x,
4121+ center - (m_RunningIndicator->GetHeight () / 2),
4122+ (float) m_RunningIndicator->GetWidth(),
4123+ (float) m_RunningIndicator->GetHeight(),
4124+ m_RunningIndicator->GetDeviceTexture(),
4125+ texxform,
4126+ color);
4127+ }
4128+ }
4129+
4130+ if (active > 0)
4131+ {
4132+ if (!m_ActiveIndicator)
4133+ {
4134+ GdkPixbuf *pbuf = gdk_pixbuf_new_from_file (PKGDATADIR"/focused_indicator.png", NULL);
4135+ m_ActiveIndicator = nux::CreateTextureFromPixbuf (pbuf);
4136+ g_object_unref (pbuf);
4137+ }
4138+ nux::TexCoordXForm texxform;
4139+
4140+ nux::Color color = nux::Color::LightGrey;
4141+ GfxContext.QRP_GLSL_1Tex ((geo.x + geo.width) - m_ActiveIndicator->GetWidth (),
4142+ markerCenter - (m_ActiveIndicator->GetHeight () / 2),
4143+ (float) m_ActiveIndicator->GetWidth(),
4144+ (float) m_ActiveIndicator->GetHeight(),
4145+ m_ActiveIndicator->GetDeviceTexture(),
4146+ texxform,
4147+ color);
4148+ }
4149+}
4150+
4151+void Launcher::RenderIcon(nux::GraphicsEngine& GfxContext,
4152+ RenderArg const &arg,
4153+ nux::BaseTexture *icon,
4154+ nux::Color bkg_color,
4155+ float alpha,
4156+ nux::Vector4 xform_coords[],
4157+ nux::Geometry geo)
4158+{
4159+ if (icon == NULL || icon->IsNull ())
4160+ return;
4161+
4162+ nux::Matrix4 ObjectMatrix;
4163+ nux::Matrix4 ViewMatrix;
4164+ nux::Matrix4 ProjectionMatrix;
4165+ nux::Matrix4 ViewProjectionMatrix;
4166+
4167+ if(nux::Abs (arg.folding_rads) < 0.01f)
4168+ icon->GetDeviceTexture()->SetFiltering(GL_NEAREST, GL_NEAREST);
4169+ else
4170+ icon->GetDeviceTexture()->SetFiltering(GL_LINEAR, GL_LINEAR);
4171+
4172+ nux::Vector4 v0;
4173+ nux::Vector4 v1;
4174+ nux::Vector4 v2;
4175+ nux::Vector4 v3;
4176+
4177+ v0.x = xform_coords[0].x ;
4178+ v0.y = xform_coords[0].y ;
4179+ v0.z = xform_coords[0].z ;
4180+ v0.w = xform_coords[0].w ;
4181+ v1.x = xform_coords[1].x ;
4182+ v1.y = xform_coords[1].y ;
4183+ v1.z = xform_coords[1].z ;
4184+ v1.w = xform_coords[1].w ;
4185+ v2.x = xform_coords[2].x ;
4186+ v2.y = xform_coords[2].y ;
4187+ v2.z = xform_coords[2].z ;
4188+ v2.w = xform_coords[2].w ;
4189+ v3.x = xform_coords[3].x ;
4190+ v3.y = xform_coords[3].y ;
4191+ v3.z = xform_coords[3].z ;
4192+ v3.w = xform_coords[3].w ;
4193+
4194+ float s0, t0, s1, t1, s2, t2, s3, t3;
4195+ nux::Color color = nux::Color::White;
4196+
4197+ if (icon->Type ().IsDerivedFromType(nux::TextureRectangle::StaticObjectType))
4198+ {
4199+ s0 = 0.0f; t0 = 0.0f;
4200+ s1 = 0.0f; t1 = icon->GetHeight();
4201+ s2 = icon->GetWidth(); t2 = icon->GetHeight();
4202+ s3 = icon->GetWidth(); t3 = 0.0f;
4203+ }
4204+ else
4205+ {
4206+ s0 = 0.0f; t0 = 0.0f;
4207+ s1 = 0.0f; t1 = 1.0f;
4208+ s2 = 1.0f; t2 = 1.0f;
4209+ s3 = 1.0f; t3 = 0.0f;
4210+ }
4211+
4212+ float VtxBuffer[] =
4213+ {// Perspective correct
4214+ 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(),
4215+ 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(),
4216+ 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(),
4217+ 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(),
4218+ };
4219+
4220+ CHECKGL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
4221+ CHECKGL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
4222+
4223+ int TextureObjectLocation;
4224+ int VertexLocation;
4225+ int TextureCoord0Location;
4226+ int VertexColorLocation;
4227+ int FragmentColor;
4228+
4229+ if(!USE_ARB_SHADERS)
4230+ {
4231+ _shader_program_uv_persp_correction->Begin();
4232+
4233+ TextureObjectLocation = _shader_program_uv_persp_correction->GetUniformLocationARB("TextureObject0");
4234+ VertexLocation = _shader_program_uv_persp_correction->GetAttributeLocation("iVertex");
4235+ TextureCoord0Location = _shader_program_uv_persp_correction->GetAttributeLocation("iTexCoord0");
4236+ VertexColorLocation = _shader_program_uv_persp_correction->GetAttributeLocation("iColor");
4237+ FragmentColor = _shader_program_uv_persp_correction->GetUniformLocationARB ("color");
4238+
4239+ nux::GetGraphicsEngine ().SetTexture(GL_TEXTURE0, icon);
4240+
4241+ if(TextureObjectLocation != -1)
4242+ CHECKGL( glUniform1iARB (TextureObjectLocation, 0) );
4243+
4244+ int VPMatrixLocation = _shader_program_uv_persp_correction->GetUniformLocationARB("ViewProjectionMatrix");
4245+ if(VPMatrixLocation != -1)
4246+ {
4247+ nux::Matrix4 mat = nux::GetGraphicsEngine ().GetModelViewProjectionMatrix ();
4248+ _shader_program_uv_persp_correction->SetUniformLocMatrix4fv ((GLint)VPMatrixLocation, 1, false, (GLfloat*)&(mat.m));
4249+ }
4250+ }
4251+ else
4252+ {
4253+ _AsmShaderProg->Begin();
4254+
4255+ VertexLocation = nux::VTXATTRIB_POSITION;
4256+ TextureCoord0Location = nux::VTXATTRIB_TEXCOORD0;
4257+ VertexColorLocation = nux::VTXATTRIB_COLOR;
4258+
4259+ nux::GetGraphicsEngine().SetTexture(GL_TEXTURE0, icon);
4260+ }
4261+
4262+ CHECKGL( glEnableVertexAttribArrayARB(VertexLocation) );
4263+ CHECKGL( glVertexAttribPointerARB((GLuint)VertexLocation, 4, GL_FLOAT, GL_FALSE, 48, VtxBuffer) );
4264+
4265+ if(TextureCoord0Location != -1)
4266+ {
4267+ CHECKGL( glEnableVertexAttribArrayARB(TextureCoord0Location) );
4268+ CHECKGL( glVertexAttribPointerARB((GLuint)TextureCoord0Location, 4, GL_FLOAT, GL_FALSE, 48, VtxBuffer + 4) );
4269+ }
4270+
4271+ if(VertexColorLocation != -1)
4272+ {
4273+ CHECKGL( glEnableVertexAttribArrayARB(VertexColorLocation) );
4274+ CHECKGL( glVertexAttribPointerARB((GLuint)VertexColorLocation, 4, GL_FLOAT, GL_FALSE, 48, VtxBuffer + 8) );
4275+ }
4276+
4277+ bkg_color.SetAlpha (bkg_color.A () * alpha);
4278+
4279+ if(!USE_ARB_SHADERS)
4280+ {
4281+ CHECKGL ( glUniform4fARB (FragmentColor, bkg_color.R(), bkg_color.G(), bkg_color.B(), bkg_color.A() ) );
4282+ nux::GetGraphicsEngine ().SetTexture(GL_TEXTURE0, icon);
4283+ CHECKGL( glDrawArrays(GL_QUADS, 0, 4) );
4284+ }
4285+ else
4286+ {
4287+ CHECKGL ( glProgramLocalParameter4fARB (GL_FRAGMENT_PROGRAM_ARB, 0, bkg_color.R(), bkg_color.G(), bkg_color.B(), bkg_color.A() ) );
4288+ nux::GetGraphicsEngine ().SetTexture(GL_TEXTURE0, icon);
4289+ CHECKGL( glDrawArrays(GL_QUADS, 0, 4) );
4290+ }
4291+
4292+ if(VertexLocation != -1)
4293+ CHECKGL( glDisableVertexAttribArrayARB(VertexLocation) );
4294+ if(TextureCoord0Location != -1)
4295+ CHECKGL( glDisableVertexAttribArrayARB(TextureCoord0Location) );
4296+ if(VertexColorLocation != -1)
4297+ CHECKGL( glDisableVertexAttribArrayARB(VertexColorLocation) );
4298+
4299+ if(!USE_ARB_SHADERS)
4300+ {
4301+ _shader_program_uv_persp_correction->End();
4302+ }
4303+ else
4304+ {
4305+ _AsmShaderProg->End();
4306+ }
4307+}
4308+
4309+void Launcher::DrawRenderArg (nux::GraphicsEngine& GfxContext, RenderArg const &arg, nux::Geometry geo)
4310+{
4311+ GfxContext.GetRenderStates ().SetSeparateBlend (true,
4312+ GL_SRC_ALPHA,
4313+ GL_ONE_MINUS_SRC_ALPHA,
4314+ GL_ONE_MINUS_DST_ALPHA,
4315+ GL_ONE);
4316+
4317+ GfxContext.GetRenderStates ().SetColorMask (true, true, true, true);
4318+
4319+ if (arg.backlight_intensity < 1.0f)
4320+ {
4321+ RenderIcon(GfxContext,
4322+ arg,
4323+ _icon_outline_texture,
4324+ nux::Color(0xAAFFFFFF),
4325+ 1.0f - arg.backlight_intensity,
4326+ arg.icon->_xform_coords["Tile"],
4327+ geo);
4328+ }
4329+
4330+ if (arg.backlight_intensity > 0.0f)
4331+ {
4332+ RenderIcon(GfxContext,
4333+ arg,
4334+ _icon_bkg_texture,
4335+ arg.icon->BackgroundColor (),
4336+ arg.backlight_intensity,
4337+ arg.icon->_xform_coords["Tile"],
4338+ geo);
4339+ }
4340+
4341+ GfxContext.GetRenderStates ().SetSeparateBlend (true,
4342+ GL_SRC_ALPHA,
4343+ GL_ONE_MINUS_SRC_ALPHA,
4344+ GL_ONE_MINUS_DST_ALPHA,
4345+ GL_ONE);
4346+ GfxContext.GetRenderStates ().SetColorMask (true, true, true, true);
4347+
4348+ RenderIcon (GfxContext,
4349+ arg,
4350+ arg.icon->TextureForSize (_icon_image_size),
4351+ nux::Color::White,
4352+ arg.alpha,
4353+ arg.icon->_xform_coords["Image"],
4354+ geo);
4355+
4356+ if (arg.backlight_intensity > 0.0f)
4357+ {
4358+ RenderIcon(GfxContext,
4359+ arg,
4360+ _icon_shine_texture,
4361+ nux::Color::White,
4362+ arg.backlight_intensity,
4363+ arg.icon->_xform_coords["Tile"],
4364+ geo);
4365+ }
4366+
4367+ if (false)
4368+ {
4369+ switch (arg.window_indicators)
4370+ {
4371+ case 2:
4372+ RenderIcon(GfxContext,
4373+ arg,
4374+ _icon_2indicator,
4375+ nux::Color::White,
4376+ 1.0f,
4377+ arg.icon->_xform_coords["Tile"],
4378+ geo);
4379+ break;
4380+ case 3:
4381+ RenderIcon(GfxContext,
4382+ arg,
4383+ _icon_3indicator,
4384+ nux::Color::White,
4385+ 1.0f,
4386+ arg.icon->_xform_coords["Tile"],
4387+ geo);
4388+ break;
4389+ case 4:
4390+ RenderIcon(GfxContext,
4391+ arg,
4392+ _icon_4indicator,
4393+ nux::Color::White,
4394+ 1.0f,
4395+ arg.icon->_xform_coords["Tile"],
4396+ geo);
4397+ break;
4398+ }
4399+ }
4400+
4401+ if (arg.glow_intensity > 0.0f)
4402+ {
4403+ RenderIcon(GfxContext,
4404+ arg,
4405+ _icon_glow_texture,
4406+ arg.icon->GlowColor (),
4407+ arg.glow_intensity,
4408+ arg.icon->_xform_coords["Glow"],
4409+ geo);
4410+ }
4411+
4412+ if (arg.shimmer_progress > 0.0f && arg.shimmer_progress < 1.0f)
4413+ {
4414+ nux::Geometry base = GetGeometry ();
4415+ int x1 = base.x + base.width;
4416+ int x2 = base.x + base.width;
4417+ float shimmer_constant = 1.9f;
4418+
4419+ x1 -= geo.width * arg.shimmer_progress * shimmer_constant;
4420+ GfxContext.PushClippingRectangle(nux::Geometry (x1, geo.y, x2 - x1, geo.height));
4421+
4422+ float fade_out = 1.0f - CLAMP (((x2 - x1) - geo.width) / (geo.width * (shimmer_constant - 1.0f)), 0.0f, 1.0f);
4423+
4424+ RenderIcon(GfxContext,
4425+ arg,
4426+ _icon_glow_texture,
4427+ arg.icon->GlowColor (),
4428+ fade_out,
4429+ arg.icon->_xform_coords["Glow"],
4430+ geo);
4431+
4432+ GfxContext.PopClippingRectangle();
4433+ }
4434+
4435+ RenderIndicators (GfxContext,
4436+ arg,
4437+ arg.running_arrow ? arg.window_indicators : 0,
4438+ arg.active_arrow ? 1 : 0,
4439+ geo);
4440+}
4441+
4442+void Launcher::DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw)
4443+{
4444+ nux::Geometry base = GetGeometry();
4445+ GfxContext.PushClippingRectangle(base);
4446+ nux::Geometry bkg_box;
4447+ std::list<Launcher::RenderArg> args;
4448+ std::list<Launcher::RenderArg>::reverse_iterator rev_it;
4449+ std::list<Launcher::RenderArg>::iterator it;
4450+
4451+ nux::ROPConfig ROP;
4452+ ROP.Blend = false;
4453+ ROP.SrcBlend = GL_SRC_ALPHA;
4454+ ROP.DstBlend = GL_ONE_MINUS_SRC_ALPHA;
4455+
4456+ RenderArgs (args, bkg_box);
4457+
4458+ // clear region
4459+ gPainter.PushDrawColorLayer(GfxContext, base, nux::Color(0x00000000), true, ROP);
4460+
4461+ // clip vertically but not horizontally
4462+ GfxContext.PushClippingRectangle(nux::Geometry (base.x, bkg_box.y, base.width, bkg_box.height));
4463+ GfxContext.GetRenderStates ().SetSeparateBlend (true,
4464+ GL_SRC_ALPHA,
4465+ GL_ONE_MINUS_SRC_ALPHA,
4466+ GL_ONE_MINUS_DST_ALPHA,
4467+ GL_ONE);
4468+
4469+ gPainter.Paint2DQuadColor (GfxContext, bkg_box, nux::Color(0xAA000000));
4470+
4471+ UpdateIconXForm (args);
4472+ EventLogic ();
4473+
4474+ /* draw launcher */
4475+ for (rev_it = args.rbegin (); rev_it != args.rend (); rev_it++)
4476+ {
4477+ if ((*rev_it).folding_rads >= 0.0f || (*rev_it).skip)
4478+ continue;
4479+
4480+ DrawRenderArg (GfxContext, *rev_it, bkg_box);
4481+ }
4482+
4483+ for (it = args.begin(); it != args.end(); it++)
4484+ {
4485+ if ((*it).folding_rads < 0.0f || (*it).skip)
4486+ continue;
4487+
4488+ DrawRenderArg (GfxContext, *it, bkg_box);
4489+ }
4490+
4491+
4492+ gPainter.Paint2DQuadColor (GfxContext, nux::Geometry (bkg_box.x + bkg_box.width - 1, bkg_box.y, 1, bkg_box.height), nux::Color(0x60FFFFFF));
4493+
4494+ GfxContext.GetRenderStates().SetColorMask (true, true, true, true);
4495+ GfxContext.GetRenderStates ().SetSeparateBlend (false,
4496+ GL_SRC_ALPHA,
4497+ GL_ONE_MINUS_SRC_ALPHA,
4498+ GL_SRC_ALPHA,
4499+ GL_ONE_MINUS_SRC_ALPHA);
4500+
4501+ gPainter.PopBackground();
4502+ GfxContext.PopClippingRectangle();
4503+ GfxContext.PopClippingRectangle();
4504+}
4505+
4506+void Launcher::PostDraw(nux::GraphicsEngine& GfxContext, bool force_draw)
4507+{
4508+}
4509+
4510+void Launcher::PreLayoutManagement()
4511+{
4512+ View::PreLayoutManagement();
4513+ if(m_CompositionLayout)
4514+ {
4515+ m_CompositionLayout->SetGeometry(GetGeometry());
4516+ }
4517+}
4518+
4519+long Launcher::PostLayoutManagement(long LayoutResult)
4520+{
4521+ View::PostLayoutManagement(LayoutResult);
4522+
4523+ _mouse_position = nux::Point2 (0, 0);
4524+
4525+ return nux::eCompliantHeight | nux::eCompliantWidth;
4526+}
4527+
4528+void Launcher::PositionChildLayout(float offsetX, float offsetY)
4529+{
4530+}
4531+
4532+bool Launcher::TooltipNotify(LauncherIcon* Icon)
4533+{
4534+ if(GetActiveMenuIcon())
4535+ return false;
4536+ return true;
4537+}
4538+
4539+bool Launcher::MenuNotify(LauncherIcon* Icon)
4540+{
4541+
4542+
4543+ return true;
4544+}
4545+
4546+void Launcher::NotifyMenuTermination(LauncherIcon* Icon)
4547+{
4548+}
4549+
4550+void Launcher::StartIconDrag (LauncherIcon *icon)
4551+{
4552+ if (!icon)
4553+ return;
4554+
4555+ _drag_icon = icon;
4556+
4557+ if (_drag_window)
4558+ {
4559+ _drag_window->ShowWindow (false);
4560+ _drag_window->UnReference ();
4561+ _drag_window = NULL;
4562+ }
4563+
4564+ _drag_window = new LauncherDragWindow (icon, _icon_size);
4565+ _drag_window->SinkReference ();
4566+
4567+ _drag_window->ShowWindow (true);
4568+
4569+ nux::GetWindowCompositor ().SetAlwaysOnFrontWindow (_drag_window);
4570+}
4571+
4572+void Launcher::EndIconDrag ()
4573+{
4574+ if (_drag_window)
4575+ {
4576+ _drag_window->ShowWindow (false);
4577+ _drag_window->UnReference ();
4578+ _drag_window = NULL;
4579+ }
4580+
4581+ _drag_icon_under_mouse = NULL;
4582+ _drag_icon = NULL;
4583+}
4584+
4585+void Launcher::UpdateDragWindowPosition (int x, int y)
4586+{
4587+ if (_drag_window)
4588+ {
4589+ nux::Geometry geo = _drag_window->GetGeometry ();
4590+ _drag_window->SetBaseXY (x - geo.width / 2 + _parent->GetGeometry ().x, y - geo.height / 2 + _parent->GetGeometry ().y);
4591+
4592+ LauncherIcon *hovered_icon = MouseIconIntersection ((int) (GetGeometry ().x / 2.0f), y);
4593+
4594+ if (_drag_icon && hovered_icon && _drag_icon != hovered_icon)
4595+ {
4596+ request_reorder.emit (_drag_icon, hovered_icon);
4597+ }
4598+ }
4599+}
4600+
4601+void Launcher::RecvMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags)
4602+{
4603+ _mouse_position = nux::Point2 (x, y);
4604+
4605+ MouseDownLogic (x, y, button_flags, key_flags);
4606+ EnsureAnimation ();
4607+}
4608+
4609+void Launcher::RecvMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags)
4610+{
4611+ _mouse_position = nux::Point2 (x, y);
4612+ nux::Geometry geo = GetGeometry ();
4613+
4614+ if (_launcher_action_state != ACTION_NONE && !geo.IsInside(nux::Point(x, y)))
4615+ {
4616+ // we are no longer hovered
4617+ UnsetHover ();
4618+ }
4619+
4620+ MouseUpLogic (x, y, button_flags, key_flags);
4621+
4622+ if (_launcher_action_state == ACTION_DRAG_ICON)
4623+ EndIconDrag ();
4624+
4625+ _launcher_action_state = ACTION_NONE;
4626+ _dnd_delta_x = 0;
4627+ _dnd_delta_y = 0;
4628+ EnsureAnimation ();
4629+}
4630+
4631+void Launcher::RecvMouseDrag(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags)
4632+{
4633+ _mouse_position = nux::Point2 (x, y);
4634+
4635+ _dnd_delta_y += dy;
4636+ _dnd_delta_x += dx;
4637+
4638+ if (nux::Abs (_dnd_delta_y) < 15 &&
4639+ nux::Abs (_dnd_delta_x) < 15 &&
4640+ _launcher_action_state == ACTION_NONE)
4641+ return;
4642+
4643+ if (_icon_under_mouse)
4644+ {
4645+ _icon_under_mouse->MouseLeave.emit ();
4646+ _icon_under_mouse->_mouse_inside = false;
4647+ _icon_under_mouse = 0;
4648+ }
4649+
4650+ if (_launcher_action_state == ACTION_NONE)
4651+ {
4652+ SetTimeStruct (&_drag_start_time);
4653+
4654+ if (nux::Abs (_dnd_delta_y) >= nux::Abs (_dnd_delta_x))
4655+ {
4656+ _launcher_drag_delta += _dnd_delta_y;
4657+ _launcher_action_state = ACTION_DRAG_LAUNCHER;
4658+ }
4659+ else
4660+ {
4661+ LauncherIcon *drag_icon = MouseIconIntersection ((int) (GetGeometry ().x / 2.0f), y);
4662+
4663+ if (drag_icon)
4664+ {
4665+ StartIconDrag (drag_icon);
4666+ _launcher_action_state = ACTION_DRAG_ICON;
4667+ UpdateDragWindowPosition (x, y);
4668+ }
4669+
4670+ }
4671+ }
4672+ else if (_launcher_action_state == ACTION_DRAG_LAUNCHER)
4673+ {
4674+ _launcher_drag_delta += dy;
4675+ }
4676+ else if (_launcher_action_state == ACTION_DRAG_ICON)
4677+ {
4678+ UpdateDragWindowPosition (x, y);
4679+ }
4680+
4681+ EnsureAnimation ();
4682+}
4683+
4684+void Launcher::RecvMouseEnter(int x, int y, unsigned long button_flags, unsigned long key_flags)
4685+{
4686+ _mouse_position = nux::Point2 (x, y);
4687+ _mouse_inside_launcher = true;
4688+
4689+ SetHover ();
4690+
4691+ EventLogic ();
4692+ EnsureAnimation ();
4693+}
4694+
4695+void Launcher::RecvMouseLeave(int x, int y, unsigned long button_flags, unsigned long key_flags)
4696+{
4697+ _mouse_position = nux::Point2 (x, y);
4698+ _mouse_inside_launcher = false;
4699+
4700+ if (_launcher_action_state == ACTION_NONE)
4701+ UnsetHover ();
4702+
4703+ EventLogic ();
4704+ EnsureAnimation ();
4705+}
4706+
4707+void Launcher::RecvMouseMove(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags)
4708+{
4709+ _mouse_position = nux::Point2 (x, y);
4710+
4711+ // Every time the mouse moves, we check if it is inside an icon...
4712+ EventLogic ();
4713+}
4714+
4715+void Launcher::RecvMouseWheel(int x, int y, int wheel_delta, unsigned long button_flags, unsigned long key_flags)
4716+{
4717+}
4718+
4719+void Launcher::RecvQuicklistOpened (QuicklistView *quicklist)
4720+{
4721+ EventLogic ();
4722+ EnsureAnimation ();
4723+}
4724+
4725+void Launcher::RecvQuicklistClosed (QuicklistView *quicklist)
4726+{
4727+ SetupAutohideTimer ();
4728+
4729+ EventLogic ();
4730+ EnsureAnimation ();
4731+}
4732+
4733+void Launcher::EventLogic ()
4734+{
4735+ if (_launcher_action_state != ACTION_NONE)
4736+ return;
4737+
4738+ LauncherIcon* launcher_icon = 0;
4739+
4740+ if (_mouse_inside_launcher)
4741+ launcher_icon = MouseIconIntersection (_mouse_position.x, _mouse_position.y);
4742+
4743+ if (_icon_under_mouse && (_icon_under_mouse != launcher_icon))
4744+ {
4745+ _icon_under_mouse->MouseLeave.emit ();
4746+ _icon_under_mouse->_mouse_inside = false;
4747+ _icon_under_mouse = 0;
4748+ }
4749+
4750+ if (launcher_icon && (_icon_under_mouse != launcher_icon))
4751+ {
4752+ launcher_icon->MouseEnter.emit ();
4753+ launcher_icon->_mouse_inside = true;
4754+ _icon_under_mouse = launcher_icon;
4755+ }
4756+}
4757+
4758+void Launcher::MouseDownLogic (int x, int y, unsigned long button_flags, unsigned long key_flags)
4759+{
4760+ LauncherIcon* launcher_icon = 0;
4761+ launcher_icon = MouseIconIntersection (_mouse_position.x, _mouse_position.y);
4762+
4763+ if (launcher_icon)
4764+ {
4765+ _icon_mouse_down = launcher_icon;
4766+ launcher_icon->MouseDown.emit (nux::GetEventButton (button_flags));
4767+ }
4768+}
4769+
4770+void Launcher::MouseUpLogic (int x, int y, unsigned long button_flags, unsigned long key_flags)
4771+{
4772+ LauncherIcon* launcher_icon = 0;
4773+ launcher_icon = MouseIconIntersection (_mouse_position.x, _mouse_position.y);
4774+
4775+ if (_icon_mouse_down && (_icon_mouse_down == launcher_icon))
4776+ {
4777+ _icon_mouse_down->MouseUp.emit (nux::GetEventButton (button_flags));
4778+
4779+ if (_launcher_action_state == ACTION_NONE)
4780+ _icon_mouse_down->MouseClick.emit (nux::GetEventButton (button_flags));
4781+ }
4782+
4783+ if (launcher_icon && (_icon_mouse_down != launcher_icon))
4784+ {
4785+ launcher_icon->MouseUp.emit (nux::GetEventButton (button_flags));
4786+ }
4787+
4788+ if (_launcher_action_state == ACTION_DRAG_LAUNCHER)
4789+ {
4790+ SetTimeStruct (&_drag_end_time);
4791+ }
4792+
4793+ _icon_mouse_down = 0;
4794+}
4795+
4796+LauncherIcon* Launcher::MouseIconIntersection (int x, int y)
4797+{
4798+ LauncherModel::iterator it;
4799+ LauncherModel::reverse_iterator rev_it;
4800+ // We are looking for the icon at screen coordinates x, y;
4801+ nux::Point2 mouse_position(x, y);
4802+ int inside = 0;
4803+
4804+ // Because of the way icons fold and stack on one another, we must proceed in 2 steps.
4805+ for (rev_it = _model->rbegin (); rev_it != _model->rend (); rev_it++)
4806+ {
4807+ if ((*rev_it)->_folding_angle < 0.0f || !(*rev_it)->GetQuirk (LAUNCHER_ICON_QUIRK_VISIBLE))
4808+ continue;
4809+
4810+ nux::Point2 screen_coord [4];
4811+ for (int i = 0; i < 4; i++)
4812+ {
4813+ screen_coord [i].x = (*rev_it)->_xform_coords["HitArea"] [i].x;
4814+ screen_coord [i].y = (*rev_it)->_xform_coords["HitArea"] [i].y;
4815+ }
4816+ inside = PointInside2DPolygon (screen_coord, 4, mouse_position, 1);
4817+ if (inside)
4818+ return (*rev_it);
4819+ }
4820+
4821+ for (it = _model->begin(); it != _model->end (); it++)
4822+ {
4823+ if ((*it)->_folding_angle >= 0.0f || !(*it)->GetQuirk (LAUNCHER_ICON_QUIRK_VISIBLE))
4824+ continue;
4825+
4826+ nux::Point2 screen_coord [4];
4827+ for (int i = 0; i < 4; i++)
4828+ {
4829+ screen_coord [i].x = (*it)->_xform_coords["HitArea"] [i].x;
4830+ screen_coord [i].y = (*it)->_xform_coords["HitArea"] [i].y;
4831+ }
4832+ inside = PointInside2DPolygon (screen_coord, 4, mouse_position, 1);
4833+ if (inside)
4834+ return (*it);
4835+ }
4836+
4837+ return 0;
4838+}
4839+
4840+void Launcher::SetIconXForm (LauncherIcon *icon, nux::Matrix4 ViewProjectionMatrix, nux::Geometry geo,
4841+ float x, float y, float w, float h, float z, std::string name)
4842+{
4843+ nux::Vector4 v0 = nux::Vector4(x, y, z, 1.0f);
4844+ nux::Vector4 v1 = nux::Vector4(x, y+h, z, 1.0f);
4845+ nux::Vector4 v2 = nux::Vector4(x+w, y+h, z, 1.0f);
4846+ nux::Vector4 v3 = nux::Vector4(x+w, y, z, 1.0f);
4847+
4848+ v0 = ViewProjectionMatrix * v0;
4849+ v1 = ViewProjectionMatrix * v1;
4850+ v2 = ViewProjectionMatrix * v2;
4851+ v3 = ViewProjectionMatrix * v3;
4852+
4853+ v0.divide_xyz_by_w();
4854+ v1.divide_xyz_by_w();
4855+ v2.divide_xyz_by_w();
4856+ v3.divide_xyz_by_w();
4857+
4858+ // normalize to the viewport coordinates and translate to the correct location
4859+ v0.x = geo.width *(v0.x + 1.0f)/2.0f - geo.width/2.0f + x + w/2.0f;
4860+ v0.y = -geo.height*(v0.y - 1.0f)/2.0f - geo.height/2.0f + y + h/2.0f;
4861+ v1.x = geo.width *(v1.x + 1.0f)/2.0f - geo.width/2.0f + x + w/2.0f;;
4862+ v1.y = -geo.height*(v1.y - 1.0f)/2.0f - geo.height/2.0f + y + h/2.0f;
4863+ v2.x = geo.width *(v2.x + 1.0f)/2.0f - geo.width/2.0f + x + w/2.0f;
4864+ v2.y = -geo.height*(v2.y - 1.0f)/2.0f - geo.height/2.0f + y + h/2.0f;
4865+ v3.x = geo.width *(v3.x + 1.0f)/2.0f - geo.width/2.0f + x + w/2.0f;
4866+ v3.y = -geo.height*(v3.y - 1.0f)/2.0f - geo.height/2.0f + y + h/2.0f;
4867+
4868+
4869+ nux::Vector4* vectors = icon->_xform_coords[name];
4870+
4871+ vectors[0].x = v0.x;
4872+ vectors[0].y = v0.y;
4873+ vectors[0].z = v0.z;
4874+ vectors[0].w = v0.w;
4875+ vectors[1].x = v1.x;
4876+ vectors[1].y = v1.y;
4877+ vectors[1].z = v1.z;
4878+ vectors[1].w = v1.w;
4879+ vectors[2].x = v2.x;
4880+ vectors[2].y = v2.y;
4881+ vectors[2].z = v2.z;
4882+ vectors[2].w = v2.w;
4883+ vectors[3].x = v3.x;
4884+ vectors[3].y = v3.y;
4885+ vectors[3].z = v3.z;
4886+ vectors[3].w = v3.w;
4887+}
4888+
4889+void Launcher::UpdateIconXForm (std::list<Launcher::RenderArg> &args)
4890+{
4891+ nux::Geometry geo = GetGeometry ();
4892+ nux::Matrix4 ObjectMatrix;
4893+ nux::Matrix4 ViewMatrix;
4894+ nux::Matrix4 ProjectionMatrix;
4895+ nux::Matrix4 ViewProjectionMatrix;
4896+
4897+ GetInverseScreenPerspectiveMatrix(ViewMatrix, ProjectionMatrix, geo.width, geo.height, 0.1f, 1000.0f, DEGTORAD(90));
4898+
4899+ //LauncherModel::iterator it;
4900+ std::list<Launcher::RenderArg>::iterator it;
4901+ for(it = args.begin(); it != args.end(); it++)
4902+ {
4903+
4904+ LauncherIcon* launcher_icon = (*it).icon;
4905+
4906+ // We to store the icon angle in the icons itself. Makes one thing easier afterward.
4907+ launcher_icon->_folding_angle = (*it).folding_rads;
4908+
4909+ float w = _icon_size;
4910+ float h = _icon_size;
4911+ float x = (*it).center.x - w/2.0f; // x: top left corner
4912+ float y = (*it).center.y - h/2.0f; // y: top left corner
4913+ float z = (*it).center.z;
4914+
4915+ if ((*it).skip)
4916+ {
4917+ w = 1;
4918+ h = 1;
4919+ x = -100;
4920+ y = -100;
4921+ }
4922+
4923+ ObjectMatrix = nux::Matrix4::TRANSLATE(geo.width/2.0f, geo.height/2.0f, z) * // Translate the icon to the center of the viewport
4924+ nux::Matrix4::ROTATEX((*it).folding_rads) * // rotate the icon
4925+ nux::Matrix4::TRANSLATE(-x - w/2.0f, -y - h/2.0f, -z); // Put the center the icon to (0, 0)
4926+
4927+ ViewProjectionMatrix = ProjectionMatrix*ViewMatrix*ObjectMatrix;
4928+
4929+ SetIconXForm (launcher_icon, ViewProjectionMatrix, geo, x, y, w, h, z, "Tile");
4930+
4931+ w = _icon_image_size;
4932+ h = _icon_image_size;
4933+ x = (*it).center.x - _icon_size/2.0f + _icon_image_size_delta/2.0f;
4934+ y = (*it).center.y - _icon_size/2.0f + _icon_image_size_delta/2.0f;
4935+ z = (*it).center.z;
4936+
4937+ SetIconXForm (launcher_icon, ViewProjectionMatrix, geo, x, y, w, h, z, "Image");
4938+
4939+ w = _icon_glow_size;
4940+ h = _icon_glow_size;
4941+ x = (*it).center.x - _icon_glow_size/2.0f;
4942+ y = (*it).center.y - _icon_glow_size/2.0f;
4943+ z = (*it).center.z;
4944+
4945+ SetIconXForm (launcher_icon, ViewProjectionMatrix, geo, x, y, w, h, z, "Glow");
4946+
4947+ w = geo.width + 2;
4948+ h = _icon_size + _space_between_icons;
4949+ x = (*it).center.x - w/2.0f;
4950+ y = (*it).center.y - h/2.0f;
4951+ z = (*it).center.z;
4952+
4953+ SetIconXForm (launcher_icon, ViewProjectionMatrix, geo, x, y, w, h, z, "HitArea");
4954+ }
4955+}
4956+
4957+void GetInverseScreenPerspectiveMatrix(nux::Matrix4& ViewMatrix, nux::Matrix4& PerspectiveMatrix,
4958+ int ViewportWidth,
4959+ int ViewportHeight,
4960+ float NearClipPlane,
4961+ float FarClipPlane,
4962+ float Fovy)
4963+{
4964+/*
4965+ Objective:
4966+ Given a perspective matrix defined by (Fovy, AspectRatio, NearPlane, FarPlane), we want to compute
4967+ the ModelView matrix that transform a quad defined by its top-left coord (0, 0) and its
4968+ bottom-right coord (WindowWidth, WindowHeight) into a full screen quad that covers the entire viewport (one to one).
4969+ Any quad that is facing the camera and whose 4 points are on the 4 guiding line of the view frustum (pyramid)
4970+ will always cover the entire viewport one to one (when projected on the screen).
4971+ 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
4972+ the quad touches the 4 guiding lines of the view frustum.
4973+ We consider a well centered projection view (no skewing, no oblique clipping plane, ...) and derive the following equations:
4974+ x_cs = AspectRatio*y_cs
4975+ 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).
4976+
4977+ 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)
4978+ 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,
4979+ then its 4 corners are each on the 4 lines of the view frustum.
4980+
4981+ (-x_cs, y_cs) Camera Space
4982+ ^
4983+ __________|__________
4984+ | | |
4985+ | | |
4986+ | |(0, 0) |
4987+ |----------|----------|->
4988+ | | |
4989+ | | |
4990+ |__________|__________|
4991+ (x_cs, -y_cs)
4992+
4993+ The full-screen quad (in screen space) is defined by the point (0, 0) (top-left) and (WindowWidth, WindowHeight) (bottom-right).
4994+ 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
4995+ the full-screen space.
4996+
4997+ (0, 0) Screen Space
4998+ _____________________->
4999+ | | |
5000+ | | |
The diff has been truncated for viewing.