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 <stdlib.h>
21 #include <string.h>
22 #include <cairo-dock.h>  // include before to have 'HAVE_X11'
23 #ifdef HAVE_X11
24 #ifdef HAVE_XRANDR
25 #include <X11/Xlib.h>
26 #include <X11/extensions/Xrandr.h>
27 #include <gdk/gdkx.h>
28 #endif
29 #endif
30 
31 #include "applet-struct.h"
32 #include "applet-notifications.h"
33 
34 
_cd_allow_minimize(CairoDesklet * pDesklet,gpointer data)35 static gboolean _cd_allow_minimize (CairoDesklet *pDesklet, gpointer data)
36 {
37 	pDesklet->bAllowMinimize = TRUE;
38 	return FALSE;
39 }
40 
_cd_show_hide_desktop(gboolean bShowDesklets)41 static void _cd_show_hide_desktop (gboolean bShowDesklets)
42 {
43 	if (! myData.bDesktopVisible && ! bShowDesklets)  // on autorise chaque desklet a etre minimise. l'autorisation est annulee lors de leur cachage, donc on n'a pas besoin de faire le contraire apres avoir montre le bureau.
44 	{
45 		gldi_desklets_foreach ((GldiDeskletForeachFunc) _cd_allow_minimize, NULL);
46 	}
47 
48 	gldi_desktop_show_hide (! myData.bDesktopVisible);
49 }
50 
_cd_show_hide_desklet(void)51 static void _cd_show_hide_desklet (void)
52 {
53 	if (!myData.bDeskletsVisible)
54 	{
55 		myData.pLastActiveWindow = gldi_windows_get_active ();
56 		gldi_object_ref (GLDI_OBJECT(myData.pLastActiveWindow));
57 		gldi_desklets_set_visible (TRUE);  // TRUE <=> les desklets de la couche widget aussi.
58 	}
59 	else
60 	{
61 		gldi_desklets_set_visibility_to_default ();
62 		if (myData.pLastActiveWindow)
63 		{
64 			gldi_window_show (myData.pLastActiveWindow);
65 			gldi_object_unref (GLDI_OBJECT(myData.pLastActiveWindow));
66 			myData.pLastActiveWindow = NULL;
67 		}
68 	}
69 	myData.bDeskletsVisible = ! myData.bDeskletsVisible;
70 
71 	if (myConfig.cVisibleImage)
72 	{
73 		if (myData.bDesktopVisible || myData.bDeskletsVisible)
74 			CD_APPLET_SET_IMAGE_ON_MY_ICON (myConfig.cVisibleImage);
75 		else
76 			CD_APPLET_SET_IMAGE_ON_MY_ICON (myConfig.cHiddenImage);
77 	}
78 }
79 
80 
_cd_show_widget_layer(void)81 static void _cd_show_widget_layer (void)
82 {
83 	gldi_desktop_show_widget_layer ();
84 }
85 
_cd_expose(void)86 static void _cd_expose (void)
87 {
88 	gldi_desktop_present_desktops ();
89 }
_expose_delayed(G_GNUC_UNUSED gpointer data)90 static gboolean _expose_delayed (G_GNUC_UNUSED gpointer data)
91 {
92 	_cd_expose ();
93 	return FALSE;
94 }
_cd_action(CDActionOnClick iAction)95 static void _cd_action (CDActionOnClick iAction)
96 {
97 	switch (iAction)
98 	{
99 		case CD_SHOW_DESKTOP :
100 			_cd_show_hide_desktop (FALSE);
101 		break ;
102 		case CD_SHOW_DESKLETS :
103 			_cd_show_hide_desklet ();
104 		break ;
105 		case CD_SHOW_DESKTOP_AND_DESKLETS :
106 			_cd_show_hide_desktop (TRUE);  // TRUE <=> show the desklets
107 		break ;
108 		case CD_SHOW_WIDGET_LAYER :
109 			if (gldi_desktop_can_show_widget_layer ())
110 				_cd_show_widget_layer ();
111 			else
112 			{
113 				cd_warning ("It seems there is no widget layer, we show/hide the desktop");
114 				_cd_show_hide_desktop (FALSE);
115 			}
116 		break ;
117 		case CD_EXPOSE :
118 			if (gldi_desktop_can_present_desktops ())
119 			{
120 				g_timeout_add (250, _expose_delayed, NULL);  // Gnome-Shell bug here: it doesn't execute the Dbus command right after a click; I suspect the delay to be the interval of a double-click... anyway, it's stupid but it's barely noticeable, so it doesn't hurt that much even when not using GS.
121 			}
122 			else
123 			{
124 				cd_warning ("It seems we can't present desktops, we show/hide the desktop");
125 				_cd_show_hide_desktop (FALSE);
126 			}
127 		break ;
128 		default:
129 		break;
130 	}
131 }
132 
133 //\___________ Define here the action to be taken when the user left-clicks on your icon or on its subdock or your desklet. The icon and the container that were clicked are available through the macros CD_APPLET_CLICKED_ICON and CD_APPLET_CLICKED_CONTAINER. CD_APPLET_CLICKED_ICON may be NULL if the user clicked in the container but out of icons.
134 CD_APPLET_ON_CLICK_BEGIN
135 	_cd_action (myConfig.iActionOnLeftClick);
136 CD_APPLET_ON_CLICK_END
137 
138 
139 //\___________ Define here the entries you want to add to the menu when the user right-clicks on your icon or on its subdock or your desklet. The icon and the container that were clicked are available through the macros CD_APPLET_CLICKED_ICON and CD_APPLET_CLICKED_CONTAINER. CD_APPLET_CLICKED_ICON may be NULL if the user clicked in the container but out of icons. The menu where you can add your entries is available throught the macro CD_APPLET_MY_MENU; you can add sub-menu to it if you want.
140 #ifdef HAVE_X11
141 #ifdef HAVE_XRANDR
_on_select_resolution(GtkMenuItem * menu_item,gpointer data)142 static void _on_select_resolution (GtkMenuItem *menu_item, gpointer data)  /// TODO: put that in the core...
143 {
144 	CD_APPLET_ENTER;
145 	int 				    iNumRes = GPOINTER_TO_INT (data);
146 	Display                 *dpy;
147 	Window                  root;
148 	XRRScreenConfiguration  *conf;
149 	short                   *rates;
150 	int                     num_rates;
151 	dpy = gdk_x11_get_default_xdisplay ();
152 	root = RootWindow(dpy, 0);
153 
154 	conf = XRRGetScreenInfo(dpy, root);
155 	CD_APPLET_LEAVE_IF_FAIL (conf != NULL);
156 	//g_return_if_fail (conf != NULL);
157 
158 	rates = XRRRates(dpy, 0, iNumRes, &num_rates);
159 	CD_APPLET_LEAVE_IF_FAIL (num_rates > 0);
160 	//g_return_if_fail (num_rates > 0);
161 	cd_debug ("available rates : from %d to %d Hz", rates[0], rates[num_rates-1]);
162 
163 	XRRSetScreenConfigAndRate(dpy, conf, root, iNumRes, RR_Rotate_0, rates[num_rates-1], CurrentTime);
164 	XRRFreeScreenConfigInfo (conf);
165 
166 	// restore original conf :  XRRSetScreenConfigAndRate(dpy, conf, root, original_size_id, original_rotation, original_rate, CurrentTime);
167 	CD_APPLET_LEAVE();
168 }
169 #endif
170 #endif
_show_desktop(GtkMenuItem * menu_item,gpointer data)171 static void _show_desktop (GtkMenuItem *menu_item, gpointer data)
172 {
173 	_cd_show_hide_desktop (FALSE);
174 }
175 CD_APPLET_ON_BUILD_MENU_BEGIN
176 	gchar *cLabel;
177 
178 	if (myConfig.iActionOnLeftClick != CD_SHOW_DESKTOP)  // action is not bound to left-click => put it in the menu
179 	{
180 		if (myConfig.iActionOnMiddleClick == CD_SHOW_DESKTOP)
181 			cLabel = g_strdup_printf ("%s (%s)", D_("Show desktop"), D_("middle-click"));
182 		else
183 			cLabel = g_strdup (D_("Show desktop"));
184 		CD_APPLET_ADD_IN_MENU_WITH_STOCK (cLabel,
185 			MY_APPLET_SHARE_DATA_DIR"/../shared-files/images/show-desktop.svg",
186 			_show_desktop,
187 			CD_APPLET_MY_MENU);
188 		g_free (cLabel);
189 	}
190 	if (myConfig.iActionOnLeftClick != CD_EXPOSE && gldi_desktop_can_present_desktops ())  // action is not bound to left-click => put it in the menu
191 	{
192 		if (myConfig.iActionOnMiddleClick == CD_EXPOSE)
193 			cLabel = g_strdup_printf ("%s (%s)", D_("Expose all the desktops"), D_("middle-click"));
194 		else
195 			cLabel = g_strdup (D_("Expose all the desktops"));
196 		CD_APPLET_ADD_IN_MENU_WITH_STOCK (cLabel,
197 			MY_APPLET_SHARE_DATA_DIR"/../shared-files/images/expose-desktops.svg",
198 			_cd_expose,
199 			CD_APPLET_MY_MENU);
200 		g_free (cLabel);
201 	}
202 	if (myConfig.iActionOnLeftClick != CD_SHOW_WIDGET_LAYER && gldi_desktop_can_show_widget_layer ())  // action is not bound to left-click => put it in the menu
203 	{
204 		if (myConfig.iActionOnMiddleClick == CD_SHOW_WIDGET_LAYER)
205 			cLabel = g_strdup_printf ("%s (%s)", D_("Show the Widget Layer"), D_("middle-click"));
206 		else
207 			cLabel = g_strdup (D_("Show the Widget Layer"));
208 		CD_APPLET_ADD_IN_MENU_WITH_STOCK (cLabel,
209 			MY_APPLET_SHARE_DATA_DIR"/../shared-files/images/widget-layer.svg",
210 		_cd_show_widget_layer,
211 		CD_APPLET_MY_MENU);
212 		g_free (cLabel);
213 	}  // on ne met pas les actions sur les desklets, surement assez peu utilisees.
214 
215 	// Main Menu
216 	#ifdef HAVE_X11
217 	#ifdef HAVE_XRANDR
218 	if (cairo_dock_check_xrandr (1, 1))
219 	{
220 		GtkWidget *pResSubMenu = CD_APPLET_ADD_SUB_MENU_WITH_IMAGE (D_("Change screen resolution"), CD_APPLET_MY_MENU, GLDI_ICON_NAME_FULLSCREEN);
221 
222 		Display                 *dpy;
223 		Window                  root;
224 		XRRScreenConfiguration  *conf;
225 		Rotation                original_rotation;
226 		SizeID                  original_size_id;
227 
228 		dpy = gdk_x11_get_default_xdisplay ();
229 		root = RootWindow(dpy, 0);
230 
231 		conf = XRRGetScreenInfo(dpy, root);  // config  courante.
232 		if (conf != NULL)
233 		{
234 			//original_rate = XRRConfigCurrentRate(conf);
235 			original_size_id = XRRConfigCurrentConfiguration(conf, &original_rotation);
236 
237 			// resolutions possibles.
238 			int num_sizes = 0;
239 			XRRScreenSize *xrrs = XRRSizes(dpy, 0, &num_sizes);
240 			// add to the menu
241 			GString *pResString = g_string_new ("");
242 			int i;
243 			for (i = 0; i < num_sizes; i ++)
244 			{
245 				g_string_printf (pResString, "%dx%d", xrrs[i].width, xrrs[i].height);
246 				if (i == original_size_id)
247 					CD_APPLET_ADD_IN_MENU_WITH_STOCK_AND_DATA (pResString->str, GLDI_ICON_NAME_GO_FORWARD, _on_select_resolution, pResSubMenu, GINT_TO_POINTER (i));
248 				else
249 					CD_APPLET_ADD_IN_MENU_WITH_DATA (pResString->str, _on_select_resolution, pResSubMenu, GINT_TO_POINTER (i));
250 				/*short   *rates;
251 				int     num_rates;
252 				rates = XRRRates(dpy, 0, i, &num_rates);
253 				for(int j = 0; j < num_rates; j ++) {
254 					possible_frequencies[i][j] = rates[j];
255 					printf("%4i ", rates[j]); }*/
256 			}
257 			g_string_free (pResString, TRUE);
258 			XRRFreeScreenConfigInfo (conf);
259 		}
260 	}
261 	else
262 		cd_warning ("Xrandr extension not available.");
263 	#endif
264 	#endif
265 CD_APPLET_ON_BUILD_MENU_END
266 
267 
268 CD_APPLET_ON_MIDDLE_CLICK_BEGIN
269 	_cd_action (myConfig.iActionOnMiddleClick);
270 CD_APPLET_ON_MIDDLE_CLICK_END
271 
272 
_get_desktop_path(void)273 static gchar *_get_desktop_path (void)
274 {
275 	gchar *cDesktopDir = cairo_dock_launch_command_sync ("xdg-user-dir DESKTOP");
276 	if (cDesktopDir == NULL)
277 		cDesktopDir = g_strdup_printf ("%s/Desktop", g_getenv ("HOME"));
278 	return cDesktopDir;
279 }
_move_to_desktop(GtkMenuItem * menu_item,GldiModuleInstance * myApplet)280 static void _move_to_desktop (GtkMenuItem *menu_item, GldiModuleInstance *myApplet)
281 {
282 	gchar *cDesktopDir = _get_desktop_path ();
283 	if (cDesktopDir != NULL)
284 	{
285 		cairo_dock_launch_command_printf ("mv \"%s\" \"%s\"", NULL, myData.cPendingFile, cDesktopDir);
286 		g_free (cDesktopDir);
287 	}
288 }
_copy_to_desktop(GtkMenuItem * menu_item,GldiModuleInstance * myApplet)289 static void _copy_to_desktop (GtkMenuItem *menu_item, GldiModuleInstance *myApplet)
290 {
291 	gchar *cDesktopDir = _get_desktop_path ();
292 	if (cDesktopDir != NULL)
293 	{
294 		cairo_dock_launch_command_printf ("cp -r \"%s\" \"%s\"", NULL, myData.cPendingFile, cDesktopDir);
295 		g_free (cDesktopDir);
296 	}
297 }
_link_to_desktop(GtkMenuItem * menu_item,GldiModuleInstance * myApplet)298 static void _link_to_desktop (GtkMenuItem *menu_item, GldiModuleInstance *myApplet)
299 {
300 	gchar *cDesktopDir = _get_desktop_path ();
301 	if (cDesktopDir != NULL)
302 	{
303 		cairo_dock_launch_command_printf ("ln -s \"%s\" \"%s\"", NULL, myData.cPendingFile, cDesktopDir);
304 		g_free (cDesktopDir);
305 	}
306 }
_make_link_to_desktop(GtkMenuItem * menu_item,GldiModuleInstance * myApplet)307 static void _make_link_to_desktop (GtkMenuItem *menu_item, GldiModuleInstance *myApplet)
308 {
309 	gchar *cDesktopDir = _get_desktop_path ();
310 	if (cDesktopDir != NULL)
311 	{
312 		gchar *cName = g_path_get_basename (myData.cPendingFile);
313 		gchar *cContent = g_strdup_printf ("[Desktop Entry]\n"
314 			"Encoding=UTF-8\n"
315 			"Name=%s\n"
316 			"URL=%s\n"
317 			"Icon=file\n"
318 			"Type=Link\n",
319 			cName, myData.cPendingFile);
320 
321 		gchar *cLinkPath = g_strdup_printf ("%s/Link to %s", cDesktopDir, cName);
322 		g_file_set_contents (cLinkPath,
323 			cContent,
324 			-1,
325 			NULL);
326 
327 		g_free (cLinkPath);
328 		g_free (cContent);
329 		g_free (cName);
330 		g_free (cDesktopDir);
331 	}
332 }
_dl_finished(gpointer data)333 static void _dl_finished (gpointer data)
334 {
335 	cd_debug ("DL IS FINISHED");
336 }
_download_to_desktop(GtkMenuItem * menu_item,GldiModuleInstance * myApplet)337 static void _download_to_desktop (GtkMenuItem *menu_item, GldiModuleInstance *myApplet)
338 {
339 	gchar *cDesktopDir = _get_desktop_path ();
340 	if (cDesktopDir != NULL)
341 	{
342 		cairo_dock_download_file_async (myData.cPendingFile, NULL, (GFunc)_dl_finished, myApplet);
343 		g_free (cDesktopDir);
344 	}
345 }
346 
347 CD_APPLET_ON_DROP_DATA_BEGIN
348 	GtkWidget *pMenu = gldi_menu_new (myIcon);
349 	g_free (myData.cPendingFile);
350 	myData.cPendingFile = g_strdup (CD_APPLET_RECEIVED_DATA);
351 
352 	if (*CD_APPLET_RECEIVED_DATA == '/' || strncmp (CD_APPLET_RECEIVED_DATA, "file://", 7))  // fichier local
353 	{
354 		cairo_dock_add_in_menu_with_stock_and_data (("Move to the Desktop"), GLDI_ICON_NAME_CUT, G_CALLBACK (_move_to_desktop), pMenu, myApplet);
355 		cairo_dock_add_in_menu_with_stock_and_data (("Copy to the Desktop"), GLDI_ICON_NAME_COPY, G_CALLBACK (_copy_to_desktop), pMenu, myApplet);
356 		cairo_dock_add_in_menu_with_stock_and_data (("Link to the Desktop"), GLDI_ICON_NAME_JUMP_TO, G_CALLBACK (_link_to_desktop), pMenu, myApplet);
357 	}
358 	else  // fichier a telecharger.
359 	{
360 		cairo_dock_add_in_menu_with_stock_and_data (("Link to the Desktop"), GLDI_ICON_NAME_JUMP_TO, G_CALLBACK (_make_link_to_desktop), pMenu, myApplet);
361 		cairo_dock_add_in_menu_with_stock_and_data (("Download onto the Desktop"), GLDI_ICON_NAME_COPY, G_CALLBACK (_download_to_desktop), pMenu, myApplet);
362 	}
363 	CD_APPLET_POPUP_MENU_ON_MY_ICON (pMenu);
364 
365 
366 CD_APPLET_ON_DROP_DATA_END
367 
368 
on_keybinding_pull(const char * keystring,gpointer user_data)369 void on_keybinding_pull (const char *keystring, gpointer user_data)
370 {
371 	CD_APPLET_ENTER;
372 	_cd_action (myConfig.iActionOnMiddleClick);
373 	CD_APPLET_LEAVE();
374 }
375 
376 
on_show_desktop(GldiModuleInstance * myApplet)377 gboolean on_show_desktop (GldiModuleInstance *myApplet)
378 {
379 	CD_APPLET_ENTER;
380 	myData.bDesktopVisible = gldi_desktop_is_visible ();
381 	cd_debug ("bDesktopVisible <- %d", myData.bDesktopVisible);
382 
383 	if (myConfig.cVisibleImage)
384 	{
385 		if (myData.bDesktopVisible || myData.bDeskletsVisible)
386 			CD_APPLET_SET_IMAGE_ON_MY_ICON (myConfig.cVisibleImage);
387 		else
388 			CD_APPLET_SET_IMAGE_ON_MY_ICON (myConfig.cHiddenImage);
389 		CD_APPLET_REDRAW_MY_ICON;
390 	}
391 	CD_APPLET_LEAVE (GLDI_NOTIFICATION_LET_PASS);
392 }
393