| 2209 return; |
2209 return; |
| 2210 |
2210 |
| 2211 gdk_window_set_cursor(widget->window, NULL); |
2211 gdk_window_set_cursor(widget->window, NULL); |
| 2212 } |
2212 } |
| 2213 |
2213 |
| |
2214 struct _icon_chooser { |
| |
2215 GtkWidget *icon_filesel; |
| |
2216 GtkWidget *icon_preview; |
| |
2217 GtkWidget *icon_text; |
| |
2218 |
| |
2219 void (*callback)(const char*,gpointer); |
| |
2220 gpointer data; |
| |
2221 }; |
| |
2222 |
| |
2223 #if !GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */ |
| |
2224 static void |
| |
2225 icon_filesel_delete_cb(GtkWidget *w, struct _icon_chooser *dialog) |
| |
2226 { |
| |
2227 if (dialog->icon_filesel != NULL) |
| |
2228 gtk_widget_destroy(dialog->icon_filesel); |
| |
2229 |
| |
2230 if (dialog->callback) |
| |
2231 dialog->callback(NULL, data); |
| |
2232 |
| |
2233 g_free(dialog); |
| |
2234 } |
| |
2235 #endif /* FILECHOOSER */ |
| |
2236 |
| |
2237 |
| |
2238 |
| |
2239 #if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */ |
| |
2240 static void |
| |
2241 icon_filesel_choose_cb(GtkWidget *widget, gint response, struct _icon_chooser *dialog) |
| |
2242 { |
| |
2243 char *filename, *current_folder; |
| |
2244 |
| |
2245 if (response != GTK_RESPONSE_ACCEPT) { |
| |
2246 if (response == GTK_RESPONSE_CANCEL) { |
| |
2247 gtk_widget_destroy(dialog->icon_filesel); |
| |
2248 } |
| |
2249 dialog->icon_filesel = NULL; |
| |
2250 if (dialog->callback) |
| |
2251 dialog->callback(NULL, dialog->data); |
| |
2252 g_free(dialog); |
| |
2253 return; |
| |
2254 } |
| |
2255 |
| |
2256 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog->icon_filesel)); |
| |
2257 current_folder = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(dialog->icon_filesel)); |
| |
2258 if (current_folder != NULL) { |
| |
2259 gaim_prefs_set_string("/gaim/gtk/filelocations/last_icon_folder", current_folder); |
| |
2260 g_free(current_folder); |
| |
2261 } |
| |
2262 |
| |
2263 #else /* FILECHOOSER */ |
| |
2264 static void |
| |
2265 icon_filesel_choose_cb(GtkWidget *w, AccountPrefsDialog *dialog) |
| |
2266 { |
| |
2267 char *filename, *current_folder; |
| |
2268 |
| |
2269 filename = g_strdup(gtk_file_selection_get_filename( |
| |
2270 GTK_FILE_SELECTION(dialog->icon_filesel))); |
| |
2271 |
| |
2272 /* If they typed in a directory, change there */ |
| |
2273 if (gaim_gtk_check_if_dir(filename, |
| |
2274 GTK_FILE_SELECTION(dialog->icon_filesel))) |
| |
2275 { |
| |
2276 g_free(filename); |
| |
2277 return; |
| |
2278 } |
| |
2279 |
| |
2280 current_folder = g_path_get_dirname(filename); |
| |
2281 if (current_folder != NULL) { |
| |
2282 gaim_prefs_set_string("/gaim/gtk/filelocations/last_icon_folder", current_folder); |
| |
2283 g_free(current_folder); |
| |
2284 } |
| |
2285 |
| |
2286 #endif /* FILECHOOSER */ |
| |
2287 if (dialog->callback) |
| |
2288 dialog->callback(filename, dialog->data); |
| |
2289 gtk_widget_destroy(dialog->icon_filesel); |
| |
2290 g_free(filename); |
| |
2291 g_free(dialog); |
| |
2292 } |
| |
2293 |
| |
2294 |
| |
2295 static void |
| |
2296 #if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */ |
| |
2297 icon_preview_change_cb(GtkFileChooser *widget, struct _icon_chooser *dialog) |
| |
2298 #else /* FILECHOOSER */ |
| |
2299 icon_preview_change_cb(GtkTreeSelection *sel, struct _icon_chooser *dialog) |
| |
2300 #endif /* FILECHOOSER */ |
| |
2301 { |
| |
2302 GdkPixbuf *pixbuf, *scale; |
| |
2303 int height, width; |
| |
2304 char *basename, *markup, *size; |
| |
2305 struct stat st; |
| |
2306 char *filename; |
| |
2307 |
| |
2308 #if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */ |
| |
2309 filename = gtk_file_chooser_get_preview_filename( |
| |
2310 GTK_FILE_CHOOSER(dialog->icon_filesel)); |
| |
2311 #else /* FILECHOOSER */ |
| |
2312 filename = g_strdup(gtk_file_selection_get_filename( |
| |
2313 GTK_FILE_SELECTION(dialog->icon_filesel))); |
| |
2314 #endif /* FILECHOOSER */ |
| |
2315 |
| |
2316 if (!filename || g_stat(filename, &st)) |
| |
2317 { |
| |
2318 g_free(filename); |
| |
2319 return; |
| |
2320 } |
| |
2321 |
| |
2322 pixbuf = gdk_pixbuf_new_from_file(filename, NULL); |
| |
2323 if (!pixbuf) { |
| |
2324 gtk_image_set_from_pixbuf(GTK_IMAGE(dialog->icon_preview), NULL); |
| |
2325 gtk_label_set_markup(GTK_LABEL(dialog->icon_text), ""); |
| |
2326 #if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */ |
| |
2327 gtk_file_chooser_set_preview_widget_active( |
| |
2328 GTK_FILE_CHOOSER(dialog->icon_filesel), FALSE); |
| |
2329 #endif /* FILECHOOSER */ |
| |
2330 g_free(filename); |
| |
2331 return; |
| |
2332 } |
| |
2333 |
| |
2334 width = gdk_pixbuf_get_width(pixbuf); |
| |
2335 height = gdk_pixbuf_get_height(pixbuf); |
| |
2336 basename = g_path_get_basename(filename); |
| |
2337 size = gaim_str_size_to_units(st.st_size); |
| |
2338 markup = g_strdup_printf(_("<b>File:</b> %s\n" |
| |
2339 "<b>File size:</b> %s\n" |
| |
2340 "<b>Image size:</b> %dx%d"), |
| |
2341 basename, size, width, height); |
| |
2342 |
| |
2343 scale = gdk_pixbuf_scale_simple(pixbuf, width * 50 / height, |
| |
2344 50, GDK_INTERP_BILINEAR); |
| |
2345 gtk_image_set_from_pixbuf(GTK_IMAGE(dialog->icon_preview), scale); |
| |
2346 #if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */ |
| |
2347 gtk_file_chooser_set_preview_widget_active( |
| |
2348 GTK_FILE_CHOOSER(dialog->icon_filesel), TRUE); |
| |
2349 #endif /* FILECHOOSER */ |
| |
2350 gtk_label_set_markup(GTK_LABEL(dialog->icon_text), markup); |
| |
2351 |
| |
2352 g_object_unref(G_OBJECT(pixbuf)); |
| |
2353 g_object_unref(G_OBJECT(scale)); |
| |
2354 g_free(filename); |
| |
2355 g_free(basename); |
| |
2356 g_free(size); |
| |
2357 g_free(markup); |
| |
2358 } |
| |
2359 |
| |
2360 |
| |
2361 GtkWidget *gaim_gtk_buddy_icon_chooser_new(GtkWindow *parent, void(*callback)(const char*,gpointer), gpointer data) { |
| |
2362 struct _icon_chooser *dialog = g_new0(struct _icon_chooser, 1); |
| |
2363 |
| |
2364 #if !GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */ |
| |
2365 GtkWidget *hbox; |
| |
2366 GtkWidget *tv; |
| |
2367 GtkTreeSelection *sel; |
| |
2368 |
| |
2369 #endif /* FILECHOOSER */ |
| |
2370 const char *current_folder; |
| |
2371 |
| |
2372 dialog->callback = callback; |
| |
2373 dialog->data = data; |
| |
2374 |
| |
2375 if (dialog->icon_filesel != NULL) { |
| |
2376 gtk_window_present(GTK_WINDOW(dialog->icon_filesel)); |
| |
2377 return NULL; |
| |
2378 } |
| |
2379 |
| |
2380 current_folder = gaim_prefs_get_string("/gaim/gtk/filelocations/last_icon_folder"); |
| |
2381 #if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */ |
| |
2382 |
| |
2383 dialog->icon_filesel = gtk_file_chooser_dialog_new(_("Buddy Icon"), |
| |
2384 parent, |
| |
2385 GTK_FILE_CHOOSER_ACTION_OPEN, |
| |
2386 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, |
| |
2387 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, |
| |
2388 NULL); |
| |
2389 gtk_dialog_set_default_response(GTK_DIALOG(dialog->icon_filesel), GTK_RESPONSE_ACCEPT); |
| |
2390 if ((current_folder != NULL) && (*current_folder != '\0')) |
| |
2391 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog->icon_filesel), |
| |
2392 current_folder); |
| |
2393 |
| |
2394 dialog->icon_preview = gtk_image_new(); |
| |
2395 dialog->icon_text = gtk_label_new(NULL); |
| |
2396 gtk_widget_set_size_request(GTK_WIDGET(dialog->icon_preview), -1, 50); |
| |
2397 gtk_file_chooser_set_preview_widget(GTK_FILE_CHOOSER(dialog->icon_filesel), |
| |
2398 GTK_WIDGET(dialog->icon_preview)); |
| |
2399 g_signal_connect(G_OBJECT(dialog->icon_filesel), "update-preview", |
| |
2400 G_CALLBACK(icon_preview_change_cb), dialog); |
| |
2401 g_signal_connect(G_OBJECT(dialog->icon_filesel), "response", |
| |
2402 G_CALLBACK(icon_filesel_choose_cb), dialog); |
| |
2403 icon_preview_change_cb(NULL, dialog); |
| |
2404 #else /* FILECHOOSER */ |
| |
2405 dialog->icon_filesel = gtk_file_selection_new(_("Buddy Icon")); |
| |
2406 dialog->icon_preview = gtk_image_new(); |
| |
2407 dialog->icon_text = gtk_label_new(NULL); |
| |
2408 if ((current_folder != NULL) && (*current_folder != '\0')) |
| |
2409 gtk_file_selection_set_filename(GTK_FILE_SELECTION(dialog->icon_filesel), |
| |
2410 current_folder); |
| |
2411 |
| |
2412 gtk_widget_set_size_request(GTK_WIDGET(dialog->icon_preview), -1, 50); |
| |
2413 hbox = gtk_hbox_new(FALSE, GAIM_HIG_BOX_SPACE); |
| |
2414 gtk_box_pack_start( |
| |
2415 GTK_BOX(GTK_FILE_SELECTION(dialog->icon_filesel)->main_vbox), |
| |
2416 hbox, FALSE, FALSE, 0); |
| |
2417 gtk_box_pack_end(GTK_BOX(hbox), dialog->icon_preview, |
| |
2418 FALSE, FALSE, 0); |
| |
2419 gtk_box_pack_end(GTK_BOX(hbox), dialog->icon_text, FALSE, FALSE, 0); |
| |
2420 |
| |
2421 tv = GTK_FILE_SELECTION(dialog->icon_filesel)->file_list; |
| |
2422 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tv)); |
| |
2423 |
| |
2424 g_signal_connect(G_OBJECT(sel), "changed", |
| |
2425 G_CALLBACK(icon_preview_change_cb), dialog); |
| |
2426 g_signal_connect( |
| |
2427 G_OBJECT(GTK_FILE_SELECTION(dialog->icon_filesel)->ok_button), |
| |
2428 "clicked", |
| |
2429 G_CALLBACK(icon_filesel_choose_cb), dialog); |
| |
2430 g_signal_connect( |
| |
2431 G_OBJECT(GTK_FILE_SELECTION(dialog->icon_filesel)->cancel_button), |
| |
2432 "clicked", |
| |
2433 G_CALLBACK(icon_filesel_delete_cb), dialog); |
| |
2434 g_signal_connect(G_OBJECT(dialog->icon_filesel), "destroy", |
| |
2435 G_CALLBACK(icon_filesel_delete_cb), dialog); |
| |
2436 #endif /* FILECHOOSER */ |
| |
2437 return dialog->icon_filesel; |
| |
2438 } |
| |
2439 |
| |
2440 |
| |
2441 #if GTK_CHECK_VERSION(2,2,0) |
| |
2442 static gboolean |
| |
2443 str_array_match(char **a, char **b) |
| |
2444 { |
| |
2445 int i, j; |
| |
2446 |
| |
2447 if (!a || !b) |
| |
2448 return FALSE; |
| |
2449 for (i = 0; a[i] != NULL; i++) |
| |
2450 for (j = 0; b[j] != NULL; j++) |
| |
2451 if (!g_ascii_strcasecmp(a[i], b[j])) |
| |
2452 return TRUE; |
| |
2453 return FALSE; |
| |
2454 } |
| |
2455 #endif |
| |
2456 |
| |
2457 char* |
| |
2458 gaim_gtk_convert_buddy_icon(GaimPlugin *plugin, const char *path) |
| |
2459 { |
| |
2460 #if GTK_CHECK_VERSION(2,2,0) |
| |
2461 int width, height; |
| |
2462 char **pixbuf_formats = NULL; |
| |
2463 GdkPixbufFormat *format; |
| |
2464 GdkPixbuf *pixbuf; |
| |
2465 GaimPluginProtocolInfo *prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(plugin); |
| |
2466 char **prpl_formats = g_strsplit (prpl_info->icon_spec.format,",",0); |
| |
2467 #if !GTK_CHECK_VERSION(2,4,0) |
| |
2468 GdkPixbufLoader *loader; |
| |
2469 FILE *file; |
| |
2470 struct stat st; |
| |
2471 void *data = NULL; |
| |
2472 #endif |
| |
2473 #endif |
| |
2474 const char *dirname = gaim_buddy_icons_get_cache_dir(); |
| |
2475 char *random = g_strdup_printf("%x", g_random_int()); |
| |
2476 char *filename = g_build_filename(dirname, random, NULL); |
| |
2477 |
| |
2478 if (!g_file_test(dirname, G_FILE_TEST_IS_DIR)) { |
| |
2479 gaim_debug_info("buddyicon", "Creating icon cache directory.\n"); |
| |
2480 |
| |
2481 if (g_mkdir(dirname, S_IRUSR | S_IWUSR | S_IXUSR) < 0) { |
| |
2482 gaim_debug_error("buddyicon", |
| |
2483 "Unable to create directory %s: %s\n", |
| |
2484 dirname, strerror(errno)); |
| |
2485 #if GTK_CHECK_VERSION(2,2,0) |
| |
2486 g_strfreev(prpl_formats); |
| |
2487 #endif |
| |
2488 g_free(random); |
| |
2489 g_free(filename); |
| |
2490 return NULL; |
| |
2491 } |
| |
2492 } |
| |
2493 |
| |
2494 #if GTK_CHECK_VERSION(2,2,0) |
| |
2495 #if GTK_CHECK_VERSION(2,4,0) |
| |
2496 format = gdk_pixbuf_get_file_info (path, &width, &height); |
| |
2497 #else |
| |
2498 loader = gdk_pixbuf_loader_new(); |
| |
2499 if (!g_stat(path, &st) && (file = g_fopen(path, "rb")) != NULL) { |
| |
2500 data = g_malloc(st.st_size); |
| |
2501 fread(data, 1, st.st_size, file); |
| |
2502 fclose(file); |
| |
2503 gdk_pixbuf_loader_write(loader, data, st.st_size, NULL); |
| |
2504 g_free(data); |
| |
2505 } |
| |
2506 gdk_pixbuf_loader_close(loader, NULL); |
| |
2507 pixbuf = gdk_pixbuf_loader_get_pixbuf(loader); |
| |
2508 width = gdk_pixbuf_get_width(pixbuf); |
| |
2509 height = gdk_pixbuf_get_height(pixbuf); |
| |
2510 format = gdk_pixbuf_loader_get_format(loader); |
| |
2511 g_object_unref(G_OBJECT(loader)); |
| |
2512 #endif |
| |
2513 pixbuf_formats = gdk_pixbuf_format_get_extensions(format); |
| |
2514 |
| |
2515 if (str_array_match(pixbuf_formats, prpl_formats) && /* This is an acceptable format AND */ |
| |
2516 (!(prpl_info->icon_spec.scale_rules & GAIM_ICON_SCALE_SEND) || /* The prpl doesn't scale before it sends OR */ |
| |
2517 (prpl_info->icon_spec.min_width <= width && |
| |
2518 prpl_info->icon_spec.max_width >= width && |
| |
2519 prpl_info->icon_spec.min_height <= height && |
| |
2520 prpl_info->icon_spec.max_height >= height))) /* The icon is the correct size */ |
| |
2521 #endif |
| |
2522 { |
| |
2523 gchar *contents; |
| |
2524 gsize length; |
| |
2525 FILE *image; |
| |
2526 |
| |
2527 #if GTK_CHECK_VERSION(2,2,0) |
| |
2528 g_strfreev(prpl_formats); |
| |
2529 g_strfreev(pixbuf_formats); |
| |
2530 #endif |
| |
2531 |
| |
2532 /* Copy the image to the cache folder as "filename". */ |
| |
2533 |
| |
2534 if (!g_file_get_contents(path, &contents, &length, NULL) || |
| |
2535 (image = g_fopen(filename, "wb")) == NULL) |
| |
2536 { |
| |
2537 g_free(random); |
| |
2538 g_free(filename); |
| |
2539 #if GTK_CHECK_VERSION(2,2,0) && !GTK_CHECK_VERSION(2,4,0) |
| |
2540 g_object_unref(G_OBJECT(pixbuf)); |
| |
2541 #endif |
| |
2542 return NULL; |
| |
2543 } |
| |
2544 |
| |
2545 if (fwrite(contents, 1, length, image) != length) |
| |
2546 { |
| |
2547 fclose(image); |
| |
2548 g_unlink(filename); |
| |
2549 |
| |
2550 g_free(random); |
| |
2551 g_free(filename); |
| |
2552 #if GTK_CHECK_VERSION(2,2,0) && !GTK_CHECK_VERSION(2,4,0) |
| |
2553 g_object_unref(G_OBJECT(pixbuf)); |
| |
2554 #endif |
| |
2555 return NULL; |
| |
2556 } |
| |
2557 fclose(image); |
| |
2558 |
| |
2559 #if GTK_CHECK_VERSION(2,2,0) && !GTK_CHECK_VERSION(2,4,0) |
| |
2560 g_object_unref(G_OBJECT(pixbuf)); |
| |
2561 #endif |
| |
2562 |
| |
2563 g_free(filename); |
| |
2564 return random; |
| |
2565 } |
| |
2566 #if GTK_CHECK_VERSION(2,2,0) |
| |
2567 else |
| |
2568 { |
| |
2569 int i; |
| |
2570 GError *error = NULL; |
| |
2571 GdkPixbuf *scale; |
| |
2572 pixbuf = gdk_pixbuf_new_from_file(path, &error); |
| |
2573 g_strfreev(pixbuf_formats); |
| |
2574 if (!error && (prpl_info->icon_spec.scale_rules & GAIM_ICON_SCALE_SEND) && |
| |
2575 (width < prpl_info->icon_spec.min_width || |
| |
2576 width > prpl_info->icon_spec.max_width || |
| |
2577 height < prpl_info->icon_spec.min_height || |
| |
2578 height > prpl_info->icon_spec.max_height)) |
| |
2579 { |
| |
2580 int new_width = width; |
| |
2581 int new_height = height; |
| |
2582 |
| |
2583 if(new_width > prpl_info->icon_spec.max_width) |
| |
2584 new_width = prpl_info->icon_spec.max_width; |
| |
2585 else if(new_width < prpl_info->icon_spec.min_width) |
| |
2586 new_width = prpl_info->icon_spec.min_width; |
| |
2587 if(new_height > prpl_info->icon_spec.max_height) |
| |
2588 new_height = prpl_info->icon_spec.max_height; |
| |
2589 else if(new_height < prpl_info->icon_spec.min_height) |
| |
2590 new_height = prpl_info->icon_spec.min_height; |
| |
2591 |
| |
2592 /* preserve aspect ratio */ |
| |
2593 if ((double)height * (double)new_width > |
| |
2594 (double)width * (double)new_height) { |
| |
2595 new_width = 0.5 + (double)width * (double)new_height / (double)height; |
| |
2596 } else { |
| |
2597 new_height = 0.5 + (double)height * (double)new_width / (double)width; |
| |
2598 } |
| |
2599 |
| |
2600 scale = gdk_pixbuf_scale_simple (pixbuf, new_width, new_height, |
| |
2601 GDK_INTERP_HYPER); |
| |
2602 g_object_unref(G_OBJECT(pixbuf)); |
| |
2603 pixbuf = scale; |
| |
2604 } |
| |
2605 if (error) { |
| |
2606 g_free(random); |
| |
2607 g_free(filename); |
| |
2608 gaim_debug_error("buddyicon", "Could not open icon for conversion: %s\n", error->message); |
| |
2609 g_error_free(error); |
| |
2610 g_strfreev(prpl_formats); |
| |
2611 return NULL; |
| |
2612 } |
| |
2613 |
| |
2614 for (i = 0; prpl_formats[i]; i++) { |
| |
2615 gaim_debug_info("buddyicon", "Converting buddy icon to %s as %s\n", prpl_formats[i], filename); |
| |
2616 /* The gdk-pixbuf documentation is wrong. gdk_pixbuf_save returns TRUE if it was successful, |
| |
2617 * FALSE if an error was set. */ |
| |
2618 if (gdk_pixbuf_save (pixbuf, filename, prpl_formats[i], &error, NULL) == TRUE) |
| |
2619 break; |
| |
2620 gaim_debug_warning("buddyicon", "Could not convert to %s: %s\n", prpl_formats[i], error->message); |
| |
2621 g_error_free(error); |
| |
2622 error = NULL; |
| |
2623 } |
| |
2624 g_strfreev(prpl_formats); |
| |
2625 if (!error) { |
| |
2626 g_object_unref(G_OBJECT(pixbuf)); |
| |
2627 g_free(filename); |
| |
2628 return random; |
| |
2629 } else { |
| |
2630 gaim_debug_error("buddyicon", "Could not convert icon to usable format: %s\n", error->message); |
| |
2631 g_error_free(error); |
| |
2632 } |
| |
2633 g_free(random); |
| |
2634 g_free(filename); |
| |
2635 g_object_unref(G_OBJECT(pixbuf)); |
| |
2636 } |
| |
2637 return NULL; |
| |
2638 #endif |
| |
2639 } |