From c98062b2c6a79a3fc6314f06b7215b70134a7b32 Mon Sep 17 00:00:00 2001 From: Adam Spiers Date: Sun, 6 Nov 2022 17:44:13 +0000 Subject: [PATCH 1/3] track window titles set by users Users can manually name windows by right-clicking on the empty space to the right of the tab bar, and selecting "Name window..." In this case, the window title as reflected in the window title as shown by the window manager will be the user-defined name rather than the active tab's title. --- chrome-session-dump.go | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/chrome-session-dump.go b/chrome-session-dump.go index 0bcc369..208bea2 100644 --- a/chrome-session-dump.go +++ b/chrome-session-dump.go @@ -48,6 +48,7 @@ const ( kCommandSetTabGroup = 25 kCommandSetTabGroupMetadata2 = 27 kCommandSetSelectedNavigationIndex = 7 + kCommandSetWindowUserTitle = 31 kCommandTabClosed = 16 kCommandWindowClosed = 17 kCommandSetTabIndexInWindow = 2 @@ -66,6 +67,7 @@ type window struct { id uint32 deleted bool tabs []*tab + userTitle string } type histItem struct { @@ -232,9 +234,10 @@ type Tab struct { } type Window struct { - Tabs []*Tab `json:"tabs"` - Active bool `json:"active"` - Deleted bool `json:"deleted"` + Tabs []*Tab `json:"tabs"` + Active bool `json:"active"` + Deleted bool `json:"deleted"` + UserTitle string `json:"userTitle"` } type HistoryItem struct { @@ -350,6 +353,12 @@ func parse(path string) Result { id := readUint32(data) getTab(id).win = win + case kCommandSetWindowUserTitle: + readUint32(data) //size of the data (again) + id := readUint32(data) + title := readString(data) + + getWindow(id).userTitle = title case kCommandWindowClosed: id := readUint32(data) @@ -398,7 +407,7 @@ func parse(path string) Result { var Windows []*Window for _, w := range windows { - W := &Window{Active: w == activeWindow, Deleted: w.deleted} + W := &Window{Active: w == activeWindow, Deleted: w.deleted, UserTitle: w.userTitle} idx := 0 for _, t := range w.tabs { From daf623167a1e204971ace90106ac6453c3827dc4 Mon Sep 17 00:00:00 2001 From: Adam Spiers Date: Sun, 6 Nov 2022 18:14:55 +0000 Subject: [PATCH 2/3] track tab group colors and collapsed/expanded state --- chrome-session-dump.go | 61 +++++++++++++++++++++++++++++++++--------- 1 file changed, 48 insertions(+), 13 deletions(-) diff --git a/chrome-session-dump.go b/chrome-session-dump.go index 208bea2..29e0f5f 100644 --- a/chrome-session-dump.go +++ b/chrome-session-dump.go @@ -57,9 +57,12 @@ const ( ) type group struct { - high uint64 - low uint64 - name string + + high uint64 + low uint64 + name string + color uint32 + collapsed bool } type window struct { @@ -102,7 +105,7 @@ func getWindow(id uint32) *window { func getGroup(high uint64, low uint64) *group { key := fmt.Sprintf("%x%x", high, low) if _, ok := groups[key]; !ok { - groups[key] = &group{high, low, ""} + groups[key] = &group{high, low, "", 0, false} } return groups[key] @@ -116,6 +119,21 @@ func getTab(id uint32) *tab { return tabs[id] } +func readBool(r io.Reader) bool { + var b [1]byte + if n, err := r.Read(b[:]); err != nil || n != 1 { + if err != nil { + panic(err) + } + if uint8(b[0]) > 1 { + panic(fmt.Errorf("Failed to read bool as 0 or 1.")) + } + panic(fmt.Errorf("Failed to read int8.")) + } + + return uint8(b[0]) == 1 +} + func readUint8(r io.Reader) uint8 { var b [1]byte if n, err := r.Read(b[:]); err != nil || n != 1 { @@ -225,12 +243,14 @@ type Result struct { } type Tab struct { - Active bool `json:"active"` - History []*HistoryItem `json:"history"` - Url string `json:"url"` - Title string `json:"title"` - Deleted bool `json:"deleted"` - Group string `json:"group"` + Active bool `json:"active"` + History []*HistoryItem `json:"history"` + Url string `json:"url"` + Title string `json:"title"` + Deleted bool `json:"deleted"` + Group string `json:"group"` + GroupColor uint32 `json:"groupColor"` + GroupCollapsed bool `json:"groupCollapsed"` } type Window struct { @@ -337,9 +357,14 @@ func parse(path string) Result { high := readUint64(data) low := readUint64(data) - name := readString16(data) - getGroup(high, low).name = name + color := readUint32(data) + collapsed := readBool(data) + + group := getGroup(high, low) + group.name = name + group.color = color + group.collapsed = collapsed case kCommandSetTabGroup: id := readUint32(data) readUint32(data) //Struct padding @@ -412,11 +437,21 @@ func parse(path string) Result { idx := 0 for _, t := range w.tabs { groupName := "" + groupCollapsed := false + groupColor := uint32(0) if t.group != nil { groupName = t.group.name + groupCollapsed = t.group.collapsed + groupColor = t.group.color } - T := &Tab{Active: idx == int(w.activeTabIdx), Deleted: t.deleted, Group: groupName} + T := &Tab{ + Active: idx == int(w.activeTabIdx), + Deleted: t.deleted, + Group: groupName, + GroupColor: groupColor, + GroupCollapsed: groupCollapsed, + } for _, h := range t.history { T.History = append(T.History, &HistoryItem{h.url, h.title}) From 0318dda9eccd76b40b10dd582673b3cc8d261199 Mon Sep 17 00:00:00 2001 From: Adam Spiers Date: Sun, 6 Nov 2022 18:33:37 +0000 Subject: [PATCH 3/3] track which tab groups are in which windows --- chrome-session-dump.go | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/chrome-session-dump.go b/chrome-session-dump.go index 29e0f5f..9e4f7c6 100644 --- a/chrome-session-dump.go +++ b/chrome-session-dump.go @@ -70,6 +70,7 @@ type window struct { id uint32 deleted bool tabs []*tab + tabGroups map[string]*group userTitle string } @@ -96,14 +97,18 @@ var groups = map[string]*group{} func getWindow(id uint32) *window { if _, ok := windows[id]; !ok { - windows[id] = &window{id: id} + windows[id] = &window{id: id, tabGroups: map[string]*group{}} } return windows[id] } +func getGroupKey(high uint64, low uint64) string { + return fmt.Sprintf("%x%x", high, low) +} + func getGroup(high uint64, low uint64) *group { - key := fmt.Sprintf("%x%x", high, low) + key := getGroupKey(high, low) if _, ok := groups[key]; !ok { groups[key] = &group{high, low, "", 0, false} } @@ -253,11 +258,19 @@ type Tab struct { GroupCollapsed bool `json:"groupCollapsed"` } +type TabGroup struct { + Name string `json:"name"` + Color uint32 `json:"color"` + Collapsed bool `json:"collapsed"` +} + type Window struct { - Tabs []*Tab `json:"tabs"` - Active bool `json:"active"` - Deleted bool `json:"deleted"` - UserTitle string `json:"userTitle"` + Tabs []*Tab `json:"tabs"` + TabGroups []*TabGroup `json:"tabGroups"` + Active bool `json:"active"` + Deleted bool `json:"deleted"` + Name string `json:"name"` + UserTitle string `json:"userTitle"` } type HistoryItem struct { @@ -440,9 +453,11 @@ func parse(path string) Result { groupCollapsed := false groupColor := uint32(0) if t.group != nil { + groupKey := getGroupKey(t.group.high, t.group.low) groupName = t.group.name groupCollapsed = t.group.collapsed groupColor = t.group.color + w.tabGroups[groupKey] = t.group } T := &Tab{ @@ -468,6 +483,16 @@ func parse(path string) Result { } } + for _, tg := range w.tabGroups { + TG := &TabGroup{ + Name: tg.name, + Color: tg.color, + Collapsed: tg.collapsed, + } + + W.TabGroups = append(W.TabGroups, TG) + } + Windows = append(Windows, W) }