Add check update plugin.

This plugin provides a way to check on win32 or mac osx if there is a new release.
parent 57cbc3ce
......@@ -50,12 +50,17 @@ AC_CHECK_FUNCS(fsync)
dnl make sure we keep ACLOCAL_FLAGS around for maintainer builds to work
AC_SUBST(ACLOCAL_AMFLAGS, "$ACLOCAL_FLAGS -I m4")
dnl active plugins for gedit.schemas
ACTIVE_PLUGINS="docinfo,modelines,filebrowser,spell,time"
AC_SUBST(ACTIVE_PLUGINS)
dnl check for win32 platform
AC_MSG_CHECKING([for Win32 platform])
case "$host" in
*-*-mingw*|*-*-cygwin*)
platform_win32=yes
AC_CHECK_TOOL(WINDRES, windres)
ACTIVE_PLUGINS += ",checkupdate"
;;
*)
platform_win32=no
......@@ -81,6 +86,7 @@ AC_MSG_CHECKING([for Mac OS X platform])
case "$host" in
*-*-darwin*)
platform_osx=yes
ACTIVE_PLUGINS += ",checkupdate"
;;
*)
platform_osx=no
......@@ -124,6 +130,35 @@ AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE", [Gettext package])
AM_GLIB_GNU_GETTEXT
dnl ================================================================
dnl check update plugin
dnl ================================================================
AC_ARG_ENABLE([updater],
AS_HELP_STRING([--disable-updater],[Disable check update plugin (default: enabled)]),
[enable_updater=$enableval],
[enable_updater=yes])
if test "x$enable_updater" != "xno"; then
PKG_CHECK_MODULES(LIBSOUP, \
libsoup-2.4,
have_libsoup=yes,
have_libsoup=no)
if test x"have_libsoup" = "xyes"; then
if test "x$platform_win32" = "xyes"; then
enable_updater=yes
elif test "x$platform_osx" = "xyes"; then
enable_updater=yes
else
enable_updater=no
fi
else
enable_updater=no
fi
fi
AM_CONDITIONAL(ENABLE_UPDATER, test x"$enable_updater" = "xyes")
dnl ================================================================
dnl spell plugins checks: enchant and iso-codes
......@@ -424,6 +459,7 @@ Makefile
data/gedit.desktop.in
data/gedit-bugreport.sh
data/gedit.pc
data/gedit.schemas.in
data/Makefile
docs/Makefile
docs/reference/Makefile
......@@ -438,6 +474,7 @@ plugin-loaders/python/Makefile
plugin-loaders/python/bindings/Makefile
plugins/Makefile
plugins/changecase/Makefile
plugins/checkupdate/Makefile
plugins/docinfo/Makefile
plugins/externaltools/data/Makefile
plugins/externaltools/Makefile
......
......@@ -33,6 +33,7 @@ endif
EXTRA_DIST = \
$(desktop_in_files) \
$(schemas_in_files) \
gedit.schemas.in.in \
$(man_MANS) \
gedit.pc.in \
gedit-bugreport.sh.in
......
......@@ -501,7 +501,7 @@
<owner>gedit</owner>
<type>list</type>
<list_type>string</list_type>
<default>[docinfo,modelines,filebrowser,spell,time]</default>
<default>[@ACTIVE_PLUGINS@]</default>
<locale name="C">
<short>Active plugins</short>
<long>List of active plugins. It contains the "Location" of the active plugins. See the .gedit-plugin file for obtaining
......
......@@ -25,5 +25,9 @@ DIST_SUBDIRS += externaltools pythonconsole snippets quickopen
SUBDIRS += externaltools pythonconsole snippets quickopen
endif
if ENABLE_UPDATER
DIST_SUBDIRS += checkupdate
SUBDIRS += checkupdate
endif
-include $(top_srcdir)/git.mk
# gedit win32 updater
plugindir = $(GEDIT_PLUGINS_LIBS_DIR)
INCLUDES = \
-I$(top_srcdir) \
$(GEDIT_CFLAGS) \
$(LIBSOUP_CFLAGS) \
$(WARN_CFLAGS) \
$(DISABLE_DEPRECATED_CFLAGS)
plugin_LTLIBRARIES = libcheckupdate.la
libcheckupdate_la_SOURCES = \
gedit-check-update-plugin.h \
gedit-check-update-plugin.c
libcheckupdate_la_LDFLAGS = $(PLUGIN_LIBTOOL_FLAGS)
libcheckupdate_la_LIBADD = $(GEDIT_LIBS) $(LIBSOUP_LIBS)
plugin_in_files = checkupdate.gedit-plugin.desktop.in
%.gedit-plugin: %.gedit-plugin.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache
plugin_DATA = $(plugin_in_files:.gedit-plugin.desktop.in=.gedit-plugin)
EXTRA_DIST = $(plugin_in_files)
CLEANFILES = $(plugin_DATA)
DISTCLEANFILES = $(plugin_DATA)
-include $(top_srcdir)/git.mk
[Gedit Plugin]
Module=checkupdate
IAge=2
_Name=Check update
_Description=Check for latest version of gedit
Icon=gedit-plugin
Authors=Ignacio Casal Quinteiro <icq@gnome.org>
Copyright=Copyright © 2009 Ignacio Casal Quinteiro
Website=http://www.gedit.org
/*
* Copyright (C) 2009 - Ignacio Casal Quinteiro <icq@gnome.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "gedit-check-update-plugin.h"
#include <glib/gi18n-lib.h>
#include <gedit/gedit-debug.h>
#include <gedit/gedit-utils.h>
#include <libsoup/soup.h>
#include <gtk/gtk.h>
#include <stdlib.h>
#if !GTK_CHECK_VERSION(2, 17, 1)
#include <gedit/gedit-message-area.h>
#endif
#define WINDOW_DATA_KEY "GeditCheckUpdatePluginWindowData"
#define VERSION_PLACE "<a href=\"[0-9]\\.[0-9]+/\">"
#ifndef G_OS_WIN32
#define GEDIT_URL "http://ftp.acc.umu.se/pub/gnome/binaries/win32/gedit/"
#define FILE_REGEX "gedit\\-setup\\-[0-9]+\\.[0-9]+\\.[0-9]+(\\-[0-9]+)?\\.exe"
#else
#define GEDIT_URL "http://ftp.acc.umu.se/pub/gnome/binaries/mac/gedit/"
#define FILE_REGEX "gedit\\-[0-9]+\\.[0-9]+\\.[0-9]+(\\-[0-9]+)?\\.dmg"
#endif
#define GEDIT_CHECK_UPDATE_PLUGIN_GET_PRIVATE(object) \
(G_TYPE_INSTANCE_GET_PRIVATE ((object), \
GEDIT_TYPE_CHECK_UPDATE_PLUGIN, \
GeditCheckUpdatePluginPrivate))
GEDIT_PLUGIN_REGISTER_TYPE (GeditCheckUpdatePlugin, gedit_check_update_plugin)
struct _GeditCheckUpdatePluginPrivate
{
SoupSession *session;
};
static void
gedit_check_update_plugin_init (GeditCheckUpdatePlugin *plugin)
{
plugin->priv = GEDIT_CHECK_UPDATE_PLUGIN_GET_PRIVATE (plugin);
gedit_debug_message (DEBUG_PLUGINS,
"GeditCheckUpdatePlugin initializing");
plugin->priv->session = soup_session_async_new ();
}
static void
gedit_check_update_plugin_dispose (GObject *object)
{
GeditCheckUpdatePlugin *plugin = GEDIT_CHECK_UPDATE_PLUGIN (object);
if (plugin->priv->session != NULL)
{
g_object_unref (plugin->priv->session);
plugin->priv->session = NULL;
}
gedit_debug_message (DEBUG_PLUGINS,
"GeditCheckUpdatePlugin disposing");
G_OBJECT_CLASS (gedit_check_update_plugin_parent_class)->dispose (object);
}
static void
gedit_check_update_plugin_finalize (GObject *object)
{
gedit_debug_message (DEBUG_PLUGINS,
"GeditCheckUpdatePlugin finalizing");
G_OBJECT_CLASS (gedit_check_update_plugin_parent_class)->finalize (object);
}
static void
set_contents (GtkWidget *infobar,
GtkWidget *contents)
{
#if !GTK_CHECK_VERSION (2, 17, 1)
gedit_message_area_set_contents (GEDIT_MESSAGE_AREA (infobar),
contents);
#else
GtkWidget *content_area;
content_area = gtk_info_bar_get_content_area (GTK_INFO_BAR (infobar));
gtk_container_add (GTK_CONTAINER (content_area), contents);
#endif
}
static void
set_message_area_text_and_icon (GtkWidget *message_area,
const gchar *icon_stock_id,
const gchar *primary_text,
const gchar *secondary_text)
{
GtkWidget *hbox_content;
GtkWidget *image;
GtkWidget *vbox;
gchar *primary_markup;
gchar *secondary_markup;
GtkWidget *primary_label;
GtkWidget *secondary_label;
hbox_content = gtk_hbox_new (FALSE, 8);
gtk_widget_show (hbox_content);
image = gtk_image_new_from_stock (icon_stock_id, GTK_ICON_SIZE_DIALOG);
gtk_widget_show (image);
gtk_box_pack_start (GTK_BOX (hbox_content), image, FALSE, FALSE, 0);
gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0);
vbox = gtk_vbox_new (FALSE, 6);
gtk_widget_show (vbox);
gtk_box_pack_start (GTK_BOX (hbox_content), vbox, TRUE, TRUE, 0);
primary_markup = g_strdup_printf ("<b>%s</b>", primary_text);
primary_label = gtk_label_new (primary_markup);
g_free (primary_markup);
gtk_widget_show (primary_label);
gtk_box_pack_start (GTK_BOX (vbox), primary_label, TRUE, TRUE, 0);
gtk_label_set_use_markup (GTK_LABEL (primary_label), TRUE);
gtk_label_set_line_wrap (GTK_LABEL (primary_label), TRUE);
gtk_misc_set_alignment (GTK_MISC (primary_label), 0, 0.5);
GTK_WIDGET_SET_FLAGS (primary_label, GTK_CAN_FOCUS);
gtk_label_set_selectable (GTK_LABEL (primary_label), TRUE);
if (secondary_text != NULL)
{
secondary_markup = g_strdup_printf ("<small>%s</small>",
secondary_text);
secondary_label = gtk_label_new (secondary_markup);
g_free (secondary_markup);
gtk_widget_show (secondary_label);
gtk_box_pack_start (GTK_BOX (vbox), secondary_label, TRUE, TRUE, 0);
GTK_WIDGET_SET_FLAGS (secondary_label, GTK_CAN_FOCUS);
gtk_label_set_use_markup (GTK_LABEL (secondary_label), TRUE);
gtk_label_set_line_wrap (GTK_LABEL (secondary_label), TRUE);
gtk_label_set_selectable (GTK_LABEL (secondary_label), TRUE);
gtk_misc_set_alignment (GTK_MISC (secondary_label), 0, 0.5);
}
set_contents (message_area, hbox_content);
}
static void
on_response_cb (GtkWidget *infobar,
gint response_id,
GeditWindow *window)
{
if (response_id == GTK_RESPONSE_YES)
{
GError *error = NULL;
gchar *url;
url = g_object_get_data (G_OBJECT (window), WINDOW_DATA_KEY);
gtk_show_uri (gtk_widget_get_screen (GTK_WIDGET (window)),
url,
GDK_CURRENT_TIME,
&error);
if (error != NULL)
{
GtkWidget *dialog;
dialog = gtk_message_dialog_new (GTK_WINDOW (window),
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_ERROR,
GTK_BUTTONS_CLOSE,
_("There was an error displaying the url."));
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
"%s", error->message);
g_signal_connect (G_OBJECT (dialog),
"response",
G_CALLBACK (gtk_widget_destroy),
NULL);
gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
gtk_widget_show (dialog);
g_error_free (error);
}
}
gtk_widget_destroy (infobar);
}
static GtkWidget *
create_infobar (GeditWindow *window)
{
GtkWidget *infobar;
GtkWidget *button;
#if !GTK_CHECK_VERSION (2, 17, 1)
infobar = gedit_message_area_new ();
gedit_message_area_add_stock_button_with_text (GEDIT_MESSAGE_AREA (infobar),
_("_Download"),
GTK_STOCK_SAVE,
GTK_RESPONSE_YES);
gedit_message_area_add_button (GEDIT_MESSAGE_AREA (infobar),
GTK_STOCK_CANCEL,
GTK_RESPONSE_CANCEL);
#else
infobar = gtk_info_bar_new ();
button = gedit_gtk_button_new_with_stock_icon (_("_Download"),
GTK_STOCK_SAVE);
gtk_widget_show (button);
gtk_info_bar_add_action_widget (GTK_INFO_BAR (infobar),
button,
GTK_RESPONSE_YES);
gtk_info_bar_add_button (GTK_INFO_BAR (infobar),
GTK_STOCK_CANCEL,
GTK_RESPONSE_CANCEL);
gtk_info_bar_set_message_type (GTK_INFO_BAR (infobar),
GTK_MESSAGE_INFO);
#endif
set_message_area_text_and_icon (infobar,
"gtk-dialog-info",
_("There is a new version of gedit"),
_("You can download the new version of gedit"
" by pressing on the download button"));
g_signal_connect (infobar, "response",
G_CALLBACK (on_response_cb),
window);
return infobar;
}
static void
pack_infobar (GtkWidget *window,
GtkWidget *infobar)
{
GtkWidget *vbox;
vbox = gtk_bin_get_child (GTK_BIN (window));
gtk_box_pack_start (GTK_BOX (vbox), infobar, FALSE, FALSE, 0);
gtk_box_reorder_child (GTK_BOX (vbox), infobar, 2);
}
static gchar *
get_file (const gchar *text,
const gchar *regex_place)
{
GRegex *regex;
GMatchInfo *match_info;
gchar *word = NULL;
regex = g_regex_new (regex_place, 0, 0, NULL);
g_regex_match (regex, text, 0, &match_info);
while (g_match_info_matches (match_info))
{
g_free (word);
word = g_match_info_fetch (match_info, 0);
g_match_info_next (match_info, NULL);
}
g_match_info_free (match_info);
g_regex_unref (regex);
return word;
}
static void
get_numbers (const gchar *version,
gint *major,
gint *minor,
gint *micro)
{
gchar **split;
gint num = 2;
if (micro != NULL)
num = 3;
split = g_strsplit (version, ".", num);
*major = atoi (split[0]);
*minor = atoi (split[1]);
if (micro != NULL)
*micro = atoi (split[2]);
g_strfreev (split);
}
static gboolean
newer_version (const gchar *v1,
const gchar *v2,
gboolean with_micro)
{
gboolean newer = FALSE;
gint major1, minor1, micro1;
gint major2, minor2, micro2;
if (v1 == NULL || v2 == NULL)
return FALSE;
if (with_micro)
{
get_numbers (v1, &major1, &minor1, &micro1);
get_numbers (v2, &major2, &minor2, &micro2);
}
else
{
get_numbers (v1, &major1, &minor1, NULL);
get_numbers (v2, &major2, &minor2, NULL);
}
if (major1 > major2)
{
newer = TRUE;
}
else if (minor1 > minor2 && major1 == major2)
{
newer = TRUE;
}
else if (with_micro && micro1 > micro2 && minor1 == minor2)
{
newer = TRUE;
}
return newer;
}
static gchar *
parse_file_version (const gchar *file)
{
gchar *p, *aux;
p = (gchar *)file;
while (*p != '\0' && !g_ascii_isdigit (*p))
{
p++;
}
if (*p == '\0')
return NULL;
aux = g_strrstr (p, "-");
if (aux == NULL)
aux = g_strrstr (p, ".");
return g_strndup (p, aux - p);
}
static void
parse_page_file (SoupSession *session,
SoupMessage *msg,
GeditWindow *window)
{
if (msg->status_code == SOUP_STATUS_OK)
{
gchar *file;
gchar *file_version;
file = get_file (msg->response_body->data, FILE_REGEX);
file_version = parse_file_version (file);
if (newer_version (file_version, VERSION, TRUE))
{
GtkWidget *infobar;
gchar *file_url;
file_url = g_strconcat (g_object_get_data (G_OBJECT (window), WINDOW_DATA_KEY),
file, NULL);
g_object_set_data_full (G_OBJECT (window),
WINDOW_DATA_KEY,
file_url,
g_free);
infobar = create_infobar (window);
pack_infobar (GTK_WIDGET (window), infobar);
gtk_widget_show (infobar);
}
g_free (file_version);
g_free (file);
}
}
static gboolean
is_unstable (const gchar *version)
{
gchar **split;
gint minor;
gboolean unstable = TRUE;;
split = g_strsplit (version, ".", 2);
minor = atoi (split[1]);
g_strfreev (split);
if ((minor % 2) == 0)
unstable = FALSE;
return unstable;
}
static gchar *
get_file_page_version (const gchar *text,
const gchar *regex_place)
{
GRegex *regex;
GMatchInfo *match_info;
GString *string = NULL;
gchar *unstable = NULL;
gchar *stable = NULL;
regex = g_regex_new (regex_place, 0, 0, NULL);
g_regex_match (regex, text, 0, &match_info);
while (g_match_info_matches (match_info))
{
gint end;
gint i;
g_match_info_fetch_pos (match_info, 0, NULL, &end);
string = g_string_new ("");
i = end;
while (text[i] != '/')
{
string = g_string_append_c (string, text[i]);
i++;
}
if (is_unstable (string->str))
{
g_free (unstable);
unstable = g_string_free (string, FALSE);
}
else
{
g_free (stable);
stable = g_string_free (string, FALSE);
}
g_match_info_next (match_info, NULL);
}
g_match_info_free (match_info);
g_regex_unref (regex);
if ((GEDIT_MINOR_VERSION % 2) == 0)
{
g_free (unstable);
return stable;
}
else
{
/* We need to check that stable isn't newer than unstable */
if (newer_version (stable, unstable, FALSE))
{
g_free (unstable);
return stable;
}
else
{
g_free (stable);
return unstable;
}
}
}
static void
parse_page_version (SoupSession *session,
SoupMessage *msg,
GeditWindow *window)
{
if (msg->status_code == SOUP_STATUS_OK)
{
gchar *version;
gchar *new_url;
SoupMessage *msg2;
version = get_file_page_version (msg->response_body->data,
VERSION_PLACE);
new_url = g_strconcat (GEDIT_URL, version, "/", NULL);
g_free (version);
msg2 = soup_message_new ("GET", new_url);
g_object_set_data_full (G_OBJECT (window),
WINDOW_DATA_KEY,
new_url,
g_free);
soup_session_queue_message (session, msg2,
(SoupSessionCallback)parse_page_file,
window);
}
}
static void
impl_activate (GeditPlugin *plugin,
GeditWindow *window)
{
SoupMessage *msg;
gedit_debug (DEBUG_PLUGINS);
msg = soup_message_new ("GET", GEDIT_URL);
soup_session_queue_message (GEDIT_CHECK_UPDATE_PLUGIN (plugin)->priv->session, msg,
(SoupSessionCallback)parse_page_version,
window);
}
static void
impl_deactivate (GeditPlugin *plugin,
GeditWindow *window)
{
gedit_debug (DEBUG_PLUGINS);
soup_session_abort (GEDIT_CHECK_UPDATE_PLUGIN (plugin)->priv->session);
g_object_set_data (G_OBJECT (window),
WINDOW_DATA_KEY,
NULL);
}
static void
gedit_check_update_plugin_class_init (GeditCheckUpdatePluginClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GeditPluginClass *plugin_class = GEDIT_PLUGIN_CLASS (klass);
g_type_class_add_private (object_class, sizeof (GeditCheckUpdatePluginPrivate));
object_class->finalize = gedit_check_update_plugin_finalize;
object_class->dispose = gedit_check_update_plugin_dispose;
plugin_class->activate = impl_activate;
plugin_class->deactivate = impl_deactivate;
}
/*
* Copyright (C) 2009 - Ignacio Casal Quinteiro <icq@gnome.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/