We have some strong aliases/typedefs like `UserId`, `UserName`,
`EmoteName`, etc. Currently, they wrap a `QString`. In some cases, we
don't want to use owned types. Notably, when looking up items in a map.
There, it would be fine to look them up by `QStringView`. However,
`QStringView` isn't "tagged" to contain a user ID, username, etc.
This PR adds `-View` types as "tagged" versions of `QStringView`. So now
`EmoteName` has a corresponding `EmoteNameView`. The view can be created
from the owned type, and they can be compared to each other.
The containers don't know about this relationship - for example,
`std::unordered_map<EmoteName, V>` doesn't know that you can do lookup
by `EmoteNameView`. To tell them, we need to provide both a transparent
hasher (i.e. a hasher working for both types) and a transparent
comparator. For the hasher, there's `EmoteNameHash` which forwards to
the `QStringView` hash. For the comparison,
[`std::equal_to<>`](https://en.cppreference.com/cpp/utility/functional/equal_to_void)
can be used. See the tests for examples.
Reviewed-by: pajlada <rasmus.karlsson@pajlada.com>
this allows most elements to be configured with the "exhaustiveFlags"
flag which ensures that _all_ of the element's flags must be set in the
context for it to be laid out.
`parseTwitchEmotes` and `appendTwitchEmoteOccurrences` do some string
parsing. Notably they split the emote range strings
(`<emote-id>:<ranges...>/<emote-id>:...`) into owned `QString`s. They
don't have to do that.
This PR moves the parsing from using `QString`s to `QStringView`s and
using `tokenize` (lazy split) and `splitOnce`. Furthermore, the message
indices are now stack-allocated if possible and use 16 bits (enough for
Twitch messages).
Reviewed-by: pajlada <rasmus.karlsson@pajlada.com>
The nightly release is failing, because it can't update the tag.
Re-enable `persist-credentials` to make it work.
Reviewed-by: pajlada <rasmus.karlsson@pajlada.com>
To prevent issues from using GitHub actions and dependabot, I hardened
the workflows using [zizmor](https://docs.zizmor.sh/). There are still
77 open findings. I only applied the ones that are easy wins.
- Pin actions to a commit hash instead of tag - tags are not immutable
(see [`unpinned-uses`](https://docs.zizmor.sh/audits/#unpinned-uses))
- Disable `persist-credentials` on checkout - we don't need it (see
[`artipacked`](https://docs.zizmor.sh/audits/#artipacked))
- Set cooldown on dependabot updates (see
[`dependabot-cooldown`](https://docs.zizmor.sh/audits/#dependabot-cooldown)).
For our own packages, we can manually create PRs.
I left the docker images unpinned, because they're frequently updated,
but zizmor would like to see them pinned as well.
Reviewed-by: pajlada <rasmus.karlsson@pajlada.com>
When passing a `MessageElement` instead of an init table to
`Message:append_element` in a lua plugin, it would error with "Invalid
message type" suggesting that it calls `elementFromTable`, i.e. acts as
if a `MessageElementInit` table was passed.
```
Reviewed-by: Nerixyz <nerixdev@outlook.de>
Reviewed-by: pajlada <rasmus.karlsson@pajlada.com>
I noticed that the popup window was not shown when choosing `Open
channel in a new popup window` in the right-click menu of the user
avatar in the UserInfoPopup and then found that `createWindow` did not
use `args.show`. This also affected the `/popup [channel]` command.
The bug was introduced in #7058.
Reviewed-by: pajlada <rasmus.karlsson@pajlada.com>
Parent-pr: 7058
The application now provides a `connect` method to connect to all
required services (i.e. Twitch). Furthermore, the listeners for emotes
are moved to the Twitch IRC server as they belong to it.
Both are intended to make the app usable in an embedded context where
the host already runs the Qt event loop.
Reviewed-by: pajlada <rasmus.karlsson@pajlada.com>
After #6909, we can clone message elements. With this PR, we can clone
whole messages. The messages are non-frozen afterward, so plugins can
edit their properties and add/remove elements.
Reviewed-by: pajlada <rasmus.karlsson@pajlada.com>
This PR adds the ability for plugins to add actions to context menus of
ChannelViews. They can add actions, submenus and separators.
I added the signal to the `WindowManager` to allow plugins to listen to
these events in any channel.
Here's an example plugin:
```lua
c2.windows:on_channelview_context_menu_requested(function(args)
args.menu:add_action("Testing", function()
args.channel:add_system_message("Clicked!")
end)
args.menu:insert_action(1, "First!", function()
local msg = "text='" .. args.message.message_text .. "'"
if args.message_element then
msg = msg .. " element=" .. args.message_element.type
end
if args.split then
msg = msg .. " split={channel=" .. args.split.channel:get_name() .. "}"
end
args.channel:add_system_message(msg)
end)
local sub = args.menu:add_menu("Submenu")
sub:add_action("An action", function() end)
sub:add_separator()
sub:add_action("Second one", function() end)
end)
```
Reviewed-by: Mm2PL <mm2pl+gh@kotmisia.pl>
Reviewed-by: pajlada <rasmus.karlsson@pajlada.com>
This makes our plugin storage use a variant for the different plugin
states:
- UnloadedPlugin (used if the plugin's meta was invalid)
- PluginPtr (a normal valid plugin, which may still contain lua errors)
How to test the crash that doesn't crash with this PR:
Add an invalid permission in your `info.json` file
Co-authored-by: Mm2PL <mm2pl+gh@kotmisia.pl>
Added missing ellipsis (…) to menu items that open a dialog requiring
user input,
following standard HIG conventions.
Co-authored-by: Rasmus Karlsson <rasmus.karlsson@pajlada.com>
Tested-by: voiceofgrog
With Visual Studio 2026 18.6, Microsoft included a script to easily
enable the segment heap for apps
([blog](https://devblogs.microsoft.com/cppblog/segment-heap-support-for-c-projects-in-visual-studio/)).
The segment heap was already available for some years, but it hasn't
been enabled by default. With the provided script we can add a manifest
to enable it. In my basic testing it reduced the memory usage from
~75MiB to ~70MiB with one tab and 4 messages. So it should be a free win
for us.
Reviewed-by: pajlada <rasmus.karlsson@pajlada.com>
The last main part from #6906: Produce the JSON in the descriptors
instead of in the window layout. This mainly moves the content from
`encodeNodeRecursively` into `toJson` functions on the descriptors.
Reviewed-by: pajlada <rasmus.karlsson@pajlada.com>
This sets the window roles for our windows similar to what I described
in #6655. All roles are prefixed with `chatterino.` to avoid collision
in the case where we're embedded.
- Main Window: `chatterino.main`
- Popups: `chatterino.popup.{id}`
- Emote popup: `chatterino.emote-popup`
- Settings: `chatterino.settings`
- Overlay: `chatterino.overlay`
Right now, you need to pass `-session {session-id}_0` when starting, but
I hope future Qt versions add a way to set the session ID after the
`QGuiApplication` is created. Note that because of this, restoration
won't work out of the box. That's expected. You can see the session
status in the logs of `qt.qpa.wayland`.
Tested with KDE 6.7 and Qt 6.12-beta1.
Closes#6655.
Reviewed-by: pajlada <rasmus.karlsson@pajlada.com>
Reviewed-by: Mm2PL <mm2pl+gh@kotmisia.pl>
It's useful for other components to get a split descriptor from a split
(e.g. chatterino-embed). To avoid differences between the descriptor and
the JSON output (e.g. adding a field to the split data), this makes the
descriptor mandatory. Instead of going `SplitContainer* -> JSON`, we do
`SplitContainer* -> NodeDescriptor -> JSON`. In a followup, I'm going to
add `*Descriptor::toJSON`.
Reviewed-by: pajlada <rasmus.karlsson@pajlada.com>
FFZ badges consume a decent amount of memory in Chatterino. Before this
PR, they consumed 18.4 MiB.
We can do two cheap optimizations that cut the use in half:
- Use [`QVarLengthArray`](https://doc.qt.io/qt-6/qvarlengtharray.html)
to store the badges for a user instead of `std::set`. `std::set` always
allocates, even if there's only one badge. Since most users only have
one, we create many small allocations. With `QVarLengthArray<T, N>`, `N`
elements are stored inline. This reduced the memory usage to 11.9 MiB.
- Use `boost::unordered_flat_map` instead of `std::unordered_map`.
Because of relaxed requirements for the Boost map, it doesn't need to
store as much auxiliary data. This reduced the memory usage to 9.3 MiB.
A further optimization could be the use of a
`boost::container::flat_multimap<std::string, int>`. This gets us to 4.6
MiB. I haven't measured the performance of this. We'd have to assume
that FFZ returns us unique users per badge. The comparison with
`QString` for the lookup can be done by comparing `QString <
QLatin1StringView` (as we know badge IDs are latin1).
Reviewed-by: pajlada <rasmus.karlsson@pajlada.com>
Bumps
[lib/twitch-eventsub-ws/lib/date](https://github.com/HowardHinnant/date)
from `7875f43` to `179a6b9`.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/HowardHinnant/date/commit/179a6b921ccd6179b5b04dce812a89f71a51b4df"><code>179a6b9</code></a>
Update remote_version to new website</li>
<li>See full diff in <a
href="https://github.com/HowardHinnant/date/compare/7875f43aa9288d176191c83e8284d61acdd5ab7c...179a6b921ccd6179b5b04dce812a89f71a51b4df">compare
view</a></li>
</ul>
</details>
<br />
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
</details>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Since #7009, our Windows nightly builds were missing the OpenSSL TLS
plugin for Qt. Qt 6.8+ only deploys the OpenSSL plugin if it sees
`libcrypto.dll` or `libssl.dll`. However, our OpenSSL is named
`lib{ssl,crypto}-3-x64.dll`. `--force-openssl` will deploy the SSL
plugin regardless.
Reviewed-by: pajlada <rasmus.karlsson@pajlada.com>
In hopes to not land a PR for #7116, this increases the wait + timeout
as described in
https://github.com/Chatterino/chatterino2/issues/7116#issuecomment-5015316981.
I think the issue is that macOS runners on GitHub Actions are so
incredibly slow sometimes that we get these weird timings. And if that's
the cause, the overhead (e.g. from switching tasks) should be constant.
Then, if we increase the wait and timeout, we also increase the accepted
jitter (timeout - wait) from 100ms to 1s. So if the lag we get is at
about 150ms, that is now accepted.
Reviewed-by: pajlada <rasmus.karlsson@pajlada.com>
I think the text in the pinned message banner is too large in relation
to the default UI font width, so I scaled it down.
Reviewed-by: pajlada <rasmus.karlsson@pajlada.com>
Parent-pr: 7014
If the split is not 100dp wide, the calculated message height can be
wrong. If the split is larger than 100dp and the message would wrap at
that size, the widget would be too tall. And vice versa for splits
smaller than 100dp.
We do calculate the height in our resize event, but we use the size of
our children. Their resize events are delivered after we're resized. So
we check if we need to resize after we show the widget. This does result
in a small flash where the content is sized incorrectly, but better than
it being incorrect the entire time.
Parent-pr: 7014
Reviewed-by: pajlada <rasmus.karlsson@pajlada.com>