1 /**
2 * This file is a part of the Cairo-Dock project
3 *
4 * Copyright : (C) see the 'copyright' file.
5 * E-mail    : see the 'copyright' file.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 3
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #include <string.h>
21 #include <math.h>
22 
23 #include <cairo-dock.h>
24 
25 #include "applet-struct.h"
26 #include "applet-bookmarks.h"
27 #include "applet-disk-usage.h"
28 #include "applet-drives.h"
29 #include "applet-load-icons.h"
30 
31 
cd_shortcuts_set_icon_order_by_name(Icon * pNewIcon,GList * pIconsList)32 void cd_shortcuts_set_icon_order_by_name (Icon *pNewIcon, GList *pIconsList)
33 {
34 	GList *ic;
35 	Icon *pIcon;
36 	for (ic = pIconsList; ic != NULL; ic = ic->next)
37 	{
38 		pIcon = ic->data;
39 		if (pIcon->iGroup == pNewIcon->iGroup)
40 			break;
41 	}
42 	GList *ic0 = ic;
43 	if (! ic0)
44 	{
45 		pNewIcon->fOrder = 0;
46 		return;
47 	}
48 
49 	pIcon = ic0->data;
50 	if (cairo_dock_compare_icons_name (pNewIcon, pIcon) <= 0)
51 	{
52 		pNewIcon->fOrder = pIcon->fOrder - 1;
53 		//g_print ("name : %s <= %s -> %.2f\n", pNewIcon->cName, pIcon->cName, pNewIcon->fOrder);
54 		return;
55 	}
56 
57 	pNewIcon->fOrder = 0;
58 	for (ic = ic0; ic != NULL; ic = ic->next)
59 	{
60 		pIcon = ic->data;
61 		if (pIcon->iGroup != pNewIcon->iGroup)
62 			break;
63 		if (cairo_dock_compare_icons_name (pNewIcon, pIcon) < 0)
64 		{
65 			if (ic->prev == NULL)
66 				pNewIcon->fOrder = pIcon->fOrder - 1;
67 			else
68 			{
69 				Icon *pPrevIcon = ic->prev->data;
70 				pNewIcon->fOrder = (pIcon->fOrder + pPrevIcon->fOrder) / 2;
71 			}
72 			//g_print ("  name : %s < %s -> %.2f\n", pNewIcon->cName, pIcon->cName, pNewIcon->fOrder);
73 			break;
74 		}
75 		pNewIcon->fOrder = pIcon->fOrder + 1;
76 	}
77 }
78 
79 
_cd_shortcuts_on_network_event(CairoDockFMEventType iEventType,const gchar * cURI,GldiModuleInstance * myApplet)80 static void _cd_shortcuts_on_network_event (CairoDockFMEventType iEventType, const gchar *cURI, GldiModuleInstance *myApplet)
81 {
82 	CD_APPLET_ENTER;
83 
84 	//g_print (" * event %d on network '%s'\n", iEventType, cURI);
85 	GList *pIconsList = CD_APPLET_MY_ICONS_LIST;
86 	GldiContainer *pContainer = CD_APPLET_MY_ICONS_LIST_CONTAINER;
87 	CD_APPLET_LEAVE_IF_FAIL (pContainer != NULL);
88 
89 	switch (iEventType)
90 	{
91 		case CAIRO_DOCK_FILE_DELETED :  // un reseau a ete deconnecte.
92 		{
93 			Icon *pConcernedIcon = cairo_dock_get_icon_with_base_uri (pIconsList, cURI);
94 			if (pConcernedIcon == NULL)  // on cherche par nom.
95 			{
96 				pConcernedIcon = cairo_dock_get_icon_with_name (pIconsList, cURI);
97 			}
98 			if (pConcernedIcon == NULL)
99 			{
100 				cd_warning ("  an unknown network was removed");
101 				return ;
102 			}
103 			//g_print (" %s will be removed\n", pConcernedIcon->cName);
104 
105 			CD_APPLET_REMOVE_ICON_FROM_MY_ICONS_LIST (pConcernedIcon);
106 		}
107 		break ;
108 
109 		case CAIRO_DOCK_FILE_CREATED :  // un reseau a ete connecte.
110 		{
111 			//\_______________________ on verifie qu'elle n'existe pas deja.
112 			Icon *pSameIcon = cairo_dock_get_icon_with_base_uri (pIconsList, cURI);
113 			if (pSameIcon != NULL)
114 			{
115 				cd_warning ("this mount point (%s) already exists.", pSameIcon->cName);
116 				return;  // on decide de ne rien faire, c'est surement un signal inutile.
117 			}
118 
119 			//\_______________________ on cree une icone pour cette nouvelle URI.
120 			Icon *pNewIcon = cairo_dock_fm_create_icon_from_URI (cURI, pContainer, CAIRO_DOCK_FM_SORT_BY_NAME);
121 			if (pNewIcon == NULL)
122 			{
123 				cd_warning ("couldn't create an icon for this network");
124 				return ;
125 			}
126 			pNewIcon->iGroup = CD_NETWORK_GROUP;
127 
128 			//\_______________________ on la place au bon endroit suivant son nom.
129 			cd_shortcuts_set_icon_order_by_name (pNewIcon, pIconsList);
130 			//g_print (" new network : %s, order = %.2f\n", pNewIcon->cName, pNewIcon->fOrder);
131 
132 			//\_______________________ on l'insere dans la liste.
133 			CD_APPLET_ADD_ICON_IN_MY_ICONS_LIST (pNewIcon);
134 
135 			//\_______________________ on affiche un message.
136 			gldi_dialog_show_temporary_with_icon_printf (
137 				D_("%s has been connected"),
138 				pNewIcon, pContainer,
139 				4000,
140 				NULL,  // son icone n'est pas encore chargee
141 				pNewIcon->cName);
142 		}
143 		break ;
144 
145 		case CAIRO_DOCK_FILE_MODIFIED :  // un point de montage a ete (de)monte
146 		{
147 			//\_______________________ on cherche l'icone concernee.
148 			Icon *pConcernedIcon = cairo_dock_get_icon_with_base_uri (pIconsList, cURI);
149 			if (pConcernedIcon == NULL)  // on cherche par nom.
150 			{
151 				pConcernedIcon = cairo_dock_get_icon_with_name (pIconsList, cURI);
152 			}
153 			if (pConcernedIcon == NULL)
154 			{
155 				cd_warning ("  an unknown network was modified");
156 				return ;
157 			}
158 			//g_print (" %s is modified\n", pConcernedIcon->cName);
159 
160 			//\_______________________ on recupere les infos actuelles.
161 			Icon *pNewIcon = cairo_dock_fm_create_icon_from_URI (cURI, pContainer, CAIRO_DOCK_FM_SORT_BY_NAME);
162 			if (pNewIcon == NULL)
163 			{
164 				cd_warning ("couldn't create an icon for this network");
165 				return ;
166 			}
167 			pNewIcon->iGroup = CD_NETWORK_GROUP;
168 
169 			//\_______________________ on remplace l'icone si des choses ont change.
170 			if (cairo_dock_strings_differ (pConcernedIcon->cName, pNewIcon->cName) || cairo_dock_strings_differ (pConcernedIcon->cFileName, pNewIcon->cFileName))
171 			{
172 				//g_print (" '%s' -> '%s'\n'%s' -> '%s'\n", pConcernedIcon->cName, pNewIcon->cName, pConcernedIcon->cFileName, pNewIcon->cFileName);
173 
174 				CD_APPLET_REMOVE_ICON_FROM_MY_ICONS_LIST (pConcernedIcon);
175 				pIconsList = CD_APPLET_MY_ICONS_LIST;
176 
177 				cd_shortcuts_set_icon_order_by_name (pNewIcon, pIconsList);
178 				CD_APPLET_ADD_ICON_IN_MY_ICONS_LIST (pNewIcon);
179 			}
180 			else
181 			{
182 				gldi_object_unref (GLDI_OBJECT (pNewIcon));
183 			}
184 		}
185 		break ;
186 
187 		case CAIRO_DOCK_NB_EVENT_ON_FILES :
188 		break ;
189 	}
190 	CD_APPLET_LEAVE();
191 }
192 
193 
_load_icons(CDSharedMemory * pSharedMemory)194 static inline GList * _load_icons (CDSharedMemory *pSharedMemory)
195 {
196 	GList *pIconList = NULL;
197 
198 	if (pSharedMemory->bListDrives)
199 	{
200 		pIconList = cd_shortcuts_list_drives (pSharedMemory);
201 	}
202 
203 	if (pSharedMemory->bListNetwork)
204 	{
205 		gchar *cFullURI = NULL;
206 		GList *pIconList2 = cairo_dock_fm_list_directory (CAIRO_DOCK_FM_NETWORK, CAIRO_DOCK_FM_SORT_BY_NAME, CD_NETWORK_GROUP, FALSE, 100, &cFullURI);
207 		cd_message ("  cFullURI : %s", cFullURI);
208 
209 		pIconList = g_list_concat (pIconList, pIconList2);
210 
211 		pSharedMemory->cNetworkURI = cFullURI;
212 	}
213 
214 	if (pSharedMemory->bListBookmarks)
215 	{
216 		// guess the file we should use (from GTK 3.6, the new one should be used, but some system (like Mint-14) didn't switch on time and still use the old one...)
217 		gchar *cBookmarkFilePath = NULL;
218 		#if GTK_CHECK_VERSION (3, 6, 0)
219 		gchar *cBookmarkFilePathNew = g_strdup_printf ("%s/"GTK_BOOKMARKS_PATH, g_getenv ("HOME"));
220 		gchar *cBookmarkFilePathOld = g_strdup_printf ("%s/"GTK_BOOKMARKS_PATH_OLD, g_getenv ("HOME"));
221 		if (! g_file_test (cBookmarkFilePathNew, G_FILE_TEST_EXISTS))  // the new file doesn't exist yet, it's either that the old one is used, or that none is used
222 		{
223 			if (g_file_test (cBookmarkFilePathOld, G_FILE_TEST_EXISTS))
224 			{
225 				cBookmarkFilePath = cBookmarkFilePathOld;
226 				cBookmarkFilePathOld = NULL;
227 			}
228 			else  // none are used, use the new one
229 			{
230 				cBookmarkFilePath = cBookmarkFilePathNew;
231 				cBookmarkFilePathNew = NULL;
232 			}
233 		}
234 		else  // the new one exists -> take it, unless it's empty and the old one exists too (may happen if we created the new one when the old one was still used, in version 3.3.1)
235 		{
236 			if (cairo_dock_get_file_size (cBookmarkFilePathNew) == 0 && g_file_test (cBookmarkFilePathOld, G_FILE_TEST_EXISTS) && cairo_dock_get_file_size (cBookmarkFilePathOld) != 0)
237 			{
238 				cBookmarkFilePath = cBookmarkFilePathOld;
239 				cBookmarkFilePathOld = NULL;
240 			}
241 			else  // none are used, use the new one
242 			{
243 				cBookmarkFilePath = cBookmarkFilePathNew;
244 				cBookmarkFilePathNew = NULL;
245 			}
246 		}
247 		g_free (cBookmarkFilePathOld);
248 		g_free (cBookmarkFilePathNew);
249 		#else
250 		cBookmarkFilePath = g_strdup_printf ("%s/"GTK_BOOKMARKS_PATH_OLD, g_getenv ("HOME"));
251 		#endif
252 		// we create this file if it doesn't exist in order to be able to add bookmarks later
253 		if (! g_file_test (cBookmarkFilePath, G_FILE_TEST_EXISTS))
254 		{
255 			// first, we need to be sure that its directory exists
256 			char *str = strrchr (cBookmarkFilePath, '/'); // last occurrence of '/'
257 			*str = '\0';
258 			g_mkdir_with_parents (cBookmarkFilePath, 7*8*8+7*8+5);
259 			*str = '/';
260 			// create the empty file
261 			FILE *f = fopen (cBookmarkFilePath, "a");
262 			if (f)
263 				fclose (f);
264 		}
265 
266 		GList *pIconList2 = cd_shortcuts_list_bookmarks (cBookmarkFilePath, pSharedMemory->pApplet);
267 
268 		pIconList = g_list_concat (pIconList, pIconList2);
269 
270 		pSharedMemory->cBookmarksURI = cBookmarkFilePath;
271 	}
272 
273 	return pIconList;
274 }
cd_shortcuts_get_shortcuts_data(CDSharedMemory * pSharedMemory)275 static void cd_shortcuts_get_shortcuts_data (CDSharedMemory *pSharedMemory)
276 {
277 	pSharedMemory->pIconList = _load_icons (pSharedMemory);
278 }
279 
cd_shortcuts_build_shortcuts_from_data(CDSharedMemory * pSharedMemory)280 static gboolean cd_shortcuts_build_shortcuts_from_data (CDSharedMemory *pSharedMemory)
281 {
282 	GldiModuleInstance *myApplet = pSharedMemory->pApplet;
283 	g_return_val_if_fail (myIcon != NULL, FALSE);  // paranoia
284 	CD_APPLET_ENTER;
285 
286 	//\_______________________ get the result of the thread.
287 	GList *pIconList = pSharedMemory->pIconList;
288 	pSharedMemory->pIconList = NULL;
289 	myData.cDisksURI = pSharedMemory->cDisksURI;
290 	pSharedMemory->cDisksURI = NULL;
291 	myData.cNetworkURI = pSharedMemory->cNetworkURI;
292 	pSharedMemory->cNetworkURI = NULL;
293 	myData.cBookmarksURI = pSharedMemory->cBookmarksURI;
294 	pSharedMemory->cBookmarksURI = NULL;
295 
296 	//\_______________________ monitor the sets.
297 	if (myData.cDisksURI)
298 	{
299 		if (! cairo_dock_fm_add_monitor_full (myData.cDisksURI, TRUE, NULL, (CairoDockFMMonitorCallback) cd_shortcuts_on_drive_event, myApplet))
300 			cd_warning ("Shortcuts : can't monitor drives");
301 	}
302 	if (myData.cNetworkURI)
303 	{
304 		if (! cairo_dock_fm_add_monitor_full (myData.cNetworkURI, TRUE, NULL, (CairoDockFMMonitorCallback) _cd_shortcuts_on_network_event, myApplet))
305 			cd_warning ("Shortcuts : can't monitor network");
306 	}
307 	if (myData.cBookmarksURI)
308 	{
309 		if (! cairo_dock_fm_add_monitor_full (myData.cBookmarksURI, FALSE, NULL, (CairoDockFMMonitorCallback) cd_shortcuts_on_bookmarks_event, myApplet))
310 			cd_warning ("Shortcuts : can't monitor bookmarks");
311 	}
312 
313 	//\_______________________ On efface l'ancienne liste.
314 	CD_APPLET_DELETE_MY_ICONS_LIST;
315 
316 	//\_______________________ On charge la nouvelle liste.
317 	const gchar *cDeskletRendererName = NULL;
318 	switch (myConfig.iDeskletRendererType)
319 	{
320 		case CD_DESKLET_SLIDE :
321 		default :
322 			cDeskletRendererName = "Viewport";
323 		break ;
324 
325 		case CD_DESKLET_TREE :
326 			cDeskletRendererName = "Tree";
327 		break ;
328 	}
329 	CD_APPLET_LOAD_MY_ICONS_LIST (pIconList, myConfig.cRenderer, cDeskletRendererName, NULL);  // takes ownership of 'pIconList'
330 
331 	//\_______________________ add a progress bar on disk volumes (must be done after inserting the icons into a container)
332 	pIconList = CD_APPLET_MY_ICONS_LIST;
333 	Icon *pIcon;
334 	GList *ic;
335 	for (ic = pIconList; ic != NULL; ic = ic->next)
336 	{
337 		pIcon = ic->data;
338 		if (CD_APPLET_GET_MY_ICON_DATA (pIcon) != NULL)  // drive
339 			cd_shortcuts_add_progress_bar (pIcon, myApplet);
340 	}
341 
342 	//\_______________________ On lance la tache de mesure des disques.
343 	cd_shortcuts_launch_disk_periodic_task (myApplet);
344 
345 	if (myData.bShowMenuPending)
346 	{
347 		gldi_object_notify (myContainer, NOTIFICATION_CLICK_ICON, myIcon, myDock, GDK_BUTTON1_MASK);
348 		myData.bShowMenuPending = FALSE;
349 	}
350 
351 	gldi_task_discard (myData.pTask);
352 	myData.pTask = NULL;
353 
354 	CD_APPLET_LEAVE (TRUE);
355 }
356 
_free_shared_memory(CDSharedMemory * pSharedMemory)357 static void _free_shared_memory (CDSharedMemory *pSharedMemory)
358 {
359 	g_free (pSharedMemory->cDisksURI);
360 	g_free (pSharedMemory->cNetworkURI);
361 	g_free (pSharedMemory->cBookmarksURI);
362 	g_list_foreach (pSharedMemory->pIconList, (GFunc)g_free, NULL);
363 	g_list_free (pSharedMemory->pIconList);
364 	g_free (pSharedMemory);
365 }
cd_shortcuts_start(GldiModuleInstance * myApplet)366 void cd_shortcuts_start (GldiModuleInstance *myApplet)
367 {
368 	if (myData.pTask != NULL)
369 	{
370 		gldi_task_discard (myData.pTask);
371 		myData.pTask = NULL;
372 	}
373 
374 	CDSharedMemory *pSharedMemory = g_new0 (CDSharedMemory, 1);
375 	pSharedMemory->bListDrives = myConfig.bListDrives;
376 	pSharedMemory->bListNetwork = myConfig.bListNetwork;
377 	pSharedMemory->bListBookmarks = myConfig.bListBookmarks;
378 	pSharedMemory->pApplet = myApplet;
379 
380 	myData.pTask = gldi_task_new_full (0,
381 		(GldiGetDataAsyncFunc) cd_shortcuts_get_shortcuts_data,
382 		(GldiUpdateSyncFunc) cd_shortcuts_build_shortcuts_from_data,
383 		(GFreeFunc) _free_shared_memory,
384 		pSharedMemory);
385 
386 	if (cairo_dock_is_loading ())
387 		gldi_task_launch_delayed (myData.pTask, 0); // 0 <=> g_idle
388 	else
389 		gldi_task_launch (myData.pTask);
390 }
391 
392