| 1628 else if (purple_str_has_suffix(basename, ".desktop") && (item = purple_desktop_item_new_from_file(filename))) { |
1626 else if (purple_str_has_suffix(basename, ".desktop") && (item = purple_desktop_item_new_from_file(filename))) { |
| 1629 PurpleDesktopItemType dtype; |
1627 PurpleDesktopItemType dtype; |
| 1630 char key[64]; |
1628 char key[64]; |
| 1631 const char *itemname = NULL; |
1629 const char *itemname = NULL; |
| 1632 |
1630 |
| 1633 #if GTK_CHECK_VERSION(2,6,0) |
|
| 1634 const char * const *langs; |
1631 const char * const *langs; |
| 1635 int i; |
1632 int i; |
| 1636 langs = g_get_language_names(); |
1633 langs = g_get_language_names(); |
| 1637 for (i = 0; langs[i]; i++) { |
1634 for (i = 0; langs[i]; i++) { |
| 1638 g_snprintf(key, sizeof(key), "Name[%s]", langs[i]); |
1635 g_snprintf(key, sizeof(key), "Name[%s]", langs[i]); |
| 1639 itemname = purple_desktop_item_get_string(item, key); |
1636 itemname = purple_desktop_item_get_string(item, key); |
| 1640 break; |
1637 break; |
| 1641 } |
1638 } |
| 1642 #else |
1639 |
| 1643 const char *lang = g_getenv("LANG"); |
|
| 1644 char *dot; |
|
| 1645 dot = strchr(lang, '.'); |
|
| 1646 if (dot) |
|
| 1647 *dot = '\0'; |
|
| 1648 g_snprintf(key, sizeof(key), "Name[%s]", lang); |
|
| 1649 itemname = purple_desktop_item_get_string(item, key); |
|
| 1650 #endif |
|
| 1651 if (!itemname) |
1640 if (!itemname) |
| 1652 itemname = purple_desktop_item_get_string(item, "Name"); |
1641 itemname = purple_desktop_item_get_string(item, "Name"); |
| 1653 |
1642 |
| 1654 dtype = purple_desktop_item_get_entry_type(item); |
1643 dtype = purple_desktop_item_get_entry_type(item); |
| 1655 switch (dtype) { |
1644 switch (dtype) { |
| 1662 gtk_imhtml_insert_link(GTK_IMHTML(gtkconv->entry), |
1651 gtk_imhtml_insert_link(GTK_IMHTML(gtkconv->entry), |
| 1663 gtk_text_buffer_get_insert(GTK_IMHTML(gtkconv->entry)->text_buffer), |
1652 gtk_text_buffer_get_insert(GTK_IMHTML(gtkconv->entry)->text_buffer), |
| 1664 purple_desktop_item_get_string(item, "URL"), itemname); |
1653 purple_desktop_item_get_string(item, "URL"), itemname); |
| 1665 break; |
1654 break; |
| 1666 default: |
1655 default: |
| 1667 /* I don't know if we really want to do anything here. Most of the desktop item types are crap like |
1656 /* I don't know if we really want to do anything here. Most of |
| 1668 * "MIME Type" (I have no clue how that would be a desktop item) and "Comment"... nothing we can really |
1657 * the desktop item types are crap like "MIME Type" (I have no |
| 1669 * send. The only logical one is "Application," but do we really want to send a binary and nothing else? |
1658 * clue how that would be a desktop item) and "Comment"... |
| 1670 * Probably not. I'll just give an error and return. */ |
1659 * nothing we can really send. The only logical one is |
| |
1660 * "Application," but do we really want to send a binary and |
| |
1661 * nothing else? Probably not. I'll just give an error and |
| |
1662 * return. */ |
| 1671 /* The original patch sent the icon used by the launcher. That's probably wrong */ |
1663 /* The original patch sent the icon used by the launcher. That's probably wrong */ |
| 1672 purple_notify_error(NULL, NULL, _("Cannot send launcher"), |
1664 purple_notify_error(NULL, NULL, _("Cannot send launcher"), |
| 1673 _("You dragged a desktop launcher. Most " |
1665 _("You dragged a desktop launcher. Most " |
| 1674 "likely you wanted to send the target " |
1666 "likely you wanted to send the target " |
| 1675 "of this launcher instead of this " |
1667 "of this launcher instead of this " |
| 1860 } |
1852 } |
| 1861 purple_menu_action_free(act); |
1853 purple_menu_action_free(act); |
| 1862 return menuitem; |
1854 return menuitem; |
| 1863 } |
1855 } |
| 1864 |
1856 |
| 1865 #if GTK_CHECK_VERSION(2,3,0) |
|
| 1866 # define NEW_STYLE_COMPLETION |
|
| 1867 #endif |
|
| 1868 |
|
| 1869 typedef struct |
1857 typedef struct |
| 1870 { |
1858 { |
| 1871 GtkWidget *entry; |
1859 GtkWidget *entry; |
| 1872 GtkWidget *accountopt; |
1860 GtkWidget *accountopt; |
| 1873 |
1861 |
| 1874 PidginFilterBuddyCompletionEntryFunc filter_func; |
1862 PidginFilterBuddyCompletionEntryFunc filter_func; |
| 1875 gpointer filter_func_user_data; |
1863 gpointer filter_func_user_data; |
| 1876 |
1864 |
| 1877 #ifdef NEW_STYLE_COMPLETION |
|
| 1878 GtkListStore *store; |
1865 GtkListStore *store; |
| 1879 #else |
|
| 1880 GCompletion *completion; |
|
| 1881 gboolean completion_started; |
|
| 1882 GList *log_items; |
|
| 1883 #endif /* NEW_STYLE_COMPLETION */ |
|
| 1884 } PidginCompletionData; |
1866 } PidginCompletionData; |
| 1885 |
1867 |
| 1886 #ifndef NEW_STYLE_COMPLETION |
|
| 1887 static gboolean |
|
| 1888 completion_entry_event(GtkEditable *entry, GdkEventKey *event, |
|
| 1889 PidginCompletionData *data) |
|
| 1890 { |
|
| 1891 int pos, end_pos; |
|
| 1892 |
|
| 1893 if (event->type == GDK_KEY_PRESS && event->keyval == GDK_Tab) |
|
| 1894 { |
|
| 1895 gtk_editable_get_selection_bounds(entry, &pos, &end_pos); |
|
| 1896 |
|
| 1897 if (data->completion_started && |
|
| 1898 pos != end_pos && pos > 1 && |
|
| 1899 end_pos == strlen(gtk_entry_get_text(GTK_ENTRY(entry)))) |
|
| 1900 { |
|
| 1901 gtk_editable_select_region(entry, 0, 0); |
|
| 1902 gtk_editable_set_position(entry, -1); |
|
| 1903 |
|
| 1904 return TRUE; |
|
| 1905 } |
|
| 1906 } |
|
| 1907 else if (event->type == GDK_KEY_PRESS && event->length > 0) |
|
| 1908 { |
|
| 1909 char *prefix, *nprefix; |
|
| 1910 |
|
| 1911 gtk_editable_get_selection_bounds(entry, &pos, &end_pos); |
|
| 1912 |
|
| 1913 if (data->completion_started && |
|
| 1914 pos != end_pos && pos > 1 && |
|
| 1915 end_pos == strlen(gtk_entry_get_text(GTK_ENTRY(entry)))) |
|
| 1916 { |
|
| 1917 char *temp; |
|
| 1918 |
|
| 1919 temp = gtk_editable_get_chars(entry, 0, pos); |
|
| 1920 prefix = g_strconcat(temp, event->string, NULL); |
|
| 1921 g_free(temp); |
|
| 1922 } |
|
| 1923 else if (pos == end_pos && pos > 1 && |
|
| 1924 end_pos == strlen(gtk_entry_get_text(GTK_ENTRY(entry)))) |
|
| 1925 { |
|
| 1926 prefix = g_strconcat(gtk_entry_get_text(GTK_ENTRY(entry)), |
|
| 1927 event->string, NULL); |
|
| 1928 } |
|
| 1929 else |
|
| 1930 return FALSE; |
|
| 1931 |
|
| 1932 pos = strlen(prefix); |
|
| 1933 nprefix = NULL; |
|
| 1934 |
|
| 1935 g_completion_complete(data->completion, prefix, &nprefix); |
|
| 1936 |
|
| 1937 if (nprefix != NULL) |
|
| 1938 { |
|
| 1939 gtk_entry_set_text(GTK_ENTRY(entry), nprefix); |
|
| 1940 gtk_editable_set_position(entry, pos); |
|
| 1941 gtk_editable_select_region(entry, pos, -1); |
|
| 1942 |
|
| 1943 data->completion_started = TRUE; |
|
| 1944 |
|
| 1945 g_free(nprefix); |
|
| 1946 g_free(prefix); |
|
| 1947 |
|
| 1948 return TRUE; |
|
| 1949 } |
|
| 1950 |
|
| 1951 g_free(prefix); |
|
| 1952 } |
|
| 1953 |
|
| 1954 return FALSE; |
|
| 1955 } |
|
| 1956 |
|
| 1957 static void |
|
| 1958 destroy_completion_data(GtkWidget *w, PidginCompletionData *data) |
|
| 1959 { |
|
| 1960 g_list_foreach(data->completion->items, (GFunc)g_free, NULL); |
|
| 1961 g_completion_free(data->completion); |
|
| 1962 |
|
| 1963 g_free(data); |
|
| 1964 } |
|
| 1965 #endif /* !NEW_STYLE_COMPLETION */ |
|
| 1966 |
|
| 1967 #ifdef NEW_STYLE_COMPLETION |
|
| 1968 static gboolean buddyname_completion_match_func(GtkEntryCompletion *completion, |
1868 static gboolean buddyname_completion_match_func(GtkEntryCompletion *completion, |
| 1969 const gchar *key, GtkTreeIter *iter, gpointer user_data) |
1869 const gchar *key, GtkTreeIter *iter, gpointer user_data) |
| 1970 { |
1870 { |
| 1971 GtkTreeModel *model; |
1871 GtkTreeModel *model; |
| 1972 GValue val1; |
1872 GValue val1; |
| 2111 PidginBuddyCompletionEntry entry; |
2010 PidginBuddyCompletionEntry entry; |
| 2112 entry.is_buddy = FALSE; |
2011 entry.is_buddy = FALSE; |
| 2113 entry.entry.logged_buddy = set; |
2012 entry.entry.logged_buddy = set; |
| 2114 |
2013 |
| 2115 if (filter_func(&entry, user_data)) { |
2014 if (filter_func(&entry, user_data)) { |
| 2116 #ifdef NEW_STYLE_COMPLETION |
|
| 2117 add_buddyname_autocomplete_entry(data->store, |
2015 add_buddyname_autocomplete_entry(data->store, |
| 2118 NULL, NULL, set->account, set->name); |
2016 NULL, NULL, set->account, set->name); |
| 2119 #else |
|
| 2120 /* Steal the name for the GCompletion. */ |
|
| 2121 data->log_items = g_list_append(data->log_items, set->name); |
|
| 2122 set->name = set->normalized_name = NULL; |
|
| 2123 #endif /* NEW_STYLE_COMPLETION */ |
|
| 2124 } |
2017 } |
| 2125 } |
2018 } |
| 2126 } |
2019 } |
| 2127 |
2020 |
| 2128 static void |
2021 static void |
| 2131 PurpleBlistNode *gnode, *cnode, *bnode; |
2024 PurpleBlistNode *gnode, *cnode, *bnode; |
| 2132 PidginFilterBuddyCompletionEntryFunc filter_func = data->filter_func; |
2025 PidginFilterBuddyCompletionEntryFunc filter_func = data->filter_func; |
| 2133 gpointer user_data = data->filter_func_user_data; |
2026 gpointer user_data = data->filter_func_user_data; |
| 2134 GHashTable *sets; |
2027 GHashTable *sets; |
| 2135 |
2028 |
| 2136 #ifdef NEW_STYLE_COMPLETION |
|
| 2137 gtk_list_store_clear(data->store); |
2029 gtk_list_store_clear(data->store); |
| 2138 #else |
|
| 2139 GList *item = g_list_append(NULL, NULL); |
|
| 2140 |
|
| 2141 g_list_foreach(data->completion->items, (GFunc)g_free, NULL); |
|
| 2142 g_completion_clear_items(data->completion); |
|
| 2143 #endif /* NEW_STYLE_COMPLETION */ |
|
| 2144 |
2030 |
| 2145 for (gnode = purple_get_blist()->root; gnode != NULL; gnode = gnode->next) |
2031 for (gnode = purple_get_blist()->root; gnode != NULL; gnode = gnode->next) |
| 2146 { |
2032 { |
| 2147 if (!PURPLE_BLIST_NODE_IS_GROUP(gnode)) |
2033 if (!PURPLE_BLIST_NODE_IS_GROUP(gnode)) |
| 2148 continue; |
2034 continue; |
| 2157 PidginBuddyCompletionEntry entry; |
2043 PidginBuddyCompletionEntry entry; |
| 2158 entry.is_buddy = TRUE; |
2044 entry.is_buddy = TRUE; |
| 2159 entry.entry.buddy = (PurpleBuddy *) bnode; |
2045 entry.entry.buddy = (PurpleBuddy *) bnode; |
| 2160 |
2046 |
| 2161 if (filter_func(&entry, user_data)) { |
2047 if (filter_func(&entry, user_data)) { |
| 2162 #ifdef NEW_STYLE_COMPLETION |
|
| 2163 add_buddyname_autocomplete_entry(data->store, |
2048 add_buddyname_autocomplete_entry(data->store, |
| 2164 ((PurpleContact *)cnode)->alias, |
2049 ((PurpleContact *)cnode)->alias, |
| 2165 purple_buddy_get_contact_alias(entry.entry.buddy), |
2050 purple_buddy_get_contact_alias(entry.entry.buddy), |
| 2166 entry.entry.buddy->account, |
2051 entry.entry.buddy->account, |
| 2167 entry.entry.buddy->name |
2052 entry.entry.buddy->name |
| 2168 ); |
2053 ); |
| 2169 #else |
|
| 2170 item->data = g_strdup(entry.entry.buddy->name); |
|
| 2171 g_completion_add_items(data->completion, item); |
|
| 2172 #endif /* NEW_STYLE_COMPLETION */ |
|
| 2173 } |
2054 } |
| 2174 } |
2055 } |
| 2175 } |
2056 } |
| 2176 } |
2057 } |
| 2177 |
|
| 2178 #ifndef NEW_STYLE_COMPLETION |
|
| 2179 g_list_free(item); |
|
| 2180 data->log_items = NULL; |
|
| 2181 #endif /* NEW_STYLE_COMPLETION */ |
|
| 2182 |
2058 |
| 2183 sets = purple_log_get_log_sets(); |
2059 sets = purple_log_get_log_sets(); |
| 2184 g_hash_table_foreach(sets, (GHFunc)get_log_set_name, data); |
2060 g_hash_table_foreach(sets, (GHFunc)get_log_set_name, data); |
| 2185 g_hash_table_destroy(sets); |
2061 g_hash_table_destroy(sets); |
| 2186 |
2062 |
| 2187 #ifndef NEW_STYLE_COMPLETION |
|
| 2188 g_completion_add_items(data->completion, data->log_items); |
|
| 2189 g_list_free(data->log_items); |
|
| 2190 #endif /* NEW_STYLE_COMPLETION */ |
|
| 2191 } |
2063 } |
| 2192 |
2064 |
| 2193 static void |
2065 static void |
| 2194 buddyname_autocomplete_destroyed_cb(GtkWidget *widget, gpointer data) |
2066 buddyname_autocomplete_destroyed_cb(GtkWidget *widget, gpointer data) |
| 2195 { |
2067 { |
| 2250 gtk_entry_completion_set_model(completion, GTK_TREE_MODEL(store)); |
2121 gtk_entry_completion_set_model(completion, GTK_TREE_MODEL(store)); |
| 2251 g_object_unref(store); |
2122 g_object_unref(store); |
| 2252 |
2123 |
| 2253 gtk_entry_completion_set_text_column(completion, 0); |
2124 gtk_entry_completion_set_text_column(completion, 0); |
| 2254 |
2125 |
| 2255 #else /* !NEW_STYLE_COMPLETION */ |
|
| 2256 |
|
| 2257 data = g_new0(PidginCompletionData, 1); |
|
| 2258 |
|
| 2259 data->entry = entry; |
|
| 2260 data->accountopt = accountopt; |
|
| 2261 if (filter_func == NULL) { |
|
| 2262 data->filter_func = pidgin_screenname_autocomplete_default_filter; |
|
| 2263 data->filter_func_user_data = NULL; |
|
| 2264 } else { |
|
| 2265 data->filter_func = filter_func; |
|
| 2266 data->filter_func_user_data = user_data; |
|
| 2267 } |
|
| 2268 data->completion = g_completion_new(NULL); |
|
| 2269 data->completion_started = FALSE; |
|
| 2270 |
|
| 2271 add_completion_list(data); |
|
| 2272 |
|
| 2273 g_completion_set_compare(data->completion, g_ascii_strncasecmp); |
|
| 2274 |
|
| 2275 g_signal_connect(G_OBJECT(entry), "event", |
|
| 2276 G_CALLBACK(completion_entry_event), data); |
|
| 2277 g_signal_connect(G_OBJECT(entry), "destroy", |
|
| 2278 G_CALLBACK(destroy_completion_data), data); |
|
| 2279 |
|
| 2280 #endif /* !NEW_STYLE_COMPLETION */ |
|
| 2281 |
|
| 2282 purple_signal_connect(purple_connections_get_handle(), "signed-on", entry, |
2126 purple_signal_connect(purple_connections_get_handle(), "signed-on", entry, |
| 2283 PURPLE_CALLBACK(repopulate_autocomplete), data); |
2127 PURPLE_CALLBACK(repopulate_autocomplete), data); |
| 2284 purple_signal_connect(purple_connections_get_handle(), "signed-off", entry, |
2128 purple_signal_connect(purple_connections_get_handle(), "signed-off", entry, |
| 2285 PURPLE_CALLBACK(repopulate_autocomplete), data); |
2129 PURPLE_CALLBACK(repopulate_autocomplete), data); |
| 2286 |
2130 |
| 2345 |
2185 |
| 2346 void (*callback)(const char*,gpointer); |
2186 void (*callback)(const char*,gpointer); |
| 2347 gpointer data; |
2187 gpointer data; |
| 2348 }; |
2188 }; |
| 2349 |
2189 |
| 2350 #if !GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */ |
|
| 2351 static void |
|
| 2352 icon_filesel_delete_cb(GtkWidget *w, struct _icon_chooser *dialog) |
|
| 2353 { |
|
| 2354 if (dialog->icon_filesel != NULL) |
|
| 2355 gtk_widget_destroy(dialog->icon_filesel); |
|
| 2356 |
|
| 2357 if (dialog->callback) |
|
| 2358 dialog->callback(NULL, dialog->data); |
|
| 2359 |
|
| 2360 g_free(dialog); |
|
| 2361 } |
|
| 2362 #endif /* FILECHOOSER */ |
|
| 2363 |
|
| 2364 |
|
| 2365 |
|
| 2366 #if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */ |
|
| 2367 static void |
2190 static void |
| 2368 icon_filesel_choose_cb(GtkWidget *widget, gint response, struct _icon_chooser *dialog) |
2191 icon_filesel_choose_cb(GtkWidget *widget, gint response, struct _icon_chooser *dialog) |
| 2369 { |
2192 { |
| 2370 char *filename, *current_folder; |
2193 char *filename, *current_folder; |
| 2371 |
2194 |
| 2385 if (current_folder != NULL) { |
2208 if (current_folder != NULL) { |
| 2386 purple_prefs_set_path(PIDGIN_PREFS_ROOT "/filelocations/last_icon_folder", current_folder); |
2209 purple_prefs_set_path(PIDGIN_PREFS_ROOT "/filelocations/last_icon_folder", current_folder); |
| 2387 g_free(current_folder); |
2210 g_free(current_folder); |
| 2388 } |
2211 } |
| 2389 |
2212 |
| 2390 #else /* FILECHOOSER */ |
2213 |
| 2391 static void |
|
| 2392 icon_filesel_choose_cb(GtkWidget *w, struct _icon_chooser *dialog) |
|
| 2393 { |
|
| 2394 char *filename, *current_folder; |
|
| 2395 |
|
| 2396 filename = g_strdup(gtk_file_selection_get_filename( |
|
| 2397 GTK_FILE_SELECTION(dialog->icon_filesel))); |
|
| 2398 |
|
| 2399 /* If they typed in a directory, change there */ |
|
| 2400 if (pidgin_check_if_dir(filename, |
|
| 2401 GTK_FILE_SELECTION(dialog->icon_filesel))) |
|
| 2402 { |
|
| 2403 g_free(filename); |
|
| 2404 return; |
|
| 2405 } |
|
| 2406 |
|
| 2407 current_folder = g_path_get_dirname(filename); |
|
| 2408 if (current_folder != NULL) { |
|
| 2409 purple_prefs_set_path(PIDGIN_PREFS_ROOT "/filelocations/last_icon_folder", current_folder); |
|
| 2410 g_free(current_folder); |
|
| 2411 } |
|
| 2412 |
|
| 2413 #endif /* FILECHOOSER */ |
|
| 2414 #if 0 /* mismatched curly braces */ |
|
| 2415 } |
|
| 2416 #endif |
|
| 2417 if (dialog->callback) |
2214 if (dialog->callback) |
| 2418 dialog->callback(filename, dialog->data); |
2215 dialog->callback(filename, dialog->data); |
| 2419 gtk_widget_destroy(dialog->icon_filesel); |
2216 gtk_widget_destroy(dialog->icon_filesel); |
| 2420 g_free(filename); |
2217 g_free(filename); |
| 2421 g_free(dialog); |
2218 g_free(dialog); |
| 2422 } |
2219 } |
| 2423 |
2220 |
| 2424 |
2221 |
| 2425 static void |
2222 static void |
| 2426 #if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */ |
|
| 2427 icon_preview_change_cb(GtkFileChooser *widget, struct _icon_chooser *dialog) |
2223 icon_preview_change_cb(GtkFileChooser *widget, struct _icon_chooser *dialog) |
| 2428 #else /* FILECHOOSER */ |
|
| 2429 icon_preview_change_cb(GtkTreeSelection *sel, struct _icon_chooser *dialog) |
|
| 2430 #endif /* FILECHOOSER */ |
|
| 2431 { |
2224 { |
| 2432 GdkPixbuf *pixbuf, *scale; |
2225 GdkPixbuf *pixbuf, *scale; |
| 2433 int height, width; |
2226 int height, width; |
| 2434 char *basename, *markup, *size; |
2227 char *basename, *markup, *size; |
| 2435 struct stat st; |
2228 struct stat st; |
| 2436 char *filename; |
2229 char *filename; |
| 2437 |
2230 |
| 2438 #if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */ |
|
| 2439 filename = gtk_file_chooser_get_preview_filename( |
2231 filename = gtk_file_chooser_get_preview_filename( |
| 2440 GTK_FILE_CHOOSER(dialog->icon_filesel)); |
2232 GTK_FILE_CHOOSER(dialog->icon_filesel)); |
| 2441 #else /* FILECHOOSER */ |
|
| 2442 filename = g_strdup(gtk_file_selection_get_filename( |
|
| 2443 GTK_FILE_SELECTION(dialog->icon_filesel))); |
|
| 2444 #endif /* FILECHOOSER */ |
|
| 2445 |
2233 |
| 2446 if (!filename || g_stat(filename, &st) || !(pixbuf = gdk_pixbuf_new_from_file(filename, NULL))) |
2234 if (!filename || g_stat(filename, &st) || !(pixbuf = gdk_pixbuf_new_from_file(filename, NULL))) |
| 2447 { |
2235 { |
| 2448 gtk_image_set_from_pixbuf(GTK_IMAGE(dialog->icon_preview), NULL); |
2236 gtk_image_set_from_pixbuf(GTK_IMAGE(dialog->icon_preview), NULL); |
| 2449 gtk_label_set_markup(GTK_LABEL(dialog->icon_text), ""); |
2237 gtk_label_set_markup(GTK_LABEL(dialog->icon_text), ""); |
| 2475 |
2263 |
| 2476 |
2264 |
| 2477 GtkWidget *pidgin_buddy_icon_chooser_new(GtkWindow *parent, void(*callback)(const char *, gpointer), gpointer data) { |
2265 GtkWidget *pidgin_buddy_icon_chooser_new(GtkWindow *parent, void(*callback)(const char *, gpointer), gpointer data) { |
| 2478 struct _icon_chooser *dialog = g_new0(struct _icon_chooser, 1); |
2266 struct _icon_chooser *dialog = g_new0(struct _icon_chooser, 1); |
| 2479 |
2267 |
| 2480 #if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */ |
|
| 2481 GtkWidget *vbox; |
2268 GtkWidget *vbox; |
| 2482 #else |
|
| 2483 GtkWidget *hbox; |
|
| 2484 GtkWidget *tv; |
|
| 2485 GtkTreeSelection *sel; |
|
| 2486 #endif /* FILECHOOSER */ |
|
| 2487 const char *current_folder; |
2269 const char *current_folder; |
| 2488 |
2270 |
| 2489 dialog->callback = callback; |
2271 dialog->callback = callback; |
| 2490 dialog->data = data; |
2272 dialog->data = data; |
| 2491 |
2273 |
| 2492 current_folder = purple_prefs_get_path(PIDGIN_PREFS_ROOT "/filelocations/last_icon_folder"); |
2274 current_folder = purple_prefs_get_path(PIDGIN_PREFS_ROOT "/filelocations/last_icon_folder"); |
| 2493 #if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */ |
|
| 2494 |
2275 |
| 2495 dialog->icon_filesel = gtk_file_chooser_dialog_new(_("Buddy Icon"), |
2276 dialog->icon_filesel = gtk_file_chooser_dialog_new(_("Buddy Icon"), |
| 2496 parent, |
2277 parent, |
| 2497 GTK_FILE_CHOOSER_ACTION_OPEN, |
2278 GTK_FILE_CHOOSER_ACTION_OPEN, |
| 2498 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, |
2279 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, |
| 2519 g_signal_connect(G_OBJECT(dialog->icon_filesel), "update-preview", |
2300 g_signal_connect(G_OBJECT(dialog->icon_filesel), "update-preview", |
| 2520 G_CALLBACK(icon_preview_change_cb), dialog); |
2301 G_CALLBACK(icon_preview_change_cb), dialog); |
| 2521 g_signal_connect(G_OBJECT(dialog->icon_filesel), "response", |
2302 g_signal_connect(G_OBJECT(dialog->icon_filesel), "response", |
| 2522 G_CALLBACK(icon_filesel_choose_cb), dialog); |
2303 G_CALLBACK(icon_filesel_choose_cb), dialog); |
| 2523 icon_preview_change_cb(NULL, dialog); |
2304 icon_preview_change_cb(NULL, dialog); |
| 2524 #else /* FILECHOOSER */ |
|
| 2525 dialog->icon_filesel = gtk_file_selection_new(_("Buddy Icon")); |
|
| 2526 dialog->icon_preview = gtk_image_new(); |
|
| 2527 dialog->icon_text = gtk_label_new(NULL); |
|
| 2528 if ((current_folder != NULL) && (*current_folder != '\0')) |
|
| 2529 gtk_file_selection_set_filename(GTK_FILE_SELECTION(dialog->icon_filesel), |
|
| 2530 current_folder); |
|
| 2531 |
|
| 2532 gtk_widget_set_size_request(GTK_WIDGET(dialog->icon_preview),-1, 50); |
|
| 2533 hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE); |
|
| 2534 gtk_box_pack_start( |
|
| 2535 GTK_BOX(GTK_FILE_SELECTION(dialog->icon_filesel)->main_vbox), |
|
| 2536 hbox, FALSE, FALSE, 0); |
|
| 2537 gtk_box_pack_end(GTK_BOX(hbox), dialog->icon_preview, |
|
| 2538 FALSE, FALSE, 0); |
|
| 2539 gtk_box_pack_end(GTK_BOX(hbox), dialog->icon_text, FALSE, FALSE, 0); |
|
| 2540 |
|
| 2541 tv = GTK_FILE_SELECTION(dialog->icon_filesel)->file_list; |
|
| 2542 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tv)); |
|
| 2543 |
|
| 2544 g_signal_connect(G_OBJECT(sel), "changed", |
|
| 2545 G_CALLBACK(icon_preview_change_cb), dialog); |
|
| 2546 g_signal_connect( |
|
| 2547 G_OBJECT(GTK_FILE_SELECTION(dialog->icon_filesel)->ok_button), |
|
| 2548 "clicked", |
|
| 2549 G_CALLBACK(icon_filesel_choose_cb), dialog); |
|
| 2550 g_signal_connect( |
|
| 2551 G_OBJECT(GTK_FILE_SELECTION(dialog->icon_filesel)->cancel_button), |
|
| 2552 "clicked", |
|
| 2553 G_CALLBACK(icon_filesel_delete_cb), dialog); |
|
| 2554 g_signal_connect(G_OBJECT(dialog->icon_filesel), "destroy", |
|
| 2555 G_CALLBACK(icon_filesel_delete_cb), dialog); |
|
| 2556 #endif /* FILECHOOSER */ |
|
| 2557 |
2305 |
| 2558 #ifdef _WIN32 |
2306 #ifdef _WIN32 |
| 2559 g_signal_connect(G_OBJECT(dialog->icon_filesel), "show", |
2307 g_signal_connect(G_OBJECT(dialog->icon_filesel), "show", |
| 2560 G_CALLBACK(winpidgin_ensure_onscreen), dialog->icon_filesel); |
2308 G_CALLBACK(winpidgin_ensure_onscreen), dialog->icon_filesel); |
| 2561 #endif |
2309 #endif |
| 2562 |
2310 |
| 2563 return dialog->icon_filesel; |
2311 return dialog->icon_filesel; |
| 2564 } |
2312 } |
| 2565 |
2313 |
| 2566 |
2314 |
| 2567 #if GTK_CHECK_VERSION(2,2,0) |
|
| 2568 static gboolean |
2315 static gboolean |
| 2569 str_array_match(char **a, char **b) |
2316 str_array_match(char **a, char **b) |
| 2570 { |
2317 { |
| 2571 int i, j; |
2318 int i, j; |
| 2572 |
2319 |
| 2576 for (j = 0; b[j] != NULL; j++) |
2323 for (j = 0; b[j] != NULL; j++) |
| 2577 if (!g_ascii_strcasecmp(a[i], b[j])) |
2324 if (!g_ascii_strcasecmp(a[i], b[j])) |
| 2578 return TRUE; |
2325 return TRUE; |
| 2579 return FALSE; |
2326 return FALSE; |
| 2580 } |
2327 } |
| 2581 #endif |
|
| 2582 |
2328 |
| 2583 gpointer |
2329 gpointer |
| 2584 pidgin_convert_buddy_icon(PurplePlugin *plugin, const char *path, size_t *len) |
2330 pidgin_convert_buddy_icon(PurplePlugin *plugin, const char *path, size_t *len) |
| 2585 { |
2331 { |
| 2586 PurplePluginProtocolInfo *prpl_info; |
2332 PurplePluginProtocolInfo *prpl_info; |
| 2587 #if GTK_CHECK_VERSION(2,2,0) |
|
| 2588 char **prpl_formats; |
2333 char **prpl_formats; |
| 2589 int width, height; |
2334 int width, height; |
| 2590 char **pixbuf_formats = NULL; |
2335 char **pixbuf_formats = NULL; |
| 2591 GdkPixbufFormat *format; |
2336 GdkPixbufFormat *format; |
| 2592 GdkPixbuf *pixbuf; |
2337 GdkPixbuf *pixbuf; |
| 2593 #if !GTK_CHECK_VERSION(2,4,0) |
|
| 2594 GdkPixbufLoader *loader; |
|
| 2595 #endif |
|
| 2596 #endif |
|
| 2597 gchar *contents; |
2338 gchar *contents; |
| 2598 gsize length; |
2339 gsize length; |
| 2599 |
2340 |
| 2600 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(plugin); |
2341 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(plugin); |
| 2601 |
2342 |
| 2602 g_return_val_if_fail(prpl_info->icon_spec.format != NULL, NULL); |
2343 g_return_val_if_fail(prpl_info->icon_spec.format != NULL, NULL); |
| 2603 |
2344 |
| 2604 |
2345 |
| 2605 #if GTK_CHECK_VERSION(2,2,0) |
|
| 2606 #if GTK_CHECK_VERSION(2,4,0) |
|
| 2607 format = gdk_pixbuf_get_file_info(path, &width, &height); |
2346 format = gdk_pixbuf_get_file_info(path, &width, &height); |
| 2608 #else |
2347 |
| 2609 loader = gdk_pixbuf_loader_new(); |
|
| 2610 if (g_file_get_contents(path, &contents, &length, NULL)) { |
|
| 2611 gdk_pixbuf_loader_write(loader, contents, length, NULL); |
|
| 2612 g_free(contents); |
|
| 2613 } |
|
| 2614 gdk_pixbuf_loader_close(loader, NULL); |
|
| 2615 pixbuf = gdk_pixbuf_loader_get_pixbuf(loader); |
|
| 2616 width = gdk_pixbuf_get_width(pixbuf); |
|
| 2617 height = gdk_pixbuf_get_height(pixbuf); |
|
| 2618 format = gdk_pixbuf_loader_get_format(loader); |
|
| 2619 g_object_unref(G_OBJECT(loader)); |
|
| 2620 #endif |
|
| 2621 if (format == NULL) |
2348 if (format == NULL) |
| 2622 return NULL; |
2349 return NULL; |
| 2623 |
2350 |
| 2624 pixbuf_formats = gdk_pixbuf_format_get_extensions(format); |
2351 pixbuf_formats = gdk_pixbuf_format_get_extensions(format); |
| 2625 prpl_formats = g_strsplit(prpl_info->icon_spec.format,",",0); |
2352 prpl_formats = g_strsplit(prpl_info->icon_spec.format,",",0); |
| 2627 (!(prpl_info->icon_spec.scale_rules & PURPLE_ICON_SCALE_SEND) || /* The prpl doesn't scale before it sends OR */ |
2354 (!(prpl_info->icon_spec.scale_rules & PURPLE_ICON_SCALE_SEND) || /* The prpl doesn't scale before it sends OR */ |
| 2628 (prpl_info->icon_spec.min_width <= width && |
2355 (prpl_info->icon_spec.min_width <= width && |
| 2629 prpl_info->icon_spec.max_width >= width && |
2356 prpl_info->icon_spec.max_width >= width && |
| 2630 prpl_info->icon_spec.min_height <= height && |
2357 prpl_info->icon_spec.min_height <= height && |
| 2631 prpl_info->icon_spec.max_height >= height))) /* The icon is the correct size */ |
2358 prpl_info->icon_spec.max_height >= height))) /* The icon is the correct size */ |
| 2632 #endif |
|
| 2633 { |
2359 { |
| 2634 #if GTK_CHECK_VERSION(2,2,0) |
|
| 2635 g_strfreev(prpl_formats); |
2360 g_strfreev(prpl_formats); |
| 2636 g_strfreev(pixbuf_formats); |
2361 g_strfreev(pixbuf_formats); |
| 2637 #endif |
2362 |
| 2638 /* We don't need to scale the image. */ |
2363 /* We don't need to scale the image. */ |
| 2639 |
|
| 2640 contents = NULL; |
2364 contents = NULL; |
| 2641 if (!g_file_get_contents(path, &contents, &length, NULL)) |
2365 if (!g_file_get_contents(path, &contents, &length, NULL)) |
| 2642 { |
2366 { |
| 2643 g_free(contents); |
2367 g_free(contents); |
| 2644 #if GTK_CHECK_VERSION(2,2,0) && !GTK_CHECK_VERSION(2,4,0) |
|
| 2645 g_object_unref(G_OBJECT(pixbuf)); |
|
| 2646 #endif |
|
| 2647 return NULL; |
2368 return NULL; |
| 2648 } |
2369 } |
| 2649 } |
2370 } |
| 2650 #if GTK_CHECK_VERSION(2,2,0) |
|
| 2651 else |
2371 else |
| 2652 { |
2372 { |
| 2653 int i; |
2373 int i; |
| 2654 GError *error = NULL; |
2374 GError *error = NULL; |
| 2655 GdkPixbuf *scale; |
2375 GdkPixbuf *scale; |
| 2767 } |
2487 } |
| 2768 |
2488 |
| 2769 if (len) |
2489 if (len) |
| 2770 *len = length; |
2490 *len = length; |
| 2771 return contents; |
2491 return contents; |
| 2772 #else |
2492 } |
| 2773 /* |
|
| 2774 * The chosen icon wasn't the right size, and we're using |
|
| 2775 * GTK+ 2.0 so we can't scale it. |
|
| 2776 */ |
|
| 2777 return NULL; |
|
| 2778 #endif |
|
| 2779 } |
|
| 2780 |
|
| 2781 #if !GTK_CHECK_VERSION(2,6,0) |
|
| 2782 static void |
|
| 2783 _gdk_file_scale_size_prepared_cb (GdkPixbufLoader *loader, |
|
| 2784 int width, |
|
| 2785 int height, |
|
| 2786 gpointer data) |
|
| 2787 { |
|
| 2788 struct { |
|
| 2789 gint width; |
|
| 2790 gint height; |
|
| 2791 gboolean preserve_aspect_ratio; |
|
| 2792 } *info = data; |
|
| 2793 |
|
| 2794 g_return_if_fail (width > 0 && height > 0); |
|
| 2795 |
|
| 2796 if (info->preserve_aspect_ratio && |
|
| 2797 (info->width > 0 || info->height > 0)) { |
|
| 2798 if (info->width < 0) |
|
| 2799 { |
|
| 2800 width = width * (double)info->height/(double)height; |
|
| 2801 height = info->height; |
|
| 2802 } |
|
| 2803 else if (info->height < 0) |
|
| 2804 { |
|
| 2805 height = height * (double)info->width/(double)width; |
|
| 2806 width = info->width; |
|
| 2807 } |
|
| 2808 else if ((double)height * (double)info->width > |
|
| 2809 (double)width * (double)info->height) { |
|
| 2810 width = 0.5 + (double)width * (double)info->height / (double)height; |
|
| 2811 height = info->height; |
|
| 2812 } else { |
|
| 2813 height = 0.5 + (double)height * (double)info->width / (double)width; |
|
| 2814 width = info->width; |
|
| 2815 } |
|
| 2816 } else { |
|
| 2817 if (info->width > 0) |
|
| 2818 width = info->width; |
|
| 2819 if (info->height > 0) |
|
| 2820 height = info->height; |
|
| 2821 } |
|
| 2822 |
|
| 2823 #if GTK_CHECK_VERSION(2,2,0) /* 2.0 users are going to have very strangely sized things */ |
|
| 2824 gdk_pixbuf_loader_set_size (loader, width, height); |
|
| 2825 #else |
|
| 2826 #warning nosnilmot could not be bothered to fix this properly for you |
|
| 2827 #warning ... good luck ... your images may end up strange sizes |
|
| 2828 #endif |
|
| 2829 } |
|
| 2830 |
|
| 2831 GdkPixbuf * |
|
| 2832 gdk_pixbuf_new_from_file_at_scale(const char *filename, int width, int height, |
|
| 2833 gboolean preserve_aspect_ratio, |
|
| 2834 GError **error) |
|
| 2835 { |
|
| 2836 GdkPixbufLoader *loader; |
|
| 2837 GdkPixbuf *pixbuf; |
|
| 2838 guchar buffer [4096]; |
|
| 2839 int length; |
|
| 2840 FILE *f; |
|
| 2841 struct { |
|
| 2842 gint width; |
|
| 2843 gint height; |
|
| 2844 gboolean preserve_aspect_ratio; |
|
| 2845 } info; |
|
| 2846 GdkPixbufAnimation *animation; |
|
| 2847 GdkPixbufAnimationIter *iter; |
|
| 2848 gboolean has_frame; |
|
| 2849 |
|
| 2850 g_return_val_if_fail (filename != NULL, NULL); |
|
| 2851 g_return_val_if_fail (width > 0 || width == -1, NULL); |
|
| 2852 g_return_val_if_fail (height > 0 || height == -1, NULL); |
|
| 2853 |
|
| 2854 f = g_fopen (filename, "rb"); |
|
| 2855 if (!f) { |
|
| 2856 gint save_errno = errno; |
|
| 2857 gchar *display_name = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL); |
|
| 2858 g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (save_errno), |
|
| 2859 _("Failed to open file '%s': %s"), |
|
| 2860 display_name ? display_name : "(unknown)", |
|
| 2861 g_strerror (save_errno)); |
|
| 2862 g_free (display_name); |
|
| 2863 return NULL; |
|
| 2864 } |
|
| 2865 |
|
| 2866 loader = gdk_pixbuf_loader_new (); |
|
| 2867 |
|
| 2868 info.width = width; |
|
| 2869 info.height = height; |
|
| 2870 info.preserve_aspect_ratio = preserve_aspect_ratio; |
|
| 2871 |
|
| 2872 g_signal_connect (loader, "size-prepared", G_CALLBACK (_gdk_file_scale_size_prepared_cb), &info); |
|
| 2873 |
|
| 2874 has_frame = FALSE; |
|
| 2875 while (!has_frame && !feof (f) && !ferror (f)) { |
|
| 2876 length = fread (buffer, 1, sizeof (buffer), f); |
|
| 2877 if (length > 0) |
|
| 2878 if (!gdk_pixbuf_loader_write (loader, buffer, length, error)) { |
|
| 2879 gdk_pixbuf_loader_close (loader, NULL); |
|
| 2880 fclose (f); |
|
| 2881 g_object_unref (loader); |
|
| 2882 return NULL; |
|
| 2883 } |
|
| 2884 |
|
| 2885 animation = gdk_pixbuf_loader_get_animation (loader); |
|
| 2886 if (animation) { |
|
| 2887 iter = gdk_pixbuf_animation_get_iter (animation, 0); |
|
| 2888 if (!gdk_pixbuf_animation_iter_on_currently_loading_frame (iter)) { |
|
| 2889 has_frame = TRUE; |
|
| 2890 } |
|
| 2891 g_object_unref (iter); |
|
| 2892 } |
|
| 2893 } |
|
| 2894 |
|
| 2895 fclose (f); |
|
| 2896 |
|
| 2897 if (!gdk_pixbuf_loader_close (loader, error) && !has_frame) { |
|
| 2898 g_object_unref (loader); |
|
| 2899 return NULL; |
|
| 2900 } |
|
| 2901 |
|
| 2902 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader); |
|
| 2903 |
|
| 2904 if (!pixbuf) { |
|
| 2905 gchar *display_name = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL); |
|
| 2906 g_object_unref (loader); |
|
| 2907 g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED, |
|
| 2908 _("Failed to load image '%s': reason not known, probably a corrupt image file"), |
|
| 2909 display_name ? display_name : "(unknown)"); |
|
| 2910 g_free (display_name); |
|
| 2911 return NULL; |
|
| 2912 } |
|
| 2913 |
|
| 2914 g_object_ref (pixbuf); |
|
| 2915 |
|
| 2916 g_object_unref (loader); |
|
| 2917 |
|
| 2918 return pixbuf; |
|
| 2919 } |
|
| 2920 #endif /* ! Gtk 2.6.0 */ |
|
| 2921 |
2493 |
| 2922 void pidgin_set_custom_buddy_icon(PurpleAccount *account, const char *who, const char *filename) |
2494 void pidgin_set_custom_buddy_icon(PurpleAccount *account, const char *who, const char *filename) |
| 2923 { |
2495 { |
| 2924 PurpleBuddy *buddy; |
2496 PurpleBuddy *buddy; |
| 2925 PurpleContact *contact; |
2497 PurpleContact *contact; |
| 2949 return ret; |
2521 return ret; |
| 2950 } |
2522 } |
| 2951 |
2523 |
| 2952 void pidgin_set_urgent(GtkWindow *window, gboolean urgent) |
2524 void pidgin_set_urgent(GtkWindow *window, gboolean urgent) |
| 2953 { |
2525 { |
| 2954 #if GTK_CHECK_VERSION(2,8,0) |
2526 #if defined _WIN32 |
| |
2527 winpidgin_window_flash(window, urgent); |
| |
2528 #else |
| 2955 gtk_window_set_urgency_hint(window, urgent); |
2529 gtk_window_set_urgency_hint(window, urgent); |
| 2956 #elif defined _WIN32 |
|
| 2957 winpidgin_window_flash(window, urgent); |
|
| 2958 #elif defined GDK_WINDOWING_X11 |
|
| 2959 GdkWindow *gdkwin; |
|
| 2960 XWMHints *hints; |
|
| 2961 |
|
| 2962 g_return_if_fail(window != NULL); |
|
| 2963 |
|
| 2964 gdkwin = GTK_WIDGET(window)->window; |
|
| 2965 |
|
| 2966 g_return_if_fail(gdkwin != NULL); |
|
| 2967 |
|
| 2968 hints = XGetWMHints(GDK_WINDOW_XDISPLAY(gdkwin), |
|
| 2969 GDK_WINDOW_XWINDOW(gdkwin)); |
|
| 2970 if(!hints) |
|
| 2971 hints = XAllocWMHints(); |
|
| 2972 |
|
| 2973 if (urgent) |
|
| 2974 hints->flags |= XUrgencyHint; |
|
| 2975 else |
|
| 2976 hints->flags &= ~XUrgencyHint; |
|
| 2977 XSetWMHints(GDK_WINDOW_XDISPLAY(gdkwin), |
|
| 2978 GDK_WINDOW_XWINDOW(gdkwin), hints); |
|
| 2979 XFree(hints); |
|
| 2980 #else |
|
| 2981 /* do something else? */ |
|
| 2982 #endif |
2530 #endif |
| 2983 } |
2531 } |
| 2984 |
2532 |
| 2985 static GSList *minidialogs = NULL; |
2533 static GSList *minidialogs = NULL; |
| 2986 |
2534 |
| 3285 style->text_aa[GTK_STATE_NORMAL].green >> 8, |
2833 style->text_aa[GTK_STATE_NORMAL].green >> 8, |
| 3286 style->text_aa[GTK_STATE_NORMAL].blue >> 8); |
2834 style->text_aa[GTK_STATE_NORMAL].blue >> 8); |
| 3287 return dim_grey_string; |
2835 return dim_grey_string; |
| 3288 } |
2836 } |
| 3289 |
2837 |
| 3290 #if !GTK_CHECK_VERSION(2,2,0) |
|
| 3291 GtkTreePath * |
|
| 3292 gtk_tree_path_new_from_indices (gint first_index, ...) |
|
| 3293 { |
|
| 3294 int arg; |
|
| 3295 va_list args; |
|
| 3296 GtkTreePath *path; |
|
| 3297 |
|
| 3298 path = gtk_tree_path_new (); |
|
| 3299 |
|
| 3300 va_start (args, first_index); |
|
| 3301 arg = first_index; |
|
| 3302 |
|
| 3303 while (arg != -1) |
|
| 3304 { |
|
| 3305 gtk_tree_path_append_index (path, arg); |
|
| 3306 arg = va_arg (args, gint); |
|
| 3307 } |
|
| 3308 |
|
| 3309 va_end (args); |
|
| 3310 |
|
| 3311 return path; |
|
| 3312 } |
|
| 3313 #endif |
|
| 3314 |
|
| 3315 static void |
2838 static void |
| 3316 combo_box_changed_cb(GtkComboBox *combo_box, GtkEntry *entry) |
2839 combo_box_changed_cb(GtkComboBox *combo_box, GtkEntry *entry) |
| 3317 { |
2840 { |
| 3318 char *text = gtk_combo_box_get_active_text(combo_box); |
2841 char *text = gtk_combo_box_get_active_text(combo_box); |
| 3319 gtk_entry_set_text(entry, text ? text : ""); |
2842 gtk_entry_set_text(entry, text ? text : ""); |
| 3582 { |
3103 { |
| 3583 /* Copied from gtkft.c:open_button_cb */ |
3104 /* Copied from gtkft.c:open_button_cb */ |
| 3584 #ifdef _WIN32 |
3105 #ifdef _WIN32 |
| 3585 /* If using Win32... */ |
3106 /* If using Win32... */ |
| 3586 int code; |
3107 int code; |
| 3587 if (G_WIN32_HAVE_WIDECHAR_API()) { |
3108 wchar_t *wc_filename = g_utf8_to_utf16( |
| 3588 wchar_t *wc_filename = g_utf8_to_utf16( |
3109 uri, -1, NULL, NULL, NULL); |
| 3589 uri, -1, NULL, NULL, NULL); |
3110 |
| 3590 |
3111 code = (int)ShellExecuteW(NULL, NULL, wc_filename, NULL, NULL, |
| 3591 code = (int)ShellExecuteW(NULL, NULL, wc_filename, NULL, NULL, |
3112 SW_SHOW); |
| 3592 SW_SHOW); |
3113 |
| 3593 |
3114 g_free(wc_filename); |
| 3594 g_free(wc_filename); |
|
| 3595 } else { |
|
| 3596 char *l_filename = g_locale_from_utf8( |
|
| 3597 uri, -1, NULL, NULL, NULL); |
|
| 3598 |
|
| 3599 code = (int)ShellExecuteA(NULL, NULL, l_filename, NULL, NULL, |
|
| 3600 SW_SHOW); |
|
| 3601 |
|
| 3602 g_free(l_filename); |
|
| 3603 } |
|
| 3604 |
3115 |
| 3605 if (code == SE_ERR_ASSOCINCOMPLETE || code == SE_ERR_NOASSOC) |
3116 if (code == SE_ERR_ASSOCINCOMPLETE || code == SE_ERR_NOASSOC) |
| 3606 { |
3117 { |
| 3607 purple_notify_error(imhtml, NULL, |
3118 purple_notify_error(imhtml, NULL, |
| 3608 _("There is no application configured to open this type of file."), NULL); |
3119 _("There is no application configured to open this type of file."), NULL); |
| 3695 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img); |
3206 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img); |
| 3696 g_signal_connect_swapped(G_OBJECT(item), "activate", G_CALLBACK(gtk_imhtml_link_activate), link); |
3207 g_signal_connect_swapped(G_OBJECT(item), "activate", G_CALLBACK(gtk_imhtml_link_activate), link); |
| 3697 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); |
3208 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); |
| 3698 |
3209 |
| 3699 /* Open Containing Directory */ |
3210 /* Open Containing Directory */ |
| 3700 #if GTK_CHECK_VERSION(2,6,0) |
|
| 3701 img = gtk_image_new_from_stock(GTK_STOCK_DIRECTORY, GTK_ICON_SIZE_MENU); |
3211 img = gtk_image_new_from_stock(GTK_STOCK_DIRECTORY, GTK_ICON_SIZE_MENU); |
| 3702 item = gtk_image_menu_item_new_with_mnemonic(_("Open _Containing Directory")); |
3212 item = gtk_image_menu_item_new_with_mnemonic(_("Open _Containing Directory")); |
| 3703 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img); |
3213 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img); |
| 3704 #else |
3214 |
| 3705 item = gtk_menu_item_new_with_mnemonic(_("Open _Containing Directory")); |
|
| 3706 #endif |
|
| 3707 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(open_containing_cb), (gpointer)url); |
3215 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(open_containing_cb), (gpointer)url); |
| 3708 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); |
3216 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); |
| 3709 |
3217 |
| 3710 return TRUE; |
3218 return TRUE; |
| 3711 } |
3219 } |
| 3767 return TRUE; |
3275 return TRUE; |
| 3768 |
3276 |
| 3769 url = gtk_imhtml_link_get_url(link); |
3277 url = gtk_imhtml_link_get_url(link); |
| 3770 |
3278 |
| 3771 /* Play Sound */ |
3279 /* Play Sound */ |
| 3772 #if GTK_CHECK_VERSION(2,6,0) |
|
| 3773 img = gtk_image_new_from_stock(GTK_STOCK_MEDIA_PLAY, GTK_ICON_SIZE_MENU); |
3280 img = gtk_image_new_from_stock(GTK_STOCK_MEDIA_PLAY, GTK_ICON_SIZE_MENU); |
| 3774 item = gtk_image_menu_item_new_with_mnemonic(_("_Play Sound")); |
3281 item = gtk_image_menu_item_new_with_mnemonic(_("_Play Sound")); |
| 3775 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img); |
3282 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img); |
| 3776 #else |
3283 |
| 3777 item = gtk_menu_item_new_with_mnemonic(_("_Play Sound")); |
|
| 3778 #endif |
|
| 3779 g_signal_connect_swapped(G_OBJECT(item), "activate", G_CALLBACK(gtk_imhtml_link_activate), link); |
3284 g_signal_connect_swapped(G_OBJECT(item), "activate", G_CALLBACK(gtk_imhtml_link_activate), link); |
| 3780 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); |
3285 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); |
| 3781 |
3286 |
| 3782 /* Save File */ |
3287 /* Save File */ |
| 3783 img = gtk_image_new_from_stock(GTK_STOCK_SAVE, GTK_ICON_SIZE_MENU); |
3288 img = gtk_image_new_from_stock(GTK_STOCK_SAVE, GTK_ICON_SIZE_MENU); |
| 3895 int idx = 0; |
3400 int idx = 0; |
| 3896 LONG ret = ERROR_SUCCESS; |
3401 LONG ret = ERROR_SUCCESS; |
| 3897 |
3402 |
| 3898 do { |
3403 do { |
| 3899 DWORD nameSize = 256; |
3404 DWORD nameSize = 256; |
| 3900 char start[256]; |
3405 wchar_t start[256]; |
| 3901 /* I don't think we need to worry about non-ASCII protocol names */ |
3406 ret = RegEnumKeyExW(HKEY_CLASSES_ROOT, idx++, start, &nameSize, |
| 3902 ret = RegEnumKeyExA(HKEY_CLASSES_ROOT, idx++, start, &nameSize, |
|
| 3903 NULL, NULL, NULL, NULL); |
3407 NULL, NULL, NULL, NULL); |
| 3904 if (ret == ERROR_SUCCESS) { |
3408 if (ret == ERROR_SUCCESS) { |
| 3905 HKEY reg_key = NULL; |
3409 HKEY reg_key = NULL; |
| 3906 ret = RegOpenKeyExA(HKEY_CLASSES_ROOT, start, 0, KEY_READ, ®_key); |
3410 ret = RegOpenKeyExW(HKEY_CLASSES_ROOT, start, 0, KEY_READ, ®_key); |
| 3907 if (ret == ERROR_SUCCESS) { |
3411 if (ret == ERROR_SUCCESS) { |
| 3908 ret = RegQueryValueExA(reg_key, "URL Protocol", NULL, NULL, NULL, NULL); |
3412 ret = RegQueryValueExW(reg_key, L"URL Protocol", NULL, NULL, NULL, NULL); |
| 3909 if (ret == ERROR_SUCCESS) { |
3413 if (ret == ERROR_SUCCESS) { |
| 3910 gchar *protocol = g_strdup_printf("%s:", start); |
3414 gchar *utf8 = g_utf16_to_utf8(start, -1, NULL, NULL, NULL); |
| |
3415 gchar *protocol = g_strdup_printf("%s:", utf8); |
| |
3416 g_free(utf8); |
| 3911 registered_url_handlers = g_slist_prepend(registered_url_handlers, protocol); |
3417 registered_url_handlers = g_slist_prepend(registered_url_handlers, protocol); |
| 3912 /* We still pass everything to the "http" "open" handler for security reasons */ |
3418 /* We still pass everything to the "http" "open" handler for security reasons */ |
| 3913 gtk_imhtml_class_register_protocol(protocol, url_clicked_cb, link_context_menu); |
3419 gtk_imhtml_class_register_protocol(protocol, url_clicked_cb, link_context_menu); |
| 3914 } |
3420 } |
| 3915 RegCloseKey(reg_key); |
3421 RegCloseKey(reg_key); |