# HG changeset patch # User Sean Egan # Date 1043609983 0 # Node ID b5669740e34c11684605c037de958475815195ce # Parent 88920ce27a9fb659f9bc423778ee37dcafaa8072 [gaim-migrate @ 4703] Two patches from Ray Strode to clean up browser launching (esp. Netscape and Mozilla) and to show only available browsers in the prefs drop down list. committer: Tailor Script diff -r 88920ce27a9f -r b5669740e34c src/browser.c --- a/src/browser.c Sun Jan 26 14:10:49 2003 +0000 +++ b/src/browser.c Sun Jan 26 19:39:43 2003 +0000 @@ -34,6 +34,9 @@ #include #else #include +#ifndef HOST_NAME_MAX +#define HOST_NAME_MAX 255 +#endif #include #endif #include @@ -69,6 +72,10 @@ static GdkAtom GDKA_MOZILLA_COMMAND = 0; static GdkAtom GDKA_MOZILLA_RESPONSE = 0; +static char *window_check_mozilla_version(Window); +static const char *get_lock_data(); +static GdkFilterReturn netscape_response_cb(XEvent *, GdkEvent *, GdkWindow *); +static gboolean netscape_command(const char *); static int netscape_lock; @@ -202,6 +209,33 @@ GDKA_MOZILLA_RESPONSE = gdk_atom_intern(MOZILLA_RESPONSE_PROP, 0); } +static char *window_check_mozilla_version(Window window) { + + Atom type; + int format; + unsigned long nitems, bytesafter; + unsigned char *version = 0; + gchar *retval = NULL; + + if (XGetWindowProperty(gdk_display, window, + gdk_x11_atom_to_xatom(GDKA_MOZILLA_VERSION), + 0, (65536 / sizeof(long)), + False, XA_STRING, + &type, &format, &nitems, &bytesafter, + &version) != Success) { + return NULL; + } + + if (!version) { + return NULL; + } + + retval = g_strdup(version); + XFree(version); + + return retval; +} + static GdkWindow *mozilla_remote_find_window() { int i; @@ -210,7 +244,21 @@ unsigned int nkids; Window result = 0; Window tenative = 0; - unsigned char *tenative_version = 0; + unsigned char *tenative_version = 0, *version = 0; + static GdkWindow *remote_window = NULL; + + if (remote_window != NULL) { + version = window_check_mozilla_version(GDK_WINDOW_XID(remote_window)); + + if (version != NULL) { + g_free(version); + return remote_window; + } + g_free(version); + + gdk_window_destroy(remote_window); + remote_window = NULL; + } if (!XQueryTree(gdk_display, root, &root2, &parent, &kids, &nkids)) { debug_printf("%s: XQueryTree failed on display %s\n", progname, @@ -227,32 +275,25 @@ } for (i = nkids - 1; i >= 0; i--) { - Atom type; - int format; - unsigned long nitems, bytesafter; - unsigned char *version = 0; Window w = GClientWindow(gdk_display, kids[i]); - int status = XGetWindowProperty(gdk_display, w, - gdk_x11_atom_to_xatom(GDKA_MOZILLA_VERSION), - 0, (65536 / sizeof(long)), - False, XA_STRING, - &type, &format, &nitems, &bytesafter, - &version); + + version = window_check_mozilla_version(w); - if (!version) + if (version == NULL) { continue; + } if (strcmp((char *)version, expected_mozilla_version) && !tenative) { tenative = w; tenative_version = version; continue; } - XFree(version); - if (status == Success && type != None) { + + g_free(version); + result = w; break; } - } XFree(kids); @@ -279,35 +320,41 @@ } -static char *lock_data = 0; - -static void mozilla_remote_obtain_lock(GdkWindow * window) -{ - Bool locked = False; +static const char *get_lock_data() { + static char *lock_data = NULL; - if (!lock_data) { - lock_data = (char *)g_malloc(255); - sprintf(lock_data, "pid%d@", getpid()); - if (gethostname(lock_data + strlen(lock_data), 100)) { - return; + if (lock_data == NULL) { + char hostname[HOST_NAME_MAX + 1] = {0}; + + if (gethostname(hostname, HOST_NAME_MAX + 1) == 0) { + lock_data = g_strdup_printf("pid%d@%s", getpid(), hostname); + } else { + lock_data = g_strdup_printf("pid%d", getpid()); } } - do { + return lock_data; +} + +static gboolean mozilla_remote_obtain_lock(GdkWindow * window) +{ + gboolean locked = False; + const char *lock_data = get_lock_data(); int result; GdkAtom actual_type; gint actual_format; gint nitems; unsigned char *data = 0; - result = gdk_property_get(window, GDKA_MOZILLA_LOCK, + gdk_x11_grab_server(); + if (!gdk_property_get(window, GDKA_MOZILLA_LOCK, gdk_x11_xatom_to_atom (XA_STRING), 0, (65536 / sizeof(long)), 0, - &actual_type, &actual_format, &nitems, &data); - if (result != Success || actual_type == None) { + &actual_type, &actual_format, &nitems, &data)) { + /* It's not now locked - lock it. */ - debug_printf("%s: (writing " MOZILLA_LOCK_PROP - " \"%s\" to 0x%x)\n", progname, lock_data, (unsigned int)window); + debug_printf("%s: (writing " MOZILLA_LOCK_PROP " \"%s\" to 0x%x)\n", + progname, lock_data, (unsigned int) window); gdk_property_change(window, GDKA_MOZILLA_LOCK, gdk_x11_xatom_to_atom (XA_STRING), @@ -316,15 +363,9 @@ locked = True; } - if (!locked) { - /* Then just fuck it. */ if (data) g_free(data); - return; - } - if (data) - g_free(data); - } while (!locked); + gdk_x11_ungrab_server(); } @@ -332,9 +373,10 @@ { int result = 0; GdkAtom actual_type; - gint actual_format; + gint actual_format; gint nitems; unsigned char *data = 0; + const char *lock_data = get_lock_data(); debug_printf("%s: (deleting " MOZILLA_LOCK_PROP " \"%s\" from 0x%x)\n", progname, lock_data, (unsigned int)window); @@ -343,7 +385,8 @@ gdk_x11_xatom_to_atom (XA_STRING), 0, (65536 / sizeof(long)), 1, &actual_type, &actual_format, &nitems, &data); - if (result != Success) { + + if (result != TRUE) { debug_printf("%s: unable to read and delete " MOZILLA_LOCK_PROP " property\n", progname); return; } else if (!data || !*data) { @@ -356,12 +399,67 @@ return; } - if (data) - g_free(data); + XFree(data); } +static GdkFilterReturn netscape_response_cb(XEvent *event, GdkEvent *translated, GdkWindow *window) +{ + Atom actual_type, mozilla_response; + Window xid; + int actual_format; + unsigned long nitems, bytes_after; + unsigned char *data = 0; + char *error = NULL; -static int mozilla_remote_command(GdkWindow * window, const char *command, Bool raise_p) + if (window == NULL || GDK_WINDOW_OBJECT(window)->destroyed) { + do_error_dialog(_("Communication with the browser failed. Please close all " + "windows and try again."), NULL, GAIM_ERROR); + debug_printf("netscape_response_cb called with NULL window.\n"); + return GDK_FILTER_CONTINUE; + } + + mozilla_response = gdk_x11_atom_to_xatom(GDKA_MOZILLA_RESPONSE); + xid = GDK_WINDOW_XID(window); + + /* If the event isn't what we want then let gtk handle it */ + if (event->xany.type != PropertyNotify || + event->xproperty.state != PropertyNewValue || + event->xproperty.window != xid || + event->xproperty.atom != mozilla_response) { + return GDK_FILTER_CONTINUE; + } + + if (XGetWindowProperty (gdk_display, xid, mozilla_response, + 0, (65536 / sizeof (long)), + True, + XA_STRING, + &actual_type, &actual_format, + &nitems, &bytes_after, + &data) != Success + || data == NULL || (data[0] != '1' && data[0] != '2')) { + + do_error_dialog(_("Communication with the browser failed. Please close all " + "windows and try again."), NULL, GAIM_ERROR); + } + + if (data[0] == '1') { + /* Netscape isn't ready yet */ + debug_printf("Remote Netscape window isn't ready yet.\n"); + return GDK_FILTER_REMOVE; + } + + if (data[0] == '2') { + /* Yay! It worked */ + debug_printf("Successfully sent command to remote Netscape window.\n"); + } + + gdk_window_remove_filter(window, (GdkFilterFunc) netscape_response_cb, window); + mozilla_remote_free_lock(window); + netscape_lock = 0; + return GDK_FILTER_REMOVE; +} + +static void mozilla_remote_command(GdkWindow * window, const char *command, Bool raise_p) { int result = 0; Bool done = False; diff -r 88920ce27a9f -r b5669740e34c src/prefs.c --- a/src/prefs.c Sun Jan 26 14:10:49 2003 +0000 +++ b/src/prefs.c Sun Jan 26 19:39:43 2003 +0000 @@ -65,9 +65,11 @@ GtkWidget *gaim_button(const char *, guint *, int, GtkWidget *); GtkWidget *gaim_labeled_spin_button(GtkWidget *, const gchar *, int*, int, int, GtkSizeGroup *); static GtkWidget *gaim_dropdown(GtkWidget *, const gchar *, int *, int, ...); +static GtkWidget *gaim_dropdown_from_list(GtkWidget *, const gchar *, int *, int, GList *); static GtkWidget *show_color_pref(GtkWidget *, gboolean); static void delete_prefs(GtkWidget *, void *); void set_default_away(GtkWidget *, gpointer); +static gboolean program_is_valid(const char *); struct debug_window *dw = NULL; GtkWidget *prefs = NULL; @@ -781,11 +783,57 @@ } #ifndef _WIN32 -static void browser_print_option(GtkEntry *entry, void *nullish) { - g_snprintf(web_command, sizeof(web_command), "%s", gtk_entry_get_text(entry)); +static void manual_browser_set(GtkButton *button, GtkEntry *entry) { + + const char *program = gtk_entry_get_text(entry); + if (!program_is_valid(program)) { + char *error = g_strdup_printf(_("The entered manual browser " + "'%s' is not valid. Hyperlinks will " + "not work."), program); + do_error_dialog(error, NULL, GAIM_WARNING); + } + + g_strlcpy(web_command, program, sizeof(web_command)); +} + +static void manual_browser_reset(GtkButton *button, GtkEntry *entry) { + gtk_entry_set_text(entry, web_command); } #endif +static GList *get_available_browsers() +{ + struct browser { + char *name; + char *command; + int id; + }; + + static struct browser possible_browsers[] = { + {N_("Konqueror"), "kfmclient", BROWSER_KONQ}, + {N_("Opera"), "opera", BROWSER_OPERA}, + {N_("Galeon"), "galeon", BROWSER_GALEON}, + {N_("Netscape"), "netscape", BROWSER_NETSCAPE}, + {N_("Mozilla"), "mozilla", BROWSER_MOZILLA}, + }; + static const int num_possible_browsers = 5; + + GList *browsers = NULL; + int i = 0; + + browsers = g_list_prepend(browsers, GINT_TO_POINTER(BROWSER_MANUAL)); + browsers = g_list_prepend(browsers, _("Manual")); + for (i = 0; i < num_possible_browsers; i++) { + if (program_is_valid(possible_browsers[i].command)) { + browsers = g_list_prepend(browsers, + GINT_TO_POINTER(possible_browsers[i].id)); + browsers = g_list_prepend(browsers, possible_browsers[i].name); + } + } + + return browsers; +} + GtkWidget *browser_page() { GtkWidget *ret; GtkWidget *vbox; @@ -794,6 +842,7 @@ #endif GtkWidget *label; GtkSizeGroup *sg; + GList *browsers = NULL; ret = gtk_vbox_new(FALSE, 18); gtk_container_set_border_width (GTK_CONTAINER (ret), 12); @@ -802,17 +851,14 @@ #ifndef _WIN32 /* Registered default browser is used by Windows */ vbox = make_frame (ret, _("Browser Selection")); - label = gaim_dropdown(vbox, _("_Browser"), &web_browser, -1, - "Netscape", BROWSER_NETSCAPE, - "Konqueror", BROWSER_KONQ, - "Mozilla", BROWSER_MOZILLA, - _("Manual"), BROWSER_MANUAL, -/* fixme: GNOME binary helper - _("GNOME URL Handler"), BROWSER_GNOME, */ - "Galeon", BROWSER_GALEON, - "Opera", BROWSER_OPERA, NULL); + + browsers = get_available_browsers(); + if (browsers != NULL) { + label = gaim_dropdown_from_list(vbox,_("_Browser"), &web_browser, -1, + browsers); gtk_misc_set_alignment(GTK_MISC(label), 0, 0); gtk_size_group_add_widget(sg, label); + } hbox = gtk_hbox_new(FALSE, 5); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); @@ -823,15 +869,27 @@ browser_entry = gtk_entry_new(); gtk_label_set_mnemonic_widget(GTK_LABEL(label), browser_entry); if (web_browser != BROWSER_MANUAL) - gtk_widget_set_sensitive(browser_entry, FALSE); + gtk_widget_set_sensitive(hbox, FALSE); gtk_box_pack_start (GTK_BOX (hbox), browser_entry, FALSE, FALSE, 0); gtk_entry_set_text(GTK_ENTRY(browser_entry), web_command); - g_signal_connect(GTK_OBJECT(browser_entry), "changed", - G_CALLBACK(browser_print_option), NULL); + g_signal_connect_swapped(GTK_OBJECT(browser_entry), "activate", + G_CALLBACK(manual_browser_set), NULL); + label = gtk_button_new_with_label(_("Set")); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); + g_signal_connect(GTK_OBJECT(label), "clicked", + G_CALLBACK(manual_browser_set), browser_entry); + label = gtk_button_new_with_label(_("Reset")); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); + g_signal_connect(GTK_OBJECT(label), "clicked", + G_CALLBACK(manual_browser_reset), browser_entry); + #endif /* end !_WIN32 */ + if (browsers != NULL) { vbox = make_frame (ret, _("Browser Options")); + label = gaim_button(_("Open new _window by default"), &misc_options, OPT_MISC_BROWSER_POPUP, vbox); + } #ifdef _WIN32 /* Until I figure out how to implement this on windows */ gtk_widget_set_sensitive(label, FALSE); @@ -2119,6 +2177,32 @@ default_away = g_slist_nth_data(away_messages, (int)i); } +static gboolean program_is_valid(const char *program) +{ + GError *error = NULL; + char **argv; + gboolean is_valid = FALSE; + + if (program == NULL || *program == '\0') { + return FALSE; + } + + if (!g_shell_parse_argv(program, NULL, &argv, &error)) { + debug_printf("Could not parse program '%s': ", error->message); + return FALSE; + } + + if (argv == NULL) { + return FALSE; + } + + is_valid = g_find_program_in_path(argv[0]) != NULL; + + g_strfreev(argv); + + return is_valid; +} + static void update_spin_value(GtkWidget *w, GtkWidget *spin) { int *value = gtk_object_get_user_data(GTK_OBJECT(spin)); @@ -2179,9 +2263,9 @@ gtk_widget_set_sensitive(prefs_proxy_frame, TRUE); } else if (option == &web_browser) { if (opt == BROWSER_MANUAL) - gtk_widget_set_sensitive(browser_entry, TRUE); + gtk_widget_set_sensitive(gtk_widget_get_parent(browser_entry), TRUE); else - gtk_widget_set_sensitive(browser_entry, FALSE); + gtk_widget_set_sensitive(gtk_widget_get_parent(browser_entry), FALSE); } else if (option == (int*)&sound_options) { if (opt == OPT_SOUND_CMD) gtk_widget_set_sensitive(sndcmd, TRUE); @@ -2206,7 +2290,36 @@ static GtkWidget *gaim_dropdown(GtkWidget *box, const gchar *title, int *option, int clear, ...) { - va_list menuitems; + va_list ap; + GList *menuitems = NULL; + GtkWidget *dropdown = NULL; + char *name; + int id; + + va_start(ap, clear); + while ((name = va_arg(ap, char *)) != NULL) { + id = va_arg(ap, int); + + menuitems = g_list_prepend(menuitems, name); + menuitems = g_list_prepend(menuitems, GINT_TO_POINTER(id)); + } + va_end(ap); + + if (menuitems == NULL) { + return; + } + + menuitems = g_list_reverse(menuitems); + + dropdown = gaim_dropdown_from_list(box, title, option, clear, menuitems); + + g_list_free(menuitems); + + return dropdown; +} + +static GtkWidget *gaim_dropdown_from_list(GtkWidget *box, const gchar *title, int *option, int clear, GList *menuitems) +{ GtkWidget *dropdown, *opt, *menu; GtkWidget *label; gchar *text; @@ -2214,6 +2327,8 @@ int o = 0; GtkWidget *hbox; + g_return_val_if_fail(menuitems != NULL, NULL); + hbox = gtk_hbox_new(FALSE, 5); gtk_container_add (GTK_CONTAINER (box), hbox); gtk_widget_show(hbox); @@ -2222,19 +2337,17 @@ gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); gtk_widget_show(label); - va_start(menuitems, clear); - text = va_arg(menuitems, gchar *); - - if (!text) - return NULL; - dropdown = gtk_option_menu_new(); menu = gtk_menu_new(); gtk_label_set_mnemonic_widget(GTK_LABEL(label), dropdown); - while (text) { - value = va_arg(menuitems, int); + while (menuitems != NULL && (text = (char *) menuitems->data) != NULL) { + menuitems = g_list_next(menuitems); + g_return_val_if_fail(menuitems != NULL, NULL); + value = GPOINTER_TO_INT(menuitems->data); + menuitems = g_list_next(menuitems); + opt = gtk_menu_item_new_with_label(text); gtk_object_set_user_data(GTK_OBJECT(opt), (void *)value); gtk_object_set_data(GTK_OBJECT(opt), "clear", (void *)clear); @@ -2246,12 +2359,10 @@ if (((clear > -1) && ((*option & value) == value)) || *option == value) { gtk_menu_set_active(GTK_MENU(menu), o); } - text = va_arg(menuitems, gchar *); o++; + } - va_end(menuitems); - gtk_option_menu_set_menu(GTK_OPTION_MENU(dropdown), menu); gtk_box_pack_start(GTK_BOX(hbox), dropdown, FALSE, FALSE, 0); gtk_widget_show(dropdown);