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 <math.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <cairo.h>
24 
25 #include "cairo-dock-image-buffer.h"
26 #include "cairo-dock-draw.h"
27 #include "cairo-dock-utils.h"  // cairo_dock_launch_command
28 #include "cairo-dock-launcher-manager.h"
29 #include "cairo-dock-surface-factory.h"
30 #include "cairo-dock-animations.h"
31 #include "cairo-dock-packages.h"
32 #include "cairo-dock-keyfile-utilities.h"
33 #include "cairo-dock-module-instance-manager.h"  // GldiModuleInstance
34 #include "cairo-dock-module-manager.h"  // GldiModuleInstance
35 #include "cairo-dock-log.h"
36 #include "cairo-dock-config.h"
37 #include "cairo-dock-dock-factory.h"
38 #include "cairo-dock-dock-manager.h"
39 #include "cairo-dock-draw-opengl.h"
40 #include "cairo-dock-icon-factory.h"
41 #include "cairo-dock-container.h"
42 #include "cairo-dock-gui-manager.h"
43 #include "cairo-dock-backends-manager.h"
44 #include "cairo-dock-dock-facility.h"
45 #include "cairo-dock-icon-facility.h"
46 #include "cairo-dock-applet-facility.h"
47 
48 extern gchar *g_cExtrasDirPath;
49 
50 extern gboolean g_bUseOpenGL;
51 
52 
cairo_dock_set_icon_surface_full(cairo_t * pIconContext,cairo_surface_t * pSurface,double fScale,double fAlpha,Icon * pIcon)53 void cairo_dock_set_icon_surface_full (cairo_t *pIconContext, cairo_surface_t *pSurface, double fScale, double fAlpha, Icon *pIcon)
54 {
55 	//\________________ On efface l'ancienne image.
56 	if (! cairo_dock_begin_draw_icon_cairo (pIcon, 0, pIconContext))  // 0 <=> erase
57 		return;
58 
59 	//\________________ On applique la nouvelle image.
60 	if (pSurface != NULL && fScale > 0)
61 	{
62 		cairo_save (pIconContext);
63 		if (fScale != 1 && pIcon != NULL)
64 		{
65 			int iWidth, iHeight;
66 			cairo_dock_get_icon_extent (pIcon, &iWidth, &iHeight);
67 			cairo_translate (pIconContext, .5 * iWidth * (1 - fScale) , .5 * iHeight * (1 - fScale));
68 			cairo_scale (pIconContext, fScale, fScale);
69 		}
70 
71 		cairo_set_source_surface (
72 			pIconContext,
73 			pSurface,
74 			0.,
75 			0.);
76 
77 		if (fAlpha != 1)
78 			cairo_paint_with_alpha (pIconContext, fAlpha);
79 		else
80 			cairo_paint (pIconContext);
81 		cairo_restore (pIconContext);
82 	}
83 	cairo_dock_end_draw_icon_cairo (pIcon);
84 }
85 
86 
87 /// TODO: don't use 'cairo_dock_set_icon_surface' here...
cairo_dock_set_image_on_icon(cairo_t * pIconContext,const gchar * cIconName,Icon * pIcon,G_GNUC_UNUSED GldiContainer * pContainer)88 gboolean cairo_dock_set_image_on_icon (cairo_t *pIconContext, const gchar *cIconName, Icon *pIcon, G_GNUC_UNUSED GldiContainer *pContainer)
89 {
90 	//g_print ("%s (%s)\n", __func__, cIconName);
91 	// load the image in a surface.
92 	int iWidth, iHeight;
93 	cairo_dock_get_icon_extent (pIcon, &iWidth, &iHeight);
94 	cairo_surface_t *pImageSurface = cairo_dock_create_surface_from_icon (cIconName,
95 		iWidth,
96 		iHeight);
97 
98 	// check that it's ok.
99 	if (pImageSurface == NULL)  // let the icon in its current state.
100 		return FALSE;
101 
102 	// set the new image on the icon
103 	cairo_dock_set_icon_surface (pIconContext, pImageSurface, pIcon);
104 
105 	cairo_surface_destroy (pImageSurface);
106 
107 	if (cIconName != pIcon->cFileName)
108 	{
109 		g_free (pIcon->cFileName);
110 		pIcon->cFileName = g_strdup (cIconName);
111 	}
112 	return TRUE;
113 }
114 
cairo_dock_set_image_on_icon_with_default(cairo_t * pIconContext,const gchar * cIconName,Icon * pIcon,GldiContainer * pContainer,const gchar * cDefaultImagePath)115 void cairo_dock_set_image_on_icon_with_default (cairo_t *pIconContext, const gchar *cIconName, Icon *pIcon, GldiContainer *pContainer, const gchar *cDefaultImagePath)
116 {
117 	if (! cIconName || ! cairo_dock_set_image_on_icon (pIconContext, cIconName, pIcon, pContainer))
118 		cairo_dock_set_image_on_icon (pIconContext, cDefaultImagePath, pIcon, pContainer);
119 }
120 
121 
cairo_dock_set_hours_minutes_as_quick_info(Icon * pIcon,int iTimeInSeconds)122 void cairo_dock_set_hours_minutes_as_quick_info (Icon *pIcon, int iTimeInSeconds)
123 {
124 	int hours = iTimeInSeconds / 3600;
125 	int minutes = (iTimeInSeconds % 3600) / 60;
126 	if (hours != 0)
127 		gldi_icon_set_quick_info_printf (pIcon, "%dh%02d", hours, abs (minutes));
128 	else
129 		gldi_icon_set_quick_info_printf (pIcon, "%dmn", minutes);
130 }
131 
cairo_dock_set_minutes_secondes_as_quick_info(Icon * pIcon,int iTimeInSeconds)132 void cairo_dock_set_minutes_secondes_as_quick_info (Icon *pIcon, int iTimeInSeconds)
133 {
134 	int minutes = iTimeInSeconds / 60;
135 	int secondes = iTimeInSeconds % 60;
136 	//cd_debug ("%s (%d:%d)", __func__, minutes, secondes);
137 	if (minutes != 0)
138 		gldi_icon_set_quick_info_printf (pIcon, "%d:%02d", minutes, abs (secondes));
139 	else
140 		gldi_icon_set_quick_info_printf (pIcon, "%s0:%02d", (secondes < 0 ? "-" : ""), abs (secondes));
141 }
142 
cairo_dock_get_human_readable_size(long long int iSizeInBytes)143 gchar *cairo_dock_get_human_readable_size (long long int iSizeInBytes)
144 {
145 	double fValue;
146 	if (iSizeInBytes >> 10 == 0)
147 	{
148 		return g_strdup_printf ("%dB", (int) iSizeInBytes);
149 	}
150 	else if (iSizeInBytes >> 20 == 0)
151 	{
152 		fValue = (double) (iSizeInBytes) / 1024.;
153 		return g_strdup_printf (fValue < 10 ? "%.1fK" : "%.0fK", fValue);
154 	}
155 	else if (iSizeInBytes >> 30 == 0)
156 	{
157 		fValue = (double) (iSizeInBytes >> 10) / 1024.;
158 		return g_strdup_printf (fValue < 10 ? "%.1fM" : "%.0fM", fValue);
159 	}
160 	else if (iSizeInBytes >> 40 == 0)
161 	{
162 		fValue = (double) (iSizeInBytes >> 20) / 1024.;
163 		return g_strdup_printf (fValue < 10 ? "%.1fG" : "%.0fG", fValue);
164 	}
165 	else
166 	{
167 		fValue = (double) (iSizeInBytes >> 30) / 1024.;
168 		return g_strdup_printf (fValue < 10 ? "%.1fT" : "%.0fT", fValue);
169 	}
170 }
171 
cairo_dock_set_size_as_quick_info(Icon * pIcon,long long int iSizeInBytes)172 void cairo_dock_set_size_as_quick_info (Icon *pIcon, long long int iSizeInBytes)
173 {
174 	gchar *cSize = cairo_dock_get_human_readable_size (iSizeInBytes);
175 	gldi_icon_set_quick_info (pIcon, cSize);
176 	g_free (cSize);
177 }
178 
179 
180 
cairo_dock_get_theme_path_for_module(const gchar * cAppletConfFilePath,GKeyFile * pKeyFile,const gchar * cGroupName,const gchar * cKeyName,gboolean * bFlushConfFileNeeded,const gchar * cDefaultThemeName,const gchar * cShareThemesDir,const gchar * cExtraDirName)181 gchar *cairo_dock_get_theme_path_for_module (const gchar *cAppletConfFilePath, GKeyFile *pKeyFile, const gchar *cGroupName, const gchar *cKeyName, gboolean *bFlushConfFileNeeded, const gchar *cDefaultThemeName, const gchar *cShareThemesDir, const gchar *cExtraDirName)
182 {
183 	gchar *cThemeName = cairo_dock_get_string_key_value (pKeyFile, cGroupName, cKeyName, bFlushConfFileNeeded, cDefaultThemeName, NULL, NULL);
184 
185 	gchar *cUserThemesDir = (cExtraDirName != NULL ? g_strdup_printf ("%s/%s", g_cExtrasDirPath, cExtraDirName) : NULL);
186 	CairoDockPackageType iType = cairo_dock_extract_package_type_from_name (cThemeName);
187 	gchar *cThemePath = cairo_dock_get_package_path (cThemeName, cShareThemesDir, cUserThemesDir, cExtraDirName, iType);
188 
189 	if (iType != CAIRO_DOCK_ANY_PACKAGE)
190 	{
191 		g_key_file_set_string (pKeyFile, cGroupName, cKeyName, cThemeName);
192 		cairo_dock_write_keys_to_file (pKeyFile, cAppletConfFilePath);
193 	}
194 	g_free (cThemeName);
195 	g_free (cUserThemesDir);
196 	return cThemePath;
197 }
198 
199 
200 //Utile pour jouer des fichiers son depuis le dock.
201 //A utiliser avec l'Objet UI 'u' dans les .conf
cairo_dock_play_sound(const gchar * cSoundPath)202 void cairo_dock_play_sound (const gchar *cSoundPath)
203 {
204 	cd_debug ("%s (%s)", __func__, cSoundPath);
205 	if (cSoundPath == NULL)
206 	{
207 		cd_warning ("No sound to play, skip.");
208 		return;
209 	}
210 
211 	gchar *cSoundCommand = NULL;
212 	if (g_file_test ("/usr/bin/paplay", G_FILE_TEST_EXISTS))
213 		cSoundCommand = g_strdup_printf("paplay --client-name=cairo-dock \"%s\"", cSoundPath);
214 
215 	else if (g_file_test ("/usr/bin/aplay", G_FILE_TEST_EXISTS))
216 		cSoundCommand = g_strdup_printf("aplay \"%s\"", cSoundPath);
217 
218 	else if (g_file_test ("/usr/bin/play", G_FILE_TEST_EXISTS))
219 		cSoundCommand = g_strdup_printf("play \"%s\"", cSoundPath);
220 
221 
222 	cairo_dock_launch_command (cSoundCommand);
223 
224 	g_free (cSoundCommand);
225 }
226 
227 // should be in gnome-integration if needed...
228 /*void cairo_dock_get_gnome_version (int *iMajor, int *iMinor, int *iMicro) {
229 	gchar *cContent = NULL;
230 	gsize length = 0;
231 	GError *erreur = NULL;
232 	g_file_get_contents ("/usr/share/gnome-about/gnome-version.xml", &cContent, &length, &erreur);
233 
234 	if (erreur != NULL) {
235 		cd_warning (erreur->message);
236 		g_error_free (erreur);
237 		erreur = NULL;
238 		*iMajor = 0;
239 		*iMinor = 0;
240 		*iMicro = 0;
241 		return;
242 	}
243 
244 	gchar **cLineList = g_strsplit (cContent, "\n", -1);
245 	gchar *cOneLine = NULL, *cMajor = NULL, *cMinor = NULL, *cMicro = NULL;
246 	int i, iMaj = 0, iMin = 0, iMic = 0;
247 	for (i = 0; cLineList[i] != NULL; i ++) {
248 		cOneLine = cLineList[i];
249 		if (*cOneLine == '\0')
250 			continue;
251 
252 		//Seeking for Major
253 		cMajor = g_strstr_len (cOneLine, -1, "<platform>");  //<platform>2</platform>
254 		if (cMajor != NULL) {
255 			cMajor += 10; //On saute <platform>
256 			gchar *str = strchr (cMajor, '<');
257 			if (str != NULL)
258 				*str = '\0'; //On bloque a </platform>
259 			iMaj = atoi (cMajor);
260 		}
261 		else { //Gutsy xml's doesn't have <platform> but <major>
262 			cMajor = g_strstr_len (cOneLine, -1, "<major>");  //<major>2</major>
263 			if (cMajor != NULL) {
264 				cMajor += 7; //On saute <major>
265 				gchar *str = strchr (cMajor, '<');
266 				if (str != NULL)
267 					*str = '\0'; //On bloque a </major>
268 				iMaj = atoi (cMajor);
269 			}
270 		}
271 
272 		//Seeking for Minor
273 		cMinor = g_strstr_len (cOneLine, -1, "<minor>");  //<minor>22</minor>
274 		if (cMinor != NULL) {
275 			cMinor += 7; //On saute <minor>
276 			gchar *str = strchr (cMinor, '<');
277 			if (str != NULL)
278 				*str = '\0'; //On bloque a </minor>
279 			iMin = atoi (cMinor);
280 		}
281 
282 		//Seeking for Micro
283 		cMicro = g_strstr_len (cOneLine, -1, "<micro>");  //<micro>3</micro>
284 		if (cMicro != NULL) {
285 			cMicro += 7; //On saute <micro>
286 			gchar *str = strchr (cMicro, '<');
287 			if (str != NULL)
288 				*str = '\0'; //On bloque a </micro>
289 			iMic = atoi (cMicro);
290 		}
291 
292 		if (iMaj != 0 && iMin != 0 && iMic != 0)
293 			break; //On s'enfou du reste
294 	}
295 
296 	cd_debug ("Gnome Version %d.%d.%d", iMaj, iMin, iMic);
297 
298 	*iMajor = iMaj;
299 	*iMinor = iMin;
300 	*iMicro = iMic;
301 
302 	g_free (cContent);
303 	g_strfreev (cLineList);
304 }*/
305 
cairo_dock_pop_up_about_applet(G_GNUC_UNUSED GtkMenuItem * menu_item,GldiModuleInstance * pModuleInstance)306 void cairo_dock_pop_up_about_applet (G_GNUC_UNUSED GtkMenuItem *menu_item, GldiModuleInstance *pModuleInstance)
307 {
308 	gldi_module_instance_popup_description (pModuleInstance);
309 }
310 
311 
cairo_dock_open_module_config_on_demand(int iClickedButton,G_GNUC_UNUSED GtkWidget * pInteractiveWidget,GldiModuleInstance * pModuleInstance,G_GNUC_UNUSED CairoDialog * pDialog)312 void cairo_dock_open_module_config_on_demand (int iClickedButton, G_GNUC_UNUSED GtkWidget *pInteractiveWidget, GldiModuleInstance *pModuleInstance, G_GNUC_UNUSED CairoDialog *pDialog)
313 {
314 	if (iClickedButton == 0 || iClickedButton == -1)  // bouton OK ou touche Entree.
315 	{
316 		cairo_dock_show_module_instance_gui (pModuleInstance, -1);
317 	}
318 }
319 
320 
cairo_dock_insert_icons_in_applet(GldiModuleInstance * pInstance,GList * pIconsList,const gchar * cDockRenderer,const gchar * cDeskletRenderer,gpointer pDeskletRendererData)321 void cairo_dock_insert_icons_in_applet (GldiModuleInstance *pInstance, GList *pIconsList, const gchar *cDockRenderer, const gchar *cDeskletRenderer, gpointer pDeskletRendererData)
322 {
323 	Icon *pIcon = pInstance->pIcon;
324 	g_return_if_fail (pIcon != NULL);
325 
326 	GldiContainer *pContainer = pInstance->pContainer;
327 	g_return_if_fail (pContainer != NULL);
328 
329 	if (pInstance->pDock)
330 	{
331 		if (pIcon->pSubDock == NULL)
332 		{
333 			if (pIcon->cName == NULL)
334 				gldi_icon_set_name (pIcon, pInstance->pModule->pVisitCard->cModuleName);
335 			if (cairo_dock_check_unique_subdock_name (pIcon))
336 				gldi_icon_set_name (pIcon, pIcon->cName);
337 			pIcon->pSubDock = gldi_subdock_new (pIcon->cName, cDockRenderer, pInstance->pDock, pIconsList);
338 			if (pIcon->pSubDock)
339 				pIcon->pSubDock->bPreventDraggingIcons = TRUE;  // par defaut pour toutes les applets on empeche de pouvoir deplacer/supprimer les icones a la souris.
340 		}
341 		else
342 		{
343 			Icon *pOneIcon;
344 			GList *ic;
345 			for (ic = pIconsList; ic != NULL; ic = ic->next)
346 			{
347 				pOneIcon = ic->data;
348 				gldi_icon_insert_in_container (pOneIcon, CAIRO_CONTAINER(pIcon->pSubDock), ! CAIRO_DOCK_ANIMATE_ICON);
349 			}
350 			g_list_free (pIconsList);
351 
352 			cairo_dock_set_renderer (pIcon->pSubDock, cDockRenderer);
353 			cairo_dock_update_dock_size (pIcon->pSubDock);
354 		}
355 
356 		if (pIcon->iSubdockViewType != 0)  // trigger the redraw after the icons are loaded.
357 			cairo_dock_trigger_redraw_subdock_content_on_icon (pIcon);
358 	}
359 	else if (pInstance->pDesklet)
360 	{
361 		Icon *pOneIcon;
362 		GList *ic;
363 		for (ic = pIconsList; ic != NULL; ic = ic->next)
364 		{
365 			pOneIcon = ic->data;
366 			cairo_dock_set_icon_container (pOneIcon, pInstance->pDesklet);
367 		}
368 		pInstance->pDesklet->icons = g_list_concat (pInstance->pDesklet->icons, pIconsList);  /// + sort icons and insert automatic separators...
369 		cairo_dock_set_desklet_renderer_by_name (pInstance->pDesklet, cDeskletRenderer, (CairoDeskletRendererConfigPtr) pDeskletRendererData);
370 		cairo_dock_redraw_container (pInstance->pContainer);
371 	}
372 }
373 
374 
cairo_dock_insert_icon_in_applet(GldiModuleInstance * pInstance,Icon * pOneIcon)375 void cairo_dock_insert_icon_in_applet (GldiModuleInstance *pInstance, Icon *pOneIcon)
376 {
377 	// get the container (create it if necessary)
378 	GldiContainer *pContainer = NULL;
379 	if (pInstance->pDock)
380 	{
381 		Icon *pIcon = pInstance->pIcon;
382 		if (pIcon->pSubDock == NULL)
383 		{
384 			if (pIcon->cName == NULL)
385 				gldi_icon_set_name (pIcon, pInstance->pModule->pVisitCard->cModuleName);
386 			if (cairo_dock_check_unique_subdock_name (pIcon))
387 				gldi_icon_set_name (pIcon, pIcon->cName);
388 			pIcon->pSubDock = gldi_subdock_new (pIcon->cName, NULL, pInstance->pDock, NULL);
389 			if (pIcon->pSubDock)
390 				pIcon->pSubDock->bPreventDraggingIcons = TRUE;  // par defaut pour toutes les applets on empeche de pouvoir deplacer/supprimer les icones a la souris.
391 		}
392 		pContainer = CAIRO_CONTAINER (pIcon->pSubDock);
393 	}
394 	else if (pInstance->pDesklet)
395 	{
396 		pContainer = CAIRO_CONTAINER (pInstance->pDesklet);
397 	}
398 	g_return_if_fail (pContainer != NULL);
399 
400 	// insert the icon inside
401 	gldi_icon_insert_in_container (pOneIcon, pContainer, ! CAIRO_DOCK_ANIMATE_ICON);
402 }
403 
404 
cairo_dock_remove_all_icons_from_applet(GldiModuleInstance * pInstance)405 void cairo_dock_remove_all_icons_from_applet (GldiModuleInstance *pInstance)
406 {
407 	Icon *pIcon = pInstance->pIcon;
408 	g_return_if_fail (pIcon != NULL);
409 
410 	GldiContainer *pContainer = pInstance->pContainer;
411 	g_return_if_fail (pContainer != NULL);
412 
413 	cd_debug ("%s (%s)", __func__, pInstance->pModule->pVisitCard->cModuleName);
414 	if (pInstance->pDesklet && pInstance->pDesklet->icons != NULL)
415 	{
416 		cd_debug (" destroy desklet icons");
417 		GList *icons = pInstance->pDesklet->icons;
418 		pInstance->pDesklet->icons = NULL;
419 		GList *ic;
420 		Icon *icon;
421 		for (ic = icons; ic != NULL; ic = ic->next)
422 		{
423 			icon = ic->data;
424 			cairo_dock_set_icon_container (icon, NULL);
425 			gldi_object_unref (GLDI_OBJECT(icon));
426 		}
427 		g_list_free (icons);
428 		cairo_dock_redraw_container (pInstance->pContainer);
429 	}
430 	if (pIcon->pSubDock != NULL)
431 	{
432 		if (pInstance->pDock)  // optimisation : on ne detruit pas le sous-dock.
433 		{
434 			cd_debug (" destroy sub-dock icons");
435 			GList *icons = pIcon->pSubDock->icons;
436 			pIcon->pSubDock->icons = NULL;
437 			GList *ic;
438 			Icon *icon;
439 			for (ic = icons; ic != NULL; ic = ic->next)
440 			{
441 				icon = ic->data;
442 				cairo_dock_set_icon_container (icon, NULL);
443 				gldi_object_unref (GLDI_OBJECT(icon));
444 			}
445 			g_list_free (icons);
446 		}
447 		else  // precaution pas chere
448 		{
449 			cd_debug (" destroy sub-dock");
450 			gldi_object_unref (GLDI_OBJECT(pIcon->pSubDock));
451 			pIcon->pSubDock = NULL;
452 		}
453 	}
454 }
455 
456 
cairo_dock_resize_applet(GldiModuleInstance * pInstance,int w,int h)457 void cairo_dock_resize_applet (GldiModuleInstance *pInstance, int w, int h)
458 {
459 	Icon *pIcon = pInstance->pIcon;
460 	g_return_if_fail (pIcon != NULL);
461 
462 	GldiContainer *pContainer = pInstance->pContainer;
463 	g_return_if_fail (pContainer != NULL);
464 
465 	if (pInstance->pDock)
466 	{
467 		cairo_dock_icon_set_requested_size (pIcon, w, h);
468 		cairo_dock_resize_icon_in_dock (pIcon, pInstance->pDock);
469 	}
470 	else  // in desklet mode, just resize the desklet, it will trigger the reload of the applet when the 'configure' event is received.
471 	{
472 		gtk_window_resize (GTK_WINDOW (pContainer->pWidget),
473 			w,
474 			h);  /// TODO: actually, the renderer should handle this, because except with the 'Simple' view, we can't know the actual size of the icon.
475 	}
476 }
477 
478