version 3.3:
* add support for Opera Mobile
+* only offer installed browsers in the config GUI
+* make continuous mode operation the default; disable non-continuous-mode on
+ Fremantle (needed for correct operation on D-Bus system bus)
+* Fremantle: major overhaul of MicroB launching to improve robustness; should
+ result in speed and behavior indistinguishable from when Browser Switchboard
+ isn't installed when MicroB is configured as default browser
* fall back to the built-in default if the user's configured default browser
isn't installed
+* listen on D-Bus system bus as well as session bus, to accommodate some broken
+ applications that send their requests on the system bus
+* Fremantle: start browser-switchboard on X session startup, and also prestart
+ MicroB if it's the default browser or the user asks for it
+* Fremantle: prestart MicroB when the user changes to MicroB as the default
+ browser
* introduce a command-line config utility; this is mainly intended to give
browser vendors a way to set their browser as the default
-* provide a description for users who don't know what MicroB is; thanks
- Emanuele Cassioli for pointing out the need
+* config UI: provide a description for users who don't know what MicroB is;
+ thanks Emanuele Cassioli for pointing out the need
* major rewrite of configuration loading/saving code
version 3.2:
install -c -m 0755 microb $(DESTDIR)$(PREFIX)/bin
install -c -m 0644 microb.desktop $(DESTDIR)$(PREFIX)/share/applications/hildon
+install-xsession-script:
+ mkdir -p $(DESTDIR)/etc/X11/Xsession.post
+ install -c -m 0755 xsession-post.sh $(DESTDIR)/etc/X11/Xsession.post/35browser-switchboard
+
clean:
rm -f $(APP) $(obj) dbus-server-glue.h
-.PHONY: strip install diablo fremantle
+.PHONY: strip install install-xsession-script diablo fremantle
BROWSER SWITCHBOARD
-version 3.3b1
+version 3.3b2
Browser Switchboard is a program which allows you to choose which
browser to use as the default browser. It supports MicroB, Tear,
Quick Start:
1. Download the binary package: browser-switchboard_X.Y-Z_all.deb
(where X.Y-Z is the version number, of course).
-2. If you're using a Maemo 5 device, make sure all your MicroB browser
-windows are closed.
-3. Install the package using the Application Manager (open the
+2. Install the package using the Application Manager (open the
Application Manager, then select Application->Install from file in the
menu).
default_browser = "your_browser"
EOF
-where your_browser can be one of "tear", "microb", "fennec", "midori",
-or "other" (see below for more on the "other" option). You can of
-course also edit the $HOME/.config/browser-switchboard file with your
+where your_browser can be one of "tear", "microb", "fennec", "opera",
+"midori" or "other" (see below for more on the "other" option). You can
+of course also edit the $HOME/.config/browser-switchboard file with your
favorite text editor.
To restore the default behavior, just delete the config file:
# BEGIN SAMPLE CONFIG FILE
# This is a comment
# continuous_mode: 0 -- close after handling a request; 1 -- run
-# continuously in the background
-continuous_mode = 0
-# default_browser: "tear", "microb", "fennec", "midori", or "other"
+# continuously in the background (default)
+# On Fremantle, this is forced to 1 regardless of config setting
+continuous_mode = 1
+# default_browser: "tear", "microb", "fennec", "midori", "opera" or
+# "other"
default_browser = "tear"
# other_browser_cmd: If default browser is "other", what program
# to run (%s will be replaced by URI)
#other_browser_cmd = "some_browser %s"
# logging: Where log output should go: "stdout", "syslog", "none"
#logging = "stdout"
+# autostart_microb: Fremantle only: whether MicroB should be
+# prestarted in the background: 0 -- never prestart MicroB; 1 -- always
+# prestart MicroB; -1 -- only prestart MicroB when MicroB is the default
+# browser (default behavior if unset)
+#autostart_microb = 0
# END SAMPLE CONFIG FILE
Lines beginning with # characters are comments and are ignored by the
In continuous mode, Browser Switchboard keeps running in the background
instead of closing after handling each request. This saves a bit of
startup time for each link (on my N800 running Diablo), but costs you
-about 100 KB extra memory. Continuous mode is disabled by default; set
-continuous_mode to 1 to enable. [This option corresponds to the
-"Optimize Browser Switchboard for" option group in the UI; "Lower memory
-usage" corresponds to continuous_mode off, while "Faster browser startup
-time" corresponds to continuous_mode on.]
-
-The "tear", "microb", "fennec", and "midori" options for default_browser
-should be self-explanatory. [These correspond to the options in the
-"Default browser" combo box in the UI.]
+about 100 KB extra memory. Continuous mode is enabled by default; set
+continuous_mode to 0 to enable. On Fremantle, continuous mode is always
+enabled regardless of the value of this config setting, to provide
+better compatibility with MicroB's behavior. [This option corresponds
+to the "Optimize Browser Switchboard for" option group in the UI; "Lower
+memory usage" corresponds to continuous_mode off, while "Faster browser
+startup time" corresponds to continuous_mode on.]
+
+The "tear", "microb", "fennec", "opera" and "midori" options for
+default_browser should be self-explanatory. [These correspond to the
+options in the "Default browser" combo box in the UI.]
If the default browser is "other", Browser Switchboard will run the
program specified in other_browser_cmd as the default browser, with a
to the system log (assuming you have a syslogd set up on your device),
and "none" disables debug logging entirely.
+On Fremantle only, autostart_microb controls whether MicroB is
+prestarted when the device boots and whether the MicroB browser process
+is left running when no browser windows are open. By default, MicroB is
+prestarted (and the process left open when no browser windows are open)
+only when MicroB is set as the default browser; you can force MicroB to
+always prestart by setting autostart_microb = 1, while you can force it
+to never prestart by setting autostart_microb = 0. [This option has no
+corresponding UI at the moment.]
+
+
+The browser-switchboard-config Command-Line Configuration Tool:
+
+A command-line configuration utility is provided to allow programs and
+scripts to query and set Browser Switchboard configuration variables.
+For example,
+
+$ browser-switchboard-config -b
+
+will display the default browser, and
+
+$ browser-switchboard-config -s -b "opera"
+
+will set the default browser to Opera Mobile. See the help output from
+running browser-switchboard-config with no arguments for more
+information.
+
+The primary purpose of this tool is to allow browser vendors to provide
+an option in their browsers to set themselves as the default browser,
+via something like this (shell-like pseudocode):
+
+if [ -x /usr/bin/browser-switchboard-config ]; then
+ if [ `browser-switchboard-config -b` = "mybrowser" ]; then
+ display "MyBrowser is the default browser."
+ else
+ button "Make MyBrowser the default browser"
+ action "browser-switchboard-config -s -b mybrowser"
+ fi
+else
+ display "Install Browser Switchboard to make MyBrowser the default browser"
+fi
+
+Browser vendors: setting yourself as the default browser without
+prompting the user first (via package maintainer scripts, for example)
+is strongly discouraged.
+
Browser Switchboard and MicroB's browserd:
int continuous_mode;
void (*default_browser_launcher)(struct swb_context *, char *);
char *other_browser_cmd;
+#ifdef FREMANTLE
+ int autostart_microb;
+#endif
DBusGConnection *session_bus;
DBusGProxy *dbus_proxy;
+ DBusGConnection *system_bus;
+ DBusGProxy *dbus_system_proxy;
};
#endif /* _BROWSER_SWITCHBOARD_H */
@echo ' make util -- build command-line configuration utility'
@echo ' make diablo-hildon-app -- build standalone Diablo Hildon application'
@echo ' make diablo-plugin -- build Diablo hildon-control-panel plugin'
+ @echo ' make fremantle-util -- build command-line configuration utility for Fremantle'
@echo ' make fremantle-hildon-app -- build standalone Fremantle Hildon application'
@echo ' make fremantle-plugin -- build Fremantle hildon-control-panel plugin'
app: $(APP)
util: $(UTIL)
diablo-hildon-app: $(HILDON_APP)
diablo-plugin: $(PLUGIN)
+fremantle-util:
+ @$(MAKE) EXTRA_CPPFLAGS='-DFREMANTLE $(EXTRA_CPPFLAGS)' $(UTIL)
fremantle-hildon-app:
@$(MAKE) EXTRA_CPPFLAGS='-DFREMANTLE $(EXTRA_CPPFLAGS)' $(HILDON_APP)
fremantle-plugin:
$(PLUGIN): $(plugin_obj)
$(CC) $(CFLAGS) $(CFLAGS_PLUGIN) -o $(PLUGIN) $(plugin_obj) \
$(LDFLAGS) $(LDFLAGS_PLUGIN)
-
+
%.plugin.o: %.c
$(CC) $(CFLAGS) $(CFLAGS_PLUGIN) $(CPPFLAGS) $(CPPFLAGS_PLUGIN) \
/*
- * browser-switchboard-config.c -- command-line configuration utility for
+ * browser-switchboard-config.c -- command-line configuration utility for
* Browser Switchboard
- *
+ *
* Copyright (C) 2009-2010 Steven Luo
- *
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
#include <stddef.h>
#include <string.h>
#include <stdio.h>
+#include <unistd.h>
#include <getopt.h>
#include "config.h"
+#include "save-config.h"
+#include "browsers.h"
extern struct swb_config_option swb_config_options[];
return retval;
}
-static int set_config_value(char *name, char *value) {
+static int get_default_browser(void) {
struct swb_config cfg;
+ int i;
+
+ swb_config_init(&cfg);
+
+ if (!swb_config_load(&cfg))
+ return 1;
+
+ /* Check to see if the configured default browser is installed
+ If not, report the default default browser */
+ for (i = 0; browsers[i].config; ++i) {
+ if (strcmp(browsers[i].config, cfg.default_browser))
+ continue;
+
+ if (browsers[i].binary && access(browsers[i].binary, X_OK))
+ printf("%s\n", browsers[0].config);
+ else
+ printf("%s\n", browsers[i].config);
+
+ break;
+ }
+
+ if (!browsers[i].config)
+ /* Unknown browser configured as default, report the default
+ default browser */
+ printf("%s\n", browsers[0].config);
+
+ swb_config_free(&cfg);
+
+ return 0;
+}
+
+static int set_config_value(char *name, char *value) {
+ struct swb_config orig_cfg, cfg;
struct swb_config_option *optinfo;
ptrdiff_t i;
int retval = 1;
- swb_config_init(&cfg);
+ swb_config_init(&orig_cfg);
- if (!swb_config_load(&cfg))
+ if (!swb_config_load(&orig_cfg))
return 1;
+ swb_config_copy(&cfg, &orig_cfg);
+
for (optinfo = swb_config_options; optinfo->name; ++optinfo) {
if (strcmp(name, optinfo->name))
continue;
i = optinfo - swb_config_options;
switch (optinfo->type) {
case SWB_CONFIG_OPT_STRING:
- /* Free any existing string */
- if (cfg.flags & optinfo->set_mask)
- free(*(char **)cfg.entries[i]);
-
if (strlen(value) == 0) {
/* If the new value is empty, clear the config
setting */
if (!swb_config_save(&cfg))
retval = 1;
- swb_config_free(&cfg);
+ /* Reconfigure a running browser-switchboard, if present */
+ swb_reconfig(&orig_cfg, &cfg);
- /* Try to send SIGHUP to any running browser-switchboard process
- This causes it to reread config files if in continuous_mode, or
- die so that the config will be reloaded on next start otherwise */
- system("kill -HUP `pidof browser-switchboard` > /dev/null 2>&1");
+ swb_config_free(&orig_cfg);
+ /* XXX can't free all of cfg, it contains pointers to memory we just
+ freed above
+ swb_config_free(&cfg); */
+ if (optinfo->name && optinfo->type == SWB_CONFIG_OPT_STRING)
+ free(*(char **)cfg.entries[i]);
return retval;
}
int opt, done = 0;
int set = 0;
char *selected_opt = NULL;
-
+
while (!done && (opt = getopt(argc, argv, "hsbcmo:")) != -1) {
switch (opt) {
case 'h':
exit(1);
}
return set_config_value(selected_opt, argv[optind]);
- } else
+ } else if (!strcmp(selected_opt, "default_browser"))
+ /* Default browser value needs special handling */
+ return get_default_browser();
+ else
return get_config_value(selected_opt);
}
/*
* browser-switchboard-cp.c -- a hildon-control-panel applet for
* selecting the default browser for Browser Switchboard
- *
+ *
* Copyright (C) 2009-2010 Steven Luo
* Copyright (C) 2009-2010 Faheem Pervez
- *
+ *
* Derived from services-cp.c from maemo-control-services
* Copyright (c) 2008 Janne Kataja <janne.kataja@iki.fi>
* Copyright (c) 2008 Nokia Corporation
- *
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
#endif /* HILDON */
#include "config.h"
+#include "save-config.h"
+#include "browsers.h"
#define CONTINUOUS_MODE_DEFAULT 0
#define _HILDON_SIZE_DEFAULT (HILDON_SIZE_AUTO_WIDTH|HILDON_SIZE_FINGER_HEIGHT)
#endif
-struct browser_entry {
- char *config;
- char *displayname;
-};
-struct browser_entry browsers[] = {
- { "microb", "MicroB (stock browser)" }, /* First entry is the default! */
- { "tear", "Tear" },
- { "fennec", "Mobile Firefox (Fennec)" },
- { "opera", "Opera Mobile" },
- { "midori", "Midori" },
- { "other", "Other" },
- { NULL, NULL },
-};
-
struct swb_config orig_cfg;
struct config_widgets {
#if defined(HILDON) && defined(FREMANTLE)
- GtkWidget *continuous_mode_selector;
GtkWidget *default_browser_selector;
#else
GtkWidget *continuous_mode_off_radio;
GtkWidget *dialog;
+struct browser_entry *installed_browsers;
+void init_installed_browsers(void) {
+ struct browser_entry *cur = browsers;
+ unsigned int count = 0;
+
+ installed_browsers = calloc(sizeof browsers, 1);
+ if (!installed_browsers)
+ exit(1);
+
+ count = 0;
+ for (; cur->config; ++cur)
+ if (!cur->binary || !access(cur->binary, X_OK))
+ installed_browsers[count++] = *cur;
+}
+
/**********************************************************************
* Configuration routines
**********************************************************************/
#if defined(HILDON) && defined(FREMANTLE)
-static inline int get_continuous_mode(void) {
- return hildon_touch_selector_get_active(HILDON_TOUCH_SELECTOR(cw.continuous_mode_selector), 0);
-}
-static inline void set_continuous_mode(int state) {
- hildon_touch_selector_set_active(HILDON_TOUCH_SELECTOR(cw.continuous_mode_selector), 0, state);
-}
-
static inline char *get_default_browser(void) {
- return browsers[hildon_touch_selector_get_active(HILDON_TOUCH_SELECTOR(cw.default_browser_selector), 0)].config;
+ return installed_browsers[hildon_touch_selector_get_active(HILDON_TOUCH_SELECTOR(cw.default_browser_selector), 0)].config;
}
#else /* !defined(HILDON) || !defined(FREMANTLE) */
}
static inline char *get_default_browser(void) {
- return browsers[gtk_combo_box_get_active(GTK_COMBO_BOX(cw.default_browser_combo))].config;
+ return installed_browsers[gtk_combo_box_get_active(GTK_COMBO_BOX(cw.default_browser_combo))].config;
}
#endif /* defined(HILDON) && defined(FREMANTLE) */
gint i;
/* Loop through browsers looking for a match */
- for (i = 0; browsers[i].config && strcmp(browsers[i].config, browser);
- ++i);
+ for (i = 0;
+ installed_browsers[i].config && strcmp(installed_browsers[i].config, browser);
+ ++i);
- if (!browsers[i].config)
+ if (!installed_browsers[i].config)
/* No match found, set to the default browser */
i = 0;
static void load_config(void) {
swb_config_init(&orig_cfg);
-
+
swb_config_load(&orig_cfg);
+#ifndef FREMANTLE
set_continuous_mode(orig_cfg.continuous_mode);
+#endif
set_default_browser(orig_cfg.default_browser);
if (orig_cfg.other_browser_cmd)
set_other_browser_cmd(orig_cfg.other_browser_cmd);
swb_config_copy(&new_cfg, &orig_cfg);
+#ifndef FREMANTLE
if (get_continuous_mode() != orig_cfg.continuous_mode) {
new_cfg.continuous_mode = get_continuous_mode();
new_cfg.flags |= SWB_CONFIG_CONTINUOUS_MODE_SET;
}
+#endif
if (strcmp(get_default_browser(), orig_cfg.default_browser)) {
new_cfg.default_browser = get_default_browser();
new_cfg.flags |= SWB_CONFIG_DEFAULT_BROWSER_SET;
}
swb_config_save(&new_cfg);
-}
-
-static void do_reconfig(void) {
- save_config();
- /* Try to send SIGHUP to any running browser-switchboard process
- This causes it to reread config files if in continuous_mode, or
- die so that the config will be reloaded on next start otherwise */
- system("kill -HUP `pidof browser-switchboard` > /dev/null 2>&1");
+ /* Reconfigure a running browser-switchboard, if present */
+ swb_reconfig(&orig_cfg, &new_cfg);
}
GtkWidget *dialog_vbox;
GtkWidget *default_browser_selector_button;
- GtkWidget *continuous_mode_selector_button;
int i;
HildonGtkInputMode input_mode;
dialog_vbox = GTK_DIALOG(dialog)->vbox;
/* Config options */
+ init_installed_browsers();
cw.default_browser_selector = hildon_touch_selector_new_text();
- for (i = 0; browsers[i].config; ++i)
- hildon_touch_selector_append_text(HILDON_TOUCH_SELECTOR(cw.default_browser_selector), browsers[i].displayname);
+ for (i = 0; installed_browsers[i].config; ++i)
+ hildon_touch_selector_append_text(HILDON_TOUCH_SELECTOR(cw.default_browser_selector), installed_browsers[i].displayname);
hildon_touch_selector_set_active(HILDON_TOUCH_SELECTOR(cw.default_browser_selector), 0, 0);
default_browser_selector_button = hildon_picker_button_new(_HILDON_SIZE_DEFAULT, HILDON_BUTTON_ARRANGEMENT_HORIZONTAL);
hildon_button_set_title(HILDON_BUTTON(default_browser_selector_button),
gtk_box_pack_start(GTK_BOX(dialog_vbox),
cw.other_browser_cmd_entry_label, FALSE, FALSE, 0);
- cw.continuous_mode_selector = hildon_touch_selector_new_text();
- hildon_touch_selector_append_text(HILDON_TOUCH_SELECTOR(cw.continuous_mode_selector), "Lower memory usage");
- hildon_touch_selector_append_text(HILDON_TOUCH_SELECTOR(cw.continuous_mode_selector), "Faster browser startup time");
-
- continuous_mode_selector_button = hildon_picker_button_new(_HILDON_SIZE_DEFAULT, HILDON_BUTTON_ARRANGEMENT_VERTICAL);
- hildon_button_set_title(HILDON_BUTTON(continuous_mode_selector_button),
- "Optimize Browser Switchboard for:");
- hildon_picker_button_set_selector(HILDON_PICKER_BUTTON(continuous_mode_selector_button), HILDON_TOUCH_SELECTOR(cw.continuous_mode_selector));
- hildon_button_set_alignment(HILDON_BUTTON(continuous_mode_selector_button),
- 0, 0, 0, 0);
- set_continuous_mode(CONTINUOUS_MODE_DEFAULT);
- gtk_box_pack_start(GTK_BOX(dialog_vbox),
- continuous_mode_selector_button, FALSE, FALSE, 0);
-
gtk_widget_show_all(dialog);
return GTK_DIALOG(dialog);
}
gtk_table_set_row_spacings(GTK_TABLE(options_table), 5);
gtk_box_pack_start(GTK_BOX(dialog_vbox), options_table, FALSE, FALSE, 0);
+ init_installed_browsers();
cw.default_browser_combo = gtk_combo_box_new_text();
- for (i = 0; browsers[i].config; ++i)
+ for (i = 0; installed_browsers[i].config; ++i)
gtk_combo_box_append_text(GTK_COMBO_BOX(cw.default_browser_combo),
- browsers[i].displayname);
+ installed_browsers[i].displayname);
gtk_combo_box_set_active(GTK_COMBO_BOX(cw.default_browser_combo), 0);
default_browser_combo_label = gtk_label_new("Default browser:");
gtk_misc_set_alignment(GTK_MISC(default_browser_combo_label), 1, 0.5);
response = gtk_dialog_run(dialog);
if (response == GTK_RESPONSE_OK)
- do_reconfig();
+ save_config();
gtk_widget_destroy(GTK_WIDGET(dialog));
response = gtk_dialog_run(dialog);
if (response == GTK_RESPONSE_OK)
- do_reconfig();
+ save_config();
gtk_widget_destroy(GTK_WIDGET(dialog));
-[Desktop Entry]
+[Desktop Entry]
Encoding=UTF-8
Version=1.0
Name=Browser Switchboard
--- /dev/null
+/*
+ * browsers.h -- the list of known browsers
+ *
+ * Copyright (C) 2010 Steven Luo
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ */
+
+#ifndef _BROWSERS_H
+#define _BROWSERS_H 1
+
+struct browser_entry {
+ char *config;
+ char *displayname;
+ char *binary;
+};
+
+struct browser_entry browsers[] = {
+ { "microb", "MicroB (stock browser)", NULL }, /* First entry is the default! */
+ { "tear", "Tear", "/usr/bin/tear" },
+ { "fennec", "Firefox Mobile", "/usr/bin/fennec" },
+ { "opera", "Opera Mobile", "/usr/bin/opera" },
+ { "midori", "Midori", "/usr/bin/midori" },
+ { "other", "Other", NULL },
+ { NULL, NULL, NULL },
+};
+
+#endif /* _BROWSERS_H */
#include <sys/types.h>
#include <sys/stat.h>
+#ifdef FREMANTLE
+#include <sys/wait.h>
+#endif
+
#include "configfile.h"
#include "config.h"
struct swb_config *cfg, char *name) {
struct swb_config_option *opt;
ptrdiff_t i;
-
+
for (opt = swb_config_options; opt->name; ++opt) {
if (strcmp(opt->name, name))
continue;
fclose(fp);
return retval;
}
+
+/* Reconfigure a running browser-switchboard process with new settings */
+void swb_reconfig(struct swb_config *old, struct swb_config *new) {
+#ifdef FREMANTLE
+ int microb_was_autostarted, microb_should_autostart;
+ pid_t pid;
+ int status;
+#endif
+
+ /* Try to send SIGHUP to any running browser-switchboard process
+ This causes it to reread config files if in continuous_mode, or
+ die so that the config will be reloaded on next start otherwise */
+ system("kill -HUP `pidof browser-switchboard` > /dev/null 2>&1");
+
+#ifdef FREMANTLE
+ if (!old || !new)
+ return;
+
+ microb_was_autostarted = (old->autostart_microb == 1) ||
+ (!strcmp(old->default_browser, "microb") &&
+ old->autostart_microb);
+ microb_should_autostart = (new->autostart_microb == 1) ||
+ (!strcmp(new->default_browser, "microb") &&
+ new->autostart_microb);
+ if (!microb_was_autostarted && microb_should_autostart) {
+ /* MicroB should be started if it's not running */
+ status = system("pidof browser > /dev/null");
+ if (WIFEXITED(status) && WEXITSTATUS(status)) {
+ if ((pid = fork()) == -1)
+ return;
+
+ if (!pid) {
+ /* Child process, start MicroB */
+ execl("/usr/bin/maemo-invoker", "browser",
+ (char *)NULL);
+ }
+ }
+ }
+ /* XXX: We'd like to stop MicroB if (microb_was_autostarted &&
+ !microb_should_autostart), but we don't know if the open MicroB
+ process has open windows. */
+#endif /* FREMANTLE */
+
+ return;
+}
--- /dev/null
+/*
+ * save-config.h -- definitions for saving Browser Switchboard configuration
+ *
+ * Copyright (C) 2009-2010 Steven Luo
+ * Derived from a Python implementation by Jason Simpson and Steven Luo
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ */
+
+#ifndef _SAVE_CONFIG_H
+#define _SAVE_CONFIG_H
+
+#include "config.h"
+
+int swb_config_save(struct swb_config *cfg);
+void swb_reconfig(struct swb_config *old, struct swb_config *new);
+
+#endif /* _SAVE_CONFIG_H */
{ "default_browser", SWB_CONFIG_OPT_STRING, SWB_CONFIG_DEFAULT_BROWSER_SET },
{ "other_browser_cmd", SWB_CONFIG_OPT_STRING, SWB_CONFIG_OTHER_BROWSER_CMD_SET },
{ "logging", SWB_CONFIG_OPT_STRING, SWB_CONFIG_LOGGING_SET },
+ { "autostart_microb", SWB_CONFIG_OPT_INT, SWB_CONFIG_AUTOSTART_MICROB_SET },
{ NULL, 0, 0 },
};
/* Browser Switchboard configuration defaults */
static struct swb_config swb_config_defaults = {
.flags = SWB_CONFIG_INITIALIZED,
- .continuous_mode = 0,
+ .continuous_mode = 1,
.default_browser = "microb",
.other_browser_cmd = NULL,
.logging = "stdout",
+ .autostart_microb = -1,
};
dst->entries[1] = &(dst->default_browser);
dst->entries[2] = &(dst->other_browser_cmd);
dst->entries[3] = &(dst->logging);
+ dst->entries[4] = &(dst->autostart_microb);
dst->flags = src->flags;
dst->default_browser = src->default_browser;
dst->other_browser_cmd = src->other_browser_cmd;
dst->logging = src->logging;
+ dst->autostart_microb = src->autostart_microb;
}
/* Initialize a swb_config struct with configuration defaults */
char *name, char *value) {
struct swb_config_option *opt;
ptrdiff_t i;
- int retval = 0;
+ /* Search through list of recognized config options for a match */
for (opt = swb_config_options; opt->name; ++opt) {
if (strcmp(name, opt->name))
continue;
break;
}
cfg->flags |= opt->set_mask;
+ } else {
+ /* Option was repeated in the config file
+ We want the first value, so ignore this one */
+ free(value);
}
- retval = 1;
- break;
+ return 1;
}
- if (!retval)
- free(value);
-
- return retval;
+ /* Unrecognized config option */
+ free(value);
+ return 0;
}
/* Read the config file and load settings into the provided swb_config struct
#define SWB_CONFIG_DEFAULT_BROWSER_SET 0x04
#define SWB_CONFIG_OTHER_BROWSER_CMD_SET 0x08
#define SWB_CONFIG_LOGGING_SET 0x10
+#define SWB_CONFIG_AUTOSTART_MICROB_SET 0x20
struct swb_config {
unsigned int flags;
/* Array of pointers to the elements of the struct, in the order given
in swb_config_options[] */
- void *entries[4];
+ void *entries[5];
int continuous_mode;
char *default_browser;
char *other_browser_cmd;
char *logging;
+ int autostart_microb;
};
struct swb_config_option {
int swb_config_load(struct swb_config *cfg);
-int swb_config_save(struct swb_config *cfg);
-
#endif /* _CONFIG_H */
/* calloc() zeroes the memory, so string is automatically
null terminated */
- /* make key point to a null-terminated string holding the
+ /* make key point to a null-terminated string holding the
config key */
len = substrs[1].rm_eo - substrs[1].rm_so;
memmove(line->key, line->key+substrs[1].rm_so, len);
GError *error = NULL;
guint result;
- if (!ctx || !ctx->dbus_proxy)
+ if (!ctx || !ctx->dbus_proxy || !ctx->dbus_system_proxy)
return;
+ /* Acquire the com.nokia.osso_browser name on the session bus */
if (!dbus_g_proxy_call(ctx->dbus_proxy, "RequestName", &error,
G_TYPE_STRING, "com.nokia.osso_browser",
G_TYPE_UINT, DBUS_NAME_FLAG_REPLACE_EXISTING|DBUS_NAME_FLAG_DO_NOT_QUEUE,
log_msg("Couldn't acquire name com.nokia.osso_browser\n");
exit(1);
}
- if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
+ if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
log_msg("Couldn't acquire name com.nokia.osso_browser\n");
exit(1);
}
+
+ /* Try to acquire the com.nokia.osso_browser name on the system bus
+ Treat a failure as non-fatal, which makes testing on desktop systems
+ easier */
+ if (!dbus_g_proxy_call(ctx->dbus_system_proxy, "RequestName", &error,
+ G_TYPE_STRING, "com.nokia.osso_browser",
+ G_TYPE_UINT, DBUS_NAME_FLAG_REPLACE_EXISTING|DBUS_NAME_FLAG_DO_NOT_QUEUE,
+ G_TYPE_INVALID,
+ G_TYPE_UINT, &result,
+ G_TYPE_INVALID)) {
+ log_msg("Couldn't acquire name com.nokia.osso_browser on system bus\n");
+ g_error_free(error);
+ }
+ if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
+ log_msg("Couldn't acquire name com.nokia.osso_browser on system bus\n");
+ }
}
/* Release the name com.nokia.osso_browser on the D-Bus session bus */
GError *error = NULL;
guint result;
- if (!ctx || !ctx->dbus_proxy)
+ if (!ctx || !ctx->dbus_proxy || !ctx->dbus_system_proxy)
return;
dbus_g_proxy_call(ctx->dbus_proxy, "ReleaseName", &error,
G_TYPE_INVALID,
G_TYPE_UINT, &result,
G_TYPE_INVALID);
+ dbus_g_proxy_call(ctx->dbus_system_proxy, "ReleaseName", &error,
+ G_TYPE_STRING, "com.nokia.osso_browser",
+ G_TYPE_INVALID,
+ G_TYPE_UINT, &result,
+ G_TYPE_INVALID);
}
#ifdef FREMANTLE
static int microb_started = 0;
-
-/* Check to see whether MicroB is ready to handle D-Bus requests yet
- See the comments in launch_microb to understand how this works. */
-static DBusHandlerResult check_microb_started(DBusConnection *connection,
- DBusMessage *message,
- void *user_data) {
- DBusError error;
- char *name, *old, *new;
-
- log_msg("Checking to see if MicroB is ready\n");
- dbus_error_init(&error);
- if (!dbus_message_get_args(message, &error,
- DBUS_TYPE_STRING, &name,
- DBUS_TYPE_STRING, &old,
- DBUS_TYPE_STRING, &new,
- DBUS_TYPE_INVALID)) {
- log_msg("%s\n", error.message);
- dbus_error_free(&error);
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
- }
- /* If old is an empty string, then the name has been acquired, and
- MicroB should be ready to handle our request */
- if (strlen(old) == 0) {
- log_msg("MicroB ready\n");
- microb_started = 1;
- }
-
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-
-/* Get a browserd PID from the corresponding Mozilla profile lockfile */
-static pid_t get_browserd_pid(const char *lockfile) {
- char buf[256], *tmp;
-
- /* The lockfile is a symlink pointing to "[ipaddr]:+[pid]", so read in
- the target of the symlink and parse it that way */
- memset(buf, '\0', 256);
- if (readlink(lockfile, buf, 255) == -1)
- return -errno;
- if (!(tmp = strstr(buf, ":+")))
- return 0;
- tmp += 2; /* Skip over the ":+" */
-
- return atoi(tmp);
-}
#endif
+
/* Close stdin/stdout/stderr and replace with /dev/null */
static int close_stdio(void) {
int fd;
return 0;
}
+
static void launch_tear(struct swb_context *ctx, char *uri) {
int status;
static DBusGProxy *tear_proxy = NULL;
}
}
-void launch_microb(struct swb_context *ctx, char *uri) {
- int kill_browserd = 0;
+
+#ifdef FREMANTLE
+/* Get a browserd PID from the corresponding Mozilla profile lockfile */
+static pid_t get_browserd_pid(const char *lockfile) {
+ char buf[256], *tmp;
+
+ /* The lockfile is a symlink pointing to "[ipaddr]:+[pid]", so read in
+ the target of the symlink and parse it that way */
+ memset(buf, '\0', 256);
+ if (readlink(lockfile, buf, 255) == -1)
+ return -errno;
+ if (!(tmp = strstr(buf, ":+")))
+ return 0;
+ tmp += 2; /* Skip over the ":+" */
+
+ return atoi(tmp);
+}
+
+/* Check to see whether MicroB is ready to handle D-Bus requests yet
+ See the comments in microb_start_dbus_watch_* to understand how this
+ works. */
+static DBusHandlerResult check_microb_started(DBusConnection *connection,
+ DBusMessage *message,
+ void *user_data) {
+ DBusError error;
+ char *name, *old, *new;
+
+ log_msg("Checking to see if MicroB is ready\n");
+ dbus_error_init(&error);
+ if (!dbus_message_get_args(message, &error,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_STRING, &old,
+ DBUS_TYPE_STRING, &new,
+ DBUS_TYPE_INVALID)) {
+ log_msg("%s\n", error.message);
+ dbus_error_free(&error);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ /* If new is not an empty string, then the name has been acquired, and
+ MicroB should be ready to handle our request */
+ if (strlen(new) > 0) {
+ log_msg("MicroB ready\n");
+ microb_started = 1;
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+/* Set up the D-Bus eavesdropping we'll use to watch for MicroB acquiring the
+ com.nokia.osso_browser D-Bus name.
+
+ Ideas for how to do this monitoring derived from the dbus-monitor code
+ (tools/dbus-monitor.c in the D-Bus codebase). */
+DBusConnection *microb_start_dbus_watch_init(void) {
+ DBusConnection *conn;
+ DBusError dbus_error;
+ DBusHandleMessageFunction filter_func = check_microb_started;
+
+ dbus_error_init(&dbus_error);
+
+ conn = dbus_bus_get_private(DBUS_BUS_SESSION, &dbus_error);
+ if (!conn) {
+ log_msg("Failed to open connection to session bus: %s\n",
+ dbus_error.message);
+ dbus_error_free(&dbus_error);
+ return NULL;
+ }
+
+ dbus_bus_add_match(conn,
+ "type='signal',interface='org.freedesktop.DBus',member='NameOwnerChanged',arg0='com.nokia.osso_browser'",
+ &dbus_error);
+ if (dbus_error_is_set(&dbus_error)) {
+ log_msg("Failed to set up watch for browser UI start: %s\n",
+ dbus_error.message);
+ dbus_error_free(&dbus_error);
+ return NULL;
+ }
+ if (!dbus_connection_add_filter(conn, filter_func, NULL, NULL)) {
+ log_msg("Failed to set up watch filter!\n");
+ return NULL;
+ }
+
+ return conn;
+}
+
+/* Wait for MicroB to acquire the com.nokia.osso_browser D-Bus name
+ Blocks until name is acquired, then returns */
+void microb_start_dbus_watch_wait(DBusConnection *conn) {
+ microb_started = 0;
+ log_msg("Waiting for MicroB to start\n");
+ while (!microb_started &&
+ dbus_connection_read_write_dispatch(conn, -1));
+}
+
+/* Tear down the D-Bus watch for acquiring com.nokia.osso-browser */
+void microb_start_dbus_watch_remove(DBusConnection *conn) {
+ DBusError dbus_error;
+ DBusHandleMessageFunction filter_func = check_microb_started;
+
+ dbus_error_init(&dbus_error);
+
+ dbus_connection_remove_filter(conn, filter_func, NULL);
+ dbus_bus_remove_match(conn,
+ "type='signal',interface='org.freedesktop.DBus',member='NameOwnerChanged',arg0='com.nokia.osso_browser'",
+ &dbus_error);
+ if (dbus_error_is_set(&dbus_error))
+ /* Don't really care -- about to disconnect from the
+ bus anyhow */
+ dbus_error_free(&dbus_error);
+ dbus_connection_close(conn);
+ dbus_connection_unref(conn);
+}
+
+/* Start a new MicroB browser process if one isn't already running */
+pid_t launch_microb_start_browser_process(DBusConnection *conn, int fd) {
+ pid_t pid;
+ int status;
+
+ status = system("pidof browser > /dev/null");
+ if (WIFEXITED(status) && !WEXITSTATUS(status)) {
+ /* MicroB browser already running */
+ return 0;
+ }
+
+ if ((pid = fork()) == -1) {
+ log_perror(errno, "fork");
+ return -1;
+ }
+
+ if (!pid) {
+ /* Child process */
+ dbus_connection_close(conn);
+ dbus_connection_unref(conn);
+ if (fd != -1)
+ close(fd);
+ close_stdio();
+
+ /* exec maemo-invoker directly instead of relying on the
+ /usr/bin/browser symlink, since /usr/bin/browser may have
+ been replaced with a shell script calling us via D-Bus */
+ /* Launch the browser in the background -- our parent will
+ wait for it to claim the D-Bus name and then display the
+ window using D-Bus */
+ execl("/usr/bin/maemo-invoker", "browser", (char *)NULL);
+
+ /* If we get here, exec() failed */
+ exit(1);
+ }
+
+ return pid;
+}
+
+/* Open a MicroB window using the D-Bus interface
+ It's assumed that we have already released the D-Bus name and that it's been
+ ensured that MicroB has acquired com.nokia.osso_browser (otherwise this will
+ cause D-Bus to try forever to launch another browser-switchboard) */
+
+#define LAUNCH_MICROB_BOOKMARK_WIN_OK 0x1
+
+int launch_microb_open_window(struct swb_context *ctx, char *uri,
+ int flags) {
+ DBusGProxy *g_proxy;
+ GError *gerror = NULL;
+
+ g_proxy = dbus_g_proxy_new_for_name(ctx->session_bus,
+ "com.nokia.osso_browser",
+ "/com/nokia/osso_browser/request",
+ "com.nokia.osso_browser");
+ if (!g_proxy) {
+ log_msg("Couldn't get a com.nokia.osso_browser proxy\n");
+ return 0;
+ }
+
+ if (!strcmp(uri, "new_window")) {
+ if (flags & LAUNCH_MICROB_BOOKMARK_WIN_OK) {
+ if (!dbus_g_proxy_call(g_proxy, "top_application",
+ &gerror, G_TYPE_INVALID,
+ G_TYPE_INVALID)) {
+ log_msg("Opening window failed: %s\n",
+ gerror->message);
+ g_error_free(gerror);
+ return 0;
+ }
+
+ return 1;
+ } else {
+ /* Since we can't detect when the bookmark window
+ closes, we'd have a corner case where, if the user
+ just closes the bookmark window without opening any
+ browser windows, we don't kill off MicroB or resume
+ handling com.nokia.osso_browser */
+ uri = "about:blank";
+ }
+ }
+ if (!dbus_g_proxy_call(g_proxy, "load_url",
+ &gerror,
+ G_TYPE_STRING, uri,
+ G_TYPE_INVALID,
+ G_TYPE_INVALID)) {
+ log_msg("Opening window failed: %s\n", gerror->message);
+ g_error_free(gerror);
+ return 0;
+ }
+
+ g_object_unref(g_proxy);
+ return 1;
+}
+
+/* Launch Fremantle MicroB and kill it when the session is finished */
+void launch_microb_fremantle_with_kill(struct swb_context *ctx, char *uri) {
int status;
pid_t pid;
-#ifdef FREMANTLE
char *homedir, *microb_profile_dir, *microb_lockfile;
size_t len;
int fd, inot_wd;
DBusConnection *raw_connection;
- DBusError dbus_error;
- DBusHandleMessageFunction filter_func;
- DBusGProxy *g_proxy;
- GError *gerror = NULL;
int bytes_read;
char buf[256], *pos;
struct inotify_event *event;
pid_t browserd_pid, waited_pid;
struct sigaction act, oldact;
int ignore_sigstop;
-#endif
-
- if (!uri)
- uri = "new_window";
- log_msg("launch_microb with uri '%s'\n", uri);
-
- /* Launch browserd if it's not running */
- status = system("pidof browserd > /dev/null");
- if (WIFEXITED(status) && WEXITSTATUS(status)) {
- kill_browserd = 1;
-#ifdef FREMANTLE
- system("/usr/sbin/browserd -d -b > /dev/null 2>&1");
-#else
- system("/usr/sbin/browserd -d > /dev/null 2>&1");
-#endif
- }
-
- /* Release the osso_browser D-Bus name so that MicroB can take it */
- dbus_release_osso_browser_name(ctx);
-
-#ifdef FREMANTLE
/* Put together the path to the MicroB browserd lockfile */
if (!(homedir = getenv("HOME")))
homedir = DEFAULT_HOMEDIR;
/* Set up the D-Bus eavesdropping we'll use to watch for MicroB
acquiring the com.nokia.osso_browser D-Bus name. Again, this needs
to happen before the browser is launched, so that there's no race
- between establishing the watch and browser startup.
-
- Ideas for how to do this monitoring derived from the dbus-monitor
- code (tools/dbus-monitor.c in the D-Bus codebase). */
- dbus_error_init(&dbus_error);
-
- raw_connection = dbus_bus_get_private(DBUS_BUS_SESSION, &dbus_error);
- if (!raw_connection) {
- log_msg("Failed to open connection to session bus: %s\n",
- dbus_error.message);
- dbus_error_free(&dbus_error);
+ between establishing the watch and browser startup. */
+ if (!(raw_connection = microb_start_dbus_watch_init())) {
exit(1);
}
- dbus_bus_add_match(raw_connection,
- "type='signal',interface='org.freedesktop.DBus',member='NameOwnerChanged',arg0='com.nokia.osso_browser'",
- &dbus_error);
- if (dbus_error_is_set(&dbus_error)) {
- log_msg("Failed to set up watch for browser UI start: %s\n",
- dbus_error.message);
- dbus_error_free(&dbus_error);
+ /* Launch a MicroB browser process if it's not already running */
+ if ((pid = launch_microb_start_browser_process(raw_connection, fd)) < 0)
exit(1);
- }
- filter_func = check_microb_started;
- if (!dbus_connection_add_filter(raw_connection,
- filter_func, NULL, NULL)) {
- log_msg("Failed to set up watch filter!\n");
- exit(1);
- }
- if ((pid = fork()) == -1) {
- log_perror(errno, "fork");
+ /* Release the osso_browser D-Bus name so that MicroB can take it */
+ dbus_release_osso_browser_name(ctx);
+
+ /* Wait for our child to start the browser UI process and
+ for it to acquire the com.nokia.osso_browser D-Bus name,
+ then make the appropriate method call to open the browser
+ window. */
+ microb_start_dbus_watch_wait(raw_connection);
+ microb_start_dbus_watch_remove(raw_connection);
+ if (!launch_microb_open_window(ctx, uri, 0)) {
exit(1);
}
- if (pid > 0) {
- /* Parent process */
- /* Wait for our child to start the browser UI process and
- for it to acquire the com.nokia.osso_browser D-Bus name,
- then make the appropriate method call to open the browser
- window. */
- microb_started = 0;
- log_msg("Waiting for MicroB to start\n");
- while (!microb_started &&
- dbus_connection_read_write_dispatch(raw_connection,
- -1));
- dbus_connection_remove_filter(raw_connection,
- filter_func, NULL);
- dbus_bus_remove_match(raw_connection,
- "type='signal',interface='org.freedesktop.DBus',member='NameOwnerChanged',arg0='com.nokia.osso_browser'",
- &dbus_error);
- if (dbus_error_is_set(&dbus_error))
- /* Don't really care -- about to disconnect from the
- bus anyhow */
- dbus_error_free(&dbus_error);
- dbus_connection_close(raw_connection);
- dbus_connection_unref(raw_connection);
-
- /* Browser UI's started, send it the request for a new window
- via D-Bus */
- g_proxy = dbus_g_proxy_new_for_name(ctx->session_bus,
- "com.nokia.osso_browser",
- "/com/nokia/osso_browser/request",
- "com.nokia.osso_browser");
- if (!g_proxy) {
- log_msg("Couldn't get a com.nokia.osso_browser proxy\n");
- exit(1);
- }
- if (!strcmp(uri, "new_window")) {
-#if 0 /* Since we can't detect when the bookmark window closes, we'd have a
- corner case where, if the user just closes the bookmark window
- without opening any browser windows, we don't kill off MicroB or
- resume handling com.nokia.osso_browser */
- if (!dbus_g_proxy_call(g_proxy, "top_application",
- &gerror, G_TYPE_INVALID,
- G_TYPE_INVALID)) {
- log_msg("Opening window failed: %s\n",
- gerror->message);
- exit(1);
- }
-#endif
- if (!dbus_g_proxy_call(g_proxy, "load_url",
- &gerror,
- G_TYPE_STRING, "about:blank",
- G_TYPE_INVALID,
- G_TYPE_INVALID)) {
- log_msg("Opening window failed: %s\n",
- gerror->message);
- exit(1);
- }
- } else {
- if (!dbus_g_proxy_call(g_proxy, "load_url",
- &gerror,
- G_TYPE_STRING, uri,
- G_TYPE_INVALID,
- G_TYPE_INVALID)) {
- log_msg("Opening window failed: %s\n",
- gerror->message);
- exit(1);
- }
- }
- g_object_unref(g_proxy);
-
- /* Workaround: the browser process we started is going to want
- to hang around forever, hogging the com.nokia.osso_browser
- D-Bus interface while at it. To fix this, we notice that
- when the last browser window closes, the browser UI restarts
- its attached browserd process. Get the browserd process's
- PID and use ptrace() to watch for process termination.
-
- This has the problem of not being able to detect whether
- the bookmark window is open and/or in use, but it's the best
- that I can think of. Better suggestions would be greatly
- appreciated. */
-
- /* Wait for the MicroB browserd lockfile to be created */
+ /* Workaround: the browser process we started is going to want
+ to hang around forever, hogging the com.nokia.osso_browser
+ D-Bus interface while at it. To fix this, we notice that
+ when the last browser window closes, the browser UI restarts
+ its attached browserd process. Get the browserd process's
+ PID and use ptrace() to watch for process termination.
+
+ This has the problem of not being able to detect whether
+ the bookmark window is open and/or in use, but it's the best
+ that I can think of. Better suggestions would be greatly
+ appreciated. */
+
+ if (!pid)
+ /* If we didn't start the MicroB browser process ourselves, try
+ to get the PID of the browserd from the lockfile */
+ browserd_pid = get_browserd_pid(microb_lockfile);
+ else
+ browserd_pid = 0;
+
+ /* If getting the lockfile PID failed, or the lockfile PID doesn't
+ exist, assume that we have a stale lockfile and wait for the new
+ browserd lockfile to be created */
+ if (browserd_pid <= 0 || kill(browserd_pid, 0) == ESRCH) {
log_msg("Waiting for browserd lockfile to be created\n");
memset(buf, '\0', 256);
/* read() blocks until there are events to be read */
or until all the events are processed */
while (pos && (pos-buf) < bytes_read) {
event = (struct inotify_event *)pos;
- len = sizeof(struct inotify_event)
- + event->len;
- if (!strcmp(MICROB_LOCKFILE,
- event->name)) {
+ len = sizeof(struct inotify_event) + event->len;
+ if (!strcmp(MICROB_LOCKFILE, event->name)) {
/* Lockfile created */
pos = NULL;
break;
break;
memset(buf, '\0', 256);
}
- inotify_rm_watch(fd, inot_wd);
- close(fd);
- /* Get the PID of the browserd from the lockfile */
if ((browserd_pid = get_browserd_pid(microb_lockfile)) <= 0) {
if (browserd_pid == 0)
log_msg("Profile lockfile link lacks PID\n");
"readlink() on lockfile failed");
exit(1);
}
- free(microb_lockfile);
-
- /* Wait for the browserd to close */
- log_msg("Waiting for MicroB (browserd pid %d) to finish\n",
- browserd_pid);
- /* Clear any existing SIGCHLD handler to prevent interference
- with our wait() */
- act.sa_handler = SIG_DFL;
- act.sa_flags = 0;
- sigemptyset(&(act.sa_mask));
- if (sigaction(SIGCHLD, &act, &oldact) == -1) {
- log_perror(errno, "clearing SIGCHLD handler failed");
- exit(1);
- }
+ }
+ inotify_rm_watch(fd, inot_wd);
+ close(fd);
+ free(microb_lockfile);
+
+ /* Wait for the browserd to close */
+ log_msg("Waiting for MicroB (browserd pid %d) to finish\n",
+ browserd_pid);
+ /* Clear any existing SIGCHLD handler to prevent interference
+ with our wait() */
+ act.sa_handler = SIG_DFL;
+ act.sa_flags = 0;
+ sigemptyset(&(act.sa_mask));
+ if (sigaction(SIGCHLD, &act, &oldact) == -1) {
+ log_perror(errno, "clearing SIGCHLD handler failed");
+ exit(1);
+ }
- /* Trace the browserd to get a close notification */
- ignore_sigstop = 1;
- if (ptrace(PTRACE_ATTACH, browserd_pid, NULL, NULL) == -1) {
- log_perror(errno, "PTRACE_ATTACH");
- exit(1);
- }
- ptrace(PTRACE_CONT, browserd_pid, NULL, NULL);
- while ((waited_pid = wait(&status)) > 0) {
- if (waited_pid != browserd_pid)
- /* Not interested in other processes */
+ /* Trace the browserd to get a close notification */
+ ignore_sigstop = 1;
+ if (ptrace(PTRACE_ATTACH, browserd_pid, NULL, NULL) == -1) {
+ log_perror(errno, "PTRACE_ATTACH");
+ exit(1);
+ }
+ ptrace(PTRACE_CONT, browserd_pid, NULL, NULL);
+ while ((waited_pid = wait(&status)) > 0) {
+ if (waited_pid != browserd_pid)
+ /* Not interested in other processes */
+ continue;
+ if (WIFEXITED(status) || WIFSIGNALED(status))
+ /* browserd exited */
+ break;
+ else if (WIFSTOPPED(status)) {
+ /* browserd was sent a signal
+ We're responsible for making sure this signal gets
+ delivered */
+ if (ignore_sigstop && WSTOPSIG(status) == SIGSTOP) {
+ /* Ignore the first SIGSTOP received
+ This is raised for some reason immediately
+ after we start tracing the process, and
+ won't be followed by a SIGCONT at any point
+ */
+ log_msg("Ignoring first SIGSTOP\n");
+ ptrace(PTRACE_CONT, browserd_pid, NULL, NULL);
+ ignore_sigstop = 0;
continue;
- if (WIFEXITED(status) || WIFSIGNALED(status))
- /* browserd exited */
- break;
- else if (WIFSTOPPED(status)) {
- /* browserd was sent a signal
- We're responsible for making sure this
- signal gets delivered */
- if (ignore_sigstop &&
- WSTOPSIG(status) == SIGSTOP) {
- /* Ignore the first SIGSTOP received
- This is raised for some reason
- immediately after we start tracing
- the process, and won't be followed
- by a SIGCONT at any point */
- log_msg("Ignoring first SIGSTOP\n");
- ptrace(PTRACE_CONT, browserd_pid,
- NULL, NULL);
- ignore_sigstop = 0;
- continue;
- }
- log_msg("Forwarding signal %d to browserd\n",
- WSTOPSIG(status));
- ptrace(PTRACE_CONT, browserd_pid,
- NULL, WSTOPSIG(status));
}
+ log_msg("Forwarding signal %d to browserd\n",
+ WSTOPSIG(status));
+ ptrace(PTRACE_CONT, browserd_pid, NULL,
+ WSTOPSIG(status));
}
+ }
- /* Kill off browser UI
- XXX: There is a race here with the restarting of the closed
- browserd; if that happens before we kill the browser UI, the
- newly started browserd may not close with the UI
- XXX: Hope we don't cause data loss here! */
- log_msg("Killing MicroB\n");
+ /* Kill off browser UI
+ XXX: There is a race here with the restarting of the closed
+ browserd; if that happens before we kill the browser UI, the newly
+ started browserd may not close with the UI
+ XXX: Hope we don't cause data loss here! */
+ log_msg("Killing MicroB\n");
+ if (pid > 0) {
kill(pid, SIGTERM);
waitpid(pid, &status, 0);
-
- /* Restore old SIGCHLD handler */
- if (sigaction(SIGCHLD, &oldact, NULL) == -1) {
- log_perror(errno,
- "restoring old SIGCHLD handler failed");
- exit(1);
- }
} else {
- /* Child process */
- dbus_connection_close(raw_connection);
- dbus_connection_unref(raw_connection);
- close(fd);
- close_stdio();
+ system("kill `pidof browser` > /dev/null 2>&1");
+ }
- /* exec maemo-invoker directly instead of relying on the
- /usr/bin/browser symlink, since /usr/bin/browser may have
- been replaced with a shell script calling us via D-Bus */
- /* Launch the browser in the background -- our parent will
- wait for it to claim the D-Bus name and then display the
- window using D-Bus */
- execl("/usr/bin/maemo-invoker", "browser", (char *)NULL);
+ /* Restore old SIGCHLD handler */
+ if (sigaction(SIGCHLD, &oldact, NULL) == -1) {
+ log_perror(errno, "restoring old SIGCHLD handler failed");
+ exit(1);
+ }
+
+ dbus_request_osso_browser_name(ctx);
+}
+
+/* Launch a new window in Fremantle MicroB; don't kill the MicroB process
+ when the session is finished
+ This is designed to work with a prestarted MicroB process that runs
+ continuously in the background */
+void launch_microb_fremantle(struct swb_context *ctx, char *uri) {
+ DBusConnection *raw_connection;
+
+ /* Set up the D-Bus eavesdropping we'll use to watch for MicroB
+ acquiring the com.nokia.osso_browser D-Bus name */
+ if (!(raw_connection = microb_start_dbus_watch_init())) {
+ exit(1);
+ }
+
+ /* Launch a MicroB browser process if it's not already running */
+ if (launch_microb_start_browser_process(raw_connection, -1) < 0)
+ exit(1);
+
+ /* Release the osso_browser D-Bus name so that MicroB can take it */
+ dbus_release_osso_browser_name(ctx);
+
+ /* Wait for MicroB to acquire com.nokia.osso_browser, then make the
+ appropriate method call to open the browser window. */
+ microb_start_dbus_watch_wait(raw_connection);
+ microb_start_dbus_watch_remove(raw_connection);
+ if (!launch_microb_open_window(ctx, uri,
+ LAUNCH_MICROB_BOOKMARK_WIN_OK)) {
+ exit(1);
+ }
+
+ /* Take back the osso_browser D-Bus name from MicroB */
+ dbus_request_osso_browser_name(ctx);
+}
+#endif /* FREMANTLE */
+
+void launch_microb(struct swb_context *ctx, char *uri) {
+ int kill_browserd = 0;
+ int status;
+#ifndef FREMANTLE
+ pid_t pid;
+#endif
+
+ if (!uri)
+ uri = "new_window";
+
+ log_msg("launch_microb with uri '%s'\n", uri);
+
+ /* Launch browserd if it's not running */
+ status = system("pidof browserd > /dev/null");
+ if (WIFEXITED(status) && WEXITSTATUS(status)) {
+ kill_browserd = 1;
+#ifdef FREMANTLE
+ system("/usr/sbin/browserd -d -b > /dev/null 2>&1");
+#else
+ system("/usr/sbin/browserd -d > /dev/null 2>&1");
+#endif
+ }
+
+#ifdef FREMANTLE
+ /* Do the insanity to launch Fremantle MicroB */
+ if ((ctx->default_browser_launcher == launch_microb &&
+ ctx->autostart_microb) || ctx->autostart_microb == 1) {
+
+ /* If MicroB is set as the default browser, or if the user has
+ configured MicroB to always be running, just send the
+ running MicroB the request */
+ launch_microb_fremantle(ctx, uri);
+ } else {
+ /* Otherwise, launch MicroB and kill it when the user's
+ MicroB session is done */
+ launch_microb_fremantle_with_kill(ctx, uri);
}
#else /* !FREMANTLE */
+ /* Release the osso_browser D-Bus name so that MicroB can take it */
+ dbus_release_osso_browser_name(ctx);
+
if ((pid = fork()) == -1) {
log_perror(errno, "fork");
exit(1);
"browser", "--url", uri, (char *)NULL);
}
}
+
+ dbus_request_osso_browser_name(ctx);
#endif /* FREMANTLE */
/* Kill off browserd if we started it */
if (kill_browserd)
system("kill `pidof browserd`");
- if (!ctx || !ctx->continuous_mode)
+ if (!ctx || !ctx->continuous_mode)
exit(0);
-
- dbus_request_osso_browser_name(ctx);
}
static void launch_other_browser(struct swb_context *ctx, char *uri) {
/* Parent process or error in fork() */
if (urilen > 0)
free(quoted_uri);
- free(command);
+ free(command);
return;
}
/* Child process */
swb_config_load(&cfg);
log_config(cfg.logging);
+#ifdef FREMANTLE
+ /* continuous mode is required on Fremantle */
+ ctx.continuous_mode = 1;
+ if (!cfg.continuous_mode)
+ log_msg("continuous_mode = 0 operation no longer supported, ignoring config setting\n");
+#else
ctx.continuous_mode = cfg.continuous_mode;
+#endif
free(ctx.other_browser_cmd);
if (cfg.other_browser_cmd) {
if (!(ctx.other_browser_cmd = strdup(cfg.other_browser_cmd))) {
} else
ctx.other_browser_cmd = NULL;
update_default_browser(&ctx, cfg.default_browser);
+#ifdef FREMANTLE
+ ctx.autostart_microb = cfg.autostart_microb;
+#endif
log_msg("continuous_mode: %d\n", cfg.continuous_mode);
log_msg("default_browser: '%s'\n", cfg.default_browser);
int main() {
OssoBrowser *obj_osso_browser, *obj_osso_browser_req;
+ OssoBrowser *obj_osso_browser_sys, *obj_osso_browser_sys_req;
GMainLoop *mainloop;
GError *error = NULL;
int reqname_result;
error->message);
return 1;
}
- if (reqname_result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
+ if (reqname_result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
log_msg("Another browser-switchboard already running\n");
return 1;
}
+ /* Get a connection to the D-Bus system bus */
+ ctx.system_bus = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error);
+ if (!ctx.system_bus) {
+ log_msg("Couldn't get a D-Bus system bus connection\n");
+ return 1;
+ }
+ ctx.dbus_system_proxy = dbus_g_proxy_new_for_name(ctx.system_bus,
+ "org.freedesktop.DBus", "/org/freedesktop/DBus",
+ "org.freedesktop.DBus");
+ if (!ctx.dbus_system_proxy) {
+ log_msg("Couldn't get an org.freedesktop.DBus proxy\n");
+ return 1;
+ }
+
dbus_request_osso_browser_name(&ctx);
/* Register ourselves to handle the osso_browser D-Bus methods */
obj_osso_browser = g_object_new(OSSO_BROWSER_TYPE, NULL);
obj_osso_browser_req = g_object_new(OSSO_BROWSER_TYPE, NULL);
+ obj_osso_browser_sys = g_object_new(OSSO_BROWSER_TYPE, NULL);
+ obj_osso_browser_sys_req = g_object_new(OSSO_BROWSER_TYPE, NULL);
dbus_g_connection_register_g_object(ctx.session_bus,
"/com/nokia/osso_browser", G_OBJECT(obj_osso_browser));
dbus_g_connection_register_g_object(ctx.session_bus,
"/com/nokia/osso_browser/request",
G_OBJECT(obj_osso_browser_req));
+ dbus_g_connection_register_g_object(ctx.system_bus,
+ "/com/nokia/osso_browser",
+ G_OBJECT(obj_osso_browser_sys));
+ dbus_g_connection_register_g_object(ctx.system_bus,
+ "/com/nokia/osso_browser/request",
+ G_OBJECT(obj_osso_browser_sys_req));
mainloop = g_main_loop_new(NULL, FALSE);
log_msg("Starting main loop\n");
#!/bin/sh
+get_name_owner() {
+ output=$(dbus-send --session --type=method_call --print-reply --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.GetNameOwner string:"$1" 2>/dev/null)
+ RETVAL=$?
+ if [ $RETVAL -ne 0 ]; then
+ return $RETVAL
+ fi
+ echo "$output" | tail -1
+ return 0
+}
+
case "$1" in
--url=* )
url="${1#--url=}"
;;
esac
-if pidof browser > /dev/null 2>&1; then
- method=open_new_window
-else
+# Check whether Browser Switchboard owns the com.nokia.osso_browser name or not
+osso_browser_owner=$(get_name_owner com.nokia.osso_browser)
+if [ $? -ne 0 ]; then
+ # No one owns com.nokia.osso_browser -- let D-Bus start
+ # browser-switchboard to handle this request
method=switchboard_launch_microb
+else
+ # If com.nokia.osso_browser is owned by the owner of
+ # org.maemo.garage.browser-switchboard, then Browser Switchboard must
+ # be the owner
+ browser_switchboard_owner=$(get_name_owner org.maemo.garage.browser-switchboard)
+ if [ "$osso_browser_owner" = "$browser_switchboard_owner" ]; then
+ # Browser Switchboard owns com.nokia.osso_browser
+ method=switchboard_launch_microb
+ else
+ # Assume MicroB owns com.nokia.osso_browser
+ method=open_new_window
+ fi
fi
dbus-send --session --type=method_call --print-reply --dest="com.nokia.osso_browser" /com/nokia/osso_browser/request com.nokia.osso_browser.$method string:${url:-"new_window"} > /dev/null 2>&1
--- /dev/null
+#!/bin/sh
+
+# start Browser Switchboard, then start MicroB if appropriate
+/usr/bin/browser-switchboard > /dev/null 2>&1 &
+
+if ! /bin/pidof browser > /dev/null 2>&1; then
+ DEFAULT_BROWSER=`/usr/bin/browser-switchboard-config -b`
+ AUTOSTART_MICROB=`/usr/bin/browser-switchboard-config -o autostart_microb`
+ if [ "$AUTOSTART_MICROB" -eq 1 ] || [ "$DEFAULT_BROWSER" = "microb" -a "$AUTOSTART_MICROB" -ne 0 ]; then
+ /usr/bin/maemo-invoker /usr/bin/browser.launch > /dev/null 2>&1 &
+ fi
+fi