--- xfce4-tips/data/Makefile.am +++ xfce4-tips/data/Makefile.am @@ -1,10 +1,5 @@ tipsdir = $(datadir)/xfce4/tips -tips_DATA = \ - tips \ - tips.dat - -tips.dat: $(srcdir)/tips - strfile $(srcdir)/tips tips.dat +tips_DATA = tips EXTRA_DIST = $(tips_DATA) --- xfce4-tips/main.c +++ xfce4-tips/main.c @@ -43,7 +43,8 @@ -static const gchar *titles[] = { +static const gchar *titles[] = +{ N_("Tips and Tricks"), N_("Fortunes") }; @@ -52,8 +53,65 @@ static GtkWidget *dlg = NULL; static guint option = OPTION_TIPS; +static gchar *fortune_cmd = NULL; +static GPtrArray *tips = NULL; + + +static void +read_tips_from_file (void) +{ + gchar *data; + gchar *entry; + gsize len; + guint i, j; + GError *error = NULL; + + /* read the whole file */ + g_file_get_contents (TIPSDIR "/tips", &data, &len, &error); + + tips = g_ptr_array_new (); + if (error != NULL) + { + g_ptr_array_add (tips, g_strdup_printf (_("Could not load tips database (%s)."), + error->message)); + g_free (data); + g_error_free (error); + return; + } + + entry = g_malloc (len + 1); + i = j = 0; + while (data[i]) + { + if (data[i] == '%') + { + /* add a new tip */ + entry[j] = '\0'; + j = 0; + if (entry[0]) + g_ptr_array_add (tips, g_strdup(entry)); + /* skip the following line break character(s) */ + if (data[i] == '\r' && (i + 1) < len && data[i + 1] == '\n') + i += 2; + else + i += 1; + } + else + entry[j++] = data[i]; + + i++; + } + g_free (data); + g_free (entry); +} +static void +free_tip (gpointer data, gpointer user_data) +{ + g_free (data); +} + static gboolean autostart_enabled (void) @@ -95,47 +153,93 @@ item_cb (GtkWidget *btn, gpointer data) { - option = GPOINTER_TO_UINT(data); + option = GPOINTER_TO_UINT (data); gtk_window_set_title (GTK_WINDOW (dlg), _(titles[option])); } +static gchar* +run_fortune (void) +{ + GError *error = NULL; + gchar *out = NULL; + gchar *err = NULL; + gchar *buffer = NULL; + + if (fortune_cmd != NULL && g_spawn_command_line_sync (fortune_cmd, &out, &err, NULL, &error)) + { + if (out != NULL && *out != '\0') + { + /* check output for valid UTF-8 */ + if (g_utf8_validate (out, -1, NULL)) + buffer = out; + else + { + /* we got something else than UTF-8, try to convert it from the user's locale */ + buffer = g_locale_to_utf8 (out, -1, NULL, NULL, NULL); + if (buffer == NULL) + { + /* converting it from the user's locale failed too, we give up */ + buffer = g_strdup_printf (_("Invalid output of fortune.")); + } + } + } + else + { + buffer = g_strdup_printf (_("Executing fortune failed (%s)"), err); + } + if (buffer != out) + g_free (out); + g_free(err); + } + else + { + buffer = g_strdup_printf (_("Executing fortune failed (%s)"), error->message); + g_error_free (error); + } + + return buffer; +} + + + static void next_cb(GtkWidget *btn, GtkTextBuffer *textbuf) { - gchar buffer[1024]; + gchar *buffer = NULL; GtkTextIter start; GtkTextIter end; - FILE *fp; /* clear the text buffer */ - gtk_text_buffer_get_bounds(textbuf, &start, &end); - gtk_text_buffer_delete(textbuf, &start, &end); + gtk_text_buffer_get_bounds (textbuf, &start, &end); + gtk_text_buffer_delete (textbuf, &start, &end); - switch (option) { - case OPTION_TIPS: - strcpy(buffer, "fortune " TIPSDIR "/tips"); - break; - - case OPTION_FORTUNES: - strcpy(buffer, "fortune"); - break; - } - - if ((fp = popen(buffer, "r")) == NULL) { - perror("Unable to execute fortune"); - return; - } - - while (fgets(buffer, sizeof(buffer), fp) != NULL) { - gtk_text_buffer_get_end_iter(textbuf, &end); - gtk_text_buffer_insert(textbuf, &end, buffer, -1); - } + switch (option) + { + case OPTION_TIPS: + { + if (! tips || tips->len == 0) + buffer = _("Error while loading tips."); + else + /* no need to check or convert the encoding of our own tips file as it is already UTF-8 */ + buffer = g_ptr_array_index (tips, g_random_int_range(0, tips->len)); + break; + } + case OPTION_FORTUNES: + { + buffer = run_fortune (); + break; + } + } - pclose (fp); -} + /* add the text to the buffer */ + gtk_text_buffer_get_end_iter (textbuf, &end); + gtk_text_buffer_insert (textbuf, &end, buffer, -1); + if (option == OPTION_FORTUNES) + g_free (buffer); +} int @@ -152,9 +256,14 @@ GtkWidget *close; xfce_textdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR, "UTF-8"); - + gtk_init (&argc, &argv); + /* test for fortune */ + fortune_cmd = g_find_program_in_path ("fortune"); + + read_tips_from_file (); + /* fake a SM client id, so the session manager does not restart us */ gdk_set_sm_client_id ("FAKED CLIENTID"); @@ -193,25 +302,28 @@ gtk_box_pack_start (GTK_BOX (vbox2), check, FALSE, FALSE, 0); gtk_widget_show (check); - menu = gtk_menu_new (); - gtk_widget_show (menu); - - item = gtk_menu_item_new_with_label (_("Tips and tricks")); - g_signal_connect (item, "activate", G_CALLBACK (item_cb), GUINT_TO_POINTER (OPTION_TIPS)); - g_signal_connect (item, "activate", G_CALLBACK (next_cb), gtk_text_view_get_buffer (GTK_TEXT_VIEW (view))); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); - gtk_widget_show (item); - - item = gtk_menu_item_new_with_label (_("Fortunes")); - g_signal_connect (item, "activate", G_CALLBACK (item_cb), GUINT_TO_POINTER (OPTION_FORTUNES)); - g_signal_connect (item, "activate", G_CALLBACK (next_cb), gtk_text_view_get_buffer (GTK_TEXT_VIEW (view))); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); - gtk_widget_show (item); - - opt = gtk_option_menu_new(); - gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu); - gtk_dialog_add_action_widget (GTK_DIALOG (dlg), opt, GTK_RESPONSE_NONE); - gtk_widget_show(opt); + if (fortune_cmd != NULL) + { + menu = gtk_menu_new (); + gtk_widget_show (menu); + + item = gtk_menu_item_new_with_label (titles[OPTION_TIPS]); + g_signal_connect (item, "activate", G_CALLBACK (item_cb), GUINT_TO_POINTER (OPTION_TIPS)); + g_signal_connect (item, "activate", G_CALLBACK (next_cb), gtk_text_view_get_buffer (GTK_TEXT_VIEW (view))); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + gtk_widget_show (item); + + item = gtk_menu_item_new_with_label (titles[OPTION_FORTUNES]); + g_signal_connect (item, "activate", G_CALLBACK (item_cb), GUINT_TO_POINTER (OPTION_FORTUNES)); + g_signal_connect (item, "activate", G_CALLBACK (next_cb), gtk_text_view_get_buffer (GTK_TEXT_VIEW (view))); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + gtk_widget_show (item); + + opt = gtk_option_menu_new(); + gtk_option_menu_set_menu(GTK_OPTION_MENU(opt), menu); + gtk_dialog_add_action_widget (GTK_DIALOG (dlg), opt, GTK_RESPONSE_NONE); + gtk_widget_show(opt); + } next = gtk_button_new_with_label (_("Next")); gtk_dialog_add_action_widget (GTK_DIALOG (dlg), next, GTK_RESPONSE_NONE); @@ -232,5 +344,14 @@ gtk_main (); + + /* cleanup */ + g_free (fortune_cmd); + if (tips != NULL) + { + g_ptr_array_foreach (tips, free_tip, NULL); + g_ptr_array_free (tips, TRUE); + } + return EXIT_SUCCESS; }