aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/ephy-tab.c59
-rw-r--r--src/ephy-tab.h3
-rw-r--r--src/ephy-tabs-menu.c96
3 files changed, 89 insertions, 69 deletions
diff --git a/src/ephy-tab.c b/src/ephy-tab.c
index 893472ad6..2df157c0c 100644
--- a/src/ephy-tab.c
+++ b/src/ephy-tab.c
@@ -74,8 +74,6 @@
struct _EphyTabPrivate
{
- guint id;
-
int width;
int height;
guint idle_resize_handler;
@@ -93,14 +91,6 @@ enum
static GObjectClass *parent_class;
-/* We need to assign unique IDs to tabs, otherwise accels get confused in the
- * tabs menu (bug #339548). We could use a serial #, but the ID is used in the
- * action name which is stored in a GQuark and so we should use them sparingly.
- */
-
-static GArray *tabs_id_array = NULL;
-static guint n_tabs = 0;
-
/* Class functions */
GType
@@ -250,8 +240,6 @@ static void
ephy_tab_finalize (GObject *object)
{
EphyTab *tab = EPHY_TAB (object);
- EphyTabPrivate *priv = tab->priv;
- guint id = priv->id;
G_OBJECT_CLASS (parent_class)->finalize (object);
@@ -260,14 +248,6 @@ ephy_tab_finalize (GObject *object)
#endif
LOG ("EphyTab finalized %p", tab);
-
- /* Remove the ID */
- g_array_index (tabs_id_array, gpointer, id) = NULL;
- if (--n_tabs == 0)
- {
- g_array_free (tabs_id_array, TRUE);
- tabs_id_array = NULL;
- }
}
static gboolean
@@ -601,41 +581,11 @@ ephy_tab_init (EphyTab *tab)
{
EphyTabPrivate *priv;
GObject *embed;
- guint id;
LOG ("EphyTab initialising %p", tab);
priv = tab->priv = EPHY_TAB_GET_PRIVATE (tab);
- /* Make tab ID */
- ++n_tabs;
-
- if (tabs_id_array == NULL)
- {
- tabs_id_array = g_array_sized_new (FALSE /* zero-terminate */,
- TRUE /* clear */,
- sizeof (gpointer),
- 64 /* initial size */);
- }
-
- for (id = 0; id < tabs_id_array->len; ++id)
- {
- if (g_array_index (tabs_id_array, gpointer, id) == NULL) break;
- }
-
- priv->id = id;
-
- /* Grow array if necessary */
- if (id >= tabs_id_array->len)
- {
- g_array_append_val (tabs_id_array, tab);
- g_assert (g_array_index (tabs_id_array, gpointer, id) == tab);
- }
- else
- {
- g_array_index (tabs_id_array, gpointer, id) = tab;
- }
-
tab->priv->width = -1;
tab->priv->height = -1;
@@ -649,12 +599,3 @@ ephy_tab_init (EphyTab *tab)
G_CALLBACK (ephy_tab_dom_mouse_click_cb),
tab, 0);
}
-
-/* private */
-guint
-_ephy_tab_get_id (EphyTab *tab)
-{
- g_return_val_if_fail (EPHY_IS_TAB (tab), (guint) -1);
-
- return tab->priv->id;
-}
diff --git a/src/ephy-tab.h b/src/ephy-tab.h
index 46ed4c6e6..e2f042b07 100644
--- a/src/ephy-tab.h
+++ b/src/ephy-tab.h
@@ -68,9 +68,6 @@ void ephy_tab_set_size (EphyTab *tab,
int width,
int height);
-/* private */
-guint _ephy_tab_get_id (EphyTab *tab);
-
G_END_DECLS
#endif
diff --git a/src/ephy-tabs-menu.c b/src/ephy-tabs-menu.c
index f9887d850..6fcf11c5b 100644
--- a/src/ephy-tabs-menu.c
+++ b/src/ephy-tabs-menu.c
@@ -41,8 +41,11 @@
#include <libxml/entities.h>
#define LABEL_WIDTH_CHARS 32
-#define ACTION_VERB_FORMAT "JmpTab%x"
+#define ACTION_VERB_FORMAT_PREFIX "JmpTab"
+#define ACTION_VERB_FORMAT_PREFIX_LEN (6) /* strlen (ACTION_VERB_FORMAT_PREFIX) */
+#define ACTION_VERB_FORMAT ACTION_VERB_FORMAT_PREFIX "%x"
#define ACTION_VERB_FORMAT_LENGTH strlen (ACTION_VERB_FORMAT) + 14 + 1
+#define ACTION_VERB_FORMAT_BASE (16) /* %x is hex */
#define ACCEL_PATH_FORMAT "<Actions>/TabsActions/%s"
#define ACCEL_PATH_FORMAT_LENGTH strlen (ACCEL_PATH_FORMAT) -2 + ACTION_VERB_FORMAT_LENGTH
#define DATA_KEY "EphyTabsMenu::Action"
@@ -67,8 +70,88 @@ static void ephy_tabs_menu_class_init (EphyTabsMenuClass *klass);
static void ephy_tabs_menu_init (EphyTabsMenu *menu);
static void ephy_tabs_menu_update (EphyTabsMenu *menu);
+/* FIXME: this can be severely optimised */
+static GByteArray *tabs_id_array = NULL;
+static guint n_tabs = 0;
+
G_DEFINE_TYPE (EphyTabsMenu, ephy_tabs_menu, G_TYPE_OBJECT)
+/* We need to assign unique IDs to tabs, otherwise accels get confused in the
+ * tabs menu (bug #339548). We could use a serial #, but the ID is used in the
+ * action name which is stored in a GQuark and so we should allocate them
+ * efficiently.
+ */
+static guint
+allocate_tab_id (void)
+{
+ int bit;
+ guint b, len;
+ guint8 *data;
+ guint8 byte, mask;
+
+ if (n_tabs++ == 0)
+ {
+ g_assert (tabs_id_array == NULL);
+ tabs_id_array = g_byte_array_sized_new (16);
+ }
+
+ /* Find a free ID */
+ len = tabs_id_array->len;
+ data = tabs_id_array->data;
+ for (b = 0; b < len; ++b)
+ {
+ if (data[b] != 0xff)
+ break;
+ }
+
+ /* Need to append a new byte */
+ if (b == len)
+ {
+ guint8 bytes[] = { 0 };
+ g_byte_array_append (tabs_id_array, bytes, G_N_ELEMENTS (bytes));
+ g_assert (tabs_id_array->len > b);
+ }
+
+ data = tabs_id_array->data + b;
+ byte = 0xff ^ *data;
+ /* Now find the first free bit */
+ bit = g_bit_nth_lsf (byte, -1);
+ mask = 1 << bit;
+ g_assert (bit >= 0 && bit <= 7);
+ g_assert ((*data & mask) == 0);
+ /* And mark it as allocated */
+ *data |= mask;
+
+ return b * 8 + bit;
+}
+
+static void
+free_tab_id (GtkAction *action)
+{
+ const char *name;
+ guint id;
+ guint8 *data;
+ guint b, bit;
+
+ name = gtk_action_get_name (action);
+ id = g_ascii_strtoull (name + ACTION_VERB_FORMAT_PREFIX_LEN, NULL,
+ ACTION_VERB_FORMAT_BASE);
+ g_assert (id >= 0 && id < tabs_id_array->len * 8);
+
+ b = id >> 3;
+ bit = id & 0x7;
+ data = tabs_id_array->data + b;
+ *data &= ~(1 << bit);
+
+ g_assert (n_tabs > 0);
+ if (--n_tabs == 0)
+ {
+ g_assert (tabs_id_array != NULL);
+ g_byte_array_free (tabs_id_array, TRUE);
+ tabs_id_array = NULL;
+ }
+}
+
static void
tab_action_activate_cb (GtkToggleAction *action,
EphyTabsMenu *menu)
@@ -117,8 +200,7 @@ notebook_page_added_cb (EphyNotebook *notebook,
LOG ("tab_added_cb tab=%p", tab);
- g_snprintf (verb, sizeof (verb), ACTION_VERB_FORMAT,
- _ephy_tab_get_id (tab));
+ g_snprintf (verb, sizeof (verb), ACTION_VERB_FORMAT, allocate_tab_id ());
action = g_object_new (GTK_TYPE_RADIO_ACTION,
"name", verb,
@@ -166,6 +248,8 @@ notebook_page_removed_cb (EphyNotebook *notebook,
action = g_object_get_data (G_OBJECT (tab), DATA_KEY);
g_return_if_fail (action != NULL);
+ free_tab_id (action);
+
g_signal_handlers_disconnect_by_func
(tab, G_CALLBACK (sync_tab_title), action);
@@ -301,11 +385,9 @@ ephy_tabs_menu_class_init (EphyTabsMenuClass *klass)
g_object_class_install_property (object_class,
PROP_WINDOW,
- g_param_spec_object ("window",
- "Window",
- "Parent window",
+ g_param_spec_object ("window", NULL, NULL,
EPHY_TYPE_WINDOW,
- G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB |
+ G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB |
G_PARAM_CONSTRUCT_ONLY));
g_type_class_add_private (object_class, sizeof (EphyTabsMenuPrivate));