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 
23 #include "applet-struct.h"
24 #include "applet-composite.h"
25 
26 static void (*s_activate_composite) (gboolean) = NULL;
27 
28   /////////////////////
29  ///  WM Composite ///
30 /////////////////////
31 
_set_metacity_composite(gboolean bActive)32 static void _set_metacity_composite (gboolean bActive)
33 {
34 	int r;
35 	if (bActive)
36 		r = system ("if test -n \"`dconf read /org/gnome/metacity/compositing-manager`\"; then dconf write /org/gnome/metacity/compositing-manager true; metacity --replace& else gconftool-2 -s '/apps/metacity/general/compositing_manager' --type bool true; fi");  // metacity's new feature : now uses Dconf and crashes after activating the composite
37 	else
38 		r = system ("if test -n \"`dconf read /org/gnome/metacity/compositing-manager`\"; then dconf write /org/gnome/metacity/compositing-manager false; metacity --replace& else gconftool-2 -s '/apps/metacity/general/compositing_manager' --type bool false; fi");
39 	if (r < 0)
40 		cd_warning ("Not able to launch this command: gconftool-2");
41 }
42 
_set_xfwm_composite(gboolean bActive)43 static void _set_xfwm_composite (gboolean bActive)
44 {
45 	int r;
46 	if (bActive)
47 		r = system ("xfconf-query -c xfwm4 -p '/general/use_compositing' -t 'bool' -s 'true'");
48 	else
49 		r = system ("xfconf-query -c xfwm4 -p '/general/use_compositing' -t 'bool' -s 'false'");
50 	if (r < 0)
51 		cd_warning ("Not able to launch this command: gconftool-2");
52 }
53 
_set_kwin_composite(gboolean bActive)54 static void _set_kwin_composite (gboolean bActive)
55 {
56 	int r;
57 	if (bActive)
58 		r = system ("[ \"$(qdbus org.kde.kwin /KWin compositingActive)\" == \"false\" ] && qdbus org.kde.kwin /KWin toggleCompositing");  // not active, so activating
59 	else
60 		r = system ("[ \"$(qdbus org.kde.kwin /KWin compositingActive)\" == \"true\" ] && qdbus org.kde.kwin /KWin toggleCompositing");  // active, so deactivating
61 	if (r < 0)
62 		cd_warning ("Not able to launch this command: gconftool-2");
63 }
64 
65   ///////////////////////
66  /// Welcome message ///
67 ///////////////////////
68 
cd_help_show_welcome_message(void)69 static void cd_help_show_welcome_message (void)
70 {
71 	gldi_dialog_show (D_("Welcome in Cairo-Dock !\n"
72 		"This applet is here to help you start using the dock; just click on it.\n"
73 		"If you have any question/request/remark, please pay us a visit at http://glx-dock.org.\n"
74 		"Hope you will enjoy this soft !\n"
75 		"  (you can now click on this dialog to close it)"),
76 		myIcon, myContainer,
77 		0,
78 		"same icon",
79 		NULL, NULL, NULL, NULL);
80 	myData.bFirstLaunch = FALSE;
81 }
82 
83   ////////////////////////
84  /// Composite dialog ///
85 ////////////////////////
86 
_cancel_wm_composite(void)87 static inline void _cancel_wm_composite (void)
88 {
89 	s_activate_composite (FALSE);
90 }
_accept_wm_composite(int iClickedButton,G_GNUC_UNUSED GtkWidget * pInteractiveWidget,gpointer data,G_GNUC_UNUSED CairoDialog * pDialog)91 static void _accept_wm_composite (int iClickedButton, G_GNUC_UNUSED GtkWidget *pInteractiveWidget, gpointer data, G_GNUC_UNUSED CairoDialog *pDialog)
92 {
93 	cd_debug ("%s (%d)", __func__, iClickedButton);
94 	if (iClickedButton == 1 || iClickedButton == -2)  // clic explicite sur "cancel", ou Echap ou auto-delete.
95 	{
96 		_cancel_wm_composite ();
97 	}
98 	gboolean *bAccepted = data;
99 	*bAccepted = TRUE;  // l'utilisateur a valide son choix.
100 }
_on_free_wm_dialog(gpointer data)101 static void _on_free_wm_dialog (gpointer data)
102 {
103 	gboolean *bAccepted = data;
104 	cd_debug ("%s (%d)", __func__, *bAccepted);
105 	if (! *bAccepted)  // le dialogue s'est detruit sans que l'utilisateur n'ait valide la question => on annule tout.
106 	{
107 		_cancel_wm_composite ();
108 	}
109 	g_free (data);
110 
111 	if (myData.bFirstLaunch)
112 	{
113 		cd_help_show_welcome_message ();
114 	}
115 }
116 
_toggle_remember_choice(GtkCheckButton * pButton,GtkWidget * pDialog)117 static void _toggle_remember_choice (GtkCheckButton *pButton, GtkWidget *pDialog)
118 {
119 	g_object_set_data (G_OBJECT (pDialog), "remember", GINT_TO_POINTER (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (pButton))));
120 }
121 
_on_free_info_dialog(G_GNUC_UNUSED gpointer data)122 static void _on_free_info_dialog (G_GNUC_UNUSED gpointer data)
123 {
124 	if (myData.bFirstLaunch)
125 	{
126 		cd_help_show_welcome_message ();
127 	}
128 }
129 
130   ///////////////////////
131  /// Check composite ///
132 ///////////////////////
133 
cd_help_enable_composite(void)134 void cd_help_enable_composite (void)
135 {
136 	// find the current WM.
137 	s_activate_composite = NULL;
138 	gchar *cPsef = cairo_dock_launch_command_sync ("pgrep metacity");  // 'ps | grep' ne marche pas, il faut le lancer dans un script :-/
139 	cd_debug ("cPsef: '%s'", cPsef);
140 	if (cPsef != NULL && *cPsef != '\0')
141 	{
142 		s_activate_composite = _set_metacity_composite;
143 	}
144 	else
145 	{
146 		cPsef = cairo_dock_launch_command_sync ("pgrep xfwm");
147 		if (cPsef != NULL && *cPsef != '\0')
148 		{
149 			s_activate_composite = _set_xfwm_composite;
150 		}
151 		else
152 		{
153 			cPsef = cairo_dock_launch_command_sync ("pgrep kwin");
154 			if (cPsef != NULL && *cPsef != '\0')
155 			{
156 				s_activate_composite = _set_kwin_composite;
157 			}
158 		}
159 	}
160 
161 	// if the WM can handle the composite, ask the user if he wants to enable it.
162 	if (s_activate_composite != NULL)  // the WM can activate the composite.
163 	{
164 		GtkWidget *pAskBox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 3);
165 		GtkWidget *label = gtk_label_new (D_("Don't ask me any more"));
166 		gldi_dialog_set_widget_text_color (label);
167 		GtkWidget *pCheckBox = gtk_check_button_new ();
168 		gtk_box_pack_end (GTK_BOX (pAskBox), pCheckBox, FALSE, FALSE, 0);
169 		gtk_box_pack_end (GTK_BOX (pAskBox), label, FALSE, FALSE, 0);
170 		g_signal_connect (G_OBJECT (pCheckBox), "toggled", G_CALLBACK(_toggle_remember_choice), pAskBox);
171 		int iClickedButton = gldi_dialog_show_and_wait (D_("To remove the black rectangle around the dock, you need to activate a composite manager.\nDo you want to activate it now?"), myIcon, myContainer, NULL, pAskBox);
172 
173 		gboolean bRememberChoice = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (pCheckBox));
174 		gtk_widget_destroy (pAskBox);  // le widget survit a un dialogue bloquant.
175 		if (bRememberChoice)  // if not ticked, we'll check the composite on the next startup, and if it's ok, we'll not check it any more.
176 		{
177 			myData.bTestComposite = FALSE;
178 		}
179 		if (iClickedButton == 0 || iClickedButton == -1)  // ok or Enter.
180 		{
181 			s_activate_composite (TRUE);
182 			gldi_dialog_show (D_("Do you want to keep this setting?\nIn 15 seconds, the previous setting will be restored."),
183 				myIcon, myContainer,
184 				15e3,
185 				"same icon",
186 				NULL,
187 				(CairoDockActionOnAnswerFunc) _accept_wm_composite,
188 				g_new0 (gboolean, 1),
189 				(GFreeFunc)_on_free_wm_dialog);
190 		}
191 		else if (myData.bFirstLaunch)
192 		{
193 			cd_help_show_welcome_message ();
194 		}
195 	}
196 	else  // just notify him about the problem and its solution.
197 	{
198 		gldi_dialog_show (D_("To remove the black rectangle around the dock, you will need to activate a composite manager.\nFor instance, this can be done by activating desktop effects, launching Compiz, or activating the composition in Metacity.\nIf your machine can't support composition, Cairo-Dock can emulate it. This option is in the 'System' module of the configuration, at the bottom of the page."),
199 			myIcon, myContainer,
200 			0,
201 			"same icon",
202 			NULL,
203 			NULL,
204 			NULL,
205 			(GFreeFunc)_on_free_info_dialog);
206 	}
207 	g_free (cPsef);
208 }
209 
cd_help_check_composite(G_GNUC_UNUSED gpointer data)210 static gboolean cd_help_check_composite (G_GNUC_UNUSED gpointer data)
211 {
212 	GdkScreen *pScreen = gdk_screen_get_default ();
213 	if (! gdk_screen_is_composited (pScreen))  // no composite yet.
214 	{
215 		cd_debug ("no composite (%d)", myData.iNbTestComposite);
216 		myData.iNbTestComposite ++;
217 		if (myData.iNbTestComposite < 4)  // check during 4 seconds.
218 			return TRUE;
219 
220 		cd_help_enable_composite ();
221 	}
222 	else  // composite is active, but we don't remember this parameter, since it could change if another session is used one day.
223 	{
224 		if (myData.bFirstLaunch)
225 		{
226 			cd_help_show_welcome_message ();
227 		}
228 	}
229 
230 	// remember if we don't need to check the composite any more.
231 	if (! myData.bTestComposite)
232 	{
233 		gchar *cConfFilePath = g_strdup_printf ("%s/.help", g_cCairoDockDataDir);
234 		cairo_dock_update_conf_file (cConfFilePath,
235 			G_TYPE_BOOLEAN, "Launch", "test composite", myData.bTestComposite,
236 			G_TYPE_INVALID);
237 		g_free (cConfFilePath);
238 	}
239 	myData.iSidTestComposite = 0;
240 	return FALSE;
241 }
242 
cd_help_get_params(G_GNUC_UNUSED gpointer data)243 gboolean cd_help_get_params (G_GNUC_UNUSED gpointer data)
244 {
245 	// read our file.
246 	gchar *cConfFilePath = g_strdup_printf ("%s/.help", g_cCairoDockDataDir);
247 	if (g_file_test (cConfFilePath, G_FILE_TEST_EXISTS))  // file already exists, get the latest state.
248 	{
249 		GKeyFile *pKeyFile = cairo_dock_open_key_file (cConfFilePath);
250 		if (pKeyFile != NULL)
251 		{
252 			myData.iLastTipGroup = g_key_file_get_integer (pKeyFile, "Last Tip", "group", NULL);
253 			myData.iLastTipKey = g_key_file_get_integer (pKeyFile, "Last Tip", "key", NULL);
254 			myData.bTestComposite = g_key_file_get_boolean (pKeyFile, "Launch", "test composite", NULL);
255 
256 			g_key_file_free (pKeyFile);
257 		}
258 	}
259 	else  // no file, means it's the first time we are launched.
260 	{
261 		myData.bFirstLaunch = TRUE;
262 		myData.bTestComposite = TRUE;
263 
264 		// create the file with all the entries
265 		cairo_dock_update_conf_file (cConfFilePath,
266 			G_TYPE_BOOLEAN, "Launch", "test composite", myData.bTestComposite,
267 			G_TYPE_INT, "Last Tip", "group", myData.iLastTipGroup,
268 			G_TYPE_INT, "Last Tip", "key", myData.iLastTipKey,
269 			G_TYPE_INVALID);
270 	}
271 
272 	// test the composite in a few seconds (the Composite Manager may not be active yet).
273 	if (myData.bTestComposite/** && ! myContainersParam.bUseFakeTransparency*/)
274 	{
275 		myData.iSidTestComposite = g_timeout_add_seconds (2, cd_help_check_composite, NULL);
276 	}
277 	else if (myData.bFirstLaunch)
278 	{
279 		cd_help_show_welcome_message ();
280 	}
281 
282 	g_free (cConfFilePath);
283 	myData.iSidGetParams = 0;
284 	return FALSE;
285 }
286