1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/sessions/session_service_commands.h"
9 #include "base/pickle.h"
10 #include "components/sessions/base_session_service_commands.h"
11 #include "components/sessions/base_session_service_delegate.h"
12 #include "components/sessions/session_command.h"
13 #include "components/sessions/session_types.h"
17 // Identifier for commands written to file.
18 static const SessionCommand::id_type kCommandSetTabWindow
= 0;
19 // OBSOLETE Superseded by kCommandSetWindowBounds3.
20 // static const SessionCommand::id_type kCommandSetWindowBounds = 1;
21 static const SessionCommand::id_type kCommandSetTabIndexInWindow
= 2;
22 static const SessionCommand::id_type
23 kCommandTabNavigationPathPrunedFromBack
= 5;
24 static const SessionCommand::id_type kCommandUpdateTabNavigation
= 6;
25 static const SessionCommand::id_type kCommandSetSelectedNavigationIndex
= 7;
26 static const SessionCommand::id_type kCommandSetSelectedTabInIndex
= 8;
27 static const SessionCommand::id_type kCommandSetWindowType
= 9;
28 // OBSOLETE Superseded by kCommandSetWindowBounds3. Except for data migration.
29 // static const SessionCommand::id_type kCommandSetWindowBounds2 = 10;
30 static const SessionCommand::id_type
31 kCommandTabNavigationPathPrunedFromFront
= 11;
32 static const SessionCommand::id_type kCommandSetPinnedState
= 12;
33 static const SessionCommand::id_type kCommandSetExtensionAppID
= 13;
34 static const SessionCommand::id_type kCommandSetWindowBounds3
= 14;
35 static const SessionCommand::id_type kCommandSetWindowAppName
= 15;
36 static const SessionCommand::id_type kCommandTabClosed
= 16;
37 static const SessionCommand::id_type kCommandWindowClosed
= 17;
38 static const SessionCommand::id_type kCommandSetTabUserAgentOverride
= 18;
39 static const SessionCommand::id_type kCommandSessionStorageAssociated
= 19;
40 static const SessionCommand::id_type kCommandSetActiveWindow
= 20;
44 // Various payload structures.
45 struct ClosedPayload
{
46 SessionID::id_type id
;
50 struct WindowBoundsPayload2
{
51 SessionID::id_type window_id
;
59 struct WindowBoundsPayload3
{
60 SessionID::id_type window_id
;
68 typedef SessionID::id_type ActiveWindowPayload
;
70 struct IDAndIndexPayload
{
71 SessionID::id_type id
;
75 typedef IDAndIndexPayload TabIndexInWindowPayload
;
77 typedef IDAndIndexPayload TabNavigationPathPrunedFromBackPayload
;
79 typedef IDAndIndexPayload SelectedNavigationIndexPayload
;
81 typedef IDAndIndexPayload SelectedTabInIndexPayload
;
83 typedef IDAndIndexPayload WindowTypePayload
;
85 typedef IDAndIndexPayload TabNavigationPathPrunedFromFrontPayload
;
87 struct PinnedStatePayload
{
88 SessionID::id_type tab_id
;
92 // Persisted versions of ui::WindowShowState that are written to disk and can
94 enum PersistedWindowShowState
{
95 // SHOW_STATE_DEFAULT (0) never persisted.
96 PERSISTED_SHOW_STATE_NORMAL
= 1,
97 PERSISTED_SHOW_STATE_MINIMIZED
= 2,
98 PERSISTED_SHOW_STATE_MAXIMIZED
= 3,
99 // SHOW_STATE_INACTIVE (4) never persisted.
100 PERSISTED_SHOW_STATE_FULLSCREEN
= 5,
101 PERSISTED_SHOW_STATE_DETACHED_DEPRECATED
= 6,
102 PERSISTED_SHOW_STATE_END
= 6
105 typedef std::map
<SessionID::id_type
, SessionTab
*> IdToSessionTab
;
106 typedef std::map
<SessionID::id_type
, SessionWindow
*> IdToSessionWindow
;
108 // Assert to ensure PersistedWindowShowState is updated if ui::WindowShowState
110 static_assert(ui::SHOW_STATE_END
==
111 static_cast<ui::WindowShowState
>(PERSISTED_SHOW_STATE_END
),
112 "SHOW_STATE_END must equal PERSISTED_SHOW_STATE_END");
114 // Returns the show state to store to disk based |state|.
115 PersistedWindowShowState
ShowStateToPersistedShowState(
116 ui::WindowShowState state
) {
118 case ui::SHOW_STATE_NORMAL
:
119 return PERSISTED_SHOW_STATE_NORMAL
;
120 case ui::SHOW_STATE_MINIMIZED
:
121 return PERSISTED_SHOW_STATE_MINIMIZED
;
122 case ui::SHOW_STATE_MAXIMIZED
:
123 return PERSISTED_SHOW_STATE_MAXIMIZED
;
124 case ui::SHOW_STATE_FULLSCREEN
:
125 return PERSISTED_SHOW_STATE_FULLSCREEN
;
127 case ui::SHOW_STATE_DEFAULT
:
128 case ui::SHOW_STATE_INACTIVE
:
129 return PERSISTED_SHOW_STATE_NORMAL
;
131 case ui::SHOW_STATE_END
:
135 return PERSISTED_SHOW_STATE_NORMAL
;
138 // Lints show state values when read back from persited disk.
139 ui::WindowShowState
PersistedShowStateToShowState(int state
) {
141 case PERSISTED_SHOW_STATE_NORMAL
:
142 return ui::SHOW_STATE_NORMAL
;
143 case PERSISTED_SHOW_STATE_MINIMIZED
:
144 return ui::SHOW_STATE_MINIMIZED
;
145 case PERSISTED_SHOW_STATE_MAXIMIZED
:
146 return ui::SHOW_STATE_MAXIMIZED
;
147 case PERSISTED_SHOW_STATE_FULLSCREEN
:
148 return ui::SHOW_STATE_FULLSCREEN
;
149 case PERSISTED_SHOW_STATE_DETACHED_DEPRECATED
:
150 return ui::SHOW_STATE_NORMAL
;
153 return ui::SHOW_STATE_NORMAL
;
156 // Iterates through the vector updating the selected_tab_index of each
157 // SessionWindow based on the actual tabs that were restored.
158 void UpdateSelectedTabIndex(std::vector
<SessionWindow
*>* windows
) {
159 for (std::vector
<SessionWindow
*>::const_iterator i
= windows
->begin();
160 i
!= windows
->end(); ++i
) {
161 // See note in SessionWindow as to why we do this.
163 for (std::vector
<SessionTab
*>::const_iterator j
= (*i
)->tabs
.begin();
164 j
!= (*i
)->tabs
.end(); ++j
) {
165 if ((*j
)->tab_visual_index
== (*i
)->selected_tab_index
) {
166 new_index
= static_cast<int>(j
- (*i
)->tabs
.begin());
170 (*i
)->selected_tab_index
= new_index
;
174 // Returns the window in windows with the specified id. If a window does
175 // not exist, one is created.
176 SessionWindow
* GetWindow(SessionID::id_type window_id
,
177 IdToSessionWindow
* windows
) {
178 std::map
<int, SessionWindow
*>::iterator i
= windows
->find(window_id
);
179 if (i
== windows
->end()) {
180 SessionWindow
* window
= new SessionWindow();
181 window
->window_id
.set_id(window_id
);
182 (*windows
)[window_id
] = window
;
188 // Returns the tab with the specified id in tabs. If a tab does not exist,
190 SessionTab
* GetTab(SessionID::id_type tab_id
, IdToSessionTab
* tabs
) {
192 std::map
<int, SessionTab
*>::iterator i
= tabs
->find(tab_id
);
193 if (i
== tabs
->end()) {
194 SessionTab
* tab
= new SessionTab();
195 tab
->tab_id
.set_id(tab_id
);
196 (*tabs
)[tab_id
] = tab
;
202 // Returns an iterator into navigations pointing to the navigation whose
203 // index matches |index|. If no navigation index matches |index|, the first
204 // navigation with an index > |index| is returned.
206 // This assumes the navigations are ordered by index in ascending order.
207 std::vector
<sessions::SerializedNavigationEntry
>::iterator
208 FindClosestNavigationWithIndex(
209 std::vector
<sessions::SerializedNavigationEntry
>* navigations
,
212 for (std::vector
<sessions::SerializedNavigationEntry
>::iterator
213 i
= navigations
->begin(); i
!= navigations
->end(); ++i
) {
214 if (i
->index() >= index
)
217 return navigations
->end();
220 // Function used in sorting windows. Sorting is done based on window id. As
221 // window ids increment for each new window, this effectively sorts by creation
223 static bool WindowOrderSortFunction(const SessionWindow
* w1
,
224 const SessionWindow
* w2
) {
225 return w1
->window_id
.id() < w2
->window_id
.id();
228 // Compares the two tabs based on visual index.
229 static bool TabVisualIndexSortFunction(const SessionTab
* t1
,
230 const SessionTab
* t2
) {
231 const int delta
= t1
->tab_visual_index
- t2
->tab_visual_index
;
232 return delta
== 0 ? (t1
->tab_id
.id() < t2
->tab_id
.id()) : (delta
< 0);
235 // Does the following:
236 // . Deletes and removes any windows with no tabs. NOTE: constrained windows
237 // that have been dragged out are of type browser. As such, this preserves any
238 // dragged out constrained windows (aka popups that have been dragged out).
239 // . Sorts the tabs in windows with valid tabs based on the tabs
240 // visual order, and adds the valid windows to windows.
241 void SortTabsBasedOnVisualOrderAndPrune(
242 std::map
<int, SessionWindow
*>* windows
,
243 std::vector
<SessionWindow
*>* valid_windows
) {
244 std::map
<int, SessionWindow
*>::iterator i
= windows
->begin();
245 while (i
!= windows
->end()) {
246 SessionWindow
* window
= i
->second
;
247 if (window
->tabs
.empty() || window
->is_constrained
) {
251 // Valid window; sort the tabs and add it to the list of valid windows.
252 std::sort(window
->tabs
.begin(), window
->tabs
.end(),
253 &TabVisualIndexSortFunction
);
254 // Otherwise, add the window such that older windows appear first.
255 if (valid_windows
->empty()) {
256 valid_windows
->push_back(window
);
258 valid_windows
->insert(
259 std::upper_bound(valid_windows
->begin(), valid_windows
->end(),
260 window
, &WindowOrderSortFunction
),
268 // Adds tabs to their parent window based on the tab's window_id. This
269 // ignores tabs with no navigations.
270 void AddTabsToWindows(std::map
<int, SessionTab
*>* tabs
,
271 std::map
<int, SessionWindow
*>* windows
) {
272 DVLOG(1) << "AddTabsToWindws";
273 DVLOG(1) << "Tabs " << tabs
->size() << ", windows " << windows
->size();
274 std::map
<int, SessionTab
*>::iterator i
= tabs
->begin();
275 while (i
!= tabs
->end()) {
276 SessionTab
* tab
= i
->second
;
277 if (tab
->window_id
.id() && !tab
->navigations
.empty()) {
278 SessionWindow
* window
= GetWindow(tab
->window_id
.id(), windows
);
279 window
->tabs
.push_back(tab
);
282 // See note in SessionTab as to why we do this.
283 std::vector
<sessions::SerializedNavigationEntry
>::iterator j
=
284 FindClosestNavigationWithIndex(&(tab
->navigations
),
285 tab
->current_navigation_index
);
286 if (j
== tab
->navigations
.end()) {
287 tab
->current_navigation_index
=
288 static_cast<int>(tab
->navigations
.size() - 1);
290 tab
->current_navigation_index
=
291 static_cast<int>(j
- tab
->navigations
.begin());
294 // Never got a set tab index in window, or tabs are empty, nothing
301 // Creates tabs and windows from the commands specified in |data|. The created
302 // tabs and windows are added to |tabs| and |windows| respectively, with the
303 // id of the active window set in |active_window_id|. It is up to the caller
304 // to delete the tabs and windows added to |tabs| and |windows|.
306 // This does NOT add any created SessionTabs to SessionWindow.tabs, that is
307 // done by AddTabsToWindows.
308 bool CreateTabsAndWindows(const ScopedVector
<SessionCommand
>& data
,
309 std::map
<int, SessionTab
*>* tabs
,
310 std::map
<int, SessionWindow
*>* windows
,
311 SessionID::id_type
* active_window_id
) {
312 // If the file is corrupt (command with wrong size, or unknown command), we
313 // still return true and attempt to restore what we we can.
314 DVLOG(1) << "CreateTabsAndWindows";
316 for (std::vector
<SessionCommand
*>::const_iterator i
= data
.begin();
317 i
!= data
.end(); ++i
) {
318 const SessionCommand::id_type kCommandSetWindowBounds2
= 10;
319 const SessionCommand
* command
= *i
;
321 DVLOG(1) << "Read command " << (int) command
->id();
322 switch (command
->id()) {
323 case kCommandSetTabWindow
: {
324 SessionID::id_type payload
[2];
325 if (!command
->GetPayload(payload
, sizeof(payload
))) {
326 DVLOG(1) << "Failed reading command " << command
->id();
329 GetTab(payload
[1], tabs
)->window_id
.set_id(payload
[0]);
333 // This is here for forward migration only. New data is saved with
334 // |kCommandSetWindowBounds3|.
335 case kCommandSetWindowBounds2
: {
336 WindowBoundsPayload2 payload
;
337 if (!command
->GetPayload(&payload
, sizeof(payload
))) {
338 DVLOG(1) << "Failed reading command " << command
->id();
341 GetWindow(payload
.window_id
, windows
)->bounds
.SetRect(payload
.x
,
345 GetWindow(payload
.window_id
, windows
)->show_state
=
346 payload
.is_maximized
?
347 ui::SHOW_STATE_MAXIMIZED
: ui::SHOW_STATE_NORMAL
;
351 case kCommandSetWindowBounds3
: {
352 WindowBoundsPayload3 payload
;
353 if (!command
->GetPayload(&payload
, sizeof(payload
))) {
354 DVLOG(1) << "Failed reading command " << command
->id();
357 GetWindow(payload
.window_id
, windows
)->bounds
.SetRect(payload
.x
,
361 GetWindow(payload
.window_id
, windows
)->show_state
=
362 PersistedShowStateToShowState(payload
.show_state
);
366 case kCommandSetTabIndexInWindow
: {
367 TabIndexInWindowPayload payload
;
368 if (!command
->GetPayload(&payload
, sizeof(payload
))) {
369 DVLOG(1) << "Failed reading command " << command
->id();
372 GetTab(payload
.id
, tabs
)->tab_visual_index
= payload
.index
;
376 case kCommandTabClosed
:
377 case kCommandWindowClosed
: {
378 ClosedPayload payload
;
379 if (!command
->GetPayload(&payload
, sizeof(payload
))) {
380 DVLOG(1) << "Failed reading command " << command
->id();
383 if (command
->id() == kCommandTabClosed
) {
384 delete GetTab(payload
.id
, tabs
);
385 tabs
->erase(payload
.id
);
387 delete GetWindow(payload
.id
, windows
);
388 windows
->erase(payload
.id
);
393 case kCommandTabNavigationPathPrunedFromBack
: {
394 TabNavigationPathPrunedFromBackPayload payload
;
395 if (!command
->GetPayload(&payload
, sizeof(payload
))) {
396 DVLOG(1) << "Failed reading command " << command
->id();
399 SessionTab
* tab
= GetTab(payload
.id
, tabs
);
400 tab
->navigations
.erase(
401 FindClosestNavigationWithIndex(&(tab
->navigations
), payload
.index
),
402 tab
->navigations
.end());
406 case kCommandTabNavigationPathPrunedFromFront
: {
407 TabNavigationPathPrunedFromFrontPayload payload
;
408 if (!command
->GetPayload(&payload
, sizeof(payload
)) ||
409 payload
.index
<= 0) {
410 DVLOG(1) << "Failed reading command " << command
->id();
413 SessionTab
* tab
= GetTab(payload
.id
, tabs
);
415 // Update the selected navigation index.
416 tab
->current_navigation_index
=
417 std::max(-1, tab
->current_navigation_index
- payload
.index
);
419 // And update the index of existing navigations.
420 for (std::vector
<sessions::SerializedNavigationEntry
>::iterator
421 i
= tab
->navigations
.begin();
422 i
!= tab
->navigations
.end();) {
423 i
->set_index(i
->index() - payload
.index
);
425 i
= tab
->navigations
.erase(i
);
432 case kCommandUpdateTabNavigation
: {
433 sessions::SerializedNavigationEntry navigation
;
434 SessionID::id_type tab_id
;
435 if (!RestoreUpdateTabNavigationCommand(*command
,
438 DVLOG(1) << "Failed reading command " << command
->id();
441 SessionTab
* tab
= GetTab(tab_id
, tabs
);
442 std::vector
<sessions::SerializedNavigationEntry
>::iterator i
=
443 FindClosestNavigationWithIndex(&(tab
->navigations
),
445 if (i
!= tab
->navigations
.end() && i
->index() == navigation
.index())
448 tab
->navigations
.insert(i
, navigation
);
452 case kCommandSetSelectedNavigationIndex
: {
453 SelectedNavigationIndexPayload payload
;
454 if (!command
->GetPayload(&payload
, sizeof(payload
))) {
455 DVLOG(1) << "Failed reading command " << command
->id();
458 GetTab(payload
.id
, tabs
)->current_navigation_index
= payload
.index
;
462 case kCommandSetSelectedTabInIndex
: {
463 SelectedTabInIndexPayload payload
;
464 if (!command
->GetPayload(&payload
, sizeof(payload
))) {
465 DVLOG(1) << "Failed reading command " << command
->id();
468 GetWindow(payload
.id
, windows
)->selected_tab_index
= payload
.index
;
472 case kCommandSetWindowType
: {
473 WindowTypePayload payload
;
474 if (!command
->GetPayload(&payload
, sizeof(payload
))) {
475 DVLOG(1) << "Failed reading command " << command
->id();
478 GetWindow(payload
.id
, windows
)->is_constrained
= false;
479 GetWindow(payload
.id
, windows
)->type
=
480 static_cast<SessionWindow::WindowType
>(payload
.index
);
484 case kCommandSetPinnedState
: {
485 PinnedStatePayload payload
;
486 if (!command
->GetPayload(&payload
, sizeof(payload
))) {
487 DVLOG(1) << "Failed reading command " << command
->id();
490 GetTab(payload
.tab_id
, tabs
)->pinned
= payload
.pinned_state
;
494 case kCommandSetWindowAppName
: {
495 SessionID::id_type window_id
;
496 std::string app_name
;
497 if (!RestoreSetWindowAppNameCommand(*command
, &window_id
, &app_name
))
500 GetWindow(window_id
, windows
)->app_name
.swap(app_name
);
504 case kCommandSetExtensionAppID
: {
505 SessionID::id_type tab_id
;
506 std::string extension_app_id
;
507 if (!RestoreSetTabExtensionAppIDCommand(*command
,
509 &extension_app_id
)) {
510 DVLOG(1) << "Failed reading command " << command
->id();
514 GetTab(tab_id
, tabs
)->extension_app_id
.swap(extension_app_id
);
518 case kCommandSetTabUserAgentOverride
: {
519 SessionID::id_type tab_id
;
520 std::string user_agent_override
;
521 if (!RestoreSetTabUserAgentOverrideCommand(
524 &user_agent_override
)) {
528 GetTab(tab_id
, tabs
)->user_agent_override
.swap(user_agent_override
);
532 case kCommandSessionStorageAssociated
: {
533 scoped_ptr
<Pickle
> command_pickle(command
->PayloadAsPickle());
534 SessionID::id_type command_tab_id
;
535 std::string session_storage_persistent_id
;
536 PickleIterator
iter(*command_pickle
.get());
537 if (!iter
.ReadInt(&command_tab_id
) ||
538 !iter
.ReadString(&session_storage_persistent_id
))
540 // Associate the session storage back.
541 GetTab(command_tab_id
, tabs
)->session_storage_persistent_id
=
542 session_storage_persistent_id
;
546 case kCommandSetActiveWindow
: {
547 ActiveWindowPayload payload
;
548 if (!command
->GetPayload(&payload
, sizeof(payload
))) {
549 DVLOG(1) << "Failed reading command " << command
->id();
552 *active_window_id
= payload
;
557 // TODO(skuhne): This might call back into a callback handler to extend
558 // the command set for specific implementations.
559 DVLOG(1) << "Failed reading an unknown command " << command
->id();
568 scoped_ptr
<SessionCommand
> CreateSetSelectedTabInWindowCommand(
569 const SessionID
& window_id
,
571 SelectedTabInIndexPayload payload
= { 0 };
572 payload
.id
= window_id
.id();
573 payload
.index
= index
;
574 scoped_ptr
<SessionCommand
> command(
575 new SessionCommand(kCommandSetSelectedTabInIndex
, sizeof(payload
)));
576 memcpy(command
->contents(), &payload
, sizeof(payload
));
580 scoped_ptr
<SessionCommand
> CreateSetTabWindowCommand(const SessionID
& window_id
,
581 const SessionID
& tab_id
) {
582 SessionID::id_type payload
[] = { window_id
.id(), tab_id
.id() };
583 scoped_ptr
<SessionCommand
> command(
584 new SessionCommand(kCommandSetTabWindow
, sizeof(payload
)));
585 memcpy(command
->contents(), payload
, sizeof(payload
));
589 scoped_ptr
<SessionCommand
> CreateSetWindowBoundsCommand(
590 const SessionID
& window_id
,
591 const gfx::Rect
& bounds
,
592 ui::WindowShowState show_state
) {
593 WindowBoundsPayload3 payload
= { 0 };
594 payload
.window_id
= window_id
.id();
595 payload
.x
= bounds
.x();
596 payload
.y
= bounds
.y();
597 payload
.w
= bounds
.width();
598 payload
.h
= bounds
.height();
599 payload
.show_state
= ShowStateToPersistedShowState(show_state
);
600 scoped_ptr
<SessionCommand
> command(
601 new SessionCommand(kCommandSetWindowBounds3
, sizeof(payload
)));
602 memcpy(command
->contents(), &payload
, sizeof(payload
));
606 scoped_ptr
<SessionCommand
> CreateSetTabIndexInWindowCommand(
607 const SessionID
& tab_id
,
609 TabIndexInWindowPayload payload
= { 0 };
610 payload
.id
= tab_id
.id();
611 payload
.index
= new_index
;
612 scoped_ptr
<SessionCommand
> command(
613 new SessionCommand(kCommandSetTabIndexInWindow
, sizeof(payload
)));
614 memcpy(command
->contents(), &payload
, sizeof(payload
));
618 scoped_ptr
<SessionCommand
> CreateTabClosedCommand(
619 const SessionID::id_type tab_id
) {
620 ClosedPayload payload
;
621 // Because of what appears to be a compiler bug setting payload to {0} doesn't
622 // set the padding to 0, resulting in Purify reporting an UMR when we write
623 // the structure to disk. To avoid this we explicitly memset the struct.
624 memset(&payload
, 0, sizeof(payload
));
626 payload
.close_time
= base::Time::Now().ToInternalValue();
627 scoped_ptr
<SessionCommand
> command(
628 new SessionCommand(kCommandTabClosed
, sizeof(payload
)));
629 memcpy(command
->contents(), &payload
, sizeof(payload
));
633 scoped_ptr
<SessionCommand
> CreateWindowClosedCommand(
634 const SessionID::id_type window_id
) {
635 ClosedPayload payload
;
636 // See comment in CreateTabClosedCommand as to why we do this.
637 memset(&payload
, 0, sizeof(payload
));
638 payload
.id
= window_id
;
639 payload
.close_time
= base::Time::Now().ToInternalValue();
640 scoped_ptr
<SessionCommand
> command(
641 new SessionCommand(kCommandWindowClosed
, sizeof(payload
)));
642 memcpy(command
->contents(), &payload
, sizeof(payload
));
646 scoped_ptr
<SessionCommand
> CreateSetSelectedNavigationIndexCommand(
647 const SessionID
& tab_id
,
649 SelectedNavigationIndexPayload payload
= { 0 };
650 payload
.id
= tab_id
.id();
651 payload
.index
= index
;
652 scoped_ptr
<SessionCommand
> command(
653 new SessionCommand(kCommandSetSelectedNavigationIndex
, sizeof(payload
)));
654 memcpy(command
->contents(), &payload
, sizeof(payload
));
658 scoped_ptr
<SessionCommand
> CreateSetWindowTypeCommand(
659 const SessionID
& window_id
,
660 SessionWindow::WindowType type
) {
661 WindowTypePayload payload
= { 0 };
662 payload
.id
= window_id
.id();
663 payload
.index
= static_cast<int32
>(type
);
664 scoped_ptr
<SessionCommand
> command(
665 new SessionCommand( kCommandSetWindowType
, sizeof(payload
)));
666 memcpy(command
->contents(), &payload
, sizeof(payload
));
670 scoped_ptr
<SessionCommand
> CreatePinnedStateCommand(
671 const SessionID
& tab_id
,
673 PinnedStatePayload payload
= { 0 };
674 payload
.tab_id
= tab_id
.id();
675 payload
.pinned_state
= is_pinned
;
676 scoped_ptr
<SessionCommand
> command(
677 new SessionCommand(kCommandSetPinnedState
, sizeof(payload
)));
678 memcpy(command
->contents(), &payload
, sizeof(payload
));
682 scoped_ptr
<SessionCommand
> CreateSessionStorageAssociatedCommand(
683 const SessionID
& tab_id
,
684 const std::string
& session_storage_persistent_id
) {
686 pickle
.WriteInt(tab_id
.id());
687 pickle
.WriteString(session_storage_persistent_id
);
688 return scoped_ptr
<SessionCommand
>(
689 new SessionCommand(kCommandSessionStorageAssociated
, pickle
));
692 scoped_ptr
<SessionCommand
> CreateSetActiveWindowCommand(
693 const SessionID
& window_id
) {
694 ActiveWindowPayload payload
= 0;
695 payload
= window_id
.id();
696 scoped_ptr
<SessionCommand
> command(
697 new SessionCommand(kCommandSetActiveWindow
, sizeof(payload
)));
698 memcpy(command
->contents(), &payload
, sizeof(payload
));
702 scoped_ptr
<SessionCommand
> CreateTabNavigationPathPrunedFromBackCommand(
703 const SessionID
& tab_id
,
705 TabNavigationPathPrunedFromBackPayload payload
= { 0 };
706 payload
.id
= tab_id
.id();
707 payload
.index
= count
;
708 scoped_ptr
<SessionCommand
> command(
709 new SessionCommand(kCommandTabNavigationPathPrunedFromBack
,
711 memcpy(command
->contents(), &payload
, sizeof(payload
));
715 scoped_ptr
<SessionCommand
> CreateTabNavigationPathPrunedFromFrontCommand(
716 const SessionID
& tab_id
,
718 TabNavigationPathPrunedFromFrontPayload payload
= { 0 };
719 payload
.id
= tab_id
.id();
720 payload
.index
= count
;
721 scoped_ptr
<SessionCommand
> command(
722 new SessionCommand(kCommandTabNavigationPathPrunedFromFront
,
724 memcpy(command
->contents(), &payload
, sizeof(payload
));
728 scoped_ptr
<SessionCommand
> CreateUpdateTabNavigationCommand(
729 const SessionID
& tab_id
,
730 const sessions::SerializedNavigationEntry
& navigation
) {
731 return CreateUpdateTabNavigationCommand(kCommandUpdateTabNavigation
,
736 scoped_ptr
<SessionCommand
> CreateSetTabExtensionAppIDCommand(
737 const SessionID
& tab_id
,
738 const std::string
& extension_id
) {
739 return CreateSetTabExtensionAppIDCommand(kCommandSetExtensionAppID
,
744 scoped_ptr
<SessionCommand
> CreateSetTabUserAgentOverrideCommand(
745 const SessionID
& tab_id
,
746 const std::string
& user_agent_override
) {
747 return CreateSetTabUserAgentOverrideCommand(kCommandSetTabUserAgentOverride
,
749 user_agent_override
);
752 scoped_ptr
<SessionCommand
> CreateSetWindowAppNameCommand(
753 const SessionID
& window_id
,
754 const std::string
& app_name
) {
755 return CreateSetWindowAppNameCommand(kCommandSetWindowAppName
,
760 bool ReplacePendingCommand(BaseSessionService
* base_session_service
,
761 scoped_ptr
<SessionCommand
>* command
) {
762 // We optimize page navigations, which can happen quite frequently and
763 // is expensive. And activation is like Highlander, there can only be one!
764 if ((*command
)->id() != kCommandUpdateTabNavigation
&&
765 (*command
)->id() != kCommandSetActiveWindow
) {
768 for (ScopedVector
<SessionCommand
>::const_reverse_iterator i
=
769 base_session_service
->pending_commands().rbegin();
770 i
!= base_session_service
->pending_commands().rend(); ++i
) {
771 SessionCommand
* existing_command
= *i
;
772 if ((*command
)->id() == kCommandUpdateTabNavigation
&&
773 existing_command
->id() == kCommandUpdateTabNavigation
) {
774 scoped_ptr
<Pickle
> command_pickle((*command
)->PayloadAsPickle());
775 PickleIterator
iterator(*command_pickle
);
776 SessionID::id_type command_tab_id
;
777 int command_nav_index
;
778 if (!iterator
.ReadInt(&command_tab_id
) ||
779 !iterator
.ReadInt(&command_nav_index
)) {
782 SessionID::id_type existing_tab_id
;
783 int existing_nav_index
;
785 // Creating a pickle like this means the Pickle references the data from
786 // the command. Make sure we delete the pickle before the command, else
787 // the pickle references deleted memory.
788 scoped_ptr
<Pickle
> existing_pickle(existing_command
->PayloadAsPickle());
789 iterator
= PickleIterator(*existing_pickle
);
790 if (!iterator
.ReadInt(&existing_tab_id
) ||
791 !iterator
.ReadInt(&existing_nav_index
)) {
795 if (existing_tab_id
== command_tab_id
&&
796 existing_nav_index
== command_nav_index
) {
797 // existing_command is an update for the same tab/index pair. Replace
798 // it with the new one. We need to add to the end of the list just in
799 // case there is a prune command after the update command.
800 base_session_service
->EraseCommand(*(i
.base() - 1));
801 base_session_service
->AppendRebuildCommand((*command
).Pass());
806 if ((*command
)->id() == kCommandSetActiveWindow
&&
807 existing_command
->id() == kCommandSetActiveWindow
) {
808 base_session_service
->SwapCommand(existing_command
, (*command
).Pass());
815 bool IsClosingCommand(SessionCommand
* command
) {
816 return command
->id() == kCommandTabClosed
||
817 command
->id() == kCommandWindowClosed
;
820 void RestoreSessionFromCommands(const ScopedVector
<SessionCommand
>& commands
,
821 std::vector
<SessionWindow
*>* valid_windows
,
822 SessionID::id_type
* active_window_id
) {
823 std::map
<int, SessionTab
*> tabs
;
824 std::map
<int, SessionWindow
*> windows
;
826 DVLOG(1) << "RestoreSessionFromCommands " << commands
.size();
827 if (CreateTabsAndWindows(commands
, &tabs
, &windows
, active_window_id
)) {
828 AddTabsToWindows(&tabs
, &windows
);
829 SortTabsBasedOnVisualOrderAndPrune(&windows
, valid_windows
);
830 UpdateSelectedTabIndex(valid_windows
);
832 STLDeleteValues(&tabs
);
833 // Don't delete contents of windows, that is done by the caller as all
834 // valid windows are added to valid_windows.
837 } // namespace sessions