Permalink
Fetching contributors…
Cannot retrieve contributors at this time
551 lines (454 sloc) 16.7 KB
/* $Id$ */
/*
* Papadimitriou Spiros <spapadim+@cs.cmu.edu>
*
* 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
#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 (gtk_widget_get_screen (GTK_WIDGET (gw_applet->applet)),
"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 (G_OBJECT (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", GTK_STOCK_REFRESH, N_("_Update"),
NULL, NULL,
G_CALLBACK (update_cb) },
{ "Props", GTK_STOCK_PROPERTIES, N_("_Preferences"),
NULL, NULL,
G_CALLBACK (pref_cb) },
{ "Help", GTK_STOCK_HELP, N_("_Help"),
NULL, NULL,
G_CALLBACK (help_cb) },
{ "About", GTK_STOCK_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 = gw_applet->size;
const gchar *temp;
const gchar *icon_name;
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 */
icon_name = weather_info_get_icon_name (gw_applet->mateweather_info);
gw_applet->image = gtk_image_new_from_icon_name(icon_name, GTK_ICON_SIZE_BUTTON);
if (icon_name != NULL) {
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;
}
/* Create the temperature label */
gw_applet->label = gtk_label_new("0\302\260F");
/* Update temperature text */
temp = weather_info_get_temp_summary(gw_applet->mateweather_info);
if (temp)
gtk_label_set_text(GTK_LABEL(gw_applet->label), temp);
/* 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);
/* Rebuild the applet it's visual area */
gtk_container_add (GTK_CONTAINER (gw_applet->container), 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)
{
MateWeatherApplet *gw_applet = (MateWeatherApplet *)data;
if ((gw_applet->orient == MATE_PANEL_APPLET_ORIENT_LEFT) || (gw_applet->orient == MATE_PANEL_APPLET_ORIENT_RIGHT)) {
if (gw_applet->size == allocation->width)
return;
gw_applet->size = allocation->width;
} else {
if (gw_applet->size == allocation->height)
return;
gw_applet->size = allocation->height;
}
place_widgets(gw_applet);
return;
}
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;
gchar *ui_path;
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);
mate_panel_applet_set_background_widget(gw_applet->applet,
GTK_WIDGET(gw_applet->applet));
g_set_application_name (_("Weather Report"));
gtk_window_set_default_icon_name ("weather-storm");
gw_applet->container = gtk_alignment_new (0.5, 0.5, 0, 0);
gtk_container_add (GTK_CONTAINER (gw_applet->applet), gw_applet->container);
g_signal_connect (G_OBJECT(gw_applet->applet), "change_orient",
G_CALLBACK(change_orient_cb), gw_applet);
g_signal_connect (G_OBJECT(gw_applet->applet), "size_allocate",
G_CALLBACK(size_allocate_cb), gw_applet);
g_signal_connect (G_OBJECT(gw_applet->applet), "destroy",
G_CALLBACK (applet_destroy), gw_applet);
g_signal_connect (G_OBJECT(gw_applet->applet), "button_press_event",
G_CALLBACK(clicked_cb), gw_applet);
g_signal_connect (G_OBJECT(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);
ui_path = g_build_filename (MATEWEATHER_MENU_UI_DIR, "mateweather-applet-menu.xml", NULL);
mate_panel_applet_setup_menu_from_file (gw_applet->applet,
ui_path, action_group);
g_free (ui_path);
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
char *s;
MateWeatherApplet *gw_applet = (MateWeatherApplet *)data;
gint nxtSunEvent;
const gchar *icon_name;
/* Update timer */
if (gw_applet->timeout_tag > 0)
g_source_remove(gw_applet->timeout_tag);
if (gw_applet->mateweather_pref.update_enabled)
{
gw_applet->timeout_tag =
g_timeout_add_seconds (
gw_applet->mateweather_pref.update_interval,
timeout_cb, gw_applet);
nxtSunEvent = weather_info_next_sun_event(gw_applet->mateweather_info);
if (nxtSunEvent >= 0)
gw_applet->suncalc_timeout_tag =
g_timeout_add_seconds (nxtSunEvent,
suncalc_timeout_cb, gw_applet);
}
if ((TRUE == weather_info_is_valid (info)) ||
(gw_fault_counter >= MAX_CONSECUTIVE_FAULTS))
{
gw_fault_counter = 0;
icon_name = weather_info_get_icon_name (gw_applet->mateweather_info);
gtk_image_set_from_icon_name (GTK_IMAGE(gw_applet->image),
icon_name, GTK_ICON_SIZE_BUTTON);
gtk_label_set_text (GTK_LABEL (gw_applet->label),
weather_info_get_temp_summary(
gw_applet->mateweather_info));
s = weather_info_get_weather_summary (gw_applet->mateweather_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
{
/* 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;
const gchar *icon_name;
icon_name = weather_info_get_icon_name(gw_applet->mateweather_info);
gtk_image_set_from_icon_name (GTK_IMAGE (gw_applet->image),
icon_name, GTK_ICON_SIZE_BUTTON);
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);
}
}