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 <gdk/gdkx.h>  // gldi_container_present
24 
25 #include "applet-struct.h"
26 #include "applet-search.h"
27 #include "applet-listing.h"
28 #include "applet-notifications.h"
29 #include "applet-session.h"
30 
31 
cd_do_open_session(void)32 void cd_do_open_session (void)
33 {
34 	if (cd_do_session_is_running ())  // session already running
35 		return;
36 
37 	// on termine la precedente session.
38 	cd_do_exit_session ();
39 	cd_do_stop_all_backends ();  // on le fait maintenant pour ne pas bloquer au exit.
40 
41 	// register to draw on dock.
42 	if (cd_do_session_is_off ())
43 	{
44 		gldi_object_register_notification (g_pMainDock,
45 			NOTIFICATION_UPDATE,
46 			(GldiNotificationFunc) cd_do_update_container,
47 			GLDI_RUN_AFTER, NULL);
48 		gldi_object_register_notification (g_pMainDock,
49 			NOTIFICATION_RENDER,
50 			(GldiNotificationFunc) cd_do_render,
51 			GLDI_RUN_AFTER, NULL);
52 	}
53 
54 	// wait for keyboard input.
55 	gldi_object_register_notification (&myContainerObjectMgr,
56 		NOTIFICATION_KEY_PRESSED,
57 		(GldiNotificationFunc) cd_do_key_pressed,
58 		GLDI_RUN_AFTER, NULL);
59 	gldi_object_register_notification (&myWindowObjectMgr,
60 		NOTIFICATION_WINDOW_ACTIVATED,
61 		(GldiNotificationFunc) cd_do_check_active_dock,
62 		GLDI_RUN_AFTER, NULL);
63 
64 	myData.sCurrentText = g_string_sized_new (20);
65 	myConfig.labelDescription.iSize = myConfig.fFontSizeRatio * g_pMainDock->iMaxDockHeight;
66 	myData.iPromptAnimationCount = 0;
67 	if (myData.pPromptSurface == NULL)
68 	{
69 		cairo_t *pCairoContext = cairo_dock_create_drawing_context_generic (CAIRO_CONTAINER (g_pMainDock));
70 		myData.pPromptSurface = cairo_dock_create_surface_from_text (D_("Enter your search"), &myConfig.labelDescription, &myData.iPromptWidth, &myData.iPromptHeight);
71 		cairo_destroy (pCairoContext);
72 		if (g_bUseOpenGL)
73 		{
74 			myData.iPromptTexture = cairo_dock_create_texture_from_surface (myData.pPromptSurface);
75 		}
76 	}
77 
78 	// on montre le main dock.
79 	cairo_dock_emit_enter_signal (CAIRO_CONTAINER (g_pMainDock));
80 
81 	// le main dock prend le focus.
82 	gldi_container_present (CAIRO_CONTAINER (g_pMainDock));
83 	cairo_dock_freeze_docks (TRUE);
84 
85 	// On lance l'animation d'attente.
86 	cairo_dock_launch_animation (CAIRO_CONTAINER (g_pMainDock));
87 
88 	myData.iSessionState = 2;
89 }
90 
cd_do_close_session(void)91 void cd_do_close_session (void)
92 {
93 	if (! cd_do_session_is_running ())  // session not running
94 		return;
95 
96 	// no more keyboard input.
97 	gldi_object_remove_notification (&myContainerObjectMgr,
98 		NOTIFICATION_KEY_PRESSED,
99 		(GldiNotificationFunc) cd_do_key_pressed, NULL);
100 	gldi_object_remove_notification (&myWindowObjectMgr,
101 		NOTIFICATION_WINDOW_ACTIVATED,
102 		(GldiNotificationFunc) cd_do_check_active_dock, NULL);
103 
104 	g_string_free (myData.sCurrentText, TRUE);
105 	myData.sCurrentText = NULL;
106 	myData.iNbValidCaracters = 0;
107 
108 	// on cache les resultats
109 	cd_do_hide_listing ();
110 
111 	g_free (myData.cSearchText);
112 	myData.cSearchText = NULL;
113 	myData.iCurrentFilter = 0;
114 
115 	cairo_dock_emit_leave_signal (CAIRO_CONTAINER (g_pMainDock));
116 
117 	// on quitte dans une animation.
118 	myData.iCloseTime = myConfig.iCloseDuration;
119 	cairo_dock_launch_animation (CAIRO_CONTAINER (g_pMainDock));
120 	cairo_dock_freeze_docks (FALSE);
121 
122 	myData.iSessionState = 1;
123 }
124 
cd_do_exit_session(void)125 void cd_do_exit_session (void)
126 {
127 	if (cd_do_session_is_off ())  // session already off
128 		return;
129 
130 
131 	cd_do_close_session ();
132 
133 	myData.iCloseTime = 0;
134 
135 	gldi_object_remove_notification (g_pMainDock, NOTIFICATION_RENDER, (GldiNotificationFunc) cd_do_render, NULL);
136 	gldi_object_remove_notification (g_pMainDock, NOTIFICATION_UPDATE, (GldiNotificationFunc) cd_do_update_container, NULL);
137 
138 	/// arreter les backends...
139 
140 
141 	if (myData.pCharList != NULL)
142 	{
143 		cd_do_free_char_list (myData.pCharList);
144 		myData.pCharList = NULL;
145 		myData.iTextWidth = 0;
146 		myData.iTextHeight = 0;
147 		cairo_dock_redraw_container (CAIRO_CONTAINER (g_pMainDock));
148 	}
149 	if (myData.pMatchingIcons != NULL)
150 	{
151 		Icon *pIcon;
152 		GList *ic;
153 		for (ic = myData.pMatchingIcons; ic != NULL; ic = ic->next)
154 		{
155 			pIcon = ic->data;
156 			if (pIcon->cDesktopFileName && strncmp (pIcon->cDesktopFileName, "/usr", 4) == 0 && pIcon->image.pSurface != NULL)
157 			{
158 				cairo_surface_destroy (pIcon->image.pSurface);
159 				pIcon->image.pSurface = NULL;
160 				if (pIcon->image.iTexture != 0)
161 				{
162 					_cairo_dock_delete_texture (pIcon->image.iTexture);
163 					pIcon->image.iTexture = 0;
164 				}
165 			}
166 		}
167 		g_list_free (myData.pMatchingIcons);
168 		myData.pMatchingIcons = NULL;
169 		myData.pCurrentMatchingElement = NULL;
170 		myData.pCurrentMatchingElement = NULL;
171 		myData.iMatchingGlideCount = 0;
172 		myData.iPreviousMatchingOffset = 0;
173 		myData.iCurrentMatchingOffset = 0;
174 	}
175 
176 	myData.iSessionState = 0;
177 }
178 
179 
180 
cd_do_free_char(CDChar * pChar)181 void cd_do_free_char (CDChar *pChar)
182 {
183 	if (pChar == NULL)
184 		return ;
185 	if (pChar->pSurface != NULL)
186 	{
187 		cairo_surface_destroy (pChar->pSurface);
188 	}
189 	if (pChar->iTexture != 0)
190 	{
191 		_cairo_dock_delete_texture (pChar->iTexture);
192 	}
193 	g_free (pChar);
194 }
195 
cd_do_free_char_list(GList * pCharList)196 void cd_do_free_char_list (GList *pCharList)
197 {
198 	g_list_foreach (pCharList, (GFunc) cd_do_free_char, NULL);
199 	g_list_free (pCharList);
200 }
201 
202 
cd_do_load_pending_caracters(void)203 void cd_do_load_pending_caracters (void)
204 {
205 	cairo_surface_t *pSurface;
206 	gboolean bLoadTexture = (CAIRO_CONTAINER_IS_OPENGL (g_pMainDock));
207 	gchar c[2] = {'\0', '\0'};
208 	CDChar *pChar;
209 	cairo_t *pCairoContext = cairo_dock_create_drawing_context_generic (CAIRO_CONTAINER (g_pMainDock));
210 	int iDeltaT = cairo_dock_get_animation_delta_t (g_pMainDock);
211 	guint i;
212 	int iOffsetX=0;
213 	for (i = myData.iNbValidCaracters-0; i < myData.sCurrentText->len; i++)
214 	{
215 		//g_print (" on charge la lettre '%c' (%d) tex:%d\n", myData.sCurrentText->str[i], i, bLoadTexture);
216 		c[0] = myData.sCurrentText->str[i];
217 
218 		pChar = g_new0 (CDChar, 1);
219 		pChar->c = c[0];
220 		pChar->iInitialX = myData.iTextWidth/2 + iOffsetX;  // il part du coin haut droit.
221 		pChar->iInitialY = g_pMainDock->container.iHeight/2;  // en bas.
222 		pChar->iCurrentX = pChar->iInitialX;
223 		pChar->iCurrentY = pChar->iInitialY;
224 		pChar->fRotationAngle = 10. * myConfig.iAppearanceDuration / iDeltaT;
225 		//g_print (" on commence a x=%d\n", pChar->iInitialX);
226 		myData.pCharList = g_list_append (myData.pCharList, pChar);
227 
228 		// on cree la surface.
229 		pSurface = cairo_dock_create_surface_from_text (c, &myConfig.labelDescription, &pChar->iWidth, &pChar->iHeight);
230 		if (g_pMainDock->container.bIsHorizontal)
231 		{
232 			myData.iTextWidth += pChar->iWidth;
233 			iOffsetX += pChar->iWidth;
234 			pChar->iInitialY = g_pMainDock->iMaxDockHeight - pChar->iHeight;
235 			myData.iTextHeight = MAX (myData.iTextHeight, pChar->iHeight);
236 		}
237 		else
238 		{
239 			myData.iTextHeight += pChar->iHeight;
240 			iOffsetX += pChar->iHeight;
241 			pChar->iInitialY = g_pMainDock->iMaxDockHeight - pChar->iWidth;
242 			myData.iTextWidth = MAX (myData.iTextWidth, pChar->iWidth);
243 		}
244 
245 		// on cree la texture.
246 		if (bLoadTexture)
247 		{
248 			pChar->iTexture = cairo_dock_create_texture_from_surface (pSurface);
249 			cairo_surface_destroy (pSurface);
250 		}
251 		else
252 		{
253 			pChar->pSurface = pSurface;
254 		}
255 	}
256 	cairo_destroy (pCairoContext);
257 }
258 
259 
cd_do_compute_final_coords(void)260 void cd_do_compute_final_coords (void)
261 {
262 	int x = - myData.iTextWidth / 2;  // par rapport au milieu du dock.
263 	CDChar *pChar;
264 	GList *c;
265 	for (c = myData.pCharList; c != NULL; c = c->next)
266 	{
267 		pChar = c->data;
268 
269 		pChar->iFinalX = x;
270 		pChar->iFinalY = 0;
271 		x += pChar->iWidth;
272 
273 		pChar->iInitialX = pChar->iCurrentX;
274 		pChar->iInitialY = pChar->iCurrentY;
275 	}
276 }
277 
278 
cd_do_launch_appearance_animation(void)279 void cd_do_launch_appearance_animation (void)
280 {
281 	cd_do_compute_final_coords ();
282 	myData.iAppearanceTime = myConfig.iAppearanceDuration;
283 	cairo_dock_launch_animation (CAIRO_CONTAINER (g_pMainDock));  // animation de disparition.
284 }
285 
286 
cd_do_delete_invalid_caracters(void)287 void cd_do_delete_invalid_caracters (void)
288 {
289 	if (myData.sCurrentText->len == 0)
290 		return;
291 
292 	// on efface les lettres precedentes jusqu'a la derniere position validee.
293 	CDChar *pChar;
294 	GList *c = g_list_last (myData.pCharList), *c_prev;
295 	guint i;
296 	for (i = myData.iNbValidCaracters; i < myData.sCurrentText->len && c != NULL; i ++)
297 	{
298 		//g_print ("on efface '%c'\n", myData.sCurrentText->str[i]);
299 		c_prev = c->prev;
300 		pChar = c->data;
301 
302 		myData.iTextWidth -= pChar->iWidth;
303 		cd_do_free_char (pChar);
304 		myData.pCharList = g_list_delete_link (myData.pCharList, c);  // detruit c.
305 		c = c_prev;
306 	}
307 
308 	// on tronque la chaine de la meme maniere.
309 	g_string_truncate (myData.sCurrentText, myData.iNbValidCaracters);
310 	cd_debug (" -> '%s' (%d)", myData.sCurrentText->str, myData.iNbValidCaracters);
311 
312 	// on remet a jour la hauteur du texte.
313 	myData.iTextHeight = 0;
314 	for (c = myData.pCharList; c != NULL; c = c->next)
315 	{
316 		pChar = c->data;
317 		myData.iTextHeight = MAX (myData.iTextHeight, pChar->iHeight);
318 	}
319 }
320