/* $Id$ */ /* * Papadimitriou Spiros * * This code released under the GNU GPL. * Read the file COPYING for more information. * * Main applet widget * */ #ifdef HAVE_CONFIG_H #include #endif /* HAVE_CONFIG_H */ #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_LIBNOTIFY #include #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 (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", "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 = 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) { 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; 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); g_set_application_name (_("Weather Report")); gtk_window_set_default_icon_name ("weather-storm"); 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); 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 (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 (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); } }