pidgin/gtkutils.c

branch
next.minor
changeset 29496
8807ee3e55c5
parent 28234
4d001b258a59
child 29497
4502da3fe427
equal deleted inserted replaced
29495:87921e3ffe95 29496:8807ee3e55c5
1259 gint *x, 1259 gint *x,
1260 gint *y, 1260 gint *y,
1261 gboolean *push_in, 1261 gboolean *push_in,
1262 gpointer data) 1262 gpointer data)
1263 { 1263 {
1264 #if GTK_CHECK_VERSION(2,2,0)
1265 GtkWidget *widget; 1264 GtkWidget *widget;
1266 GtkRequisition requisition; 1265 GtkRequisition requisition;
1267 GdkScreen *screen; 1266 GdkScreen *screen;
1268 GdkRectangle monitor; 1267 GdkRectangle monitor;
1269 gint monitor_num; 1268 gint monitor_num;
1400 } 1399 }
1401 else 1400 else
1402 { 1401 {
1403 *y = monitor.y; 1402 *y = monitor.y;
1404 } 1403 }
1405 #endif
1406 } 1404 }
1407 1405
1408 1406
1409 void 1407 void
1410 pidgin_treeview_popup_menu_position_func(GtkMenu *menu, 1408 pidgin_treeview_popup_menu_position_func(GtkMenu *menu,
1637 else if (purple_str_has_suffix(basename, ".desktop") && (item = purple_desktop_item_new_from_file(filename))) { 1635 else if (purple_str_has_suffix(basename, ".desktop") && (item = purple_desktop_item_new_from_file(filename))) {
1638 PurpleDesktopItemType dtype; 1636 PurpleDesktopItemType dtype;
1639 char key[64]; 1637 char key[64];
1640 const char *itemname = NULL; 1638 const char *itemname = NULL;
1641 1639
1642 #if GTK_CHECK_VERSION(2,6,0)
1643 const char * const *langs; 1640 const char * const *langs;
1644 int i; 1641 int i;
1645 langs = g_get_language_names(); 1642 langs = g_get_language_names();
1646 for (i = 0; langs[i]; i++) { 1643 for (i = 0; langs[i]; i++) {
1647 g_snprintf(key, sizeof(key), "Name[%s]", langs[i]); 1644 g_snprintf(key, sizeof(key), "Name[%s]", langs[i]);
1648 itemname = purple_desktop_item_get_string(item, key); 1645 itemname = purple_desktop_item_get_string(item, key);
1649 break; 1646 break;
1650 } 1647 }
1651 #else 1648
1652 const char *lang = g_getenv("LANG");
1653 char *dot;
1654 dot = strchr(lang, '.');
1655 if (dot)
1656 *dot = '\0';
1657 g_snprintf(key, sizeof(key), "Name[%s]", lang);
1658 itemname = purple_desktop_item_get_string(item, key);
1659 #endif
1660 if (!itemname) 1649 if (!itemname)
1661 itemname = purple_desktop_item_get_string(item, "Name"); 1650 itemname = purple_desktop_item_get_string(item, "Name");
1662 1651
1663 dtype = purple_desktop_item_get_entry_type(item); 1652 dtype = purple_desktop_item_get_entry_type(item);
1664 switch (dtype) { 1653 switch (dtype) {
1671 gtk_imhtml_insert_link(GTK_IMHTML(gtkconv->entry), 1660 gtk_imhtml_insert_link(GTK_IMHTML(gtkconv->entry),
1672 gtk_text_buffer_get_insert(GTK_IMHTML(gtkconv->entry)->text_buffer), 1661 gtk_text_buffer_get_insert(GTK_IMHTML(gtkconv->entry)->text_buffer),
1673 purple_desktop_item_get_string(item, "URL"), itemname); 1662 purple_desktop_item_get_string(item, "URL"), itemname);
1674 break; 1663 break;
1675 default: 1664 default:
1676 /* I don't know if we really want to do anything here. Most of the desktop item types are crap like 1665 /* I don't know if we really want to do anything here. Most of
1677 * "MIME Type" (I have no clue how that would be a desktop item) and "Comment"... nothing we can really 1666 * the desktop item types are crap like "MIME Type" (I have no
1678 * send. The only logical one is "Application," but do we really want to send a binary and nothing else? 1667 * clue how that would be a desktop item) and "Comment"...
1679 * Probably not. I'll just give an error and return. */ 1668 * nothing we can really send. The only logical one is
1669 * "Application," but do we really want to send a binary and
1670 * nothing else? Probably not. I'll just give an error and
1671 * return. */
1680 /* The original patch sent the icon used by the launcher. That's probably wrong */ 1672 /* The original patch sent the icon used by the launcher. That's probably wrong */
1681 purple_notify_error(NULL, NULL, _("Cannot send launcher"), 1673 purple_notify_error(NULL, NULL, _("Cannot send launcher"),
1682 _("You dragged a desktop launcher. Most " 1674 _("You dragged a desktop launcher. Most "
1683 "likely you wanted to send the target " 1675 "likely you wanted to send the target "
1684 "of this launcher instead of this " 1676 "of this launcher instead of this "
1863 } 1855 }
1864 purple_menu_action_free(act); 1856 purple_menu_action_free(act);
1865 return menuitem; 1857 return menuitem;
1866 } 1858 }
1867 1859
1868 #if GTK_CHECK_VERSION(2,3,0)
1869 # define NEW_STYLE_COMPLETION
1870 #endif
1871
1872 typedef struct 1860 typedef struct
1873 { 1861 {
1874 GtkWidget *entry; 1862 GtkWidget *entry;
1875 GtkWidget *accountopt; 1863 GtkWidget *accountopt;
1876 1864
1877 PidginFilterBuddyCompletionEntryFunc filter_func; 1865 PidginFilterBuddyCompletionEntryFunc filter_func;
1878 gpointer filter_func_user_data; 1866 gpointer filter_func_user_data;
1879 1867
1880 #ifdef NEW_STYLE_COMPLETION
1881 GtkListStore *store; 1868 GtkListStore *store;
1882 #else
1883 GCompletion *completion;
1884 gboolean completion_started;
1885 GList *log_items;
1886 #endif /* NEW_STYLE_COMPLETION */
1887 } PidginCompletionData; 1869 } PidginCompletionData;
1888 1870
1889 #ifndef NEW_STYLE_COMPLETION
1890 static gboolean
1891 completion_entry_event(GtkEditable *entry, GdkEventKey *event,
1892 PidginCompletionData *data)
1893 {
1894 int pos, end_pos;
1895
1896 if (event->type == GDK_KEY_PRESS && event->keyval == GDK_Tab)
1897 {
1898 gtk_editable_get_selection_bounds(entry, &pos, &end_pos);
1899
1900 if (data->completion_started &&
1901 pos != end_pos && pos > 1 &&
1902 end_pos == strlen(gtk_entry_get_text(GTK_ENTRY(entry))))
1903 {
1904 gtk_editable_select_region(entry, 0, 0);
1905 gtk_editable_set_position(entry, -1);
1906
1907 return TRUE;
1908 }
1909 }
1910 else if (event->type == GDK_KEY_PRESS && event->length > 0)
1911 {
1912 char *prefix, *nprefix;
1913
1914 gtk_editable_get_selection_bounds(entry, &pos, &end_pos);
1915
1916 if (data->completion_started &&
1917 pos != end_pos && pos > 1 &&
1918 end_pos == strlen(gtk_entry_get_text(GTK_ENTRY(entry))))
1919 {
1920 char *temp;
1921
1922 temp = gtk_editable_get_chars(entry, 0, pos);
1923 prefix = g_strconcat(temp, event->string, NULL);
1924 g_free(temp);
1925 }
1926 else if (pos == end_pos && pos > 1 &&
1927 end_pos == strlen(gtk_entry_get_text(GTK_ENTRY(entry))))
1928 {
1929 prefix = g_strconcat(gtk_entry_get_text(GTK_ENTRY(entry)),
1930 event->string, NULL);
1931 }
1932 else
1933 return FALSE;
1934
1935 pos = strlen(prefix);
1936 nprefix = NULL;
1937
1938 g_completion_complete(data->completion, prefix, &nprefix);
1939
1940 if (nprefix != NULL)
1941 {
1942 gtk_entry_set_text(GTK_ENTRY(entry), nprefix);
1943 gtk_editable_set_position(entry, pos);
1944 gtk_editable_select_region(entry, pos, -1);
1945
1946 data->completion_started = TRUE;
1947
1948 g_free(nprefix);
1949 g_free(prefix);
1950
1951 return TRUE;
1952 }
1953
1954 g_free(prefix);
1955 }
1956
1957 return FALSE;
1958 }
1959
1960 static void
1961 destroy_completion_data(GtkWidget *w, PidginCompletionData *data)
1962 {
1963 g_list_foreach(data->completion->items, (GFunc)g_free, NULL);
1964 g_completion_free(data->completion);
1965
1966 g_free(data);
1967 }
1968 #endif /* !NEW_STYLE_COMPLETION */
1969
1970 #ifdef NEW_STYLE_COMPLETION
1971 static gboolean buddyname_completion_match_func(GtkEntryCompletion *completion, 1871 static gboolean buddyname_completion_match_func(GtkEntryCompletion *completion,
1972 const gchar *key, GtkTreeIter *iter, gpointer user_data) 1872 const gchar *key, GtkTreeIter *iter, gpointer user_data)
1973 { 1873 {
1974 GtkTreeModel *model; 1874 GtkTreeModel *model;
1975 GValue val1; 1875 GValue val1;
2099 -1); 1999 -1);
2100 } 2000 }
2101 2001
2102 g_free(normalized_buddyname); 2002 g_free(normalized_buddyname);
2103 } 2003 }
2104 #endif /* NEW_STYLE_COMPLETION */
2105 2004
2106 static void get_log_set_name(PurpleLogSet *set, gpointer value, PidginCompletionData *data) 2005 static void get_log_set_name(PurpleLogSet *set, gpointer value, PidginCompletionData *data)
2107 { 2006 {
2108 PidginFilterBuddyCompletionEntryFunc filter_func = data->filter_func; 2007 PidginFilterBuddyCompletionEntryFunc filter_func = data->filter_func;
2109 gpointer user_data = data->filter_func_user_data; 2008 gpointer user_data = data->filter_func_user_data;
2114 PidginBuddyCompletionEntry entry; 2013 PidginBuddyCompletionEntry entry;
2115 entry.is_buddy = FALSE; 2014 entry.is_buddy = FALSE;
2116 entry.entry.logged_buddy = set; 2015 entry.entry.logged_buddy = set;
2117 2016
2118 if (filter_func(&entry, user_data)) { 2017 if (filter_func(&entry, user_data)) {
2119 #ifdef NEW_STYLE_COMPLETION
2120 add_buddyname_autocomplete_entry(data->store, 2018 add_buddyname_autocomplete_entry(data->store,
2121 NULL, NULL, set->account, set->name); 2019 NULL, NULL, set->account, set->name);
2122 #else
2123 /* Steal the name for the GCompletion. */
2124 data->log_items = g_list_append(data->log_items, set->name);
2125 set->name = set->normalized_name = NULL;
2126 #endif /* NEW_STYLE_COMPLETION */
2127 } 2020 }
2128 } 2021 }
2129 } 2022 }
2130 2023
2131 static void 2024 static void
2134 PurpleBlistNode *gnode, *cnode, *bnode; 2027 PurpleBlistNode *gnode, *cnode, *bnode;
2135 PidginFilterBuddyCompletionEntryFunc filter_func = data->filter_func; 2028 PidginFilterBuddyCompletionEntryFunc filter_func = data->filter_func;
2136 gpointer user_data = data->filter_func_user_data; 2029 gpointer user_data = data->filter_func_user_data;
2137 GHashTable *sets; 2030 GHashTable *sets;
2138 2031
2139 #ifdef NEW_STYLE_COMPLETION
2140 gtk_list_store_clear(data->store); 2032 gtk_list_store_clear(data->store);
2141 #else
2142 GList *item = g_list_append(NULL, NULL);
2143
2144 g_list_foreach(data->completion->items, (GFunc)g_free, NULL);
2145 g_completion_clear_items(data->completion);
2146 #endif /* NEW_STYLE_COMPLETION */
2147 2033
2148 for (gnode = purple_get_blist()->root; gnode != NULL; gnode = gnode->next) 2034 for (gnode = purple_get_blist()->root; gnode != NULL; gnode = gnode->next)
2149 { 2035 {
2150 if (!PURPLE_BLIST_NODE_IS_GROUP(gnode)) 2036 if (!PURPLE_BLIST_NODE_IS_GROUP(gnode))
2151 continue; 2037 continue;
2160 PidginBuddyCompletionEntry entry; 2046 PidginBuddyCompletionEntry entry;
2161 entry.is_buddy = TRUE; 2047 entry.is_buddy = TRUE;
2162 entry.entry.buddy = (PurpleBuddy *) bnode; 2048 entry.entry.buddy = (PurpleBuddy *) bnode;
2163 2049
2164 if (filter_func(&entry, user_data)) { 2050 if (filter_func(&entry, user_data)) {
2165 #ifdef NEW_STYLE_COMPLETION
2166 add_buddyname_autocomplete_entry(data->store, 2051 add_buddyname_autocomplete_entry(data->store,
2167 ((PurpleContact *)cnode)->alias, 2052 ((PurpleContact *)cnode)->alias,
2168 purple_buddy_get_contact_alias(entry.entry.buddy), 2053 purple_buddy_get_contact_alias(entry.entry.buddy),
2169 entry.entry.buddy->account, 2054 entry.entry.buddy->account,
2170 entry.entry.buddy->name 2055 entry.entry.buddy->name
2171 ); 2056 );
2172 #else
2173 item->data = g_strdup(entry.entry.buddy->name);
2174 g_completion_add_items(data->completion, item);
2175 #endif /* NEW_STYLE_COMPLETION */
2176 } 2057 }
2177 } 2058 }
2178 } 2059 }
2179 } 2060 }
2180
2181 #ifndef NEW_STYLE_COMPLETION
2182 g_list_free(item);
2183 data->log_items = NULL;
2184 #endif /* NEW_STYLE_COMPLETION */
2185 2061
2186 sets = purple_log_get_log_sets(); 2062 sets = purple_log_get_log_sets();
2187 g_hash_table_foreach(sets, (GHFunc)get_log_set_name, data); 2063 g_hash_table_foreach(sets, (GHFunc)get_log_set_name, data);
2188 g_hash_table_destroy(sets); 2064 g_hash_table_destroy(sets);
2189 2065
2190 #ifndef NEW_STYLE_COMPLETION
2191 g_completion_add_items(data->completion, data->log_items);
2192 g_list_free(data->log_items);
2193 #endif /* NEW_STYLE_COMPLETION */
2194 } 2066 }
2195 2067
2196 static void 2068 static void
2197 buddyname_autocomplete_destroyed_cb(GtkWidget *widget, gpointer data) 2069 buddyname_autocomplete_destroyed_cb(GtkWidget *widget, gpointer data)
2198 { 2070 {
2209 void 2081 void
2210 pidgin_setup_screenname_autocomplete_with_filter(GtkWidget *entry, GtkWidget *accountopt, PidginFilterBuddyCompletionEntryFunc filter_func, gpointer user_data) 2082 pidgin_setup_screenname_autocomplete_with_filter(GtkWidget *entry, GtkWidget *accountopt, PidginFilterBuddyCompletionEntryFunc filter_func, gpointer user_data)
2211 { 2083 {
2212 PidginCompletionData *data; 2084 PidginCompletionData *data;
2213 2085
2214 #ifdef NEW_STYLE_COMPLETION
2215 /* 2086 /*
2216 * Store the displayed completion value, the buddy name, the UTF-8 2087 * Store the displayed completion value, the buddy name, the UTF-8
2217 * normalized & casefolded buddy name, the UTF-8 normalized & 2088 * normalized & casefolded buddy name, the UTF-8 normalized &
2218 * casefolded value for comparison, and the account. 2089 * casefolded value for comparison, and the account.
2219 */ 2090 */
2253 gtk_entry_completion_set_model(completion, GTK_TREE_MODEL(store)); 2124 gtk_entry_completion_set_model(completion, GTK_TREE_MODEL(store));
2254 g_object_unref(store); 2125 g_object_unref(store);
2255 2126
2256 gtk_entry_completion_set_text_column(completion, 0); 2127 gtk_entry_completion_set_text_column(completion, 0);
2257 2128
2258 #else /* !NEW_STYLE_COMPLETION */
2259
2260 data = g_new0(PidginCompletionData, 1);
2261
2262 data->entry = entry;
2263 data->accountopt = accountopt;
2264 if (filter_func == NULL) {
2265 data->filter_func = pidgin_screenname_autocomplete_default_filter;
2266 data->filter_func_user_data = NULL;
2267 } else {
2268 data->filter_func = filter_func;
2269 data->filter_func_user_data = user_data;
2270 }
2271 data->completion = g_completion_new(NULL);
2272 data->completion_started = FALSE;
2273
2274 add_completion_list(data);
2275
2276 g_completion_set_compare(data->completion, g_ascii_strncasecmp);
2277
2278 g_signal_connect(G_OBJECT(entry), "event",
2279 G_CALLBACK(completion_entry_event), data);
2280 g_signal_connect(G_OBJECT(entry), "destroy",
2281 G_CALLBACK(destroy_completion_data), data);
2282
2283 #endif /* !NEW_STYLE_COMPLETION */
2284
2285 purple_signal_connect(purple_connections_get_handle(), "signed-on", entry, 2129 purple_signal_connect(purple_connections_get_handle(), "signed-on", entry,
2286 PURPLE_CALLBACK(repopulate_autocomplete), data); 2130 PURPLE_CALLBACK(repopulate_autocomplete), data);
2287 purple_signal_connect(purple_connections_get_handle(), "signed-off", entry, 2131 purple_signal_connect(purple_connections_get_handle(), "signed-off", entry,
2288 PURPLE_CALLBACK(repopulate_autocomplete), data); 2132 PURPLE_CALLBACK(repopulate_autocomplete), data);
2289 2133
2323 2167
2324 cursor = gdk_cursor_new(cursor_type); 2168 cursor = gdk_cursor_new(cursor_type);
2325 gdk_window_set_cursor(widget->window, cursor); 2169 gdk_window_set_cursor(widget->window, cursor);
2326 gdk_cursor_unref(cursor); 2170 gdk_cursor_unref(cursor);
2327 2171
2328 #if GTK_CHECK_VERSION(2,4,0)
2329 gdk_display_flush(gdk_drawable_get_display(GDK_DRAWABLE(widget->window))); 2172 gdk_display_flush(gdk_drawable_get_display(GDK_DRAWABLE(widget->window)));
2330 #else
2331 gdk_flush();
2332 #endif
2333 } 2173 }
2334 2174
2335 void pidgin_clear_cursor(GtkWidget *widget) 2175 void pidgin_clear_cursor(GtkWidget *widget)
2336 { 2176 {
2337 g_return_if_fail(widget != NULL); 2177 g_return_if_fail(widget != NULL);
2348 2188
2349 void (*callback)(const char*,gpointer); 2189 void (*callback)(const char*,gpointer);
2350 gpointer data; 2190 gpointer data;
2351 }; 2191 };
2352 2192
2353 #if !GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
2354 static void
2355 icon_filesel_delete_cb(GtkWidget *w, struct _icon_chooser *dialog)
2356 {
2357 if (dialog->icon_filesel != NULL)
2358 gtk_widget_destroy(dialog->icon_filesel);
2359
2360 if (dialog->callback)
2361 dialog->callback(NULL, dialog->data);
2362
2363 g_free(dialog);
2364 }
2365 #endif /* FILECHOOSER */
2366
2367
2368
2369 #if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
2370 static void 2193 static void
2371 icon_filesel_choose_cb(GtkWidget *widget, gint response, struct _icon_chooser *dialog) 2194 icon_filesel_choose_cb(GtkWidget *widget, gint response, struct _icon_chooser *dialog)
2372 { 2195 {
2373 char *filename, *current_folder; 2196 char *filename, *current_folder;
2374 2197
2388 if (current_folder != NULL) { 2211 if (current_folder != NULL) {
2389 purple_prefs_set_path(PIDGIN_PREFS_ROOT "/filelocations/last_icon_folder", current_folder); 2212 purple_prefs_set_path(PIDGIN_PREFS_ROOT "/filelocations/last_icon_folder", current_folder);
2390 g_free(current_folder); 2213 g_free(current_folder);
2391 } 2214 }
2392 2215
2393 #else /* FILECHOOSER */ 2216
2394 static void
2395 icon_filesel_choose_cb(GtkWidget *w, struct _icon_chooser *dialog)
2396 {
2397 char *filename, *current_folder;
2398
2399 filename = g_strdup(gtk_file_selection_get_filename(
2400 GTK_FILE_SELECTION(dialog->icon_filesel)));
2401
2402 /* If they typed in a directory, change there */
2403 if (pidgin_check_if_dir(filename,
2404 GTK_FILE_SELECTION(dialog->icon_filesel)))
2405 {
2406 g_free(filename);
2407 return;
2408 }
2409
2410 current_folder = g_path_get_dirname(filename);
2411 if (current_folder != NULL) {
2412 purple_prefs_set_path(PIDGIN_PREFS_ROOT "/filelocations/last_icon_folder", current_folder);
2413 g_free(current_folder);
2414 }
2415
2416 #endif /* FILECHOOSER */
2417 #if 0 /* mismatched curly braces */
2418 }
2419 #endif
2420 if (dialog->callback) 2217 if (dialog->callback)
2421 dialog->callback(filename, dialog->data); 2218 dialog->callback(filename, dialog->data);
2422 gtk_widget_destroy(dialog->icon_filesel); 2219 gtk_widget_destroy(dialog->icon_filesel);
2423 g_free(filename); 2220 g_free(filename);
2424 g_free(dialog); 2221 g_free(dialog);
2425 } 2222 }
2426 2223
2427 2224
2428 static void 2225 static void
2429 #if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
2430 icon_preview_change_cb(GtkFileChooser *widget, struct _icon_chooser *dialog) 2226 icon_preview_change_cb(GtkFileChooser *widget, struct _icon_chooser *dialog)
2431 #else /* FILECHOOSER */
2432 icon_preview_change_cb(GtkTreeSelection *sel, struct _icon_chooser *dialog)
2433 #endif /* FILECHOOSER */
2434 { 2227 {
2435 GdkPixbuf *pixbuf, *scale; 2228 GdkPixbuf *pixbuf, *scale;
2436 int height, width; 2229 int height, width;
2437 char *basename, *markup, *size; 2230 char *basename, *markup, *size;
2438 struct stat st; 2231 struct stat st;
2439 char *filename; 2232 char *filename;
2440 2233
2441 #if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
2442 filename = gtk_file_chooser_get_preview_filename( 2234 filename = gtk_file_chooser_get_preview_filename(
2443 GTK_FILE_CHOOSER(dialog->icon_filesel)); 2235 GTK_FILE_CHOOSER(dialog->icon_filesel));
2444 #else /* FILECHOOSER */
2445 filename = g_strdup(gtk_file_selection_get_filename(
2446 GTK_FILE_SELECTION(dialog->icon_filesel)));
2447 #endif /* FILECHOOSER */
2448 2236
2449 if (!filename || g_stat(filename, &st) || !(pixbuf = gdk_pixbuf_new_from_file(filename, NULL))) 2237 if (!filename || g_stat(filename, &st) || !(pixbuf = gdk_pixbuf_new_from_file(filename, NULL)))
2450 { 2238 {
2451 gtk_image_set_from_pixbuf(GTK_IMAGE(dialog->icon_preview), NULL); 2239 gtk_image_set_from_pixbuf(GTK_IMAGE(dialog->icon_preview), NULL);
2452 gtk_label_set_markup(GTK_LABEL(dialog->icon_text), ""); 2240 gtk_label_set_markup(GTK_LABEL(dialog->icon_text), "");
2478 2266
2479 2267
2480 GtkWidget *pidgin_buddy_icon_chooser_new(GtkWindow *parent, void(*callback)(const char *, gpointer), gpointer data) { 2268 GtkWidget *pidgin_buddy_icon_chooser_new(GtkWindow *parent, void(*callback)(const char *, gpointer), gpointer data) {
2481 struct _icon_chooser *dialog = g_new0(struct _icon_chooser, 1); 2269 struct _icon_chooser *dialog = g_new0(struct _icon_chooser, 1);
2482 2270
2483 #if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
2484 GtkWidget *vbox; 2271 GtkWidget *vbox;
2485 #else
2486 GtkWidget *hbox;
2487 GtkWidget *tv;
2488 GtkTreeSelection *sel;
2489 #endif /* FILECHOOSER */
2490 const char *current_folder; 2272 const char *current_folder;
2491 2273
2492 dialog->callback = callback; 2274 dialog->callback = callback;
2493 dialog->data = data; 2275 dialog->data = data;
2494 2276
2495 current_folder = purple_prefs_get_path(PIDGIN_PREFS_ROOT "/filelocations/last_icon_folder"); 2277 current_folder = purple_prefs_get_path(PIDGIN_PREFS_ROOT "/filelocations/last_icon_folder");
2496 #if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
2497 2278
2498 dialog->icon_filesel = gtk_file_chooser_dialog_new(_("Buddy Icon"), 2279 dialog->icon_filesel = gtk_file_chooser_dialog_new(_("Buddy Icon"),
2499 parent, 2280 parent,
2500 GTK_FILE_CHOOSER_ACTION_OPEN, 2281 GTK_FILE_CHOOSER_ACTION_OPEN,
2501 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, 2282 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
2522 g_signal_connect(G_OBJECT(dialog->icon_filesel), "update-preview", 2303 g_signal_connect(G_OBJECT(dialog->icon_filesel), "update-preview",
2523 G_CALLBACK(icon_preview_change_cb), dialog); 2304 G_CALLBACK(icon_preview_change_cb), dialog);
2524 g_signal_connect(G_OBJECT(dialog->icon_filesel), "response", 2305 g_signal_connect(G_OBJECT(dialog->icon_filesel), "response",
2525 G_CALLBACK(icon_filesel_choose_cb), dialog); 2306 G_CALLBACK(icon_filesel_choose_cb), dialog);
2526 icon_preview_change_cb(NULL, dialog); 2307 icon_preview_change_cb(NULL, dialog);
2527 #else /* FILECHOOSER */
2528 dialog->icon_filesel = gtk_file_selection_new(_("Buddy Icon"));
2529 dialog->icon_preview = gtk_image_new();
2530 dialog->icon_text = gtk_label_new(NULL);
2531 if ((current_folder != NULL) && (*current_folder != '\0'))
2532 gtk_file_selection_set_filename(GTK_FILE_SELECTION(dialog->icon_filesel),
2533 current_folder);
2534
2535 gtk_widget_set_size_request(GTK_WIDGET(dialog->icon_preview),-1, 50);
2536 hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
2537 gtk_box_pack_start(
2538 GTK_BOX(GTK_FILE_SELECTION(dialog->icon_filesel)->main_vbox),
2539 hbox, FALSE, FALSE, 0);
2540 gtk_box_pack_end(GTK_BOX(hbox), dialog->icon_preview,
2541 FALSE, FALSE, 0);
2542 gtk_box_pack_end(GTK_BOX(hbox), dialog->icon_text, FALSE, FALSE, 0);
2543
2544 tv = GTK_FILE_SELECTION(dialog->icon_filesel)->file_list;
2545 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tv));
2546
2547 g_signal_connect(G_OBJECT(sel), "changed",
2548 G_CALLBACK(icon_preview_change_cb), dialog);
2549 g_signal_connect(
2550 G_OBJECT(GTK_FILE_SELECTION(dialog->icon_filesel)->ok_button),
2551 "clicked",
2552 G_CALLBACK(icon_filesel_choose_cb), dialog);
2553 g_signal_connect(
2554 G_OBJECT(GTK_FILE_SELECTION(dialog->icon_filesel)->cancel_button),
2555 "clicked",
2556 G_CALLBACK(icon_filesel_delete_cb), dialog);
2557 g_signal_connect(G_OBJECT(dialog->icon_filesel), "destroy",
2558 G_CALLBACK(icon_filesel_delete_cb), dialog);
2559 #endif /* FILECHOOSER */
2560 2308
2561 #ifdef _WIN32 2309 #ifdef _WIN32
2562 g_signal_connect(G_OBJECT(dialog->icon_filesel), "show", 2310 g_signal_connect(G_OBJECT(dialog->icon_filesel), "show",
2563 G_CALLBACK(winpidgin_ensure_onscreen), dialog->icon_filesel); 2311 G_CALLBACK(winpidgin_ensure_onscreen), dialog->icon_filesel);
2564 #endif 2312 #endif
2565 2313
2566 return dialog->icon_filesel; 2314 return dialog->icon_filesel;
2567 } 2315 }
2568 2316
2569 2317
2570 #if GTK_CHECK_VERSION(2,2,0)
2571 static gboolean 2318 static gboolean
2572 str_array_match(char **a, char **b) 2319 str_array_match(char **a, char **b)
2573 { 2320 {
2574 int i, j; 2321 int i, j;
2575 2322
2579 for (j = 0; b[j] != NULL; j++) 2326 for (j = 0; b[j] != NULL; j++)
2580 if (!g_ascii_strcasecmp(a[i], b[j])) 2327 if (!g_ascii_strcasecmp(a[i], b[j]))
2581 return TRUE; 2328 return TRUE;
2582 return FALSE; 2329 return FALSE;
2583 } 2330 }
2584 #endif
2585 2331
2586 gpointer 2332 gpointer
2587 pidgin_convert_buddy_icon(PurplePlugin *plugin, const char *path, size_t *len) 2333 pidgin_convert_buddy_icon(PurplePlugin *plugin, const char *path, size_t *len)
2588 { 2334 {
2589 PurplePluginProtocolInfo *prpl_info; 2335 PurplePluginProtocolInfo *prpl_info;
2590 #if GTK_CHECK_VERSION(2,2,0)
2591 char **prpl_formats; 2336 char **prpl_formats;
2592 int width, height; 2337 int width, height;
2593 char **pixbuf_formats = NULL; 2338 char **pixbuf_formats = NULL;
2594 GdkPixbufFormat *format; 2339 GdkPixbufFormat *format;
2595 GdkPixbuf *pixbuf; 2340 GdkPixbuf *pixbuf;
2596 #if !GTK_CHECK_VERSION(2,4,0)
2597 GdkPixbufLoader *loader;
2598 #endif
2599 #endif
2600 gchar *contents; 2341 gchar *contents;
2601 gsize length; 2342 gsize length;
2602 2343
2603 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(plugin); 2344 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(plugin);
2604 2345
2605 g_return_val_if_fail(prpl_info->icon_spec.format != NULL, NULL); 2346 g_return_val_if_fail(prpl_info->icon_spec.format != NULL, NULL);
2606 2347
2607 2348
2608 #if GTK_CHECK_VERSION(2,2,0)
2609 #if GTK_CHECK_VERSION(2,4,0)
2610 format = gdk_pixbuf_get_file_info(path, &width, &height); 2349 format = gdk_pixbuf_get_file_info(path, &width, &height);
2611 #else 2350
2612 loader = gdk_pixbuf_loader_new();
2613 if (g_file_get_contents(path, &contents, &length, NULL)) {
2614 gdk_pixbuf_loader_write(loader, contents, length, NULL);
2615 g_free(contents);
2616 }
2617 gdk_pixbuf_loader_close(loader, NULL);
2618 pixbuf = gdk_pixbuf_loader_get_pixbuf(loader);
2619 width = gdk_pixbuf_get_width(pixbuf);
2620 height = gdk_pixbuf_get_height(pixbuf);
2621 format = gdk_pixbuf_loader_get_format(loader);
2622 g_object_unref(G_OBJECT(loader));
2623 #endif
2624 if (format == NULL) 2351 if (format == NULL)
2625 return NULL; 2352 return NULL;
2626 2353
2627 pixbuf_formats = gdk_pixbuf_format_get_extensions(format); 2354 pixbuf_formats = gdk_pixbuf_format_get_extensions(format);
2628 prpl_formats = g_strsplit(prpl_info->icon_spec.format,",",0); 2355 prpl_formats = g_strsplit(prpl_info->icon_spec.format,",",0);
2630 (!(prpl_info->icon_spec.scale_rules & PURPLE_ICON_SCALE_SEND) || /* The prpl doesn't scale before it sends OR */ 2357 (!(prpl_info->icon_spec.scale_rules & PURPLE_ICON_SCALE_SEND) || /* The prpl doesn't scale before it sends OR */
2631 (prpl_info->icon_spec.min_width <= width && 2358 (prpl_info->icon_spec.min_width <= width &&
2632 prpl_info->icon_spec.max_width >= width && 2359 prpl_info->icon_spec.max_width >= width &&
2633 prpl_info->icon_spec.min_height <= height && 2360 prpl_info->icon_spec.min_height <= height &&
2634 prpl_info->icon_spec.max_height >= height))) /* The icon is the correct size */ 2361 prpl_info->icon_spec.max_height >= height))) /* The icon is the correct size */
2635 #endif
2636 { 2362 {
2637 #if GTK_CHECK_VERSION(2,2,0)
2638 g_strfreev(prpl_formats); 2363 g_strfreev(prpl_formats);
2639 g_strfreev(pixbuf_formats); 2364 g_strfreev(pixbuf_formats);
2640 #endif 2365
2641 /* We don't need to scale the image. */ 2366 /* We don't need to scale the image. */
2642
2643 contents = NULL; 2367 contents = NULL;
2644 if (!g_file_get_contents(path, &contents, &length, NULL)) 2368 if (!g_file_get_contents(path, &contents, &length, NULL))
2645 { 2369 {
2646 g_free(contents); 2370 g_free(contents);
2647 #if GTK_CHECK_VERSION(2,2,0) && !GTK_CHECK_VERSION(2,4,0)
2648 g_object_unref(G_OBJECT(pixbuf));
2649 #endif
2650 return NULL; 2371 return NULL;
2651 } 2372 }
2652 } 2373 }
2653 #if GTK_CHECK_VERSION(2,2,0)
2654 else 2374 else
2655 { 2375 {
2656 int i; 2376 int i;
2657 GError *error = NULL; 2377 GError *error = NULL;
2658 GdkPixbuf *scale; 2378 GdkPixbuf *scale;
2769 } 2489 }
2770 2490
2771 if (len) 2491 if (len)
2772 *len = length; 2492 *len = length;
2773 return contents; 2493 return contents;
2774 #else 2494 }
2775 /*
2776 * The chosen icon wasn't the right size, and we're using
2777 * GTK+ 2.0 so we can't scale it.
2778 */
2779 return NULL;
2780 #endif
2781 }
2782
2783 #if !GTK_CHECK_VERSION(2,6,0)
2784 static void
2785 _gdk_file_scale_size_prepared_cb (GdkPixbufLoader *loader,
2786 int width,
2787 int height,
2788 gpointer data)
2789 {
2790 struct {
2791 gint width;
2792 gint height;
2793 gboolean preserve_aspect_ratio;
2794 } *info = data;
2795
2796 g_return_if_fail (width > 0 && height > 0);
2797
2798 if (info->preserve_aspect_ratio &&
2799 (info->width > 0 || info->height > 0)) {
2800 if (info->width < 0)
2801 {
2802 width = width * (double)info->height/(double)height;
2803 height = info->height;
2804 }
2805 else if (info->height < 0)
2806 {
2807 height = height * (double)info->width/(double)width;
2808 width = info->width;
2809 }
2810 else if ((double)height * (double)info->width >
2811 (double)width * (double)info->height) {
2812 width = 0.5 + (double)width * (double)info->height / (double)height;
2813 height = info->height;
2814 } else {
2815 height = 0.5 + (double)height * (double)info->width / (double)width;
2816 width = info->width;
2817 }
2818 } else {
2819 if (info->width > 0)
2820 width = info->width;
2821 if (info->height > 0)
2822 height = info->height;
2823 }
2824
2825 #if GTK_CHECK_VERSION(2,2,0) /* 2.0 users are going to have very strangely sized things */
2826 gdk_pixbuf_loader_set_size (loader, width, height);
2827 #else
2828 #warning nosnilmot could not be bothered to fix this properly for you
2829 #warning ... good luck ... your images may end up strange sizes
2830 #endif
2831 }
2832
2833 GdkPixbuf *
2834 gdk_pixbuf_new_from_file_at_scale(const char *filename, int width, int height,
2835 gboolean preserve_aspect_ratio,
2836 GError **error)
2837 {
2838 GdkPixbufLoader *loader;
2839 GdkPixbuf *pixbuf;
2840 guchar buffer [4096];
2841 int length;
2842 FILE *f;
2843 struct {
2844 gint width;
2845 gint height;
2846 gboolean preserve_aspect_ratio;
2847 } info;
2848 GdkPixbufAnimation *animation;
2849 GdkPixbufAnimationIter *iter;
2850 gboolean has_frame;
2851
2852 g_return_val_if_fail (filename != NULL, NULL);
2853 g_return_val_if_fail (width > 0 || width == -1, NULL);
2854 g_return_val_if_fail (height > 0 || height == -1, NULL);
2855
2856 f = g_fopen (filename, "rb");
2857 if (!f) {
2858 gint save_errno = errno;
2859 gchar *display_name = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
2860 g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (save_errno),
2861 _("Failed to open file '%s': %s"),
2862 display_name ? display_name : "(unknown)",
2863 g_strerror (save_errno));
2864 g_free (display_name);
2865 return NULL;
2866 }
2867
2868 loader = gdk_pixbuf_loader_new ();
2869
2870 info.width = width;
2871 info.height = height;
2872 info.preserve_aspect_ratio = preserve_aspect_ratio;
2873
2874 g_signal_connect (loader, "size-prepared", G_CALLBACK (_gdk_file_scale_size_prepared_cb), &info);
2875
2876 has_frame = FALSE;
2877 while (!has_frame && !feof (f) && !ferror (f)) {
2878 length = fread (buffer, 1, sizeof (buffer), f);
2879 if (length > 0)
2880 if (!gdk_pixbuf_loader_write (loader, buffer, length, error)) {
2881 gdk_pixbuf_loader_close (loader, NULL);
2882 fclose (f);
2883 g_object_unref (loader);
2884 return NULL;
2885 }
2886
2887 animation = gdk_pixbuf_loader_get_animation (loader);
2888 if (animation) {
2889 iter = gdk_pixbuf_animation_get_iter (animation, 0);
2890 if (!gdk_pixbuf_animation_iter_on_currently_loading_frame (iter)) {
2891 has_frame = TRUE;
2892 }
2893 g_object_unref (iter);
2894 }
2895 }
2896
2897 fclose (f);
2898
2899 if (!gdk_pixbuf_loader_close (loader, error) && !has_frame) {
2900 g_object_unref (loader);
2901 return NULL;
2902 }
2903
2904 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
2905
2906 if (!pixbuf) {
2907 gchar *display_name = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
2908 g_object_unref (loader);
2909 g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED,
2910 _("Failed to load image '%s': reason not known, probably a corrupt image file"),
2911 display_name ? display_name : "(unknown)");
2912 g_free (display_name);
2913 return NULL;
2914 }
2915
2916 g_object_ref (pixbuf);
2917
2918 g_object_unref (loader);
2919
2920 return pixbuf;
2921 }
2922 #endif /* ! Gtk 2.6.0 */
2923 2495
2924 void pidgin_set_custom_buddy_icon(PurpleAccount *account, const char *who, const char *filename) 2496 void pidgin_set_custom_buddy_icon(PurpleAccount *account, const char *who, const char *filename)
2925 { 2497 {
2926 PurpleBuddy *buddy; 2498 PurpleBuddy *buddy;
2927 PurpleContact *contact; 2499 PurpleContact *contact;
2951 return ret; 2523 return ret;
2952 } 2524 }
2953 2525
2954 void pidgin_set_urgent(GtkWindow *window, gboolean urgent) 2526 void pidgin_set_urgent(GtkWindow *window, gboolean urgent)
2955 { 2527 {
2956 #if GTK_CHECK_VERSION(2,8,0)
2957 gtk_window_set_urgency_hint(window, urgent); 2528 gtk_window_set_urgency_hint(window, urgent);
2958 #elif defined _WIN32 2529 #if defined _WIN32
2959 winpidgin_window_flash(window, urgent); 2530 winpidgin_window_flash(window, urgent);
2960 #elif defined GDK_WINDOWING_X11
2961 GdkWindow *gdkwin;
2962 XWMHints *hints;
2963
2964 g_return_if_fail(window != NULL);
2965
2966 gdkwin = GTK_WIDGET(window)->window;
2967
2968 g_return_if_fail(gdkwin != NULL);
2969
2970 hints = XGetWMHints(GDK_WINDOW_XDISPLAY(gdkwin),
2971 GDK_WINDOW_XWINDOW(gdkwin));
2972 if(!hints)
2973 hints = XAllocWMHints();
2974
2975 if (urgent)
2976 hints->flags |= XUrgencyHint;
2977 else
2978 hints->flags &= ~XUrgencyHint;
2979 XSetWMHints(GDK_WINDOW_XDISPLAY(gdkwin),
2980 GDK_WINDOW_XWINDOW(gdkwin), hints);
2981 XFree(hints);
2982 #else
2983 /* do something else? */
2984 #endif 2531 #endif
2985 } 2532 }
2986 2533
2987 static GSList *minidialogs = NULL; 2534 static GSList *minidialogs = NULL;
2988 2535
3287 style->text_aa[GTK_STATE_NORMAL].green >> 8, 2834 style->text_aa[GTK_STATE_NORMAL].green >> 8,
3288 style->text_aa[GTK_STATE_NORMAL].blue >> 8); 2835 style->text_aa[GTK_STATE_NORMAL].blue >> 8);
3289 return dim_grey_string; 2836 return dim_grey_string;
3290 } 2837 }
3291 2838
3292 #if !GTK_CHECK_VERSION(2,2,0)
3293 GtkTreePath *
3294 gtk_tree_path_new_from_indices (gint first_index, ...)
3295 {
3296 int arg;
3297 va_list args;
3298 GtkTreePath *path;
3299
3300 path = gtk_tree_path_new ();
3301
3302 va_start (args, first_index);
3303 arg = first_index;
3304
3305 while (arg != -1)
3306 {
3307 gtk_tree_path_append_index (path, arg);
3308 arg = va_arg (args, gint);
3309 }
3310
3311 va_end (args);
3312
3313 return path;
3314 }
3315 #endif
3316
3317 static void 2839 static void
3318 combo_box_changed_cb(GtkComboBox *combo_box, GtkEntry *entry) 2840 combo_box_changed_cb(GtkComboBox *combo_box, GtkEntry *entry)
3319 { 2841 {
3320 char *text = gtk_combo_box_get_active_text(combo_box); 2842 char *text = gtk_combo_box_get_active_text(combo_box);
3321 gtk_entry_set_text(entry, text ? text : ""); 2843 gtk_entry_set_text(entry, text ? text : "");
3457 return TRUE; 2979 return TRUE;
3458 } 2980 }
3459 return FALSE; 2981 return FALSE;
3460 #endif 2982 #endif
3461 #else 2983 #else
3462 #if GTK_CHECK_VERSION(2,4,0)
3463 /* This finds the currently active window and makes that the parent window. */ 2984 /* This finds the currently active window and makes that the parent window. */
3464 GList *windows = NULL; 2985 GList *windows = NULL;
3465 GtkWidget *parent = NULL; 2986 GtkWidget *parent = NULL;
3466 GdkEvent *event = gtk_get_current_event(); 2987 GdkEvent *event = gtk_get_current_event();
3467 GdkWindow *menu = NULL; 2988 GdkWindow *menu = NULL;
3500 g_list_free(windows); 3021 g_list_free(windows);
3501 if (parent) { 3022 if (parent) {
3502 gtk_window_set_transient_for(GTK_WINDOW(widget), GTK_WINDOW(parent)); 3023 gtk_window_set_transient_for(GTK_WINDOW(widget), GTK_WINDOW(parent));
3503 return TRUE; 3024 return TRUE;
3504 } 3025 }
3505 #endif
3506 return FALSE; 3026 return FALSE;
3507 #endif 3027 #endif
3508 } 3028 }
3509 3029
3510 GdkPixbuf * pidgin_pixbuf_from_imgstore(PurpleStoredImage *image) 3030 GdkPixbuf * pidgin_pixbuf_from_imgstore(PurpleStoredImage *image)
3697 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img); 3217 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img);
3698 g_signal_connect_swapped(G_OBJECT(item), "activate", G_CALLBACK(gtk_imhtml_link_activate), link); 3218 g_signal_connect_swapped(G_OBJECT(item), "activate", G_CALLBACK(gtk_imhtml_link_activate), link);
3699 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); 3219 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
3700 3220
3701 /* Open Containing Directory */ 3221 /* Open Containing Directory */
3702 #if GTK_CHECK_VERSION(2,6,0)
3703 img = gtk_image_new_from_stock(GTK_STOCK_DIRECTORY, GTK_ICON_SIZE_MENU); 3222 img = gtk_image_new_from_stock(GTK_STOCK_DIRECTORY, GTK_ICON_SIZE_MENU);
3704 item = gtk_image_menu_item_new_with_mnemonic(_("Open _Containing Directory")); 3223 item = gtk_image_menu_item_new_with_mnemonic(_("Open _Containing Directory"));
3705 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img); 3224 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img);
3706 #else 3225
3707 item = gtk_menu_item_new_with_mnemonic(_("Open _Containing Directory"));
3708 #endif
3709 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(open_containing_cb), (gpointer)url); 3226 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(open_containing_cb), (gpointer)url);
3710 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); 3227 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
3711 3228
3712 return TRUE; 3229 return TRUE;
3713 } 3230 }
3769 return TRUE; 3286 return TRUE;
3770 3287
3771 url = gtk_imhtml_link_get_url(link); 3288 url = gtk_imhtml_link_get_url(link);
3772 3289
3773 /* Play Sound */ 3290 /* Play Sound */
3774 #if GTK_CHECK_VERSION(2,6,0)
3775 img = gtk_image_new_from_stock(GTK_STOCK_MEDIA_PLAY, GTK_ICON_SIZE_MENU); 3291 img = gtk_image_new_from_stock(GTK_STOCK_MEDIA_PLAY, GTK_ICON_SIZE_MENU);
3776 item = gtk_image_menu_item_new_with_mnemonic(_("_Play Sound")); 3292 item = gtk_image_menu_item_new_with_mnemonic(_("_Play Sound"));
3777 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img); 3293 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img);
3778 #else 3294
3779 item = gtk_menu_item_new_with_mnemonic(_("_Play Sound"));
3780 #endif
3781 g_signal_connect_swapped(G_OBJECT(item), "activate", G_CALLBACK(gtk_imhtml_link_activate), link); 3295 g_signal_connect_swapped(G_OBJECT(item), "activate", G_CALLBACK(gtk_imhtml_link_activate), link);
3782 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); 3296 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
3783 3297
3784 /* Save File */ 3298 /* Save File */
3785 img = gtk_image_new_from_stock(GTK_STOCK_SAVE, GTK_ICON_SIZE_MENU); 3299 img = gtk_image_new_from_stock(GTK_STOCK_SAVE, GTK_ICON_SIZE_MENU);

mercurial