Merge lp:~andyrock/unity/dnd-enhancements into lp:unity

Proposed by Andrea Azzarone on 2011-08-10
Reviewer Review Type Date Requested Status
Jason Smith (community) 2011-08-10 Approve on 2011-08-19
Review via email: mp+71003@code.launchpad.net

Description of the Change

THE DNDCOLLECTION WINDOW
The first objective of this branch is creating a DNDCollectionWindow to get nux/x drag and drop (dnd) data as soon as dnd starts and not when mouse pointer enters launcher window.
The DNDcolletionWindow hides itself as soon as processdndmove is called or when dnd ends (so there should be no "invisble window" problem). After that it emits a collected signal that is handled by the launcher.

THE DNDDATA CLASS
So I have created this facility class to manage the 1-N relationship between uris and uris types. This class uses std::set to avoid data duplication.

C++0x FOR
I have rewrited some for loops using new c++0x for.

To post a comment you must log in.
Jason Smith (jassmith) wrote :

Im sorry it took me so long to get to this, I was gone last week.

I will be reviewing this with excitement tomorrow! Good work :)

Jason Smith (jassmith) wrote :

So after running the branch, it does a great job making the launcher appear and do the hinting as soon as a drag starts, however the actual act of dropping something on the launcher is broken in this branch.

review: Needs Fixing
Andrea Azzarone (andyrock) wrote :

So I should fix that?

Jason Smith (jassmith) wrote :

Yes

lp:~andyrock/unity/dnd-enhancements updated on 2011-08-19
1371. By Andrea Azzarone on 2011-08-19

Merge trunk.

1372. By Andrea Azzarone on 2011-08-19

Fixes window stack problem.

Andrea Azzarone (andyrock) wrote :

The problem should be gone away...

Jason Smith (jassmith) wrote :

Looking great!

review: Approve

Preview Diff

1=== modified file 'plugins/unityshell/src/AbstractLauncherIcon.h'
2--- plugins/unityshell/src/AbstractLauncherIcon.h 2011-08-05 06:20:39 +0000
3+++ plugins/unityshell/src/AbstractLauncherIcon.h 2011-08-19 08:55:26 +0000
4@@ -31,6 +31,8 @@
5
6 #include <libdbusmenu-glib/menuitem.h>
7
8+#include "DndData.h"
9+
10 class ActionArg
11 {
12 public:
13@@ -161,9 +163,9 @@
14
15 virtual std::list<DbusmenuMenuitem*> Menus() = 0;
16
17- virtual nux::DndAction QueryAcceptDrop(std::list<char*> paths) = 0;
18+ virtual nux::DndAction QueryAcceptDrop(unity::DndData& dnd_data) = 0;
19
20- virtual void AcceptDrop(std::list<char*> paths) = 0;
21+ virtual void AcceptDrop(unity::DndData& dnd_data) = 0;
22
23 virtual void SendDndEnter() = 0;
24
25
26=== modified file 'plugins/unityshell/src/BamfLauncherIcon.cpp'
27--- plugins/unityshell/src/BamfLauncherIcon.cpp 2011-08-18 00:38:22 +0000
28+++ plugins/unityshell/src/BamfLauncherIcon.cpp 2011-08-19 08:55:26 +0000
29@@ -21,12 +21,11 @@
30 #include "Nux/BaseWindow.h"
31
32 #include "BamfLauncherIcon.h"
33+#include "FavoriteStore.h"
34 #include "Launcher.h"
35 #include "PluginAdapter.h"
36-#include "FavoriteStore.h"
37-
38+#include "UBusMessages.h"
39 #include "ubus-server.h"
40-#include "UBusMessages.h"
41
42 #include <glib/gi18n-lib.h>
43 #include <gio/gdesktopappinfo.h>
44@@ -34,6 +33,8 @@
45 #include <core/core.h>
46 #include <core/atoms.h>
47
48+#include <UnityCore/GLibWrapper.h>
49+
50 using unity::FavoriteStore;
51
52 struct _ShortcutData
53@@ -133,7 +134,9 @@
54 }
55
56 BamfLauncherIcon::BamfLauncherIcon(Launcher* IconManager, BamfApplication* app, CompScreen* screen)
57- : SimpleLauncherIcon(IconManager)
58+ : SimpleLauncherIcon(IconManager)
59+ , _supported_types_filled(false)
60+ , _fill_supported_types_id(0)
61 {
62 _cached_desktop_file = NULL;
63 _cached_name = NULL;
64@@ -188,8 +191,11 @@
65 PluginAdapter::Default()->window_minimized.connect(sigc::mem_fun(this, &BamfLauncherIcon::OnWindowMinimized));
66 IconManager->hidden_changed.connect(sigc::mem_fun(this, &BamfLauncherIcon::OnLauncherHiddenChanged));
67
68- /* hack */
69+ // hack
70 SetProgress(0.0f);
71+
72+ // Calls when there are no higher priority events pending to the default main loop.
73+ _fill_supported_types_id = g_idle_add((GSourceFunc)FillSupportedTypes, this);
74
75 }
76
77@@ -213,6 +219,9 @@
78 if (_on_desktop_file_changed_handler_id != 0)
79 g_signal_handler_disconnect((gpointer) _desktop_file_monitor,
80 _on_desktop_file_changed_handler_id);
81+
82+ if (_fill_supported_types_id != 0)
83+ g_source_remove(_fill_supported_types_id);
84
85 g_signal_handlers_disconnect_by_func(m_App, (void*) &BamfLauncherIcon::OnChildRemoved, this);
86 g_signal_handlers_disconnect_by_func(m_App, (void*) &BamfLauncherIcon::OnChildAdded, this);
87@@ -352,11 +361,10 @@
88 return owns;
89 }
90
91-void BamfLauncherIcon::OpenInstanceWithUris(std::list<char*> uris)
92+void BamfLauncherIcon::OpenInstanceWithUris(std::set<std::string> uris)
93 {
94 GDesktopAppInfo* appInfo;
95 GError* error = NULL;
96- std::list<char*>::iterator it;
97
98 appInfo = g_desktop_app_info_new_from_filename(bamf_application_get_desktop_file(BAMF_APPLICATION(m_App)));
99
100@@ -364,18 +372,19 @@
101 {
102 GList* list = NULL;
103
104- for (it = uris.begin(); it != uris.end(); it++)
105- list = g_list_prepend(list, *it);
106+ for (auto it : uris)
107+ list = g_list_prepend(list, g_strdup(it.c_str()));
108
109 g_app_info_launch_uris(G_APP_INFO(appInfo), list, NULL, &error);
110- g_list_free(list);
111+ g_list_free_full(list, g_free);
112 }
113 else if (g_app_info_supports_files(G_APP_INFO(appInfo)))
114 {
115 GList* list = NULL, *l;
116- for (it = uris.begin(); it != uris.end(); it++)
117+
118+ for (auto it : uris)
119 {
120- GFile* file = g_file_new_for_uri(*it);
121+ GFile* file = g_file_new_for_uri(it.c_str());
122 list = g_list_prepend(list, file);
123 }
124 g_app_info_launch(G_APP_INFO(appInfo), list, NULL, &error);
125@@ -403,7 +412,7 @@
126
127 void BamfLauncherIcon::OpenInstanceLauncherIcon(ActionArg arg)
128 {
129- std::list<char*> empty;
130+ std::set<std::string> empty;
131 OpenInstanceWithUris(empty);
132 ubus_server_send_message(ubus_server_get_default(), UBUS_LAUNCHER_ACTION_DONE, NULL);
133 }
134@@ -1038,62 +1047,21 @@
135 return _remote_uri;
136 }
137
138-std::list<char*> BamfLauncherIcon::ValidateUrisForLaunch(std::list<char*> uris)
139+std::set<std::string> BamfLauncherIcon::ValidateUrisForLaunch(unity::DndData& uris)
140 {
141- GKeyFile* key_file;
142- const char* desktop_file;
143- GError* error = NULL;
144- std::list<char*> results;
145-
146- desktop_file = DesktopFile();
147-
148- if (!desktop_file || strlen(desktop_file) <= 1)
149- return results;
150-
151- key_file = g_key_file_new();
152- g_key_file_load_from_file(key_file, desktop_file, (GKeyFileFlags) 0, &error);
153-
154- if (error)
155- {
156- g_error_free(error);
157- g_key_file_free(key_file);
158- return results;
159- }
160-
161- char** mimes = g_key_file_get_string_list(key_file, "Desktop Entry", "MimeType", NULL, NULL);
162- if (!mimes)
163- {
164- g_key_file_free(key_file);
165- return results;
166- }
167-
168- std::list<char*>::iterator it;
169- for (it = uris.begin(); it != uris.end(); it++)
170- {
171- GFile* file = g_file_new_for_uri(*it);
172- GFileInfo* info = g_file_query_info(file, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, G_FILE_QUERY_INFO_NONE, NULL, NULL);
173- const char* content_type = g_file_info_get_content_type(info);
174-
175- int i = 0;
176- for (; mimes[i]; i++)
177- {
178- char* super_type = g_content_type_from_mime_type(mimes[i]);
179- if (g_content_type_is_a(content_type, super_type))
180+ std::set<std::string> result;
181+
182+ for (auto i : uris.Types())
183+ for (auto j : GetSupportedTypes())
184+ if (g_content_type_is_a(i.c_str(), j.c_str()))
185 {
186- results.push_back(*it);
187+ for (auto k : uris.UrisByType(i))
188+ result.insert(k);
189+
190 break;
191 }
192- g_free(super_type);
193- }
194-
195-
196- g_object_unref(file);
197- g_object_unref(info);
198- }
199-
200- g_strfreev(mimes);
201- g_key_file_free(key_file);
202- return results;
203+
204+ return result;
205 }
206
207 gboolean BamfLauncherIcon::OnDndHoveredTimeout(gpointer data)
208@@ -1121,14 +1089,14 @@
209 _dnd_hover_timer = 0;
210 }
211
212-nux::DndAction BamfLauncherIcon::OnQueryAcceptDrop(std::list<char*> uris)
213+nux::DndAction BamfLauncherIcon::OnQueryAcceptDrop(unity::DndData& dnd_data)
214 {
215- return ValidateUrisForLaunch(uris).empty() ? nux::DNDACTION_NONE : nux::DNDACTION_COPY;
216+ return ValidateUrisForLaunch(dnd_data).empty() ? nux::DNDACTION_NONE : nux::DNDACTION_COPY;
217 }
218
219-void BamfLauncherIcon::OnAcceptDrop(std::list<char*> uris)
220+void BamfLauncherIcon::OnAcceptDrop(unity::DndData& dnd_data)
221 {
222- OpenInstanceWithUris(ValidateUrisForLaunch(uris));
223+ OpenInstanceWithUris(ValidateUrisForLaunch(dnd_data));
224 }
225
226 void BamfLauncherIcon::OnDesktopFileChanged(GFileMonitor* monitor,
227@@ -1181,3 +1149,65 @@
228 g_list_free(children);
229 return result;
230 }
231+
232+const std::set<std::string>&
233+BamfLauncherIcon::GetSupportedTypes()
234+{
235+ if (!_supported_types_filled)
236+ FillSupportedTypes(this);
237+
238+ return _supported_types;
239+}
240+
241+gboolean
242+BamfLauncherIcon::FillSupportedTypes(gpointer data)
243+{
244+ BamfLauncherIcon* self = (BamfLauncherIcon*) data;
245+
246+ if (self->_fill_supported_types_id)
247+ {
248+ g_source_remove(self->_fill_supported_types_id);
249+ self->_fill_supported_types_id = 0;
250+ }
251+
252+ if (!self->_supported_types_filled)
253+ {
254+ self->_supported_types_filled = true;
255+
256+ self->_supported_types.clear();
257+
258+ const char* desktop_file = self->DesktopFile();
259+
260+ if (!desktop_file || strlen(desktop_file) <= 1)
261+ return false;
262+
263+ GKeyFile* key_file = g_key_file_new();
264+ unity::glib::Error error;
265+
266+ g_key_file_load_from_file(key_file, desktop_file, (GKeyFileFlags) 0, &error);
267+
268+ if (error)
269+ {
270+ g_key_file_free(key_file);
271+ return false;
272+ }
273+
274+ char** mimes = g_key_file_get_string_list(key_file, "Desktop Entry", "MimeType", NULL, NULL);
275+ if (!mimes)
276+ {
277+ g_key_file_free(key_file);
278+ return false;
279+ }
280+
281+ for (int i=0; mimes[i]; i++)
282+ {
283+ unity::glib::String super_type(g_content_type_from_mime_type(mimes[i]));
284+ self->_supported_types.insert(super_type.Str());
285+ }
286+
287+ g_key_file_free(key_file);
288+ g_strfreev(mimes);
289+ }
290+
291+ return false;
292+}
293
294=== modified file 'plugins/unityshell/src/BamfLauncherIcon.h'
295--- plugins/unityshell/src/BamfLauncherIcon.h 2011-08-04 20:19:46 +0000
296+++ plugins/unityshell/src/BamfLauncherIcon.h 2011-08-19 08:55:26 +0000
297@@ -63,14 +63,14 @@
298
299 const gchar* GetRemoteUri();
300
301- nux::DndAction OnQueryAcceptDrop(std::list<char*> uris);
302- void OnAcceptDrop(std::list<char*> uris);
303+ nux::DndAction OnQueryAcceptDrop(unity::DndData& dnd_data);
304+ void OnAcceptDrop(unity::DndData& dnd_data);
305 void OnDndEnter();
306 void OnDndLeave();
307
308 void OpenInstanceLauncherIcon(ActionArg arg);
309
310- std::list<char*> ValidateUrisForLaunch(std::list<char*> uris);
311+ std::set<std::string> ValidateUrisForLaunch(unity::DndData& dnd_data);
312
313 const char* BamfName();
314
315@@ -89,15 +89,18 @@
316 gchar* _cached_desktop_file;
317 gchar* _cached_name;
318
319-
320 GFileMonitor* _desktop_file_monitor;
321 gulong _on_desktop_file_changed_handler_id;
322+
323+ std::set<std::string> _supported_types;
324+ bool _supported_types_filled;
325+ guint _fill_supported_types_id;
326
327 void EnsureWindowState();
328
329 void UpdateMenus();
330
331- void OpenInstanceWithUris(std::list<char*> uris);
332+ void OpenInstanceWithUris(std::set<std::string> uris);
333 void Focus();
334 bool Spread(int state, bool force);
335
336@@ -105,6 +108,8 @@
337
338 void OnWindowMinimized(guint32 xid);
339 bool OwnsWindow(Window w);
340+
341+ const std::set<std::string>& GetSupportedTypes();
342
343 static void OnClosed(BamfView* view, gpointer data);
344 static void OnUserVisibleChanged(BamfView* view, gboolean visible, gpointer data);
345@@ -125,6 +130,7 @@
346 gpointer data);
347
348 static gboolean OnDndHoveredTimeout(gpointer data);
349+ static gboolean FillSupportedTypes(gpointer data);
350 };
351
352 #endif // BAMFLAUNCHERICON_H
353
354=== added file 'plugins/unityshell/src/DNDCollectionWindow.cpp'
355--- plugins/unityshell/src/DNDCollectionWindow.cpp 1970-01-01 00:00:00 +0000
356+++ plugins/unityshell/src/DNDCollectionWindow.cpp 2011-08-19 08:55:26 +0000
357@@ -0,0 +1,63 @@
358+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
359+/*
360+* Copyright (C) 2011 Canonical Ltd
361+*
362+* This program is free software: you can redistribute it and/or modify
363+* it under the terms of the GNU General Public License version 3 as
364+* published by the Free Software Foundation.
365+*
366+* This program is distributed in the hope that it will be useful,
367+* but WITHOUT ANY WARRANTY; without even the implied warranty of
368+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
369+* GNU General Public License for more details.
370+*
371+* You should have received a copy of the GNU General Public License
372+* along with this program. If not, see <http://www.gnu.org/licenses/>.
373+*
374+* Authored by: Andrea Azzarone <azzaronea@gmail.com>
375+*/
376+
377+#include "DNDCollectionWindow.h"
378+
379+namespace unity {
380+
381+NUX_IMPLEMENT_OBJECT_TYPE(DNDCollectionWindow);
382+
383+DNDCollectionWindow::DNDCollectionWindow(CompScreen* screen)
384+ : nux::BaseWindow("")
385+{
386+ SetBackgroundColor(nux::Color(0x00000000));
387+ SetBaseSize(screen->width(), screen->height());
388+ SetBaseXY(0, 0);
389+
390+ ShowWindow(true);
391+ PushToBack();
392+ // Hack
393+ EnableInputWindow(true, "DNDCollectionWindow");
394+ EnableInputWindow(false, "DNDCollectionWindow");
395+ SetDndEnabled(false, true);
396+}
397+
398+DNDCollectionWindow::~DNDCollectionWindow()
399+{
400+ for (auto it : mimes_)
401+ g_free(it);
402+}
403+
404+void DNDCollectionWindow::ProcessDndMove(int x, int y, std::list<char*> mimes)
405+{
406+ // Hide the window as soon as possible
407+ EnableInputWindow(false, "DNDCollectionWindow");
408+
409+ for (auto it : mimes_)
410+ g_free(it);
411+ mimes_.clear();
412+
413+ // Duplicate the list
414+ for (auto it : mimes)
415+ mimes_.push_back(g_strdup(it));
416+
417+ collected.emit(mimes_);
418+}
419+
420+} // namespace unity
421
422=== added file 'plugins/unityshell/src/DNDCollectionWindow.h'
423--- plugins/unityshell/src/DNDCollectionWindow.h 1970-01-01 00:00:00 +0000
424+++ plugins/unityshell/src/DNDCollectionWindow.h 2011-08-19 08:55:26 +0000
425@@ -0,0 +1,55 @@
426+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
427+/*
428+* Copyright (C) 2011 Canonical Ltd
429+*
430+* This program is free software: you can redistribute it and/or modify
431+* it under the terms of the GNU General Public License version 3 as
432+* published by the Free Software Foundation.
433+*
434+* This program is distributed in the hope that it will be useful,
435+* but WITHOUT ANY WARRANTY; without even the implied warranty of
436+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
437+* GNU General Public License for more details.
438+*
439+* You should have received a copy of the GNU General Public License
440+* along with this program. If not, see <http://www.gnu.org/licenses/>.
441+*
442+* Authored by: Andrea Azzarone <azzaronea@gmail.com>
443+*/
444+
445+#ifndef DNDCOLLECTIONWINDOW_H
446+#define DNDCOLLECTIONWINDOW_H
447+
448+#include <list>
449+
450+#include <core/screen.h>
451+#include <Nux/Nux.h>
452+#include <Nux/BaseWindow.h>
453+#include <sigc++/sigc++.h>
454+
455+namespace unity {
456+
457+class DNDCollectionWindow : public nux::BaseWindow
458+{
459+NUX_DECLARE_OBJECT_TYPE(DNDCollectionWindow, nux::BaseWindow);
460+
461+// Methods
462+public:
463+ DNDCollectionWindow(CompScreen* screen);
464+ ~DNDCollectionWindow();
465+
466+private:
467+ void ProcessDndMove(int x, int y, std::list<char*> mimes);
468+
469+// Members
470+public:
471+ sigc::signal<void, const std::list<char*>&> collected;
472+
473+private:
474+ std::list<char*> mimes_;
475+
476+};
477+
478+} // namespace unity
479+
480+#endif // DNDCOLLECTIONWINDOW_H
481
482=== added file 'plugins/unityshell/src/DndData.cpp'
483--- plugins/unityshell/src/DndData.cpp 1970-01-01 00:00:00 +0000
484+++ plugins/unityshell/src/DndData.cpp 2011-08-19 08:55:26 +0000
485@@ -0,0 +1,63 @@
486+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
487+/*
488+* Copyright (C) 2011 Canonical Ltd
489+*
490+* This program is free software: you can redistribute it and/or modify
491+* it under the terms of the GNU General Public License version 3 as
492+* published by the Free Software Foundation.
493+*
494+* This program is distributed in the hope that it will be useful,
495+* but WITHOUT ANY WARRANTY; without even the implied warranty of
496+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
497+* GNU General Public License for more details.
498+*
499+* You should have received a copy of the GNU General Public License
500+* along with this program. If not, see <http://www.gnu.org/licenses/>.
501+*
502+* Authored by: Andrea Azzarone <azzaronea@gmail.com>
503+*/
504+
505+#include "DndData.h"
506+
507+#include <cstring>
508+#include <vector>
509+
510+#include <gio/gio.h>
511+
512+#include <UnityCore/GLibWrapper.h>
513+
514+namespace unity {
515+
516+void DndData::Fill(char* uris)
517+{
518+ Reset();
519+
520+ char* pch = strtok (uris, "\r\n");
521+ while (pch != NULL)
522+ {
523+ glib::Object<GFile> file(g_file_new_for_uri(pch));
524+ glib::Object<GFileInfo> info(g_file_query_info(file, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, G_FILE_QUERY_INFO_NONE, NULL, NULL));
525+ const char* content_type = g_file_info_get_content_type(info);
526+
527+ uris_.insert(pch);
528+
529+ if (content_type != NULL)
530+ {
531+ types_.insert(content_type);
532+ uris_to_types_[pch] = content_type;
533+ types_to_uris_[content_type].insert(pch);
534+ }
535+
536+ pch = strtok (NULL, "\r\n");
537+ }
538+}
539+
540+void DndData::Reset()
541+{
542+ uris_.clear();
543+ types_.clear();
544+ uris_to_types_.clear();
545+ types_to_uris_.clear();
546+}
547+
548+} // namespace unity
549
550=== added file 'plugins/unityshell/src/DndData.h'
551--- plugins/unityshell/src/DndData.h 1970-01-01 00:00:00 +0000
552+++ plugins/unityshell/src/DndData.h 2011-08-19 08:55:26 +0000
553@@ -0,0 +1,71 @@
554+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
555+/*
556+* Copyright (C) 2011 Canonical Ltd
557+*
558+* This program is free software: you can redistribute it and/or modify
559+* it under the terms of the GNU General Public License version 3 as
560+* published by the Free Software Foundation.
561+*
562+* This program is distributed in the hope that it will be useful,
563+* but WITHOUT ANY WARRANTY; without even the implied warranty of
564+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
565+* GNU General Public License for more details.
566+*
567+* You should have received a copy of the GNU General Public License
568+* along with this program. If not, see <http://www.gnu.org/licenses/>.
569+*
570+* Authored by: Andrea Azzarone <azzaronea@gmail.com>
571+*/
572+
573+#ifndef DNDDATA_H
574+#define DNDDATA_H
575+
576+#include <map>
577+#include <set>
578+#include <string>
579+
580+namespace unity {
581+
582+class DndData
583+{
584+public:
585+ /**
586+ * Fills the object given a list of uris.
587+ **/
588+ void Fill(char* uris);
589+
590+ /**
591+ * Resets the object. Call this function when no longer need data
592+ **/
593+ void Reset();
594+
595+ /**
596+ * Returns a std::set<std::string> with all the uris.
597+ **/
598+ std::set<std::string>& Uris() { return uris_; }
599+
600+ /**
601+ * Returns a std::set<std::string> with all the types.
602+ **/
603+ std::set<std::string>& Types() { return types_; }
604+
605+ /**
606+ * Returns a std::set<std::string> with all uris of a given type.
607+ **/
608+ std::set<std::string>& UrisByType(const std::string& type) { return types_to_uris_[type]; }
609+
610+ /**
611+ * Returns a std::set<std::string> with all types of a given uri.
612+ **/
613+ std::string& TypeByUri(const std::string& uris) { return uris_to_types_[uris]; }
614+
615+private:
616+ std::set<std::string> uris_;
617+ std::set<std::string> types_;
618+ std::map<std::string, std::string> uris_to_types_;
619+ std::map<std::string, std::set<std::string>> types_to_uris_;
620+};
621+
622+} // namespace unity
623+
624+#endif // DNDDATA_H
625
626=== modified file 'plugins/unityshell/src/Launcher.cpp'
627--- plugins/unityshell/src/Launcher.cpp 2011-08-13 06:17:26 +0000
628+++ plugins/unityshell/src/Launcher.cpp 2011-08-19 08:55:26 +0000
629@@ -48,12 +48,11 @@
630 #include "ubus-server.h"
631 #include "UBusMessages.h"
632
633+#include <UnityCore/GLibWrapper.h>
634 #include <UnityCore/Variant.h>
635
636 using namespace unity::ui;
637
638-using namespace unity::ui;
639-
640 namespace
641 {
642
643@@ -136,13 +135,15 @@
644 Launcher::Launcher(nux::BaseWindow* parent,
645 CompScreen* screen,
646 NUX_FILE_LINE_DECL)
647- : View(NUX_FILE_LINE_PARAM)
648- , m_ContentOffsetY(0)
649- , m_BackgroundLayer(0)
650- , _model(0)
651- , _background_color (nux::color::DimGray)
652- , _dash_is_open (false)
653+ : View(NUX_FILE_LINE_PARAM)
654+ , m_ContentOffsetY(0)
655+ , m_BackgroundLayer(0)
656+ , _model(0)
657+ , _collection_window(NULL)
658+ , _background_color(nux::color::DimGray)
659+ , _dash_is_open(false)
660 {
661+
662 _parent = parent;
663 _screen = screen;
664 _active_quicklist = 0;
665@@ -263,6 +264,11 @@
666 _bfb_width = 1;
667 _bfb_height = 1;
668
669+ _data_checked = false;
670+ _collection_window = new unity::DNDCollectionWindow(_screen);
671+ _collection_window->SinkReference();
672+ _on_data_collected_connection = _collection_window->collected.connect(sigc::mem_fun(this, &Launcher::OnDNDDataCollected));
673+
674 // 0 out timers to avoid wonky startups
675 int i;
676 for (i = 0; i < TIME_LAST; ++i)
677@@ -271,6 +277,7 @@
678 _times[i].tv_nsec = 0;
679 }
680
681+ _dnd_hovered_icon = NULL;
682 _drag_window = NULL;
683 _offscreen_drag_texture = nux::GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableDeviceTexture(2, 2, 1, nux::BITFMT_R8G8B8A8);
684
685@@ -350,6 +357,9 @@
686
687 if (_launcher_animation_timeout > 0)
688 g_source_remove(_launcher_animation_timeout);
689+
690+ if (_on_data_collected_connection.connected())
691+ _on_data_collected_connection.disconnect();
692
693 UBusServer* ubus = ubus_server_get_default();
694 for (unsigned int i = 0; i < G_N_ELEMENTS(_ubus_handles); ++i)
695@@ -359,6 +369,9 @@
696 }
697
698 g_idle_remove_by_data(this);
699+
700+ if (_collection_window)
701+ _collection_window->UnReference();
702
703 delete _hover_machine;
704 delete _hide_machine;
705@@ -656,7 +669,7 @@
706 time = icon->GetQuirkTime(LauncherIcon::QUIRK_PROGRESS);
707 if (TimeDelta(&current, &time) < ANIM_DURATION)
708 return true;
709-
710+
711 time = icon->GetQuirkTime(LauncherIcon::QUIRK_DROP_DIM);
712 if (TimeDelta(&current, &time) < ANIM_DURATION)
713 return true;
714@@ -1091,7 +1104,7 @@
715 arg.alpha *= size_modifier;
716 center.z = 300.0f * (1.0f - size_modifier);
717 }
718-
719+
720 float drop_dim_value = 0.2f + 0.8f * IconDropDimValue(icon, current);
721
722 if (drop_dim_value < 1.0f)
723@@ -1513,7 +1526,7 @@
724 _parent->EnableInputWindow(!hidden, "launcher", false, false);
725
726 if (!hidden && GetActionState() == ACTION_DRAG_EXTERNAL)
727- ProcessDndLeave();
728+ DndLeave();
729
730 EnsureAnimation();
731
732@@ -1614,10 +1627,19 @@
733
734 if (drag_owner && (mask & (Button1Mask | Button2Mask | Button3Mask)))
735 {
736- self->_hide_machine->SetQuirk(LauncherHideMachine::EXTERNAL_DND_ACTIVE, true);
737+ if (self->_data_checked == false)
738+ {
739+ self->_data_checked = true;
740+ self->_collection_window->EnableInputWindow(true, "DNDCollectionWindow");
741+ }
742+
743 return true;
744 }
745+
746+ self->_data_checked = false;
747+ self->_collection_window->EnableInputWindow(false, "DNDCollectionWindow");
748
749+ self->DndLeave();
750 self->_hide_machine->SetQuirk(LauncherHideMachine::EXTERNAL_DND_ACTIVE, false);
751 self->_hide_machine->SetQuirk(LauncherHideMachine::DND_PUSHED_OFF, false);
752
753@@ -1681,11 +1703,6 @@
754
755 if (_hidemode == LAUNCHER_HIDE_NEVER)
756 return;
757-
758- if (PluginAdapter::Default ()->IsScaleActive ())
759- _parent->InputWindowEnableStruts (true);
760- else
761- _parent->InputWindowEnableStruts (false);
762 }
763
764 Launcher::LauncherHideMode Launcher::GetHideMode()
765@@ -2803,10 +2820,51 @@
766 nux::GetWindowCompositor().RestoreRenderingSurface();
767 }
768
769+void Launcher::OnDNDDataCollected(const std::list<char*>& mimes)
770+{
771+ _dnd_data.Reset();
772+
773+ unity::glib::String uri_list_const(g_strdup("text/uri-list"));
774+
775+ for (auto it : mimes)
776+ {
777+ if (!g_str_equal(it, uri_list_const.Value()))
778+ continue;
779+
780+ _dnd_data.Fill(nux::GetWindow().GetDndData(uri_list_const.Value()));
781+ break;
782+ }
783+
784+ if (!_dnd_data.Uris().size())
785+ return;
786+
787+ _hide_machine->SetQuirk(LauncherHideMachine::EXTERNAL_DND_ACTIVE, true);
788+
789+ for (auto it : _dnd_data.Uris())
790+ {
791+ if (g_str_has_suffix(it.c_str(), ".desktop"))
792+ {
793+ _steal_drag = true;
794+ break;
795+ }
796+ }
797+
798+ if (!_steal_drag)
799+ {
800+ for (auto it : *_model)
801+ {
802+ if (it->QueryAcceptDrop(_dnd_data) != nux::DNDACTION_NONE)
803+ it->SetQuirk(LauncherIcon::QUIRK_DROP_PRELIGHT, true);
804+ else
805+ it->SetQuirk(LauncherIcon::QUIRK_DROP_DIM, true);
806+ }
807+ }
808+}
809+
810 void
811 Launcher::ProcessDndEnter()
812 {
813- _drag_data.clear();
814+ _dnd_data.Reset();
815 _drag_action = nux::DNDACTION_NONE;
816 _steal_drag = false;
817 _data_checked = false;
818@@ -2815,35 +2873,32 @@
819 }
820
821 void
822+Launcher::DndLeave()
823+{
824+
825+ _dnd_data.Reset();
826+
827+ for (auto it : *_model)
828+ {
829+ it->SetQuirk(LauncherIcon::QUIRK_DROP_PRELIGHT, false);
830+ it->SetQuirk(LauncherIcon::QUIRK_DROP_DIM, false);
831+ }
832+
833+ ProcessDndLeave();
834+}
835+
836+void
837 Launcher::ProcessDndLeave()
838 {
839 SetStateMouseOverLauncher(false);
840 _drag_edge_touching = false;
841
842 SetActionState(ACTION_NONE);
843-
844- if (!_drag_data.empty())
845- {
846- std::list<char*>::iterator it;
847- for (it = _drag_data.begin(); it != _drag_data.end(); it++)
848- {
849- g_free(*it);
850- }
851- }
852- _drag_data.clear();
853-
854- LauncherModel::iterator it;
855- for (it = _model->begin(); it != _model->end(); it++)
856- {
857- (*it)->SetQuirk(LauncherIcon::QUIRK_DROP_PRELIGHT, false);
858- (*it)->SetQuirk(LauncherIcon::QUIRK_DROP_DIM, false);
859- }
860-
861+
862 if (_steal_drag && _dnd_hovered_icon)
863 {
864 _dnd_hovered_icon->SetQuirk(LauncherIcon::QUIRK_VISIBLE, false);
865 _dnd_hovered_icon->remove.emit(_dnd_hovered_icon);
866-
867 }
868
869 if (!_steal_drag && _dnd_hovered_icon)
870@@ -2854,58 +2909,33 @@
871
872 _steal_drag = false;
873 _dnd_hovered_icon = 0;
874-
875-}
876-
877-std::list<char*>
878-Launcher::StringToUriList(char* input)
879-{
880- std::list<char*> result;
881-
882- if (!input)
883- return result;
884-
885- char** imtrappedinastringfactory = g_strsplit(input, "\r\n", -1);
886- int i = 0;
887- while (imtrappedinastringfactory[i]) // get kinda bored
888- {
889- // empty string check
890- if (imtrappedinastringfactory[i][0])
891- result.push_back(g_strdup(imtrappedinastringfactory[i]));
892- ++i;
893- }
894-
895- g_strfreev(imtrappedinastringfactory);
896-
897- return result;
898 }
899
900 void
901 Launcher::ProcessDndMove(int x, int y, std::list<char*> mimes)
902 {
903- std::list<char*>::iterator it;
904 nux::Area* parent = GetToplevel();
905- char* uri_list_const = g_strdup("text/uri-list");
906+ unity::glib::String uri_list_const(g_strdup("text/uri-list"));
907
908 if (!_data_checked)
909 {
910 _data_checked = true;
911- _drag_data.clear();
912+ _dnd_data.Reset();
913
914 // get the data
915- for (it = mimes.begin(); it != mimes.end(); it++)
916- {
917- if (!g_str_equal(*it, uri_list_const))
918+ for (auto it : mimes)
919+ {
920+ if (!g_str_equal(it, uri_list_const.Value()))
921 continue;
922
923- _drag_data = StringToUriList(nux::GetWindow().GetDndData(uri_list_const));
924+ _dnd_data.Fill(nux::GetWindow().GetDndData(uri_list_const.Value()));
925 break;
926 }
927-
928+
929 // see if the launcher wants this one
930- for (it = _drag_data.begin(); it != _drag_data.end(); it++)
931+ for (auto it : _dnd_data.Uris())
932 {
933- if (g_str_has_suffix(*it, ".desktop"))
934+ if (g_str_has_suffix(it.c_str(), ".desktop"))
935 {
936 _steal_drag = true;
937 break;
938@@ -2916,19 +2946,18 @@
939 SetActionState(ACTION_DRAG_EXTERNAL);
940 SetStateMouseOverLauncher(true);
941
942- LauncherModel::iterator it;
943- for (it = _model->begin(); it != _model->end() && !_steal_drag; it++)
944+ if (!_steal_drag)
945 {
946- if ((*it)->QueryAcceptDrop(_drag_data) != nux::DNDACTION_NONE && !_steal_drag)
947- (*it)->SetQuirk(LauncherIcon::QUIRK_DROP_PRELIGHT, true);
948- else
949- (*it)->SetQuirk(LauncherIcon::QUIRK_DROP_DIM, true);
950+ for (auto it : *_model)
951+ {
952+ if (it->QueryAcceptDrop(_dnd_data) != nux::DNDACTION_NONE)
953+ it->SetQuirk(LauncherIcon::QUIRK_DROP_PRELIGHT, true);
954+ else
955+ it->SetQuirk(LauncherIcon::QUIRK_DROP_DIM, true);
956+ }
957 }
958-
959 }
960
961- g_free(uri_list_const);
962-
963 SetMousePosition(x - parent->GetGeometry().x, y - parent->GetGeometry().y);
964
965 if (_mouse_position.x == 0 && _mouse_position.y <= (_parent->GetGeometry().height - _icon_size - 2 * _space_between_icons) && !_drag_edge_touching)
966@@ -2991,7 +3020,7 @@
967 if (hovered_icon)
968 {
969 hovered_icon->SendDndEnter();
970- _drag_action = hovered_icon->QueryAcceptDrop(_drag_data);
971+ _drag_action = hovered_icon->QueryAcceptDrop(_dnd_data);
972 }
973 else
974 {
975@@ -3020,23 +3049,21 @@
976 if (_steal_drag)
977 {
978 char* path = 0;
979- std::list<char*>::iterator it;
980
981- for (it = _drag_data.begin(); it != _drag_data.end(); it++)
982+ for (auto it : _dnd_data.Uris())
983 {
984- if (g_str_has_suffix(*it, ".desktop"))
985+ if (g_str_has_suffix(it.c_str(), ".desktop"))
986 {
987- if (g_str_has_prefix(*it, "application://"))
988+ if (g_str_has_prefix(it.c_str(), "application://"))
989 {
990- const char* tmp = *it + strlen("application://");
991- char* tmp2 = g_strdup_printf("file:///usr/share/applications/%s", tmp);
992- path = g_filename_from_uri(tmp2, NULL, NULL);
993- g_free(tmp2);
994+ const char* tmp = it.c_str() + strlen("application://");
995+ unity::glib::String tmp2(g_strdup_printf("file:///usr/share/applications/%s", tmp));
996+ path = g_filename_from_uri(tmp2.Value(), NULL, NULL);
997 break;
998 }
999- else if (g_str_has_prefix(*it, "file://"))
1000+ else if (g_str_has_prefix(it.c_str(), "file://"))
1001 {
1002- path = g_filename_from_uri(*it, NULL, NULL);
1003+ path = g_filename_from_uri(it.c_str(), NULL, NULL);
1004 break;
1005 }
1006 }
1007@@ -3050,7 +3077,7 @@
1008 }
1009 else if (_dnd_hovered_icon && _drag_action != nux::DNDACTION_NONE)
1010 {
1011- _dnd_hovered_icon->AcceptDrop(_drag_data);
1012+ _dnd_hovered_icon->AcceptDrop(_dnd_data);
1013 }
1014
1015 if (_drag_action != nux::DNDACTION_NONE)
1016@@ -3059,10 +3086,9 @@
1017 SendDndFinished(false, _drag_action);
1018
1019 // reset our shiz
1020- ProcessDndLeave();
1021+ DndLeave();
1022 }
1023
1024-
1025 /*
1026 * Returns the current selected icon if it is in keynavmode
1027 * It will return NULL if it is not on keynavmode
1028
1029=== modified file 'plugins/unityshell/src/Launcher.h'
1030--- plugins/unityshell/src/Launcher.h 2011-08-13 06:17:26 +0000
1031+++ plugins/unityshell/src/Launcher.h 2011-08-19 08:55:26 +0000
1032@@ -27,6 +27,10 @@
1033 #include <Nux/View.h>
1034 #include <Nux/BaseWindow.h>
1035
1036+#include "AbstractIconRenderer.h"
1037+#include "DNDCollectionWindow.h"
1038+#include "DndData.h"
1039+#include "GeisAdapter.h"
1040 #include "Introspectable.h"
1041 #include "LauncherIcon.h"
1042 #include "LauncherDragWindow.h"
1043@@ -35,9 +39,6 @@
1044 #include "NuxGraphics/IOpenGLAsmShader.h"
1045 #include "Nux/TimerProc.h"
1046 #include "PluginAdapter.h"
1047-#include "GeisAdapter.h"
1048-
1049-#include "AbstractIconRenderer.h"
1050
1051 #define ANIM_DURATION_SHORT 125
1052 #define ANIM_DURATION 200
1053@@ -204,6 +205,7 @@
1054 const gchar* GetName();
1055 void AddProperties(GVariantBuilder* builder);
1056
1057+ void DndLeave();
1058 void ProcessDndEnter();
1059 void ProcessDndLeave();
1060 void ProcessDndMove(int x, int y, std::list<char*> mimes);
1061@@ -361,9 +363,9 @@
1062
1063 gboolean TapOnSuper();
1064
1065- std::list<char*> StringToUriList(char* input);
1066-
1067 static void SettingsChanged(GSettings* settings, gchar* key, Launcher* self);
1068+
1069+ void OnDNDDataCollected(const std::list<char*>& mimes);
1070
1071 nux::HLayout* m_Layout;
1072 int m_ContentOffsetY;
1073@@ -446,12 +448,14 @@
1074 LauncherHoverMachine* _hover_machine;
1075 CompScreen* _screen;
1076
1077- std::list<char*> _drag_data;
1078+ unity::DndData _dnd_data;
1079 nux::DndAction _drag_action;
1080 bool _data_checked;
1081 bool _steal_drag;
1082 bool _drag_edge_touching;
1083 LauncherIcon* _dnd_hovered_icon;
1084+ unity::DNDCollectionWindow* _collection_window;
1085+ sigc::connection _on_data_collected_connection;
1086
1087 Atom _selection_atom;
1088
1089@@ -489,5 +493,3 @@
1090 };
1091
1092 #endif // LAUNCHER_H
1093-
1094-
1095
1096=== modified file 'plugins/unityshell/src/LauncherIcon.cpp'
1097--- plugins/unityshell/src/LauncherIcon.cpp 2011-08-10 12:12:18 +0000
1098+++ plugins/unityshell/src/LauncherIcon.cpp 2011-08-19 08:55:26 +0000
1099@@ -804,10 +804,10 @@
1100 {
1101 if (_quirks[quirk] == value)
1102 return;
1103-
1104+
1105 if (quirk == QUIRK_PULSE_ONCE)
1106 _launcher->HideMachine()->SetQuirk(LauncherHideMachine::LAUNCHER_PULSE, value);
1107-
1108+
1109 _quirks[quirk] = value;
1110 if (quirk == QUIRK_VISIBLE)
1111 Launcher::SetTimeStruct(&(_quirk_times[quirk]), &(_quirk_times[quirk]), ANIM_DURATION_SHORT);
1112
1113=== modified file 'plugins/unityshell/src/LauncherIcon.h'
1114--- plugins/unityshell/src/LauncherIcon.h 2011-08-07 23:19:44 +0000
1115+++ plugins/unityshell/src/LauncherIcon.h 2011-08-19 08:55:26 +0000
1116@@ -21,6 +21,9 @@
1117 #ifndef LAUNCHERICON_H
1118 #define LAUNCHERICON_H
1119
1120+#include <set>
1121+#include <string>
1122+
1123 #include <Nux/Nux.h>
1124 #include <Nux/BaseWindow.h>
1125 #include <NuxCore/Math/MathInc.h>
1126@@ -43,7 +46,6 @@
1127
1128 class Launcher;
1129
1130-
1131 class LauncherIcon : public AbstractLauncherIcon, public unity::Introspectable, public nux::InitiallyUnownedObject
1132 {
1133 NUX_DECLARE_OBJECT_TYPE(LauncherIcon, nux::InitiallyUnownedObject);
1134@@ -150,14 +152,14 @@
1135
1136 void RemoveEntryRemote(LauncherEntryRemote* remote);
1137
1138- nux::DndAction QueryAcceptDrop(std::list<char*> paths)
1139+ nux::DndAction QueryAcceptDrop(unity::DndData& dnd_data)
1140 {
1141- return OnQueryAcceptDrop(paths);
1142+ return OnQueryAcceptDrop(dnd_data);
1143 }
1144
1145- void AcceptDrop(std::list<char*> paths)
1146+ void AcceptDrop(unity::DndData& dnd_data)
1147 {
1148- return OnAcceptDrop(paths);
1149+ return OnAcceptDrop(dnd_data);
1150 }
1151
1152 void SendDndEnter()
1153@@ -221,12 +223,12 @@
1154 return 0;
1155 }
1156
1157- virtual nux::DndAction OnQueryAcceptDrop(std::list<char*> files)
1158+ virtual nux::DndAction OnQueryAcceptDrop(unity::DndData& dnd_data)
1159 {
1160 return nux::DNDACTION_NONE;
1161 }
1162
1163- virtual void OnAcceptDrop(std::list<char*> files) {}
1164+ virtual void OnAcceptDrop(unity::DndData& dnd_data) {}
1165
1166 virtual void OnDndEnter() {}
1167
1168@@ -327,7 +329,7 @@
1169
1170 std::list<LauncherEntryRemote*> _entry_list;
1171 std::map<std::string, std::vector<nux::Vector4> > transform_map;
1172-
1173+
1174 };
1175
1176 #endif // LAUNCHERICON_H
1177
1178=== modified file 'plugins/unityshell/src/MockLauncherIcon.h'
1179--- plugins/unityshell/src/MockLauncherIcon.h 2011-08-04 20:19:46 +0000
1180+++ plugins/unityshell/src/MockLauncherIcon.h 2011-08-19 08:55:26 +0000
1181@@ -179,12 +179,12 @@
1182 return std::list<DbusmenuMenuitem*> ();
1183 }
1184
1185- nux::DndAction QueryAcceptDrop(std::list<char*> paths)
1186+ nux::DndAction QueryAcceptDrop(unity::DndData& dnd_data)
1187 {
1188 return nux::DNDACTION_NONE;
1189 }
1190
1191- void AcceptDrop(std::list<char*> paths) {}
1192+ void AcceptDrop(unity::DndData& dnd_data) {}
1193
1194 void SendDndEnter() {}
1195
1196
1197=== modified file 'plugins/unityshell/src/TrashLauncherIcon.cpp'
1198--- plugins/unityshell/src/TrashLauncherIcon.cpp 2011-07-30 09:00:43 +0000
1199+++ plugins/unityshell/src/TrashLauncherIcon.cpp 2011-08-19 08:55:26 +0000
1200@@ -18,15 +18,17 @@
1201 */
1202
1203 #include "TrashLauncherIcon.h"
1204+
1205+#include <Nux/WindowCompositor.h>
1206+
1207+#include <gio/gio.h>
1208+#include <glib/gi18n-lib.h>
1209+#include <gconf/gconf-client.h>
1210+
1211 #include "Launcher.h"
1212-#include "Nux/WindowCompositor.h"
1213-
1214 #include "QuicklistManager.h"
1215 #include "QuicklistMenuItemLabel.h"
1216
1217-#include <gio/gio.h>
1218-#include <glib/gi18n-lib.h>
1219-#include <gconf/gconf-client.h>
1220
1221 #define ASK_CONFIRMATION_KEY "/apps/nautilus/preferences/confirm_trash"
1222
1223@@ -277,19 +279,17 @@
1224 }
1225
1226 nux::DndAction
1227-TrashLauncherIcon::OnQueryAcceptDrop(std::list<char*> uris)
1228+TrashLauncherIcon::OnQueryAcceptDrop(unity::DndData& dnd_data)
1229 {
1230 return nux::DNDACTION_MOVE;
1231 }
1232
1233 void
1234-TrashLauncherIcon::OnAcceptDrop(std::list<char*> uris)
1235+TrashLauncherIcon::OnAcceptDrop(unity::DndData& dnd_data)
1236 {
1237- std::list<char*>::iterator it;
1238-
1239- for (it = uris.begin(); it != uris.end(); it++)
1240+ for (auto it : dnd_data.Uris())
1241 {
1242- GFile* file = g_file_new_for_uri(*it);
1243+ GFile* file = g_file_new_for_uri(it.c_str());
1244 g_file_trash(file, NULL, NULL);
1245 g_object_unref(file);
1246 }
1247
1248=== modified file 'plugins/unityshell/src/TrashLauncherIcon.h'
1249--- plugins/unityshell/src/TrashLauncherIcon.h 2011-07-21 14:59:25 +0000
1250+++ plugins/unityshell/src/TrashLauncherIcon.h 2011-08-19 08:55:26 +0000
1251@@ -20,6 +20,7 @@
1252 #ifndef TRASHLAUNCHERICON_H
1253 #define TRASHLAUNCHERICON_H
1254
1255+#include "DndData.h"
1256 #include "SimpleLauncherIcon.h"
1257
1258 class TrashLauncherIcon : public SimpleLauncherIcon
1259@@ -35,8 +36,8 @@
1260 protected:
1261 void UpdateTrashIcon();
1262
1263- nux::DndAction OnQueryAcceptDrop(std::list<char*> uris);
1264- void OnAcceptDrop(std::list<char*> uris);
1265+ nux::DndAction OnQueryAcceptDrop(unity::DndData& dnd_data);
1266+ void OnAcceptDrop(unity::DndData& dnd_data);
1267
1268 private:
1269 gulong _on_trash_changed_handler_id;