void cd_do_search_current_icon (gboolean bLoopSearch)
{
	//\_________________ on cherche un lanceur correspondant.
	CairoDock *pDock;
	Icon *pIcon = cd_do_search_icon_by_command (myData.sCurrentText->str, (bLoopSearch ? myData.pCurrentIcon : NULL), &pDock);
	g_print ("found icon : %s\n", pIcon ? pIcon->acName : "none");
	
	//\_________________ on gere le changement d'icone/dock.
	cd_do_change_current_icon (pIcon, pDock);
}
void cd_do_exit_session (void)
{
	if (cd_do_session_is_off ())  // session already off
		return;
	
	cd_do_close_session ();
	
	myData.iCloseTime = 0;
	
	cd_do_change_current_icon (NULL, NULL);
	
	myData.iSessionState = CD_SESSION_NONE;
}
gboolean cd_do_check_icon_destroyed (gpointer pUserData, Icon *pIcon)
{
	if (pIcon == myData.pCurrentIcon && ! myData.bIgnoreIconState)
	{
		cd_debug ("notre icone vient de se faire detruire");
		Icon *pNextIcon = NULL;
		if (myData.pCurrentDock != NULL)
		{
			pNextIcon = cairo_dock_get_next_icon (myData.pCurrentDock->icons, pIcon);
			if (! pNextIcon || CAIRO_DOCK_ICON_TYPE_IS_SEPARATOR (pNextIcon))
			{
				pNextIcon = cairo_dock_get_previous_icon (myData.pCurrentDock->icons, pIcon);
				if (! pNextIcon || CAIRO_DOCK_ICON_TYPE_IS_SEPARATOR (pNextIcon))
					pNextIcon = cairo_dock_get_first_icon (myData.pCurrentDock->icons);
			}
		}
		if (pNextIcon != NULL)
			cd_do_change_current_icon (pNextIcon, myData.pCurrentDock);
		else
			cd_do_exit_session ();
	}
	
	return GLDI_NOTIFICATION_LET_PASS;
}
void cd_do_open_session (void)
{
	if (cd_do_session_is_running ())  // session already running, noting to do
		return;
	
	if (! cd_do_session_is_off ())  // session not yet closed, close it first to reset the state.
		cd_do_exit_session ();
	
	// wait for keyboard input.
	gldi_object_register_notification (&myContainerObjectMgr,
		NOTIFICATION_KEY_PRESSED, (GldiNotificationFunc) cd_do_key_pressed, GLDI_RUN_AFTER, NULL);
	gldi_object_register_notification (&myIconObjectMgr,
		NOTIFICATION_DESTROY, (GldiNotificationFunc) cd_do_check_icon_destroyed, GLDI_RUN_AFTER, NULL);
	gldi_object_register_notification (&myWindowObjectMgr,
		NOTIFICATION_WINDOW_ACTIVATED, (GldiNotificationFunc) cd_do_check_active_dock, GLDI_RUN_AFTER, NULL);
	
	myData.sCurrentText = g_string_sized_new (20);
	
	// set initial position (dock, icon).
	myData.pCurrentDock = NULL;
	myData.pCurrentIcon =  NULL;
	
	CairoDock *pDock = gldi_dock_get (myConfig.cDockName);
	if (pDock == NULL)
		pDock = g_pMainDock;
	Icon *pIcon = NULL;
	int n = g_list_length (pDock->icons);
	if (n > 0)
	{
		pIcon =  g_list_nth_data (pDock->icons, (n-1) / 2);
		if (CAIRO_DOCK_ICON_TYPE_IS_SEPARATOR (pIcon) && n > 1)
			pIcon = g_list_nth_data (pDock->icons, (n+1) / 2);
	}
	cd_do_change_current_icon (pIcon, pDock);
	
	// show the number of the 10 first icons
	cd_do_numberize_icons (pDock);
	
	// show the dock.
	myData.bIgnoreIconState = TRUE;
	cairo_dock_emit_enter_signal (CAIRO_CONTAINER (pDock));
	myData.bIgnoreIconState = FALSE;
	
	// give it focus for inputs.
	myData.pPreviouslyActiveWindow = gldi_windows_get_active ();
	gldi_container_present (CAIRO_CONTAINER (pDock));
	cairo_dock_freeze_docks (TRUE);
	
	// launch the animation.
	myData.iPromptAnimationCount = 0;
	if (myData.pArrowImage == NULL)
	{
		myData.pArrowImage = cairo_dock_create_image_buffer (MY_APPLET_SHARE_DATA_DIR"/arrows.svg",
			pDock->iActiveHeight,
			pDock->iActiveHeight,
			CAIRO_DOCK_KEEP_RATIO);
	}
	cairo_dock_launch_animation (CAIRO_CONTAINER (pDock));
	
	myData.iSessionState = CD_SESSION_RUNNING;
}
gboolean cd_do_key_pressed (gpointer pUserData, GldiContainer *pContainer, guint iKeyVal, guint iModifierType, const gchar *string, int iKeyCode)
{
	g_return_val_if_fail (cd_do_session_is_running (), GLDI_NOTIFICATION_LET_PASS);
	g_return_val_if_fail (myData.pCurrentDock != NULL, GLDI_NOTIFICATION_LET_PASS);
	
	const gchar *cKeyName = gdk_keyval_name (iKeyVal);
	guint32 iUnicodeChar = gdk_keyval_to_unicode (iKeyVal);
	cd_debug ("+ cKeyName : %s (%c, %s, %d)", cKeyName, iUnicodeChar, string, iKeyCode);
	
	if (myData.sCurrentText->len == 0)
	{
		GdkKeymapKey *keys = NULL;
		guint *keyvals = NULL;
		int i, n_entries = 0;
		int iKeyVal2;
		gdk_keymap_get_entries_for_keycode (gdk_keymap_get_default (),
			iKeyCode,
			&keys,
			&keyvals,
			&n_entries);
		for (i = 0; i < n_entries; i ++)
		{
			iKeyVal2 = keyvals[i];
			if ((iKeyVal2 >= GDK_KEY_0 && iKeyVal2 <= GDK_KEY_9) || (iKeyVal2 >= GDK_KEY_KP_0 && iKeyVal2 <= GDK_KEY_KP_9))
			{
				iKeyVal = iKeyVal2;
				break;
			}
		}
		g_free (keys);
		g_free (keyvals);
	}
	
	if (iKeyVal == GDK_KEY_Escape)  // on clot la session.
	{
		// give the focus back to the window that had it before the user opened this session.
		if (myData.pPreviouslyActiveWindow != NULL)
		{
			gldi_window_show (myData.pPreviouslyActiveWindow);
		}
		cd_do_close_session ();
	}
	else if (iKeyVal == GDK_KEY_space && myData.sCurrentText->len == 0)  // pas d'espace en debut de chaine.
	{
		// on rejette.
	}
	else if (iKeyVal >= GDK_KEY_Shift_L && iKeyVal <= GDK_KEY_Hyper_R)  // on n'ecrit pas les modificateurs.
	{
		// on rejette.
	}
	else if (iKeyVal == GDK_KEY_Menu)  // emulation du clic droit.
	{
		if (myData.pCurrentIcon != NULL)
		{
			myData.bIgnoreIconState = TRUE;
			gldi_icon_stop_animation (myData.pCurrentIcon);  // car on va perdre le focus.
			myData.bIgnoreIconState = FALSE;
			
			GtkWidget *menu = gldi_container_build_menu (CAIRO_CONTAINER (myData.pCurrentDock), myData.pCurrentIcon);
			gldi_menu_popup (menu);
		}
	}
	else if (iKeyVal == GDK_KEY_BackSpace)  // on efface la derniere lettre.
	{
		if (myData.sCurrentText->len > 0)
		{
			cd_debug ("we remove the last letter of %s (%d)", myData.sCurrentText->str, myData.sCurrentText->len);
			
			g_string_truncate (myData.sCurrentText, myData.sCurrentText->len-1);
			
			// on relance la recherche.
			if (myData.pCurrentIcon == NULL)  // sinon l'icone actuelle convient toujours.
				cd_do_search_current_icon (FALSE);
		}
	}
	else if (iKeyVal == GDK_KEY_Tab)  // jump to next icon.
	{
		if (myData.sCurrentText->len > 0)
		{
			//gboolean bPrevious = iModifierType & GDK_SHIFT_MASK;
			// on cherche l'icone suivante.
			cd_do_search_current_icon (TRUE);  // pCurrentIcon peut etre NULL si elle s'est faite detruire pendant la recherche, auquel cas on cherchera juste normalement.
		}
	}
	else if (iKeyVal == GDK_KEY_Return)
	{
		if (myData.pCurrentIcon != NULL)
		{
			cd_debug ("we click on the icon '%s' [%d, %d]", myData.pCurrentIcon->cName, iModifierType, GDK_SHIFT_MASK);
			
			myData.bIgnoreIconState = TRUE;
			if (iModifierType & GDK_MOD1_MASK)  // ALT
			{
				myData.bIgnoreIconState = TRUE;
				gldi_icon_stop_animation (myData.pCurrentIcon);  // car aucune animation ne va la remplacer.
				myData.bIgnoreIconState = FALSE;
				gldi_object_notify (CAIRO_CONTAINER (myData.pCurrentDock), NOTIFICATION_MIDDLE_CLICK_ICON, myData.pCurrentIcon, myData.pCurrentDock);
			}
			else if (iModifierType & GDK_CONTROL_MASK)  // CTRL
			{
				myData.bIgnoreIconState = TRUE;
				gldi_icon_stop_animation (myData.pCurrentIcon);  // car on va perdre le focus.
				myData.bIgnoreIconState = FALSE;
				
				GtkWidget *menu = gldi_container_build_menu (CAIRO_CONTAINER (myData.pCurrentDock), myData.pCurrentIcon);
				gldi_menu_popup (menu);
			}
			else
			{
				cd_do_simulate_click (CAIRO_CONTAINER (myData.pCurrentDock), myData.pCurrentIcon, iModifierType);
			}
			gldi_icon_start_animation (myData.pCurrentIcon);
			myData.bIgnoreIconState = FALSE;
			myData.pCurrentIcon = NULL;  // sinon on va interrompre l'animation en fermant la session.
		}
		cd_do_close_session ();
	}
	else if (iKeyVal == GDK_KEY_Left || iKeyVal == GDK_KEY_Right || iKeyVal == GDK_KEY_Up || iKeyVal == GDK_KEY_Down)
	{
		iKeyVal = _orient_arrow (pContainer, iKeyVal);
		if (iKeyVal == GDK_KEY_Up)
		{
			if (myData.pCurrentIcon != NULL && myData.pCurrentIcon->pSubDock != NULL)
			{
				cd_debug ("on monte dans le sous-dock %s", myData.pCurrentIcon->cName);
				Icon *pIcon = cairo_dock_get_first_icon (myData.pCurrentIcon->pSubDock->icons);
				cd_do_change_current_icon (pIcon, myData.pCurrentIcon->pSubDock);
			}
		}
		else if (iKeyVal == GDK_KEY_Down)
		{
			if (myData.pCurrentDock->iRefCount > 0)
			{
				CairoDock *pParentDock = NULL;
				Icon *pPointingIcon = cairo_dock_search_icon_pointing_on_dock (myData.pCurrentDock, &pParentDock);
				if (pPointingIcon != NULL)
				{
					cd_debug ("on redescend dans le dock parent via %s", pPointingIcon->cName);
					cd_do_change_current_icon (pPointingIcon, pParentDock);
				}
			}
		}
		else if (iKeyVal == GDK_KEY_Left)
		{
			if (myData.pCurrentDock->icons != NULL)
			{
				Icon *pPrevIcon = cairo_dock_get_previous_icon (myData.pCurrentDock->icons, myData.pCurrentIcon);
				if (CAIRO_DOCK_ICON_TYPE_IS_SEPARATOR (pPrevIcon))
					pPrevIcon = cairo_dock_get_previous_icon (myData.pCurrentDock->icons, pPrevIcon);
				if (pPrevIcon == NULL)  // pas trouve ou bien 1ere icone.
				{
					pPrevIcon = cairo_dock_get_last_icon (myData.pCurrentDock->icons);
				}
				
				cd_debug ("on se deplace a gauche sur %s", pPrevIcon ? pPrevIcon->cName : "none");
				cd_do_change_current_icon (pPrevIcon, myData.pCurrentDock);
			}
		}
		else  // Gdk_Right.
		{
			if (myData.pCurrentDock->icons != NULL)
			{
				Icon *pNextIcon = cairo_dock_get_next_icon (myData.pCurrentDock->icons, myData.pCurrentIcon);
				if (CAIRO_DOCK_ICON_TYPE_IS_SEPARATOR (pNextIcon))
					pNextIcon = cairo_dock_get_next_icon (myData.pCurrentDock->icons, pNextIcon);
				if (pNextIcon == NULL)  // pas trouve ou bien 1ere icone.
				{
					pNextIcon = cairo_dock_get_first_icon (myData.pCurrentDock->icons);
				}
				
				cd_debug ("on se deplace a gauche sur %s", pNextIcon ? pNextIcon->cName : "none");
				cd_do_change_current_icon (pNextIcon, myData.pCurrentDock);
			}
		}
	}
	else if (iKeyVal == GDK_KEY_Page_Down || iKeyVal == GDK_KEY_Page_Up || iKeyVal == GDK_KEY_Home || iKeyVal == GDK_KEY_End)
	{
		if (iModifierType & GDK_CONTROL_MASK)  // changement de dock principal
		{
			gpointer data[4] = {myData.pCurrentDock, NULL, GINT_TO_POINTER (FALSE), NULL};
			gldi_docks_foreach_root ((GFunc) _find_next_dock, data);
			CairoDock *pNextDock = data[1];
			if (pNextDock == NULL)
				pNextDock = data[3];
			if (pNextDock != NULL)
			{
				Icon *pNextIcon = NULL;
				int n = g_list_length (pNextDock->icons);
				if (n > 0)
				{
					pNextIcon =  g_list_nth_data (pNextDock->icons, (n-1) / 2);
					if (CAIRO_DOCK_ICON_TYPE_IS_SEPARATOR (pNextIcon) && n > 1)
						pNextIcon = g_list_nth_data (pNextDock->icons, (n+1) / 2);
				}
				cd_do_change_current_icon (pNextIcon, pNextDock);
			}
		}
		
		Icon *pIcon = (iKeyVal == GDK_KEY_Page_Up || iKeyVal == GDK_KEY_Home ? cairo_dock_get_first_icon (myData.pCurrentDock->icons) : cairo_dock_get_last_icon (myData.pCurrentDock->icons));
		cd_debug ("on se deplace a l'extremite sur %s", pIcon ? pIcon->cName : "none");
		cd_do_change_current_icon (pIcon, myData.pCurrentDock);
	}
	else if ( ((iKeyVal >= GDK_KEY_0 && iKeyVal <= GDK_KEY_9) || (iKeyVal >= GDK_KEY_KP_0 && iKeyVal <= GDK_KEY_KP_9))
	&& myData.sCurrentText->len == 0)
	{
		_activate_nth_icon (iKeyVal, iModifierType);
	}
	else if (string)  /// utiliser l'unichar ...
	{
		cd_debug ("string:'%s'", string);
		g_string_append_c (myData.sCurrentText, *string);
		
		cd_do_search_current_icon (FALSE);
	}
	
	return GLDI_NOTIFICATION_INTERCEPT;
}