Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
05b409a
chatdlg: replace QTextBrowser with QListView for VoiceOver accessibility
Jun 19, 2026
dde15e4
chatdlg: fix link clicks and add hover cursor in QListView
Jun 20, 2026
8b1c97a
Increase accepted length of version
softins Apr 20, 2026
8df8ac8
Translated using Weblate (Russian)
Apr 19, 2026
0fa055f
Build: Bump NSIS from 3.11 to 3.12
actions-user Apr 21, 2026
c78cf18
Update ChangeLog with missing entries
ann0see Apr 24, 2026
1a8599a
Update .ts files for r3.12.0rc1
ann0see Apr 24, 2026
bdfcd86
Update version to 3.12.0rc1 for release
ann0see Apr 24, 2026
6fee5ad
Set version to 3.11.0dev
ann0see Apr 24, 2026
fd2f3df
Revert ChangeLog to 3.11.0dev
ann0see Apr 24, 2026
618c585
Use Q_OS_BSD4 to fix FreeBSD IPv6 like macOS
softins Apr 29, 2026
06b8035
Handle differences between macOS and FreeBSD
softins Apr 29, 2026
4d38f02
Translated using Weblate (Portuguese (Brazil))
Apr 28, 2026
af13ade
Translated using Weblate (Portuguese (Brazil))
Apr 28, 2026
29bc01c
Translated using Weblate (Portuguese (Brazil))
Apr 28, 2026
162c795
Translated using Weblate (Portuguese (Brazil))
Apr 28, 2026
54d61d5
Translated using Weblate (Portuguese (Brazil))
Apr 28, 2026
a0a4e67
Translated using Weblate (Portuguese (Brazil))
melcon Apr 28, 2026
f29a4f5
Translated using Weblate (Portuguese (Brazil))
Apr 28, 2026
c752136
Add missing override specifiers
softins Apr 30, 2026
773a459
Update ChangeLog for upcoming release
ann0see May 2, 2026
f51bb3b
Update version to 3.12.0 for release
ann0see May 2, 2026
3899cf1
Set version to 3.12.0dev
ann0see May 2, 2026
41d7973
Optimize images
ImgBotApp Apr 10, 2026
86ffb07
Fix deprecation of result_of in C++17
softins May 8, 2026
314dfa6
Do not do update checks while connect dialog open
softins May 14, 2026
6cec57c
Update ChangeLog and Jamulus.pro for 3.12.1 release
pljones May 17, 2026
6926e0a
Set version to 3.12.1dev
pljones May 17, 2026
be5ddb8
Set version to 3.12.1dev
pljones May 17, 2026
9257970
make server version string searchable
dingodoppelt May 16, 2026
6ea789b
Introduce Asian directory server
ann0see May 18, 2026
144f244
Add 16-bit PCM uncompressed audio transmission
dingodoppelt Apr 17, 2026
52848bf
Add RAW_SUPPORTED protocol message and refactor client and server code
softins May 9, 2026
daf9c9f
make raw audio optional at server
dingodoppelt May 15, 2026
8ce1610
Remove unused default constructor to fix AI finding
softins May 19, 2026
c145684
Fix wrongly mentioned changelog entry (#3707)
ann0see May 20, 2026
c8b08cd
Fix some typos found by AI review
ann0see May 20, 2026
606dfb7
Default reported OS to Unix if not Linux (e.g. FreeBSD)
softins May 20, 2026
3e3facb
Move update checks and directories to jamulus.app
ann0see May 20, 2026
09631e7
Rename CENTSERV_ to DIR_ADDR_
ann0see May 20, 2026
18f62b0
chatdlg: fix VoiceOver silence by setting AccessibleTextRole and prop…
Jun 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 81 additions & 35 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,8 +1,78 @@
### 3.11.0dev <- NOTE: the release version number will be 3.12.0 ###
### 3.12.1dev <- NOTE: the release version number will be 4.0.0 ###

- Add uncompressed audio transmission - dedicated to the memory of Hans Petter Selasky (1982 - 2023)
(contributed by @dingodoppelt)

### 3.12.1 (2026-05-17) ###

- Client: Fix occasional spurious version updated message display (#3691).
(contributed by @softins)

### 3.12.0 (2026-05-02) ###

- FreeBSD: make -6 option work properly with both IPv6 and IPv4 peers (#3664).
(contributed by @softins)

- Added missing override specifiers for virtual methods (#3667).
(contributed by @softins)

- Client+Server: Correct QoS setting for IPv6 (#3622).
(contributed by @rdica)

- Tools: Updated checkkeys.pl to flag missing accelerator key in translation (#3635).
(contributed by @softins)

- Tools: Updated changelog-helper to report skipped PRs (#3639).
(contributed by @softins)

- Server/Client: Allow registration and display of longer version numbers (#3657).
(contributed by @softins)

- Extended SRV record support (#3556).
(contributed by @softins, @rdica)

- Client RPC: Added a jamulusclient/setFaderLevel method to the RPC remote interface (#3571).
(contributed by @corrados)

- Client RPC: Added jamulusclient/pollServerList methods and jamulusclient/receivedServerList notification to JSON-RPC interface (#3479).
(contributed by @ann0see)

- Server RPC: Added jamulusserver/setDirectory request (#3533).
(contributed by @pljones)

- iOS/Android: Use compact view as default view on mobile OS for better usability (#3587).
(contributed by @ann0see)

- Added link to privacy policy (#3586).
(contributed by @ann0see)

- Tools: checkkeys.pl now automatically finds the translation directory (#3590).
(contributed by @softins)

- Tools: updated checkkeys.pl to use XML::LibXML (#3558).
(contributed by @softins)

- Tools: added improvements to changelog-helper.sh (#3459).
(contributed by @softins)

- Tools: Added missing Makefile.in files to Opus 1.5.2 distro (#3488).
(contributed by @softins)

- Translation: Added Japanese translation (#3568).
(contributed by @tsukurun)

- Translation: Updated Slovak translation (#3650).
(contributed by @jose1711)

- Translations updated from Hosted Weblate (#3540, #3453, #3441, #3388, #3652, #3638, #3620, #3656, #3663).
(contributed by @weblate)

- Client: Added MIDI tab to Settings GUI exposing MIDI parameters. MIDI Learn feature also added (#3502).
(contributed by @ignotus666)

- Client: Added screen-reader accessibility to server list in the Connect dialog (#3606).
(contributed by @chigkim)

- Client: Bug: Fix missing variables passed to connect dialog (#3578).
(contributed by @ann0see)

Expand All @@ -27,30 +97,18 @@
- Client: Added native MIDI support to the ASIO (non-Jack) Windows build (#3431).
(contributed by @softins)

- Client RPC: Added a jamulusclient/setFaderLevel method to the RPC remote interface (#3571).
(contributed by @corrados)

- Client RPC: Added jamulusclient/pollServerList methods and jamulusclient/receivedServerList notification to JSON-RPC interface (#3479).
(contributed by @ann0see)

- Server: Disabled swap memory usage on Linux (#3381).
(contributed by @dtinth)

- Server: The `-m`/`--htmlstatus` option is considered deprecated and has been replaced by JSON RPC's `jamulusserver/getClients` method. The `-m` option will be removed in future (#3398).
(contributed by @ann0see)

- Server RPC: Added jamulusserver/setDirectory request (#3533).
(contributed by @pljones)

- Windows: Avoid screensaver or sleeping if connected to a server (#3498).
(contributed by @ann0see)

- Linux: Reorder service initialization to wait for network interface before starting the Server (#3440).
(contributed by @rdica)

- iOS/Android: Use compact view as default view on mobile OS for better usability (#3587).
(contributed by @ann0see)

- iOS: Fixed GUI issue preventing the connect dialog to show correctly (#3343).
(contributed by @ann0see)

Expand All @@ -75,26 +133,20 @@
- iOS: Fix crash on Qt6 after closing the chat window (#3413).
(contributed by @ann0see)

- Added Japanese translation (ja_JP) (#3568).
(contributed by @tsukurun)

- Translations updated from Hosted Weblate (#3540, #3453, #3441, #3388).
(contributed by @weblate)

- Added link to privacy policy (#3586).
(contributed by @ann0see)
- Build: Updated bundled Qt6 to version 6.10.1 (iOS 6.7.3) (#3407, #3262, #3599).
(contributed by @app/github-actions)

- Tools: checkkeys.pl now automatically finds the translation directory (#3590).
(contributed by @softins)
- Build: Updated Windows Installer base (NSIS) to version 3.11 (#3483).
(contributed by @app/github-actions)

- Tools: updated checkkeys.pl to use XML::LibXML (#3558).
(contributed by @softins)
- Build: Bump maxim-lobanov/setup-xcode from 1.6.0 to 1.7.0 (#3645).
(contributed by @app/dependabot)

- Tools: added improvements to changelog-helper.sh (#3459).
(contributed by @softins)
- Build: Bump actions/download-artifact from 7 to 8 (#3633).
(contributed by @app/dependabot)

- Tools: Added missing Makefile.in files to Opus 1.5.2 distro (#3488).
(contributed by @softins)
- Build: Bump actions/upload-artifact from 6 to 7 (#3634).
(contributed by @app/dependabot)

- Build: Improvements and ASIO fix for Windows dependencies (#3612).
(contributed by @softins)
Expand Down Expand Up @@ -123,12 +175,6 @@
- Build: Bump Qt6 from 6.10.1 to 6.10.2 (#3616).
(contributed by @app/github-actions)

- Build: Updated bundled Qt6 to version 6.9.1 (iOS 6.7.3) (#3407, #3262).
(contributed by @app/github-actions)

- Build: Updated Windows Installer base (NSIS) to version 3.11 (#3483).
(contributed by @app/github-actions)

- Build: Updated create-dmg (macOS) to version 1.2.3 (#3561).
(contributed by @app/github-actions)

Expand Down
4 changes: 2 additions & 2 deletions Jamulus.pro
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
VERSION = 3.11.0dev
VERSION = 3.12.1dev

# Using lrelease and embed_translations only works for Qt 5.12 or later.
# See https://github.com/jamulussoftware/jamulus/pull/3288 for these changes.
Expand Down Expand Up @@ -85,7 +85,7 @@ DEFINES += APP_VERSION=\\\"$$VERSION\\\" \
CUSTOM_MODES \
_REENTRANT

# some depreciated functions need to be kept for older versions to build
# some deprecated functions need to be kept for older versions to build
# TODO as soon as we drop support for the old Qt version, remove the following line
DEFINES += QT_NO_DEPRECATED_WARNINGS

Expand Down
Binary file modified android/res/drawable-hdpi/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified android/res/drawable-ldpi/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified android/res/drawable-mdpi/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified android/res/drawable-xhdpi/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified android/res/drawable-xxhdpi/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified android/res/drawable-xxxhdpi/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions src/channel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ CChannel::CChannel ( const bool bNIsServer ) :

QObject::connect ( &Protocol, &CProtocol::ClientIDReceived, this, &CChannel::ClientIDReceived );

QObject::connect ( &Protocol, &CProtocol::RawAudioSupported, this, &CChannel::RawAudioSupported );

QObject::connect ( &Protocol, &CProtocol::MuteStateHasChangedReceived, this, &CChannel::MuteStateHasChangedReceived );

QObject::connect ( &Protocol, &CProtocol::ChangeChanInfo, this, &CChannel::OnChangeChanInfo );
Expand Down
2 changes: 2 additions & 0 deletions src/channel.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ class CChannel : public QObject
}
}
void CreateClientIDMes ( const int iChanID ) { Protocol.CreateClientIDMes ( iChanID ); }
void CreateRawAudioSupportedMes() { Protocol.CreateRawAudioSupportedMes(); }
void CreateReqNetwTranspPropsMes() { Protocol.CreateReqNetwTranspPropsMes(); }
void CreateReqSplitMessSupportMes() { Protocol.CreateReqSplitMessSupportMes(); }
void CreateReqJitBufMes() { Protocol.CreateReqJitBufMes(); }
Expand Down Expand Up @@ -272,6 +273,7 @@ public slots:
void ConClientListMesReceived ( CVector<CChannelInfo> vecChanInfo );
void ChanInfoHasChanged();
void ClientIDReceived ( int iChanID );
void RawAudioSupported();
void MuteStateHasChanged ( int iChanID, bool bIsMuted );
void MuteStateHasChangedReceived ( int iChanID, bool bIsMuted );
void ReqChanInfo();
Expand Down
126 changes: 112 additions & 14 deletions src/chatdlg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,24 @@ CChatDlg::CChatDlg ( QWidget* parent ) : CBaseDlg ( parent, Qt::Window ) // use

edtLocalInputText->setAccessibleName ( tr ( "New chat text edit box" ) );

// clear chat window and edit line
txvChatWindow->clear();
// clear edit line
edtLocalInputText->clear();

// we do not want to show a cursor in the chat history
txvChatWindow->setCursorWidth ( 0 );

// set a placeholder text to make sure where to type the message in (#384)
edtLocalInputText->setPlaceholderText ( tr ( "Type a message here" ) );

// Set up the list model and delegate for accessible per-message rows ------

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Set up the list model and delegate for accessible per-message rows ------
// Set up the list model and delegate for accessible per-message rows

Check for AI artifacts like this.

m_pChatModel = new QStandardItemModel ( this );
txvChatWindow->setModel ( m_pChatModel );
txvChatWindow->setItemDelegate ( new ChatDelegate ( txvChatWindow ) );
txvChatWindow->setSelectionMode ( QAbstractItemView::SingleSelection );
txvChatWindow->setEditTriggers ( QAbstractItemView::NoEditTriggers );
txvChatWindow->setWordWrap ( true );
txvChatWindow->setResizeMode ( QListView::Adjust );
txvChatWindow->setContextMenuPolicy ( Qt::CustomContextMenu );
txvChatWindow->installEventFilter ( this );
txvChatWindow->viewport()->installEventFilter ( this );

// Menu -------------------------------------------------------------------
QMenuBar* pMenu = new QMenuBar ( this );
QMenu* pEditMenu = new QMenu ( tr ( "&Edit" ), this );
Expand All @@ -76,7 +84,7 @@ CChatDlg::CChatDlg ( QWidget* parent ) : CBaseDlg ( parent, Qt::Window ) // use

QObject::connect ( butSend, &QPushButton::clicked, this, &CChatDlg::OnSendText );

QObject::connect ( txvChatWindow, &QTextBrowser::anchorClicked, this, &CChatDlg::OnAnchorClicked );
QObject::connect ( txvChatWindow, &QListView::customContextMenuRequested, this, &CChatDlg::OnChatContextMenu );

#if defined( Q_OS_IOS )
QObject::connect ( closeAction, &QAction::triggered, this, &CChatDlg::OnCloseClicked );
Expand Down Expand Up @@ -105,15 +113,11 @@ void CChatDlg::OnSendText()

void CChatDlg::OnClearChatHistory()
{
// clear chat window
txvChatWindow->clear();
m_pChatModel->clear();
}

void CChatDlg::AddChatText ( QString strChatText )
{
// notify accessibility plugin that text has changed
QAccessible::updateAccessibility ( new QAccessibleValueChangeEvent ( txvChatWindow, strChatText ) );

// analyze strChatText to check if hyperlink (limit ourselves to http(s)://) but do not
// replace the hyperlinks if any HTML code for a hyperlink was found (the user has done the HTML
// coding hisself and we should not mess with that)
Expand All @@ -134,8 +138,49 @@ void CChatDlg::AddChatText ( QString strChatText )
"<a href=\"\\1\">\\1</a>" );
}

// add new text in chat window
txvChatWindow->append ( strChatText );
// DisplayRole stores HTML; strip tags for the accessible name so VoiceOver reads
// clean text rather than raw angle-bracket markup when navigating to this item
QTextDocument plainDoc;
plainDoc.setHtml ( strChatText );
QString strPlainText = plainDoc.toPlainText();

QStandardItem* pItem = new QStandardItem ( strChatText );
pItem->setData ( strPlainText, Qt::AccessibleTextRole );
m_pChatModel->appendRow ( pItem );
txvChatWindow->scrollToBottom();

// tell screen readers a new row exists, then announce its text as the list's
// current value — drives VoiceOver live-region-style announcement on macOS
int row = m_pChatModel->rowCount() - 1;
QAccessibleTableModelChangeEvent* pChangeEvent =
new QAccessibleTableModelChangeEvent ( txvChatWindow, QAccessibleTableModelChangeEvent::RowsInserted );
pChangeEvent->setFirstRow ( row );
pChangeEvent->setLastRow ( row );
pChangeEvent->setFirstColumn ( 0 );
pChangeEvent->setLastColumn ( 0 );
QAccessible::updateAccessibility ( pChangeEvent );
QAccessible::updateAccessibility ( new QAccessibleValueChangeEvent ( txvChatWindow, strPlainText ) );
}

void CChatDlg::OnCopyChatMessage()
{
QModelIndexList sel = txvChatWindow->selectionModel()->selectedIndexes();
if ( sel.isEmpty() )
return;
QTextDocument doc;
doc.setHtml ( sel.first().data ( Qt::DisplayRole ).toString() );
QApplication::clipboard()->setText ( doc.toPlainText() );
}

void CChatDlg::OnChatContextMenu ( const QPoint& pos )
{
QModelIndex idx = txvChatWindow->indexAt ( pos );
if ( !idx.isValid() )
return;
txvChatWindow->setCurrentIndex ( idx );
QMenu menu ( this );
menu.addAction ( tr ( "Copy message" ), this, &CChatDlg::OnCopyChatMessage );
menu.exec ( txvChatWindow->viewport()->mapToGlobal ( pos ) );
}

void CChatDlg::OnAnchorClicked ( const QUrl& Url )
Expand All @@ -153,6 +198,59 @@ void CChatDlg::OnAnchorClicked ( const QUrl& Url )
}
}

bool CChatDlg::eventFilter ( QObject* obj, QEvent* event )
{
if ( obj == txvChatWindow && event->type() == QEvent::KeyPress )
{
QKeyEvent* ke = static_cast<QKeyEvent*> ( event );
if ( ke->matches ( QKeySequence::Copy ) )
{
OnCopyChatMessage();
return true;
}
}
if ( obj == txvChatWindow->viewport() )
{
if ( event->type() == QEvent::MouseMove )
{
QMouseEvent* me = static_cast<QMouseEvent*> ( event );
QModelIndex idx = txvChatWindow->indexAt ( me->pos() );
if ( idx.isValid() )
{
QRect rect = txvChatWindow->visualRect ( idx );
QTextDocument doc;
doc.setHtml ( idx.data ( Qt::DisplayRole ).toString() );
doc.setTextWidth ( rect.width() );
QString anchor = doc.documentLayout()->anchorAt ( me->pos() - rect.topLeft() );
txvChatWindow->viewport()->setCursor ( anchor.isEmpty() ? Qt::ArrowCursor : Qt::PointingHandCursor );
}
else
{
txvChatWindow->viewport()->setCursor ( Qt::ArrowCursor );
}
}
if ( event->type() == QEvent::MouseButtonPress )
{
QMouseEvent* me = static_cast<QMouseEvent*> ( event );
QModelIndex idx = txvChatWindow->indexAt ( me->pos() );
if ( idx.isValid() )
{
QRect rect = txvChatWindow->visualRect ( idx );
QTextDocument doc;
doc.setHtml ( idx.data ( Qt::DisplayRole ).toString() );
doc.setTextWidth ( rect.width() );
QString anchor = doc.documentLayout()->anchorAt ( me->pos() - rect.topLeft() );
if ( !anchor.isEmpty() )
{
OnAnchorClicked ( QUrl ( anchor ) );
return true;
}
}
}
}
return CBaseDlg::eventFilter ( obj, event );
}

#if defined( Q_OS_IOS ) || defined( ANDROID ) || defined( Q_OS_ANDROID )
void CChatDlg::OnCloseClicked()
{
Expand All @@ -166,4 +264,4 @@ void CChatDlg::OnCloseClicked()
close();
# endif
}
#endif
#endif
Loading