Commit Graph

17862 Commits

Author SHA1 Message Date
csoler
6160b39dab
Merge pull request #3271 from defnax/distantchat-popup-fix
💬 Fixed to not popup distant chat on incoming chat
2026-08-16 14:16:35 +02:00
csoler
48c60e1cdb
Merge pull request #3210 from jolavillette/FixSearchColumnWidthPersistence
GUI: persist search results column widths across restarts
2026-08-13 18:13:47 +02:00
jolavillette
9119058c48 GUI: persist search results column widths across restarts 2026-08-07 01:12:19 +02:00
csoler
682cde9fbd
Merge pull request #3274 from jolavillette/fix/gxs-mark-all-read-nofreeze
Fix UI freeze on "mark all as read/unread" for forums, channels and boards
2026-08-06 21:46:57 +02:00
jolavillette
1b99beebc5 Address review: pointer hand-off to the workers, event-driven board update
- GxsForumModel / PostedPostsModel: hand the id list to the background
  worker through a pointer deleted after the call, so the lambda capture
  does not deep copy it.
- PostedPostsModel: setAllMsgReadStatus() no longer updates the model
  directly. The batched READ_STATUS_CHANGED event now carries the
  affected ids and their new state (libretroshare side), and the event
  handler applies them locally — so a batch initiated by another
  frontend (e.g. webUI) updates the board view exactly the same way,
  and no post is re-read from the database.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-01 23:16:08 +02:00
jolavillette
ebac1481f0 Revert "gui(forums): opt-in latency probes on the read/unread and loading path"
Profiling code removed from the PR, as requested in review of the sibling
PRs. This reverts commit 8845aa4636e630977f4a6817e8a267735e128e28.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-01 23:16:08 +02:00
jolavillette
dea2f28dd9 gui(forums): opt-in latency probes on the read/unread and loading path
Set RS_GUI_PROFILE to a threshold in milliseconds (0 reports
everything) to get one line per measured operation on stderr, plus a
50 ms watchdog on the GUI thread that reports every stall of the event
loop wherever the blocking code lives, naming the last probed
operation. This is what located the actual freeze of the read/unread
path (a whole-model dataChanged() measured at 1072 ms) after several
plausible-from-code-reading fixes had failed to: the numbers say where
the time goes instead of a story explaining where it might go.

All probes are inert unless the environment variable is set.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 23:16:08 +02:00
jolavillette
5cbcd962dd gui(forums): re-read the group on SUBSCRIBE_STATUS_CHANGED instead of flipping the flag
The event means the subscription status changed, not that it was
toggled: guessing the new value by inverting the current flag goes
wrong as soon as one event is duplicated, lost, or refers to a state
the widget already holds. When the guess lands on 'unsubscribed', the
widget silently refuses to mark posts read or unread (the very first
check of markMsgAsReadUnread) until the next group reload puts the flag
right again. updateGroupData() was already called anyway; let it be the
only writer of the flag.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 23:16:08 +02:00
jolavillette
b0ca91c825 gui(forums): drop the expanded-items save/restore around read-status changes
setMsgReadStatus() only emits dataChanged(); it never resets the model
nor changes its layout, so the expanded items and the current index
survive it untouched. Saving and restoring them on every toggle was
pure overhead, and an expensive one: the restore walks every expanded
item and pays, for each, a linear scan of the post array plus a linear
scan of the view items -- quadratic work on the GUI thread for a single
post marked read or unread on a large forum.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 23:16:08 +02:00
jolavillette
243c417bfc GxsForumModel: size the read-status view refresh on rows, not message ids
280e51f53 restricted the dataChanged() refresh to the affected post
unless more than 5 messages changed, in which case it refreshes the
whole view. But changed_msgs counts message ids, and a post carries one
id per stored version of itself, all sharing one read status: marking a
single post read or unread on a post edited 46 times queued 47 ids and
triggered the whole-model refresh. Measured on a 8259 post forum: one
click, one row repainted, 1072 ms of frozen GUI in the dataChanged()
handling; with this fix the same click costs about 1 ms.

Count the changed rows separately and size the refresh on that.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 23:16:08 +02:00
jolavillette
3860f76dc1 gui(forums): create reload timer before setGroupId (fix ctor SIGSEGV)
The coalescing timer was allocated near the end of the constructor, but
setGroupId(forumId) is called earlier and synchronously reaches
groupIdChanged() -> updateDisplay(true) -> mDeferredReloadTimer->stop(),
dereferencing the still-uninitialised pointer and crashing the moment a forum
was opened. Allocate the timer right after setupUi(), before setGroupId().

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-01 23:16:08 +02:00
jolavillette
839293f84d gui(forums): coalesce full-forum reloads to stop sync-burst UI freezes
handleEvent_main_thread() ran a full updateDisplay(true) (updateForum ->
getForumPostsHierarchy -> setPosts full reset -> proxy re-sort/re-filter ->
tree rebuild) for every incoming GXS event. A sync batch delivers many
NEW_MESSAGE events back to back, so the forum was reloaded once per post,
freezing the UI for seconds and resetting the model out from under the user's
current selection (and racing the async read-status persistence, making a
just-read post pop back to bold).

Route those events through a single-shot QTimer (300 ms) that is restarted on
each event, so a whole burst collapses into one reload once the events settle.
An explicit reload (forum switch) cancels any pending deferred one.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-01 23:16:08 +02:00
jolavillette
78ff5d66e6 GxsForumModel: fix malformed model reset dropping freshly-arrived posts
setPosts() called beginResetModel()/endResetModel() *before* swapping mPosts,
so endResetModel() fired while the model still exposed the previous hierarchy,
then emitted an extra beginInsertRows()/endInsertRows() on top of the reset.
That double-signalling left the view/proxy row->source mapping stale, so a
post that had just arrived could map to an invalid source index: selecting it
neither displayed its content nor cleared its unread (bold) state.

Bracket the actual data swap with beginResetModel()/endResetModel() and drop
the bogus row-insertion signal; a full reset already tells the views to
re-query everything. Same anti-pattern as the channels grid-empty-on-new-post
fix.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-01 23:16:08 +02:00
jolavillette
8959b45087 gui(forums): keep single-post read latency low via unitary markRead
Routing every read through the batched markRead(grpId, vector, read) also
routed single interactive reads (selecting/opening one post) through its
waitToken(): the READ_STATUS_CHANGED event, and thus the forum-list unread
counter refresh, was only emitted once the DB write completed, adding
~100ms plus one GXS tick of latency versus the previous behaviour.

Send a single changed message through the per-message markRead(pair),
which emits the event immediately, and keep the batched call only for
larger sets (mark-all, with-children, versioned posts) where deferring the
single event until completion is what avoids the freeze.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-01 23:16:08 +02:00
jolavillette
2816dfd9f6 gui(forums): fix slow post navigation by restricting dataChanged refresh to affected post and parents 2026-08-01 23:16:08 +02:00
jolavillette
e5ed16c805 Channels/Posted models: never freeze the UI on "mark all as read"
GxsChannelPostsModel and PostedPostsModel spawned one detached std::thread (and
got one event) per post on "mark all as read/unread", freezing the UI on large
channels/boards - the same problem just fixed for forums, and worse here given
the much larger channel/board databases.

Both now collect the affected message ids and issue a single background batch
call (setMessageReadStatus / setPostReadStatus with a vector) plus a single view
refresh. PostedPostsModel additionally updates its local model up front (it
previously relied entirely on the per-message events).

Requires the matching libretroshare bulk overloads.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-01 23:16:08 +02:00
jolavillette
f4463dd17f GxsForumModel: never freeze the UI on "mark all as read"
recursSetMsgReadStatus() used to spawn one detached std::thread per changed
post (each blocking up to 5s in markRead) and emit one dataChanged() per post.
On a forum with thousands of unread posts this created thousands of threads
and signals driven from the GUI thread, freezing (and sometimes crashing) the
UI - the reported symptom being an hour-long hourglass on an 8000-post forum.

Now the recursion only collects the affected message ids and updates the
in-memory model; setMsgReadStatus() then issues a single background batch call
(rsGxsForums->markRead(group, ids, read)) and a single view refresh. The GUI
thread does O(n) in-memory work plus one thread and one signal, so it stays
responsive no matter how large the forum is.

Requires the matching libretroshare bulk markRead() overload.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-01 23:16:08 +02:00
csoler
ec9ab70561
Merge pull request #3280 from jolavillette/perf/gxs-channel-loading
GUI: stop copying and sorting the channel post array in the Qt thread
2026-08-01 21:10:36 +02:00
jolavillette
0e31d5fed0 GUI: remove the profiling probes from the channel post model
Requested in review: the RS_GXS_PROFILE instrumentation of update_posts()
and setPosts() served to measure the freeze and verify the fix, but it
should not stay in the optimised code. The libretroshare profiling header
is no longer included.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-01 14:31:38 +02:00
jolavillette
28e7f791ff GUI: stop copying and sorting the channel post array in the Qt thread
setPosts() runs in the Qt thread, through postToObject(). It copied the whole
post array a fourth time and then sorted it there, so for a channel with a few
thousand posts the interface was frozen for the duration of both.

Move the sort into the loader thread in update_posts(), where the array is
already sitting after the service call, and have setPosts() take its argument
by rvalue reference so the array is moved in rather than copied. The sort is
kept in setPosts() as a safety net: on an already ordered array it only runs
comparisons and moves nothing.

Combined with the libretroshare side making posts movable, the array is now
handed from the data store to the model without a single deep copy of a
thumbnail.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 22:34:12 +02:00
jolavillette
54d4c791aa GUI: profile the channel post model loading
Complements the GXS side instrumentation (libretroshare, gxs/rsgxsprofiler.h)
with the two phases that happen in the GUI: the service calls made from the
loader thread in update_posts(), and the model update in setPosts(), which
runs in the Qt thread and is what actually freezes the interface.

setPosts() reports its three phases separately (array copy, sort, view update)
since they have very different causes.

Enabled by the same RS_GXS_PROFILE environment variable, off by default.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 22:34:12 +02:00
csoler
2bf991418d
Merge pull request #3284 from jolavillette/fix/feedreader-mark-all-unread
FeedReader: add "Mark all as unread" alongside "Mark all as read"
2026-07-30 14:34:04 +02:00
jolavillette
2cd7c21aa6 gui(feedreader): add "Mark all as unread" alongside "Mark all as read"
The FeedReader message widget already offered "Mark all as read"
(toolbar button + context menu) but had no way to mark every visible
message as unread again. Add the symmetric "Mark all as unread" entry
to the message context menu.

Factor the shared iterate-over-visible-items logic out of
markAllAsReadMsg() into setAllMsgAsReadUnread(bool read); the read and
unread slots now just call it. Like the existing "mark all as read", the
action honours the current filter (acts on non-hidden rows only) and
goes through the existing per-message setMessageRead() path, so no
backend change is required.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-25 13:31:47 +02:00
Gioacchino Mazzurco
086184ad21
Fix GitLab mirror failing on GitHub PR refs
The mirror workflow cloned with --mirror and pushed all refs, including
GitHub's refs/pull/* and upstream/pr/*, which GitLab rejects as hidden
refs ("deny updating a hidden ref" on upstream/pr/3213), failing the
whole push. Clone --bare and push only refs/heads/* and refs/tags/*
with --prune, keeping deletion sync while never touching PR refs.
2026-07-23 18:10:46 +02:00
Gioacchino Mazzurco
76ba160ad1
Merge pull request #3269 from jolavillette/docs/build-cmake
Docs/build cmake
2026-07-23 17:56:14 +02:00
Gioacchino Mazzurco
0500db415c
Merge pull request #3243 from jolavillette/fix/cmake-qt6-detection
GUI CMake: reliably select Qt6 (with Qt5 fallback)
2026-07-23 17:03:03 +02:00
jolavillette
941a1ec6bd docs: add packaging and deployment section for Windows/MSYS2 in BUILD-cmake.md
Document portable archive creation (7-Zip / ZIP fallback), setup installer generation using NSIS, and how to execute and configure the deploy-windows.sh script.
2026-07-15 13:34:59 +02:00
jolavillette
70b1861e24 docs: add RS_USE_NATIVE_DIALOGS=ON to Windows build commands
Qt's non-native file/directory dialogs hang on Windows.
Using the OS native dialogs avoids the problem.
2026-07-13 15:29:25 +02:00
jolavillette
2759abca68 docs(BUILD): document version numbering (git describe derivation)
Explain how RS_GUI_VERSION, the libRetroShare version and RS_LIB_VERSION_HASH
are each derived from git describe at configure time, the exact commands to
read them without building, the --dirty submodule-pointer gotcha, the --long
always-suffixed libretroshare format, and the non-git fallback.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 12:47:37 +02:00
jolavillette
b3f137e580 docs(BUILD): checkout rapidjson fix commit after submodule init (GCC>=13)
The super-project pins rapidjson at f54b0e47, whose GenericStringRef::operator=
assigns to the const member `length`. That fails to compile on modern
toolchains (Debian 13 / GCC 14: "assignment of read-only member 'length'").
Add a note after the submodule init step telling testers to check out the
upstream fix 9bd618f5 (PR #719 on Tencent/rapidjson master).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-10 13:46:33 +02:00
jolavillette
6c16de174a docs(BUILD): add Debug build section for Linux (gdb symbols + ASan)
New 'Debug build (Linux)' subsection: CMAKE_BUILD_TYPE=Debug with -g3 -O0 -fno-omit-frame-pointer for full symbols and exact backtraces, a Qt6 note, a RelWithDebInfo caveat, the gdb invocation with the real binary path (Build-cmake/retroshare-gui/retroshare), and an AddressSanitizer variant for use-after-free / heap bugs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 23:51:44 +02:00
defnax
7f15e396ac Fixed to not popup distant chat on incoming chat 2026-07-09 09:30:53 +02:00
jolavillette
923fe3338a fix(cmake): reliably prefer Qt6 over Qt5 in GUI detection
find_package(QT NAMES Qt6 Qt5 ...) does not honour the NAMES order on
distros that ship Qt5 and Qt6 side by side in the same prefix (Debian/
Ubuntu multiarch /usr/lib/<arch>/cmake): CMake globs the sibling
Qt5*/Qt6* config dirs and stops at whichever <name>Config.cmake it
reaches first, which is filesystem-order dependent and routinely lands
on Qt5 even though Qt6 is listed first.

Probe Qt6 explicitly (find_package(Qt6 QUIET COMPONENTS Core)) and fall
back to Qt5. This makes the Qt6 preference deterministic and also makes
-DCMAKE_DISABLE_FIND_PACKAGE_Qt6=ON work as a reliable Qt5-force switch.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 22:12:14 +02:00
jolavillette
063fb607f9 docs(BUILD): require RS_SERVICE_TERMINAL_WEBUI_PASSWORD=ON for the service WebUI
RS_WEBUI=ON alone builds the WebUI machinery, but retroshare-service then
has no way to turn it on: enableWebUI defaults to false and only the -W
flag ever sets it, and -W/-B are gated behind
RS_SERVICE_TERMINAL_WEBUI_PASSWORD (a cmake_dependent_option requiring
RS_WEBUI=ON). Document the flag and add it to every build command block.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 22:12:02 +02:00
jolavillette
762d4d5fd9 docs(BUILD): auto-detect CPU count for the Windows build
Windows hard-coded -j3; nproc is available in MSYS2, so use -j$(nproc) like
Linux. Added a note that MinGW C++ compilation is RAM-hungry and may need a
manually lower -j on low-memory machines (the reason for the old -j3 cap).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 22:12:02 +02:00
jolavillette
8af7995d7d docs(BUILD): drop inline # comments from copy-paste blocks
zsh interactive (interactive_comments off by default) rejects # in pasted
command lines. Moved the explanations to prose; the bash blocks are now
paste-clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 22:12:02 +02:00
jolavillette
d0fb9d749e fix(docs): exclude Qt kegs from macOS include/lib harvest
The blanket -I$(brew --prefix)/opt/*/include harvest pulled BOTH qt (Qt6)
and qt@5 headers into the same translation unit when both are installed,
causing Qt5/Qt6 header collisions ("Qt major version not 6 or 7",
qGetPtrHelper exception-spec mismatch). Skip every qt* keg in the harvest
loop on macOS; Qt is provided explicitly via Qt6_DIR / Qt5_DIR.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 22:12:02 +02:00
jolavillette
e735aaf18c docs: add BUILD-cmake.md with CMake build instructions (Qt5/Qt6)
Per-platform (Linux/macOS/Windows) CMake build commands for the
super-project, documenting Qt5 vs Qt6 selection and the
-DCMAKE_DISABLE_FIND_PACKAGE_Qt6=ON Qt5-force switch.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 22:12:02 +02:00
csoler
3081f530ca
Merge pull request #3258 from csoler/v0.6-IdentityDialog3
added warning for identities using deprecated signature format
2026-07-08 21:33:51 +02:00
csoler
c11ae6b071
Merge pull request #3252 from jolavillette/FilterChatSystemMessages
filter joined/left system messages in chat rooms
2026-07-07 21:56:38 +02:00
jolavillette
711589283a filter joined/left system messages in chat rooms 2026-07-06 22:07:44 +02:00
Gioacchino Mazzurco
bb47e094b3
Merge pull request #3265 from jolavillette/fix/gui-own-version-macros
fix(gui): give RetroShare GUI its own version, independent from libretroshare
2026-07-05 18:20:38 +02:00
csoler
d7b9e03528
Merge pull request #3264 from jolavillette/gxstrans-normalize-date-format
Gxstrans normalize date format
2026-07-04 20:44:50 +02:00
jolavillette
dd5add516e fix(gui): give RetroShare GUI its own version, independent from libretroshare
The GUI reported RS_HUMAN_READABLE_VERSION (a libretroshare macro) as "the
RetroShare version". In the CMake build libretroshare exports RS_MAJOR_VERSION
as a PUBLIC define, so the GUI inherited the engine's version and displayed it
as its own: About showed the same number for both.

Give the GUI its own version, as discussed:

- Add retroshare-gui/src/rsguiversion.h defining RS_GUI_VERSION with a built-in
  default, so every build path (including qmake/Android) compiles even without
  version injection.
- Inject RS_GUI_VERSION from 'git describe' of the super-project in both CMake
  (retroshare-gui/CMakeLists.txt) and qmake (retroshare.pri).
- RsApplication::retroshareVersion() now returns the GUI's own version instead
  of libretroshare's.
- About (HelpDialog) shows the GUI version at the top; libretroshare's version
  is listed among the other libraries, like any dependency. AboutWidget already
  displayed both lines and is now correct automatically.

libretroshare needs no change: it already exposes its own version through
RsInit::libRetroShareVersion() in both build systems.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-04 11:40:36 +02:00
jolavillette
2b1fb920af gui: replace GxsTransportStatistics 4s auto-refresh with manual Refresh
The RsAutoUpdatePage(4000) base class polled getGroupStatistics() every
4 seconds. That call issues blocking GXS token requests (up to 5s per
group) and had no anti-reentrancy guard, so background refreshes piled
up, saturated the GXS queue and froze the whole UI.

Revert to MainPage and drive updates on demand instead:
 - a Refresh button
 - showEvent(), so the page refreshes when navigated to
 - settingsChanged(), kept so a date-format change re-renders

Date normalization (formatDateTime) is preserved.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-04 11:14:17 +02:00
jolavillette
6e6e1403be gui: format dates in GxsTransportStatistics using DateTime and enable auto-update 2026-07-04 09:47:06 +02:00
csoler
af44d4c0e6
Merge pull request #3261 from RetroShare/revert-3254-colored-links-v5
Revert "Added colored links feature"
2026-07-03 23:22:20 +02:00
csoler
6ec6de5d0f
Revert "Added colored links feature" 2026-07-03 23:13:00 +02:00
csoler
6a9c354a85
Merge pull request #3254 from defnax/colored-links-v5
Added colored links feature
2026-07-03 22:51:29 +02:00
csoler
348c9e7e94
Merge pull request #3256 from jolavillette/fix/shared-files-popular-files-crash
fix(SharedFiles): stop SIGSEGV when toggling "Popular files" after a search
2026-07-03 18:25:26 +02:00