1/* 2 * Copyright (C) 2011 Igalia S.L. 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Library General Public 6 * License as published by the Free Software Foundation; either 7 * version 2 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Library General Public License for more details. 13 * 14 * You should have received a copy of the GNU Library General Public License 15 * along with this library; see the file COPYING.LIB. If not, write to 16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 * Boston, MA 02110-1301, USA. 18 */ 19 20#include "config.h" 21#include "WebKitBackForwardList.h" 22 23#include "WebKitBackForwardListPrivate.h" 24#include "WebKitMarshal.h" 25#include "WebKitPrivate.h" 26#include <wtf/gobject/GRefPtr.h> 27 28/** 29 * SECTION: WebKitBackForwardList 30 * @Short_description: List of visited pages 31 * @Title: WebKitBackForwardList 32 * @See_also: #WebKitWebView, #WebKitBackForwardListItem 33 * 34 * WebKitBackForwardList maintains a list of visited pages used to 35 * navigate to recent pages. Items are inserted in the list in the 36 * order they are visited. 37 * 38 * WebKitBackForwardList also maintains the notion of the current item 39 * (which is always at index 0), the preceding item (which is at index -1), 40 * and the following item (which is at index 1). 41 * Methods webkit_web_view_go_back() and webkit_web_view_go_forward() move 42 * the current item backward or forward by one. Method 43 * webkit_web_view_go_to_back_forward_list_item() sets the current item to the 44 * specified item. All other methods returning #WebKitBackForwardListItem<!-- -->s 45 * do not change the value of the current item, they just return the requested 46 * item or items. 47 */ 48 49using namespace WebKit; 50 51enum { 52 CHANGED, 53 54 LAST_SIGNAL 55}; 56 57typedef HashMap<WebBackForwardListItem*, GRefPtr<WebKitBackForwardListItem> > BackForwardListItemsMap; 58 59struct _WebKitBackForwardListPrivate { 60 WebBackForwardList* backForwardItems; 61 BackForwardListItemsMap itemsMap; 62}; 63 64static guint signals[LAST_SIGNAL] = { 0, }; 65 66WEBKIT_DEFINE_TYPE(WebKitBackForwardList, webkit_back_forward_list, G_TYPE_OBJECT) 67 68static void webkit_back_forward_list_class_init(WebKitBackForwardListClass* listClass) 69{ 70 /** 71 * WebKitBackForwardList::changed: 72 * @back_forward_list: the #WebKitBackForwardList on which the signal was emitted 73 * @item_added: (allow-none): the #WebKitBackForwardListItem added or %NULL 74 * @items_removed: a #GList of #WebKitBackForwardListItem<!-- -->s 75 * 76 * This signal is emitted when @back_forward_list changes. This happens 77 * when the current item is updated, a new item is added or one or more 78 * items are removed. Note that both @item_added and @items_removed can 79 * %NULL when only the current item is updated. Items are only removed 80 * when the list is cleared or the maximum items limit is reached. 81 */ 82 signals[CHANGED] = 83 g_signal_new("changed", 84 G_TYPE_FROM_CLASS(listClass), 85 G_SIGNAL_RUN_LAST, 86 0, 0, 0, 87 webkit_marshal_VOID__OBJECT_POINTER, 88 G_TYPE_NONE, 2, 89 WEBKIT_TYPE_BACK_FORWARD_LIST_ITEM, 90 G_TYPE_POINTER); 91} 92 93static WebKitBackForwardListItem* webkitBackForwardListGetOrCreateItem(WebKitBackForwardList* list, WebBackForwardListItem* webListItem) 94{ 95 if (!webListItem) 96 return 0; 97 98 WebKitBackForwardListPrivate* priv = list->priv; 99 GRefPtr<WebKitBackForwardListItem> listItem = priv->itemsMap.get(webListItem); 100 if (listItem) 101 return listItem.get(); 102 103 listItem = webkitBackForwardListItemGetOrCreate(webListItem); 104 priv->itemsMap.set(webListItem, listItem); 105 106 return listItem.get(); 107} 108 109static GList* webkitBackForwardListCreateList(WebKitBackForwardList* list, ImmutableArray* backForwardItems) 110{ 111 if (!backForwardItems) 112 return 0; 113 114 GList* returnValue = 0; 115 for (size_t i = 0; i < backForwardItems->size(); ++i) { 116 WebBackForwardListItem* webItem = static_cast<WebBackForwardListItem*>(backForwardItems->at(i)); 117 returnValue = g_list_prepend(returnValue, webkitBackForwardListGetOrCreateItem(list, webItem)); 118 } 119 120 return returnValue; 121} 122 123WebKitBackForwardList* webkitBackForwardListCreate(WebBackForwardList* backForwardItems) 124{ 125 WebKitBackForwardList* list = WEBKIT_BACK_FORWARD_LIST(g_object_new(WEBKIT_TYPE_BACK_FORWARD_LIST, NULL)); 126 list->priv->backForwardItems = backForwardItems; 127 128 return list; 129} 130 131void webkitBackForwardListChanged(WebKitBackForwardList* backForwardList, WebBackForwardListItem* webAddedItem, ImmutableArray* webRemovedItems) 132{ 133 WebKitBackForwardListItem* addedItem = webkitBackForwardListGetOrCreateItem(backForwardList, webAddedItem); 134 GList* removedItems = 0; 135 136 size_t removedItemsSize = webRemovedItems ? webRemovedItems->size() : 0; 137 WebKitBackForwardListPrivate* priv = backForwardList->priv; 138 for (size_t i = 0; i < removedItemsSize; ++i) { 139 WebBackForwardListItem* webItem = static_cast<WebBackForwardListItem*>(webRemovedItems->at(i)); 140 removedItems = g_list_prepend(removedItems, g_object_ref(G_OBJECT(priv->itemsMap.get(webItem).get()))); 141 priv->itemsMap.remove(webItem); 142 } 143 144 g_signal_emit(backForwardList, signals[CHANGED], 0, addedItem, removedItems, NULL); 145 g_list_free_full(removedItems, static_cast<GDestroyNotify>(g_object_unref)); 146} 147 148/** 149 * webkit_back_forward_list_get_current_item: 150 * @back_forward_list: a #WebKitBackForwardList 151 * 152 * Returns the current item in @back_forward_list. 153 * 154 * Returns: (transfer none): a #WebKitBackForwardListItem 155 * or %NULL if @back_forward_list is empty. 156 */ 157WebKitBackForwardListItem* webkit_back_forward_list_get_current_item(WebKitBackForwardList* backForwardList) 158{ 159 g_return_val_if_fail(WEBKIT_IS_BACK_FORWARD_LIST(backForwardList), 0); 160 161 return webkitBackForwardListGetOrCreateItem(backForwardList, backForwardList->priv->backForwardItems->currentItem()); 162} 163 164/** 165 * webkit_back_forward_list_get_back_item: 166 * @back_forward_list: a #WebKitBackForwardList 167 * 168 * Returns the item that precedes the current item. 169 * 170 * Returns: (transfer none): the #WebKitBackForwardListItem 171 * preceding the current item or %NULL. 172 */ 173WebKitBackForwardListItem* webkit_back_forward_list_get_back_item(WebKitBackForwardList* backForwardList) 174{ 175 g_return_val_if_fail(WEBKIT_IS_BACK_FORWARD_LIST(backForwardList), 0); 176 177 return webkitBackForwardListGetOrCreateItem(backForwardList, backForwardList->priv->backForwardItems->backItem()); 178} 179 180/** 181 * webkit_back_forward_list_get_forward_item: 182 * @back_forward_list: a #WebKitBackForwardList 183 * 184 * Returns the item that follows the current item. 185 * 186 * Returns: (transfer none): the #WebKitBackForwardListItem 187 * following the current item or %NULL. 188 */ 189WebKitBackForwardListItem* webkit_back_forward_list_get_forward_item(WebKitBackForwardList* backForwardList) 190{ 191 g_return_val_if_fail(WEBKIT_IS_BACK_FORWARD_LIST(backForwardList), 0); 192 193 return webkitBackForwardListGetOrCreateItem(backForwardList, backForwardList->priv->backForwardItems->forwardItem()); 194} 195 196/** 197 * webkit_back_forward_list_get_nth_item: 198 * @back_forward_list: a #WebKitBackForwardList 199 * @index: the index of the item 200 * 201 * Returns the item at a given index relative to the current item. 202 * 203 * Returns: (transfer none): the #WebKitBackForwardListItem 204 * located at the specified index relative to the current item. 205 */ 206WebKitBackForwardListItem* webkit_back_forward_list_get_nth_item(WebKitBackForwardList* backForwardList, gint index) 207{ 208 g_return_val_if_fail(WEBKIT_IS_BACK_FORWARD_LIST(backForwardList), 0); 209 210 return webkitBackForwardListGetOrCreateItem(backForwardList, backForwardList->priv->backForwardItems->itemAtIndex(index)); 211} 212 213/** 214 * webkit_back_forward_list_get_length: 215 * @back_forward_list: a #WebKitBackForwardList 216 * 217 * Returns: the length of @back_forward_list. 218 */ 219guint webkit_back_forward_list_get_length(WebKitBackForwardList* backForwardList) 220{ 221 g_return_val_if_fail(WEBKIT_IS_BACK_FORWARD_LIST(backForwardList), 0); 222 223 WebKitBackForwardListPrivate* priv = backForwardList->priv; 224 guint currentItem = webkit_back_forward_list_get_current_item(backForwardList) ? 1 : 0; 225 return priv->backForwardItems->backListCount() + priv->backForwardItems->forwardListCount() + currentItem; 226} 227 228/** 229 * webkit_back_forward_list_get_back_list: 230 * @back_forward_list: a #WebKitBackForwardList 231 * 232 * Returns: (element-type WebKit2.BackForwardListItem) (transfer container): a #GList of 233 * items preceding the current item. 234 */ 235GList* webkit_back_forward_list_get_back_list(WebKitBackForwardList* backForwardList) 236{ 237 g_return_val_if_fail(WEBKIT_IS_BACK_FORWARD_LIST(backForwardList), 0); 238 239 return webkit_back_forward_list_get_back_list_with_limit(backForwardList, backForwardList->priv->backForwardItems->backListCount()); 240} 241 242/** 243 * webkit_back_forward_list_get_back_list_with_limit: 244 * @back_forward_list: a #WebKitBackForwardList 245 * @limit: the number of items to retrieve 246 * 247 * Returns: (element-type WebKit2.BackForwardListItem) (transfer container): a #GList of 248 * items preceding the current item limited by @limit. 249 */ 250GList* webkit_back_forward_list_get_back_list_with_limit(WebKitBackForwardList* backForwardList, guint limit) 251{ 252 g_return_val_if_fail(WEBKIT_IS_BACK_FORWARD_LIST(backForwardList), 0); 253 254 WebKitBackForwardListPrivate* priv = backForwardList->priv; 255 RefPtr<ImmutableArray> immutableArray = priv->backForwardItems->backListAsImmutableArrayWithLimit(limit); 256 return webkitBackForwardListCreateList(backForwardList, immutableArray.get()); 257} 258 259/** 260 * webkit_back_forward_list_get_forward_list: 261 * @back_forward_list: a #WebKitBackForwardList 262 * 263 * Returns: (element-type WebKit2.BackForwardListItem) (transfer container): a #GList of 264 * items following the current item. 265 */ 266GList* webkit_back_forward_list_get_forward_list(WebKitBackForwardList* backForwardList) 267{ 268 g_return_val_if_fail(WEBKIT_IS_BACK_FORWARD_LIST(backForwardList), 0); 269 270 return webkit_back_forward_list_get_forward_list_with_limit(backForwardList, backForwardList->priv->backForwardItems->forwardListCount()); 271} 272 273/** 274 * webkit_back_forward_list_get_forward_list_with_limit: 275 * @back_forward_list: a #WebKitBackForwardList 276 * @limit: the number of items to retrieve 277 * 278 * Returns: (element-type WebKit2.BackForwardListItem) (transfer container): a #GList of 279 * items following the current item limited by @limit. 280 */ 281GList* webkit_back_forward_list_get_forward_list_with_limit(WebKitBackForwardList* backForwardList, guint limit) 282{ 283 g_return_val_if_fail(WEBKIT_IS_BACK_FORWARD_LIST(backForwardList), 0); 284 285 WebKitBackForwardListPrivate* priv = backForwardList->priv; 286 RefPtr<ImmutableArray> immutableArray = priv->backForwardItems->forwardListAsImmutableArrayWithLimit(limit); 287 return webkitBackForwardListCreateList(backForwardList, immutableArray.get()); 288} 289