summaryrefslogtreecommitdiff
path: root/mateweather/src/mateweather-applet.c
diff options
context:
space:
mode:
Diffstat (limited to 'mateweather/src/mateweather-applet.c')
-rw-r--r--mateweather/src/mateweather-applet.c560
1 files changed, 560 insertions, 0 deletions
diff --git a/mateweather/src/mateweather-applet.c b/mateweather/src/mateweather-applet.c
new file mode 100644
index 00000000..efb2c308
--- /dev/null
+++ b/mateweather/src/mateweather-applet.c
@@ -0,0 +1,560 @@
+/* $Id$ */
+
+/*
+ * Papadimitriou Spiros <[email protected]>
+ *
+ * This code released under the GNU GPL.
+ * Read the file COPYING for more information.
+ *
+ * Main applet widget
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include <gio/gio.h>
+#include <mate-panel-applet.h>
+#include <mate-panel-applet-gsettings.h>
+
+#include <gdk/gdkkeysyms.h>
+
+#ifdef HAVE_LIBNOTIFY
+#include <libnotify/notify.h>
+#endif
+
+#define MATEWEATHER_I_KNOW_THIS_IS_UNSTABLE
+
+#include "mateweather.h"
+#include "mateweather-about.h"
+#include "mateweather-pref.h"
+#include "mateweather-dialog.h"
+#include "mateweather-applet.h"
+
+#define MAX_CONSECUTIVE_FAULTS (3)
+
+static void about_cb (GtkAction *action,
+ MateWeatherApplet *gw_applet)
+{
+
+ mateweather_about_run (gw_applet);
+}
+
+static void help_cb (GtkAction *action,
+ MateWeatherApplet *gw_applet)
+{
+ GError *error = NULL;
+
+ gtk_show_uri_on_window (NULL,
+ "help:mateweather",
+ gtk_get_current_event_time (),
+ &error);
+
+ if (error) {
+ GtkWidget *dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
+ _("There was an error displaying help: %s"), error->message);
+ g_signal_connect (dialog, "response",
+ G_CALLBACK (gtk_widget_destroy),
+ NULL);
+ gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
+ gtk_window_set_screen (GTK_WINDOW (dialog), gtk_widget_get_screen (GTK_WIDGET (gw_applet->applet)));
+ gtk_widget_show (dialog);
+ g_error_free (error);
+ error = NULL;
+ }
+}
+
+static void pref_cb (GtkAction *action,
+ MateWeatherApplet *gw_applet)
+{
+ if (gw_applet->pref_dialog) {
+ gtk_window_present (GTK_WINDOW (gw_applet->pref_dialog));
+ } else {
+ gw_applet->pref_dialog = mateweather_pref_new(gw_applet);
+ g_object_add_weak_pointer(G_OBJECT(gw_applet->pref_dialog),
+ (gpointer *)&(gw_applet->pref_dialog));
+ gtk_widget_show_all (gw_applet->pref_dialog);
+ }
+}
+
+static void details_cb (GtkAction *action,
+ MateWeatherApplet *gw_applet)
+{
+ if (gw_applet->details_dialog) {
+ gtk_window_present (GTK_WINDOW (gw_applet->details_dialog));
+ } else {
+ gw_applet->details_dialog = mateweather_dialog_new(gw_applet);
+ g_object_add_weak_pointer(G_OBJECT(gw_applet->details_dialog),
+ (gpointer *)&(gw_applet->details_dialog));
+ mateweather_dialog_update (MATEWEATHER_DIALOG (gw_applet->details_dialog));
+ gtk_widget_show (gw_applet->details_dialog);
+ }
+}
+
+static void update_cb (GtkAction *action,
+ MateWeatherApplet *gw_applet)
+{
+ mateweather_update (gw_applet);
+}
+
+static const GtkActionEntry weather_applet_menu_actions [] = {
+ { "Details", NULL, N_("_Details"),
+ NULL, NULL,
+ G_CALLBACK (details_cb) },
+ { "Update", "view-refresh", N_("_Update"),
+ NULL, NULL,
+ G_CALLBACK (update_cb) },
+ { "Props", "document-properties", N_("_Preferences"),
+ NULL, NULL,
+ G_CALLBACK (pref_cb) },
+ { "Help", "help-browser", N_("_Help"),
+ NULL, NULL,
+ G_CALLBACK (help_cb) },
+ { "About", "help-about", N_("_About"),
+ NULL, NULL,
+ G_CALLBACK (about_cb) }
+};
+
+static void
+place_widgets (MateWeatherApplet *gw_applet)
+{
+ GtkRequisition req;
+ int total_size = 0;
+ gboolean horizontal = FALSE;
+ int panel_size = (int) gw_applet->size;
+ const gchar *temp = NULL;
+ const gchar *icon_name = NULL;
+
+ switch (gw_applet->orient) {
+ case MATE_PANEL_APPLET_ORIENT_LEFT:
+ case MATE_PANEL_APPLET_ORIENT_RIGHT:
+ horizontal = FALSE;
+ break;
+ case MATE_PANEL_APPLET_ORIENT_UP:
+ case MATE_PANEL_APPLET_ORIENT_DOWN:
+ horizontal = TRUE;
+ break;
+ }
+
+ /* Create the weather icon */
+ if ((gw_applet->mateweather_info) && ((icon_name = weather_info_get_icon_name (gw_applet->mateweather_info)) != NULL)) {
+ gw_applet->image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_BUTTON);
+ } else {
+ gw_applet->image = gtk_image_new_from_icon_name ("weather-storm", GTK_ICON_SIZE_BUTTON);;
+ }
+ gtk_widget_show (gw_applet->image);
+ gtk_widget_get_preferred_size (gw_applet->image, &req, NULL);
+ if (horizontal)
+ total_size += req.height;
+ else
+ total_size += req.width;
+
+ /* Update temperature text */
+ if ((gw_applet->mateweather_info != NULL) && ((temp = weather_info_get_temp_summary (gw_applet->mateweather_info)) != NULL))
+ gw_applet->label = gtk_label_new (temp);
+ else
+ gw_applet->label = gtk_label_new(_("?"));
+
+ /* Check the label size to determine box layout */
+ gtk_widget_show (gw_applet->label);
+ gtk_widget_get_preferred_size (gw_applet->label, &req, NULL);
+ if (horizontal)
+ total_size += req.height;
+ else
+ total_size += req.width;
+
+ /* Pack the box */
+ if (gw_applet->box)
+ gtk_widget_destroy (gw_applet->box);
+
+ if (horizontal && (total_size <= panel_size))
+ gw_applet->box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+ else if (horizontal && (total_size > panel_size))
+ gw_applet->box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
+ else if (!horizontal && (total_size <= panel_size))
+ gw_applet->box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
+ else
+ gw_applet->box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+
+ /* better for vertical panels */
+ if (horizontal)
+ gtk_widget_set_valign (gw_applet->box, GTK_ALIGN_CENTER);
+ else
+ gtk_widget_set_halign (gw_applet->box, GTK_ALIGN_CENTER);
+
+ /* Rebuild the applet it's visual area */
+ gtk_container_add (GTK_CONTAINER (gw_applet->applet), gw_applet->box);
+ gtk_box_pack_start (GTK_BOX (gw_applet->box), gw_applet->image, TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (gw_applet->box), gw_applet->label, TRUE, TRUE, 0);
+
+ gtk_widget_show_all (GTK_WIDGET (gw_applet->applet));
+}
+
+static void change_orient_cb (MatePanelApplet *w, MatePanelAppletOrient o, gpointer data)
+{
+ MateWeatherApplet *gw_applet = (MateWeatherApplet *)data;
+
+ gw_applet->orient = o;
+ place_widgets(gw_applet);
+ return;
+}
+
+static void size_allocate_cb(MatePanelApplet *w, GtkAllocation *allocation, gpointer data)
+{
+ guint size;
+ MateWeatherApplet *gw_applet = (MateWeatherApplet *)data;
+
+ switch (gw_applet->orient) {
+ case MATE_PANEL_APPLET_ORIENT_LEFT:
+ case MATE_PANEL_APPLET_ORIENT_RIGHT:
+ size = (guint) allocation->width;
+ break;
+
+ default:
+ size = (guint) allocation->height;
+ }
+
+ if (gw_applet->size == size)
+ return;
+
+ gw_applet->size = size;
+ place_widgets (gw_applet);
+}
+
+static gboolean clicked_cb (GtkWidget *widget, GdkEventButton *ev, gpointer data)
+{
+ MateWeatherApplet *gw_applet = data;
+
+ if ((ev == NULL) || (ev->button != 1))
+ return FALSE;
+
+ if (ev->type == GDK_BUTTON_PRESS) {
+ if (!gw_applet->details_dialog)
+ details_cb (NULL, gw_applet);
+ else
+ gtk_widget_destroy (GTK_WIDGET (gw_applet->details_dialog));
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+key_press_cb (GtkWidget *widget, GdkEventKey *event, MateWeatherApplet *gw_applet)
+{
+ switch (event->keyval) {
+ case GDK_KEY_u:
+ if (event->state == GDK_CONTROL_MASK) {
+ mateweather_update (gw_applet);
+ return TRUE;
+ }
+ break;
+ case GDK_KEY_d:
+ if (event->state == GDK_CONTROL_MASK) {
+ details_cb (NULL, gw_applet);
+ return TRUE;
+ }
+ break;
+ case GDK_KEY_KP_Enter:
+ case GDK_KEY_ISO_Enter:
+ case GDK_KEY_3270_Enter:
+ case GDK_KEY_Return:
+ case GDK_KEY_space:
+ case GDK_KEY_KP_Space:
+ details_cb (NULL, gw_applet);
+ return TRUE;
+ default:
+ break;
+ }
+
+ return FALSE;
+
+}
+
+static void
+network_changed (GNetworkMonitor *monitor, gboolean available, MateWeatherApplet *gw_applet)
+{
+ if (available) {
+ mateweather_update (gw_applet);
+ }
+}
+
+static void
+applet_destroy (GtkWidget *widget, MateWeatherApplet *gw_applet)
+{
+ GNetworkMonitor *monitor;
+
+ if (gw_applet->pref_dialog)
+ gtk_widget_destroy (gw_applet->pref_dialog);
+
+ if (gw_applet->details_dialog)
+ gtk_widget_destroy (gw_applet->details_dialog);
+
+ if (gw_applet->timeout_tag != 0) {
+ g_source_remove (gw_applet->timeout_tag);
+ gw_applet->timeout_tag = 0;
+ }
+
+ if (gw_applet->suncalc_timeout_tag != 0) {
+ g_source_remove (gw_applet->suncalc_timeout_tag);
+ gw_applet->suncalc_timeout_tag = 0;
+ }
+
+ if (gw_applet->settings) {
+ g_object_unref (gw_applet->settings);
+ gw_applet->settings = NULL;
+ }
+
+ monitor = g_network_monitor_get_default ();
+ g_signal_handlers_disconnect_by_func (monitor,
+ G_CALLBACK (network_changed),
+ gw_applet);
+
+ weather_info_abort (gw_applet->mateweather_info);
+}
+
+void mateweather_applet_create (MateWeatherApplet *gw_applet)
+{
+ GtkActionGroup *action_group;
+ AtkObject *atk_obj;
+ GNetworkMonitor*monitor;
+
+ gw_applet->mateweather_pref.location = NULL;
+ gw_applet->mateweather_pref.show_notifications = FALSE;
+ gw_applet->mateweather_pref.update_interval = 1800;
+ gw_applet->mateweather_pref.update_enabled = TRUE;
+ gw_applet->mateweather_pref.detailed = FALSE;
+ gw_applet->mateweather_pref.radar_enabled = TRUE;
+ gw_applet->mateweather_pref.temperature_unit = TEMP_UNIT_INVALID;
+ gw_applet->mateweather_pref.speed_unit = SPEED_UNIT_INVALID;
+ gw_applet->mateweather_pref.pressure_unit = PRESSURE_UNIT_INVALID;
+ gw_applet->mateweather_pref.distance_unit = DISTANCE_UNIT_INVALID;
+
+ mate_panel_applet_set_flags (gw_applet->applet, MATE_PANEL_APPLET_EXPAND_MINOR);
+
+#ifndef ENABLE_IN_PROCESS
+ g_set_application_name (_("Weather Report"));
+#endif
+
+ gtk_window_set_default_icon_name ("weather-storm");
+
+ g_signal_connect (gw_applet->applet, "change-orient",
+ G_CALLBACK (change_orient_cb),
+ gw_applet);
+
+ g_signal_connect (gw_applet->applet, "size-allocate",
+ G_CALLBACK (size_allocate_cb),
+ gw_applet);
+
+ g_signal_connect (gw_applet->applet, "destroy",
+ G_CALLBACK (applet_destroy),
+ gw_applet);
+
+ g_signal_connect (gw_applet->applet, "button-press-event",
+ G_CALLBACK(clicked_cb),
+ gw_applet);
+
+ g_signal_connect (gw_applet->applet, "key-press-event",
+ G_CALLBACK (key_press_cb),
+ gw_applet);
+
+ gtk_widget_set_tooltip_text (GTK_WIDGET(gw_applet->applet), _("MATE Weather"));
+
+ atk_obj = gtk_widget_get_accessible (GTK_WIDGET (gw_applet->applet));
+ if (GTK_IS_ACCESSIBLE (atk_obj))
+ atk_object_set_name (atk_obj, _("MATE Weather"));
+
+ gw_applet->size = mate_panel_applet_get_size (gw_applet->applet);
+
+ gw_applet->orient = mate_panel_applet_get_orient (gw_applet->applet);
+
+ action_group = gtk_action_group_new ("MateWeather Applet Actions");
+ gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
+ gtk_action_group_add_actions (action_group,
+ weather_applet_menu_actions,
+ G_N_ELEMENTS (weather_applet_menu_actions),
+ gw_applet);
+ mate_panel_applet_setup_menu_from_resource (gw_applet->applet,
+ WEATHER_RESOURCE_PATH "mateweather-applet-menu.xml",
+ action_group);
+
+ if (mate_panel_applet_get_locked_down (gw_applet->applet)) {
+ GtkAction *action;
+
+ action = gtk_action_group_get_action (action_group, "Props");
+ gtk_action_set_visible (action, FALSE);
+ }
+ g_object_unref (action_group);
+
+ place_widgets(gw_applet);
+
+ monitor = g_network_monitor_get_default();
+ g_signal_connect (monitor, "network-changed",
+ G_CALLBACK (network_changed),
+ gw_applet);
+}
+
+gint timeout_cb (gpointer data)
+{
+ MateWeatherApplet *gw_applet = (MateWeatherApplet *)data;
+
+ mateweather_update(gw_applet);
+ return 0; /* Do not repeat timeout (will be reset by mateweather_update) */
+}
+
+static void
+update_finish (WeatherInfo *info, gpointer data)
+{
+ static int gw_fault_counter = 0;
+#ifdef HAVE_LIBNOTIFY
+ char *message, *detail;
+#endif
+ MateWeatherApplet *gw_applet = (MateWeatherApplet *)data;
+
+ /* Update timer */
+ if (gw_applet->timeout_tag > 0)
+ g_source_remove(gw_applet->timeout_tag);
+ if (gw_applet->mateweather_pref.update_enabled)
+ {
+ gint nxtSunEvent;
+
+ gw_applet->timeout_tag
+ = g_timeout_add_seconds ((guint) gw_applet->mateweather_pref.update_interval,
+ timeout_cb, gw_applet);
+
+ if ((info != NULL) && ((nxtSunEvent = weather_info_next_sun_event (info)) >= 0))
+ {
+ gw_applet->suncalc_timeout_tag
+ = g_timeout_add_seconds ((guint) nxtSunEvent,
+ suncalc_timeout_cb, gw_applet);
+ }
+ }
+
+ if ((info != NULL) && weather_info_is_valid (info))
+ {
+ char *s;
+
+ gw_fault_counter = 0;
+
+ /* update tooltip */
+ s = weather_info_get_weather_summary (info);
+ gtk_widget_set_tooltip_text (GTK_WIDGET (gw_applet->applet), s);
+ g_free (s);
+
+ /* Update dialog -- if one is present */
+ if (gw_applet->details_dialog)
+ mateweather_dialog_update (MATEWEATHER_DIALOG (gw_applet->details_dialog));
+
+ /* update applet */
+ place_widgets (gw_applet);
+
+#ifdef HAVE_LIBNOTIFY
+ if (gw_applet->mateweather_pref.show_notifications)
+ {
+ NotifyNotification *n;
+
+ /* Show notifications if possible */
+ if (!notify_is_initted ())
+ notify_init (_("Weather Forecast"));
+
+ if (notify_is_initted ())
+ {
+ GError *error = NULL;
+ const char *icon;
+
+ /* Show notification */
+ message = g_strdup_printf ("%s: %s",
+ weather_info_get_location_name (info),
+ weather_info_get_sky (info));
+ detail = g_strdup_printf (_("City: %s\nSky: %s\nTemperature: %s"),
+ weather_info_get_location_name (info),
+ weather_info_get_sky (info),
+ weather_info_get_temp_summary (info));
+
+ icon = weather_info_get_icon_name (gw_applet->mateweather_info);
+ if (icon == NULL)
+ icon = "stock-unknown";
+
+ n = notify_notification_new (message, detail, icon);
+
+ notify_notification_show (n, &error);
+ if (error)
+ {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ }
+
+ g_free (message);
+ g_free (detail);
+ }
+ }
+#endif
+ } else {
+ if (gw_fault_counter >= MAX_CONSECUTIVE_FAULTS) {
+ gw_fault_counter = 0;
+
+ /* Update dialog -- if one is present */
+ if (gw_applet->details_dialog)
+ mateweather_dialog_update (MATEWEATHER_DIALOG (gw_applet->details_dialog));
+
+ /* update applet */
+ place_widgets (gw_applet);
+ } else {
+ /* there has been an error during retrival
+ * just update the fault counter
+ */
+ gw_fault_counter++;
+ }
+ }
+}
+
+gint suncalc_timeout_cb (gpointer data)
+{
+ WeatherInfo *info = ((MateWeatherApplet *)data)->mateweather_info;
+ update_finish(info, data);
+ return 0; /* Do not repeat timeout (will be reset by update_finish) */
+}
+
+void mateweather_update (MateWeatherApplet *gw_applet)
+{
+ WeatherPrefs prefs;
+
+ gtk_widget_set_tooltip_text (GTK_WIDGET(gw_applet->applet), _("Updating..."));
+
+ /* Set preferred forecast type */
+ prefs.type = gw_applet->mateweather_pref.detailed ? FORECAST_ZONE : FORECAST_STATE;
+
+ /* Set radar map retrieval option */
+ prefs.radar = gw_applet->mateweather_pref.radar_enabled;
+ prefs.radar_custom_url = (gw_applet->mateweather_pref.use_custom_radar_url &&
+ gw_applet->mateweather_pref.radar) ?
+ gw_applet->mateweather_pref.radar : NULL;
+
+ /* Set the units */
+ prefs.temperature_unit = gw_applet->mateweather_pref.temperature_unit;
+ prefs.speed_unit = gw_applet->mateweather_pref.speed_unit;
+ prefs.pressure_unit = gw_applet->mateweather_pref.pressure_unit;
+ prefs.distance_unit = gw_applet->mateweather_pref.distance_unit;
+
+ /* Update current conditions */
+ if (gw_applet->mateweather_info &&
+ weather_location_equal(weather_info_get_location(gw_applet->mateweather_info),
+ gw_applet->mateweather_pref.location)) {
+ weather_info_update(gw_applet->mateweather_info, &prefs,
+ update_finish, gw_applet);
+ } else {
+ weather_info_free(gw_applet->mateweather_info);
+ gw_applet->mateweather_info = weather_info_new(gw_applet->mateweather_pref.location,
+ &prefs,
+ update_finish, gw_applet);
+ }
+}