Merge lp:~azzar1/unity/launcher-devices-improvement into lp:unity

Proposed by Andrea Azzarone
Status: Merged
Merged at revision: 1313
Proposed branch: lp:~azzar1/unity/launcher-devices-improvement
Merge into: lp:unity
Diff against target: 1452 lines (+575/-447)
11 files modified
UnityCore/GLibWrapper.cpp (+4/-1)
com.canonical.Unity.gschema.xml (+4/-9)
plugins/unityshell/src/DeviceLauncherIcon.cpp (+209/-240)
plugins/unityshell/src/DeviceLauncherIcon.h (+12/-9)
plugins/unityshell/src/DeviceLauncherSection.cpp (+98/-70)
plugins/unityshell/src/DeviceLauncherSection.h (+34/-20)
plugins/unityshell/src/DevicesSettings.cpp (+136/-62)
plugins/unityshell/src/DevicesSettings.h (+50/-33)
plugins/unityshell/src/LauncherController.h (+1/-1)
plugins/unityshell/src/unityshell.cpp (+5/-2)
plugins/unityshell/unityshell.xml.in (+22/-0)
To merge this branch: bzr merge lp:~azzar1/unity/launcher-devices-improvement
Reviewer Review Type Date Requested Status
Neil J. Patel (community) Approve
Tim Penhey (community) Approve
Review via email: mp+65537@code.launchpad.net

Commit message

First of all let me show what changes I have done:
* I moved launcher devices options from GSettings to CompizConfig Settings Manager.
* I added a "Keep in launcher" item also for the devices. Since it have no sense having the quicklist item for "Never" and "Always" mode it is enabled only in "Only Mounted" one.
* I changed a bit the signals manager for GVolumeMonitor. Inter alia I moved all volume signals from DeviceLauncherIcon to DeviceLauncherSignal (according to me is less confusing!).
* Use std::map instad of g_hash_table.
* Use GLibWrapper to avoid memory leaks.
* Porting to new code style.

I have tested this work on three different computers. Thanks to Alessandro Cutilli, Nicolò Turatello and Andrea Virgillito for testing. I hope there is not error (code style or weird behavior).

Please pardon me in this case.

Sorry for my poor English.

To post a comment you must log in.
Revision history for this message
Tim Penhey (thumper) wrote :

I notice that your editor is using tab stops. Can you configure it to use
spaces instead of tabs? See the diff for
plugins/unityshell/src/DeviceLauncherSection.cpp to see what I see.

If you are going to the trouble of adding an anonymous namespace, then you
should replace the #define:

plugins/unityshell/src/DeviceLauncherIcon.cpp

namespace {
const char* DEFAULT_ICON = "drive-removable-media";
}

  DeviceLauncherIcon::DeviceLauncherIcon(Launcher *launcher, GVolume *volume)
should be:
  DeviceLauncherIcon::DeviceLauncherIcon(Launcher* launcher, GVolume* volume)

Keep the pointer with the type not the variable name.

> void DeviceLauncherIcon::UpdateDeviceIcon()

The extra scoping you have in this method don't really help the readability,
nor are they required for early destruction of the objects. Can you remove
them please?

There is no point at all in adding the "inline" keyword to a function in the
source file. Inlining only works if the compiler knows at the time the other
source file is being compiled (at least I'm fairly sure about that).

> std::list<DbusmenuMenuitem *> DeviceLauncherIcon::GetMenus()

I'm not a fan of returning containers from methods. Normally there is a
better way to structure the program. You don't need to do anything about this
at this stage, just somethingn to consider for the future.

Although I just noticed that the list is containing things that you explicitly
create. This means that every time you call this method you need to remember
to explicitly free all of the objects. Hmm... I also see that you didn't
create this method. I'll chase this up elsewhere.

> void DeviceLauncherIcon::ShowMount(GMount *mount)

Please keep the pointer with the type.

> g_mount_unmount_with_operation(mount.RawPtr(),

This should work without the .RawPtr() call. The object implements an
operator OBJECT* method, and since the g_mount_unmount_with_operation expects
a GMount, the method is used.

Same for g_drive_stop.
Also try for the g_signal_connect. It should work. Let me know if it
doesn't.

std::map<GVolume *, DeviceLauncherIcon *> is screaming for a typedef. The
whole using a map based on pointers makes me queezy. I don't feel comfortable
that the contained values are destroyed consistently. The are newed when
added to the map, but removal just calls erase. I don't see a corresponding
delete. Instead of storing raw pointers, could we key it off a consistent
name perhaps? And store smart pointers?

review: Needs Fixing
Revision history for this message
Andrea Azzarone (azzar1) wrote :
Download full text (3.3 KiB)

> I notice that your editor is using tab stops. Can you configure it to use
> spaces instead of tabs? See the diff for
> plugins/unityshell/src/DeviceLauncherSection.cpp to see what I see.

Of course.

> If you are going to the trouble of adding an anonymous namespace, then you
> should replace the #define:
>
> plugins/unityshell/src/DeviceLauncherIcon.cpp
>
> namespace {
> const char* DEFAULT_ICON = "drive-removable-media";
> }

Of course.

> DeviceLauncherIcon::DeviceLauncherIcon(Launcher *launcher, GVolume *volume)
> should be:
> DeviceLauncherIcon::DeviceLauncherIcon(Launcher* launcher, GVolume* volume)
>
> Keep the pointer with the type not the variable name.

I don't like it, but it will be done ;)

> > void DeviceLauncherIcon::UpdateDeviceIcon()
>
> The extra scoping you have in this method don't really help the readability,
> nor are they required for early destruction of the objects. Can you remove
> them please?
>

Sure. They are not my method.

> There is no point at all in adding the "inline" keyword to a function in the
> source file. Inlining only works if the compiler knows at the time the other
> source file is being compiled (at least I'm fairly sure about that).
>

Ops...

> > std::list<DbusmenuMenuitem *> DeviceLauncherIcon::GetMenus()
>
> I'm not a fan of returning containers from methods. Normally there is a
> better way to structure the program. You don't need to do anything about this
> at this stage, just somethingn to consider for the future.
>
> Although I just noticed that the list is containing things that you explicitly
> create. This means that every time you call this method you need to remember
> to explicitly free all of the objects. Hmm... I also see that you didn't
> create this method. I'll chase this up elsewhere.
>

I can do nothing here. This is the quicklist manager if i am not wrong. Let me know
what can i do here.

> > void DeviceLauncherIcon::ShowMount(GMount *mount)
>
> Please keep the pointer with the type.
>
> > g_mount_unmount_with_operation(mount.RawPtr(),
>
> This should work without the .RawPtr() call. The object implements an
> operator OBJECT* method, and since the g_mount_unmount_with_operation expects
> a GMount, the method is used.
>

I use this because sometimes i got warnings.

> Same for g_drive_stop.
> Also try for the g_signal_connect. It should work. Let me know if it
> doesn't.
>

I will try...

> std::map<GVolume *, DeviceLauncherIcon *> is screaming for a typedef. The
> whole using a map based on pointers makes me queezy. I don't feel comfortable
> that the contained values are destroyed consistently. The are newed when
> added to the map, but removal just calls erase. I don't see a corresponding
> delete. Instead of storing raw pointers, could we key it off a consistent
> name perhaps? And store smart pointers?

Instead of <GVolume*> we could use a uuid but according to me is too slow... For the key
(GVolume *) we don't need a g_object_unref(...).
For what regard the value (DeviceLauncherIcon *) we cannot use a smart pointer (i used a boost one) because when we OnVolumeRemoved is called, we call "self->map_[volume]->OnRemoved();" that call Ico...

Read more...

Revision history for this message
Andrea Azzarone (azzar1) wrote :

I haven't tested what happens removing RawPtr in other computers (just on mine).

Revision history for this message
Tim Penhey (thumper) wrote :

> > > void DeviceLauncherIcon::UpdateDeviceIcon()
> >
> > The extra scoping you have in this method don't really help the readability,
> > nor are they required for early destruction of the objects. Can you remove
> > them please?
> >
>
> Sure. They are not my method.

Aah. You are right. I can now see that you just replaced the gchar with the
glib::String. The old scopes were there to show the lifetime of the glib
created data, and they are no longer needed. Thanks for cleaning this up.

> > > std::list<DbusmenuMenuitem *> DeviceLauncherIcon::GetMenus()
> I can do nothing here. This is the quicklist manager if i am not wrong. Let me
> know what can i do here.

I did say that I can see this wasn't created by you :-) I will chase up the
design.

> > > void DeviceLauncherIcon::ShowMount(GMount *mount)
> >
> > Please keep the pointer with the type.
> >
> > > g_mount_unmount_with_operation(mount.RawPtr(),
> >
> > This should work without the .RawPtr() call. The object implements an
> > operator OBJECT* method, and since the g_mount_unmount_with_operation
> expects
> > a GMount, the method is used.
> >
>
> I use this because sometimes i got warnings.

There would be warnings in the places where it wasn't clear to the compiler
what you were wanting. But for most places it should work without the
.RawPtr() call.

> > std::map<GVolume *, DeviceLauncherIcon *> is screaming for a typedef. The
> > whole using a map based on pointers makes me queezy. I don't feel
> comfortable
> > that the contained values are destroyed consistently. The are newed when
> > added to the map, but removal just calls erase. I don't see a corresponding
> > delete. Instead of storing raw pointers, could we key it off a consistent
> > name perhaps? And store smart pointers?
>
> Instead of <GVolume*> we could use a uuid but according to me is too slow...
> For the key
> (GVolume *) we don't need a g_object_unref(...).
> For what regard the value (DeviceLauncherIcon *) we cannot use a smart pointer
> (i used a boost one) because when we OnVolumeRemoved is called, we call
> "self->map_[volume]->OnRemoved();" that call IconLauncher::Remove() that emit
> a signal that is handled by LancherController.cpp or LauncherModels.cpp (I
> don't remember! :) ) that unref the icon... If we use a smartpointer we
> "unref" it twice... Correct me if I'm wrong.

You see... here is my problem. None of this is obvious to me (the reader of
the code). I'll leave that logic part to Neil to verify.

= New stuff =

You have a checked_ member variable. "Checked" I think could be changed to
something a little more descriptive. "keep_in_launcher_" perhaps?

The constructor sets:
  checked_ = !(pos != favorites.end());
this is more simply written:
  checked_ = pos == favorites.end();

Which then makes me wonder, what is the purpose of "checked_".

This same double negative logic is found in
DeviceLauncherIcon::OnSettingsChanged

In summary, the only things I'd like to hear back about is the checked_
member, and the double negative logic.

Thanks for the updates.

review: Needs Fixing
Revision history for this message
Andrea Azzarone (azzar1) wrote :

* I changed 'checked_' in `keep_in_launcher_` and also its behavior to make it more readable.
* I ported it to 4.0 trunk.

Revision history for this message
Tim Penhey (thumper) wrote :

I'm happy with these changes. I'd like Neil to just confirm the lifecycle of the DeviceLauncherIcon you mentioned above. I've copied it here to make it easy for Neil :-)

> Instead of <GVolume*> we could use a uuid but according to me is too slow... For the key
> (GVolume *) we don't need a g_object_unref(...).
> For what regard the value (DeviceLauncherIcon *) we cannot use a smart pointer (i used a boost one)
> because when we OnVolumeRemoved is called, we call "self->map_[volume]->OnRemoved();" that call
> IconLauncher::Remove() that emit a signal that is handled by LancherController.cpp or LauncherModels.cpp
> (I don't remember! :) ) that unref the icon... If we use a smartpointer we "unref" it
> twice... Correct me if I'm wrong.

review: Approve
Revision history for this message
Andrea Azzarone (azzar1) wrote :

@Tim, if the destructor of the DeviceLauncherIcon is called, it means that it works right?

Revision history for this message
Andrea Azzarone (azzar1) wrote :

@Tim I think that in glib::String::Str() there is a little problem:

=================================================================
std::string String::Str() const
{
  return std::string(string_);
}
=================================================================

In fact if string_ is NULL an exception is thrown (at least this happens on
my computer). I noticed this because this branch crash if we have
a gvolume without uuid (e.g. a cd-rom). This fix works good but i don't know
if this is the better way to fix:

=================================================================
std::string String::Str() const
{
  if (string_)
    return std::string(string_);
  else
    return std::string("");
}
=================================================================

You are the expert, so let me know if this is a good fix :)

Revision history for this message
Tim Penhey (thumper) wrote :

On Sat, 25 Jun 2011 20:18:31 you wrote:
> @Tim I think that in glib::String::Str() there is a little problem:
>
> =================================================================
> std::string String::Str() const
> {
> return std::string(string_);
> }
> =================================================================
>
> In fact if string_ is NULL an exception is thrown (at least this happens on
> my computer). I noticed this because this branch crash if we have
> a gvolume without uuid (e.g. a cd-rom). This fix works good but i don't
> know if this is the better way to fix:
>
> =================================================================
> std::string String::Str() const
> {
> if (string_)
> return std::string(string_);
> else
> return std::string("");
> }
> =================================================================
>
> You are the expert, so let me know if this is a good fix :)

Yeah. I think that fix is fine.

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

Hey, sorry for the late merge. This looks good and works well. However it has a merge-conflict with trunk. If you could update it I'll merge it as soon as it's ready.

Nice work!

review: Approve
Revision history for this message
Omer Akram (om26er) wrote :

Could you also change the string 'springboard' to 'launcher' when fixing the merge conflict. Not many people are aware of what springboard is

Revision history for this message
Andrea Azzarone (azzar1) wrote :

Done.

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

Thanks Andrea, could you please ping me tomorrow as there's a few things I need to check with you before committing the code, thanks!

review: Approve
Revision history for this message
Andrea Azzarone (azzar1) wrote :

Of course, see you tomorrow...

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

Hey Andy, so I cleaned out my system and tested again on a fresh Nux and Unity install on Oneiric. Adding/removing USB/external harddrives/cd-rom's etc works perfectly. And the setting in ccsm works perfectly too, nice one!

However I never see the "Keep in Launcher" option on any device (when I have "Only Mounted" showing) :/ Is there something else that needs to change for me to see that? I've updated my system-wide unity schema with the one from your branch so it shouldn't be that...

Revision history for this message
Andrea Azzarone (azzar1) wrote :

"Keep in launcher" option should be visible only for un-removable devices (when "Only Mounted" is checked). I will work on it.

Revision history for this message
Andrea Azzarone (azzar1) wrote :

Hey Neil, maybe you have a "automounted configuration" in /etc/fstab (or something like that). I know, it's a my mistake, but if it is the problem, last commit should resolve the problem. Let me know!

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

Hey Andrea, fstab has no automount configuration for these drives (one is CD-ROM and other is 4G USB key). I tried your latest branch but still doesn't show the Keep In Launcher :( Are you on Oneiric? I wonder if something has changed...maybe tomorrow if you ping me we can debug this together, I can play around with the branch and get some more debug information for you.

Revision history for this message
Tim Penhey (thumper) wrote :

Neil,

Why would you want a "Keep in Launcher" option for a removable device?

Revision history for this message
Andrea Azzarone (azzar1) wrote :

Neil, i am on Oneiric...
I'll ping you as soon as possible, by the way you can printf the value of:
DevicesSettings::GetDefault().GetDevicesOption() == DevicesSettings::ONLY_MOUNTED

and of:
g_drive_is_media_removable (drive)

in DeviceLauncherIcons::GetMenus

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

I don't, but it was part of the design I believe.

@andyrock, will try and do that tomorrow morning (am not at computer today)

Sent from my iPhone

On 7 Jul 2011, at 22:56, Tim Penhey <email address hidden> wrote:

> Neil,
>
> Why would you want a "Keep in Launcher" option for a removable device?
>
> --
> https://code.launchpad.net/~andyrock/unity/launcher-devices-improvement/+merge/65537
> You are reviewing the proposed merge of lp:~andyrock/unity/launcher-devices-improvement into lp:unity.

Revision history for this message
Andrea Azzarone (azzar1) wrote :

===================================================================
1) It should be possible to remove specific file system icons from the Launcher by un-checking the “Keep in Launcher” option (or dragging to the trash).
===================================================================

This branch use the "Keep in Launcher" option but not the dragging to the trash, since there is another bug report (#764905), and my merge proposal, with a different behavior: «Drag and drop a USB key into the trash should eject the USB key».

===================================================================
2) In the case of non-removable file systems, the system should remember these settings so that rebooting will not return these icons to the Launcher.
===================================================================
Ok, this branch does it (at least I hope :)

===================================================================
3) In the case of removable file systems (USB keys, SD cards, etc...), if a removable file system is removed and then re-attached it should re-appear in the Launcher. If the removable file system is not removed and the user has removed it's icon from the Launcher, the icon should not return to the Launcher even if the computer is re-booted.
===================================================================

According to me, this is absurd and make no sense and not so easy to do! :)

===================================================================
4) All 'specific file system' icons that the user has removed from the Launcher should be displayed in the Dash file Lens in the “Favourite Folders/Folders” category. This allows the user to re-add these icons to the Launcher at a later date
===================================================================
According to me this is in part a unity-file-place (???) bug... So first we should add the "specific file system" icons in the Dash file Lens and i cannot (i hate python!) do this.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'UnityCore/GLibWrapper.cpp'
2--- UnityCore/GLibWrapper.cpp 2011-07-21 14:59:25 +0000
3+++ UnityCore/GLibWrapper.cpp 2011-07-26 12:37:20 +0000
4@@ -79,7 +79,10 @@
5
6 std::string String::Str() const
7 {
8- return std::string(string_);
9+ if (string_)
10+ return std::string(string_);
11+ else
12+ return std::string("");
13 }
14
15
16
17=== modified file 'com.canonical.Unity.gschema.xml'
18--- com.canonical.Unity.gschema.xml 2011-07-21 09:54:39 +0000
19+++ com.canonical.Unity.gschema.xml 2011-07-26 12:37:20 +0000
20@@ -4,11 +4,6 @@
21 <value nick="Desktop" value="1" />
22 <value nick="Netbook" value="2" />
23 </enum>
24- <enum id="devices-option-enum">
25- <value nick="Never" value="0" />
26- <value nick="OnlyMounted" value="1" />
27- <value nick="Always" value="2" />
28- </enum>
29 <enum id="home-expanded-enum">
30 <value nick="Not Expanded" value="0" />
31 <value nick="Expanded" value="1" />
32@@ -51,10 +46,10 @@
33 </key>
34 </schema>
35 <schema path="/desktop/unity/devices/" id="com.canonical.Unity.Devices" gettext-domain="unity">
36- <key enum="devices-option-enum" name="devices-option">
37- <default>"OnlyMounted"</default>
38- <summary>The devices that will be shown on launcher</summary>
39- <description>Key for setting the devices that will be shown on launcher. </description>
40+ <key type="as" name="favorites">
41+ <default>[]</default>
42+ <summary>List of device uuid for favorites on the launcher.</summary>
43+ <description>These devices are shown in the Launcher by default.</description>
44 </key>
45 </schema>
46 <schema path="/desktop/unity/runner/" id="com.canonical.Unity.Runner" gettext-domain="unity">
47
48=== modified file 'plugins/unityshell/src/DeviceLauncherIcon.cpp'
49--- plugins/unityshell/src/DeviceLauncherIcon.cpp 2011-07-21 14:59:25 +0000
50+++ plugins/unityshell/src/DeviceLauncherIcon.cpp 2011-07-26 12:37:20 +0000
51@@ -19,428 +19,397 @@
52
53 #include "DeviceLauncherIcon.h"
54
55+#include <algorithm>
56+#include <list>
57+
58+#include <glib/gi18n-lib.h>
59+#include <libnotify/notify.h>
60+
61+#include "DevicesSettings.h"
62 #include "ubus-server.h"
63 #include "UBusMessages.h"
64
65-#include <glib/gi18n-lib.h>
66-#include <libnotify/notify.h>
67-
68-#define DEFAULT_ICON "drive-removable-media"
69+namespace unity {
70
71 DeviceLauncherIcon::DeviceLauncherIcon(Launcher* launcher, GVolume* volume)
72- : SimpleLauncherIcon(launcher),
73- _volume(volume)
74+ : SimpleLauncherIcon(launcher)
75+ , volume_(volume)
76 {
77-
78- DevicesSettings::GetDefault()->changed.connect(sigc::mem_fun(this, &DeviceLauncherIcon::OnSettingsChanged));
79-
80- _on_removed_handler_id = g_signal_connect(_volume,
81- "removed",
82- G_CALLBACK(&DeviceLauncherIcon::OnRemoved),
83- this);
84-
85- _on_changed_handler_id = g_signal_connect(_volume,
86- "changed",
87- G_CALLBACK(&DeviceLauncherIcon::OnChanged),
88- this);
89-
90+ DevicesSettings::GetDefault().changed.connect(sigc::mem_fun(this, &DeviceLauncherIcon::OnSettingsChanged));
91+
92+ // Checks if in favourites!
93+ glib::String uuid(g_volume_get_identifier(volume_, G_VOLUME_IDENTIFIER_KIND_UUID));
94+ DeviceList favorites = DevicesSettings::GetDefault().GetFavorites();
95+ DeviceList::iterator pos = std::find(favorites.begin(), favorites.end(), uuid.Str());
96+
97+ keep_in_launcher_ = pos != favorites.end();
98+
99 UpdateDeviceIcon();
100-
101 UpdateVisibility();
102-
103-}
104-
105-DeviceLauncherIcon::~DeviceLauncherIcon()
106-{
107- if (_on_removed_handler_id != 0)
108- g_signal_handler_disconnect((gpointer) _volume, _on_removed_handler_id);
109-
110- if (_on_changed_handler_id != 0)
111- g_signal_handler_disconnect((gpointer) _volume, _on_changed_handler_id);
112-}
113-
114-void
115-DeviceLauncherIcon::UpdateDeviceIcon()
116-{
117- {
118- gchar* name;
119- name = g_volume_get_name(_volume);
120- tooltip_text = name;
121-
122- g_free(name);
123- }
124-
125- {
126- GIcon* icon;
127- gchar* icon_string;
128-
129- icon = g_volume_get_icon(_volume);
130- icon_string = g_icon_to_string(icon);
131-
132- SetIconName(icon_string);
133-
134- g_object_unref(icon);
135- g_free(icon_string);
136- }
137-
138- SetQuirk(QUIRK_VISIBLE, true);
139+}
140+
141+void DeviceLauncherIcon::UpdateDeviceIcon()
142+{
143+ glib::String name(g_volume_get_name(volume_));
144+ glib::Object<GIcon> icon(g_volume_get_icon(volume_));
145+ glib::String icon_string(g_icon_to_string(icon));
146+
147+ tooltip_text = name.Value();
148+ SetIconName(icon_string.Value());
149+
150+ SetIconType(TYPE_DEVICE);
151 SetQuirk(QUIRK_RUNNING, false);
152- SetIconType(TYPE_DEVICE);
153-}
154-
155-nux::Color
156-DeviceLauncherIcon::BackgroundColor()
157-{
158- return nux::Color(0xFF333333);
159-}
160-
161-nux::Color
162-DeviceLauncherIcon::GlowColor()
163-{
164- return nux::Color(0xFF333333);
165 }
166
167 bool
168 DeviceLauncherIcon::CanEject()
169 {
170- return g_volume_can_eject(_volume);
171-}
172-
173-std::list<DbusmenuMenuitem*>
174-DeviceLauncherIcon::GetMenus()
175-{
176- std::list<DbusmenuMenuitem*> result;
177- DbusmenuMenuitem* menu_item;
178- GDrive* drive;
179-
180+ return g_volume_can_eject(volume_);
181+}
182+
183+nux::Color DeviceLauncherIcon::BackgroundColor()
184+{
185+ return nux::Color(0xFF333333);
186+}
187+
188+nux::Color DeviceLauncherIcon::GlowColor()
189+{
190+ return nux::Color(0xFF333333);
191+}
192+
193+std::list<DbusmenuMenuitem*> DeviceLauncherIcon::GetMenus()
194+{
195+ std::list<DbusmenuMenuitem*> result;
196+ DbusmenuMenuitem* menu_item;
197+ glib::Object<GDrive> drive(g_volume_get_drive(volume_));
198+
199+ // "Keep in launcher" item
200+ if (DevicesSettings::GetDefault().GetDevicesOption() == DevicesSettings::ONLY_MOUNTED
201+ && drive && !g_drive_is_media_removable (drive))
202+ {
203+ menu_item = dbusmenu_menuitem_new();
204+
205+ dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Keep in launcher"));
206+ dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE, DBUSMENU_MENUITEM_TOGGLE_CHECK);
207+ dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
208+ dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
209+ dbusmenu_menuitem_property_set_int(menu_item, DBUSMENU_MENUITEM_PROP_TOGGLE_STATE, !keep_in_launcher_);
210+
211+ g_signal_connect(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
212+ G_CALLBACK(&DeviceLauncherIcon::OnTogglePin), this);
213+
214+ result.push_back(menu_item);
215+ }
216+
217+ // "Open" item
218 menu_item = dbusmenu_menuitem_new();
219+
220 dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Open"));
221 dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
222 dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
223+
224 g_signal_connect(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
225 G_CALLBACK(&DeviceLauncherIcon::OnOpen), this);
226+
227 result.push_back(menu_item);
228
229- if (g_volume_can_eject(_volume))
230+ // "Eject" item
231+ if (g_volume_can_eject(volume_))
232 {
233 menu_item = dbusmenu_menuitem_new();
234+
235 dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Eject"));
236 dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
237 dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
238+
239 g_signal_connect(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
240 G_CALLBACK(&DeviceLauncherIcon::OnEject), this);
241+
242 result.push_back(menu_item);
243 }
244
245- drive = g_volume_get_drive(_volume);
246+ // "Safely Remove" item (FIXME: Should it be "Safely remove"?)
247 if (drive && g_drive_can_stop(drive))
248 {
249 menu_item = dbusmenu_menuitem_new();
250+
251 dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Safely Remove"));
252 dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
253 dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
254+
255 g_signal_connect(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
256 G_CALLBACK(&DeviceLauncherIcon::OnDriveStop), this);
257+
258 result.push_back(menu_item);
259 }
260- if (drive)
261- {
262- g_object_unref(drive);
263- }
264-
265- if (!g_volume_can_eject(_volume)) // Don't need Unmount if can Eject
266- {
267- GMount* mount = g_volume_get_mount(_volume);
268+
269+ // "Unmount" item
270+ if (!g_volume_can_eject(volume_)) // Don't need Unmount if can Eject
271+ {
272+ glib::Object<GMount> mount(g_volume_get_mount(volume_));
273+
274 if (mount && g_mount_can_unmount(mount))
275 {
276 menu_item = dbusmenu_menuitem_new();
277+
278 dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Unmount"));
279 dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
280 dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
281+
282 g_signal_connect(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
283 G_CALLBACK(&DeviceLauncherIcon::OnUnmount), this);
284+
285 result.push_back(menu_item);
286 }
287- if (mount)
288- {
289- g_object_unref(mount);
290- }
291 }
292
293 return result;
294 }
295
296-void
297-DeviceLauncherIcon::ShowMount(GMount* mount)
298+void DeviceLauncherIcon::ShowMount(GMount* mount)
299 {
300- gchar* name;
301-
302- name = g_volume_get_name(_volume);
303+ glib::String name(g_volume_get_name(volume_));
304+
305 if (G_IS_MOUNT(mount))
306 {
307- GFile* root;
308+ glib::Object<GFile> root(g_mount_get_root(mount));
309
310- root = g_mount_get_root(mount);
311- if (G_IS_FILE(root))
312+ if (G_IS_FILE(root.RawPtr()))
313 {
314- gchar* uri;
315- GError* error = NULL;
316-
317- uri = g_file_get_uri(root);
318-
319- g_app_info_launch_default_for_uri(uri, NULL, &error);
320+ glib::String uri(g_file_get_uri(root));
321+ glib::Error error;
322+
323+ g_app_info_launch_default_for_uri(uri.Value(), NULL, error.AsOutParam());
324+
325 if (error)
326- {
327- g_warning("Cannot open volume '%s': Unable to show %s: %s", name, uri, error->message);
328- g_error_free(error);
329- }
330-
331- g_free(uri);
332- g_object_unref(root);
333+ g_warning("Cannot open volume '%s': Unable to show %s: %s", name.Value(), uri.Value(), error.Message().c_str());
334 }
335 else
336 {
337- g_warning("Cannot open volume '%s': Mount has no root", name);
338+ g_warning ("Cannot open volume '%s': Mount has no root", name.Value());
339 }
340 }
341 else
342 {
343- g_warning("Cannot open volume '%s': Mount-point is invalid", name);
344+ g_warning ("Cannot open volume '%s': Mount-point is invalid", name.Value());
345 }
346-
347- g_free(name);
348 }
349
350-void
351-DeviceLauncherIcon::ActivateLauncherIcon(ActionArg arg)
352+void DeviceLauncherIcon::ActivateLauncherIcon(ActionArg arg)
353 {
354- GMount* mount;
355- gchar* name;
356-
357 SetQuirk(QUIRK_STARTING, true);
358+
359+ glib::Object<GMount> mount(g_volume_get_mount(volume_));
360
361- name = g_volume_get_name(_volume);
362- mount = g_volume_get_mount(_volume);
363- if (G_IS_MOUNT(mount))
364- {
365+ if (G_IS_MOUNT(mount.RawPtr()))
366 ShowMount(mount);
367- g_object_unref(mount);
368- }
369 else
370- {
371- g_volume_mount(_volume,
372+ g_volume_mount(volume_,
373 (GMountMountFlags)0,
374 NULL,
375 NULL,
376 (GAsyncReadyCallback)&DeviceLauncherIcon::OnMountReady,
377 this);
378- }
379-
380- g_free(name);
381 }
382
383-void
384-DeviceLauncherIcon::OnMountReady(GObject* object, GAsyncResult* result, DeviceLauncherIcon* self)
385+void DeviceLauncherIcon::OnMountReady(GObject* object,
386+ GAsyncResult* result,
387+ DeviceLauncherIcon* self)
388 {
389- GError* error = NULL;
390+ glib::Error error;
391
392- if (g_volume_mount_finish(self->_volume, result, &error))
393+ if (g_volume_mount_finish(self->volume_, result, error.AsOutParam()))
394 {
395- GMount* mount;
396-
397- mount = g_volume_get_mount(self->_volume);
398+ glib::Object<GMount> mount(g_volume_get_mount(self->volume_));
399 self->ShowMount(mount);
400-
401- g_object_unref(mount);
402 }
403 else
404 {
405- gchar* name;
406+ glib::String name(g_volume_get_name(self->volume_));
407
408- name = g_volume_get_name(self->_volume);
409 g_warning("Cannot open volume '%s': %s",
410- name,
411- error ? error->message : "Mount operation failed");
412- g_error_free(error);
413-
414- g_free(name);
415+ name.Value(),
416+ error ? error.Message().c_str() : "Mount operation failed");
417 }
418 }
419
420-void
421-DeviceLauncherIcon::OnEjectReady(GObject* object,
422- GAsyncResult* result,
423- DeviceLauncherIcon* self)
424+void DeviceLauncherIcon::OnEjectReady(GObject* object,
425+ GAsyncResult* result,
426+ DeviceLauncherIcon* self)
427 {
428- if (g_volume_eject_with_operation_finish(self->_volume, result, NULL))
429+ if (g_volume_eject_with_operation_finish(self->volume_, result, NULL))
430 {
431 NotifyNotification* notification;
432- gchar* name = g_volume_get_name(self->_volume);
433+ glib::String name(g_volume_get_name(self->volume_));
434
435- notification = notify_notification_new(name,
436+ notification = notify_notification_new(name.Value(),
437 _("The drive has been successfully ejected"),
438 "drive-removable-media-usb");
439
440 notify_notification_show(notification, NULL);
441-
442- g_free(name);
443 }
444 }
445
446-void
447-DeviceLauncherIcon::Eject()
448+void DeviceLauncherIcon::Eject()
449 {
450- GMountOperation* mount_op;
451-
452- mount_op = gtk_mount_operation_new(NULL);
453-
454- g_volume_eject_with_operation(_volume,
455+ glib::Object<GMountOperation> mount_op(gtk_mount_operation_new(NULL));
456+
457+ g_volume_eject_with_operation(volume_,
458 (GMountUnmountFlags)0,
459 mount_op,
460 NULL,
461 (GAsyncReadyCallback)OnEjectReady,
462 this);
463-
464- g_object_unref(mount_op);
465-}
466-
467-void
468-DeviceLauncherIcon::OnOpen(DbusmenuMenuitem* item, int time, DeviceLauncherIcon* self)
469+}
470+
471+void DeviceLauncherIcon::OnTogglePin(DbusmenuMenuitem* item,
472+ int time,
473+ DeviceLauncherIcon* self)
474+{
475+ glib::String uuid(g_volume_get_identifier(self->volume_, G_VOLUME_IDENTIFIER_KIND_UUID));
476+
477+ self->keep_in_launcher_ = !self->keep_in_launcher_;
478+
479+ if (!self->keep_in_launcher_)
480+ {
481+ // If the volume is not mounted hide the icon
482+ glib::Object<GMount> mount(g_volume_get_mount(self->volume_));
483+
484+ if (!mount)
485+ self->SetQuirk(QUIRK_VISIBLE, false);
486+
487+ // Remove from favorites
488+ if (!uuid.Str().empty())
489+ DevicesSettings::GetDefault().RemoveFavorite(uuid.Str());
490+ }
491+ else
492+ {
493+ if (!uuid.Str().empty())
494+ DevicesSettings::GetDefault().AddFavorite(uuid.Str());
495+ }
496+}
497+
498+void DeviceLauncherIcon::OnOpen(DbusmenuMenuitem* item,
499+ int time,
500+ DeviceLauncherIcon* self)
501 {
502 self->ActivateLauncherIcon(ActionArg(ActionArg::OTHER, 0));
503 }
504
505-void
506-DeviceLauncherIcon::OnEject(DbusmenuMenuitem* item, int time, DeviceLauncherIcon* self)
507+void DeviceLauncherIcon::OnEject(DbusmenuMenuitem* item,
508+ int time,
509+ DeviceLauncherIcon* self)
510 {
511 self->Eject();
512 }
513
514-void
515-DeviceLauncherIcon::OnUnmountReady(GObject* object,
516- GAsyncResult* result,
517- DeviceLauncherIcon* self)
518+void DeviceLauncherIcon::OnUnmountReady(GObject* object,
519+ GAsyncResult* result,
520+ DeviceLauncherIcon* self)
521 {
522 if (G_IS_MOUNT(object))
523- {
524 g_mount_unmount_with_operation_finish(G_MOUNT(object), result, NULL);
525- }
526 }
527
528-void
529-DeviceLauncherIcon::Unmount()
530+void DeviceLauncherIcon::Unmount()
531 {
532- GMount* mount = g_volume_get_mount(_volume);
533+ glib::Object<GMount> mount(g_volume_get_mount(volume_));
534+
535 if (mount)
536 {
537- GMountOperation* op = gtk_mount_operation_new(NULL);
538+ glib::Object<GMountOperation> op(gtk_mount_operation_new(NULL));
539+
540 g_mount_unmount_with_operation(mount,
541 (GMountUnmountFlags)0,
542 op,
543 NULL,
544 (GAsyncReadyCallback)OnUnmountReady,
545 this);
546- g_object_unref(op);
547- g_object_unref(mount);
548 }
549 }
550
551-void
552-DeviceLauncherIcon::OnUnmount(DbusmenuMenuitem* item, int time, DeviceLauncherIcon* self)
553+void DeviceLauncherIcon::OnUnmount(DbusmenuMenuitem* item,
554+ int time,
555+ DeviceLauncherIcon* self)
556 {
557 self->Unmount();
558 }
559
560-void
561-DeviceLauncherIcon::OnRemoved(GVolume* volume, DeviceLauncherIcon* self)
562+void DeviceLauncherIcon::OnRemoved()
563 {
564- self->_volume = NULL;
565- self->Remove();
566+ Remove();
567 }
568
569-void
570-DeviceLauncherIcon::OnDriveStop(DbusmenuMenuitem* item, int time, DeviceLauncherIcon* self)
571+void DeviceLauncherIcon::OnDriveStop(DbusmenuMenuitem* item,
572+ int time,
573+ DeviceLauncherIcon* self)
574 {
575 self->StopDrive();
576 }
577
578-void
579-DeviceLauncherIcon::StopDrive()
580+void DeviceLauncherIcon::StopDrive()
581 {
582- GDrive* drive;
583- GMountOperation* mount_op;
584+ glib::Object<GDrive> drive(g_volume_get_drive(volume_));
585+ glib::Object<GMountOperation> mount_op(gtk_mount_operation_new(NULL));
586
587- drive = g_volume_get_drive(_volume);
588- mount_op = gtk_mount_operation_new(NULL);
589 g_drive_stop(drive,
590 (GMountUnmountFlags)0,
591 mount_op,
592 NULL,
593 (GAsyncReadyCallback)OnStopDriveReady,
594 this);
595- g_object_unref(drive);
596- g_object_unref(mount_op);
597 }
598
599-void
600-DeviceLauncherIcon::OnStopDriveReady(GObject* object,
601- GAsyncResult* result,
602- DeviceLauncherIcon* self)
603+void DeviceLauncherIcon::OnStopDriveReady(GObject* object,
604+ GAsyncResult* result,
605+ DeviceLauncherIcon* self)
606 {
607- GDrive* drive;
608
609- if (!self || !G_IS_VOLUME(self->_volume))
610- {
611+ if (!self || !G_IS_VOLUME(self->volume_))
612 return;
613- }
614
615- drive = g_volume_get_drive(self->_volume);
616+ glib::Object<GDrive> drive(g_volume_get_drive(self->volume_));
617 g_drive_stop_finish(drive, result, NULL);
618- g_object_unref(drive);
619-}
620-
621-void
622-DeviceLauncherIcon::OnChanged(GVolume* volume, DeviceLauncherIcon* self)
623-{
624- if (DevicesSettings::GetDefault()->GetDevicesOption() == DevicesSettings::ONLY_MOUNTED
625- && g_volume_get_mount(volume) == NULL)
626- {
627- self->SetQuirk(QUIRK_VISIBLE, false);
628- }
629-}
630-
631-void
632-DeviceLauncherIcon::UpdateVisibility()
633-{
634- switch (DevicesSettings::GetDefault()->GetDevicesOption())
635+}
636+
637+void DeviceLauncherIcon::UpdateVisibility(int visibility)
638+{
639+ switch (DevicesSettings::GetDefault().GetDevicesOption())
640 {
641 case DevicesSettings::NEVER:
642 SetQuirk(QUIRK_VISIBLE, false);
643 break;
644 case DevicesSettings::ONLY_MOUNTED:
645- {
646- GMount* mount = g_volume_get_mount(_volume);
647-
648- if (mount == NULL)
649- {
650- SetQuirk(QUIRK_VISIBLE, false);
651+ if (keep_in_launcher_)
652+ {
653+ SetQuirk(QUIRK_VISIBLE, true);
654+ }
655+ else if (visibility < 0)
656+ {
657+ glib::Object<GMount> mount(g_volume_get_mount(volume_));
658+ SetQuirk(QUIRK_VISIBLE, mount.RawPtr() != NULL);
659 }
660 else
661 {
662- SetQuirk(QUIRK_VISIBLE, true);
663- g_object_unref(mount);
664+ SetQuirk(QUIRK_VISIBLE, visibility);
665 }
666 break;
667- }
668 case DevicesSettings::ALWAYS:
669 SetQuirk(QUIRK_VISIBLE, true);
670 break;
671 }
672 }
673
674-void
675-DeviceLauncherIcon::OnSettingsChanged(DevicesSettings* settings)
676+void DeviceLauncherIcon::OnSettingsChanged()
677 {
678+ // Checks if in favourites!
679+ glib::String uuid(g_volume_get_identifier(volume_, G_VOLUME_IDENTIFIER_KIND_UUID));
680+ DeviceList favorites = DevicesSettings::GetDefault().GetFavorites();
681+ DeviceList::iterator pos = std::find(favorites.begin(), favorites.end(), uuid.Str());
682+
683+ keep_in_launcher_ = pos != favorites.end();
684+
685 UpdateVisibility();
686 }
687
688+} // namespace unity
689
690=== modified file 'plugins/unityshell/src/DeviceLauncherIcon.h'
691--- plugins/unityshell/src/DeviceLauncherIcon.h 2011-07-21 14:59:25 +0000
692+++ plugins/unityshell/src/DeviceLauncherIcon.h 2011-07-26 12:37:20 +0000
693@@ -20,21 +20,23 @@
694 #ifndef _DEVICE_LAUNCHER_ICON_H__H
695 #define _DEVICE_LAUNCHER_ICON_H__H
696
697+#include <gio/gio.h>
698+#include <UnityCore/GLibWrapper.h>
699+
700 #include "SimpleLauncherIcon.h"
701-#include "DevicesSettings.h"
702
703-#include <gio/gio.h>
704+namespace unity {
705
706 class DeviceLauncherIcon : public SimpleLauncherIcon
707 {
708
709 public:
710 DeviceLauncherIcon(Launcher* launcher, GVolume* volume);
711- ~DeviceLauncherIcon();
712
713 virtual nux::Color BackgroundColor();
714 virtual nux::Color GlowColor();
715- void UpdateVisibility();
716+ void UpdateVisibility(int visibility = -1);
717+ void OnRemoved();
718 bool CanEject();
719 void Eject();
720
721@@ -47,22 +49,23 @@
722 void ShowMount(GMount* mount);
723 void Unmount();
724 void StopDrive();
725+ static void OnTogglePin(DbusmenuMenuitem* item, int time, DeviceLauncherIcon* self);
726 static void OnOpen(DbusmenuMenuitem* item, int time, DeviceLauncherIcon* self);
727 static void OnEject(DbusmenuMenuitem* item, int time, DeviceLauncherIcon* self);
728 static void OnUnmount(DbusmenuMenuitem* item, int time, DeviceLauncherIcon* self);
729- static void OnRemoved(GVolume* volume, DeviceLauncherIcon* self);
730 static void OnChanged(GVolume* volume, DeviceLauncherIcon* self);
731 static void OnMountReady(GObject* object, GAsyncResult* result, DeviceLauncherIcon* self);
732 static void OnEjectReady(GObject* object, GAsyncResult* result, DeviceLauncherIcon* self);
733 static void OnUnmountReady(GObject* object, GAsyncResult* result, DeviceLauncherIcon* self);
734 static void OnDriveStop(DbusmenuMenuitem* item, int time, DeviceLauncherIcon* self);
735 static void OnStopDriveReady(GObject* object, GAsyncResult* result, DeviceLauncherIcon* self);
736- void OnSettingsChanged(DevicesSettings* settings);
737+ void OnSettingsChanged();
738
739 private:
740- GVolume* _volume;
741- gulong _on_removed_handler_id;
742- gulong _on_changed_handler_id;
743+ GVolume* volume_;
744+ bool keep_in_launcher_;
745 };
746
747+} // namespace unity
748+
749 #endif // _DEVICE_LAUNCHER_ICON_H__H
750
751=== modified file 'plugins/unityshell/src/DeviceLauncherSection.cpp'
752--- plugins/unityshell/src/DeviceLauncherSection.cpp 2011-07-21 14:59:25 +0000
753+++ plugins/unityshell/src/DeviceLauncherSection.cpp 2011-07-26 12:37:20 +0000
754@@ -16,108 +16,136 @@
755 * Authored by: Neil Jagdish Patel <neil.patel@canonical.com>
756 */
757
758-#include "DeviceLauncherIcon.h"
759-
760 #include "DeviceLauncherSection.h"
761
762+namespace unity
763+{
764+
765 DeviceLauncherSection::DeviceLauncherSection(Launcher* launcher)
766- : _launcher(launcher)
767-{
768- _monitor = g_volume_monitor_get();
769- _ht = g_hash_table_new(g_direct_hash , g_direct_equal);
770-
771- _on_volume_added_handler_id = g_signal_connect(_monitor,
772+ : launcher_(launcher)
773+ , monitor_(g_volume_monitor_get())
774+{
775+ on_volume_added_handler_id_ = g_signal_connect(monitor_,
776 "volume-added",
777 G_CALLBACK(&DeviceLauncherSection::OnVolumeAdded),
778 this);
779
780- _on_volume_removed_handler_id = g_signal_connect(_monitor,
781+ on_volume_removed_handler_id_ = g_signal_connect(monitor_,
782 "volume-removed",
783 G_CALLBACK(&DeviceLauncherSection::OnVolumeRemoved),
784 this);
785-
786- _on_mount_added_handler_id = g_signal_connect(_monitor,
787+
788+ on_mount_added_handler_id_ = g_signal_connect(monitor_,
789 "mount-added",
790 G_CALLBACK(&DeviceLauncherSection::OnMountAdded),
791 this);
792+
793+ on_mount_pre_unmount_handler_id_ = g_signal_connect(monitor_,
794+ "mount-pre-unmount",
795+ G_CALLBACK(&DeviceLauncherSection::OnMountPreUnmount),
796+ this);
797
798- _on_device_populate_entry_id = g_idle_add((GSourceFunc)&DeviceLauncherSection::PopulateEntries, this);
799+ on_device_populate_entry_id_ = g_idle_add((GSourceFunc)&DeviceLauncherSection::PopulateEntries, this);
800 }
801
802 DeviceLauncherSection::~DeviceLauncherSection()
803 {
804- if (_on_volume_added_handler_id != 0)
805- g_signal_handler_disconnect((gpointer) _monitor,
806- _on_volume_added_handler_id);
807-
808- if (_on_volume_removed_handler_id != 0)
809- g_signal_handler_disconnect((gpointer) _monitor,
810- _on_volume_removed_handler_id);
811-
812- if (_on_mount_added_handler_id != 0)
813- g_signal_handler_disconnect((gpointer) _monitor,
814- _on_mount_added_handler_id);
815-
816- if (_on_device_populate_entry_id)
817- g_source_remove(_on_device_populate_entry_id);
818-
819- g_object_unref(_monitor);
820- g_hash_table_unref(_ht);
821+ if (on_volume_added_handler_id_)
822+ g_signal_handler_disconnect((gpointer) monitor_,
823+ on_volume_added_handler_id_);
824+
825+ if (on_volume_removed_handler_id_)
826+ g_signal_handler_disconnect((gpointer) monitor_,
827+ on_volume_removed_handler_id_);
828+
829+ if (on_mount_added_handler_id_)
830+ g_signal_handler_disconnect((gpointer) monitor_,
831+ on_mount_added_handler_id_);
832+
833+ if (on_mount_pre_unmount_handler_id_)
834+ g_signal_handler_disconnect((gpointer) monitor_,
835+ on_mount_pre_unmount_handler_id_);
836+
837+ if (on_device_populate_entry_id_)
838+ g_source_remove(on_device_populate_entry_id_);
839 }
840
841-bool
842-DeviceLauncherSection::PopulateEntries(DeviceLauncherSection* self)
843+bool DeviceLauncherSection::PopulateEntries(DeviceLauncherSection* self)
844 {
845- GList* volumes, *v;
846+ GList* volumes = g_volume_monitor_get_volumes(self->monitor_);
847
848- volumes = g_volume_monitor_get_volumes(self->_monitor);
849- for (v = volumes; v; v = v->next)
850+ for (GList* v = volumes; v; v = v->next)
851 {
852- GVolume* volume = (GVolume*)v->data;
853- DeviceLauncherIcon* icon = new DeviceLauncherIcon(self->_launcher, volume);
854+ glib::Object<GVolume> volume((GVolume* )v->data);
855+ DeviceLauncherIcon* icon = new DeviceLauncherIcon(self->launcher_, volume);
856
857+ self->map_[volume] = icon;
858 self->IconAdded.emit(icon);
859-
860- g_hash_table_insert(self->_ht, (gpointer) volume, (gpointer) icon);
861-
862- g_object_unref(volume);
863 }
864
865 g_list_free(volumes);
866-
867- self->_on_device_populate_entry_id = 0;
868-
869+
870+ self->on_device_populate_entry_id_ = 0;
871+
872 return false;
873 }
874
875-void
876-DeviceLauncherSection::OnVolumeAdded(GVolumeMonitor* monitor,
877- GVolume* volume,
878- DeviceLauncherSection* self)
879+/* Uses a std::map to track all the volume icons shown and not shown.
880+ * Keep in mind: when "volume-removed" is recevied we should erase
881+ * the pair (GVolume - DeviceLauncherIcon) from the std::map to avoid leaks
882+ */
883+void DeviceLauncherSection::OnVolumeAdded(GVolumeMonitor* monitor,
884+ GVolume* volume,
885+ DeviceLauncherSection* self)
886 {
887- DeviceLauncherIcon* icon = new DeviceLauncherIcon(self->_launcher, volume);
888-
889- g_hash_table_insert(self->_ht, (gpointer) volume, (gpointer) icon);
890-
891+ DeviceLauncherIcon* icon = new DeviceLauncherIcon(self->launcher_, volume);
892+
893+ self->map_[volume] = icon;
894 self->IconAdded.emit(icon);
895 }
896
897-void
898-DeviceLauncherSection::OnVolumeRemoved(GVolumeMonitor* monitor,
899- GVolume* volume,
900- DeviceLauncherSection* self)
901-{
902- g_hash_table_remove(self->_ht, (gpointer) volume);
903-}
904-
905-#include "SimpleLauncherIcon.h"
906-void
907-DeviceLauncherSection::OnMountAdded(GVolumeMonitor* monitor,
908- GMount* mount,
909- DeviceLauncherSection* self)
910-{
911- GVolume* volume = g_mount_get_volume(mount);
912- DeviceLauncherIcon* icon = (DeviceLauncherIcon*) g_hash_table_lookup(self->_ht, (gpointer) volume);
913- if (icon)
914- icon->UpdateVisibility();
915-}
916+void DeviceLauncherSection::OnVolumeRemoved(GVolumeMonitor* monitor,
917+ GVolume* volume,
918+ DeviceLauncherSection* self)
919+{
920+ // It should not happen! Let me do the check anyway.
921+ if (self->map_.find(volume) != self->map_.end())
922+ {
923+ self->map_[volume]->OnRemoved();
924+ self->map_.erase(volume);
925+ }
926+}
927+
928+/* Keep in mind: we could have a GMount without a related GVolume
929+ * so check everything to avoid unwanted behaviors.
930+ */
931+void DeviceLauncherSection::OnMountAdded(GVolumeMonitor* monitor,
932+ GMount* mount,
933+ DeviceLauncherSection* self)
934+{
935+ std::map<GVolume* , DeviceLauncherIcon* >::iterator it;
936+ glib::Object<GVolume> volume(g_mount_get_volume(mount));
937+
938+ it = self->map_.find(volume);
939+
940+ if (it != self->map_.end())
941+ it->second->UpdateVisibility(1);
942+}
943+
944+/* We don't use "mount-removed" signal since it is received after "volume-removed"
945+ * signal. You should read also the comment above.
946+ */
947+void DeviceLauncherSection::OnMountPreUnmount(GVolumeMonitor* monitor,
948+ GMount* mount,
949+ DeviceLauncherSection* self)
950+{
951+ std::map<GVolume* , DeviceLauncherIcon* >::iterator it;
952+ glib::Object<GVolume> volume(g_mount_get_volume(mount));
953+
954+ it = self->map_.find(volume);
955+
956+ if (it != self->map_.end())
957+ it->second->UpdateVisibility(0);
958+}
959+
960+} // namespace unity
961
962=== modified file 'plugins/unityshell/src/DeviceLauncherSection.h'
963--- plugins/unityshell/src/DeviceLauncherSection.h 2011-07-21 14:59:25 +0000
964+++ plugins/unityshell/src/DeviceLauncherSection.h 2011-07-26 12:37:20 +0000
965@@ -19,14 +19,19 @@
966 #ifndef _DEVICE_LAUNCHER_SECTION_H_
967 #define _DEVICE_LAUNCHER_SECTION_H_
968
969+#include <map>
970+
971+#include <gio/gio.h>
972 #include <sigc++/sigc++.h>
973 #include <sigc++/signal.h>
974-
975-#include "Launcher.h"
976-#include "LauncherIcon.h"
977-#include "DevicesSettings.h"
978-
979-#include <gio/gio.h>
980+#include <UnityCore/GLibWrapper.h>
981+
982+#include "DeviceLauncherIcon.h"
983+
984+class Launcher;
985+class LauncherIcon;
986+
987+namespace unity {
988
989 class DeviceLauncherSection : public sigc::trackable
990 {
991@@ -38,25 +43,34 @@
992
993 private:
994 static bool PopulateEntries(DeviceLauncherSection* self);
995- static void OnVolumeAdded(GVolumeMonitor* monitor,
996- GVolume* volume,
997+
998+ static void OnVolumeAdded(GVolumeMonitor* monitor,
999+ GVolume* volume,
1000 DeviceLauncherSection* self);
1001- static void OnVolumeRemoved(GVolumeMonitor* monitor,
1002- GVolume* volume,
1003+
1004+ static void OnVolumeRemoved(GVolumeMonitor* monitor,
1005+ GVolume* volume,
1006 DeviceLauncherSection* self);
1007- static void OnMountAdded(GVolumeMonitor* monitor,
1008- GMount* mount,
1009+
1010+ static void OnMountAdded(GVolumeMonitor* monitor,
1011+ GMount* mount,
1012 DeviceLauncherSection* self);
1013-public:
1014- Launcher* _launcher;
1015- GVolumeMonitor* _monitor;
1016- GHashTable* _ht;
1017+
1018+ static void OnMountPreUnmount(GVolumeMonitor* monitor,
1019+ GMount* mount,
1020+ DeviceLauncherSection* self);
1021
1022 private:
1023- gulong _on_volume_added_handler_id;
1024- gulong _on_volume_removed_handler_id;
1025- gulong _on_mount_added_handler_id;
1026- gulong _on_device_populate_entry_id;
1027+ Launcher* launcher_;
1028+ glib::Object<GVolumeMonitor> monitor_;
1029+ std::map<GVolume*, DeviceLauncherIcon*> map_;
1030+ gulong on_volume_added_handler_id_;
1031+ gulong on_volume_removed_handler_id_;
1032+ gulong on_mount_added_handler_id_;
1033+ gulong on_mount_pre_unmount_handler_id_;
1034+ gulong on_device_populate_entry_id_;
1035 };
1036
1037+} // namespace unity
1038+
1039 #endif // _DEVICE_LAUNCHER_SECTION_H_
1040
1041=== modified file 'plugins/unityshell/src/DevicesSettings.cpp'
1042--- plugins/unityshell/src/DevicesSettings.cpp 2011-07-21 14:59:25 +0000
1043+++ plugins/unityshell/src/DevicesSettings.cpp 2011-07-26 12:37:20 +0000
1044@@ -1,69 +1,143 @@
1045 // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
1046 /*
1047-* Copyright (C) 2010 Canonical Ltd
1048-*
1049-* This program is free software: you can redistribute it and/or modify
1050-* it under the terms of the GNU General Public License version 3 as
1051-* published by the Free Software Foundation.
1052-*
1053-* This program is distributed in the hope that it will be useful,
1054-* but WITHOUT ANY WARRANTY; without even the implied warranty of
1055-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1056-* GNU General Public License for more details.
1057-*
1058-* You should have received a copy of the GNU General Public License
1059-* along with this program. If not, see <http://www.gnu.org/licenses/>.
1060-*
1061-* Authored by: Andrea Azzarone <aazzarone@hotmail.it>
1062-*/
1063+ * Copyright (C) 2010 Canonical Ltd
1064+ *
1065+ * This program is free software: you can redistribute it and/or modify
1066+ * it under the terms of the GNU General Public License version 3 as
1067+ * published by the Free Software Foundation.
1068+ *
1069+ * This program is distributed in the hope that it will be useful,
1070+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1071+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1072+ * GNU General Public License for more details.
1073+ *
1074+ * You should have received a copy of the GNU General Public License
1075+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1076+ *
1077+ * Authored by: Andrea Azzarone <aazzarone@hotmail.it>
1078+ */
1079
1080 #include "DevicesSettings.h"
1081
1082-static DevicesSettings* _devices_settings = NULL;
1083+#include <algorithm>
1084+
1085+namespace unity {
1086+
1087+namespace {
1088+
1089+const char* SETTINGS_NAME = "com.canonical.Unity.Devices";
1090+
1091+void on_settings_updated(GSettings* settings,
1092+ const gchar* key,
1093+ DevicesSettings* self);
1094+
1095+} // anonymous namespace
1096+
1097+DevicesSettings& DevicesSettings::GetDefault()
1098+{
1099+ static DevicesSettings instance;
1100+ return instance;
1101+}
1102
1103 DevicesSettings::DevicesSettings()
1104- : _settings(NULL),
1105- _raw_devices_option(1),
1106- _devices_option(ONLY_MOUNTED)
1107-{
1108- _settings = g_settings_new("com.canonical.Unity.Devices");
1109- g_signal_connect(_settings, "changed",
1110- (GCallback)(DevicesSettings::Changed), this);
1111- Refresh();
1112-}
1113-
1114-DevicesSettings::~DevicesSettings()
1115-{
1116- g_object_unref(_settings);
1117-}
1118-
1119-void
1120-DevicesSettings::Refresh()
1121-{
1122- _raw_devices_option = g_settings_get_enum(_settings, "devices-option");
1123-
1124- _devices_option = (DevicesOption)_raw_devices_option;
1125-
1126- changed.emit(this);
1127-}
1128-
1129-void
1130-DevicesSettings::Changed(GSettings* settings, char* key, DevicesSettings* self)
1131-{
1132- self->Refresh();
1133-}
1134-
1135-DevicesSettings*
1136-DevicesSettings::GetDefault()
1137-{
1138- if (G_UNLIKELY(!_devices_settings))
1139- _devices_settings = new DevicesSettings();
1140-
1141- return _devices_settings;
1142-}
1143-
1144-DevicesSettings::DevicesOption
1145-DevicesSettings::GetDevicesOption()
1146-{
1147- return _devices_option;
1148-}
1149+ : settings_(g_settings_new(SETTINGS_NAME))
1150+ , ignore_signals_(false)
1151+ , devices_option_(ONLY_MOUNTED)
1152+{
1153+
1154+ g_signal_connect(settings_, "changed", G_CALLBACK(on_settings_updated), this);
1155+
1156+ Refresh();
1157+}
1158+
1159+void DevicesSettings::Refresh()
1160+{
1161+ gchar** favs = g_settings_get_strv(settings_, "favorites");
1162+
1163+ favorites_.clear();
1164+
1165+ for (int i = 0; favs[i] != NULL; i++)
1166+ favorites_.push_back(favs[i]);
1167+
1168+ g_strfreev(favs);
1169+}
1170+
1171+void DevicesSettings::AddFavorite(std::string const& uuid)
1172+{
1173+ if (uuid.empty())
1174+ return;
1175+
1176+ favorites_.push_back(uuid);
1177+
1178+ SaveFavorites(favorites_);
1179+ Refresh();
1180+}
1181+
1182+void DevicesSettings::RemoveFavorite(std::string const& uuid)
1183+{
1184+ if (uuid.empty())
1185+ return;
1186+
1187+ DeviceList::iterator pos = std::find(favorites_.begin(), favorites_.end(), uuid);
1188+ if (pos == favorites_.end())
1189+ return;
1190+
1191+ favorites_.erase(pos);
1192+ SaveFavorites(favorites_);
1193+ Refresh();
1194+}
1195+
1196+void DevicesSettings::SaveFavorites(DeviceList const& favorites)
1197+{
1198+ const int size = favorites.size();
1199+ const char* favs[size + 1];
1200+ favs[size] = NULL;
1201+
1202+ int index = 0;
1203+ for (DeviceList::const_iterator i = favorites.begin(), end = favorites.end();
1204+ i != end; ++i, ++index)
1205+ {
1206+ favs[index] = i->c_str();
1207+ }
1208+
1209+ ignore_signals_ = true;
1210+ if (!g_settings_set_strv(settings_, "favorites", favs))
1211+ g_warning("Saving favorites failed.");
1212+ ignore_signals_ = false;
1213+}
1214+
1215+
1216+void DevicesSettings::Changed(std::string const& key)
1217+{
1218+ if (ignore_signals_)
1219+ return;
1220+
1221+ Refresh();
1222+
1223+ changed.emit();
1224+}
1225+
1226+void DevicesSettings::SetDevicesOption(DevicesOption devices_option)
1227+{
1228+ if (devices_option == devices_option_)
1229+ return;
1230+
1231+ devices_option_ = devices_option;
1232+
1233+ changed.emit();
1234+}
1235+
1236+namespace {
1237+
1238+void on_settings_updated(GSettings* settings,
1239+ const gchar* key,
1240+ DevicesSettings* self)
1241+{
1242+ if (settings and key) {
1243+ self->Changed(key);
1244+ }
1245+}
1246+
1247+} // anonymous namespace
1248+
1249+} // namespace unity
1250
1251=== modified file 'plugins/unityshell/src/DevicesSettings.h'
1252--- plugins/unityshell/src/DevicesSettings.h 2011-07-21 14:59:25 +0000
1253+++ plugins/unityshell/src/DevicesSettings.h 2011-07-26 12:37:20 +0000
1254@@ -1,30 +1,38 @@
1255 // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
1256 /*
1257-* Copyright (C) 2010 Canonical Ltd
1258-*
1259-* This program is free software: you can redistribute it and/or modify
1260-* it under the terms of the GNU General Public License version 3 as
1261-* published by the Free Software Foundation.
1262-*
1263-* This program is distributed in the hope that it will be useful,
1264-* but WITHOUT ANY WARRANTY; without even the implied warranty of
1265-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1266-* GNU General Public License for more details.
1267-*
1268-* You should have received a copy of the GNU General Public License
1269-* along with this program. If not, see <http://www.gnu.org/licenses/>.
1270-*
1271-* Authored by: Andrea Azzarone <aazzarone@hotmail.it>
1272-*/
1273+ * Copyright (C) 2010 Canonical Ltd
1274+ *
1275+ * This program is free software: you can redistribute it and/or modify
1276+ * it under the terms of the GNU General Public License version 3 as
1277+ * published by the Free Software Foundation.
1278+ *
1279+ * This program is distributed in the hope that it will be useful,
1280+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1281+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1282+ * GNU General Public License for more details.
1283+ *
1284+ * You should have received a copy of the GNU General Public License
1285+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1286+ *
1287+ * Authored by: Andrea Azzarone <aazzarone@hotmail.it>
1288+ */
1289
1290 #ifndef DEVICES_SETTINGS_H
1291 #define DEVICES_SETTINGS_H
1292
1293+#include <list>
1294+#include <string>
1295+
1296 #include <gio/gio.h>
1297-#include <Nux/Nux.h>
1298-
1299-
1300-class DevicesSettings : public nux::Object
1301+#include <boost/utility.hpp>
1302+#include <sigc++/sigc++.h>
1303+#include <UnityCore/GLibWrapper.h>
1304+
1305+namespace unity {
1306+
1307+typedef std::list<std::string> DeviceList;
1308+
1309+class DevicesSettings : boost::noncopyable
1310 {
1311 public:
1312 typedef enum
1313@@ -36,22 +44,31 @@
1314 } DevicesOption;
1315
1316 DevicesSettings();
1317- ~DevicesSettings();
1318-
1319- static DevicesSettings* GetDefault();
1320-
1321- DevicesOption GetDevicesOption();
1322-
1323- sigc::signal<void, DevicesSettings*> changed;
1324-
1325+
1326+ static DevicesSettings& GetDefault();
1327+
1328+ void SetDevicesOption(DevicesOption devices_option);
1329+ DevicesOption GetDevicesOption() { return devices_option_; };
1330+
1331+ DeviceList const& GetFavorites() { return favorites_; };
1332+ void AddFavorite(std::string const& uuid);
1333+ void RemoveFavorite(std::string const& uuid);
1334+
1335+ void Changed(std::string const& key);
1336+
1337+ // Signals
1338+ sigc::signal<void> changed;
1339+
1340 private:
1341 void Refresh();
1342- static void Changed(GSettings* settings, gchar* key, DevicesSettings* self);
1343+ void SaveFavorites(DeviceList const& favorites);
1344
1345-private:
1346- GSettings* _settings;
1347- int _raw_devices_option;
1348- DevicesOption _devices_option;
1349+ glib::Object<GSettings> settings_;
1350+ DeviceList favorites_;
1351+ bool ignore_signals_;
1352+ DevicesOption devices_option_;
1353 };
1354
1355+} // namespace unity
1356+
1357 #endif // DEVICES_SETTINGS_H
1358
1359=== modified file 'plugins/unityshell/src/LauncherController.h'
1360--- plugins/unityshell/src/LauncherController.h 2011-07-21 14:59:25 +0000
1361+++ plugins/unityshell/src/LauncherController.h 2011-07-26 12:37:20 +0000
1362@@ -56,7 +56,7 @@
1363 LauncherModel* _model;
1364 int _sort_priority;
1365 PlaceLauncherSection* _place_section;
1366- DeviceLauncherSection* _device_section;
1367+ unity::DeviceLauncherSection* _device_section;
1368 LauncherEntryRemoteModel* _remote_model;
1369 SimpleLauncherIcon* _expoIcon;
1370 int _num_workspaces;
1371
1372=== modified file 'plugins/unityshell/src/unityshell.cpp'
1373--- plugins/unityshell/src/unityshell.cpp 2011-07-21 14:59:25 +0000
1374+++ plugins/unityshell/src/unityshell.cpp 2011-07-26 12:37:20 +0000
1375@@ -30,6 +30,7 @@
1376 #include "LauncherController.h"
1377 #include "PlacesSettings.h"
1378 #include "GeisAdapter.h"
1379+#include "DevicesSettings.h"
1380 #include "PluginAdapter.h"
1381 #include "StartupNotifyService.h"
1382 #include "Timer.h"
1383@@ -146,6 +147,7 @@
1384 optionSetIconSizeNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
1385 optionSetAutohideAnimationNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
1386 optionSetDashBlurExperimentalNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
1387+ optionSetDevicesOptionNotify(boost::bind (&UnityScreen::optionChanged, this, _1, _2));
1388 optionSetShowLauncherInitiate(boost::bind(&UnityScreen::showLauncherKeyInitiate, this, _1, _2, _3));
1389 optionSetShowLauncherTerminate(boost::bind(&UnityScreen::showLauncherKeyTerminate, this, _1, _2, _3));
1390 optionSetKeyboardFocusInitiate(boost::bind(&UnityScreen::setKeyboardFocusKeyInitiate, this, _1, _2, _3));
1391@@ -967,18 +969,19 @@
1392 panelController->SetBFBSize(optionGetIconSize() + 18);
1393 launcher->SetIconSize(optionGetIconSize() + 6, optionGetIconSize());
1394 PlacesController::SetLauncherSize(optionGetIconSize() + 18);
1395-
1396 break;
1397 case UnityshellOptions::AutohideAnimation:
1398 launcher->SetAutoHideAnimation((Launcher::AutoHideAnimation) optionGetAutohideAnimation());
1399 break;
1400-
1401 case UnityshellOptions::DashBlurExperimental:
1402 PlacesSettings::GetDefault()->SetDashBlurType((PlacesSettings::DashBlurType)optionGetDashBlurExperimental());
1403 break;
1404 case UnityshellOptions::AutomaximizeValue:
1405 PluginAdapter::Default()->SetCoverageAreaBeforeAutomaximize(optionGetAutomaximizeValue() / 100.0f);
1406 break;
1407+ case UnityshellOptions::DevicesOption:
1408+ unity::DevicesSettings::GetDefault().SetDevicesOption((unity::DevicesSettings::DevicesOption) optionGetDevicesOption());
1409+ break;
1410 default:
1411 break;
1412 }
1413
1414=== modified file 'plugins/unityshell/unityshell.xml.in'
1415--- plugins/unityshell/unityshell.xml.in 2011-07-16 02:30:03 +0000
1416+++ plugins/unityshell/unityshell.xml.in 2011-07-26 12:37:20 +0000
1417@@ -213,6 +213,7 @@
1418 <_name>Static Blur</_name>
1419 </desc>
1420 </option>
1421+
1422 <option name="automaximize_value" type="int">
1423 <_short>Automaximize value</_short>
1424 <_long>The minimum value to trigger automaximize.</_long>
1425@@ -220,6 +221,27 @@
1426 <max>100</max>
1427 <default>75</default>
1428 </option>
1429+
1430+ <option name="devices_option" type="int">
1431+ <_short>Show Devices</_short>
1432+ <_long>Show devices in the launcher</_long>
1433+ <min>0</min>
1434+ <max>2</max>
1435+ <default>1</default>
1436+ <desc>
1437+ <value>0</value>
1438+ <_name>Never</_name>
1439+ </desc>
1440+ <desc>
1441+ <value>1</value>
1442+ <_name>Only Mounted</_name>
1443+ </desc>
1444+ <desc>
1445+ <value>2</value>
1446+ <_name>Always</_name>
1447+ </desc>
1448+ </option>
1449+
1450 </group>
1451 </options>
1452 </plugin>