// A scroll on the icon
void cd_xkbd_set_prev_next_group (int iDelta)
{
	XklState *state = xkl_engine_get_current_state (myData.pEngine);

	cd_debug ("keyboard current state : %d;%d +%d", state->group, state->indicators, iDelta);
	
	int i = 0, n = xkl_engine_get_num_groups (myData.pEngine);
	g_return_if_fail (n > 0);
	int iCurrentGroup = MAX (0, MIN (n-1, state->group));  // on blinde car libxklavier peut bugger en 64bits.
	const gchar **pGroupNames = xkl_engine_get_groups_names (myData.pEngine);
	do  // on passe au groupe suivant/precedent en sautant les faux (-).
	{
		i ++;
		iCurrentGroup += iDelta;  // xkl_engine_get_next_group ne marche pas.
		if (iCurrentGroup == n)
			iCurrentGroup = 0;
		else if (iCurrentGroup < 0)
			iCurrentGroup = n - 1;
	} while (i < n && (pGroupNames[iCurrentGroup] == NULL || *pGroupNames[iCurrentGroup] == '-'));
	
	state->group = iCurrentGroup;
	cd_debug ("keyboard new state : %d", state->group);
	xkl_engine_allow_one_switch_to_secondary_group (myData.pEngine);  // sert a quoi ??
	
	Window Xid = xkl_engine_get_current_window (myData.pEngine);
	xkl_engine_save_state (myData.pEngine, Xid, state);
	xkl_engine_lock_group (myData.pEngine, state->group);  // sert a quoi ??
}
static void
popup_menu_set_group (gint group_number, gboolean only_menu)
{

	XklEngine *engine = gkbd_status_get_xkl_engine ();

	XklState *st = xkl_engine_get_current_state(engine);
	Window cur;
	st->group = group_number;
	xkl_engine_allow_one_switch_to_secondary_group (engine);
	cur = xkl_engine_get_current_window (engine);
	if (cur != (Window) NULL) {
		xkl_debug (150, "Enforcing the state %d for window %lx\n",
			   st->group, cur);

		xkl_engine_save_state (engine,
				       xkl_engine_get_current_window
				       (engine), st);
/*    XSetInputFocus( GDK_DISPLAY(), cur, RevertToNone, CurrentTime );*/
	} else {
		xkl_debug (150,
			   "??? Enforcing the state %d for unknown window\n",
			   st->group);
		/* strange situation - bad things can happen */
	}
        if (!only_menu)
        	xkl_engine_lock_group (engine, st->group);
}
// Select the layout from the menu
void cd_xkbd_set_group (int iNumGroup)
{
	XklState *state = xkl_engine_get_current_state (myData.pEngine);
	cd_debug ("keyboard current state : %d;%d", state->group, state->indicators);
	
	state->group = iNumGroup;
	
	Window Xid = xkl_engine_get_current_window (myData.pEngine);
	xkl_engine_allow_one_switch_to_secondary_group (myData.pEngine);  // sert a quoi ??
	xkl_engine_save_state (myData.pEngine, Xid, state);
	xkl_engine_lock_group (myData.pEngine, state->group);  // sert a quoi ??
}
// If the group changes
static void _state_changed (XklEngine *pEngine, XklEngineStateChange type,
                            gint iGroup, gboolean bRestore)
{
	XklState *state = xkl_engine_get_current_state (myData.pEngine);
	cd_debug ("State Changed: %d -> %d (%d) ; %d", myData.iCurrentGroup, state->group, iGroup, state->indicators);

	if (type == GROUP_CHANGED && myData.iCurrentGroup != state->group) // new keyboard layout
	{
		gchar *cShortGroupName = NULL;
		const gchar *cCurrentGroup = NULL;

		// Get the current num group
		guint n = xkl_engine_get_num_groups (myData.pEngine);
		g_return_if_fail (n > 0);

		int iNewGroup = MAX (0, MIN (n-1, state->group));  // workaround for 64bits to avoid strange numbers in 'state'
		const gchar **pGroupNames = xkl_engine_get_groups_names (myData.pEngine);
		g_return_if_fail (pGroupNames != NULL);

		cCurrentGroup = pGroupNames[iNewGroup];
		g_return_if_fail (cCurrentGroup != NULL);

		cd_debug (" group name : %s (%d groups)", cCurrentGroup, n);

		// build the displayed group name
		cShortGroupName = g_strndup (cCurrentGroup, myConfig.iNLetters);
		int index = 0;
		int i;
		for (i = 0; i < state->group; i ++)  // look for groups before us having the same name.
		{
			if (strncmp (cCurrentGroup, pGroupNames[i], myConfig.iNLetters) == 0)
				index ++;
		}
		if (index != 0)  // add a number if several groups have the same name.
		{
			gchar *tmp = cShortGroupName;
			cShortGroupName = g_strdup_printf ("%s%d", cShortGroupName, index+1);
			g_free (tmp);
		}

		myData.iCurrentGroup = state->group;
		cd_xkbd_update_icon (cCurrentGroup, cShortGroupName, TRUE);
		g_free (cShortGroupName);
	}
	else if (type == INDICATORS_CHANGED)
		cd_debug ("Indicators changed"); // according to libxklavier/tests/test_monitor.c, it should work... but I have to miss something
}
static void
popup_menu_show_layout ()
{
	GtkWidget *dialog;
	XklEngine *engine =
	    xkl_engine_get_instance (GDK_DISPLAY_XDISPLAY
				     (gdk_display_get_default ()));
	XklState *xkl_state = xkl_engine_get_current_state (engine);

	gchar **group_names = gkbd_status_get_group_names ();

	gpointer p = g_hash_table_lookup (preview_dialogs,
					  GINT_TO_POINTER
					  (xkl_state->group));

	if (xkl_state->group < 0
	    || xkl_state->group >= g_strv_length (group_names)) {
		return;
	}

	if (p != NULL) {
		/* existing window */
		gtk_window_present (GTK_WINDOW (p));
		return;
	}

	if (!ensure_xkl_registry ())
		return;

	dialog = gkbd_keyboard_drawing_dialog_new ();
	gkbd_keyboard_drawing_dialog_set_group (dialog, xkl_registry, xkl_state->group);

	g_signal_connect (dialog, "destroy",
			  G_CALLBACK (show_layout_destroy),
			  GINT_TO_POINTER (xkl_state->group));
	g_hash_table_insert (preview_dialogs,
			     GINT_TO_POINTER (xkl_state->group), dialog);
	gtk_widget_show_all (dialog);
}
// only use to catch new state of the indicator
gboolean cd_xkbd_keyboard_state_changed (GldiModuleInstance *myApplet, Window *pWindow)
{
	CD_APPLET_ENTER;
	///if (pWindow == NULL)
	/// return GLDI_NOTIFICATION_LET_PASS;
	
	// Get the current state
	XklState *state = xkl_engine_get_current_state (myData.pEngine);
	guint32 indicators = _get_state_indicators ();
	
	cd_debug ("group : %d -> %d ; indic : %d -> %d (%d)",
		myData.iCurrentGroup, state->group,
		myData.iCurrentIndic, indicators, state->indicators);
	
	if (myData.iCurrentIndic == indicators)
		CD_APPLET_LEAVE (GLDI_NOTIFICATION_LET_PASS);

	// Remember the current state
	myData.iCurrentIndic = indicators;
	
	cd_xkbd_update_icon (NULL, NULL, FALSE); // redraw only the indicators
	CD_APPLET_LEAVE (GLDI_NOTIFICATION_LET_PASS);
}
static void
popup_menu_show_layout ()
{
	static GkbdKeyboardDrawingGroupLevel groupsLevels[] = { {
								 0, 1}, {
									 0,
									 3},
	{
	 0, 0}, {
		 0, 2}
	};
	static GkbdKeyboardDrawingGroupLevel *pGroupsLevels[] = {
		groupsLevels, groupsLevels + 1, groupsLevels + 2,
		groupsLevels + 3
	};

	GtkBuilder *builder;
	GtkWidget *dialog, *kbdraw;
	XkbComponentNamesRec component_names;
	XklConfigRec *xkl_data;
	GdkRectangle *rect;
	GError *error = NULL;

	XklEngine *engine = xkl_engine_get_instance (GDK_DISPLAY ());
	XklState *xkl_state = xkl_engine_get_current_state (engine);
	gchar **group_names = gkbd_status_get_group_names ();
	gpointer p = g_hash_table_lookup (preview_dialogs,
					  GINT_TO_POINTER
					  (xkl_state->group));
	if (p != NULL) {
		/* existing window */
		gtk_window_present (GTK_WINDOW (p));
		return;
	}

	builder = gtk_builder_new ();
	gtk_builder_add_from_file (builder, DATADIR "/show-layout.ui",
				   &error);

	if (error) {
		g_error ("building ui from %s failed: %s",
			 DATADIR "/show-layout.ui", error->message);
		g_clear_error (&error);
	}


	dialog =
	    GTK_WIDGET (gtk_builder_get_object
			(builder, "gswitchit_layout_view"));
	kbdraw = gkbd_keyboard_drawing_new ();

	if (xkl_state->group >= 0 &&
	    xkl_state->group < g_strv_length (group_names)) {
		char title[128] = "";
		snprintf (title, sizeof (title),
			  _("Keyboard Layout \"%s\""),
			  group_names[xkl_state->group]);
		gtk_window_set_title (GTK_WINDOW (dialog), title);
		g_object_set_data_full (G_OBJECT (dialog), "group_name",
					g_strdup (group_names
						  [xkl_state->group]),
					g_free);
	}

	gkbd_keyboard_drawing_set_groups_levels (GKBD_KEYBOARD_DRAWING
						 (kbdraw), pGroupsLevels);

	xkl_data = xkl_config_rec_new ();
	if (xkl_config_rec_get_from_server (xkl_data, engine)) {
		int num_layouts = g_strv_length (xkl_data->layouts);
		int num_variants = g_strv_length (xkl_data->variants);
		if (xkl_state->group >= 0 &&
		    xkl_state->group < num_layouts &&
		    xkl_state->group < num_variants) {
			char *l =
			    g_strdup (xkl_data->layouts[xkl_state->group]);
			char *v =
			    g_strdup (xkl_data->variants
				      [xkl_state->group]);
			char **p;
			int i;

			if ((p = xkl_data->layouts) != NULL)
				for (i = num_layouts; --i >= 0;)
					g_free (*p++);

			if ((p = xkl_data->variants) != NULL)
				for (i = num_variants; --i >= 0;)
					g_free (*p++);

			xkl_data->layouts =
			    g_realloc (xkl_data->layouts,
				       sizeof (char *) * 2);
			xkl_data->variants =
			    g_realloc (xkl_data->variants,
				       sizeof (char *) * 2);
			xkl_data->layouts[0] = l;
			xkl_data->variants[0] = v;
			xkl_data->layouts[1] = xkl_data->variants[1] =
			    NULL;
		}

		if (xkl_xkb_config_native_prepare
		    (engine, xkl_data, &component_names)) {
			gkbd_keyboard_drawing_set_keyboard
			    (GKBD_KEYBOARD_DRAWING (kbdraw),
			     &component_names);
			xkl_xkb_config_native_cleanup (engine,
						       &component_names);
		}
	}
	g_object_unref (G_OBJECT (xkl_data));

	g_object_set_data (G_OBJECT (dialog), "builderData", builder);
	g_signal_connect (GTK_OBJECT (dialog),
			  "destroy", G_CALLBACK (show_layout_destroy),
			  GINT_TO_POINTER (xkl_state->group));
	g_signal_connect (G_OBJECT (dialog), "response",
			  G_CALLBACK (show_layout_response), NULL);

	rect = gkbd_preview_load_position ();
	if (rect != NULL) {
		gtk_window_move (GTK_WINDOW (dialog), rect->x, rect->y);
		gtk_window_resize (GTK_WINDOW (dialog), rect->width,
				   rect->height);
		g_free (rect);
	} else
		gtk_window_resize (GTK_WINDOW (dialog), 700, 400);

	gtk_window_set_resizable (GTK_WINDOW (dialog), TRUE);

	gtk_container_add (GTK_CONTAINER
			   (gtk_builder_get_object
			    (builder, "preview_vbox")), kbdraw);

	g_object_set_data (G_OBJECT (dialog), "kbdraw", kbdraw);

	g_hash_table_insert (preview_dialogs,
			     GINT_TO_POINTER (xkl_state->group), dialog);

	gtk_widget_show_all (GTK_WIDGET (dialog));
}