+ gboolean crf;
+ crf = ghb_settings_get_boolean(ud->settings, "constant_rate_factor");
+ percent = 100. * (51 - val) / 51.;
+ if (crf)
+ return g_strdup_printf("RF: %.4g (%.0f%%)", val, percent);
+ else
+ return g_strdup_printf("QP: %.4g (%.0f%%)", val, percent);
+ } break;
+
+ case HB_VCODEC_FFMPEG:
+ {
+ percent = 100. * (30 - (val - 1)) / 30.;
+ return g_strdup_printf("QP: %d (%.0f%%)", (int)val, percent);
+ } break;
+
+ case HB_VCODEC_THEORA:
+ {
+ percent = 100. * val / 63.;
+ return g_strdup_printf("QP: %d (%.0f%%)", (int)val, percent);
+ } break;
+
+ default:
+ {
+ percent = 0;
+ } break;
+ }
+ return g_strdup_printf("QP: %.1f / %.1f%%", val, percent);
+}
+
+static void
+process_appcast(signal_user_data_t *ud)
+{
+ gchar *description = NULL, *build = NULL, *version = NULL, *msg;
+#if !defined(_WIN32)
+ GtkWidget *window;
+ static GtkWidget *html = NULL;
+#endif
+ GtkWidget *dialog, *label;
+ gint response, ibuild = 0, skip;
+
+ if (ud->appcast == NULL || ud->appcast_len < 15 ||
+ strncmp(&(ud->appcast[9]), "200 OK", 6))
+ {
+ goto done;
+ }
+ ghb_appcast_parse(ud->appcast, &description, &build, &version);
+ if (build)
+ ibuild = g_strtod(build, NULL);
+ skip = ghb_settings_get_int(ud->settings, "update_skip_version");
+ if (description == NULL || build == NULL || version == NULL
+ || ibuild <= hb_get_build(NULL) || skip == ibuild)
+ {
+ goto done;
+ }
+ msg = g_strdup_printf("HandBrake %s/%s is now available (you have %s/%d).",
+ version, build, hb_get_version(NULL), hb_get_build(NULL));
+ label = GHB_WIDGET(ud->builder, "update_message");
+ gtk_label_set_text(GTK_LABEL(label), msg);
+
+#if !defined(_WIN32)
+ if (html == NULL)
+ {
+ html = webkit_web_view_new();
+ window = GHB_WIDGET(ud->builder, "update_scroll");
+ gtk_container_add(GTK_CONTAINER(window), html);
+ // Show it
+ gtk_widget_set_size_request(html, 420, 240);
+ gtk_widget_show(html);
+ }
+ webkit_web_view_open(WEBKIT_WEB_VIEW(html), description);
+#endif
+ dialog = GHB_WIDGET(ud->builder, "update_dialog");
+ response = gtk_dialog_run(GTK_DIALOG(dialog));
+ gtk_widget_hide(dialog);
+ if (response == GTK_RESPONSE_OK)
+ {
+ // Skip
+ ghb_settings_set_int(ud->settings, "update_skip_version", ibuild);
+ ghb_pref_save(ud->settings, "update_skip_version");
+ }
+ g_free(msg);
+
+done:
+ if (description) g_free(description);
+ if (build) g_free(build);
+ if (version) g_free(version);
+ g_free(ud->appcast);
+ ud->appcast_len = 0;
+ ud->appcast = NULL;
+ appcast_busy = FALSE;
+}
+
+void
+ghb_net_close(GIOChannel *ioc)
+{
+ gint fd;
+
+ g_debug("ghb_net_close");
+ if (ioc == NULL) return;
+ fd = g_io_channel_unix_get_fd(ioc);
+ close(fd);
+ g_io_channel_unref(ioc);
+}
+
+G_MODULE_EXPORT gboolean
+ghb_net_recv_cb(GIOChannel *ioc, GIOCondition cond, gpointer data)
+{
+ gchar buf[2048];
+ gsize len;
+ GError *gerror = NULL;
+ GIOStatus status;
+
+ g_debug("ghb_net_recv_cb");
+ signal_user_data_t *ud = (signal_user_data_t*)data;
+
+ status = g_io_channel_read_chars (ioc, buf, 2048, &len, &gerror);
+ if ((status == G_IO_STATUS_NORMAL || status == G_IO_STATUS_EOF) &&
+ len > 0)
+ {
+ gint new_len = ud->appcast_len + len;
+ ud->appcast = g_realloc(ud->appcast, new_len + 1);
+ memcpy(&(ud->appcast[ud->appcast_len]), buf, len);
+ ud->appcast_len = new_len;
+ }
+ if (status == G_IO_STATUS_EOF)
+ {
+ ud->appcast[ud->appcast_len] = 0;
+ ghb_net_close(ioc);
+ process_appcast(ud);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+GIOChannel*
+ghb_net_open(signal_user_data_t *ud, gchar *address, gint port)
+{
+ GIOChannel *ioc;
+ gint fd;
+
+ struct sockaddr_in sock;
+ struct hostent * host;
+
+ g_debug("ghb_net_open");
+ if( !( host = gethostbyname( address ) ) )
+ {
+ g_warning( "gethostbyname failed (%s)", address );
+ appcast_busy = FALSE;
+ return NULL;
+ }
+
+ memset( &sock, 0, sizeof( struct sockaddr_in ) );
+ sock.sin_family = host->h_addrtype;
+ sock.sin_port = htons( port );
+ memcpy( &sock.sin_addr, host->h_addr, host->h_length );
+
+ fd = socket(host->h_addrtype, SOCK_STREAM, 0);
+ if( fd < 0 )
+ {
+ g_debug( "socket failed" );
+ appcast_busy = FALSE;
+ return NULL;
+ }
+
+ if(connect(fd, (struct sockaddr*)&sock, sizeof(struct sockaddr_in )) < 0 )
+ {
+ g_debug( "connect failed" );
+ appcast_busy = FALSE;
+ return NULL;
+ }
+ ioc = g_io_channel_unix_new(fd);
+ g_io_channel_set_encoding (ioc, NULL, NULL);
+ g_io_channel_set_flags(ioc, G_IO_FLAG_NONBLOCK, NULL);
+ g_io_add_watch (ioc, G_IO_IN, ghb_net_recv_cb, (gpointer)ud );
+
+ return ioc;
+}
+
+gpointer
+ghb_check_update(signal_user_data_t *ud)
+{
+ gchar *query;
+ gsize len;
+ GIOChannel *ioc;
+ GError *gerror = NULL;
+ GRegex *regex;
+ GMatchInfo *mi;
+ gchar *host, *appcast;
+
+ g_debug("ghb_check_update");
+ appcast_busy = TRUE;
+ regex = g_regex_new("^http://(.+)/(.+)$", 0, 0, NULL);
+ if (!g_regex_match(regex, HB_PROJECT_URL_APPCAST, 0, &mi))
+ {
+ return NULL;
+ }
+
+ host = g_match_info_fetch(mi, 1);
+ appcast = g_match_info_fetch(mi, 2);
+
+ if (host == NULL || appcast == NULL)
+ return NULL;
+
+ query = g_strdup_printf( "GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n",
+ appcast, host);
+
+ ioc = ghb_net_open(ud, host, 80);
+ if (ioc == NULL)
+ return NULL;
+
+ g_io_channel_write_chars(ioc, query, strlen(query), &len, &gerror);
+ g_io_channel_flush(ioc, &gerror);
+ g_free(query);
+ g_free(host);
+ g_free(appcast);
+ g_match_info_free(mi);
+ g_regex_unref(regex);
+ return NULL;
+}
+
+G_MODULE_EXPORT gboolean
+hb_visibility_event_cb(
+ GtkWidget *widget,
+ GdkEventVisibility *vs,
+ signal_user_data_t *ud)
+{
+ ud->hb_visibility = vs->state;
+ return FALSE;
+}
+
+G_MODULE_EXPORT void
+status_activate_cb(GtkStatusIcon *si, signal_user_data_t *ud)
+{
+ GtkWindow *window;
+ GdkWindowState state;
+
+ window = GTK_WINDOW(GHB_WIDGET(ud->builder, "hb_window"));
+ state = gdk_window_get_state(GTK_WIDGET(window)->window);
+ if ((state & GDK_WINDOW_STATE_ICONIFIED) ||
+ (ud->hb_visibility != GDK_VISIBILITY_UNOBSCURED))
+ {
+ gtk_window_present(window);
+ gtk_window_set_skip_taskbar_hint(window, FALSE);