weather-summary.c 31.2 KB
Newer Older
1
/*  Copyright (c) 2003-2012 Xfce Development Team
2
 *
3 4 5 6
 * 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 of the License, or
 * (at your option) any later version.
7
 *
8 9 10 11
 * 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.
12
 *
13 14 15 16
 * 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., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
17 18 19
 */

#ifdef HAVE_CONFIG_H
20
#include <config.h>
21 22
#endif

23
#include <libxfce4ui/libxfce4ui.h>
24

Nick Schermer's avatar
Nick Schermer committed
25 26 27 28 29 30
#include "weather-parsers.h"
#include "weather-data.h"
#include "weather.h"
#include "weather-summary.h"
#include "weather-translate.h"
#include "weather-icon.h"
31

32

33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
static gboolean
lnk_clicked(GtkTextTag *tag,
            GObject *obj,
            GdkEvent *event,
            GtkTextIter *iter,
            GtkWidget *textview);


#define BORDER 8

#define APPEND_BTEXT(text)                                          \
    gtk_text_buffer_insert_with_tags(GTK_TEXT_BUFFER(buffer),       \
                                     &iter, text, -1, btag, NULL);

#define APPEND_TEXT_ITEM_REAL(text)                 \
    gtk_text_buffer_insert(GTK_TEXT_BUFFER(buffer), \
                           &iter, text, -1);        \
    g_free(value);

#define APPEND_TEXT_ITEM(text, item)                            \
53 54
    rawvalue = get_data(conditions, data->units, item, FALSE);  \
    unit = get_unit(data->units, item);                         \
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
    value = g_strdup_printf("\t%s%s%s%s%s\n",                   \
                            text, text ? ": " : "",             \
                            rawvalue,                           \
                            strcmp(unit, "°") ? " " : "",       \
                            unit);                              \
    g_free(rawvalue);                                           \
    APPEND_TEXT_ITEM_REAL(value);

#define APPEND_LINK_ITEM(prefix, text, url, lnk_tag)                    \
    gtk_text_buffer_insert(GTK_TEXT_BUFFER(buffer),                     \
                           &iter, prefix, -1);                          \
    gtk_text_buffer_insert_with_tags(GTK_TEXT_BUFFER(buffer),           \
                                     &iter, text, -1, lnk_tag, NULL);   \
    gtk_text_buffer_insert(GTK_TEXT_BUFFER(buffer),                     \
                           &iter, "\n", -1);                            \
    g_object_set_data_full(G_OBJECT(lnk_tag), "url", g_strdup(url), g_free); \
    g_signal_connect(G_OBJECT(lnk_tag), "event",                        \
                     G_CALLBACK(lnk_clicked), NULL);
73

Harald Judt's avatar
Harald Judt committed
74 75 76 77 78 79 80 81 82 83 84 85
#define ATTACH_DAYTIME_HEADER(title, pos)               \
    if (data->forecast_layout == FC_LAYOUT_CALENDAR)    \
        gtk_table_attach_defaults                       \
            (GTK_TABLE(table),                          \
             add_forecast_header(title, 90.0, &darkbg), \
             0, 1, pos, pos+1);                         \
    else                                                \
        gtk_table_attach_defaults                       \
            (GTK_TABLE(table),                          \
             add_forecast_header(title, 0.0, &darkbg),  \
             pos, pos+1, 0, 1);                         \

86

87 88 89 90 91 92
static gboolean
lnk_clicked(GtkTextTag *tag,
            GObject *obj,
            GdkEvent *event,
            GtkTextIter *iter,
            GtkWidget *textview)
93
{
94 95
    const gchar *url;
    gchar *str;
96

97 98 99 100 101 102 103 104 105 106
    if (event->type == GDK_BUTTON_RELEASE) {
        url = g_object_get_data(G_OBJECT(tag), "url");
        str = g_strdup_printf("exo-open --launch WebBrowser %s", url);
        g_spawn_command_line_async(str, NULL);
        g_free(str);
    } else if (event->type == GDK_LEAVE_NOTIFY)
        gdk_window_set_cursor(gtk_text_view_get_window(GTK_TEXT_VIEW(obj),
                                                       GTK_TEXT_WINDOW_TEXT),
                              NULL);
    return FALSE;
107 108
}

109

110
static gboolean
111
icon_clicked (GtkWidget *widget,
112
              GdkEventButton *event,
113
              gpointer user_data)
114
{
115
    return lnk_clicked(user_data, NULL, (GdkEvent *) (event), NULL, NULL);
116 117
}

118 119 120 121

static gboolean
view_motion_notify(GtkWidget *widget,
                   GdkEventMotion *event,
Harald Judt's avatar
Harald Judt committed
122
                   summary_details *sum)
123
{
Harald Judt's avatar
Harald Judt committed
124 125 126 127 128
    GtkTextIter iter;
    GtkTextTag *tag;
    GSList *tags;
    GSList *cur;
    gint bx, by;
129

Harald Judt's avatar
Harald Judt committed
130
    if (event->x != -1 && event->y != -1) {
Harald Judt's avatar
Harald Judt committed
131
        gtk_text_view_window_to_buffer_coords(GTK_TEXT_VIEW(sum->text_view),
132 133
                                              GTK_TEXT_WINDOW_WIDGET,
                                              event->x, event->y, &bx, &by);
Harald Judt's avatar
Harald Judt committed
134
        gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(sum->text_view),
135 136 137
                                           &iter, bx, by);
        tags = gtk_text_iter_get_tags(&iter);
        for (cur = tags; cur != NULL; cur = cur->next) {
Harald Judt's avatar
Harald Judt committed
138
            tag = cur->data;
139
            if (g_object_get_data(G_OBJECT(tag), "url")) {
Harald Judt's avatar
Harald Judt committed
140 141 142 143
                gdk_window_set_cursor
                    (gtk_text_view_get_window(GTK_TEXT_VIEW(sum->text_view),
                                              GTK_TEXT_WINDOW_TEXT),
                     sum->hand_cursor);
144 145 146
                return FALSE;
            }
        }
147
    }
Harald Judt's avatar
Harald Judt committed
148 149 150 151 152
    if (!sum->on_icon)
        gdk_window_set_cursor
            (gtk_text_view_get_window(GTK_TEXT_VIEW(sum->text_view),
                                      GTK_TEXT_WINDOW_TEXT),
             sum->text_cursor);
153
    return FALSE;
154 155
}

156 157 158 159

static gboolean
icon_motion_notify(GtkWidget *widget,
                   GdkEventMotion *event,
Harald Judt's avatar
Harald Judt committed
160
                   summary_details *sum)
161
{
Harald Judt's avatar
Harald Judt committed
162 163 164 165 166
    sum->on_icon = TRUE;
    gdk_window_set_cursor
        (gtk_text_view_get_window(GTK_TEXT_VIEW(sum->text_view),
                                  GTK_TEXT_WINDOW_TEXT),
         sum->hand_cursor);
167
    return FALSE;
168 169
}

170 171 172 173

static gboolean
view_leave_notify(GtkWidget *widget,
                  GdkEventMotion *event,
Harald Judt's avatar
Harald Judt committed
174
                  summary_details *sum)
175
{
Harald Judt's avatar
Harald Judt committed
176 177 178 179 180
    sum->on_icon = FALSE;
    gdk_window_set_cursor
        (gtk_text_view_get_window(GTK_TEXT_VIEW(sum->text_view),
                                  GTK_TEXT_WINDOW_TEXT),
         sum->text_cursor);
181
    return FALSE;
182 183
}

184 185 186

static void
view_scrolled_cb(GtkAdjustment *adj,
Harald Judt's avatar
Harald Judt committed
187
                 summary_details *sum)
188
{
Harald Judt's avatar
Harald Judt committed
189 190
    gint x, y, x1, y1;

Harald Judt's avatar
Harald Judt committed
191 192 193 194
    if (sum->icon_ebox) {
        x1 = sum->text_view->allocation.width - 191 - 15;
        y1 = sum->text_view->requisition.height - 60 - 15;
        gtk_text_view_buffer_to_window_coords(GTK_TEXT_VIEW(sum->text_view),
195 196
                                              GTK_TEXT_WINDOW_TEXT,
                                              x1, y1, &x, &y);
Harald Judt's avatar
Harald Judt committed
197 198
        gtk_text_view_move_child(GTK_TEXT_VIEW(sum->text_view),
                                 sum->icon_ebox, x, y);
199
    }
200 201
}

202 203 204 205 206

static void
view_size_allocate_cb(GtkWidget *widget,
                      GtkAllocation *allocation,
                      gpointer data)
207
{
Harald Judt's avatar
Harald Judt committed
208
    view_scrolled_cb(NULL, data);
209
}
210

211 212 213

static gchar *
get_logo_path(void)
214
{
215 216 217 218 219 220 221
    gchar *cache_dir, *logo_path;

    cache_dir = get_cache_directory();
    logo_path = g_strconcat(cache_dir, G_DIR_SEPARATOR_S,
                            "weather_logo.gif", NULL);
    g_free(cache_dir);
    return logo_path;
222 223
}

224

225
static void
226 227 228
logo_fetched(SoupSession *session,
             SoupMessage *msg,
             gpointer user_data)
229
{
230
    if (msg && msg->response_body && msg->response_body->length > 0) {
231 232 233
        gchar *path = get_logo_path();
        GError *error = NULL;
        GdkPixbuf *pixbuf = NULL;
234 235 236 237
        if (!g_file_set_contents(path, msg->response_body->data,
                                 msg->response_body->length, &error)) {
            g_warning("Error downloading met.no logo image to %s, "
                      "err %s\n", path, error ? error->message : "?");
238 239 240 241 242 243 244 245 246 247 248
            g_error_free(error);
            g_free(path);
            return;
        }
        pixbuf = gdk_pixbuf_new_from_file(path, NULL);
        g_free(path);
        if (pixbuf) {
            gtk_image_set_from_pixbuf(GTK_IMAGE(user_data), pixbuf);
            g_object_unref(pixbuf);
        }
    }
249 250
}

251 252

static GtkWidget *
253
weather_summary_get_logo(plugin_data *data)
254
{
255
    GtkWidget *image = gtk_image_new();
Harald Judt's avatar
Harald Judt committed
256
    GdkPixbuf *pixbuf;
257 258 259 260 261
    gchar *path = get_logo_path();

    pixbuf = gdk_pixbuf_new_from_file(path, NULL);
    g_free(path);
    if (pixbuf == NULL)
262 263
        weather_http_queue_request(data->session,
                                   "http://met.no/filestore/met.no-logo.gif",
264
                                   logo_fetched, image);
265 266 267 268 269
    else {
        gtk_image_set_from_pixbuf(GTK_IMAGE(image), pixbuf);
        g_object_unref(pixbuf);
    }
    return image;
270
}
271

272

273
static GtkWidget *
274
create_summary_tab(plugin_data *data)
275
{
276 277 278
    GtkTextBuffer *buffer;
    GtkTextIter iter;
    GtkTextTag *btag, *ltag0, *ltag1;
Harald Judt's avatar
Harald Judt committed
279
    GtkWidget *view, *frame, *scrolled, *icon;
280 281 282 283 284
    GtkAdjustment *adj;
    GdkColor lnk_color;
    xml_time *conditions;
    const gchar *unit;
    struct tm *start_tm, *end_tm, *point_tm;
285
    struct tm *sunrise_tm, *sunset_tm, *moonrise_tm, *moonset_tm;
Harald Judt's avatar
Harald Judt committed
286
    gchar *value, *rawvalue, *wind;
287 288
    gchar interval_start[80], interval_end[80], point[80];
    gchar sunrise[80], sunset[80], moonrise[80], moonset[80];
Harald Judt's avatar
Harald Judt committed
289
    summary_details *sum;
290

Harald Judt's avatar
Harald Judt committed
291 292 293 294 295 296 297
    sum = g_slice_new0(summary_details);
    sum->on_icon = FALSE;
    sum->hand_cursor = gdk_cursor_new(GDK_HAND2);
    sum->text_cursor = gdk_cursor_new(GDK_XTERM);
    data->summary_details = sum;

    sum->text_view = view = gtk_text_view_new();
298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346
    gtk_text_view_set_editable(GTK_TEXT_VIEW(view), FALSE);
    gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(view), FALSE);
    frame = gtk_frame_new(NULL);
    scrolled = gtk_scrolled_window_new(NULL, NULL);

    gtk_container_add(GTK_CONTAINER(scrolled), view);
    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
                                   GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);

    gtk_container_set_border_width(GTK_CONTAINER(frame), BORDER);
    gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
    gtk_container_add(GTK_CONTAINER(frame), scrolled);

    buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view));
    gtk_text_buffer_get_iter_at_offset(GTK_TEXT_BUFFER(buffer), &iter, 0);
    btag = gtk_text_buffer_create_tag(buffer, NULL, "weight",
                                      PANGO_WEIGHT_BOLD, NULL);

    gdk_color_parse("#0000ff", &lnk_color);
    ltag0 = gtk_text_buffer_create_tag(buffer, "lnk0",
                                       "foreground-gdk", &lnk_color, NULL);
    ltag1 = gtk_text_buffer_create_tag(buffer, "lnk1",
                                       "foreground-gdk", &lnk_color, NULL);

    /* head */
    value = g_strdup_printf(_("Weather report for: %s.\n\n"),
                            data->location_name);
    APPEND_BTEXT(value);
    g_free(value);

    conditions = get_current_conditions(data->weatherdata);
    APPEND_BTEXT(_("Coordinates\n"));
    APPEND_TEXT_ITEM(_("Altitude"), ALTITUDE);
    APPEND_TEXT_ITEM(_("Latitude"), LATITUDE);
    APPEND_TEXT_ITEM(_("Longitude"), LONGITUDE);

    APPEND_BTEXT(_("\nTime\n"));
    point_tm = localtime(&conditions->point);
    strftime(point, 80, "%c", point_tm);
    value = g_strdup_printf
        (_("\tTemperature, wind, atmosphere and cloud data apply to:\n\t%s\n"),
         point);
    APPEND_TEXT_ITEM_REAL(value);

    start_tm = localtime(&conditions->start);
    strftime(interval_start, 80, "%c", start_tm);
    end_tm = localtime(&conditions->end);
    strftime(interval_end, 80, "%c", end_tm);
    value = g_strdup_printf
Harald Judt's avatar
Harald Judt committed
347 348 349 350
        (_("\n\tPrecipitation and the weather symbol have been calculated\n"
           "\tfor the following time interval:\n"
           "\tStart:\t%s\n"
           "\tEnd:\t%s\n"),
351 352 353 354
         interval_start,
         interval_end);
    APPEND_TEXT_ITEM_REAL(value);

355
    /* sun and moon */
356
    APPEND_BTEXT(_("\nAstronomical Data\n"));
357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406
    if (data->astrodata) {
        if (data->astrodata->sun_never_rises) {
            value = g_strdup(_("\tSunrise:\t\tThe sun never rises today.\n"));
            APPEND_TEXT_ITEM_REAL(value);
        } else if (data->astrodata->sun_never_sets) {
            value = g_strdup(_("\tSunset:\t\tThe sun never sets today.\n"));
            APPEND_TEXT_ITEM_REAL(value);
        } else {
            sunrise_tm = localtime(&data->astrodata->sunrise);
            strftime(sunrise, 80, "%c", sunrise_tm);
            value = g_strdup_printf(_("\tSunrise:\t\t%s\n"), sunrise);
            APPEND_TEXT_ITEM_REAL(value);

            sunset_tm = localtime(&data->astrodata->sunset);
            strftime(sunset, 80, "%c", sunset_tm);
            value = g_strdup_printf(_("\tSunset:\t\t%s\n\n"), sunset);
            APPEND_TEXT_ITEM_REAL(value);
        }

        if (data->astrodata->moon_phase)
            value = g_strdup_printf(_("\tMoon phase:\t%s\n"),
                                    translate_moon_phase
                                    (data->astrodata->moon_phase));
        else
            value = g_strdup(_("\tMoon phase:\tUnknown\n"));
        APPEND_TEXT_ITEM_REAL(value);

        if (data->astrodata->moon_never_rises) {
            value = g_strdup(_("\tMoonrise:\tThe moon never rises today.\n"));
            APPEND_TEXT_ITEM_REAL(value);
        } else if (data->astrodata->moon_never_sets) {
            value = g_strdup(_("\tMoonset:\tThe moon never sets today.\n"));
            APPEND_TEXT_ITEM_REAL(value);
        } else {
            moonrise_tm = localtime(&data->astrodata->moonrise);
            strftime(moonrise, 80, "%c", moonrise_tm);
            value = g_strdup_printf(_("\tMoonrise:\t%s\n"), moonrise);
            APPEND_TEXT_ITEM_REAL(value);

            moonset_tm = localtime(&data->astrodata->moonset);
            strftime(moonset, 80, "%c", moonset_tm);
            value = g_strdup_printf(_("\tMoonset:\t%s\n"), moonset);
            APPEND_TEXT_ITEM_REAL(value);
        }
    } else {
        value = g_strdup(_("\tData not available, will use sane "
                           "default values for night and day.\n"));
        APPEND_TEXT_ITEM_REAL(value);
    }

407 408 409 410 411 412
    /* temperature */
    APPEND_BTEXT(_("\nTemperature\n"));
    APPEND_TEXT_ITEM(_("Temperature"), TEMPERATURE);

    /* wind */
    APPEND_BTEXT(_("\nWind\n"));
413
    wind = get_data(conditions, data->units, WIND_SPEED, FALSE);
414
    rawvalue = get_data(conditions, data->units, WIND_BEAUFORT, FALSE);
415 416 417 418
    value = g_strdup_printf(_("\t%s: %s %s (%s on the Beaufort scale)\n"),
                            _("Speed"), wind,
                            get_unit(data->units, WIND_SPEED),
                            rawvalue);
419 420 421 422
    g_free(rawvalue);
    g_free(wind);
    APPEND_TEXT_ITEM_REAL(value);

423
    rawvalue = get_data(conditions, data->units, WIND_DIRECTION, FALSE);
424 425
    wind = translate_wind_direction(rawvalue);
    g_free(rawvalue);
426
    rawvalue = get_data(conditions, data->units, WIND_DIRECTION_DEG, FALSE);
427 428
    value = g_strdup_printf("\t%s: %s (%s%s)\n", _("Direction"),
                            wind, rawvalue,
429
                            get_unit(data->units, WIND_DIRECTION_DEG));
430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456
    g_free(rawvalue);
    g_free(wind);
    APPEND_TEXT_ITEM_REAL(value);

    /* precipitation */
    APPEND_BTEXT(_("\nPrecipitations\n"));
    APPEND_TEXT_ITEM(_("Precipitations amount"), PRECIPITATIONS);

    /* atmosphere */
    APPEND_BTEXT(_("\nAtmosphere\n"));
    APPEND_TEXT_ITEM(_("Pressure"), PRESSURE);
    APPEND_TEXT_ITEM(_("Humidity"), HUMIDITY);

    /* clouds */
    APPEND_BTEXT(_("\nClouds\n"));
    APPEND_TEXT_ITEM(_("Fog"), FOG);
    APPEND_TEXT_ITEM(_("Low clouds"), CLOUDS_LOW);
    APPEND_TEXT_ITEM(_("Medium clouds"), CLOUDS_MED);
    APPEND_TEXT_ITEM(_("High clouds"), CLOUDS_HIGH);
    APPEND_TEXT_ITEM(_("Cloudiness"), CLOUDINESS);

    APPEND_BTEXT(_("\nData from The Norwegian Meteorological Institute\n"));
    value = g_strdup("http://met.no");
    g_object_set_data_full(G_OBJECT(ltag0), "url", value, g_free);
    APPEND_LINK_ITEM("\t", _("Thanks to met.no"), "http://met.no/", ltag1);

    g_signal_connect(G_OBJECT(view), "motion-notify-event",
Harald Judt's avatar
Harald Judt committed
457
                     G_CALLBACK(view_motion_notify), sum);
458
    g_signal_connect(G_OBJECT(view), "leave-notify-event",
Harald Judt's avatar
Harald Judt committed
459
                     G_CALLBACK(view_leave_notify), sum);
460

Harald Judt's avatar
Harald Judt committed
461
    icon = weather_summary_get_logo(data);
462

Harald Judt's avatar
Harald Judt committed
463 464
    if (icon) {
        sum->icon_ebox = gtk_event_box_new();
465 466
        gtk_event_box_set_visible_window(GTK_EVENT_BOX(sum->icon_ebox), FALSE);
        gtk_container_add(GTK_CONTAINER(sum->icon_ebox), icon);
467
        gtk_text_view_add_child_in_window(GTK_TEXT_VIEW(view),
Harald Judt's avatar
Harald Judt committed
468
                                          sum->icon_ebox,
469
                                          GTK_TEXT_WINDOW_TEXT, 0, 0);
Harald Judt's avatar
Harald Judt committed
470
        gtk_widget_show_all(sum->icon_ebox);
471 472 473
        adj =
            gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(scrolled));
        g_signal_connect(G_OBJECT(adj), "value-changed",
Harald Judt's avatar
Harald Judt committed
474
                         G_CALLBACK(view_scrolled_cb), sum);
475
        g_signal_connect(G_OBJECT(view), "size_allocate",
Harald Judt's avatar
Harald Judt committed
476 477 478 479 480 481 482 483 484
                         G_CALLBACK(view_size_allocate_cb), sum);
        g_signal_connect(G_OBJECT(sum->icon_ebox), "button-release-event",
                         G_CALLBACK(icon_clicked), ltag0);
        g_signal_connect(G_OBJECT(sum->icon_ebox), "enter-notify-event",
                         G_CALLBACK(icon_motion_notify), sum);
        g_signal_connect(G_OBJECT(sum->icon_ebox), "motion-notify-event",
                         G_CALLBACK(icon_motion_notify), sum);
        g_signal_connect(G_OBJECT(sum->icon_ebox), "leave-notify-event",
                         G_CALLBACK(view_leave_notify), sum);
485
    }
Harald Judt's avatar
Harald Judt committed
486

487
    return frame;
488
}
489

490

Harald Judt's avatar
Harald Judt committed
491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511
static gchar *
get_dayname(gint day)
{
    struct tm fcday_tm;
    time_t now_t = time(NULL), fcday_t;
    gint weekday;

    fcday_tm = *localtime(&now_t);
    fcday_t = time_calc_day(fcday_tm, day);
    weekday = localtime(&fcday_t)->tm_wday;
    switch (day) {
    case 0:
        return g_strdup_printf(_("Today"));
    case 1:
        return g_strdup_printf(_("Tomorrow"));
    default:
        return translate_day(weekday);
    }
}


512
static GtkWidget *
Harald Judt's avatar
Harald Judt committed
513 514
wrap_forecast_cell(const GtkWidget *widget,
                   const GdkColor *color)
515
{
516
    GtkWidget *ebox;
Harald Judt's avatar
Harald Judt committed
517

518 519 520 521 522 523 524 525 526 527 528
    ebox = gtk_event_box_new();
    if (color == NULL)
        gtk_event_box_set_visible_window(GTK_EVENT_BOX(ebox), FALSE);
    else {
        gtk_event_box_set_visible_window(GTK_EVENT_BOX(ebox), TRUE);
        gtk_widget_modify_bg(GTK_WIDGET(ebox), GTK_STATE_NORMAL, color);
    }
    gtk_container_add(GTK_CONTAINER(ebox), GTK_WIDGET(widget));
    return ebox;
}

529

530
static GtkWidget *
531 532 533
add_forecast_header(const gchar *text,
                    const gdouble angle,
                    const GdkColor *color)
534
{
Harald Judt's avatar
Harald Judt committed
535
    GtkWidget *label, *align;
536 537
    gchar *str;

538 539 540 541 542
    if (angle)
        align = gtk_alignment_new(1, 1, 0, 1);
    else
        align = gtk_alignment_new(1, 1, 1, 0);
    gtk_container_set_border_width(GTK_CONTAINER(align), 4);
543 544

    label = gtk_label_new(NULL);
Harald Judt's avatar
Harald Judt committed
545
    gtk_label_set_angle(GTK_LABEL(label), angle);
546 547 548
    str = g_strdup_printf("<span foreground=\"white\"><b>%s</b></span>", text ? text : "");
    gtk_label_set_markup(GTK_LABEL(label), str);
    g_free(str);
Harald Judt's avatar
Harald Judt committed
549
    gtk_container_add(GTK_CONTAINER(align), GTK_WIDGET(label));
Harald Judt's avatar
Harald Judt committed
550
    return wrap_forecast_cell(align, color);
551 552
}

553

554
static GtkWidget *
555
add_forecast_cell(plugin_data *data,
Harald Judt's avatar
Harald Judt committed
556 557
                  gint day,
                  gint daytime)
558
{
Harald Judt's avatar
Harald Judt committed
559
    GtkWidget *box, *label, *image;
560
    GdkPixbuf *icon;
561
    const GdkColor black = {0, 0x0000, 0x0000, 0x0000};
Harald Judt's avatar
Harald Judt committed
562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631
    gchar *wind_speed, *wind_direction, *value, *rawvalue;
    xml_time *fcdata;

    box = gtk_vbox_new(FALSE, 0);

    fcdata = make_forecast_data(data->weatherdata, day, daytime);
    if (fcdata == NULL)
        return box;

    if (fcdata->location == NULL) {
        xml_time_free(fcdata);
        return box;
    }

    /* symbol */
    rawvalue = get_data(fcdata, data->units, SYMBOL, FALSE);
    icon = get_icon(data->icon_theme, rawvalue, 48, (daytime == NIGHT));
    g_free(rawvalue);
    image = gtk_image_new_from_pixbuf(icon);
    gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(image), TRUE, TRUE, 0);
    if (G_LIKELY(icon))
        g_object_unref(G_OBJECT(icon));

    /* symbol description */
    rawvalue = get_data(fcdata, data->units, SYMBOL, FALSE);
    value = g_strdup_printf("%s",
                            translate_desc(rawvalue, (daytime == NIGHT)));
    g_free(rawvalue);
    label = gtk_label_new(NULL);
    gtk_label_set_markup(GTK_LABEL(label), value);
    if (!(day % 2))
        gtk_widget_modify_fg(GTK_WIDGET(label), GTK_STATE_NORMAL, &black);
    gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(label), TRUE, TRUE, 0);
    g_free(value);

    /* temperature */
    rawvalue = get_data(fcdata, data->units,
                        TEMPERATURE, data->round);
    value = g_strdup_printf("%s %s", rawvalue,
                            get_unit(data->units, TEMPERATURE));
    g_free(rawvalue);
    label = gtk_label_new(value);
    if (!(day % 2))
        gtk_widget_modify_fg(GTK_WIDGET(label), GTK_STATE_NORMAL, &black);
    gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(label), TRUE, TRUE, 0);
    g_free(value);

    /* wind direction and speed */
    rawvalue = get_data(fcdata, data->units, WIND_DIRECTION, FALSE);
    wind_direction = translate_wind_direction(rawvalue);
    wind_speed = get_data(fcdata, data->units, WIND_SPEED, data->round);
    value = g_strdup_printf("%s %s %s", wind_direction, wind_speed,
                            get_unit(data->units, WIND_SPEED));
    g_free(wind_speed);
    g_free(wind_direction);
    g_free(rawvalue);
    label = gtk_label_new(value);
    if (!(day % 2))
        gtk_widget_modify_fg(GTK_WIDGET(label), GTK_STATE_NORMAL, &black);
    gtk_box_pack_start(GTK_BOX(box), label, TRUE, TRUE, 0);
    g_free(value);

    gtk_widget_set_size_request(GTK_WIDGET(box), 150, -1);

    xml_time_free(fcdata);
    return box;
}


static GtkWidget *
632
make_forecast(plugin_data *data)
Harald Judt's avatar
Harald Judt committed
633 634 635
{
    GtkWidget *table, *ebox, *box, *align;
    GtkWidget *forecast_box;
636 637
    const GdkColor lightbg = {0, 0xeaea, 0xeaea, 0xeaea};
    const GdkColor darkbg = {0, 0x6666, 0x6666, 0x6666};
Harald Judt's avatar
Harald Judt committed
638
    gchar *dayname;
Harald Judt's avatar
Harald Judt committed
639 640 641 642 643 644 645
    gint i;
    daytime daytime;

    if (data->forecast_layout == FC_LAYOUT_CALENDAR)
        table = gtk_table_new(5, data->forecast_days + 1, FALSE);
    else
        table = gtk_table_new(data->forecast_days + 1, 5, FALSE);
646 647 648 649 650 651 652

    gtk_table_set_row_spacings(GTK_TABLE(table), 0);
    gtk_table_set_col_spacings(GTK_TABLE(table), 0);

    /* empty upper left corner */
    box = gtk_vbox_new(FALSE, 0);
    gtk_table_attach_defaults(GTK_TABLE(table),
Harald Judt's avatar
Harald Judt committed
653
                              wrap_forecast_cell(box, &darkbg),
654 655 656
                              0, 1, 0, 1);

    /* daytime headers */
Harald Judt's avatar
Harald Judt committed
657 658 659 660
    ATTACH_DAYTIME_HEADER(_("Morning"), 1);
    ATTACH_DAYTIME_HEADER(_("Afternoon"), 2);
    ATTACH_DAYTIME_HEADER(_("Evening"), 3);
    ATTACH_DAYTIME_HEADER(_("Night"), 4);
661

662
    for (i = 0; i < data->forecast_days; i++) {
663
        /* forecast day headers */
Harald Judt's avatar
Harald Judt committed
664 665 666
        dayname = get_dayname(i);
        if (data->forecast_layout == FC_LAYOUT_CALENDAR)
            ebox = add_forecast_header(dayname, 0.0, &darkbg);
667
        else
Harald Judt's avatar
Harald Judt committed
668
            ebox = add_forecast_header(dayname, 90.0, &darkbg);
Harald Judt's avatar
Harald Judt committed
669
        g_free(dayname);
670

Harald Judt's avatar
Harald Judt committed
671 672 673 674 675 676
        if (data->forecast_layout == FC_LAYOUT_CALENDAR)
            gtk_table_attach_defaults(GTK_TABLE(table), GTK_WIDGET(ebox),
                                      i+1, i+2, 0, 1);
        else
            gtk_table_attach_defaults(GTK_TABLE(table), GTK_WIDGET(ebox),
                                      0, 1, i+1, i+2);
677

678
        /* get forecast data for each daytime */
679
        for (daytime = MORNING; daytime <= NIGHT; daytime++) {
Harald Judt's avatar
Harald Judt committed
680
            forecast_box = add_forecast_cell(data, i, daytime);
Harald Judt's avatar
Harald Judt committed
681 682 683
            align = gtk_alignment_new(0.5, 0.5, 1, 1);
            gtk_container_set_border_width(GTK_CONTAINER(align), 4);
            gtk_container_add(GTK_CONTAINER(align), GTK_WIDGET(forecast_box));
684
            if (i % 2)
Harald Judt's avatar
Harald Judt committed
685
                ebox = wrap_forecast_cell(align, NULL);
686
            else
Harald Judt's avatar
Harald Judt committed
687 688
                ebox = wrap_forecast_cell(align, &lightbg);

Harald Judt's avatar
Harald Judt committed
689 690 691 692 693 694 695 696
            if (data->forecast_layout == FC_LAYOUT_CALENDAR)
                gtk_table_attach_defaults(GTK_TABLE(table),
                                          GTK_WIDGET(ebox),
                                          i+1, i+2, 1+daytime, 2+daytime);
            else
                gtk_table_attach_defaults(GTK_TABLE(table),
                                          GTK_WIDGET(ebox),
                                          1+daytime, 2+daytime, i+1, i+2);
697 698 699
        }
    }
    return table;
700 701
}

702

703
static GtkWidget *
704
create_forecast_tab(plugin_data *data)
705
{
706
    GtkWidget *ebox, *align, *hbox, *scrolled, *table;
707
    GdkWindow *window;
708
    GdkScreen *screen;
709
    GdkRectangle rect;
Harald Judt's avatar
Harald Judt committed
710 711
    gint monitor_num = 0, h_need, h_max, height;
    gint w_need, w_max, width;
712

713 714 715 716 717 718 719 720 721 722
    /* To avoid causing a GDK assertion, determine the monitor
     * geometry using the weather icon window, which has already been
     * realized in contrast to the summary window. Then calculate the
     * maximum height we may use, subtracting some sane value just to
     * be on the safe side. */
    window = GDK_WINDOW(gtk_widget_get_window(GTK_WIDGET(data->iconimage)));
    screen = GDK_SCREEN(gdk_window_get_screen(window));
    if (G_LIKELY(window && screen))
        monitor_num = gdk_screen_get_monitor_at_window(screen, window);
    gdk_screen_get_monitor_geometry(screen, monitor_num, &rect);
723

Harald Judt's avatar
Harald Judt committed
724 725 726
    /* calculate maximum width and height */
    h_max = rect.height - 250;
    w_max = rect.width - 50;
727

Harald Judt's avatar
Harald Judt committed
728 729 730 731 732 733 734 735
    /* calculate needed space using a good arbitrary value */
    if (data->forecast_layout == FC_LAYOUT_CALENDAR) {
        w_need = ((data->forecast_days < 8) ? data->forecast_days : 7) * 142;
        h_need = 500;
    } else {
        w_need = (rect.width <= 720) ? 650 : 700;
        h_need = data->forecast_days * 110;
    }
736 737 738 739

    /* generate the forecast table */
    table = GTK_WIDGET(make_forecast(data));

Harald Judt's avatar
Harald Judt committed
740
    /* generate the containing widgets */
741
    align = gtk_alignment_new(0.5, 0, 0.5, 0);
Harald Judt's avatar
Harald Judt committed
742 743 744 745
    if ((data->forecast_layout == FC_LAYOUT_CALENDAR &&
         w_need < w_max && data->forecast_days < 8) ||
        (data->forecast_layout == FC_LAYOUT_LIST && h_need < h_max)) {
        /* no scroll window needed, just align the contents */
746 747 748 749
        gtk_container_add(GTK_CONTAINER(align), GTK_WIDGET(table));
        gtk_container_set_border_width(GTK_CONTAINER(align), BORDER);
        return align;
    } else {
Harald Judt's avatar
Harald Judt committed
750
        /* contents too big, scroll window needed */
751 752 753 754 755 756 757
        hbox = gtk_hbox_new(FALSE, 0);
        gtk_box_pack_start(GTK_BOX(hbox), table, TRUE, FALSE, 0);
        gtk_container_add(GTK_CONTAINER(align), GTK_WIDGET(hbox));

        scrolled = gtk_scrolled_window_new (NULL, NULL);
        gtk_container_set_border_width(GTK_CONTAINER(scrolled), BORDER);

758 759
        gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled),
                                              align);
760
        gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
761 762
                                       GTK_POLICY_AUTOMATIC,
                                       GTK_POLICY_AUTOMATIC);
Harald Judt's avatar
Harald Judt committed
763 764 765 766 767 768

        /* set scroll window size */
        width = (w_need > w_max) ? w_max : w_need;
        height = (h_need > h_max) ? h_max : h_need;
        gtk_widget_set_size_request(GTK_WIDGET(scrolled), width, height);

769
        ebox = gtk_event_box_new();
770
        gtk_event_box_set_visible_window(GTK_EVENT_BOX(ebox), TRUE);
771 772
        gtk_container_add(GTK_CONTAINER(ebox), GTK_WIDGET(scrolled));
        return ebox;
773
    }
774
}
775

776

777
static void
778 779
summary_dialog_response(const GtkWidget *dlg,
                        const gint response,
780
                        GtkWidget *window)
781
{
782 783
    if (response == GTK_RESPONSE_ACCEPT)
        gtk_widget_destroy(window);
784 785
}

786

787 788 789 790 791 792 793 794 795 796 797 798
static void
cb_notebook_page_switched(GtkNotebook *notebook,
                          GtkNotebookPage *page,
                          guint page_num,
                          gpointer user_data)
{
    plugin_data *data = (plugin_data *) user_data;

    data->summary_remember_tab = page_num;
}


799
GtkWidget *
800
create_summary_window(plugin_data *data)
801
{
802
    GtkWidget *window, *notebook, *vbox, *hbox, *label;
Harald Judt's avatar
Harald Judt committed
803
    gchar *title, *symbol;
804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819
    GdkPixbuf *icon;
    xml_time *conditions;

    window = xfce_titled_dialog_new_with_buttons(_("Weather Update"),
                                                 NULL,
                                                 GTK_DIALOG_NO_SEPARATOR,
                                                 GTK_STOCK_CLOSE,
                                                 GTK_RESPONSE_ACCEPT, NULL);
    if (data->location_name != NULL) {
        title = g_strdup_printf(_("Weather report for: %s"),
                                data->location_name);
        xfce_titled_dialog_set_subtitle(XFCE_TITLED_DIALOG(window), title);
        g_free(title);
    }

    vbox = gtk_vbox_new(FALSE, 0);
Harald Judt's avatar
Harald Judt committed
820
    gtk_box_pack_start(GTK_BOX(GTK_DIALOG(window)->vbox), vbox, TRUE, TRUE, 0);
821 822 823

    conditions = get_current_conditions(data->weatherdata);

824
    symbol = get_data(conditions, data->units, SYMBOL, FALSE);
825
    icon = get_icon(data->icon_theme, symbol, 48, data->night_time);
Harald Judt's avatar
Harald Judt committed
826
    g_free(symbol);
827 828 829 830 831 832

    gtk_window_set_icon(GTK_WINDOW(window), icon);

    if (G_LIKELY(icon))
        g_object_unref(G_OBJECT(icon));

833 834
    if (data->location_name == NULL || data->weatherdata == NULL ||
        data->weatherdata->current_conditions == NULL) {
835 836 837 838 839 840 841 842 843 844 845 846 847 848 849
        hbox = gtk_hbox_new(FALSE, 0);
        if (data->location_name == NULL)
            label = gtk_label_new(_("Please set a location in the plugin settings."));
        else
            label = gtk_label_new(_("Currently no data available."));
        gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(label),
                           TRUE, TRUE, 0);

        gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(hbox),
                           TRUE, TRUE, 0);
        gtk_window_set_default_size(GTK_WINDOW(window), 500, 400);
    } else {
        notebook = gtk_notebook_new();
        gtk_container_set_border_width(GTK_CONTAINER(notebook), BORDER);
        gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
850
                                 create_forecast_tab(data),
851 852 853 854 855
                                 gtk_label_new_with_mnemonic(_("_Forecast")));
        gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
                                 create_summary_tab(data),
                                 gtk_label_new_with_mnemonic(_("_Details")));
        gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
856 857 858 859
        gtk_widget_show_all(GTK_WIDGET(notebook));
        gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), data->summary_remember_tab);
        g_signal_connect(GTK_NOTEBOOK(notebook), "switch-page",
                         G_CALLBACK(cb_notebook_page_switched), data);
860 861 862 863 864 865
    }

    g_signal_connect(G_OBJECT(window), "response",
                     G_CALLBACK(summary_dialog_response), window);

    return window;
866
}
Harald Judt's avatar
Harald Judt committed
867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884


void
summary_details_free(summary_details *sum)
{
    g_assert(sum != NULL);
    if (G_UNLIKELY(sum == NULL))
        return;

    sum->icon_ebox = NULL;
    sum->text_view = NULL;
    if (sum->hand_cursor)
        gdk_cursor_unref(sum->hand_cursor);
    sum->hand_cursor = NULL;
    if (sum->text_cursor)
        gdk_cursor_unref(sum->text_cursor);
    sum->text_cursor = NULL;
}