weather-summary.c 30.6 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
#include "weather-parsers.h"
#include "weather-data.h"
#include "weather.h"
28

Nick Schermer's avatar
Nick Schermer committed
29 30 31
#include "weather-summary.h"
#include "weather-translate.h"
#include "weather-icon.h"
32

33

34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
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)                            \
54 55
    rawvalue = get_data(conditions, data->units, item, FALSE);  \
    unit = get_unit(data->units, item);                         \
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
    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);
74

Harald Judt's avatar
Harald Judt committed
75 76 77 78 79 80 81 82 83 84 85 86
#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);                         \

87

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

98 99 100 101 102 103 104 105 106 107
    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;
108 109
}

110

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

119 120 121 122

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

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

157 158 159 160

static gboolean
icon_motion_notify(GtkWidget *widget,
                   GdkEventMotion *event,
Harald Judt's avatar
Harald Judt committed
161
                   summary_details *sum)
162
{
Harald Judt's avatar
Harald Judt committed
163 164 165 166 167
    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);
168
    return FALSE;
169 170
}

171 172 173 174

static gboolean
view_leave_notify(GtkWidget *widget,
                  GdkEventMotion *event,
Harald Judt's avatar
Harald Judt committed
175
                  summary_details *sum)
176
{
Harald Judt's avatar
Harald Judt committed
177 178 179 180 181
    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);
182
    return FALSE;
183 184
}

185 186 187

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

Harald Judt's avatar
Harald Judt committed
192 193 194 195
    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),
196 197
                                              GTK_TEXT_WINDOW_TEXT,
                                              x1, y1, &x, &y);
Harald Judt's avatar
Harald Judt committed
198 199
        gtk_text_view_move_child(GTK_TEXT_VIEW(sum->text_view),
                                 sum->icon_ebox, x, y);
200
    }
201 202
}

203 204 205 206 207

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

212 213 214

static gchar *
get_logo_path(void)
215
{
216 217 218 219 220 221 222
    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;
223 224
}

225

226
static void
227 228 229
logo_fetched(SoupSession *session,
             SoupMessage *msg,
             gpointer user_data)
230
{
231
    if (msg && msg->response_body && msg->response_body->length > 0) {
232 233 234
        gchar *path = get_logo_path();
        GError *error = NULL;
        GdkPixbuf *pixbuf = NULL;
235 236 237 238
        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 : "?");
239 240 241 242 243 244 245 246 247 248 249
            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);
        }
    }
250 251
}

252 253

static GtkWidget *
254
weather_summary_get_logo(plugin_data *data)
255
{
256 257 258 259 260 261 262
    GtkWidget *image = gtk_image_new();
    GdkPixbuf *pixbuf = NULL;
    gchar *path = get_logo_path();

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

273

274
static GtkWidget *
275
create_summary_tab(plugin_data *data)
276
{
277 278 279
    GtkTextBuffer *buffer;
    GtkTextIter iter;
    GtkTextTag *btag, *ltag0, *ltag1;
Harald Judt's avatar
Harald Judt committed
280
    GtkWidget *view, *frame, *scrolled, *icon;
281 282 283 284 285
    GtkAdjustment *adj;
    GdkColor lnk_color;
    xml_time *conditions;
    const gchar *unit;
    struct tm *start_tm, *end_tm, *point_tm;
286
    struct tm *sunrise_tm, *sunset_tm, *moonrise_tm, *moonset_tm;
Harald Judt's avatar
Harald Judt committed
287
    gchar *value, *rawvalue, *wind;
288 289
    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
290
    summary_details *sum;
291

Harald Judt's avatar
Harald Judt committed
292 293 294 295 296 297 298
    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();
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 347
    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
348 349 350 351
        (_("\n\tPrecipitation and the weather symbol have been calculated\n"
           "\tfor the following time interval:\n"
           "\tStart:\t%s\n"
           "\tEnd:\t%s\n"),
352 353 354 355
         interval_start,
         interval_end);
    APPEND_TEXT_ITEM_REAL(value);

356
    /* sun and moon */
357
    APPEND_BTEXT(_("\nAstronomical Data\n"));
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 407
    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);
    }

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

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

424
    rawvalue = get_data(conditions, data->units, WIND_DIRECTION, FALSE);
425 426
    wind = translate_wind_direction(rawvalue);
    g_free(rawvalue);
427
    rawvalue = get_data(conditions, data->units, WIND_DIRECTION_DEG, FALSE);
428 429
    value = g_strdup_printf("\t%s: %s (%s%s)\n", _("Direction"),
                            wind, rawvalue,
430
                            get_unit(data->units, WIND_DIRECTION_DEG));
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 457
    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
458
                     G_CALLBACK(view_motion_notify), sum);
459
    g_signal_connect(G_OBJECT(view), "leave-notify-event",
Harald Judt's avatar
Harald Judt committed
460
                     G_CALLBACK(view_leave_notify), sum);
461

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

Harald Judt's avatar
Harald Judt committed
464 465
    if (icon) {
        sum->icon_ebox = gtk_event_box_new();
466 467
        gtk_event_box_set_visible_window(GTK_EVENT_BOX(sum->icon_ebox), FALSE);
        gtk_container_add(GTK_CONTAINER(sum->icon_ebox), icon);
468
        gtk_text_view_add_child_in_window(GTK_TEXT_VIEW(view),
Harald Judt's avatar
Harald Judt committed
469
                                          sum->icon_ebox,
470
                                          GTK_TEXT_WINDOW_TEXT, 0, 0);
Harald Judt's avatar
Harald Judt committed
471
        gtk_widget_show_all(sum->icon_ebox);
472 473 474
        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
475
                         G_CALLBACK(view_scrolled_cb), sum);
476
        g_signal_connect(G_OBJECT(view), "size_allocate",
Harald Judt's avatar
Harald Judt committed
477 478 479 480 481 482 483 484 485
                         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);
486
    }
Harald Judt's avatar
Harald Judt committed
487

488
    return frame;
489
}
490

491

Harald Judt's avatar
Harald Judt committed
492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512
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);
    }
}


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

519 520 521 522 523 524 525 526 527 528 529
    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;
}

530

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

539 540 541 542 543
    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);
544 545

    label = gtk_label_new(NULL);
Harald Judt's avatar
Harald Judt committed
546
    gtk_label_set_angle(GTK_LABEL(label), angle);
547 548 549
    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
550
    gtk_container_add(GTK_CONTAINER(align), GTK_WIDGET(label));
Harald Judt's avatar
Harald Judt committed
551
    return wrap_forecast_cell(align, color);
552 553
}

554

555
static GtkWidget *
556
add_forecast_cell(plugin_data *data,
Harald Judt's avatar
Harald Judt committed
557 558
                  gint day,
                  gint daytime)
559
{
Harald Judt's avatar
Harald Judt committed
560
    GtkWidget *box, *label, *image;
561
    GdkPixbuf *icon;
562
    const GdkColor black = {0, 0x0000, 0x0000, 0x0000};
Harald Judt's avatar
Harald Judt committed
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 632
    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 *
633
make_forecast(plugin_data *data)
Harald Judt's avatar
Harald Judt committed
634 635 636
{
    GtkWidget *table, *ebox, *box, *align;
    GtkWidget *forecast_box;
637 638
    const GdkColor lightbg = {0, 0xeaea, 0xeaea, 0xeaea};
    const GdkColor darkbg = {0, 0x6666, 0x6666, 0x6666};
Harald Judt's avatar
Harald Judt committed
639
    gchar *dayname;
Harald Judt's avatar
Harald Judt committed
640 641 642 643 644 645 646
    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);
647 648 649 650 651 652 653

    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
654
                              wrap_forecast_cell(box, &darkbg),
655 656 657
                              0, 1, 0, 1);

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

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

Harald Judt's avatar
Harald Judt committed
672 673 674 675 676 677
        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);
678

679
        /* get forecast data for each daytime */
680
        for (daytime = MORNING; daytime <= NIGHT; daytime++) {
Harald Judt's avatar
Harald Judt committed
681
            forecast_box = add_forecast_cell(data, i, daytime);
Harald Judt's avatar
Harald Judt committed
682 683 684
            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));
685
            if (i % 2)
Harald Judt's avatar
Harald Judt committed
686
                ebox = wrap_forecast_cell(align, NULL);
687
            else
Harald Judt's avatar
Harald Judt committed
688 689
                ebox = wrap_forecast_cell(align, &lightbg);

Harald Judt's avatar
Harald Judt committed
690 691 692 693 694 695 696 697
            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);
698 699 700
        }
    }
    return table;
701 702
}

703

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

714 715 716 717 718 719 720 721 722 723
    /* 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);
724

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

Harald Judt's avatar
Harald Judt committed
729 730 731 732 733 734 735 736
    /* 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;
    }
737 738 739 740

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

Harald Judt's avatar
Harald Judt committed
741
    /* generate the containing widgets */
742
    align = gtk_alignment_new(0.5, 0, 0.5, 0);
Harald Judt's avatar
Harald Judt committed
743 744 745 746
    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 */
747 748 749 750
        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
751
        /* contents too big, scroll window needed */
752 753 754 755 756 757 758
        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);

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

        /* 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);

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

777

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

787

788
GtkWidget *
789
create_summary_window(plugin_data *data)
790
{
791
    GtkWidget *window, *notebook, *vbox, *hbox, *label;
Harald Judt's avatar
Harald Judt committed
792
    gchar *title, *symbol;
793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808
    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
809
    gtk_box_pack_start(GTK_BOX(GTK_DIALOG(window)->vbox), vbox, TRUE, TRUE, 0);
810 811 812

    conditions = get_current_conditions(data->weatherdata);

813
    symbol = get_data(conditions, data->units, SYMBOL, FALSE);
814
    icon = get_icon(data->icon_theme, symbol, 48, data->night_time);
Harald Judt's avatar
Harald Judt committed
815
    g_free(symbol);
816 817 818 819 820 821

    gtk_window_set_icon(GTK_WINDOW(window), icon);

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

822 823
    if (data->location_name == NULL || data->weatherdata == NULL ||
        data->weatherdata->current_conditions == NULL) {
824 825 826 827 828 829 830 831 832 833 834 835 836 837 838
        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),
839
                                 create_forecast_tab(data),
840 841 842 843 844 845 846 847 848 849 850 851
                                 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);
    }

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

    return window;
852
}
Harald Judt's avatar
Harald Judt committed
853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870


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;
}