diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/ephy-tab.c | 59 | ||||
-rw-r--r-- | src/ephy-tab.h | 3 | ||||
-rw-r--r-- | src/ephy-tabs-menu.c | 96 |
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)); |