Compare commits

...

444 Commits

Author SHA1 Message Date
FwankiL
5c148d19dd
docs: added Fedora build deps (#131)
* Update README.md

added Fedora installation instructions
2023-01-04 01:01:54 +00:00
ouwou
acb03642c2
Merge pull request #124 from uowuo/keychain
store token in keychain
2022-12-18 20:52:19 +00:00
ouwou
ba2aea86f9 Merge branch 'master' into keychain 2022-12-16 19:28:39 -05:00
abdalrzag eisa
c704703b14
doc: Display CSS selectors and Settings as tables (#126) 2022-12-03 23:18:14 +00:00
Altoids1
33a329f16a
Fixes a few minor typos in the README (#127) 2022-12-02 20:59:40 +00:00
abdalrzag eisa
f0df06a795
doc: list deps for building on Arch Linux (#125) 2022-12-02 08:57:29 +00:00
ouwou
9ae41b7335 Merge branch 'master' into keychain 2022-12-01 20:00:44 -05:00
ouwou
b9fee0f6c9 Merge branch 'master' of https://github.com/uowuo/abaddon 2022-12-01 02:25:35 -05:00
ouwou
92273829bb update ci run to latest nlohmann/json release 2022-12-01 01:33:10 -05:00
abdalrzag eisa
86f6f81d9b
add missing setting (#123) 2022-12-01 00:56:22 +00:00
ouwou
573a619191 Merge branch 'master' into keychain 2022-11-29 15:53:02 -05:00
abdalrzag eisa
c5807a3463
Make README.md more readable (#120)
* More noticeable warnings
* Make CSS selectors stand out more from their description
* Make Settings options stand out more from their description, and make the default value easy to see
2022-11-15 07:47:16 +00:00
ouwou
2a9f49a148 add menu item + shortcuts to hide channel and member lists (closes #118) 2022-11-03 00:45:45 -04:00
ouwou
64245bf745 add option to autoconnect (closes #114) 2022-10-23 18:23:11 -04:00
ouwou
772598996c
Add option to hide the menu bar behind alt key (#115) 2022-10-23 02:56:07 +00:00
Addison Snelling
ccb82c1676
readme: list exact depedency package names for Ubuntu (#109)
Co-authored-by: Addison Snelling <fwd+gpg@ext.asnell.io>
2022-10-18 05:48:45 +00:00
ouwou
cd900cdfee update msys dependencies 2022-10-13 17:03:20 -04:00
ouwou
1767575728 make CURLOPT_ACCEPT_ENCODING automatic 2022-10-09 17:31:15 -04:00
ouwou
0a34c04b44 remove ability to join guilds
because 1. joining a guild seems to often require captchas now which are never going to be supported and 2. joining guilds is one of the things that upsets discords spam filter the most, so it kinda makes sense to remove anyways just like open dm
2022-10-06 03:08:54 -04:00
ouwou
7e85168576 remove a bunch of unnecessary fields from user settings 2022-10-06 02:34:45 -04:00
ouwou
3027e00905 open browser on mouse release (fixes #108) 2022-09-25 01:44:09 -04:00
ouwou
2ecbacc924 Merge branch 'master' of https://github.com/uowuo/abaddon 2022-09-09 02:52:17 -04:00
ouwou
84eb56d6b1 store user from interaction even if member is not present 2022-09-09 02:51:59 -04:00
ouwou
f3e5dcbe65 fix some potential crashes because of optionals 2022-09-09 02:40:33 -04:00
KnightMurloc
a78fdd386f
add opt-in hide to system tray icon (#99) 2022-09-09 05:03:55 +00:00
ouwou
348c1cb965 remove curl error buffer
it was useless anyways
2022-08-21 14:10:28 -04:00
ouwou
32fc7def7c fetch cookies and build number on startup 2022-08-17 01:42:30 -04:00
ouwou
14602a7384 make cmake unity build work 2022-08-16 17:34:55 -04:00
ouwou
c683ef9ad9 update msys-deps again 2022-08-15 23:24:40 -04:00
ouwou
039cc7458d copy over new dlls for win build 2022-08-14 22:32:33 -04:00
ouwou
d99f16f82d fix ci run on mac 2022-08-14 00:02:19 -04:00
dragontamer8740
243e48e609
remove unnecessary cstdio include (#101) 2022-08-14 03:36:56 +00:00
dragontamer8740
fac9f1ba58
Big-endian 'emojis.bin' decoding fix (#100)
* Big-endian patch: fixes emojis.bin reading on big-endian systems (tested only on 32-bit PowerPC linux)
2022-08-14 02:59:08 +00:00
ouwou
6a5ecb4d95 Merge branch 'attachments' 2022-08-12 18:35:58 -04:00
ouwou
dc28eae95a spoof a bunch of headers like the web client 2022-08-11 23:37:39 -04:00
ouwou
baf96da80c add copy url menu item to attachments (closes #96)
also refactor menu popup to fit over entire message width
2022-08-11 20:53:36 -04:00
ouwou
31ca6d9fd2 update capabilities and client build number 2022-08-10 23:38:12 -04:00
ouwou
04befeb180 Merge branch 'master' of https://github.com/uowuo/abaddon 2022-08-10 23:29:10 -04:00
ouwou
a4c8a2290d remove ability to create dms 2022-08-10 23:29:00 -04:00
ouwou
96ec5bb665 fix removing roles from members (maybe) 2022-08-10 23:20:27 -04:00
ouwou
f60cea2216 control icon pos in css 2022-08-10 00:03:04 -04:00
ouwou
77dd9fabfa change service clear user 2022-08-09 02:06:24 -04:00
ouwou
ee67037a3f store token in keychain 2022-08-08 23:25:34 -04:00
ouwou
b46cf53be5 add hrantzsch/keychain and link 2022-08-08 22:50:27 -04:00
ouwou
02741f2c1b remove unnecessary verbosity 2022-08-08 02:41:54 -04:00
ouwou
955b9239b9 hide browse icon when not in channel with perms 2022-08-08 00:40:20 -04:00
ouwou
53ac853367 fix some permission checks 2022-08-08 00:29:18 -04:00
ouwou
1c38671356 add SEND_MESSAGES permission check finally 2022-08-07 19:56:01 -04:00
ouwou
91527fbd0d pull chat input permission check out of signal 2022-08-07 19:54:39 -04:00
ouwou
537d4163c2 add some Get()s that i forgot somehow 2022-08-07 19:19:52 -04:00
ouwou
c0e4a3a988 give focus to input after choosing file 2022-08-07 19:18:05 -04:00
ouwou
860049fad5
Update README.md 2022-08-07 20:15:47 +00:00
ouwou
344f269414 add file picker to chat input 2022-08-07 02:16:20 -04:00
ouwou
3487353fc7 css tweaks 2022-08-07 02:14:26 -04:00
ouwou
86fc8f4186 Merge branch 'master' into attachments 2022-08-06 02:27:37 -04:00
ouwou
acb80da387 Merge branch 'master' of https://github.com/uowuo/abaddon 2022-08-06 02:23:15 -04:00
ouwou
d99d8443ee dont override expansion state because of active channel 2022-08-06 02:23:08 -04:00
dragontamer8740
319f9c392c
fixed text input box to not resize when typing (#89) 2022-08-05 04:22:59 +00:00
ouwou
a61a630ee6 handle null from std::locale::locale (fixes #88) 2022-08-03 02:27:43 -04:00
ouwou
e8260c164f stop printing every event type 2022-07-31 17:53:55 -04:00
ouwou
4e4986f670 grey out leave button if user owns the guild 2022-07-31 17:23:00 -04:00
ouwou
3610a2508b limit how often progress bar can update 2022-07-25 01:10:31 -04:00
ouwou
8396d07d9e try to align stuff a little better 2022-07-25 00:26:04 -04:00
ouwou
59acd0f82f handle max message payload + show filename label 2022-07-23 18:34:33 -04:00
ouwou
544ae6f915 fix potential deadlock 2022-07-14 04:12:17 -04:00
ouwou
111399cf4a move progress bar so it doesnt conflict with other stuff 2022-07-14 03:13:27 -04:00
ouwou
fba5cee519 try to fix compile again 2022-07-10 02:38:19 +00:00
ouwou
f95d79129e handle premium server upload size limits 2022-07-09 03:05:48 -04:00
ouwou
02ce353c6d check nitro size restriction + fix replying border 2022-07-09 01:57:56 -04:00
ouwou
241d9a2140 fix compile 2022-07-08 02:27:21 -04:00
ouwou
849ebf17f1 try to properly clear chat list
im sure this will break something somehow
2022-07-08 02:27:09 -04:00
ouwou
41776fbd02 add upload progress bar 2022-07-07 03:09:54 -04:00
ouwou
5c7631e713 fix checks for is bot 2022-07-05 03:53:00 -04:00
ouwou
41e2478a6f grab focus when adding attachment 2022-07-04 03:29:30 -04:00
ouwou
a9d35dcccd fix compile 2022-07-03 18:58:48 -04:00
ouwou
e87766f106 dnd'd files show preview images if displayable 2022-06-30 04:20:42 -04:00
ouwou
a038f47a25 add icon to attachments without preview 2022-06-23 01:51:30 -04:00
ouwou
d841a2c862 add change filename 2022-06-23 00:48:00 -04:00
ouwou
4ee7025ab0 add file upload via dnd + rework http 2022-06-17 02:46:55 -04:00
ouwou
d0fa308f6e preserve attachment insertion order 2022-06-16 01:09:54 -04:00
ouwou
4456c8771d refactor send message params into one struct 2022-06-14 02:36:04 -04:00
ouwou
caa551a469 Merge branch 'master' into attachments 2022-06-14 02:23:22 -04:00
ouwou
ccf5afbba9 Merge branch 'master' of https://github.com/uowuo/abaddon 2022-06-14 02:16:03 -04:00
ouwou
2474ffc2ba hoisted_role can be missing from guild member list update 2022-06-14 02:15:08 -04:00
ouwou
5cf4d8e160 dont use tmpnam because its stupid 2022-06-10 01:28:27 -04:00
ouwou
49ff9a249e remove temp attachment files when theyre actually done being uploaded 2022-06-09 01:48:24 -04:00
betty "reenii" bessa
abc448eca0
readme: Simplify submodule install process. (#81)
* readme: Simplify submodule install process.

Not only the linux version did not include any instructions on getting submodules (thus, attempting to follow the guide line-by-line would cause in a unavoiable cmake configure halt before even building), But the usage of `submodule init/update` in it's own can be simplified by using the `--recursive` flag directly in the clone instead.

* Only target "submodules" folder for cloning
2022-06-06 19:07:59 +00:00
ouwou
d7177cac97 remove temporary image file when attachment removed 2022-06-06 03:59:20 -04:00
ouwou
c6182e8923 only save temporary image when theres room in container 2022-06-06 03:55:25 -04:00
ouwou
270730d9b3 start attachments (image paste and upload) 2022-06-05 21:41:57 -04:00
ouwou
4ec5c1dfcc try to fix multiple attachment handling 2022-06-05 01:53:11 -04:00
Adrian Schollmeyer
da27c67e6b
Remove zipped resource archive in repo (#74)
* res: Remove zipped archive

This was probably added by accident.

* gitignore: Ignore archive files

Archives don't belong in the repo, so make sure they don't get
accidentally added again.
2022-05-23 16:55:27 +00:00
ouwou
de3b53c676 add include 2022-05-22 00:03:51 -04:00
ouwou
3ac993bae4 always quietly try and include fontconfig if present 2022-05-21 22:59:53 -04:00
ouwou
756de57919 save state per-user 2022-05-20 02:29:32 -04:00
ouwou
d9cf989813 remove thing i shouldnt have committed 2022-05-19 03:15:27 -04:00
ouwou
ffc69576f2 fix role updates (fixes #69, fixes #70) 2022-05-19 03:13:02 -04:00
ouwou
2bed7f161b only save state when actually disconnecting (fixes #65) 2022-05-17 20:47:01 -04:00
ouwou
607607ef0a update css 2022-05-16 01:17:34 -04:00
ouwou
b2ba7709df make it look sort of better i guess 2022-05-15 23:38:10 -04:00
ouwou
8b488a5ca9 add icons to dms 2022-05-11 15:05:32 -04:00
ouwou
1d8ef79da6 add ctrl+number key shortcuts for tabs 2022-05-10 01:09:42 -04:00
ouwou
bbf32730cd add ctrl(+shift)+tab keybinds 2022-05-09 01:33:09 -04:00
ouwou
f58ca39e8c request channels again if accessibility was lost 2022-05-08 02:40:27 -04:00
ouwou
3b5f4ded31 stop sending messages to inaccessible channels 2022-05-08 00:27:48 -04:00
ouwou
f6fdfeb95f compile oopsy 2022-05-06 04:13:29 -04:00
ouwou
2c25319fb8 clear tabs when access lost, show blanks for missing channels 2022-05-06 01:14:15 -04:00
ouwou
7daa0a250c Merge branch 'master' into tabs 2022-05-03 18:26:17 -04:00
ouwou
121c2585c8 improve resizing behavior (fixes #67) 2022-05-03 18:19:26 -04:00
ouwou
b18b94818a respect muted state for tab indicator 2022-05-02 02:38:41 -04:00
ouwou
63db16a711 open channel if its the first opened tab 2022-05-02 02:31:15 -04:00
ouwou
c30ab91738 add menu+accelerator for go back/forward 2022-04-27 17:40:37 -04:00
ouwou
e8f16292d1 add back/forward history to tabs
also lots of reformatting in .cmake because clion is weird and did that for some reason
2022-04-27 16:24:11 -04:00
ouwou
db28abaa44 dont show attention indicator on checked tab 2022-04-23 15:41:31 -04:00
ouwou
bfb2490938 dont expand channel list when changing tabs 2022-04-23 15:33:54 -04:00
ouwou
b4ab88f708 add opened tabs to state 2022-04-21 14:41:45 -04:00
ouwou
2dab595476 add open dm in new tab 2022-04-21 14:19:21 -04:00
ouwou
a98967fccc add ci run for minimal dependencies 2022-04-20 21:50:57 -04:00
ouwou
32e4540464 install libhandy dep on msys 2022-04-17 02:26:21 -04:00
ouwou
02dc28e89c Merge branch 'master' into tabs 2022-04-17 02:20:34 -04:00
ouwou
47545d9d32 fix menu bar updates again (fixes #61) 2022-04-15 02:14:25 -04:00
ouwou
5670dfc1d5
update nightly.link download url 2022-04-15 03:26:27 +00:00
ouwou
34f8af599d fix tab titles 2022-04-14 00:11:39 -04:00
ouwou
d36fe4d0e9 add server icons to channels 2022-04-09 03:33:56 -04:00
ouwou
44317e2d34 more tab work
- only one tab for any channel can be open
- rudimentary unread indicators
- add some css
2022-04-09 02:45:09 -04:00
ouwou
5b806a2589 basic tabs system 2022-04-08 23:47:12 -04:00
ouwou
5a13c7fef7 pull in libhandy optionally 2022-04-08 14:50:11 -04:00
ouwou
c22a49f64e no more vcpkg 2022-04-08 13:49:51 -04:00
ouwou
436024b4a0 remove mark all as read (it doesnt work on API end) 2022-04-07 20:26:15 -04:00
ouwou
61cde0f7e1 fix more menu stuff
also reformat
2022-04-07 20:18:10 -04:00
ouwou
a9399873fd fix open dm opening the wrong thing sometimes 2022-04-07 03:02:25 -04:00
ouwou
c2be1d3668 update readme
also format according to whatever jetbrains thinks is good i guess
2022-04-07 02:17:59 -04:00
ouwou
1d981d2c5a fix menus looking weird when opened for first time 2022-04-07 00:21:24 -04:00
ouwou
c2b7ca780e no more msvc builds 2022-04-06 21:15:50 -04:00
ouwou
57e95c8969 replace file chooser with native
also remove clipboard since it was just a workaround and i dont want to maintain it
2022-04-06 21:07:45 -04:00
ouwou
56a74fb5dd improve scrolling behavior again, refactor
scrolling is almost exactly how i want it, but when an existing message's height allocation is changed it still causes the scroll position to change, but its not that bad and is better than what i had before anyways so it is good enough for now. ideally if you are scrolled in the middle it will stay put completely
2022-04-06 19:58:41 -04:00
ouwou
49685c3989 fix up a bunch of clang-tidy stuff
mostly changing references, which i hope doesnt break stuff with models (TreeRow, iterators) since they gave me some strange problems in the past
2022-04-05 22:01:53 -04:00
ouwou
9767e1e7fd Merge branch 'master' into msys 2022-03-31 03:21:26 -04:00
ouwou
a83e9c01a6 improve scrolling up behavior when loading new messages 2022-03-31 03:21:07 -04:00
ouwou
7b1ceeedf4 enable fontconfig stuff on msys2 too 2022-03-31 03:06:36 -04:00
ouwou
a0b3c9f8a4 Merge branch 'master' into msys 2022-03-26 02:58:59 -04:00
ouwou
a2a45757e9 handle nicknames for message headers 2022-03-26 02:51:56 -04:00
ouwou
271d21c7bd fix UB 2022-03-05 01:01:19 -05:00
ouwou
46b88566f1 obfuscate token in input dialog 2022-03-04 23:04:07 -05:00
ouwou
af60bceada optimize sql for getting unknown member ids 2022-03-04 23:03:09 -05:00
ouwou
3583a5d251 dont request guild members if there are no user ids 2022-03-03 23:57:48 -05:00
ouwou
4503aeabc4 request when loading message history 2022-03-03 23:50:14 -05:00
ouwou
7f1d3df4a5 start sending request guild members for unknown members 2022-03-03 23:45:30 -05:00
ouwou
17f1289c84 fill out gateway op enum using internal names 2022-03-03 03:01:09 -05:00
ouwou
fc3d0fddd2 align stickers 2022-02-27 00:52:52 -05:00
ouwou
4bd5c89266 fix and refactor multiple embeds in one message 2022-02-20 01:20:19 -05:00
ouwou
a0599ab812 parse role mentions 2022-02-20 01:19:18 -05:00
ouwou
6c54296ba3 change windows environment to windows-2019 2022-02-18 01:15:45 -05:00
ouwou
7ed415040a delete database instead of trying to clear it 2022-02-17 02:14:19 -05:00
ouwou
011cb159cf Merge branch 'master' of https://github.com/uowuo/abaddon 2022-02-14 02:53:31 -05:00
ouwou
25fd2c3840 fix per-guild avatars 2022-02-14 02:53:21 -05:00
social reject
7e3976785f
Update README.md (#57)
include command to clone necessary submodules
2022-02-14 04:58:51 +00:00
ouwou
75213fcede handle multiple embeds in one message 2022-02-02 22:46:55 -05:00
ouwou
179ff980e9 fix ready parsing (#54) 2022-02-02 22:34:54 -05:00
ouwou
f784550964 support channel icons for dms 2022-02-02 22:27:19 -05:00
ouwou
ce238d08e9 add style option for unread indicator color 2022-01-28 14:46:33 -05:00
ouwou
f9864a24ed update readme 2022-01-27 00:15:26 -05:00
ouwou
738d50dd43 add setting to not show unread stuff 2022-01-26 18:44:31 -05:00
ouwou
7d49f934bc muted dms dont contribute to unread count 2022-01-26 18:43:47 -05:00
ouwou
fbb5522861 bump vcpkg 2022-01-23 20:27:08 -05:00
ouwou
0ce509f80e add settings for some colors 2022-01-21 00:41:35 -05:00
ouwou
b6b215ee6f add mark as unread/toggle mute for threads 2022-01-20 02:45:28 -05:00
ouwou
d7f3ee9f98 handle mute/unmute updates for threads 2022-01-20 01:52:48 -05:00
ouwou
2328c8bafe handle initial muted state for threads 2022-01-20 01:40:27 -05:00
ouwou
dfd642bb82 show unread indicators for threads 2022-01-20 01:34:36 -05:00
ouwou
6c9bf4ff81 add toggle mute dm menu item 2022-01-15 01:51:11 -05:00
ouwou
481685b3bb format all 2022-01-09 23:20:08 -05:00
ouwou
f31d431517 Merge branch 'unread' into msys 2022-01-08 20:11:52 -05:00
ouwou
604f2ffe3d show count of unread dms in header 2022-01-08 20:03:12 -05:00
ouwou
4e0b22375f handle mute/unmute for dms 2022-01-08 18:35:46 -05:00
ouwou
9d0c7691d8 fix initial read state for dms 2022-01-05 20:34:44 -05:00
ouwou
cef28e94ea add missing reset 2022-01-05 04:06:02 -05:00
ouwou
40106ddeb1 handle mutable categories 2022-01-05 03:52:20 -05:00
ouwou
8695562cb4 Merge branch 'master' into unread 2022-01-02 00:07:32 -05:00
ouwou
5338eab3a5 speed up connection speed a good bit
loading save state was slow so now theres a temporary lookup table
2021-12-31 16:42:06 -05:00
ouwou
d7bb6049e1 add mute/unmute guild menu item 2021-12-30 01:24:55 -05:00
ouwou
ea7464722b handle change of mute state for guilds 2021-12-29 23:51:12 -05:00
ouwou
d6da646d87 validate iso8601 when parsing to snowflake 2021-12-29 22:15:04 -05:00
ouwou
17c1f913df actually deserialize mute_config 2021-12-28 03:11:59 -05:00
ouwou
6c94e75513 take mute_config.end_time into account for muted entries 2021-12-28 02:58:31 -05:00
ouwou
801894abc6 messages sent by user shouldnt count as new unreads 2021-12-28 02:21:46 -05:00
ouwou
207c004228 take muted channels into account for unread guild indicator 2021-12-25 03:07:11 -05:00
ouwou
36f73a6106 check view permissions for channels in read state 2021-12-25 02:59:01 -05:00
ouwou
41d80af128 mark more channels as unread properly 2021-12-25 02:37:31 -05:00
ouwou
145504bdd6 add mark all as read 2021-12-22 01:44:26 -05:00
ouwou
9fd0d404a1 mark channel being switched off as read when switching 2021-12-20 02:13:18 -05:00
ouwou
b75599e55d fix bad if statement causing UB 2021-12-20 01:45:43 -05:00
ouwou
67062d6ed8 unread indicator for dm channels 2021-12-18 03:24:44 -05:00
ouwou
c43d49ed54 grey out muted channels in list 2021-12-18 02:17:43 -05:00
ouwou
e9867173c9 inline unread rendering 2021-12-18 02:06:16 -05:00
ouwou
f580535d35 add mute/unmute channel menu item 2021-12-18 01:58:29 -05:00
ouwou
1d7529e609 handle mute/unmute of channels (USER_GUILD_SETTINGS_UPDATE) 2021-12-17 02:34:14 -05:00
ouwou
1fb7ca0007 hide unread indicator for muted channels 2021-12-16 00:58:17 -05:00
ouwou
b576bd0fcc make fallback for config file go in home directory if possible (#52) 2021-12-15 17:43:11 -05:00
ouwou
f19dcc0114 Merge branch 'master' into msys 2021-12-13 00:34:19 -05:00
ouwou
38a49d172c warn if pixbufloaders arent found 2021-12-13 00:31:50 -05:00
ouwou
72935b0558 dont crash immediately if gif pixbufloader doesnt exist 2021-12-12 23:59:57 -05:00
ouwou
a5332efcfb fix compile 2021-12-12 21:14:20 -05:00
ouwou
15954830e2 hide guild unread indicator for muted guilds 2021-12-10 03:26:33 -05:00
ouwou
46ab760a56 render total mentions on guild, redraw on message create 2021-12-10 01:41:19 -05:00
ouwou
0b0135268e basic channel mentions count indicator 2021-12-10 00:15:39 -05:00
ouwou
511fb445d1 rudimentary guild unread indicator 2021-12-09 02:54:59 -05:00
ouwou
bcfb2146cd mark guild as read (shift+esc) 2021-12-08 19:12:35 -05:00
ouwou
a1b662a325 make mark guild as read actually work properly 2021-12-07 02:51:29 -05:00
ouwou
14b5bf7d0d reorder menu items 2021-12-06 17:35:44 -05:00
ouwou
d288989386 mark guild as read 2021-12-06 03:04:22 -05:00
ouwou
d63941797f mark channels as unread on MESSAGE_CREATE 2021-12-05 04:07:30 -05:00
ouwou
1ea2811713 dont send acks for channels known to be read 2021-12-05 04:00:02 -05:00
ouwou
af56784797 basic unread indicators for channels 2021-12-05 03:57:26 -05:00
ouwou
2461406887 split channel CellRenderer into its own sources 2021-12-04 02:21:08 -05:00
ouwou
8e11dd97e9 dont make requests for inaccessible channels 2021-12-01 03:42:15 -05:00
ouwou
2690febf20 fix corrupted disk image sqlite error (fixes #51) 2021-11-29 21:51:15 -05:00
ouwou
af3d278825 rename find module (fixes #50) 2021-11-29 17:16:11 -05:00
ouwou
c9647f9b33 update paths 2021-11-28 23:52:45 -05:00
ouwou
e1703aea3f merge master 2021-11-28 22:48:30 -05:00
ouwou
e02107feea actually retrieve roles for guilds
FetchRoles isnt needed anymore cuz full roles are fetched now
2021-11-28 22:42:55 -05:00
ouwou
192b043e7a fix distortion of non-1:1 emojis 2021-11-28 22:40:41 -05:00
ouwou
8c72d4c18d dont print identify message to console
mainly since i feel its only a matter of time before someone copy pastes it somewhere and itd be my fault
also typedef -> using
2021-11-25 02:57:11 -05:00
ouwou
0da913cd4a remove unnecessary copying left over from debugging 2021-11-25 02:32:39 -05:00
ouwou
fb3d69c5e7 bump build number in identify 2021-11-24 22:36:39 -05:00
ouwou
c40208ac66 update readme 2021-11-24 22:24:40 -05:00
ouwou
069c22e9cd add fetching private archived threads 2021-11-24 20:31:34 -05:00
ouwou
8f30bb33a3 fix build 2021-11-24 03:29:29 -05:00
ouwou
4326c5e29b remove SimpleIni as a dependency
use Glib::KeyFile instead which is basically the same file format
also read into and save from struct once, cuz its faster and less redundant
2021-11-24 03:15:22 -05:00
Dylam De La Torre
a51a54bc59
Restructure source and resource files (#46)
importantly, res is now res/res and css is now res/css
2021-11-23 04:21:56 +00:00
ouwou
d88079000a normalize include paths 2021-11-20 22:29:03 -05:00
ouwou
574cbc35d8 merge store 2021-11-20 18:48:15 -05:00
ouwou
fc76a15c46 fix sqlite error messages 2021-11-19 01:08:03 -05:00
ouwou
fd53a76bf6 copy compiled schemas 2021-11-18 23:41:47 -05:00
ouwou
b5c1394662 copy fonts 2021-11-18 21:32:27 -05:00
ouwou
66d7cb581c update cert path 2021-11-18 21:15:24 -05:00
ouwou
8f823420b6 more typos 2021-11-18 20:58:10 -05:00
ouwou
36d5e011e8 more fixings (hopefully) 2021-11-18 20:44:18 -05:00
ouwou
5a4bcbf377 update deps 2021-11-18 19:20:07 -05:00
ouwou
0fe007569e update deps 2021-11-18 18:59:24 -05:00
ouwou
c49e454ec0 double typo 2021-11-18 02:54:19 -05:00
ouwou
8afc8c62ef typo 2021-11-18 02:37:08 -05:00
ouwou
4644adff94 fix stuff 2021-11-18 02:22:53 -05:00
ouwou
5e08083b5a copy msys2 dependencies to artifact 2021-11-18 02:02:50 -05:00
ouwou
95a8da803a fix artifact path 2021-11-18 01:27:29 -05:00
ouwou
43a41b34bc update ixwebsocket submodule from master 2021-11-18 01:08:19 -05:00
ouwou
9c285a09e5 Merge branch 'master' of https://github.com/uowuo/abaddon into msys 2021-11-18 01:03:35 -05:00
Dylam De La Torre
9d21df8e1b
Fix warnings shown by GCC (#47)
* fix all warnings shown by GCC
2021-11-16 19:38:14 +00:00
ouwou
1da2c57376 fix retrieving message references
and also add a reset statement i forgot (raii might be good here...)
2021-11-16 02:37:12 -05:00
ouwou
409af292af Merge branch 'master' into store 2021-11-14 02:27:23 -05:00
ouwou
108002248c presence of ThreadMember means user added to private thread 2021-11-13 03:09:17 -05:00
ouwou
43795f4c87 dont call StopDiscord in destructor
since the destructor is run during static destruction it can cause issues
it's redundant anyways as StopDiscord is slotted into Gtk::Application::signal_shutdown
2021-11-13 00:25:54 -05:00
ouwou
1f68da6b77 update IXWebSocket submodule 2021-11-09 02:00:11 -05:00
ouwou
98e0e84d57 low iq moment 2021-11-09 01:23:43 -05:00
ouwou
6ddba4363a add uses 2021-11-09 01:14:38 -05:00
ouwou
b5b5c40ecd first try at actions 2021-11-09 01:13:06 -05:00
ouwou
d84fe2b800 use fontconfig setup on msys too 2021-11-09 01:01:33 -05:00
ouwou
da561ba4d5 initial msys compatibility 2021-11-09 00:55:18 -05:00
ouwou
2257ff9798 fix double close of store throwing 2021-11-06 01:10:56 -04:00
ouwou
c40b8a4122 add files that should have been pushed with last commit
oops
2021-11-04 01:48:13 -04:00
ouwou
1f445742b4 preserve channel list expansion and active channel (#36)
also check getenv in platform
2021-11-04 01:39:56 -04:00
ouwou
d629846220 Merge branch 'master' of https://github.com/uowuo/abaddon 2021-11-02 21:01:58 -04:00
ouwou
b26b2d4be0 remove channel row css classes from readme 2021-11-02 21:01:54 -04:00
South
b65c09411a
fix typo (#41) 2021-11-01 23:56:47 +00:00
ouwou
a51b813f70 some snowflake IsValid checks
mainly so i could debug something easier
2021-10-30 02:47:14 -04:00
ouwou
1078d94b73 fix big mistake that made it not run 2021-10-30 02:46:50 -04:00
ouwou
12c105623c templatize some stuff 2021-10-29 01:35:16 -04:00
ouwou
d950460e14 try to fix some more compilation errors/warnings 2021-10-28 04:19:05 -04:00
ouwou
2c2686946d try to fix weird ambiguous int stuff 2021-10-28 02:33:13 -04:00
ouwou
9175da2cf0 take care of some warnings 2021-10-28 02:19:13 -04:00
ouwou
14d025a342 dont use functions that dont actually exist 2021-10-28 02:08:29 -04:00
ouwou
c98b62caca fix syntax error 2021-10-28 00:42:04 -04:00
ouwou
d425997c26 rewrite store
this probably should have been broken up into smaller commits. oh well
2021-10-28 00:31:35 -04:00
ouwou
84b1b62e0e fix UB when all reactions on a msg are removed and one is added again 2021-10-27 03:01:53 -04:00
ouwou
b248e0ae9a set action versions 2021-10-18 23:56:36 -04:00
ouwou
f1a39c006f fix potential crash when loading channel with no messages 2021-10-16 16:54:25 -04:00
ouwou
3e34f785c6
Merge pull request #39 from Zander671/master
Fix another unchecked optional
2021-10-12 18:41:10 +00:00
Alexander Rosenberg
9694813724 Fix another unchecked optional 2021-10-12 03:30:26 -07:00
ouwou
3393526876 make ixwebsocket find module work 2021-10-11 02:10:18 -04:00
ouwou
b6424c9d37 update simpleini submodule 2021-10-11 01:40:51 -04:00
ouwou
bf560ae9d2 use find modules for ixwebsocket/simpleini 2021-10-11 01:03:31 -04:00
ouwou
fa1a007dc1 fix unchecked optionals
also discard exceptions in file cache futures
2021-10-08 17:52:38 -04:00
ouwou
abc0a7931e skip audit log entries with no target id 2021-10-06 02:57:15 -04:00
ouwou
ad523f37c5 preserve scroll position when loading history
it still jumps around a bit sometimes but its acceptable. hopefully there is a better solution
2021-10-06 02:30:30 -04:00
ouwou
cf33d53809 add relative to root #includes 2021-10-06 02:27:06 -04:00
ouwou
e8b1bcd216 remove FOUND_VAR
should also fix compilation in some situations because of sigc++
2021-10-06 00:55:21 -04:00
ouwou
dead7f2f6a fix #includes (#35) 2021-10-06 00:50:25 -04:00
ouwou
df6b01a632 dont purge on socket close 2021-09-29 01:14:33 -04:00
ouwou
9755090c8c try and fix potential crash on ROLE_UPDATE 2021-09-24 01:55:41 -04:00
ouwou
3815d97f5f use GTK emoji rendering by default on Windows 2021-09-21 01:49:36 -04:00
ouwou
7cb4a75ca7 update README with new info 2021-09-21 01:48:49 -04:00
ouwou
af85d5c895 Merge branch 'threads' 2021-09-13 01:44:43 -04:00
ouwou
b012340830 fix join guild
even though this probably isnt the best idea in a third party client...
2021-09-13 01:44:20 -04:00
ouwou
002004cb5f add notice for archived threads at top of chatwindow 2021-09-03 04:04:51 -04:00
ouwou
f3769ca301 remove archived threads from channel list on sync
this probably doesnt do anything but i added it while trying to fix something and it might work sometime i dont know
2021-09-03 03:49:25 -04:00
ouwou
07e30b9acd send channel lazy load when loading thread if not previously sent 2021-09-01 22:22:08 -04:00
ouwou
66747ec753 permissions check on archive/unarchive (oops) 2021-08-28 02:43:02 -04:00
ouwou
8ed2cd65b6 archive/unarchive from channel list 2021-08-28 02:28:41 -04:00
ouwou
3977159415 threads have pins 2021-08-27 20:29:00 -04:00
ouwou
3333e2ce8c make ClearChannel actually remove the channel from the db
so that the threads window does not show deleted threads in active
2021-08-24 23:04:11 -04:00
ouwou
ab948c29b7 fix moving rows 2021-08-24 01:51:49 -04:00
ouwou
af0cbcf2c1 dont try to open channels if they arent in store 2021-08-24 01:18:37 -04:00
ouwou
95b93a0698 dont fetch temp pending msgs from store 2021-08-24 00:30:46 -04:00
ouwou
04ebd069b4 ad-hoc MoveRow for channel list
so threads no longer disappear when a channel is moved
2021-08-23 19:15:38 -04:00
ouwou
fcb094463b fix RateLimitIndicator picking up updates from other channels 2021-08-23 02:48:56 -04:00
ouwou
b0d609d386 allow viewing all threads from within a thread 2021-08-22 01:36:49 -04:00
ouwou
69e03bbfb7 public/private filter in threads window 2021-08-22 01:21:06 -04:00
ouwou
962cda957d merge master 2021-08-21 03:53:53 -04:00
ouwou
5c63fe9487 hide pin/unpin if no perms, allow viewing pins in dm 2021-08-21 03:48:24 -04:00
ouwou
8059e524f1 fix build 2021-08-20 01:42:59 -04:00
ouwou
2a45d7173a proper member list in threads 2021-08-20 01:13:51 -04:00
ouwou
1fa3e5beac make channel in thread created message clickable 2021-08-17 23:29:48 -04:00
ouwou
2a2f96f9b6 update channel name in THREAD_UPDATE 2021-08-16 02:58:18 -04:00
ouwou
d2f6bd08fc handle archiving via THREAD_UPDATE (sorta) 2021-08-16 02:47:08 -04:00
ouwou
66c7ecf2ab emit thread delete if message req 404's 2021-08-15 02:02:56 -04:00
ouwou
e0db238cf0 removed deleted threads on sync 2021-08-15 01:36:57 -04:00
ouwou
613bb2b7c6 handle thread create via thread_member_update 2021-08-15 00:25:00 -04:00
ouwou
7ffded5b13 rest of view threads window 2021-08-11 03:32:09 -04:00
ouwou
e01110c739 add thread stuff to audit log 2021-08-05 23:50:15 -04:00
ouwou
856674506c better join/leave thread logic 2021-08-05 04:02:47 -04:00
ouwou
41a63df1b1 add temporary row for non-joined threads 2021-08-05 03:32:53 -04:00
ouwou
40897ece3c basic window to view threads 2021-08-04 21:30:32 -04:00
ouwou
a19d214272 basic THREAD_MEMBERS_UPDATE handling for updating channel list 2021-08-02 02:00:03 -04:00
ouwou
06f85c3a2d THREAD_LIST_SYNC 2021-08-02 00:53:08 -04:00
ouwou
6c77e89bbe leave thread via menu 2021-08-02 00:52:37 -04:00
ouwou
22376ba54a handle THREAD_DELETE 2021-07-30 01:32:43 -04:00
ouwou
355ef009c8 Merge branch 'master' into threads 2021-07-30 01:30:54 -04:00
ouwou
b659e3bc91 update identify message 2021-07-30 01:30:00 -04:00
ouwou
014e176e0a handle THREAD_CREATE
also fix compilation
also change channel_create signal to emit ChannelData
2021-07-28 03:34:36 -04:00
ouwou
9d2d13a389 very rudimentary thread support 2021-07-27 22:54:17 -04:00
ouwou
1936f9ab8a handle THREAD_CREATED message type 2021-07-26 02:47:20 -04:00
ouwou
ede2f53ba5 Merge branch 'channels-list' 2021-07-26 02:10:56 -04:00
ouwou
df243a40b5 let channel list manage itself instead of window 2021-07-26 00:56:14 -04:00
ouwou
30391836d0 add missing channel sign 2021-07-26 00:03:36 -04:00
ouwou
ea9dd29721 Merge branch 'resources' (closes #29) 2021-07-25 23:46:44 -04:00
ouwou
5bf48fa6c0 add animated guild icons to channel list 2021-07-23 00:35:33 -04:00
ouwou
96b8b19dd3 only make text channel mentions bold and clickable 2021-07-21 03:33:52 -04:00
ouwou
fdee6c22cf channel list: hide expanders and search 2021-07-21 03:23:45 -04:00
ouwou
4988db95bc select new channel when active channel changes
also automatically fix expander indicator when indirectly expanded
2021-07-21 02:30:46 -04:00
ouwou
a5e5954ae7 fix calculating hoisted color role
also slight optimization + make Snowflake::Invalid a real Snowflake
2021-07-21 01:29:17 -04:00
ouwou
a4d0cd9612 color nsfw channels 2021-07-20 17:55:03 -04:00
ouwou
d20a822fdb tweak text channel rendering 2021-07-19 03:07:27 -04:00
ouwou
0250229e81 less than ideal solution for category expander color 2021-07-19 01:42:55 -04:00
ouwou
8a4283edd1 add menu items 2021-07-18 03:33:16 -04:00
ouwou
e74e6f2342 fix build 2021-07-16 23:46:03 -04:00
ouwou
a30f7346f7 restore expansion cuz gtk behaves annoyingly 2021-07-14 03:14:30 -04:00
ouwou
8c3752ef9f add private channels to list 2021-07-13 20:09:01 -04:00
ouwou
f60e2cd6bd Merge branch 'master' into channels-list 2021-07-12 19:06:00 -04:00
ouwou
ccf7c414be fix ci hopefully 2021-07-12 17:36:06 -04:00
ouwou
f5e78c899a more reliable menu sensitivty/actions 2021-07-11 01:27:47 -04:00
ouwou
41bd2334fa restrict auto-reconnect to abnormal close code 2021-07-10 03:43:26 -04:00
ouwou
b2b55eb06e disconnect action should interrupt reconnect 2021-07-10 03:42:14 -04:00
ouwou
ca3eacbd79 dont use unordered collections (reduce memory a bit) 2021-07-10 03:11:59 -04:00
ouwou
fa87adb4a3 improve handling of socket close (#31) 2021-07-10 02:23:34 -04:00
ouwou
8321cd29d6 pick resources up from ~/.local/share/abaddon instead 2021-07-08 03:32:29 -04:00
ouwou
ecf8fb6a5f fix up channel row selection to work how i want it to 2021-07-06 02:38:27 -04:00
ouwou
9ec52e3473 make ChannelList directly subclass a container 2021-07-05 17:35:53 -04:00
ouwou
3565ec885e try to fix some weird behavior 2021-07-05 17:09:19 -04:00
ouwou
ab2c7bed88 tweak the arrow 2021-07-05 17:04:59 -04:00
ouwou
7b127439ea Merge branch 'master' into channels-list 2021-07-05 16:42:31 -04:00
ouwou
9f66990af2 remove reload settings menu item cuz it doesnt do anything 2021-07-05 01:58:32 -04:00
ouwou
b01a4406fa some more minor tweaking 2021-07-05 01:57:55 -04:00
ouwou
09872cf426 expand categories by default and preserve expansion 2021-07-05 00:10:05 -04:00
ouwou
87d5faf30b some refactorage 2021-07-04 02:36:12 -04:00
ouwou
c154a63967 update guild 2021-07-04 02:21:32 -04:00
ouwou
4102db1eb9 better channel update handling 2021-07-04 02:11:38 -04:00
ouwou
d0d5c655fc handle channel create 2021-07-04 01:39:56 -04:00
ouwou
716627f47d handle update channel 2021-07-03 22:09:53 -04:00
ouwou
f1504eca15 handle channel remove 2021-07-03 21:11:51 -04:00
ouwou
67c944f219 channel list: handle guild create/delete 2021-07-03 19:47:13 -04:00
ouwou
66e2311bf0 initial working better channel list 2021-07-03 19:06:49 -04:00
ouwou
90076cf689 add cmake config file for resource dir 2021-07-02 21:41:05 -04:00
ouwou
0fcd14c089 search priority of css+res to cwd, ~/.config/abaddon, then /usr/share/abaddon 2021-07-01 02:51:00 -04:00
ouwou
cbc65bf766 re-add suppport for static (a)png stickers 2021-07-01 02:03:41 -04:00
ouwou
4b089606ea add ABADDON_CONFIG environment variable 2021-06-30 21:45:26 -04:00
ouwou
f7ac0f2a1e allow config to go in ~/.config/abaddon 2021-06-30 19:21:29 -04:00
ouwou
698ec52d5c try loading resources from share, fallback to cwd 2021-06-30 18:15:03 -04:00
ouwou
220aa6d13a Merge branch 'master' of https://github.com/uowuo/abaddon 2021-06-26 03:18:59 -04:00
ouwou
9388c8926c
add an invite link to the readme woowee 2021-06-26 07:18:50 +00:00
ouwou
4d0eb756d2 get rid of something bad 2021-06-26 03:18:29 -04:00
ouwou
eab0e100c4 be more consistent with callbacks 2021-06-25 22:54:34 -04:00
ouwou
989ec06838 change how client determines if verification is needed (#28) 2021-06-24 14:31:50 -04:00
ouwou
6e75c4a95d add pin menu item to messages 2021-06-23 02:24:24 -04:00
ouwou
41d60e5e90 update pins window on pin/unpin 2021-06-23 02:09:07 -04:00
ouwou
7db2675087 fetch pins from store if already requested 2021-06-20 20:32:16 -04:00
ouwou
78f3164063 add unpin to menu, refactor a bit 2021-06-17 01:08:09 -04:00
ouwou
51fdcddaea move chat message menu into the chatlist 2021-06-16 03:53:30 -04:00
ouwou
d527669d39 pins: separate msgs, sort and store 2021-06-15 01:01:29 -04:00
ouwou
e166c83d33 basic pins window 2021-06-11 01:24:23 -04:00
ouwou
efc97aa2b0 reduce db access + refactor 2021-06-10 15:27:32 -04:00
ouwou
c73b08e341 update emojis 2021-06-09 19:01:11 -04:00
ouwou
5de40a4e61 add minsizerel configuration for windows 2021-06-04 22:00:41 -04:00
ouwou
8e58da2daf squelch warning 2021-06-04 03:15:56 -04:00
ouwou
43ea62d444 merge 2021-06-04 02:39:35 -04:00
ouwou
28b33d1b22 fix build(?) 2021-06-04 02:18:43 -04:00
ouwou
be44508316 slight reformat + fix stuff 2021-06-04 01:28:56 -04:00
ouwou
a4aab9bc16 fix potential crash in curl 2021-06-04 00:57:41 -04:00
ouwou
6dca3d9d17 idk 2021-06-04 00:12:35 -04:00
ouwou
7768401a03 bump vcpkg and hope it fixes whatever tf is happening 2021-06-03 22:39:21 -04:00
ouwou
5866836d5d allow overriding of gateway + api url 2021-06-03 19:23:33 -04:00
ouwou
c3b2bbd647 trim whitespace from token input 2021-06-03 17:31:24 -04:00
ouwou
c0c402797f update manage permissions stuff 2021-06-03 17:03:17 -04:00
ouwou
14d0968c92 basic support of per-guild avatars 2021-06-03 03:59:25 -04:00
ouwou
fe9642f1f1 minor css tweaking to fix text rendering 2021-06-03 03:40:44 -04:00
ouwou
79c00c68e5 update twemoji to 13.1 2021-05-28 22:59:55 -04:00
ouwou
c43b39fe70 add some workarounds/fixes for css stuff
adds a separate css file registered with a lower priority to allow for application-wide css while allowing the main css file to override more general selectors
2021-05-28 04:04:06 -04:00
ouwou
a4868e16e9 add custom-built gtk-compatible twemoji TTF 2021-05-26 04:29:01 -04:00
ouwou
91ed1359fc copy fonts folder 2021-05-26 03:35:16 -04:00
ouwou
484e21e693 display user bio in profile window 2021-05-26 02:50:22 -04:00
ouwou
193c2b7912 update .gitignore 2021-05-24 22:39:10 -04:00
ouwou
249d47c5f7 initial font stuff 2021-05-24 22:13:37 -04:00
ouwou
5d8209cf10 add tiny workaround for some compiler issues 2021-05-24 18:29:45 -04:00
ouwou
c75a91d15f add more granular control over emojis 2021-05-24 02:03:42 -04:00
ouwou
b2655260fa pull out chat list into a separate component 2021-05-24 01:42:04 -04:00
ouwou
a1c7d14efa some memory usage optimizations pending proper rewrite 2021-05-21 22:41:42 -04:00
ouwou
acbe03157c add certified moderator user flag 2021-05-19 23:27:22 -04:00
ouwou
72053457a0 optimize curl worker thread a good amount 2021-05-19 18:42:43 -04:00
ouwou
6a15f91a14 set main window to invalid channel when looking at friends 2021-05-14 23:43:37 -04:00
ouwou
a283ab14a2 friends: respect show animations setting 2021-05-14 23:23:01 -04:00
ouwou
1c5f912019 Merge branch 'master' into friends 2021-05-14 03:18:05 -04:00
ouwou
223a185124 clean up some unnecessary stuff 2021-05-14 03:16:52 -04:00
ouwou
f53b9742cb handle stage-related audit log action types 2021-05-14 03:08:27 -04:00
ouwou
cd97c55465 fix potential crash when displaying audit log 2021-05-14 02:44:07 -04:00
ouwou
95eb664641 friends: friends list is now in main content stack 2021-05-14 00:27:58 -04:00
ouwou
858fd8ce62 friends: accept incoming 2021-05-11 04:06:23 -04:00
ouwou
09cb0b07bb fix setting status to invisible 2021-05-10 18:26:39 -04:00
ouwou
06ba3acc93 friends: send friend requests 2021-05-10 02:13:12 -04:00
ouwou
81ae2b3a83 friends: disable friends menu item when disconnected 2021-05-10 00:07:23 -04:00
ouwou
e6a20e5984 add ability to remove relationships 2021-05-09 02:55:35 -04:00
ouwou
ae3b256746 friends: handle RELATIONSHIP_ADD events 2021-05-09 02:12:15 -04:00
ouwou
bf26e49f2c Merge branch 'master' into friends 2021-05-09 01:22:37 -04:00
ouwou
925405826a handle RELATIONSHIP_ADD 2021-05-09 01:20:48 -04:00
ouwou
a781cc76a0 friends: handle RELATIONSHIP_REMOVE events 2021-05-08 23:49:27 -04:00
ouwou
abd2b9c71e Merge branch 'master' into friends 2021-05-08 23:37:52 -04:00
ouwou
469053a144 handle RELATIONSHIP_REMOVE 2021-05-08 23:35:15 -04:00
ouwou
dd7852014f dont allow sending empty messages (fixes #27)
also add a nullptr check just in case
2021-05-07 04:09:07 -04:00
ouwou
78d3c5b679 friends: bold name & fix missing method 2021-05-07 03:55:14 -04:00
ouwou
e44484cc26 friends: handle presence updates 2021-05-07 03:04:05 -04:00
ouwou
19a2aed020 Merge branch 'master' into friends 2021-05-07 02:50:09 -04:00
ouwou
712e78b0c8 send user data over signal_presence_update 2021-05-07 02:49:59 -04:00
ouwou
d679b1af76 friends: accept menu item for incoming 2021-05-07 02:32:30 -04:00
ouwou
e2736e5806 friends: update labels 2021-05-07 02:26:17 -04:00
ouwou
762f501f2c friends: avatars 2021-05-07 02:17:25 -04:00
ouwou
86ab14e5ec start friends list 2021-05-07 01:57:08 -04:00
270 changed files with 16590 additions and 6134 deletions

View File

@ -3,56 +3,103 @@ name: Abaddon CI
on: [push, pull_request]
jobs:
windows:
name: windows-${{ matrix.buildtype }}
msys2:
name: msys2-mingw64
runs-on: windows-latest
strategy:
matrix:
buildtype: [Debug, RelWithDebInfo]
buildtype: [Debug, RelWithDebInfo, MinSizeRel]
mindeps: [false]
include:
- buildtype: RelWithDebInfo
mindeps: true
defaults:
run:
shell: msys2 {0}
steps:
- uses: actions/checkout@v1
with:
submodules: true
- name: Fetch CMake
uses: lukka/get-cmake@latest
- name: Fetch dependencies
uses: lukka/run-vcpkg@main
- name: Setup MSYS2 (1)
uses: haya14busa/action-cond@v1
id: setupmsys
with:
vcpkgArguments: gtkmm nlohmann-json zlib sqlite3 glibmm openssl ixwebsocket curl
vcpkgDirectory: ${{ github.workspace }}/ci/vcpkg/
vcpkgTriplet: x64-windows
cond: ${{ matrix.mindeps == true }}
if_true: >-
git
make
mingw-w64-x86_64-toolchain
mingw-w64-x86_64-cmake
mingw-w64-x86_64-ninja
mingw-w64-x86_64-sqlite3
mingw-w64-x86_64-nlohmann-json
mingw-w64-x86_64-curl
mingw-w64-x86_64-zlib
mingw-w64-x86_64-gtkmm3
if_false: >-
git
make
mingw-w64-x86_64-toolchain
mingw-w64-x86_64-cmake
mingw-w64-x86_64-ninja
mingw-w64-x86_64-sqlite3
mingw-w64-x86_64-nlohmann-json
mingw-w64-x86_64-curl
mingw-w64-x86_64-zlib
mingw-w64-x86_64-gtkmm3
mingw-w64-x86_64-libhandy
- name: Setup MSYS2 (2)
uses: msys2/setup-msys2@v2
with:
msystem: mingw64
update: true
install: ${{ steps.setupmsys.outputs.value }}
- name: Build
uses: lukka/run-cmake@main
with:
useVcpkgToolchainFile: true
vcpkgTriplet: x64-windows
buildDirectory: ${{ runner.workspace }}/build
cmakeBuildType: ${{ matrix.buildtype }}
- name: Setup artifact files
shell: cmd
run: |
del /f /s /q "${{ runner.workspace }}\build\CMakeFiles"
rmdir /s /q "${{ runner.workspace }}\build\CMakeFiles"
del /f /s /q "${{ runner.workspace }}\build\.ninja_deps"
del /f /s /q "${{ runner.workspace }}\build\.ninja_log"
del /f /s /q "${{ runner.workspace }}\build\abaddon.ilk"
del /f /s /q "${{ runner.workspace }}\build\CMakeCache.txt"
xcopy /E /I "${{ github.workspace }}\css" "${{ runner.workspace }}\build\css"
xcopy /E /I "${{ github.workspace }}\res" "${{ runner.workspace }}\build\res"
mkdir "${{ runner.workspace }}\build\share"
xcopy /E /I "${{ github.workspace }}\ci\gtk-for-windows\gtk-nsis-pack\share\glib-2.0" "${{ runner.workspace }}\build\share\glib-2.0"
copy "${{ github.workspace }}\ci\vcpkg\installed\x64-windows\tools\glib\gspawn-win64-helper.exe" "${{ runner.workspace }}\build\gspawn-win64-helper.exe"
copy "${{ github.workspace }}\ci\vcpkg\installed\x64-windows\tools\glib\gspawn-win64-helper-console.exe" "${{ runner.workspace }}\build\gspawn-win64-helper-console.exe"
cmake -GNinja -Bbuild -DCMAKE_BUILD_TYPE=${{ matrix.buildtype }}
cmake --build build
- name: Upload build
- name: Setup Artifact
run: |
mkdir -p build/artifactdir/bin build/artifactdir/ssl/certs build/artifactdir/lib build/artifactdir/share/glib-2.0/schemas
cd build
cp *.exe artifactdir/bin
cd ..
cp /mingw64/ssl/certs/ca-bundle.crt build/artifactdir/ssl/certs
cp -r /mingw64/lib/gdk-pixbuf-2.0 build/artifactdir/lib
cp -r res/css res/res res/fonts build/artifactdir/bin
cp /mingw64/share/glib-2.0/schemas/gschemas.compiled build/artifactdir/share/glib-2.0/schemas
cat "ci/msys-deps.txt" | sed 's/\r$//' | xargs -I % cp /mingw64% build/artifactdir/bin || :
cp /usr/bin/msys-ffi-8.dll build/artifactdir/bin/libffi-8.dll
mkdir -p build/artifactdir/share/icons/Adwaita
cd build/artifactdir/share/icons/Adwaita
mkdir -p 16x16/actions 24x24/actions 32x32/actions 48x48/actions 64x64/actions 96x96/actions scalable/actions
cd ../../../../../
cat "ci/used-icons.txt" | sed 's/\r$//' | xargs -I % cp ci/gtk-for-windows/gtk-nsis-pack/share/icons/Adwaita/16x16/actions/%.symbolic.png build/artifactdir/share/icons/Adwaita/16x16/actions || :
cat "ci/used-icons.txt" | sed 's/\r$//' | xargs -I % cp ci/gtk-for-windows/gtk-nsis-pack/share/icons/Adwaita/24x24/actions/%.symbolic.png build/artifactdir/share/icons/Adwaita/24x24/actions || :
cat "ci/used-icons.txt" | sed 's/\r$//' | xargs -I % cp ci/gtk-for-windows/gtk-nsis-pack/share/icons/Adwaita/32x32/actions/%.symbolic.png build/artifactdir/share/icons/Adwaita/32x32/actions || :
cat "ci/used-icons.txt" | sed 's/\r$//' | xargs -I % cp ci/gtk-for-windows/gtk-nsis-pack/share/icons/Adwaita/48x48/actions/%.symbolic.png build/artifactdir/share/icons/Adwaita/48x48/actions || :
cat "ci/used-icons.txt" | sed 's/\r$//' | xargs -I % cp ci/gtk-for-windows/gtk-nsis-pack/share/icons/Adwaita/64x64/actions/%.symbolic.png build/artifactdir/share/icons/Adwaita/64x64/actions || :
cat "ci/used-icons.txt" | sed 's/\r$//' | xargs -I % cp ci/gtk-for-windows/gtk-nsis-pack/share/icons/Adwaita/96x96/actions/%.symbolic.png build/artifactdir/share/icons/Adwaita/96x96/actions || :
cat "ci/used-icons.txt" | sed 's/\r$//' | xargs -I % cp ci/gtk-for-windows/gtk-nsis-pack/share/icons/Adwaita/scalable/actions/%.svg build/artifactdir/share/icons/Adwaita/scalable/actions || :
- name: Upload build (1)
uses: haya14busa/action-cond@v1
id: buildname
with:
cond: ${{ matrix.mindeps == true }}
if_true: "${{ matrix.buildtype }}-mindeps"
if_false: "${{ matrix.buildtype }}"
- name: Upload build (2)
uses: actions/upload-artifact@v2
with:
name: build-windows-${{ matrix.buildtype }}
path: ${{ runner.workspace }}/build
name: build-windows-msys2-${{ steps.buildname.outputs.value }}
path: build/artifactdir
mac:
name: macos-${{ matrix.buildtype }}
runs-on: macos-latest
@ -65,15 +112,16 @@ jobs:
submodules: true
- name: Fetch CMake
uses: lukka/get-cmake@latest
uses: lukka/get-cmake@v3.21.2
- name: Fetch dependencies
run: |
brew install gtkmm3
brew install nlohmann-json
brew install jpeg
- name: Build
uses: lukka/run-cmake@main
uses: lukka/run-cmake@v3
with:
buildDirectory: ${{ runner.workspace }}/build
cmakeBuildType: ${{ matrix.buildtype }}
@ -82,8 +130,8 @@ jobs:
run: |
mkdir "${{ runner.workspace }}/artifactdir"
cp "${{runner.workspace}}/build/abaddon" "${{ runner.workspace }}/artifactdir/abaddon"
cp -r "${{ github.workspace }}/css" "${{ runner.workspace }}/artifactdir/css"
cp -r "${{ github.workspace }}/res" "${{ runner.workspace }}/artifactdir/res"
cp -r "${{ github.workspace }}/res/css" "${{ runner.workspace }}/artifactdir/css"
cp -r "${{ github.workspace }}/res/res" "${{ runner.workspace }}/artifactdir/res"
- name: Upload build
uses: actions/upload-artifact@v2
@ -103,7 +151,7 @@ jobs:
submodules: true
- name: Fetch CMake
uses: lukka/get-cmake@latest
uses: lukka/get-cmake@v3.21.2
- name: Fetch dependencies
run: |
@ -112,7 +160,7 @@ jobs:
cd deps
git clone https://github.com/nlohmann/json
cd json
git checkout db78ac1d7716f56fc9f1b030b715f872f93964e4
git checkout bc889afb4c5bf1c0d8ee29ef35eaaf4c8bef8a5d
mkdir build
cd build
cmake ..
@ -122,7 +170,7 @@ jobs:
sudo apt-get install libcurl4-gnutls-dev
- name: Build
uses: lukka/run-cmake@main
uses: lukka/run-cmake@v3
env:
CC: gcc-9
CXX: g++-9
@ -135,8 +183,8 @@ jobs:
run: |
mkdir "${{ runner.workspace }}/artifactdir"
cp "${{runner.workspace}}/build/abaddon" "${{ runner.workspace }}/artifactdir/abaddon"
cp -r "${{ github.workspace }}/css" "${{ runner.workspace }}/artifactdir/css"
cp -r "${{ github.workspace }}/res" "${{ runner.workspace }}/artifactdir/res"
cp -r "${{ github.workspace }}/res/css" "${{ runner.workspace }}/artifactdir/css"
cp -r "${{ github.workspace }}/res/res" "${{ runner.workspace }}/artifactdir/res"
- name: Upload build
uses: actions/upload-artifact@v2

8
.gitignore vendored
View File

@ -354,3 +354,11 @@ testdata/
build/
out/
fonts/fonts.conf
# To make sure no zipped resources are added to the repo
*.7z
*.zip
*.tar.*
*.rar

18
.gitmodules vendored
View File

@ -1,15 +1,9 @@
[submodule "vcpkg"]
path = ci/vcpkg
url = https://github.com/microsoft/vcpkg/
[submodule "thirdparty/simpleini"]
path = thirdparty/simpleini
url = https://github.com/brofield/simpleini
[submodule "thirdparty/IXWebSocket"]
path = thirdparty/IXWebSocket
url = https://github.com/machinezone/ixwebsocket
[submodule "ci/vcpkg"]
path = ci/vcpkg
url = https://github.com/microsoft/vcpkg
[submodule "ci/gtk-for-windows"]
path = ci/gtk-for-windows
url = https://github.com/tschoonj/GTK-for-Windows-Runtime-Environment-Installer
[submodule "subprojects/ixwebsocket"]
path = subprojects/ixwebsocket
url = https://github.com/machinezone/ixwebsocket
[submodule "subprojects/keychain"]
path = subprojects/keychain
url = https://github.com/hrantzsch/keychain

View File

@ -2,11 +2,13 @@ cmake_minimum_required(VERSION 3.16)
project(abaddon)
set(ABADDON_RESOURCE_DIR "/usr/share/abaddon" CACHE PATH "Fallback directory for resources on Linux")
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/")
set(USE_TLS TRUE)
set(USE_OPEN_SSL TRUE)
option(USE_LIBHANDY "Enable features that require libhandy (default)" ON)
option(USE_KEYCHAIN "Store the token in the keychain (default)" ON)
find_package(nlohmann_json REQUIRED)
find_package(CURL)
@ -14,79 +16,104 @@ find_package(ZLIB REQUIRED)
find_package(SQLite3 REQUIRED)
find_package(gtkmm REQUIRED)
find_path(IXWEBSOCKET_INCLUDE_DIRS ixwebsocket/IXWebSocket.h)
find_library(IXWEBSOCKET_LIBRARY ixwebsocket)
if (NOT IXWEBSOCKET_LIBRARY)
add_subdirectory(thirdparty/IXWebSocket)
include_directories(IXWEBSOCKET_INCLUDE_DIRS)
endif()
set(USE_TLS TRUE)
set(USE_OPEN_SSL TRUE)
find_package(IXWebSocket QUIET)
if (NOT IXWebSocket_FOUND)
message("ixwebsocket was not found and will be included as a submodule")
add_subdirectory(subprojects/ixwebsocket)
include_directories(IXWEBSOCKET_INCLUDE_DIRS)
endif ()
include_directories(thirdparty/simpleini)
if (MINGW OR WIN32)
link_libraries(ws2_32)
endif ()
if(MINGW OR WIN32)
link_libraries(ws2_32)
endif()
if (WIN32)
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
add_compile_definitions(NOMINMAX)
endif ()
if(WIN32)
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
add_compile_definitions(NOMINMAX)
endif()
include(TestBigEndian)
test_big_endian(IS_BIG_ENDIAN)
if (IS_BIG_ENDIAN)
add_compile_definitions(ABADDON_IS_BIG_ENDIAN)
endif ()
file(GLOB ABADDON_SOURCES
"*.h"
"*.hpp"
"*.cpp"
"discord/*.hpp"
"discord/*.cpp"
"components/*.hpp"
"components/*.cpp"
"windows/*.hpp"
"windows/*.cpp"
"windows/guildsettings/*.hpp"
"windows/guildsettings/*.cpp"
"windows/profile/*.hpp"
"windows/profile/*.cpp"
"dialogs/*.hpp"
"dialogs/*.cpp"
)
configure_file(${PROJECT_SOURCE_DIR}/src/config.h.in ${PROJECT_BINARY_DIR}/config.h)
file(GLOB_RECURSE ABADDON_SOURCES
"src/*.h"
"src/*.hpp"
"src/*.cpp"
)
add_executable(abaddon ${ABADDON_SOURCES})
target_include_directories(abaddon PUBLIC ${PROJECT_SOURCE_DIR}/src)
target_include_directories(abaddon PUBLIC ${PROJECT_BINARY_DIR})
target_include_directories(abaddon PUBLIC ${GTKMM_INCLUDE_DIRS})
target_include_directories(abaddon PUBLIC ${ZLIB_INCLUDE_DIRS})
target_include_directories(abaddon PUBLIC ${SQLite3_INCLUDE_DIRS})
target_include_directories(abaddon PUBLIC ${NLOHMANN_JSON_INCLUDE_DIRS})
if ((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") OR
(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND
((CMAKE_SYSTEM_NAME STREQUAL "Linux") OR (CMAKE_CXX_COMPILER_VERSION LESS 9))))
target_link_libraries(abaddon stdc++fs)
endif()
(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND
((CMAKE_SYSTEM_NAME STREQUAL "Linux") OR (CMAKE_CXX_COMPILER_VERSION LESS 9))))
target_link_libraries(abaddon stdc++fs)
endif ()
if (IXWEBSOCKET_LIBRARY)
target_link_libraries(abaddon ${IXWEBSOCKET_LIBRARY})
find_library(MBEDTLS_X509_LIBRARY mbedx509)
find_library(MBEDTLS_TLS_LIBRARY mbedtls)
find_library(MBEDTLS_CRYPTO_LIBRARY mbedcrypto)
if (MBEDTLS_TLS_LIBRARY)
target_link_libraries(abaddon ${MBEDTLS_TLS_LIBRARY})
endif()
if (MBEDTLS_X509_LIBRARY)
target_link_libraries(abaddon ${MBEDTLS_X509_LIBRARY})
endif()
if (MBEDTLS_CRYPTO_LIBRARY)
target_link_libraries(abaddon ${MBEDTLS_CRYPTO_LIBRARY})
endif()
else()
target_link_libraries(abaddon $<BUILD_INTERFACE:ixwebsocket>)
endif()
if (IXWebSocket_LIBRARIES)
target_link_libraries(abaddon ${IXWebSocket_LIBRARIES})
find_library(MBEDTLS_X509_LIBRARY mbedx509)
find_library(MBEDTLS_TLS_LIBRARY mbedtls)
find_library(MBEDTLS_CRYPTO_LIBRARY mbedcrypto)
if (MBEDTLS_TLS_LIBRARY)
target_link_libraries(abaddon ${MBEDTLS_TLS_LIBRARY})
endif ()
if (MBEDTLS_X509_LIBRARY)
target_link_libraries(abaddon ${MBEDTLS_X509_LIBRARY})
endif ()
if (MBEDTLS_CRYPTO_LIBRARY)
target_link_libraries(abaddon ${MBEDTLS_CRYPTO_LIBRARY})
endif ()
else ()
target_link_libraries(abaddon $<BUILD_INTERFACE:ixwebsocket>)
endif ()
find_package(Threads)
if (Threads_FOUND)
target_link_libraries(abaddon Threads::Threads)
endif()
target_link_libraries(abaddon Threads::Threads)
endif ()
find_package(Fontconfig QUIET)
if (Fontconfig_FOUND)
target_link_libraries(abaddon Fontconfig::Fontconfig)
endif ()
target_link_libraries(abaddon ${SQLite3_LIBRARIES})
target_link_libraries(abaddon ${GTKMM_LIBRARIES})
target_link_libraries(abaddon ${CURL_LIBRARIES})
target_link_libraries(abaddon ${ZLIB_LIBRARY})
target_link_libraries(abaddon ${NLOHMANN_JSON_LIBRARIES})
if (USE_LIBHANDY)
find_package(libhandy)
if (NOT libhandy_FOUND)
message("libhandy could not be found. features requiring it have been disabled")
set(USE_LIBHANDY OFF)
else ()
target_include_directories(abaddon PUBLIC ${libhandy_INCLUDE_DIRS})
target_link_libraries(abaddon ${libhandy_LIBRARIES})
target_compile_definitions(abaddon PRIVATE WITH_LIBHANDY)
endif ()
endif ()
if (USE_KEYCHAIN)
find_package(keychain QUIET)
if (NOT keychain_FOUND)
message("keychain was not found and will be included as a submodule")
add_subdirectory(subprojects/keychain)
target_link_libraries(abaddon keychain)
target_compile_definitions(abaddon PRIVATE WITH_KEYCHAIN)
endif ()
endif ()

375
README.md
View File

@ -4,12 +4,16 @@ Alternative Discord client made in C++ with GTK
<img src="/.readme/s3.png">
<a href="https://discord.gg/wkCU3vuzG5"><img src="https://discord.com/api/guilds/858156817711890443/widget.png?style=shield"></a>
Current features:
* Not Electron
* Handles most types of chat messages including embeds, images, and replies
* Completely styleable/customizable with CSS (if you have a system GTK theme it won't really use it though)
* Identifies to gateway as the web client unlike other clients so less likely to be falsely flagged as spam<sup>1</sup>
* Identifies to Discord as the web client unlike other clients so less likely to be falsely flagged as spam<sup>1</sup>
* Set status
* Unread and mention indicators
* Start new DMs and group DMs
* View user profiles (notes, mutual servers, mutual friends)
* Kick, ban, and unban members
@ -18,176 +22,279 @@ Current features:
* Manage emojis
* View audit log
* Emojis<sup>2</sup>
* Thread support<sup>3</sup>
* Animated avatars, server icons, emojis (can be turned off)
1 - Other third-party clients send the IDENTIFY message that bots use which makes Discord more likely to think you are selfbotting or spamming. However, Discord still loves to ban people's accounts for no good reason, even users of the official clients. If you want to be really careful avoid joining servers really fast or cold DMing people.
2 - Getting emojis to function properly on GTK is still something I've yet to figure out ([#5](../../issues/5)). Unicode emojis are manually searched for and replaced in several places as opposed to allowing GTK to figure it out since GTK's way of doing it doesn't work very well.
1 - Abaddon tries its best (though is not perfect) to make Discord think it's a legitimate web client. Some of the
things done to do this
include: using a browser user agent, sending the same IDENTIFY message that the official web client does, using API v9
endpoints in all cases, and not using endpoints the web client does not normally use. There are still a few smaller
inconsistencies, however. For example the web client sends lots of telemetry via the `/science` endpoint (uBlock origin
stops this) as well as in the headers of all requests.<br>
**See [here](#the-spam-filter)** for things you might want to avoid if you are worried about being caught in the spam
filter.
2 - Unicode emojis are substituted manually as opposed to rendered by GTK on non-Windows platforms. This can be changed
with the `stock_emojis` setting as shown at the bottom of this README. A CBDT-based font using Twemoji is provided to
allow GTK to render emojis natively on Windows.
3 - There are some inconsistencies with thread state that might be encountered in some more uncommon cases, but they are
the result of fundamental issues with Discord's thread implementation.
### Building manually (recommended if not on Windows):
#### Windows:
1. `git clone https://github.com/uowuo/abaddon && cd abaddon`
2. `vcpkg install gtkmm:x64-windows nlohmann-json:x64-windows ixwebsocket:x64-windows zlib:x64-windows simpleini:x64-windows sqlite3:x64-windows openssl:x64-windows curl:x64-windows`
#### Windows (with MSYS2):
1. Install following packages:
* mingw-w64-x86_64-cmake
* mingw-w64-x86_64-ninja
* mingw-w64-x86_64-sqlite3
* mingw-w64-x86_64-nlohmann-json
* mingw-w64-x86_64-curl
* mingw-w64-x86_64-zlib
* mingw-w64-x86_64-gtkmm3
* mingw-w64-x86_64-libhandy
2. `git clone --recurse-submodules="subprojects" https://github.com/uowuo/abaddon && cd abaddon`
3. `mkdir build && cd build`
4. `cmake -G"Visual Studio 16 2019" -A x64 -DCMAKE_TOOLCHAIN_FILE=c:\path\to\vcpkg\scripts\buildsystems\vcpkg.cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DVCPKG_TARGET_TRIPLET=x64-windows ..`
5. Build with Visual Studio
Or, do steps 1 and 2, and open CMakeLists.txt in Visual Studio if `vcpkg integrate install` was run
4. `cmake -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo ..`
5. `ninja`
#### Mac:
1. `git clone https://github.com/uowuo/abaddon && cd abaddon`
2. `brew install gtkmm3 nlohmann-json`
1. `git clone https://github.com/uowuo/abaddon --recurse-submodules="subprojects" && cd abaddon`
2. `brew install gtkmm3 nlohmann-json libhandy`
3. `mkdir build && cd build`
4. `cmake ..`
5. `make`
#### Linux:
1. Install dependencies: `libgtkmm-3.0-dev`, `libcurl4-gnutls-dev`, and [nlohmann-json](https://github.com/nlohmann/json)
2. `git clone https://github.com/uowuo/abaddon && cd abaddon`
1. Install dependencies
* On Ubuntu 20.04 (Focal) and newer:
```Shell
$ sudo apt install g++ cmake libgtkmm-3.0-dev libcurl4-gnutls-dev libsqlite3-dev libssl-dev nlohmann-json3-dev
```
* On Arch Linux
```Shell
$ sudo pacman -S gcc cmake gtkmm3 libcurl-gnutls lib32-sqlite lib32-openssl nlohmann-json libhandy
```
* On Fedora Linux:
```Shell
$ sudo dnf install g++ cmake gtkmm3.0-devel libcurl-devel sqlite-devel openssl-devel json-devel libsecret-devel libhandy-devel
```
2. `git clone https://github.com/uowuo/abaddon --recurse-submodules="subprojects" && cd abaddon`
3. `mkdir build && cd build`
4. `cmake ..`
5. `make`
### Downloads (from CI):
- Windows: [here](https://nightly.link/uowuo/abaddon/workflows/ci/master/build-windows-RelWithDebInfo.zip)
- MacOS: [here](https://nightly.link/uowuo/abaddon/workflows/ci/master/build-macos-RelWithDebInfo.zip) unsigned, unpackaged, requires gtkmm3 (e.g. from homebrew)
- Linux: [here](https://nightly.link/uowuo/abaddon/workflows/ci/master/build-linux-MinSizeRel.zip) unpackaged (for now), requires gtkmm3. built on Ubuntu 18.04 + gcc9
### Downloads:
⚠️ Make sure you start from the directory where `css` and `res` are or else stuff will be broken
Latest release version: https://github.com/uowuo/abaddon/releases/latest
**CI:**
- Windows: [here](https://nightly.link/uowuo/abaddon/workflows/ci/master/build-windows-msys2-MinSizeRel.zip)
- MacOS: [here](https://nightly.link/uowuo/abaddon/workflows/ci/master/build-macos-RelWithDebInfo.zip) unsigned,
unpackaged, requires gtkmm3 (e.g. from homebrew)
- Linux: [here](https://nightly.link/uowuo/abaddon/workflows/ci/master/build-linux-MinSizeRel.zip) unpackaged (for now),
requires gtkmm3. built on Ubuntu 18.04 + gcc9
> **Warning**: If you use Windows, make sure to start from the `bin` directory
On Linux, `css` and `res` can also be loaded from `~/.local/share/abaddon` or `/usr/share/abaddon`
`abaddon.ini` will also be automatically used if located at `~/.config/abaddon/abaddon.ini` and there is
no `abaddon.ini` in the working directory
#### The Spam Filter
Discord likes disabling accounts/forcing them to reset their passwords if they think the user is a spam bot or
potentially had their account compromised. While the official client still often gets users caught in the spam filter,
third party clients tend to upset the spam filter more often. If you get caught by it, you can
usually [appeal](https://support.discord.com/hc/en-us/requests/new?ticket_form_id=360000029731) it and get it restored.
Here are some things you might want to do with the official client instead if you are particularly afraid of evoking the
spam filter's wrath:
* Joining or leaving servers (usually main cause of getting caught)
* Frequently disconnecting and reconnecting
* Starting new DMs with people
* Managing your friends list
* Managing your user profile while connected to a third party client
#### Dependencies:
#### Dependencies:
* [gtkmm](https://www.gtkmm.org/en/)
* [JSON for Modern C++](https://github.com/nlohmann/json)
* [IXWebSocket](https://github.com/machinezone/IXWebSocket)
* [libcurl](https://curl.se/)
* [zlib](https://zlib.net/)
* [simpleini](https://github.com/brofield/simpleini)
* [SQLite3](https://www.sqlite.org/index.html)
* [libhandy](https://gnome.pages.gitlab.gnome.org/libhandy/) (optional)
### TODO:
* Voice support
* Unread indicators
* User activities
* Nicknames
* More server management stuff
* Manage friends
* A bunch of other stuff
### Styling
#### CSS selectors
.app-window - Applied to all windows. This means the main window and all popups
.app-popup - Additional class for `.app-window`s when the window is not the main window
.channel-list - Container of the channel list
.channel-row - All rows within the channel container
.channel-row-channel - Only rows containing a channel
.channel-row-category - Only rows containing a category
.channel-row-guild - Only rows containing a guild
.channel-row-label - All labels within the channel container
.nsfw - Applied to channel row labels and their container for NSFW channels
.messages - Container of user messages
.message-container - The container which holds a user's messages
.message-container-author - The author label for a message container
.message-container-timestamp - The timestamp label for a message container
.message-container-avatar - Avatar for a user in a message
.message-container-extra - Label containing BOT/Webhook
.message-text - The text of a user message
.pending - Extra class of .message-text for messages pending to be sent
.failed - Extra class of .message-text for messages that failed to be sent
.message-attachment-box - Contains attachment info
.message-reply - Container for the replied-to message in a reply (these elements will also have .message-text set)
.message-input - Applied to the chat input container
.replying - Extra class for chat input container when a reply is currently being created
.reaction-box - Contains a reaction image and the count
.reacted - Additional class for reaction-box when the user has reacted with a particular reaction
.reaction-count - Contains the count for reaction
.completer - Container for the message completer
.completer-entry - Container for a single entry in the completer
.completer-entry-label - Contains the label for an entry in the completer
.completer-entry-image - Contains the image for an entry in the completer
.embed - Container for a message embed
.embed-author - The author of an embed
.embed-title - The title of an embed
.embed-description - The description of an embed
.embed-field-title - The title of an embed field
.embed-field-value - The value of an embed field
.embed-footer - The footer of an embed
.members - Container of the member list
.members-row - All rows within the members container
.members-row-label - All labels in the members container
.members-row-member - Rows containing a member
.members-row-role - Rows containing a role
.members-row-avatar - Contains the avatar for a row in the member list
.status-indicator - The status indicator
.online - Applied to status indicators when the associated user is online
.idle - Applied to status indicators when the associated user is away
.dnd - Applied to status indicators when the associated user is on do not disturb
.offline - Applied to status indicators when the associated user is offline
.typing-indicator - The typing indicator (also used for replies)
Used in reorderable list implementation:
.drag-icon
.drag-hover-top
.drag-hover-bottom
Used in guild settings popup:
.guild-settings-window
.guild-members-pane-list - Container for list of members in the members pane
.guild-members-pane-info - Container for member info
.guild-roles-pane-list - Container for list of roles in the roles pane
Used in profile popup:
.mutual-friend-item - Applied to every item in the mutual friends list
.mutual-friend-item-name - Name in mutual friend item
.mutual-friend-item-avatar - Avatar in mutual friend item
.mutual-guild-item - Applied to every item in the mutual guilds list
.mutual-guild-item-name - Name in mutual guild item
.mutual-guild-item-icon - Icon in mutual guild item
.mutual-guild-item-nick - User nickname in mutual guild item
.profile-connection - Applied to every item in the user connections list
.profile-connection-label - Label in profile connection item
.profile-connection-check - Checkmark in verified profile connection items
.profile-connections - Container for profile connections
.profile-notes - Container for notes in profile window
.profile-notes-label - Label that says "NOTE"
.profile-notes-text - Actual note text
.profile-info-pane - Applied to container for info section of profile popup
.profile-info-created - Label for creation date of profile
.user-profile-window
.profile-main-container - Inner container for profile
.profile-avatar
.profile-username
.profile-switcher - Buttons used to switch viewed section of profile
.profile-stack - Container for profile info that can be switched between
.profile-badges - Container for badges
.profile-badge
#### CSS selectors
| Selector | Description |
|--------------------------------|---------------------------------------------------------------------------------------------------|
| `.app-window` | Applied to all windows. This means the main window and all popups |
| `.app-popup` | Additional class for `.app-window`s when the window is not the main window |
| `.channel-list` | Container of the channel list |
| `.messages` | Container of user messages |
| `.message-container` | The container which holds a user's messages |
| `.message-container-author` | The author label for a message container |
| `.message-container-timestamp` | The timestamp label for a message container |
| `.message-container-avatar` | Avatar for a user in a message |
| `.message-container-extra` | Label containing BOT/Webhook |
| `.message-text` | The text of a user message |
| `.pending` | Extra class of .message-text for messages pending to be sent |
| `.failed` | Extra class of .message-text for messages that failed to be sent |
| `.message-attachment-box` | Contains attachment info |
| `.message-reply` | Container for the replied-to message in a reply (these elements will also have .message-text set) |
| `.message-input` | Applied to the chat input container |
| `.replying` | Extra class for chat input container when a reply is currently being created |
| `.reaction-box` | Contains a reaction image and the count |
| `.reacted` | Additional class for reaction-box when the user has reacted with a particular reaction |
| `.reaction-count` | Contains the count for reaction |
| `.completer` | Container for the message completer |
| `.completer-entry` | Container for a single entry in the completer |
| `.completer-entry-label` | Contains the label for an entry in the completer |
| `.completer-entry-image` | Contains the image for an entry in the completer |
| `.embed` | Container for a message embed |
| `.embed-author` | The author of an embed |
| `.embed-title` | The title of an embed |
| `.embed-description` | The description of an embed |
| `.embed-field-title` | The title of an embed field |
| `.embed-field-value` | The value of an embed field |
| `.embed-footer` | The footer of an embed |
| `.members` | Container of the member list |
| `.members-row` | All rows within the members container |
| `.members-row-label` | All labels in the members container |
| `.members-row-member` | Rows containing a member |
| `.members-row-role` | Rows containing a role |
| `.members-row-avatar` | Contains the avatar for a row in the member list |
| `.status-indicator` | The status indicator |
| `.online` | Applied to status indicators when the associated user is online |
| `.idle` | Applied to status indicators when the associated user is away |
| `.dnd` | Applied to status indicators when the associated user is on do not disturb |
| `.offline` | Applied to status indicators when the associated user is offline |
| `.typing-indicator` | The typing indicator (also used for replies) |
Used in reorderable list implementation:
| Selector |
|----------------------|
| `.drag-icon` |
| `.drag-hover-top` |
| `.drag-hover-bottom` |
Used in guild settings popup:
| Selector | Description |
|----------------------------|---------------------------------------------------|
| `.guild-settings-window` | Container for list of members in the members pane |
| `.guild-members-pane-list` | |
| `.guild-members-pane-info` | Container for member info |
| `.guild-roles-pane-list` | Container for list of roles in the roles pane |
Used in profile popup:
| Selector | Description |
|------------------------------|---------------------------------------------------------|
| `.mutual-friend-item` | Applied to every item in the mutual friends list |
| `.mutual-friend-item-name` | Name in mutual friend item |
| `.mutual-friend-item-avatar` | Avatar in mutual friend item |
| `.mutual-guild-item` | Applied to every item in the mutual guilds list |
| `.mutual-guild-item-name` | Name in mutual guild item |
| `.mutual-guild-item-icon` | Icon in mutual guild item |
| `.mutual-guild-item-nick` | User nickname in mutual guild item |
| `.profile-connection` | Applied to every item in the user connections list |
| `.profile-connection-label` | Label in profile connection item |
| `.profile-connection-check` | Checkmark in verified profile connection items |
| `.profile-connections` | Container for profile connections |
| `.profile-notes` | Container for notes in profile window |
| `.profile-notes-label` | Label that says "NOTE" |
| `.profile-notes-text` | Actual note text |
| `.profile-info-pane` | Applied to container for info section of profile popup |
| `.profile-info-created` | Label for creation date of profile |
| `.user-profile-window` | |
| `.profile-main-container` | Inner container for profile |
| `.profile-avatar` | |
| `.profile-username` | |
| `.profile-switcher` | Buttons used to switch viewed section of profile |
| `.profile-stack` | Container for profile info that can be switched between |
| `.profile-badges` | Container for badges |
| `.profile-badge` | |
### Settings
Settings are configured (for now) by editing abaddon.ini
You should edit these while the client is closed even though there's an option to reload while running
This listing is organized by section.
Settings are configured (for now) by editing `abaddon.ini`.
The format is similar to the standard Windows ini format **except**:
* `#` is used to begin comments as opposed to `;`
* Section and key names are case-sensitive
> **Warning**: You should edit these while the client is closed, even though there's an option to reload while running.
This listing is organized by section.
For example, memory_db would be set by adding `memory_db = true` under the line `[discord]`
#### discord
* memory_db (true or false, default false) - if true, Discord data will be kept in memory as opposed to on disk
* token (string) - Discord token used to login, this can be set from the menu
* prefetch (true or false, default false) - if true, new messages will cause the avatar and image attachments to be automatically downloaded
| Setting | Type | Default | Description |
|---------------|---------|---------|--------------------------------------------------------------------------------------------------|
| `gateway` | string | | override url for Discord gateway. must be json format and use zlib stream compression |
| `api_base` | string | | override base url for Discord API |
| `memory_db` | boolean | false | if true, Discord data will be kept in memory as opposed to on disk |
| `token` | string | | Discord token used to login, this can be set from the menu |
| `prefetch` | boolean | false | if true, new messages will cause the avatar and image attachments to be automatically downloaded |
| `autoconnect` | boolean | false | autoconnect to discord |
#### http
* user_agent (string) - sets the user-agent to use in HTTP requests to the Discord API (not including media/images)
* concurrent (int, default 10) - how many images can be concurrently retrieved
| Setting | Type | Default | Description |
|--------------|--------|---------|---------------------------------------------------------------------------------------------|
| `user_agent` | string | | sets the user-agent to use in HTTP requests to the Discord API (not including media/images) |
| `concurrent` | int | 20 | how many images can be concurrently retrieved |
#### gui
* member_list_discriminator (true or false, default true) - show user discriminators in the member list
* emojis (true or false, default true) - resolve unicode and custom emojis to images. this needs to be false to allow GTK to render emojis by itself
* css (string) - path to the main CSS file
* animations (true or false, default true) - use animated images where available (e.g. server icons, emojis, avatars). false means static images will be used
* owner_crown (true or false, default true) - show a crown next to the owner
#### misc
* linkcolor (string) - color to use for links in messages
| Setting | Type | Default | Description |
|-----------------------------|---------|---------|----------------------------------------------------------------------------------------------------------------------------|
| `member_list_discriminator` | boolean | true | show user discriminators in the member list |
| `stock_emojis` | boolean | true | allow abaddon to substitute unicode emojis with images from emojis.bin, must be false to allow GTK to render emojis itself |
| `custom_emojis` | boolean | true | download and use custom Discord emojis |
| `css` | string | | path to the main CSS file |
| `animations` | boolean | true | use animated images where available (e.g. server icons, emojis, avatars). false means static images will be used |
| `animated_guild_hover_only` | boolean | true | only animate guild icons when the guild is being hovered over |
| `owner_crown` | boolean | true | show a crown next to the owner |
| `unreads` | boolean | true | show unread indicators and mention badges |
| `save_state` | boolean | true | save the state of the gui (active channels, tabs, expanded channels) |
| `alt_menu` | boolean | false | keep the menu hidden unless revealed with alt key |
| `hide_to_tray` | boolean | false | hide abaddon to the system tray on window close |
#### style
| Setting | Type | Description |
|-------------------------|--------|-----------------------------------------------------|
| `linkcolor` | string | color to use for links in messages |
| `expandercolor` | string | color to use for the expander in the channel list |
| `nsfwchannelcolor` | string | color to use for NSFW channels in the channel list |
| `channelcolor` | string | color to use for SFW channels in the channel list |
| `mentionbadgecolor` | string | background color for mention badges |
| `mentionbadgetextcolor` | string | color to use for number displayed on mention badges |
| `unreadcolor` | string | color to use for the unread indicator |
### Environment variables
| variable | Description |
|------------------|------------------------------------------------------------------------------|
| `ABADDON_NO_FC` | (Windows only) don't use custom font config |
| `ABADDON_CONFIG` | change path of configuration file to use. relative to cwd or can be absolute |

59
ci/msys-deps.txt Normal file
View File

@ -0,0 +1,59 @@
/bin/gdbus.exe
/bin/gspawn-win64-helper-console.exe
/bin/libatk-1.0-0.dll
/bin/libatkmm-1.6-1.dll
/bin/libbrotlicommon.dll
/bin/libbrotlidec.dll
/bin/libbz2-1.dll
/bin/libcairo-2.dll
/bin/libcairo-gobject-2.dll
/bin/libcairomm-1.0-1.dll
/bin/libcrypto-1_1-x64.dll
/bin/libcurl-4.dll
/bin/libdatrie-1.dll
/bin/libdeflate.dll
/bin/libepoxy-0.dll
/bin/libexpat-1.dll
/bin/libffi-8.dll
/bin/libfontconfig-1.dll
/bin/libfreetype-6.dll
/bin/libfribidi-0.dll
/bin/libgcc_s_seh-1.dll
/bin/libgdk-3-0.dll
/bin/libgdk_pixbuf-2.0-0.dll
/bin/libgdkmm-3.0-1.dll
/bin/libgio-2.0-0.dll
/bin/libgiomm-2.4-1.dll
/bin/libglib-2.0-0.dll
/bin/libglibmm-2.4-1.dll
/bin/libgmodule-2.0-0.dll
/bin/libgobject-2.0-0.dll
/bin/libgraphite2.dll
/bin/libgtk-3-0.dll
/bin/libgtkmm-3.0-1.dll
/bin/libhandy-1-0.dll
/bin/libharfbuzz-0.dll
/bin/libiconv-2.dll
/bin/libidn2-0.dll
/bin/libintl-8.dll
/bin/libnghttp2-14.dll
/bin/libpango-1.0-0.dll
/bin/libpangocairo-1.0-0.dll
/bin/libpangoft2-1.0-0.dll
/bin/libpangomm-1.4-1.dll
/bin/libpangowin32-1.0-0.dll
/bin/libpcre2-8-0.dll
/bin/libpixman-1-0.dll
/bin/libpng16-16.dll
/bin/libpsl-5.dll
/bin/libsigc-2.0-0.dll
/bin/libsqlite3-0.dll
/bin/libssh2-1.dll
/bin/libssl-1_1-x64.dll
/bin/libstdc++-6.dll
/bin/libthai-0.dll
/bin/libunistring-2.dll
/bin/libwinpthread-1.dll
/bin/libzstd.dll
/bin/zlib1.dll
/../usr/bin/msys-2.0.dll

1
ci/used-icons.txt Normal file
View File

@ -0,0 +1 @@
document-send-symbolic

@ -1 +0,0 @@
Subproject commit 50ea8c0ab7aca3bb9245bba7fc877ad2f2a4464c

View File

@ -31,7 +31,6 @@ set(HARFBUZZ_INCLUDE_DIRS ${HARFBUZZ_INCLUDE_DIR};${HARFBUZZ_CONFIG_INCLUDE_DIRS
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(HarfBuzz
FOUND_VAR HARFBUZZ_FOUND
REQUIRED_VARS
HARFBUZZ_LIBRARY
HARFBUZZ_INCLUDE_DIR

View File

@ -0,0 +1,30 @@
set(IXWebSocket_LIBRARY_NAME ixwebsocket)
find_path(IXWebSocket_INCLUDE_DIR
NAMES ixwebsocket/IXWebSocket.h
HINTS /usr/include
/usr/local/include
/opt/local/include
PATH_SUFFIXES ${IXWebSocket_LIBRARY_NAME})
find_library(IXWebSocket_LIBRARY
NAMES ${IXWebSocket_LIBRARY_NAME}
PATH_SUFFIXES ${IXWebSocket_LIBRARY_NAME}
${IXWebSocket_LIBRARY_NAME}/include)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(IXWebSocket
REQUIRED_VARS
IXWebSocket_LIBRARY
IXWebSocket_INCLUDE_DIR)
mark_as_advanced(IXWebSocket_LIBRARY IXWebSocket_INCLUDE_DIR)
if (IXWebSocket_FOUND)
find_package(OpenSSL QUIET)
set(IXWebSocket_INCLUDE_DIRS "${IXWebSocket_INCLUDE_DIR};${OPENSSL_INCLUDE_DIR}")
set(IXWebSocket_LIBRARIES "${IXWebSocket_LIBRARY};${OPENSSL_LIBRARIES}")
endif()

View File

@ -31,7 +31,6 @@ set(ATK_INCLUDE_DIRS ${ATK_INCLUDE_DIR};${ATK_CONFIG_INCLUDE_DIRS})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(atk
FOUND_VAR ATK_FOUND
REQUIRED_VARS
ATK_LIBRARY
ATK_INCLUDE_DIR

View File

@ -42,7 +42,6 @@ set(ATKMM_INCLUDE_DIRS ${ATKMM_INCLUDE_DIR};${ATKMM_CONFIG_INCLUDE_DIR};${ATK_IN
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(atkmm
FOUND_VAR ATKMM_FOUND
REQUIRED_VARS
ATKMM_LIBRARY
ATKMM_INCLUDE_DIRS

View File

@ -31,7 +31,6 @@ set(CAIRO_INCLUDE_DIRS ${CAIRO_INCLUDE_DIR};${CAIRO_CONFIG_INCLUDE_DIRS})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(cairo
FOUND_VAR CAIRO_FOUND
REQUIRED_VARS
CAIRO_LIBRARY
CAIRO_INCLUDE_DIR

View File

@ -45,7 +45,6 @@ set(CAIROMM_INCLUDE_DIRS ${CAIROMM_INCLUDE_DIR};${CAIROMM_CONFIG_INCLUDE_DIRS};$
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(cairomm
FOUND_VAR CAIROMM_FOUND
REQUIRED_VARS
CAIROMM_LIBRARY
CAIROMM_INCLUDE_DIR

37
cmake/Findgdk.cmake Normal file
View File

@ -0,0 +1,37 @@
find_package(PkgConfig)
if (PKG_CONFIG_FOUND)
pkg_check_modules(PC_gdk QUIET gdk-3.0)
set(gdk_DEFINITIONS ${PC_gdk_CFLAGS_OTHER})
endif ()
set(gdk_INCLUDE_HINTS ${PC_gdk_INCLUDEDIR} ${PC_gdk_INCLUDE_DIRS})
set(gdk_LIBRARY_HINTS ${PC_gdk_LIBDIR} ${PC_gdk_LIBRARY_DIRS})
find_path(gdk_INCLUDE_DIR
NAMES gdk/gdk.h
HINTS ${gdk_INCLUDE_HINTS}
/usr/include
/usr/local/include
/opt/local/include
PATH_SUFFIXES gdk-3.0)
find_library(gdk_LIBRARY
NAMES gdk-3.0
gdk-3
gdk
HINTS ${gdk_LIBRARY_HINTS}
/usr/lib
/usr/local/lib
/opt/local/lib)
set(gdk_LIBRARIES ${gdk_LIBRARY})
set(gdk_INCLUDE_DIRS ${gdk_INCLUDE_DIR})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(gdk
REQUIRED_VARS
gdk_LIBRARY
gdk_INCLUDE_DIR
VERSION_VAR gdk_VERSION)
mark_as_advanced(gdk_INCLUDE_DIR gdk_LIBRARY)

View File

@ -1,49 +1,50 @@
set(GDKMM_LIBRARY_NAME gdkmm-3.0)
set(gdkmm_LIBRARY_NAME gdkmm-3.0)
find_package(PkgConfig)
if (PKG_CONFIG_FOUND)
pkg_check_modules(PKGCONFIG_GDKMM QUIET ${GDKMM_LIBRARY_NAME})
set(GDKMM_DEFINITIONS ${PKGCONFIG_GDKMM_CFLAGS_OTHER})
pkg_check_modules(PKGCONFIG_gdkmm QUIET ${gdkmm_LIBRARY_NAME})
set(gdkmm_DEFINITIONS ${PKGCONFIG_gdkmm_CFLAGS_OTHER})
endif (PKG_CONFIG_FOUND)
set(GDKMM_INCLUDE_HINTS ${PKGCONFIG_GDKMM_INCLUDEDIR} ${PKGCONFIG_GDKMM_INCLUDE_DIRS})
set(GDKMM_LIBRARY_HINTS ${PKGCONFIG_GDKMM_LIBDIR} ${PKGCONFIG_GDKMM_LIBRARY_DIRS})
set(gdkmm_INCLUDE_HINTS ${PKGCONFIG_gdkmm_INCLUDEDIR} ${PKGCONFIG_gdkmm_INCLUDE_DIRS})
set(gdkmm_LIBRARY_HINTS ${PKGCONFIG_gdkmm_LIBDIR} ${PKGCONFIG_gdkmm_LIBRARY_DIRS})
find_path(GDKMM_INCLUDE_DIR
find_path(gdkmm_INCLUDE_DIR
NAMES gdkmm.h
HINTS ${GDKMM_INCLUDE_HINTS}
HINTS ${gdkmm_INCLUDE_HINTS}
/usr/include
/usr/local/include
/opt/local/include
PATH_SUFFIXES ${GDKMM_LIBRARY_NAME})
PATH_SUFFIXES ${gdkmm_LIBRARY_NAME})
find_path(GDKMM_CONFIG_INCLUDE_DIR
find_path(gdkmm_CONFIG_INCLUDE_DIR
NAMES gdkmmconfig.h
HINTS ${GDKMM_LIBRARY_HINTS}
HINTS ${gdkmm_LIBRARY_HINTS}
/usr/lib
/usr/local/lib
/opt/local/lib
PATH_SUFFIXES ${GDKMM_LIBRARY_NAME}/include)
PATH_SUFFIXES ${gdkmm_LIBRARY_NAME}/include)
find_library(GDKMM_LIBRARY
NAMES ${GDKMM_LIBRARY_NAME}
gdkmm
HINTS ${GDKMM_LIBRARY_HINTS}
find_library(gdkmm_LIBRARY
NAMES ${gdkmm_LIBRARY_NAME}
gdkmm
HINTS ${gdkmm_LIBRARY_HINTS}
/usr/lib
/usr/local/lib
/opt/local/lib
PATH_SUFFIXES ${GDKMM_LIBRARY_NAME}
${GDKMM_LIBRARY_NAME}/include)
PATH_SUFFIXES ${gdkmm_LIBRARY_NAME}
${gdkmm_LIBRARY_NAME}/include)
set(GDKMM_LIBRARIES ${GDKMM_LIBRARY})
set(GDKMM_INCLUDE_DIRS ${GDKMM_INCLUDE_DIR};${GDKMM_CONFIG_INCLUDE_DIRS};${GDKMM_CONFIG_INCLUDE_DIR})
find_package(gdk)
set(gdkmm_LIBRARIES ${gdkmm_LIBRARY};${gdk_LIBRARIES})
set(gdkmm_INCLUDE_DIRS ${gdkmm_INCLUDE_DIR};${gdkmm_CONFIG_INCLUDE_DIRS};${gdkmm_CONFIG_INCLUDE_DIR};${gdk_INCLUDE_DIRS})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(gdkmm
FOUND_VAR GDKMM_FOUND
REQUIRED_VARS
GDKMM_LIBRARY
GDKMM_INCLUDE_DIRS
VERSION_VAR GDKMM_VERSION)
gdkmm_LIBRARY
gdkmm_INCLUDE_DIRS
VERSION_VAR gdkmm_VERSION)
mark_as_advanced(GDKMM_INCLUDE_DIR GDKMM_LIBRARY)
mark_as_advanced(gdkmm_INCLUDE_DIR gdkmm_LIBRARY)

View File

@ -33,7 +33,6 @@ set(GDKPIXBUF_INCLUDE_DIRS ${GDKPIXBUF_INCLUDE_DIR};${GDKPIXBUF_CONFIG_INCLUDE_D
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(gdkpixbuf
FOUND_VAR GDKPIXBUF_FOUND
REQUIRED_VARS
GDKPIXBUF_LIBRARY
GDKPIXBUF_INCLUDE_DIR

View File

@ -2,57 +2,70 @@ find_package(PkgConfig)
pkg_check_modules(PC_GLIB2 QUIET glib-2.0)
find_path(GLIB_INCLUDE_DIR
NAMES glib.h
HINTS ${PC_GLIB2_INCLUDEDIR}
${PC_GLIB2_INCLUDE_DIRS}
$ENV{GLIB2_HOME}/include
$ENV{GLIB2_ROOT}/include
/usr/local/include
/usr/include
/glib2/include
/glib-2.0/include
PATH_SUFFIXES glib2 glib-2.0 glib-2.0/include
)
NAMES glib.h
HINTS ${PC_GLIB2_INCLUDEDIR}
${PC_GLIB2_INCLUDE_DIRS}
$ENV{GLIB2_HOME}/include
$ENV{GLIB2_ROOT}/include
/usr/local/include
/usr/include
/glib2/include
/glib-2.0/include
PATH_SUFFIXES glib2 glib-2.0 glib-2.0/include
)
set(GLIB_INCLUDE_DIRS ${GLIB_INCLUDE_DIR})
find_library(GLIB_LIBRARIES
NAMES glib2
glib-2.0
HINTS ${PC_GLIB2_LIBDIR}
${PC_GLIB2_LIBRARY_DIRS}
$ENV{GLIB2_HOME}/lib
$ENV{GLIB2_ROOT}/lib
/usr/local/lib
/usr/lib
/lib
/glib-2.0/lib
PATH_SUFFIXES glib2 glib-2.0
)
NAMES glib2
glib-2.0
HINTS ${PC_GLIB2_LIBDIR}
${PC_GLIB2_LIBRARY_DIRS}
$ENV{GLIB2_HOME}/lib
$ENV{GLIB2_ROOT}/lib
/usr/local/lib
/usr/lib
/lib
/glib-2.0/lib
PATH_SUFFIXES glib2 glib-2.0
)
find_library(glib_GOBJECT_LIBRARIES
NAMES gobject-2.0
HINTS ${PC_GLIB2_LIBDIR}
${PC_GLIB2_LIBRARY_DIRS}
)
find_library(glib_GIO_LIBRARIES
NAMES gio-2.0
HINTS ${PC_GLIB2_LIBDIR}
${PC_GLIB2_LIBRARY_DIRS}
)
get_filename_component(_GLIB2_LIB_DIR "${GLIB_LIBRARIES}" PATH)
find_path(GLIB_CONFIG_INCLUDE_DIR
NAMES glibconfig.h
HINTS ${PC_GLIB2_INCLUDEDIR}
${PC_GLIB2_INCLUDE_DIRS}
$ENV{GLIB2_HOME}/include
$ENV{GLIB2_ROOT}/include
/usr/local/include
/usr/include
/glib2/include
/glib-2.0/include
${_GLIB2_LIB_DIR}
${CMAKE_SYSTEM_LIBRARY_PATH}
PATH_SUFFIXES glib2 glib-2.0 glib-2.0/include
)
NAMES glibconfig.h
HINTS ${PC_GLIB2_INCLUDEDIR}
${PC_GLIB2_INCLUDE_DIRS}
$ENV{GLIB2_HOME}/include
$ENV{GLIB2_ROOT}/include
/usr/local/include
/usr/include
/glib2/include
/glib-2.0/include
${_GLIB2_LIB_DIR}
${CMAKE_SYSTEM_LIBRARY_PATH}
PATH_SUFFIXES glib2 glib-2.0 glib-2.0/include
)
if (GLIB_CONFIG_INCLUDE_DIR)
set(GLIB_INCLUDE_DIRS ${GLIB_INCLUDE_DIRS} ${GLIB_CONFIG_INCLUDE_DIR})
endif()
endif ()
set(GLIB_LIBRARIES ${GLIB_LIBRARIES} ${glib_GOBJECT_LIBRARIES} ${glib_GIO_LIBRARIES})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(glib
FOUND_VAR GLIB_FOUND
REQUIRED_VARS
GLIB_LIBRARIES
GLIB_INCLUDE_DIRS
VERSION_VAR GLIB_VERSION)
mark_as_advanced(GLIB_INCLUDE_DIR GLIB_CONFIG_INCLUDE_DIR)
REQUIRED_VARS
GLIB_LIBRARIES
GLIB_INCLUDE_DIRS
VERSION_VAR GLIB_VERSION)
mark_as_advanced(GLIB_INCLUDE_DIR GLIB_CONFIG_INCLUDE_DIR glib_GOBJECT_LIBRARIES)

View File

@ -60,7 +60,6 @@ set(GLIBMM_INCLUDE_DIRS ${GLIBMM_INCLUDE_DIR};${GLIBMM_CONFIG_INCLUDE_DIR};${GIO
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(glibmm
FOUND_VAR GLIBMM_FOUND
REQUIRED_VARS
GLIBMM_LIBRARY
GLIBMM_INCLUDE_DIR

View File

@ -47,7 +47,6 @@ set(GTK_INCLUDE_DIRS ${GTK_INCLUDE_DIR};${GDK_CONFIG_INCLUDE_DIR};${GDKPIXBUF_IN
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(gtk
FOUND_VAR GTK_FOUND
REQUIRED_VARS
GTK_LIBRARY
GTK_INCLUDE_DIR

View File

@ -1,13 +1,13 @@
set(GTKMM_LIBRARY_NAME gtkmm-3.0)
set(GDKMM_LIBRARY_NAME gdkmm-3.0)
set(GTKMM_LIBRARY_NAME gtkmm-3.0)
set(GDKMM_LIBRARY_NAME gdkmm-3.0)
find_package(PkgConfig)
if(PKG_CONFIG_FOUND)
if (PKG_CONFIG_FOUND)
pkg_check_modules(PC_GTKMM QUIET ${GTKMM_LIBRARY_NAME})
pkg_check_modules(PC_GDKMM QUIET ${GDKMM_LIBRARY_NAME})
pkg_check_modules(PC_PANGOMM QUIET ${PANGOMM_LIBRARY_NAME})
set(GTKMM_DEFINITIONS ${PC_GTKMM_CFLAGS_OTHER})
endif()
set(GTKMM_DEFINITIONS ${PC_GTKMM_CFLAGS_OTHER})
endif ()
find_package(gtk)
find_package(glibmm)
@ -46,15 +46,14 @@ find_path(GDKMM_CONFIG_INCLUDE_DIR
HINTS ${GDKMM_INCLUDE_HINTS}
PATH_SUFFIXES ${GDKMM_LIBRARY_NAME}/include)
set(GTKMM_LIBRARIES ${GTKMM_LIB};${GDKMM_LIBRARY};${GTK_LIBRARIES};${GLIBMM_LIBRARIES};${PANGOMM_LIBRARIES};${CAIROMM_LIBRARIES};${ATKMM_LIBRARIES};${SIGC++_LIBRARIES})
set(GTKMM_INCLUDE_DIRS ${GTKMM_INCLUDE_DIR};${GTKMM_CONFIG_INCLUDE_DIR};${GDKMM_INCLUDE_DIR};${GDKMM_CONFIG_INCLUDE_DIR};${GTK_INCLUDE_DIRS};${GLIBMM_INCLUDE_DIRS};${PANGOMM_INCLUDE_DIRS};${CAIROMM_INCLUDE_DIRS};${ATKMM_INCLUDE_DIRS};${SIGC++_INCLUDE_DIRS})
set(GTKMM_LIBRARIES ${GTKMM_LIB};${gdkmm_LIBRARIES};${GTK_LIBRARIES};${GLIBMM_LIBRARIES};${PANGOMM_LIBRARIES};${CAIROMM_LIBRARIES};${ATKMM_LIBRARIES};${SIGC++_LIBRARIES})
set(GTKMM_INCLUDE_DIRS ${GTKMM_INCLUDE_DIR};${GTKMM_CONFIG_INCLUDE_DIR};${gdkmm_INCLUDE_DIRS};${gdkmm_CONFIG_INCLUDE_DIR};${GTK_INCLUDE_DIRS};${GLIBMM_INCLUDE_DIRS};${PANGOMM_INCLUDE_DIRS};${CAIROMM_INCLUDE_DIRS};${ATKMM_INCLUDE_DIRS};${SIGC++_INCLUDE_DIRS})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(gtkmm
FOUND_VAR GTKMM_FOUND
REQUIRED_VARS
GTKMM_LIB
GTKMM_INCLUDE_DIRS
GTKMM_LIB
GTKMM_INCLUDE_DIRS
VERSION_VAR GTKMM_VERSION)
mark_as_advanced(GTKMM_INCLUDE_DIR GTKMM_LIBRARY)

View File

@ -1,17 +0,0 @@
find_path(IXWEBSOCKET_INCLUDE_DIR
NAMES ixwebsocket/IXWebSocket.h)
find_library(IXWEBSOCKET_LIBRARY
NAMES ixwebsocket
HINTS ${IXWEBSOCKET_LIBRARY_ROOT})
set(IXWEBSOCKET_LIBRARIES ${IXWEBSOCKET_LIBRARY})
set(IXWEBSOCKET_INCLUDE_DIRS ${IXWEBSOCKET_INCLUDE_DIR})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(ixwebsocket
FOUND_VAR IXWEBSOCKET_FOUND
REQUIRED_VARS
IXWEBSOCKET_LIBRARY
IXWEBSOCKET_INCLUDE_DIR
VERSION_VAR IXWEBSOCKET_VERSION)

39
cmake/Findlibhandy.cmake Normal file
View File

@ -0,0 +1,39 @@
set(libhandy_LIBRARY_NAME libhandy-1)
find_package(PkgConfig)
if (PKG_CONFIG_FOUND)
pkg_check_modules(PC_libhandy QUIET ${libhandy_LIBRARY_NAME})
set(libhandy_DEfINITIONS ${PC_libhandy_CFLAGS_OTHER})
endif (PKG_CONFIG_FOUND)
set(libhandy_INCLUDE_HINTS ${PC_libhandy_INCLUDEDIR} ${PC_libhandy_INCLUDE_DIRS})
set(libhandy_LIBRARY_HINTS ${PC_libhandy_LIBDIR} ${PC_libhandy_LIBRARY_DIRS})
find_path(libhandy_INCLUDE_DIR
NAMES handy.h
HINTS ${libhandy_INCLUDE_HINTS}
/usr/include
/usr/local/include
/opt/local/include
PATH_SUFFIXES ${libhandy_LIBRARY_NAME})
find_library(libhandy_LIBRARY
NAMES ${libhandy_LIBRARY_NAME} handy-1
HINTS ${libhandy_LIBRARY_HINTS}
/usr/lib
/usr/local/lib
/opt/local/lib
PATH_SUFFIXES ${libhandy_LIBRARY_NAME}
${libhandy_LIBRARY_NAME}/include)
set(libhandy_LIBRARIES ${libhandy_LIBRARY})
set(libhandy_INCLUDE_DIRS ${libhandy_INCLUDE_DIR};${libhandy_CONFIG_INCLUDE_DIRS})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(libhandy
REQUIRED_VARS
libhandy_LIBRARY
libhandy_INCLUDE_DIR
VERSION_VAR libhandy_VERSION)
mark_as_advanced(libhandy_INCLUDE_DIR libhandy_LIBRARY)

View File

@ -22,7 +22,6 @@ set(NLOHMANN_JSON_LIBRARIES "")
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(nlohmann_json
FOUND_VAR NLOHMANN_JSON_FOUND
REQUIRED_VARS
NLOHMANN_JSON_INCLUDE_DIR
VERSION_VAR NLOHMANN_JSON_VERSION)

View File

@ -1,4 +1,6 @@
set(PANGO_LIBRARY_NAME pango-1.0)
set(PANGOCAIRO_LIBRARY_NAME pangocairo-1.0)
set(PANGOFT2_LIBRARY_NAME pangoft2-1.0)
find_package(HarfBuzz)
find_package(cairo)
@ -42,12 +44,31 @@ find_library(PANGO_LIBRARY
PATH_SUFFIXES ${PANGO_LIBRARY_NAME}
${PANGO_LIBRARY_NAME}/include)
set(PANGO_LIBRARIES ${PANGO_LIBRARY};${HARFBUZZ_LIBRARIES};${CAIRO_LIBRARIES};${FREETYPE_LIBRARIES})
find_library(PANGOCAIRO_LIBRARY
NAMES ${PANGOCAIRO_LIBRARY_NAME}
pangocairo
HINTS ${PANGO_LIBRARY_HINTS}
/usr/lib
/usr/local/lib
/opt/local/lib
PATH_SUFFIXES ${PANGO_LIBRARY_NAME}
${PANGO_LIBRARY_NAME}/include)
find_library(PANGOFT2_LIBRARY
NAMES ${PANGOFT2_LIBRARY_NAME}
pangoft2
HINTS ${PANGO_LIBRARY_HINTS}
/usr/lib
/usr/local/lib
/opt/local/lib
PATH_SUFFIXES ${PANGO_LIBRARY_NAME}
${PANGO_LIBRARY_NAME}/include)
set(PANGO_LIBRARIES ${PANGO_LIBRARY};${HARFBUZZ_LIBRARIES};${CAIRO_LIBRARIES};${FREETYPE_LIBRARIES};${PANGOCAIRO_LIBRARY};${PANGOFT2_LIBRARY})
set(PANGO_INCLUDE_DIRS ${PANGO_INCLUDE_DIR};${PANGO_CONFIG_INCLUDE_DIRS};${HARFBUZZ_INCLUDE_DIR};${CAIRO_INCLUDE_DIRS};${FREETYPE_INCLUDE_DIRS})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(pango
FOUND_VAR PANGO_FOUND
REQUIRED_VARS
PANGO_LIBRARY
PANGO_INCLUDE_DIR

View File

@ -56,7 +56,6 @@ set(PANGOMM_INCLUDE_DIRS ${PANGOMM_INCLUDE_DIR};${PANGOMM_CONFIG_INCLUDE_DIR};${
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(pangomm
FOUND_VAR PANGOMM_FOUND
REQUIRED_VARS
PANGOMM_LIBRARY
PANGOMM_INCLUDE_DIRS

View File

@ -32,7 +32,6 @@ set(SIGC++_INCLUDE_DIRS ${SIGC++_INCLUDE_DIR};${SIGC++_CONFIG_INCLUDE_DIR})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(sigc++
FOUND_VAR SIGC++_FOUND
REQUIRED_VARS
SIGC++_INCLUDE_DIR
SIGC++_LIBRARY

View File

@ -1,779 +0,0 @@
#include "channels.hpp"
#include <algorithm>
#include <map>
#include <unordered_map>
#include "../abaddon.hpp"
#include "../imgmanager.hpp"
#include "../util.hpp"
#include "statusindicator.hpp"
void ChannelListRow::Collapse() {}
void ChannelListRow::Expand() {}
void ChannelListRow::MakeReadOnly(Gtk::TextView *tv) {
tv->set_can_focus(false);
tv->set_editable(false);
tv->signal_realize().connect([tv]() {
auto window = tv->get_window(Gtk::TEXT_WINDOW_TEXT);
auto display = window->get_display();
auto cursor = Gdk::Cursor::create(display, "default"); // textview uses "text" which looks out of place
window->set_cursor(cursor);
});
// stupid hack to prevent selection
auto buf = tv->get_buffer();
buf->property_has_selection().signal_changed().connect([tv, buf]() {
Gtk::TextBuffer::iterator a, b;
buf->get_bounds(a, b);
buf->select_range(a, a);
});
}
ChannelListRowDMHeader::ChannelListRowDMHeader() {
m_ev = Gtk::manage(new Gtk::EventBox);
m_box = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_HORIZONTAL));
m_lbl = Gtk::manage(new Gtk::Label);
get_style_context()->add_class("channel-row");
m_lbl->get_style_context()->add_class("channel-row-label");
m_lbl->set_use_markup(true);
m_lbl->set_markup("<b>Direct Messages</b>");
m_box->set_halign(Gtk::ALIGN_START);
m_box->pack_start(*m_lbl);
m_ev->add(*m_box);
add(*m_ev);
show_all_children();
}
ChannelListRowDMChannel::ChannelListRowDMChannel(const ChannelData *data) {
ID = data->ID;
m_ev = Gtk::manage(new Gtk::EventBox);
m_box = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_HORIZONTAL));
m_lbl = Gtk::manage(new Gtk::TextView);
MakeReadOnly(m_lbl);
AddWidgetMenuHandler(m_ev, m_menu);
AddWidgetMenuHandler(m_lbl, m_menu);
m_menu_copy_id = Gtk::manage(new Gtk::MenuItem("_Copy ID", true));
m_menu_copy_id->signal_activate().connect([this] {
Gtk::Clipboard::get()->set_text(std::to_string(ID));
});
if (data->Type == ChannelType::GROUP_DM)
m_menu_close = Gtk::manage(new Gtk::MenuItem("_Leave DM", true));
else
m_menu_close = Gtk::manage(new Gtk::MenuItem("_Close DM", true));
m_menu_close->signal_activate().connect([this] {
Abaddon::Get().GetDiscordClient().CloseDM(ID);
});
m_menu.append(*m_menu_copy_id);
m_menu.append(*m_menu_close);
m_menu.show_all();
get_style_context()->add_class("channel-row");
m_lbl->get_style_context()->add_class("channel-row-label");
std::optional<UserData> top_recipient; // potentially nullopt in group dm
const auto recipients = data->GetDMRecipients();
if (recipients.size() > 0)
top_recipient = recipients[0];
if (data->Type == ChannelType::DM) {
m_status = Gtk::manage(new StatusIndicator(top_recipient->ID));
m_status->set_margin_start(5);
m_icon = Gtk::manage(new Gtk::Image(Abaddon::Get().GetImageManager().GetPlaceholder(24)));
auto cb = [this](const Glib::RefPtr<Gdk::Pixbuf> &pb) {
m_icon->property_pixbuf() = pb->scale_simple(24, 24, Gdk::INTERP_BILINEAR);
};
Abaddon::Get().GetImageManager().LoadFromURL(top_recipient->GetAvatarURL("png", "16"), sigc::track_obj(cb, *this));
}
auto buf = m_lbl->get_buffer();
if (data->Type == ChannelType::DM)
buf->set_text(top_recipient->Username);
else if (data->Type == ChannelType::GROUP_DM)
buf->set_text(std::to_string(recipients.size()) + " users");
static bool show_emojis = Abaddon::Get().GetSettings().GetShowEmojis();
if (show_emojis)
Abaddon::Get().GetEmojis().ReplaceEmojis(buf, ChannelEmojiSize);
m_box->set_halign(Gtk::ALIGN_START);
if (m_icon != nullptr)
m_box->pack_start(*m_icon);
if (m_status != nullptr)
m_box->pack_start(*m_status);
m_box->pack_start(*m_lbl);
m_ev->add(*m_box);
add(*m_ev);
show_all_children();
}
ChannelListRowGuild::ChannelListRowGuild(const GuildData *data) {
ID = data->ID;
m_ev = Gtk::manage(new Gtk::EventBox);
m_box = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_HORIZONTAL));
m_lbl = Gtk::manage(new Gtk::TextView);
MakeReadOnly(m_lbl);
AddWidgetMenuHandler(m_ev, m_menu);
AddWidgetMenuHandler(m_lbl, m_menu);
m_menu_copyid = Gtk::manage(new Gtk::MenuItem("_Copy ID", true));
m_menu_copyid->signal_activate().connect([this]() {
m_signal_copy_id.emit();
});
m_menu.append(*m_menu_copyid);
m_menu_leave = Gtk::manage(new Gtk::MenuItem("_Leave Guild", true));
m_menu_leave->signal_activate().connect([this]() {
m_signal_leave.emit();
});
m_menu.append(*m_menu_leave);
m_menu_settings = Gtk::manage(new Gtk::MenuItem("Guild _Settings", true));
m_menu_settings->signal_activate().connect([this]() {
m_signal_settings.emit();
});
m_menu.append(*m_menu_settings);
m_menu.show_all();
const auto show_animations = Abaddon::Get().GetSettings().GetShowAnimations();
auto &img = Abaddon::Get().GetImageManager();
if (data->HasIcon()) {
if (data->HasAnimatedIcon() && show_animations) {
m_icon = Gtk::manage(new Gtk::Image(img.GetPlaceholder(24)));
auto cb = [this](const Glib::RefPtr<Gdk::PixbufAnimation> &pb) {
m_icon->property_pixbuf_animation() = pb;
};
img.LoadAnimationFromURL(data->GetIconURL("gif", "32"), 24, 24, sigc::track_obj(cb, *this));
} else {
m_icon = Gtk::manage(new Gtk::Image(img.GetPlaceholder(24)));
auto cb = [this](const Glib::RefPtr<Gdk::Pixbuf> &pb) {
m_icon->property_pixbuf() = pb->scale_simple(24, 24, Gdk::INTERP_BILINEAR);
};
img.LoadFromURL(data->GetIconURL("png", "32"), sigc::track_obj(cb, *this));
}
} else {
m_icon = Gtk::manage(new Gtk::Image(Abaddon::Get().GetImageManager().GetPlaceholder(24)));
}
get_style_context()->add_class("channel-row");
get_style_context()->add_class("channel-row-guild");
m_lbl->get_style_context()->add_class("channel-row-label");
auto buf = m_lbl->get_buffer();
Gtk::TextBuffer::iterator start, end;
buf->get_bounds(start, end);
buf->insert_markup(start, "<b>" + Glib::Markup::escape_text(data->Name) + "</b>");
static bool show_emojis = Abaddon::Get().GetSettings().GetShowEmojis();
if (show_emojis)
Abaddon::Get().GetEmojis().ReplaceEmojis(buf, ChannelEmojiSize);
m_box->set_halign(Gtk::ALIGN_START);
m_box->pack_start(*m_icon);
m_box->pack_start(*m_lbl);
m_ev->add(*m_box);
add(*m_ev);
show_all_children();
}
ChannelListRowGuild::type_signal_copy_id ChannelListRowGuild::signal_copy_id() {
return m_signal_copy_id;
}
ChannelListRowGuild::type_signal_leave ChannelListRowGuild::signal_leave() {
return m_signal_leave;
}
ChannelListRowGuild::type_signal_settings ChannelListRowGuild::signal_settings() {
return m_signal_settings;
}
ChannelListRowCategory::ChannelListRowCategory(const ChannelData *data) {
ID = data->ID;
m_ev = Gtk::manage(new Gtk::EventBox);
m_box = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_HORIZONTAL));
m_lbl = Gtk::manage(new Gtk::TextView);
MakeReadOnly(m_lbl);
m_arrow = Gtk::manage(new Gtk::Arrow(Gtk::ARROW_DOWN, Gtk::SHADOW_NONE));
m_menu_copyid = Gtk::manage(new Gtk::MenuItem("_Copy ID", true));
m_menu_copyid->signal_activate().connect([this]() {
m_signal_copy_id.emit();
});
m_menu.append(*m_menu_copyid);
m_menu.show_all();
AddWidgetMenuHandler(m_ev, m_menu);
AddWidgetMenuHandler(m_lbl, m_menu);
get_style_context()->add_class("channel-row");
get_style_context()->add_class("channel-row-category");
m_lbl->get_style_context()->add_class("channel-row-label");
auto buf = m_lbl->get_buffer();
buf->set_text(*data->Name);
static bool show_emojis = Abaddon::Get().GetSettings().GetShowEmojis();
if (show_emojis)
Abaddon::Get().GetEmojis().ReplaceEmojis(buf, ChannelEmojiSize);
m_box->set_halign(Gtk::ALIGN_START);
m_box->pack_start(*m_arrow);
m_box->pack_start(*m_lbl);
m_ev->add(*m_box);
add(*m_ev);
show_all_children();
}
void ChannelListRowCategory::Collapse() {
m_arrow->set(Gtk::ARROW_RIGHT, Gtk::SHADOW_NONE);
}
void ChannelListRowCategory::Expand() {
m_arrow->set(IsUserCollapsed ? Gtk::ARROW_RIGHT : Gtk::ARROW_DOWN, Gtk::SHADOW_NONE);
}
ChannelListRowCategory::type_signal_copy_id ChannelListRowCategory::signal_copy_id() {
return m_signal_copy_id;
}
ChannelListRowChannel::ChannelListRowChannel(const ChannelData *data) {
ID = data->ID;
m_ev = Gtk::manage(new Gtk::EventBox);
m_box = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_HORIZONTAL));
m_lbl = Gtk::manage(new Gtk::TextView);
MakeReadOnly(m_lbl);
m_menu_copyid = Gtk::manage(new Gtk::MenuItem("_Copy ID", true));
m_menu_copyid->signal_activate().connect([this]() {
m_signal_copy_id.emit();
});
m_menu.append(*m_menu_copyid);
m_menu.show_all();
AddWidgetMenuHandler(m_ev, m_menu);
AddWidgetMenuHandler(m_lbl, m_menu);
get_style_context()->add_class("channel-row");
get_style_context()->add_class("channel-row-channel");
m_lbl->get_style_context()->add_class("channel-row-label");
auto buf = m_lbl->get_buffer();
if (data->IsNSFW.has_value() && *data->IsNSFW) {
get_style_context()->add_class("nsfw");
m_lbl->get_style_context()->add_class("nsfw");
}
buf->set_text("#" + *data->Name);
static bool show_emojis = Abaddon::Get().GetSettings().GetShowEmojis();
if (show_emojis)
Abaddon::Get().GetEmojis().ReplaceEmojis(buf, ChannelEmojiSize);
m_box->set_halign(Gtk::ALIGN_START);
m_box->pack_start(*m_lbl);
m_ev->add(*m_box);
add(*m_ev);
show_all_children();
}
ChannelListRowChannel::type_signal_copy_id ChannelListRowChannel::signal_copy_id() {
return m_signal_copy_id;
}
ChannelList::ChannelList() {
m_main = Gtk::manage(new Gtk::ScrolledWindow);
m_list = Gtk::manage(new Gtk::ListBox);
m_list->get_style_context()->add_class("channel-list");
m_list->set_activate_on_single_click(true);
m_list->signal_row_activated().connect(sigc::mem_fun(*this, &ChannelList::on_row_activated));
m_main->add(*m_list);
m_main->show_all();
// maybe will regret doing it this way
auto &discord = Abaddon::Get().GetDiscordClient();
auto cb = [this, &discord](const Message &message) {
const auto channel = discord.GetChannel(message.ChannelID);
if (!channel.has_value()) return;
if (channel->Type == ChannelType::DM || channel->Type == ChannelType::GROUP_DM)
CheckBumpDM(message.ChannelID);
};
discord.signal_message_create().connect(sigc::track_obj(cb, *this));
}
Gtk::Widget *ChannelList::GetRoot() const {
return m_main;
}
void ChannelList::UpdateNewGuild(Snowflake id) {
auto sort = Abaddon::Get().GetDiscordClient().GetUserSortedGuilds();
if (sort.size() == 1) {
UpdateListing();
return;
}
const auto insert_at = [this, id](int listpos) {
InsertGuildAt(id, listpos);
};
auto it = std::find(sort.begin(), sort.end(), id);
if (it == sort.end()) return;
// if the new guild pos is at the end use -1
if (it + 1 == sort.end()) {
insert_at(-1);
return;
}
// find the position of the guild below it into the listbox
auto below_id = *(it + 1);
auto below_it = m_id_to_row.find(below_id);
if (below_it == m_id_to_row.end()) {
UpdateListing();
return;
}
auto below_pos = below_it->second->get_index();
// stick it just above
insert_at(below_pos - 1);
}
void ChannelList::UpdateRemoveGuild(Snowflake id) {
auto it = m_guild_id_to_row.find(id);
if (it == m_guild_id_to_row.end()) return;
auto row = dynamic_cast<ChannelListRow *>(it->second);
if (row == nullptr) return;
DeleteRow(row);
}
void ChannelList::UpdateRemoveChannel(Snowflake id) {
auto it = m_id_to_row.find(id);
if (it == m_id_to_row.end()) return;
auto row = dynamic_cast<ChannelListRow *>(it->second);
if (row == nullptr) return;
DeleteRow(row);
}
// this is total shit
void ChannelList::UpdateChannelCategory(Snowflake id) {
const auto data = Abaddon::Get().GetDiscordClient().GetChannel(id);
const auto guild = Abaddon::Get().GetDiscordClient().GetGuild(*data->GuildID);
auto git = m_guild_id_to_row.find(*data->GuildID);
if (git == m_guild_id_to_row.end()) return;
auto *guild_row = git->second;
if (!data.has_value() || !guild.has_value()) return;
auto it = m_id_to_row.find(id);
if (it == m_id_to_row.end()) return;
auto row = dynamic_cast<ChannelListRowCategory *>(it->second);
if (row == nullptr) return;
const bool old_collapsed = row->IsUserCollapsed;
const bool visible = row->is_visible();
std::map<int, Snowflake> child_rows;
for (auto child : row->Children) {
child_rows[child->get_index()] = child->ID;
}
guild_row->Children.erase(row);
DeleteRow(row);
int pos = guild_row->get_index();
const auto sorted = guild->GetSortedChannels(id);
const auto sorted_it = std::find(sorted.begin(), sorted.end(), id);
if (sorted_it == sorted.end()) return;
if (std::next(sorted_it) == sorted.end()) {
const auto x = m_id_to_row.find(*std::prev(sorted_it));
if (x != m_id_to_row.end())
pos = x->second->get_index() + 1;
} else {
const auto x = m_id_to_row.find(*std::next(sorted_it));
if (x != m_id_to_row.end())
pos = x->second->get_index();
}
auto *new_row = Gtk::manage(new ChannelListRowCategory(&*data));
new_row->IsUserCollapsed = old_collapsed;
if (visible)
new_row->show();
m_id_to_row[id] = new_row;
new_row->signal_copy_id().connect(sigc::bind(sigc::mem_fun(*this, &ChannelList::OnMenuCopyID), new_row->ID));
new_row->Parent = guild_row;
guild_row->Children.insert(new_row);
m_list->insert(*new_row, pos);
int i = 1;
for (const auto &[idx, child_id] : child_rows) {
const auto channel = Abaddon::Get().GetDiscordClient().GetChannel(child_id);
if (channel.has_value()) {
auto *new_child = Gtk::manage(new ChannelListRowChannel(&*channel));
new_row->Children.insert(new_child);
new_child->Parent = new_row;
new_child->signal_copy_id().connect(sigc::bind(sigc::mem_fun(*this, &ChannelList::OnMenuCopyID), new_child->ID));
m_id_to_row[child_id] = new_child;
if (visible && !new_row->IsUserCollapsed)
new_child->show();
m_list->insert(*new_child, pos + i++);
}
}
}
// so is this
void ChannelList::UpdateChannel(Snowflake id) {
const auto data = Abaddon::Get().GetDiscordClient().GetChannel(id);
const auto guild = Abaddon::Get().GetDiscordClient().GetGuild(*data->GuildID);
const auto *guild_row = m_guild_id_to_row.at(*data->GuildID);
if (data->Type == ChannelType::GUILD_CATEGORY) {
UpdateChannelCategory(id);
return;
}
auto it = m_id_to_row.find(id);
if (it == m_id_to_row.end()) return; // stuff like voice doesnt have a row yet
auto row = dynamic_cast<ChannelListRowChannel *>(it->second);
const bool old_collapsed = row->IsUserCollapsed;
const bool old_visible = row->is_visible();
DeleteRow(row);
int pos = guild_row->get_index() + 1; // fallback
const auto sorted = guild->GetSortedChannels();
const auto sorted_it = std::find(sorted.begin(), sorted.end(), id);
if (sorted_it + 1 == sorted.end()) {
const auto x = m_id_to_row.find(*std::prev(sorted_it));
if (x != m_id_to_row.end())
pos = x->second->get_index() + 1;
} else {
const auto x = m_id_to_row.find(*std::next(sorted_it));
if (x != m_id_to_row.end())
pos = x->second->get_index();
}
auto *new_row = Gtk::manage(new ChannelListRowChannel(&*data));
new_row->IsUserCollapsed = old_collapsed;
m_id_to_row[id] = new_row;
if (data->ParentID.has_value()) {
new_row->Parent = m_id_to_row.at(*data->ParentID);
} else {
new_row->Parent = m_guild_id_to_row.at(*data->GuildID);
}
new_row->Parent->Children.insert(new_row);
if (new_row->Parent->is_visible() && !new_row->Parent->IsUserCollapsed)
new_row->show();
new_row->signal_copy_id().connect(sigc::bind(sigc::mem_fun(*this, &ChannelList::OnMenuCopyID), new_row->ID));
m_list->insert(*new_row, pos);
}
void ChannelList::UpdateCreateDMChannel(Snowflake id) {
const auto chan = Abaddon::Get().GetDiscordClient().GetChannel(id);
auto *dm_row = Gtk::manage(new ChannelListRowDMChannel(&*chan));
dm_row->IsUserCollapsed = false;
m_list->insert(*dm_row, m_dm_header_row->get_index() + 1);
m_dm_header_row->Children.insert(dm_row);
m_id_to_row[id] = dm_row;
if (!m_dm_header_row->IsUserCollapsed)
dm_row->show();
}
void ChannelList::UpdateCreateChannel(Snowflake id) {
const auto &discord = Abaddon::Get().GetDiscordClient();
const auto data = discord.GetChannel(id);
if (data->Type == ChannelType::DM || data->Type == ChannelType::GROUP_DM) {
UpdateCreateDMChannel(id);
return;
}
const auto guild = discord.GetGuild(*data->GuildID);
auto *guild_row = m_guild_id_to_row.at(*data->GuildID);
int pos = guild_row->get_index() + 1;
const auto sorted = guild->GetSortedChannels();
const auto sorted_it = std::find(sorted.begin(), sorted.end(), id);
if (sorted_it + 1 == sorted.end()) {
const auto x = m_id_to_row.find(*std::prev(sorted_it));
if (x != m_id_to_row.end())
pos = x->second->get_index() + 1;
} else {
const auto x = m_id_to_row.find(*std::next(sorted_it));
if (x != m_id_to_row.end())
pos = x->second->get_index();
}
ChannelListRow *row;
if (data->Type == ChannelType::GUILD_TEXT || data->Type == ChannelType::GUILD_NEWS) {
auto *tmp = Gtk::manage(new ChannelListRowChannel(&*data));
tmp->signal_copy_id().connect(sigc::bind(sigc::mem_fun(*this, &ChannelList::OnMenuCopyID), tmp->ID));
row = tmp;
} else if (data->Type == ChannelType::GUILD_CATEGORY) {
auto *tmp = Gtk::manage(new ChannelListRowCategory(&*data));
tmp->signal_copy_id().connect(sigc::bind(sigc::mem_fun(*this, &ChannelList::OnMenuCopyID), tmp->ID));
row = tmp;
} else
return;
row->IsUserCollapsed = false;
if (!guild_row->IsUserCollapsed)
row->show();
row->Parent = guild_row;
guild_row->Children.insert(row);
m_id_to_row[id] = row;
m_list->insert(*row, pos);
}
void ChannelList::UpdateGuild(Snowflake id) {
// the only thing changed is the row containing the guild item so just recreate it
const auto data = Abaddon::Get().GetDiscordClient().GetGuild(id);
if (!data.has_value()) return;
auto it = m_guild_id_to_row.find(id);
if (it == m_guild_id_to_row.end()) return;
auto *row = dynamic_cast<ChannelListRowGuild *>(it->second);
const auto children = row->Children;
const auto index = row->get_index();
const bool old_collapsed = row->IsUserCollapsed;
const bool old_gindex = row->GuildIndex;
delete row;
auto *new_row = Gtk::manage(new ChannelListRowGuild(&*data));
new_row->IsUserCollapsed = old_collapsed;
new_row->GuildIndex = old_gindex;
m_guild_id_to_row[new_row->ID] = new_row;
new_row->signal_leave().connect(sigc::bind(sigc::mem_fun(*this, &ChannelList::OnGuildMenuLeave), new_row->ID));
new_row->signal_copy_id().connect(sigc::bind(sigc::mem_fun(*this, &ChannelList::OnMenuCopyID), new_row->ID));
new_row->signal_settings().connect(sigc::bind(sigc::mem_fun(*this, &ChannelList::OnGuildMenuSettings), new_row->ID));
new_row->Children = children;
for (auto child : children)
child->Parent = new_row;
new_row->show_all();
m_list->insert(*new_row, index);
}
void ChannelList::SetActiveChannel(Snowflake id) {
auto it = m_id_to_row.find(id);
if (it == m_id_to_row.end()) return;
m_list->select_row(*it->second);
}
void ChannelList::CollapseRow(ChannelListRow *row) {
row->Collapse();
for (auto child : row->Children) {
child->hide();
CollapseRow(child);
}
}
void ChannelList::ExpandRow(ChannelListRow *row) {
row->Expand();
row->show();
if (!row->IsUserCollapsed)
for (auto child : row->Children)
ExpandRow(child);
}
void ChannelList::DeleteRow(ChannelListRow *row) {
for (auto child : row->Children)
DeleteRow(child);
if (row->Parent != nullptr)
row->Parent->Children.erase(row);
else
printf("row has no parent!\n");
if (dynamic_cast<ChannelListRowGuild *>(row) != nullptr)
m_guild_id_to_row.erase(row->ID);
else
m_id_to_row.erase(row->ID);
delete row;
}
void ChannelList::on_row_activated(Gtk::ListBoxRow *tmprow) {
auto row = dynamic_cast<ChannelListRow *>(tmprow);
if (row == nullptr) return;
bool new_collapsed = !row->IsUserCollapsed;
row->IsUserCollapsed = new_collapsed;
// kinda ugly
if (dynamic_cast<ChannelListRowChannel *>(row) != nullptr || dynamic_cast<ChannelListRowDMChannel *>(row) != nullptr)
m_signal_action_channel_item_select.emit(row->ID);
if (new_collapsed)
CollapseRow(row);
else
ExpandRow(row);
}
void ChannelList::InsertGuildAt(Snowflake id, int pos) {
const auto insert_and_adjust = [&](Gtk::Widget &widget) {
m_list->insert(widget, pos);
if (pos != -1) pos++;
};
const auto &discord = Abaddon::Get().GetDiscordClient();
const auto guild_data = discord.GetGuild(id);
if (!guild_data.has_value()) return;
std::map<int, ChannelData> orphan_channels;
std::unordered_map<Snowflake, std::vector<ChannelData>> cat_to_channels;
if (guild_data->Channels.has_value())
for (const auto &dc : *guild_data->Channels) {
const auto channel = discord.GetChannel(dc.ID);
if (!channel.has_value()) continue;
if (channel->Type != ChannelType::GUILD_TEXT && channel->Type != ChannelType::GUILD_NEWS) continue;
if (channel->ParentID.has_value())
cat_to_channels[*channel->ParentID].push_back(*channel);
else
orphan_channels[*channel->Position] = *channel;
}
auto *guild_row = Gtk::manage(new ChannelListRowGuild(&*guild_data));
guild_row->show_all();
guild_row->IsUserCollapsed = true;
guild_row->GuildIndex = m_guild_count++;
insert_and_adjust(*guild_row);
m_guild_id_to_row[guild_row->ID] = guild_row;
guild_row->signal_leave().connect(sigc::bind(sigc::mem_fun(*this, &ChannelList::OnGuildMenuLeave), guild_row->ID));
guild_row->signal_copy_id().connect(sigc::bind(sigc::mem_fun(*this, &ChannelList::OnMenuCopyID), guild_row->ID));
guild_row->signal_settings().connect(sigc::bind(sigc::mem_fun(*this, &ChannelList::OnGuildMenuSettings), guild_row->ID));
// add channels with no parent category
for (const auto &[pos, channel] : orphan_channels) {
auto *chan_row = Gtk::manage(new ChannelListRowChannel(&channel));
chan_row->IsUserCollapsed = false;
chan_row->signal_copy_id().connect(sigc::bind(sigc::mem_fun(*this, &ChannelList::OnMenuCopyID), chan_row->ID));
insert_and_adjust(*chan_row);
guild_row->Children.insert(chan_row);
chan_row->Parent = guild_row;
m_id_to_row[chan_row->ID] = chan_row;
}
// categories
std::map<int, std::vector<ChannelData>> sorted_categories;
if (guild_data->Channels.has_value())
for (const auto &dc : *guild_data->Channels) {
const auto channel = discord.GetChannel(dc.ID);
if (!channel.has_value()) continue;
if (channel->Type == ChannelType::GUILD_CATEGORY)
sorted_categories[*channel->Position].push_back(*channel);
}
for (auto &[pos, catvec] : sorted_categories) {
std::sort(catvec.begin(), catvec.end(), [](const ChannelData &a, const ChannelData &b) { return a.ID < b.ID; });
for (const auto cat : catvec) {
auto *cat_row = Gtk::manage(new ChannelListRowCategory(&cat));
cat_row->IsUserCollapsed = false;
cat_row->signal_copy_id().connect(sigc::bind(sigc::mem_fun(*this, &ChannelList::OnMenuCopyID), cat_row->ID));
insert_and_adjust(*cat_row);
guild_row->Children.insert(cat_row);
cat_row->Parent = guild_row;
m_id_to_row[cat_row->ID] = cat_row;
// child channels
if (cat_to_channels.find(cat.ID) == cat_to_channels.end()) continue;
std::map<int, ChannelData> sorted_channels;
for (const auto channel : cat_to_channels.at(cat.ID))
sorted_channels[*channel.Position] = channel;
for (const auto &[pos, channel] : sorted_channels) {
auto *chan_row = Gtk::manage(new ChannelListRowChannel(&channel));
chan_row->IsUserCollapsed = false;
chan_row->signal_copy_id().connect(sigc::bind(sigc::mem_fun(*this, &ChannelList::OnMenuCopyID), chan_row->ID));
insert_and_adjust(*chan_row);
cat_row->Children.insert(chan_row);
chan_row->Parent = cat_row;
m_id_to_row[chan_row->ID] = chan_row;
}
}
}
}
void ChannelList::AddPrivateChannels() {
const auto &discord = Abaddon::Get().GetDiscordClient();
auto dms_ = discord.GetPrivateChannels();
std::vector<ChannelData> dms;
for (const auto &x : dms_) {
const auto chan = discord.GetChannel(x);
dms.push_back(*chan);
}
std::sort(dms.begin(), dms.end(), [&](const ChannelData &a, const ChannelData &b) -> bool {
return a.LastMessageID > b.LastMessageID;
});
m_dm_header_row = Gtk::manage(new ChannelListRowDMHeader);
m_dm_header_row->show_all();
m_dm_header_row->IsUserCollapsed = true;
m_list->add(*m_dm_header_row);
for (const auto &dm : dms) {
auto *dm_row = Gtk::manage(new ChannelListRowDMChannel(&dm));
dm_row->Parent = m_dm_header_row;
m_id_to_row[dm.ID] = dm_row;
dm_row->IsUserCollapsed = false;
m_list->add(*dm_row);
m_dm_header_row->Children.insert(dm_row);
}
}
void ChannelList::UpdateListing() {
std::unordered_set<Snowflake> guilds = Abaddon::Get().GetDiscordClient().GetGuilds();
auto children = m_list->get_children();
auto it = children.begin();
while (it != children.end()) {
delete *it;
it++;
}
m_id_to_row.clear();
m_guild_count = 0;
AddPrivateChannels();
auto sorted_guilds = Abaddon::Get().GetDiscordClient().GetUserSortedGuilds();
for (auto gid : sorted_guilds) {
InsertGuildAt(gid, -1);
}
}
void ChannelList::OnMenuCopyID(Snowflake id) {
Gtk::Clipboard::get()->set_text(std::to_string(id));
}
void ChannelList::OnGuildMenuLeave(Snowflake id) {
m_signal_action_guild_leave.emit(id);
}
void ChannelList::OnGuildMenuSettings(Snowflake id) {
m_signal_action_guild_settings.emit(id);
}
void ChannelList::CheckBumpDM(Snowflake channel_id) {
auto it = m_id_to_row.find(channel_id);
if (it == m_id_to_row.end()) return;
auto *row = it->second;
const auto index = row->get_index();
if (index == 1) return; // 1 is top of dm list
const bool selected = row->is_selected();
row->Parent->Children.erase(row);
delete row;
const auto chan = Abaddon::Get().GetDiscordClient().GetChannel(channel_id);
auto *dm_row = Gtk::manage(new ChannelListRowDMChannel(&*chan));
dm_row->Parent = m_dm_header_row;
m_dm_header_row->Children.insert(dm_row);
m_id_to_row[channel_id] = dm_row;
dm_row->IsUserCollapsed = false;
m_list->insert(*dm_row, 1);
m_dm_header_row->Children.insert(dm_row);
if (selected)
m_list->select_row(*dm_row);
if (m_dm_header_row->is_visible() && !m_dm_header_row->IsUserCollapsed)
dm_row->show();
}
ChannelList::type_signal_action_channel_item_select ChannelList::signal_action_channel_item_select() {
return m_signal_action_channel_item_select;
}
ChannelList::type_signal_action_guild_leave ChannelList::signal_action_guild_leave() {
return m_signal_action_guild_leave;
}
ChannelList::type_signal_action_guild_settings ChannelList::signal_action_guild_settings() {
return m_signal_action_guild_settings;
}

View File

@ -1,191 +0,0 @@
#pragma once
#include <gtkmm.h>
#include <string>
#include <queue>
#include <mutex>
#include <unordered_set>
#include <unordered_map>
#include <sigc++/sigc++.h>
#include "../discord/discord.hpp"
static const constexpr int ChannelEmojiSize = 16;
class ChannelListRow : public Gtk::ListBoxRow {
public:
bool IsUserCollapsed;
Snowflake ID;
std::unordered_set<ChannelListRow *> Children;
ChannelListRow *Parent = nullptr;
virtual void Collapse();
virtual void Expand();
static void MakeReadOnly(Gtk::TextView *tv);
};
class ChannelListRowDMHeader : public ChannelListRow {
public:
ChannelListRowDMHeader();
protected:
Gtk::EventBox *m_ev;
Gtk::Box *m_box;
Gtk::Label *m_lbl;
};
class StatusIndicator;
class ChannelListRowDMChannel : public ChannelListRow {
public:
ChannelListRowDMChannel(const ChannelData *data);
protected:
Gtk::EventBox *m_ev;
Gtk::Box *m_box;
StatusIndicator *m_status = nullptr;
Gtk::TextView *m_lbl;
Gtk::Image *m_icon = nullptr;
Gtk::Menu m_menu;
Gtk::MenuItem *m_menu_close; // leave if group
Gtk::MenuItem *m_menu_copy_id;
};
class ChannelListRowGuild : public ChannelListRow {
public:
ChannelListRowGuild(const GuildData *data);
int GuildIndex;
protected:
Gtk::EventBox *m_ev;
Gtk::Box *m_box;
Gtk::TextView *m_lbl;
Gtk::Image *m_icon;
Gtk::Menu m_menu;
Gtk::MenuItem *m_menu_copyid;
Gtk::MenuItem *m_menu_leave;
Gtk::MenuItem *m_menu_settings;
private:
typedef sigc::signal<void> type_signal_copy_id;
typedef sigc::signal<void> type_signal_leave;
typedef sigc::signal<void> type_signal_settings;
type_signal_copy_id m_signal_copy_id;
type_signal_leave m_signal_leave;
type_signal_settings m_signal_settings;
public:
type_signal_copy_id signal_copy_id();
type_signal_leave signal_leave();
type_signal_settings signal_settings();
};
class ChannelListRowCategory : public ChannelListRow {
public:
ChannelListRowCategory(const ChannelData *data);
virtual void Collapse();
virtual void Expand();
protected:
Gtk::EventBox *m_ev;
Gtk::Box *m_box;
Gtk::TextView *m_lbl;
Gtk::Arrow *m_arrow;
Gtk::Menu m_menu;
Gtk::MenuItem *m_menu_copyid;
private:
typedef sigc::signal<void> type_signal_copy_id;
type_signal_copy_id m_signal_copy_id;
public:
type_signal_copy_id signal_copy_id();
};
class ChannelListRowChannel : public ChannelListRow {
public:
ChannelListRowChannel(const ChannelData *data);
protected:
Gtk::EventBox *m_ev;
Gtk::Box *m_box;
Gtk::TextView *m_lbl;
Gtk::Menu m_menu;
Gtk::MenuItem *m_menu_copyid;
private:
typedef sigc::signal<void> type_signal_copy_id;
type_signal_copy_id m_signal_copy_id;
public:
type_signal_copy_id signal_copy_id();
};
class ChannelList {
public:
ChannelList();
Gtk::Widget *GetRoot() const;
void UpdateListing();
void UpdateNewGuild(Snowflake id);
void UpdateRemoveGuild(Snowflake id);
void UpdateRemoveChannel(Snowflake id);
void UpdateChannel(Snowflake id);
void UpdateCreateDMChannel(Snowflake id);
void UpdateCreateChannel(Snowflake id);
void UpdateGuild(Snowflake id);
void SetActiveChannel(Snowflake id);
protected:
Gtk::ListBox *m_list;
Gtk::ScrolledWindow *m_main;
ChannelListRowDMHeader *m_dm_header_row = nullptr;
void CollapseRow(ChannelListRow *row);
void ExpandRow(ChannelListRow *row);
void DeleteRow(ChannelListRow *row);
void UpdateChannelCategory(Snowflake id);
void on_row_activated(Gtk::ListBoxRow *row);
int m_guild_count;
void OnMenuCopyID(Snowflake id);
void OnGuildMenuLeave(Snowflake id);
void OnGuildMenuSettings(Snowflake id);
Gtk::Menu m_channel_menu;
Gtk::MenuItem *m_channel_menu_copyid;
// i would use one map but in really old guilds there can be a channel w/ same id as the guild so this hacky shit has to do
std::unordered_map<Snowflake, ChannelListRow *> m_guild_id_to_row;
std::unordered_map<Snowflake, ChannelListRow *> m_id_to_row;
void InsertGuildAt(Snowflake id, int pos);
void AddPrivateChannels();
void CheckBumpDM(Snowflake channel_id);
public:
typedef sigc::signal<void, Snowflake> type_signal_action_channel_item_select;
typedef sigc::signal<void, Snowflake> type_signal_action_guild_leave;
typedef sigc::signal<void, Snowflake> type_signal_action_guild_settings;
type_signal_action_channel_item_select signal_action_channel_item_select();
type_signal_action_guild_leave signal_action_guild_leave();
type_signal_action_guild_settings signal_action_guild_settings();
protected:
type_signal_action_channel_item_select m_signal_action_channel_item_select;
type_signal_action_guild_leave m_signal_action_guild_leave;
type_signal_action_guild_settings m_signal_action_guild_settings;
};

View File

@ -1,66 +0,0 @@
#include "chatinput.hpp"
ChatInput::ChatInput() {
get_style_context()->add_class("message-input");
set_propagate_natural_height(true);
set_min_content_height(20);
set_max_content_height(250);
set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
// hack
auto cb = [this](GdkEventKey *e) -> bool {
return event(reinterpret_cast<GdkEvent *>(e));
};
m_textview.signal_key_press_event().connect(cb, false);
m_textview.set_hexpand(false);
m_textview.set_halign(Gtk::ALIGN_FILL);
m_textview.set_valign(Gtk::ALIGN_CENTER);
m_textview.set_wrap_mode(Gtk::WRAP_WORD_CHAR);
m_textview.show();
add(m_textview);
}
void ChatInput::InsertText(const Glib::ustring &text) {
GetBuffer()->insert_at_cursor(text);
m_textview.grab_focus();
}
Glib::RefPtr<Gtk::TextBuffer> ChatInput::GetBuffer() {
return m_textview.get_buffer();
}
// this isnt connected directly so that the chat window can handle stuff like the completer first
bool ChatInput::ProcessKeyPress(GdkEventKey *event) {
if (event->keyval == GDK_KEY_Escape) {
m_signal_escape.emit();
return true;
}
if (event->keyval == GDK_KEY_Return) {
if (event->state & GDK_SHIFT_MASK)
return false;
auto buf = GetBuffer();
auto text = buf->get_text();
const bool accepted = m_signal_submit.emit(text);
if (accepted)
buf->set_text("");
return true;
}
return false;
}
void ChatInput::on_grab_focus() {
m_textview.grab_focus();
}
ChatInput::type_signal_submit ChatInput::signal_submit() {
return m_signal_submit;
}
ChatInput::type_signal_escape ChatInput::signal_escape() {
return m_signal_escape;
}

View File

@ -1,28 +0,0 @@
#pragma once
#include <gtkmm.h>
class ChatInput : public Gtk::ScrolledWindow {
public:
ChatInput();
void InsertText(const Glib::ustring &text);
Glib::RefPtr<Gtk::TextBuffer> GetBuffer();
bool ProcessKeyPress(GdkEventKey *event);
protected:
void on_grab_focus() override;
private:
Gtk::TextView m_textview;
public:
typedef sigc::signal<bool, Glib::ustring> type_signal_submit;
typedef sigc::signal<void> type_signal_escape;
type_signal_submit signal_submit();
type_signal_escape signal_escape();
private:
type_signal_submit m_signal_submit;
type_signal_escape m_signal_escape;
};

View File

@ -1,411 +0,0 @@
#include "chatwindow.hpp"
#include "chatmessage.hpp"
#include "../abaddon.hpp"
#include "chatinputindicator.hpp"
#include "ratelimitindicator.hpp"
#include "chatinput.hpp"
constexpr static uint64_t SnowflakeSplitDifference = 600;
ChatWindow::ChatWindow() {
Abaddon::Get().GetDiscordClient().signal_message_send_fail().connect(sigc::mem_fun(*this, &ChatWindow::OnMessageSendFail));
m_main = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL));
m_list = Gtk::manage(new Gtk::ListBox);
m_scroll = Gtk::manage(new Gtk::ScrolledWindow);
m_input = Gtk::manage(new ChatInput);
m_input_indicator = Gtk::manage(new ChatInputIndicator);
m_rate_limit_indicator = Gtk::manage(new RateLimitIndicator);
m_meta = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_HORIZONTAL));
m_rate_limit_indicator->set_margin_end(5);
m_rate_limit_indicator->set_hexpand(true);
m_rate_limit_indicator->set_halign(Gtk::ALIGN_END);
m_rate_limit_indicator->set_valign(Gtk::ALIGN_END);
m_rate_limit_indicator->show();
m_input_indicator->set_halign(Gtk::ALIGN_START);
m_input_indicator->set_valign(Gtk::ALIGN_END);
m_input_indicator->show();
m_main->get_style_context()->add_class("messages");
m_list->get_style_context()->add_class("messages");
m_main->set_hexpand(true);
m_main->set_vexpand(true);
m_scroll->signal_edge_reached().connect(sigc::mem_fun(*this, &ChatWindow::OnScrollEdgeOvershot));
auto v = m_scroll->get_vadjustment();
v->signal_value_changed().connect([this, v] {
m_should_scroll_to_bottom = v->get_upper() - v->get_page_size() <= v->get_value();
});
m_scroll->set_can_focus(false);
m_scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS);
m_scroll->show();
m_list->signal_size_allocate().connect([this](Gtk::Allocation &) {
if (m_should_scroll_to_bottom)
ScrollToBottom();
});
m_list->set_selection_mode(Gtk::SELECTION_NONE);
m_list->set_hexpand(true);
m_list->set_vexpand(true);
m_list->set_focus_hadjustment(m_scroll->get_hadjustment());
m_list->set_focus_vadjustment(m_scroll->get_vadjustment());
m_list->show();
m_input->signal_submit().connect(sigc::mem_fun(*this, &ChatWindow::OnInputSubmit));
m_input->signal_escape().connect([this]() {
if (m_is_replying)
StopReplying();
});
m_input->signal_key_press_event().connect(sigc::mem_fun(*this, &ChatWindow::OnKeyPressEvent), false);
m_input->show();
m_completer.SetBuffer(m_input->GetBuffer());
m_completer.SetGetChannelID([this]() -> auto {
return m_active_channel;
});
m_completer.SetGetRecentAuthors([this]() -> auto {
const auto &discord = Abaddon::Get().GetDiscordClient();
std::vector<Snowflake> ret;
std::map<Snowflake, Gtk::Widget *> ordered(m_id_to_widget.begin(), m_id_to_widget.end());
for (auto it = ordered.crbegin(); it != ordered.crend(); it++) {
const auto *widget = dynamic_cast<ChatMessageItemContainer *>(it->second);
if (widget == nullptr) continue;
const auto msg = discord.GetMessage(widget->ID);
if (!msg.has_value()) continue;
if (std::find(ret.begin(), ret.end(), msg->Author.ID) == ret.end())
ret.push_back(msg->Author.ID);
}
const auto chan = discord.GetChannel(m_active_channel);
if (chan->GuildID.has_value()) {
const auto others = discord.GetUsersInGuild(*chan->GuildID);
for (const auto id : others)
if (std::find(ret.begin(), ret.end(), id) == ret.end())
ret.push_back(id);
}
return ret;
});
m_completer.show();
m_meta->set_hexpand(true);
m_meta->set_halign(Gtk::ALIGN_FILL);
m_meta->show();
m_meta->add(*m_input_indicator);
m_meta->add(*m_rate_limit_indicator);
m_scroll->add(*m_list);
m_main->add(*m_scroll);
m_main->add(m_completer);
m_main->add(*m_input);
m_main->add(*m_meta);
m_main->show();
}
Gtk::Widget *ChatWindow::GetRoot() const {
return m_main;
}
void ChatWindow::Clear() {
SetMessages(std::set<Snowflake>());
}
void ChatWindow::SetMessages(const std::set<Snowflake> &msgs) {
// empty the listbox
auto children = m_list->get_children();
auto it = children.begin();
while (it != children.end()) {
delete *it;
it++;
}
m_num_rows = 0;
m_num_messages = 0;
m_id_to_widget.clear();
for (const auto &id : msgs) {
ProcessNewMessage(id, false);
}
}
void ChatWindow::SetActiveChannel(Snowflake id) {
m_active_channel = id;
m_input_indicator->SetActiveChannel(id);
m_rate_limit_indicator->SetActiveChannel(id);
if (m_is_replying)
StopReplying();
}
void ChatWindow::AddNewMessage(Snowflake id) {
ProcessNewMessage(id, false);
}
void ChatWindow::DeleteMessage(Snowflake id) {
auto widget = m_id_to_widget.find(id);
if (widget == m_id_to_widget.end()) return;
auto *x = dynamic_cast<ChatMessageItemContainer *>(widget->second);
if (x != nullptr)
x->UpdateAttributes();
}
void ChatWindow::UpdateMessage(Snowflake id) {
auto widget = m_id_to_widget.find(id);
if (widget == m_id_to_widget.end()) return;
auto *x = dynamic_cast<ChatMessageItemContainer *>(widget->second);
if (x != nullptr) {
x->UpdateContent();
x->UpdateAttributes();
}
}
void ChatWindow::AddNewHistory(const std::vector<Snowflake> &id) {
std::set<Snowflake> ids(id.begin(), id.end());
for (auto it = ids.rbegin(); it != ids.rend(); it++)
ProcessNewMessage(*it, true);
}
void ChatWindow::InsertChatInput(std::string text) {
m_input->InsertText(text);
}
Snowflake ChatWindow::GetOldestListedMessage() {
return m_id_to_widget.begin()->first;
}
void ChatWindow::UpdateReactions(Snowflake id) {
auto it = m_id_to_widget.find(id);
if (it == m_id_to_widget.end()) return;
auto *widget = dynamic_cast<ChatMessageItemContainer *>(it->second);
if (widget == nullptr) return;
widget->UpdateReactions();
}
Snowflake ChatWindow::GetActiveChannel() const {
return m_active_channel;
}
bool ChatWindow::OnInputSubmit(const Glib::ustring &text) {
if (!m_rate_limit_indicator->CanSpeak())
return false;
if (m_active_channel.IsValid())
m_signal_action_chat_submit.emit(text, m_active_channel, m_replying_to); // m_replying_to is checked for invalid in the handler
if (m_is_replying)
StopReplying();
return true;
}
bool ChatWindow::OnKeyPressEvent(GdkEventKey *e) {
if (m_completer.ProcessKeyPress(e))
return true;
if (m_input->ProcessKeyPress(e))
return true;
return false;
}
ChatMessageItemContainer *ChatWindow::CreateMessageComponent(Snowflake id) {
auto *container = ChatMessageItemContainer::FromMessage(id);
return container;
}
void ChatWindow::RemoveMessageAndHeader(Gtk::Widget *widget) {
ChatMessageHeader *header = dynamic_cast<ChatMessageHeader *>(widget->get_ancestor(Gtk::ListBoxRow::get_type()));
if (header != nullptr) {
if (header->GetChildContent().size() == 1) {
m_num_rows--;
delete header;
} else
delete widget;
} else
delete widget;
m_num_messages--;
}
constexpr static int MaxMessagesForCull = 50; // this has to be 50 cuz that magic number is used in a couple other places and i dont feel like replacing them
void ChatWindow::ProcessNewMessage(Snowflake id, bool prepend) {
const auto &client = Abaddon::Get().GetDiscordClient();
if (!client.IsStarted()) return; // e.g. load channel and then dc
const auto data = client.GetMessage(id);
if (!data.has_value()) return;
if (!data->IsPending && data->Nonce.has_value() && data->Author.ID == client.GetUserData().ID) {
for (auto [id, widget] : m_id_to_widget) {
if (dynamic_cast<ChatMessageItemContainer *>(widget)->Nonce == *data->Nonce) {
RemoveMessageAndHeader(widget);
m_id_to_widget.erase(id);
break;
}
}
}
ChatMessageHeader *last_row = nullptr;
bool should_attach = false;
if (m_num_rows > 0) {
if (prepend)
last_row = dynamic_cast<ChatMessageHeader *>(m_list->get_row_at_index(0));
else
last_row = dynamic_cast<ChatMessageHeader *>(m_list->get_row_at_index(m_num_rows - 1));
if (last_row != nullptr) {
const uint64_t diff = std::max(id, last_row->NewestID) - std::min(id, last_row->NewestID);
if (last_row->UserID == data->Author.ID && (prepend || (diff < SnowflakeSplitDifference * Snowflake::SecondsInterval)))
should_attach = true;
}
}
m_num_messages++;
if (m_should_scroll_to_bottom && !prepend)
while (m_num_messages > MaxMessagesForCull) {
auto first_it = m_id_to_widget.begin();
RemoveMessageAndHeader(first_it->second);
m_id_to_widget.erase(first_it);
}
ChatMessageHeader *header;
if (should_attach) {
header = last_row;
} else {
const auto guild_id = *client.GetChannel(m_active_channel)->GuildID;
const auto user_id = data->Author.ID;
const auto user = client.GetUser(user_id);
if (!user.has_value()) return;
header = Gtk::manage(new ChatMessageHeader(&*data));
header->signal_action_insert_mention().connect([this, user_id]() {
m_signal_action_insert_mention.emit(user_id);
});
header->signal_action_open_user_menu().connect([this, user_id, guild_id](const GdkEvent *event) {
m_signal_action_open_user_menu.emit(event, user_id, guild_id);
});
m_num_rows++;
}
auto *content = CreateMessageComponent(id);
if (content != nullptr) {
header->AddContent(content, prepend);
m_id_to_widget[id] = content;
if (!data->IsPending) {
content->signal_action_delete().connect([this, id] {
m_signal_action_message_delete.emit(m_active_channel, id);
});
content->signal_action_edit().connect([this, id] {
m_signal_action_message_edit.emit(m_active_channel, id);
});
content->signal_action_reaction_add().connect([this, id](const Glib::ustring &param) {
m_signal_action_reaction_add.emit(id, param);
});
content->signal_action_reaction_remove().connect([this, id](const Glib::ustring &param) {
m_signal_action_reaction_remove.emit(id, param);
});
content->signal_action_channel_click().connect([this](const Snowflake &id) {
m_signal_action_channel_click.emit(id);
});
content->signal_action_reply_to().connect(sigc::mem_fun(*this, &ChatWindow::StartReplying));
}
}
header->set_margin_left(5);
header->show_all();
if (!should_attach) {
if (prepend)
m_list->prepend(*header);
else
m_list->add(*header);
}
}
void ChatWindow::StartReplying(Snowflake message_id) {
const auto &discord = Abaddon::Get().GetDiscordClient();
const auto message = *discord.GetMessage(message_id);
const auto author = discord.GetUser(message.Author.ID);
m_replying_to = message_id;
m_is_replying = true;
m_input->grab_focus();
m_input->get_style_context()->add_class("replying");
if (author.has_value())
m_input_indicator->SetCustomMarkup("Replying to " + author->GetEscapedBoldString<false>());
else
m_input_indicator->SetCustomMarkup("Replying...");
}
void ChatWindow::StopReplying() {
m_is_replying = false;
m_replying_to = Snowflake::Invalid;
m_input->get_style_context()->remove_class("replying");
m_input_indicator->ClearCustom();
}
void ChatWindow::OnScrollEdgeOvershot(Gtk::PositionType pos) {
if (pos == Gtk::POS_TOP)
m_signal_action_chat_load_history.emit(m_active_channel);
}
void ChatWindow::ScrollToBottom() {
auto x = m_scroll->get_vadjustment();
x->set_value(x->get_upper());
}
void ChatWindow::OnMessageSendFail(const std::string &nonce, float retry_after) {
for (auto [id, widget] : m_id_to_widget) {
if (auto *container = dynamic_cast<ChatMessageItemContainer *>(widget); container->Nonce == nonce) {
container->SetFailed();
break;
}
}
}
ChatWindow::type_signal_action_message_delete ChatWindow::signal_action_message_delete() {
return m_signal_action_message_delete;
}
ChatWindow::type_signal_action_message_edit ChatWindow::signal_action_message_edit() {
return m_signal_action_message_edit;
}
ChatWindow::type_signal_action_chat_submit ChatWindow::signal_action_chat_submit() {
return m_signal_action_chat_submit;
}
ChatWindow::type_signal_action_chat_load_history ChatWindow::signal_action_chat_load_history() {
return m_signal_action_chat_load_history;
}
ChatWindow::type_signal_action_channel_click ChatWindow::signal_action_channel_click() {
return m_signal_action_channel_click;
}
ChatWindow::type_signal_action_insert_mention ChatWindow::signal_action_insert_mention() {
return m_signal_action_insert_mention;
}
ChatWindow::type_signal_action_open_user_menu ChatWindow::signal_action_open_user_menu() {
return m_signal_action_open_user_menu;
}
ChatWindow::type_signal_action_reaction_add ChatWindow::signal_action_reaction_add() {
return m_signal_action_reaction_add;
}
ChatWindow::type_signal_action_reaction_remove ChatWindow::signal_action_reaction_remove() {
return m_signal_action_reaction_remove;
}

View File

@ -1,8 +0,0 @@
#pragma once
// for things that are used in stackswitchers to be able to be told when they're switched to
class INotifySwitched {
public:
virtual void on_switched_to() {};
};

View File

@ -1,97 +0,0 @@
#include "joinguild.hpp"
#include "../abaddon.hpp"
#include <nlohmann/json.hpp>
#include <regex>
JoinGuildDialog::JoinGuildDialog(Gtk::Window &parent)
: Gtk::Dialog("Join Server", parent, true)
, m_layout(Gtk::ORIENTATION_VERTICAL)
, m_ok("OK")
, m_cancel("Cancel")
, m_info("Enter code") {
set_default_size(300, 50);
get_style_context()->add_class("app-window");
get_style_context()->add_class("app-popup");
Glib::signal_idle().connect(sigc::mem_fun(*this, &JoinGuildDialog::on_idle_slot));
m_entry.signal_changed().connect(sigc::mem_fun(*this, &JoinGuildDialog::on_entry_changed));
m_ok.set_sensitive(false);
m_ok.signal_clicked().connect([&]() {
response(Gtk::RESPONSE_OK);
});
m_cancel.signal_clicked().connect([&]() {
response(Gtk::RESPONSE_CANCEL);
});
m_entry.set_hexpand(true);
m_layout.add(m_entry);
m_lower.set_hexpand(true);
m_lower.pack_start(m_info);
m_info.set_halign(Gtk::ALIGN_START);
m_lower.pack_start(m_ok, Gtk::PACK_SHRINK);
m_lower.pack_start(m_cancel, Gtk::PACK_SHRINK);
m_ok.set_halign(Gtk::ALIGN_END);
m_cancel.set_halign(Gtk::ALIGN_END);
m_layout.add(m_lower);
get_content_area()->add(m_layout);
show_all_children();
}
void JoinGuildDialog::on_entry_changed() {
std::string s = m_entry.get_text();
std::regex invite_regex(R"((https?:\/\/)?discord\.(gg(\/invite)?\/|com\/invite\/)([A-Za-z0-9\-]+))", std::regex_constants::ECMAScript);
std::smatch match;
bool full_url = std::regex_search(s, match, invite_regex);
if (full_url || IsCode(s)) {
m_code = full_url ? match[4].str() : s;
m_needs_request = true;
m_ok.set_sensitive(false);
} else {
m_ok.set_sensitive(false);
}
}
void JoinGuildDialog::CheckCode() {
auto cb = [this](const std::optional<InviteData> &invite) {
if (invite.has_value()) {
m_ok.set_sensitive(true);
if (invite->Guild.has_value()) {
if (invite->MemberCount.has_value())
m_info.set_text(invite->Guild->Name + " (" + std::to_string(*invite->MemberCount) + " members)");
else
m_info.set_text(invite->Guild->Name);
} else {
m_info.set_text("Group DM (" + std::to_string(*invite->MemberCount) + " members)");
}
} else {
m_ok.set_sensitive(false);
m_info.set_text("Invalid invite");
}
};
Abaddon::Get().GetDiscordClient().FetchInvite(m_code, sigc::track_obj(cb, *this));
}
bool JoinGuildDialog::IsCode(std::string str) {
return str.length() >= 2 && std::all_of(str.begin(), str.end(), [](char c) -> bool { return std::isalnum(c) || c == '-'; });
}
std::string JoinGuildDialog::GetCode() {
return m_code;
}
static const constexpr int RateLimitMS = 1500;
bool JoinGuildDialog::on_idle_slot() {
const auto now = std::chrono::steady_clock::now();
if (m_needs_request && ((now - m_last_req_time) > std::chrono::milliseconds(RateLimitMS))) {
m_needs_request = false;
m_last_req_time = now;
CheckCode();
}
return true;
}

View File

@ -1,31 +0,0 @@
#pragma once
#include <gtkmm.h>
#include <string>
#include <chrono>
class JoinGuildDialog : public Gtk::Dialog {
public:
JoinGuildDialog(Gtk::Window &parent);
std::string GetCode();
protected:
void on_entry_changed();
bool IsCode(std::string str);
Gtk::Box m_layout;
Gtk::Button m_ok;
Gtk::Button m_cancel;
Gtk::Box m_lower;
Gtk::Label m_info;
Gtk::Entry m_entry;
void CheckCode();
// needs a rate limit cuz if u hit it u get ip banned from /invites for a long time :(
bool m_needs_request = false;
std::chrono::time_point<std::chrono::steady_clock> m_last_req_time;
bool on_idle_slot();
private:
std::string m_code;
};

View File

@ -1,67 +0,0 @@
#include "../abaddon.hpp"
#include "channel.hpp"
void from_json(const nlohmann::json &j, ChannelData &m) {
JS_D("id", m.ID);
JS_D("type", m.Type);
JS_O("guild_id", m.GuildID);
JS_O("position", m.Position);
JS_O("permission_overwrites", m.PermissionOverwrites);
JS_ON("name", m.Name);
JS_ON("topic", m.Topic);
JS_O("nsfw", m.IsNSFW);
JS_ON("last_message_id", m.LastMessageID);
JS_O("bitrate", m.Bitrate);
JS_O("user_limit", m.UserLimit);
JS_O("rate_limit_per_user", m.RateLimitPerUser);
JS_O("recipients", m.Recipients);
JS_O("recipient_ids", m.RecipientIDs);
JS_ON("icon", m.Icon);
JS_O("owner_id", m.OwnerID);
JS_O("application_id", m.ApplicationID);
JS_ON("parent_id", m.ParentID);
JS_ON("last_pin_timestamp", m.LastPinTimestamp);
}
void ChannelData::update_from_json(const nlohmann::json &j) {
JS_RD("type", Type);
JS_RD("guild_id", GuildID);
JS_RV("position", Position, -1);
JS_RD("permission_overwrites", PermissionOverwrites);
JS_RD("name", Name);
JS_RD("topic", Topic);
JS_RD("nsfw", IsNSFW);
JS_RD("last_message_id", LastMessageID);
JS_RD("bitrate", Bitrate);
JS_RD("user_limit", UserLimit);
JS_RD("rate_limit_per_user", RateLimitPerUser);
JS_RD("recipients", Recipients);
JS_RD("icon", Icon);
JS_RD("owner_id", OwnerID);
JS_RD("application_id", ApplicationID);
JS_RD("parent_id", ParentID);
JS_RD("last_pin_timestamp", LastPinTimestamp);
}
std::optional<PermissionOverwrite> ChannelData::GetOverwrite(Snowflake id) const {
return Abaddon::Get().GetDiscordClient().GetPermissionOverwrite(ID, id);
}
std::vector<UserData> ChannelData::GetDMRecipients() const {
const auto &discord = Abaddon::Get().GetDiscordClient();
if (Recipients.has_value())
return *Recipients;
if (RecipientIDs.has_value()) {
std::vector<UserData> ret;
for (const auto &id : *RecipientIDs) {
auto user = discord.GetUser(id);
if (user.has_value())
ret.push_back(std::move(*user));
}
return ret;
}
return std::vector<UserData>();
}

View File

@ -1,50 +0,0 @@
#pragma once
#include "snowflake.hpp"
#include "json.hpp"
#include "user.hpp"
#include "permissions.hpp"
#include <string>
#include <vector>
enum class ChannelType : int {
GUILD_TEXT = 0,
DM = 1,
GUILD_VOICE = 2,
GROUP_DM = 3,
GUILD_CATEGORY = 4,
GUILD_NEWS = 5,
GUILD_STORE = 6,
/* 7 and 8 were used for LFG */
/* 9 and 10 were used for threads */
PUBLIC_THREAD = 11,
PRIVATE_THREAD = 12,
GUILD_STAGE_VOICE = 13,
};
struct ChannelData {
Snowflake ID;
ChannelType Type;
std::optional<Snowflake> GuildID;
std::optional<int> Position;
std::optional<std::vector<PermissionOverwrite>> PermissionOverwrites; // shouldnt be accessed
std::optional<std::string> Name; // null for dm's
std::optional<std::string> Topic; // null
std::optional<bool> IsNSFW;
std::optional<Snowflake> LastMessageID; // null
std::optional<int> Bitrate;
std::optional<int> UserLimit;
std::optional<int> RateLimitPerUser;
std::optional<std::vector<UserData>> Recipients; // only access id
std::optional<std::vector<Snowflake>> RecipientIDs;
std::optional<std::string> Icon; // null
std::optional<Snowflake> OwnerID;
std::optional<Snowflake> ApplicationID;
std::optional<Snowflake> ParentID; // null
std::optional<std::string> LastPinTimestamp; // null
friend void from_json(const nlohmann::json &j, ChannelData &m);
void update_from_json(const nlohmann::json &j);
std::optional<PermissionOverwrite> GetOverwrite(Snowflake id) const;
std::vector<UserData> GetDMRecipients() const;
};

View File

@ -1,37 +0,0 @@
#pragma once
#include <functional>
#include <future>
#include <string>
#include <unordered_map>
#include <memory>
#include <mutex>
#include <queue>
#include <glibmm.h>
#include "../http.hpp"
class HTTPClient {
public:
HTTPClient(std::string api_base);
void SetUserAgent(std::string agent);
void SetAuth(std::string auth);
void MakeDELETE(const std::string &path, std::function<void(http::response_type r)> cb);
void MakeGET(const std::string &path, std::function<void(http::response_type r)> cb);
void MakePATCH(const std::string &path, const std::string &payload, std::function<void(http::response_type r)> cb);
void MakePOST(const std::string &path, const std::string &payload, std::function<void(http::response_type r)> cb);
void MakePUT(const std::string &path, const std::string &payload, std::function<void(http::response_type r)> cb);
private:
void OnResponse(const http::response_type &r, std::function<void(http::response_type r)> cb);
void CleanupFutures();
mutable std::mutex m_mutex;
Glib::Dispatcher m_dispatcher;
std::queue<std::function<void()>> m_queue;
void RunCallbacks();
std::vector<std::future<void>> m_futures;
std::string m_api_base;
std::string m_authorization;
std::string m_agent;
};

File diff suppressed because it is too large Load Diff

View File

@ -1,160 +0,0 @@
#pragma once
#include "../util.hpp"
#include "objects.hpp"
#include <unordered_map>
#include <unordered_set>
#include <mutex>
#include <filesystem>
#include <sqlite3.h>
#ifdef GetMessage // fuck you windows.h
#undef GetMessage
#endif
class Store {
public:
Store(bool mem_store = false);
~Store();
bool IsValid() const;
void SetUser(Snowflake id, const UserData &user);
void SetChannel(Snowflake id, const ChannelData &chan);
void SetGuild(Snowflake id, const GuildData &guild);
void SetRole(Snowflake id, const RoleData &role);
void SetMessage(Snowflake id, const Message &message);
void SetGuildMember(Snowflake guild_id, Snowflake user_id, const GuildMember &data);
void SetPermissionOverwrite(Snowflake channel_id, Snowflake id, const PermissionOverwrite &perm);
void SetEmoji(Snowflake id, const EmojiData &emoji);
void SetBan(Snowflake guild_id, Snowflake user_id, const BanData &ban);
// slap const on everything even tho its not *really* const
std::optional<ChannelData> GetChannel(Snowflake id) const;
std::optional<EmojiData> GetEmoji(Snowflake id) const;
std::optional<GuildData> GetGuild(Snowflake id) const;
std::optional<GuildMember> GetGuildMember(Snowflake guild_id, Snowflake user_id) const;
std::optional<Message> GetMessage(Snowflake id) const;
std::optional<PermissionOverwrite> GetPermissionOverwrite(Snowflake channel_id, Snowflake id) const;
std::optional<RoleData> GetRole(Snowflake id) const;
std::optional<UserData> GetUser(Snowflake id) const;
std::optional<BanData> GetBan(Snowflake guild_id, Snowflake user_id) const;
std::vector<BanData> GetBans(Snowflake guild_id) const;
void ClearGuild(Snowflake id);
void ClearChannel(Snowflake id);
void ClearBan(Snowflake guild_id, Snowflake user_id);
using users_type = std::unordered_map<Snowflake, UserData>;
using channels_type = std::unordered_map<Snowflake, ChannelData>;
using guilds_type = std::unordered_map<Snowflake, GuildData>;
using roles_type = std::unordered_map<Snowflake, RoleData>;
using messages_type = std::unordered_map<Snowflake, Message>;
using members_type = std::unordered_map<Snowflake, std::unordered_map<Snowflake, GuildMember>>; // [guild][user]
using permission_overwrites_type = std::unordered_map<Snowflake, std::unordered_map<Snowflake, PermissionOverwrite>>; // [channel][user/role]
using emojis_type = std::unordered_map<Snowflake, EmojiData>;
const std::unordered_set<Snowflake> &GetChannels() const;
const std::unordered_set<Snowflake> &GetGuilds() const;
void ClearAll();
void BeginTransaction();
void EndTransaction();
private:
void SetMessageInteractionPair(Snowflake message_id, const MessageInteractionData &interaction);
std::unordered_set<Snowflake> m_channels;
std::unordered_set<Snowflake> m_guilds;
bool CreateTables();
bool CreateStatements();
void Cleanup();
template<typename T>
void Bind(sqlite3_stmt *stmt, int index, const std::optional<T> &opt) const;
template<typename T>
typename std::enable_if<std::is_enum<T>::value, void>::type
Bind(sqlite3_stmt *stmt, int index, T val) const;
void Bind(sqlite3_stmt *stmt, int index, int num) const;
void Bind(sqlite3_stmt *stmt, int index, uint64_t num) const;
void Bind(sqlite3_stmt *stmt, int index, const std::string &str) const;
void Bind(sqlite3_stmt *stmt, int index, bool val) const;
void Bind(sqlite3_stmt *stmt, int index, std::nullptr_t) const;
bool RunInsert(sqlite3_stmt *stmt);
bool FetchOne(sqlite3_stmt *stmt) const;
template<typename T>
void Get(sqlite3_stmt *stmt, int index, std::optional<T> &out) const;
template<typename T>
typename std::enable_if<std::is_enum<T>::value, void>::type
Get(sqlite3_stmt *stmt, int index, T &out) const;
void Get(sqlite3_stmt *stmt, int index, int &out) const;
void Get(sqlite3_stmt *stmt, int index, uint64_t &out) const;
void Get(sqlite3_stmt *stmt, int index, std::string &out) const;
void Get(sqlite3_stmt *stmt, int index, bool &out) const;
void Get(sqlite3_stmt *stmt, int index, Snowflake &out) const;
bool IsNull(sqlite3_stmt *stmt, int index) const;
void Reset(sqlite3_stmt *stmt) const;
std::filesystem::path m_db_path;
mutable sqlite3 *m_db;
mutable int m_db_err;
mutable sqlite3_stmt *m_set_user_stmt;
mutable sqlite3_stmt *m_get_user_stmt;
mutable sqlite3_stmt *m_set_perm_stmt;
mutable sqlite3_stmt *m_get_perm_stmt;
mutable sqlite3_stmt *m_set_msg_stmt;
mutable sqlite3_stmt *m_get_msg_stmt;
mutable sqlite3_stmt *m_set_role_stmt;
mutable sqlite3_stmt *m_get_role_stmt;
mutable sqlite3_stmt *m_set_emote_stmt;
mutable sqlite3_stmt *m_get_emote_stmt;
mutable sqlite3_stmt *m_set_member_stmt;
mutable sqlite3_stmt *m_get_member_stmt;
mutable sqlite3_stmt *m_set_guild_stmt;
mutable sqlite3_stmt *m_get_guild_stmt;
mutable sqlite3_stmt *m_set_chan_stmt;
mutable sqlite3_stmt *m_get_chan_stmt;
mutable sqlite3_stmt *m_set_ban_stmt;
mutable sqlite3_stmt *m_get_ban_stmt;
mutable sqlite3_stmt *m_clear_ban_stmt;
mutable sqlite3_stmt *m_get_bans_stmt;
mutable sqlite3_stmt *m_set_msg_interaction_stmt;
};
template<typename T>
inline void Store::Bind(sqlite3_stmt *stmt, int index, const std::optional<T> &opt) const {
if (opt.has_value())
Bind(stmt, index, *opt);
else
sqlite3_bind_null(stmt, index);
}
template<typename T>
inline typename std::enable_if<std::is_enum<T>::value, void>::type
Store::Bind(sqlite3_stmt *stmt, int index, T val) const {
Bind(stmt, index, static_cast<typename std::underlying_type<T>::type>(val));
}
template<typename T>
inline void Store::Get(sqlite3_stmt *stmt, int index, std::optional<T> &out) const {
if (sqlite3_column_type(stmt, index) == SQLITE_NULL)
out = std::nullopt;
else {
T v;
Get(stmt, index, v);
out = std::optional<T>(v);
}
}
template<typename T>
inline typename std::enable_if<std::is_enum<T>::value, void>::type
Store::Get(sqlite3_stmt *stmt, int index, T &out) const {
out = static_cast<T>(sqlite3_column_int(stmt, index));
}

View File

@ -1,40 +0,0 @@
#include "usersettings.hpp"
void from_json(const nlohmann::json &j, UserSettingsGuildFoldersEntry &m) {
JS_N("color", m.Color);
JS_D("guild_ids", m.GuildIDs);
JS_N("id", m.ID);
JS_N("name", m.Name);
}
void from_json(const nlohmann::json &j, UserSettings &m) {
JS_D("timezone_offset", m.TimezoneOffset);
JS_D("theme", m.Theme);
JS_D("stream_notifications_enabled", m.AreStreamNotificationsEnabled);
JS_D("status", m.Status);
JS_D("show_current_game", m.ShouldShowCurrentGame);
// JS_D("restricted_guilds", m.RestrictedGuilds);
JS_D("render_reactions", m.ShouldRenderReactions);
JS_D("render_embeds", m.ShouldRenderEmbeds);
JS_D("native_phone_integration_enabled", m.IsNativePhoneIntegrationEnabled);
JS_D("message_display_compact", m.ShouldMessageDisplayCompact);
JS_D("locale", m.Locale);
JS_D("inline_embed_media", m.ShouldInlineEmbedMedia);
JS_D("inline_attachment_media", m.ShouldInlineAttachmentMedia);
JS_D("guild_positions", m.GuildPositions);
JS_D("guild_folders", m.GuildFolders);
JS_D("gif_auto_play", m.ShouldGIFAutoplay);
// JS_D("friend_source_flags", m.FriendSourceFlags);
JS_D("explicit_content_filter", m.ExplicitContentFilter);
JS_D("enable_tts_command", m.IsTTSCommandEnabled);
JS_D("disable_games_tab", m.ShouldDisableGamesTab);
JS_D("developer_mode", m.DeveloperMode);
JS_D("detect_platform_accounts", m.ShouldDetectPlatformAccounts);
JS_D("default_guilds_restricted", m.AreDefaultGuildsRestricted);
// JS_N("custom_status", m.CustomStatus);
JS_D("convert_emoticons", m.ShouldConvertEmoticons);
JS_D("contact_sync_enabled", m.IsContactSyncEnabled);
JS_D("animate_emoji", m.ShouldAnimateEmojis);
JS_D("allow_accessibility_detection", m.IsAccessibilityDetectionAllowed);
JS_D("afk_timeout", m.AFKTimeout);
}

View File

@ -1,47 +0,0 @@
#pragma once
#include "json.hpp"
#include "snowflake.hpp"
#include <string>
struct UserSettingsGuildFoldersEntry {
int Color = -1; // null
std::vector<Snowflake> GuildIDs;
Snowflake ID; // null (this can be a snowflake as a string or an int that isnt a snowflake lol)
std::string Name; // null
friend void from_json(const nlohmann::json &j, UserSettingsGuildFoldersEntry &m);
};
struct UserSettings {
int TimezoneOffset; //
std::string Theme; //
bool AreStreamNotificationsEnabled; //
std::string Status; //
bool ShouldShowCurrentGame; //
// std::vector<Unknown> RestrictedGuilds; //
bool ShouldRenderReactions; //
bool ShouldRenderEmbeds; //
bool IsNativePhoneIntegrationEnabled; //
bool ShouldMessageDisplayCompact; //
std::string Locale; //
bool ShouldInlineEmbedMedia; //
bool ShouldInlineAttachmentMedia; //
std::vector<Snowflake> GuildPositions; // deprecated?
std::vector<UserSettingsGuildFoldersEntry> GuildFolders; //
bool ShouldGIFAutoplay; //
// Unknown FriendSourceFlags; //
int ExplicitContentFilter; //
bool IsTTSCommandEnabled; //
bool ShouldDisableGamesTab; //
bool DeveloperMode; //
bool ShouldDetectPlatformAccounts; //
bool AreDefaultGuildsRestricted; //
// Unknown CustomStatus; // null
bool ShouldConvertEmoticons; //
bool IsContactSyncEnabled; //
bool ShouldAnimateEmojis; //
bool IsAccessibilityDetectionAllowed; //
int AFKTimeout;
friend void from_json(const nlohmann::json &j, UserSettings &m);
};

121
http.cpp
View File

@ -1,121 +0,0 @@
#include "http.hpp"
namespace http {
request::request(EMethod method, const std::string &url)
: m_url(url) {
switch (method) {
case REQUEST_GET:
m_method = "GET";
break;
case REQUEST_POST:
m_method = "POST";
break;
case REQUEST_PATCH:
m_method = "PATCH";
break;
case REQUEST_PUT:
m_method = "PUT";
break;
case REQUEST_DELETE:
m_method = "DELETE";
break;
default:
m_method = "GET";
break;
}
prepare();
}
request::~request() {
if (m_curl != nullptr)
curl_easy_cleanup(m_curl);
if (m_header_list != nullptr)
curl_slist_free_all(m_header_list);
}
void request::set_verify_ssl(bool verify) {
curl_easy_setopt(m_curl, CURLOPT_SSL_VERIFYPEER, verify ? 1L : 0L);
}
void request::set_proxy(const std::string &proxy) {
curl_easy_setopt(m_curl, CURLOPT_PROXY, proxy.c_str());
}
void request::set_header(const std::string &name, const std::string &value) {
m_header_list = curl_slist_append(m_header_list, (name + ": " + value).c_str());
}
void request::set_body(const std::string &data) {
curl_easy_setopt(m_curl, CURLOPT_COPYPOSTFIELDS, data.c_str());
}
void request::set_user_agent(const std::string &data) {
curl_easy_setopt(m_curl, CURLOPT_USERAGENT, data.c_str());
}
response request::execute() {
if (m_curl == nullptr) {
auto response = detail::make_response(m_url, EStatusCode::ClientErrorCURLInit);
response.error_string = "curl pointer is null";
}
detail::check_init();
std::string str;
curl_easy_setopt(m_curl, CURLOPT_CUSTOMREQUEST, m_method);
curl_easy_setopt(m_curl, CURLOPT_URL, m_url.c_str());
curl_easy_setopt(m_curl, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, detail::curl_write_data_callback);
curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &str);
curl_easy_setopt(m_curl, CURLOPT_ERRORBUFFER, m_error_buf);
if (m_header_list != nullptr)
curl_easy_setopt(m_curl, CURLOPT_HTTPHEADER, m_header_list);
CURLcode result = curl_easy_perform(m_curl);
if (result != CURLE_OK) {
auto response = detail::make_response(m_url, EStatusCode::ClientErrorCURLPerform);
response.error_string = curl_easy_strerror(result);
response.error_string += " " + std::string(m_error_buf);
return response;
}
int response_code = 0;
curl_easy_getinfo(m_curl, CURLINFO_RESPONSE_CODE, &response_code);
auto response = detail::make_response(m_url, response_code);
response.text = str;
return response;
}
void request::prepare() {
m_curl = curl_easy_init();
}
namespace detail {
size_t curl_write_data_callback(void *ptr, size_t size, size_t nmemb, std::string *outstr) {
auto new_length = size * nmemb;
outstr->append(reinterpret_cast<char *>(ptr), new_length);
return new_length;
}
response make_response(const std::string &url, int code) {
response r;
r.url = url;
r.status_code = static_cast<EStatusCode>(code);
if (code < http::EStatusCode::ClientErrorMax)
r.error = true;
return r;
}
void check_init() {
static bool initialized = false;
if (!initialized) {
curl_global_init(CURL_GLOBAL_ALL);
initialized = true;
}
}
} // namespace detail
} // namespace http

View File

@ -0,0 +1,89 @@
/*
application wide stuff
has to be separate to allow main.css to override certain things
*/
.app-window label:not(:disabled) {
color: @text_color;
}
.app-window entry {
background: @secondary_color;
color: @text_color;
border: 1px solid #1c2e40;
}
.app-window button {
background: @secondary_color;
color: @text_color;
text-shadow: none;
box-shadow: none;
}
.app-window button:checked {
border-top: 0px;
border-left: 0px;
border-right: 0px;
border-bottom: 3px solid #39a2ed;
color: #ffffff;
}
.app-window button:not(:checked) {
border: 3px #0000ff;
}
.app-window.background {
background: @background_color;
}
.app-window treeview {
color: @text_color;
}
.app-window treeview:not(:selected) {
background: @secondary_color;
}
.app-popup list {
background: @secondary_color;
}
.app-window paned separator {
background: @background_color;
}
.app-window scrollbar {
background: @background_color;
border-left: 1px solid transparent;
}
.app-window menubar, menu {
background: @background_color;
color: #cccccc;
}
.app-window textview text {
caret-color: #ababab;
}
.app-window check,
.app-window radio {
background-clip: padding-box;
background: @secondary_color;
border-color: #070707;
box-shadow: 0 1px rgba(0, 0, 0, 0);
color: #dddddd;
}
.app-window check:checked,
.app-window radio:checked {
background-clip: border-box;
background: #0b4285;
border-color: #092444;
box-shadow: 0 1px rgba(0, 0, 0, 0);
color: #dddddd;
}
.app-window colorswatch {
box-shadow: 0 1px rgba(0, 0, 0, 0);
}

View File

@ -57,14 +57,8 @@
padding: 15px;
}
.message-container + .message-container {
margin-top: 10px;
}
.message-container-extra {
color: #78909c;
margin-left: -5px;
margin-right: -5px;
}
.message-container-timestamp {
@ -72,7 +66,8 @@
}
.message-text {
padding-top: 5px;
/* this isnt stricly necessary but it fixes emoji clipping */
padding-bottom: 5px;
}
.message-text:not(.failed) text, .message-reply {
@ -106,17 +101,38 @@
.message-input, .message-input textview, .message-input textview text {
background-color: #242424;
color: #adadad;
border-radius: 15px;
border-radius: 3px;
border: 1px solid transparent;
}
.message-input {
border: 1px solid #444444;
margin-right: 15px;
}
.message-input.replying {
border: 1px solid #026FB9;
}
.message-input {
.message-input.bad-input {
border: 1px solid #dd3300;
}
.message-input-browse-icon {
color: #b9bbbe;
margin-left: 5px;
margin-top: 11px;
}
/* i dont think theres a way to circumvent having to do this to adjust around the browse icon */
.message-input:not(.with-browser-icon) {
padding: 0px 0px 0px 5px;
}
.message-input.with-browse-icon {
padding: 0px 0px 0px 30px;
}
.members {
background-color: @background_color;
}
@ -141,6 +157,26 @@
margin: 5px;
}
.message-component {
margin: 5px;
}
.message-component.primary {
background: #5865F2;
}
.message-component.secondary, .message-component.link {
background: #4F545C;
}
.message-component.success {
background: #43B581;
}
.message-component.danger {
background: #F04747;
}
.reaction-box {
padding: 2px 5px 2px 5px;
margin: 0px 0px 0px 0px;
@ -176,62 +212,6 @@
color: @text_color;
}
.app-window label:not(:disabled) {
color: @text_color;
}
.app-window entry {
background: @secondary_color;
color: @text_color;
border: 1px solid #1c2e40;
}
.app-window button {
background: @secondary_color;
color: @text_color;
text-shadow: none;
box-shadow: none;
}
.app-window button:checked {
border-top: 0px;
border-left: 0px;
border-right: 0px;
border-bottom: 3px solid #39a2ed;
color: #ffffff;
}
.app-window button:not(:checked) {
border: 3px #0000ff;
}
.app-window.background {
background: @background_color;
}
.app-window treeview {
color: @text_color;
background: @secondary_color;
}
.app-popup list {
background: @secondary_color;
}
.app-window paned separator {
background: @background_color;
}
.app-window scrollbar {
background: @background_color;
border-left: 1px solid transparent;
}
.app-window menubar, menu {
background: @background_color;
color: #cccccc;
}
.status-indicator.dnd {
color: #982929;
}
@ -303,37 +283,10 @@
padding-left: 5px;
}
.app-window textview text {
caret-color: #ababab;
}
.guild-members-pane-info {
padding: 10px;
}
.app-window check,
.app-window radio {
background-clip: padding-box;
background: @secondary_color;
border-color: #070707;
box-shadow: 0 1px rgba(0, 0, 0, 0);
color: #dddddd;
}
.app-window check:checked,
.app-window radio:checked {
background-clip: border-box;
background: #0b4285;
border-color: #092444;
box-shadow: 0 1px rgba(0, 0, 0, 0);
color: #dddddd;
}
.app-window colorswatch {
box-shadow: 0 1px rgba(0, 0, 0, 0);
}
.drag-hover-top {
background: linear-gradient(to bottom, rgba(255, 66, 66, 0.65) 0%, rgba(0, 0, 0, 0) 35%);
}
@ -341,3 +294,69 @@
.drag-hover-bottom {
background: linear-gradient(to bottom, rgba(0, 0, 0, 0) 65%, rgba(255, 66, 66, 0.65) 100%);
}
.friends-list list {
background: @background_color;
padding-left: 10px;
}
.friends-list-row-bot {
color: #ff0000;
}
.channel-tab-switcher .box {
margin: -7px -1px -7px -1px;
background: #2a2a2a;
border: 1px solid black;
}
.channel-tab-switcher tab:hover {
box-shadow: inset 0 -6px #17633e;
}
.channel-tab-switcher tab:checked {
box-shadow: inset 0 -6px #2feb90;
}
.channel-tab-switcher tab {
background: #1A1A1A;
border: 1px solid #808080;
min-height: 35px;
}
.channel-tab-switcher tab.needs-attention:not(:checked) {
font-weight: bold;
animation: 150ms ease-in;
/* background-image: radial-gradient(ellipse at bottom, #FF5370, #1A1A1A 30%); */
box-shadow: inset 0 -6px red;
}
.channel-tab-switcher tab > button {
border: none;
padding: 0;
margin: 5px;
min-width: 16px;
min-height: 16px;
color: #FF5370;
background-color: rgba(0.21, 0.21, 0.21, 0.5);
}
.channel-tab-switcher tab > button:hover {
background-color: alpha(#ff0000, 0.5);
}
.message-progress {
border: none;
margin-bottom: -8px;
}
.message-progress trough {
border: none;
background-color: transparent;
}
.message-progress progress {
border: none;
background-color: #dd3300;
margin-left: 1px;
}

Binary file not shown.

View File

@ -0,0 +1,14 @@
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<!-- Use the Autohinter -->
<match target="pattern">
<!--
This configuration is available on the major desktop environments.
We shouldn't overwrite it with "assign" unconditionally.
Most clients may picks up the first value only. so using "append"
may simply works to avoid it.
-->
<edit name="autohint" mode="append"><bool>true</bool></edit>
</match>
</fontconfig>

View File

@ -0,0 +1,13 @@
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<match target="pattern">
<!--
This configuration is available on the major desktop environments.
We shouldn't overwrite it with "assign" unconditionally.
Most clients may picks up the first value only. so using "append"
may simply works to avoid it.
-->
<edit name="hintstyle" mode="append"><const>hintfull</const></edit>
</match>
</fontconfig>

View File

@ -0,0 +1,13 @@
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<match target="pattern">
<!--
This configuration is available on the major desktop environments.
We shouldn't overwrite it with "assign" unconditionally.
Most clients may picks up the first value only. so using "append"
may simply works to avoid it.
-->
<edit name="hintstyle" mode="append"><const>hintmedium</const></edit>
</match>
</fontconfig>

View File

@ -0,0 +1,13 @@
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<match target="pattern">
<!--
This configuration is available on the major desktop environments.
We shouldn't overwrite it with "assign" unconditionally.
Most clients may picks up the first value only. so using "append"
may simply works to avoid it.
-->
<edit name="hintstyle" mode="append"><const>hintnone</const></edit>
</match>
</fontconfig>

View File

@ -0,0 +1,13 @@
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<match target="pattern">
<!--
This configuration is available on the major desktop environments.
We shouldn't overwrite it with "assign" unconditionally.
Most clients may picks up the first value only. so using "append"
may simply works to avoid it.
-->
<edit name="hintstyle" mode="append"><const>hintslight</const></edit>
</match>
</fontconfig>

View File

@ -0,0 +1,14 @@
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<!-- Disable sub-pixel rendering -->
<match target="pattern">
<!--
This configuration is available on the major desktop environments.
We shouldn't overwrite it with "assign" unconditionally.
Most clients may picks up the first value only. so using "append"
may simply works to avoid it.
-->
<edit name="rgba" mode="append"><const>none</const></edit>
</match>
</fontconfig>

View File

@ -0,0 +1,80 @@
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<!--
If font is bitmap, calculate scale factor.
Note that color bitmap fonts have scalable=true, while
non-color ones have scalable=false. Both groups have outline=false.
-->
<match target="font">
<test name="outline" compare="eq">
<bool>false</bool>
</test>
<edit name="pixelsizefixupfactor" mode="assign">
<double>0.15</double>
</edit>
</match>
<!--
For non-scalable bitmap fonts (ie. non-color), skip
minor scaling if hinting is enabled.
-->
<match target="font">
<test name="outline" compare="eq">
<bool>false</bool>
</test>
<test name="scalable" compare="eq">
<bool>false</bool>
</test>
<test name="hinting" compare="eq">
<bool>true</bool>
</test>
<edit name="scalingnotneeded" mode="assign">
<and>
<less>
<name>pixelsizefixupfactor</name>
<double>1.2</double>
</less>
<more>
<name>pixelsizefixupfactor</name>
<double>0.8</double>
</more>
</and>
</edit>
</match>
<match target="font">
<test name="scalingnotneeded" compare="eq">
<bool>true</bool>
</test>
<edit name="pixelsizefixupfactor" mode="assign">
<double>1.0</double>
</edit>
</match>
<!--
If we *are* going to scale, go ahead and do it.
-->
<match target="font">
<test name="outline" compare="eq">
<bool>false</bool>
</test>
<test name="pixelsizefixupfactor" compare="not_eq">
<double>1.0</double>
</test>
<edit name="matrix" mode="assign">
<times>
<name>matrix</name>
<matrix>
<name>pixelsizefixupfactor</name> <double>0</double>
<double>0</double> <name>pixelsizefixupfactor</name>
</matrix>
</times>
</edit>
<edit name="size" mode="assign">
<divide>
<name>size</name>
<name>pixelsizefixupfactor</name>
</divide>
</edit>
</match>
</fontconfig>

View File

@ -0,0 +1,14 @@
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<!-- Enable sub-pixel rendering -->
<match target="pattern">
<!--
This configuration is available on the major desktop environments.
We shouldn't overwrite it with "assign" unconditionally.
Most clients may picks up the first value only. so using "append"
may simply works to avoid it.
-->
<edit name="rgba" mode="append"><const>bgr</const></edit>
</match>
</fontconfig>

View File

@ -0,0 +1,14 @@
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<!-- Enable sub-pixel rendering -->
<match target="pattern">
<!--
This configuration is available on the major desktop environments.
We shouldn't overwrite it with "assign" unconditionally.
Most clients may picks up the first value only. so using "append"
may simply works to avoid it.
-->
<edit name="rgba" mode="append"><const>rgb</const></edit>
</match>
</fontconfig>

View File

@ -0,0 +1,14 @@
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<!-- Enable sub-pixel rendering -->
<match target="pattern">
<!--
This configuration is available on the major desktop environments.
We shouldn't overwrite it with "assign" unconditionally.
Most clients may picks up the first value only. so using "append"
may simply works to avoid it.
-->
<edit name="rgba" mode="append"><const>vbgr</const></edit>
</match>
</fontconfig>

View File

@ -0,0 +1,14 @@
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<!-- Enable sub-pixel rendering -->
<match target="pattern">
<!--
This configuration is available on the major desktop environments.
We shouldn't overwrite it with "assign" unconditionally.
Most clients may picks up the first value only. so using "append"
may simply works to avoid it.
-->
<edit name="rgba" mode="append"><const>vrgb</const></edit>
</match>
</fontconfig>

View File

@ -0,0 +1,14 @@
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<!-- Disable hinting -->
<match target="pattern">
<!--
This configuration is available on the major desktop environments.
We shouldn't overwrite it with "assign" unconditionally.
Most clients may picks up the first value only. so using "append"
may simply works to avoid it.
-->
<edit name="hinting" mode="append"><bool>false</bool></edit>
</match>
</fontconfig>

View File

@ -0,0 +1,16 @@
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<!-- Use lcddefault as default for LCD filter -->
<match target="pattern">
<!--
This configuration is available on the major desktop environments.
We shouldn't overwrite it with "assign" unconditionally.
Most clients may picks up the first value only. so using "append"
may simply works to avoid it.
-->
<edit mode="append" name="lcdfilter">
<const>lcddefault</const>
</edit>
</match>
</fontconfig>

View File

@ -0,0 +1,16 @@
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<!-- Use lcdlegacy as default for LCD filter -->
<match target="pattern">
<!--
This configuration is available on the major desktop environments.
We shouldn't overwrite it with "assign" unconditionally.
Most clients may picks up the first value only. so using "append"
may simply works to avoid it.
-->
<edit mode="append" name="lcdfilter">
<const>lcdlegacy</const>
</edit>
</match>
</fontconfig>

View File

@ -0,0 +1,16 @@
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<!-- Use lcdlight as default for LCD filter -->
<match target="pattern">
<!--
This configuration is available on the major desktop environments.
We shouldn't overwrite it with "assign" unconditionally.
Most clients may picks up the first value only. so using "append"
may simply works to avoid it.
-->
<edit mode="append" name="lcdfilter">
<const>lcdlight</const>
</edit>
</match>
</fontconfig>

View File

@ -0,0 +1,48 @@
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<!--
The Bitstream Vera fonts have GASP entries suggesting that hinting be
disabled below 8 ppem, but FreeType ignores those, preferring to use
the data found in the instructed hints. The initial Vera release
didn't include the right instructions in the 'prep' table. Fix this
by disabling hinting manually at smaller sizes (< 8ppem)
-->
<match target="font">
<test name="family" compare="eq" ignore-blanks="true">
<string>Bitstream Vera Sans</string>
</test>
<test name="pixelsize" compare="less">
<double>7.5</double>
</test>
<edit name="hinting">
<bool>false</bool>
</edit>
</match>
<match target="font">
<test name="family" compare="eq" ignore-blanks="true">
<string>Bitstream Vera Serif</string>
</test>
<test name="pixelsize" compare="less">
<double>7.5</double>
</test>
<edit name="hinting">
<bool>false</bool>
</edit>
</match>
<match target="font">
<test name="family" compare="eq" ignore-blanks="true">
<string>Bitstream Vera Sans Mono</string>
</test>
<test name="pixelsize" compare="less">
<double>7.5</double>
</test>
<edit name="hinting">
<bool>false</bool>
</edit>
</match>
</fontconfig>

View File

@ -0,0 +1,128 @@
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<!-- We can't hint CJK fonts well, so turn off hinting for CJK fonts. -->
<match target="font">
<test name="family" compare="eq" ignore-blanks="true">
<string>Kochi Mincho</string>
</test>
<edit name="hinting" mode="assign">
<bool>false</bool>
</edit>
</match>
<match target="font">
<test name="family" compare="eq" ignore-blanks="true">
<string>Kochi Gothic</string>
</test>
<edit name="hinting" mode="assign">
<bool>false</bool>
</edit>
</match>
<match target="font">
<test name="family" compare="eq" ignore-blanks="true">
<string>Sazanami Mincho</string>
</test>
<edit name="hinting" mode="assign">
<bool>false</bool>
</edit>
</match>
<match target="font">
<test name="family" compare="eq" ignore-blanks="true">
<string>Sazanami Gothic</string>
</test>
<edit name="hinting" mode="assign">
<bool>false</bool>
</edit>
</match>
<match target="font">
<test name="family" compare="eq" ignore-blanks="true">
<string>Baekmuk Batang</string>
</test>
<edit name="hinting" mode="assign">
<bool>false</bool>
</edit>
</match>
<match target="font">
<test name="family" compare="eq" ignore-blanks="true">
<string>Baekmuk Dotum</string>
</test>
<edit name="hinting" mode="assign">
<bool>false</bool>
</edit>
</match>
<match target="font">
<test name="family" compare="eq" ignore-blanks="true">
<string>Baekmuk Gulim</string>
</test>
<edit name="hinting" mode="assign">
<bool>false</bool>
</edit>
</match>
<match target="font">
<test name="family" compare="eq" ignore-blanks="true">
<string>Baekmuk Headline</string>
</test>
<edit name="hinting" mode="assign">
<bool>false</bool>
</edit>
</match>
<match target="font">
<test name="family" compare="eq" ignore-blanks="true">
<string>AR PL Mingti2L Big5</string>
</test>
<edit name="hinting" mode="assign">
<bool>false</bool>
</edit>
</match>
<match target="font">
<test name="family" compare="eq" ignore-blanks="true">
<string>AR PL ShanHeiSun Uni</string>
</test>
<edit name="hinting" mode="assign">
<bool>false</bool>
</edit>
</match>
<match target="font">
<test name="family" compare="eq" ignore-blanks="true">
<string>AR PL KaitiM Big5</string>
</test>
<edit name="hinting" mode="assign">
<bool>false</bool>
</edit>
</match>
<match target="font">
<test name="family" compare="eq" ignore-blanks="true">
<string>AR PL ZenKai Uni</string>
</test>
<edit name="hinting" mode="assign">
<bool>false</bool>
</edit>
</match>
<match target="font">
<test name="family" compare="eq" ignore-blanks="true">
<string>AR PL SungtiL GB</string>
</test>
<edit name="hinting" mode="assign">
<bool>false</bool>
</edit>
</match>
<match target="font">
<test name="family" compare="eq" ignore-blanks="true">
<string>AR PL KaitiM GB</string>
</test>
<edit name="hinting" mode="assign">
<bool>false</bool>
</edit>
</match>
<match target="font">
<test name="family" compare="eq" ignore-blanks="true">
<string>ZYSong18030</string>
</test>
<edit name="hinting" mode="assign">
<bool>false</bool>
</edit>
</match>
</fontconfig>

View File

@ -0,0 +1,652 @@
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<!--
Alias similar/metric-compatible families from various sources:
PostScript fonts: URW fonts: GUST fonts: Windows fonts:
====================== ================== ================= ==================
Helvetica Nimbus Sans TeX Gyre Heros
Helvetica Narrow Nimbus Sans Narrow TeX Gyre Heros Cn
Times Nimbus Roman TeX Gyre Termes
Courier Nimbus Mono PS TeX Gyre Cursor
ITC Avant Garde Gothic URW Gothic TeX Gyre Adventor
ITC Bookman URW Bookman TeX Gyre Bonum Bookman Old Style
ITC Zapf Chancery Z003 TeX Gyre Chorus
Palatino P052 TeX Gyre Pagella Palatino Linotype
New Century Schoolbook C059 TeX Gyre Schola Century Schoolbook
Microsoft fonts: Liberation fonts: Google CrOS core fonts: StarOffice fonts: AMT fonts:
================ ====================== ======================= ================= ==============
Arial Liberation Sans Arimo Albany Albany AMT
Arial Narrow Liberation Sans Narrow
Times New Roman Liberation Serif Tinos Thorndale Thorndale AMT
Courier New Liberation Mono Cousine Cumberland Cumberland AMT
Cambria Caladea
Calibri Carlito
Symbol SymbolNeu
Microsoft fonts: Other fonts:
================ ============
Georgia Gelasio
We want for each of them to fallback to any of these available,
but in an order preferring similar designs first. We do this in three steps:
1) Alias each specific to its generic family.
e.g. Liberation Sans to Arial
2) Weak alias each generic to the other generic of its family.
e.g. Arial to Helvetica
3) Alias each generic to its specifics.
e.g. Arial to Liberation Sans, Arimo, Albany, and Albany AMT
-->
<!-- Map specifics to generics -->
<!-- PostScript -->
<alias binding="same">
<family>Nimbus Sans L</family>
<default>
<family>Helvetica</family>
</default>
</alias>
<alias binding="same">
<family>Nimbus Sans</family>
<default>
<family>Helvetica</family>
</default>
</alias>
<alias binding="same">
<family>TeX Gyre Heros</family>
<default>
<family>Helvetica</family>
</default>
</alias>
<alias binding="same">
<family>Nimbus Sans Narrow</family>
<default>
<family>Helvetica Narrow</family>
</default>
</alias>
<alias binding="same">
<family>TeX Gyre Heros Cn</family>
<default>
<family>Helvetica Narrow</family>
</default>
</alias>
<alias binding="same">
<family>Nimbus Roman No9 L</family>
<default>
<family>Times</family>
</default>
</alias>
<alias binding="same">
<family>Nimbus Roman</family>
<default>
<family>Times</family>
</default>
</alias>
<alias binding="same">
<family>TeX Gyre Termes</family>
<default>
<family>Times</family>
</default>
</alias>
<alias binding="same">
<family>Nimbus Mono L</family>
<default>
<family>Courier</family>
</default>
</alias>
<alias binding="same">
<family>Nimbus Mono</family>
<default>
<family>Courier</family>
</default>
</alias>
<alias binding="same">
<family>Nimbus Mono PS</family>
<default>
<family>Courier</family>
</default>
</alias>
<alias binding="same">
<family>TeX Gyre Cursor</family>
<default>
<family>Courier</family>
</default>
</alias>
<alias binding="same">
<family>Avant Garde</family>
<default>
<family>ITC Avant Garde Gothic</family>
</default>
</alias>
<alias binding="same">
<family>URW Gothic L</family>
<default>
<family>ITC Avant Garde Gothic</family>
</default>
</alias>
<alias binding="same">
<family>URW Gothic</family>
<default>
<family>ITC Avant Garde Gothic</family>
</default>
</alias>
<alias binding="same">
<family>TeX Gyre Adventor</family>
<default>
<family>ITC Avant Garde Gothic</family>
</default>
</alias>
<alias binding="same">
<family>Bookman</family>
<default>
<family>ITC Bookman</family>
</default>
</alias>
<alias binding="same">
<family>URW Bookman L</family>
<default>
<family>ITC Bookman</family>
</default>
</alias>
<alias binding="same">
<family>Bookman URW</family>
<default>
<family>ITC Bookman</family>
</default>
</alias>
<alias binding="same">
<family>URW Bookman</family>
<default>
<family>ITC Bookman</family>
</default>
</alias>
<alias binding="same">
<family>TeX Gyre Bonum</family>
<default>
<family>ITC Bookman</family>
</default>
</alias>
<alias binding="same">
<family>Bookman Old Style</family>
<default>
<family>ITC Bookman</family>
</default>
</alias>
<alias binding="same">
<family>Zapf Chancery</family>
<default>
<family>ITC Zapf Chancery</family>
</default>
</alias>
<alias binding="same">
<family>URW Chancery L</family>
<default>
<family>ITC Zapf Chancery</family>
</default>
</alias>
<alias binding="same">
<family>Chancery URW</family>
<default>
<family>ITC Zapf Chancery</family>
</default>
</alias>
<alias binding="same">
<family>Z003</family>
<default>
<family>ITC Zapf Chancery</family>
</default>
</alias>
<alias binding="same">
<family>TeX Gyre Chorus</family>
<default>
<family>ITC Zapf Chancery</family>
</default>
</alias>
<alias binding="same">
<family>URW Palladio L</family>
<default>
<family>Palatino</family>
</default>
</alias>
<alias binding="same">
<family>Palladio URW</family>
<default>
<family>Palatino</family>
</default>
</alias>
<alias binding="same">
<family>P052</family>
<default>
<family>Palatino</family>
</default>
</alias>
<alias binding="same">
<family>TeX Gyre Pagella</family>
<default>
<family>Palatino</family>
</default>
</alias>
<alias binding="same">
<family>Palatino Linotype</family>
<default>
<family>Palatino</family>
</default>
</alias>
<alias binding="same">
<family>Century Schoolbook L</family>
<default>
<family>New Century Schoolbook</family>
</default>
</alias>
<alias binding="same">
<family>Century SchoolBook URW</family>
<default>
<family>New Century Schoolbook</family>
</default>
</alias>
<alias binding="same">
<family>C059</family>
<default>
<family>New Century Schoolbook</family>
</default>
</alias>
<alias binding="same">
<family>TeX Gyre Schola</family>
<default>
<family>New Century Schoolbook</family>
</default>
</alias>
<alias binding="same">
<family>Century Schoolbook</family>
<default>
<family>New Century Schoolbook</family>
</default>
</alias>
<!-- Microsoft -->
<alias binding="same">
<family>Arimo</family>
<default>
<family>Arial</family>
</default>
</alias>
<alias binding="same">
<family>Liberation Sans</family>
<default>
<family>Arial</family>
</default>
</alias>
<alias binding="same">
<family>Liberation Sans Narrow</family>
<default>
<family>Arial Narrow</family>
</default>
</alias>
<alias binding="same">
<family>Albany</family>
<default>
<family>Arial</family>
</default>
</alias>
<alias binding="same">
<family>Albany AMT</family>
<default>
<family>Arial</family>
</default>
</alias>
<alias binding="same">
<family>Tinos</family>
<default>
<family>Times New Roman</family>
</default>
</alias>
<alias binding="same">
<family>Liberation Serif</family>
<default>
<family>Times New Roman</family>
</default>
</alias>
<alias binding="same">
<family>Thorndale</family>
<default>
<family>Times New Roman</family>
</default>
</alias>
<alias binding="same">
<family>Thorndale AMT</family>
<default>
<family>Times New Roman</family>
</default>
</alias>
<alias binding="same">
<family>Cousine</family>
<default>
<family>Courier New</family>
</default>
</alias>
<alias binding="same">
<family>Liberation Mono</family>
<default>
<family>Courier New</family>
</default>
</alias>
<alias binding="same">
<family>Cumberland</family>
<default>
<family>Courier New</family>
</default>
</alias>
<alias binding="same">
<family>Cumberland AMT</family>
<default>
<family>Courier New</family>
</default>
</alias>
<alias binding="same">
<family>Gelasio</family>
<default>
<family>Georgia</family>
</default>
</alias>
<alias binding="same">
<family>Caladea</family>
<default>
<family>Cambria</family>
</default>
</alias>
<alias binding="same">
<family>Carlito</family>
<default>
<family>Calibri</family>
</default>
</alias>
<alias binding="same">
<family>SymbolNeu</family>
<default>
<family>Symbol</family>
</default>
</alias>
<!-- Accept the other group as fallback -->
<!-- PostScript -->
<alias>
<family>Helvetica</family>
<default>
<family>Arial</family>
</default>
</alias>
<alias>
<family>Helvetica Narrow</family>
<default>
<family>Arial Narrow</family>
</default>
</alias>
<alias>
<family>Times</family>
<default>
<family>Times New Roman</family>
</default>
</alias>
<alias>
<family>Courier</family>
<default>
<family>Courier New</family>
</default>
</alias>
<!-- Microsoft -->
<alias>
<family>Arial</family>
<default>
<family>Helvetica</family>
</default>
</alias>
<alias>
<family>Arial Narrow</family>
<default>
<family>Helvetica Narrow</family>
</default>
</alias>
<alias>
<family>Times New Roman</family>
<default>
<family>Times</family>
</default>
</alias>
<alias>
<family>Courier New</family>
<default>
<family>Courier</family>
</default>
</alias>
<!-- Map generics to specifics -->
<!-- PostScript -->
<alias binding="same">
<family>Helvetica</family>
<accept>
<family>TeX Gyre Heros</family>
<family>Nimbus Sans</family>
<family>Nimbus Sans L</family>
</accept>
</alias>
<alias binding="same">
<family>Helvetica Narrow</family>
<accept>
<family>TeX Gyre Heros Cn</family>
<family>Nimbus Sans Narrow</family>
</accept>
</alias>
<alias binding="same">
<family>Times</family>
<accept>
<family>TeX Gyre Termes</family>
<family>Nimbus Roman</family>
<family>Nimbus Roman No9 L</family>
</accept>
</alias>
<alias binding="same">
<family>Courier</family>
<accept>
<family>TeX Gyre Cursor</family>
<family>Nimbus Mono PS</family>
<family>Nimbus Mono</family>
<family>Nimbus Mono L</family>
</accept>
</alias>
<alias binding="same">
<family>ITC Avant Garde Gothic</family>
<accept>
<family>TeX Gyre Adventor</family>
<family>URW Gothic</family>
<family>URW Gothic L</family>
</accept>
</alias>
<alias binding="same">
<family>ITC Bookman</family>
<accept>
<family>Bookman Old Style</family>
<family>TeX Gyre Bonum</family>
<family>URW Bookman</family>
<family>Bookman URW</family>
<family>URW Bookman L</family>
</accept>
</alias>
<alias binding="same">
<family>ITC Zapf Chancery</family>
<accept>
<family>TeX Gyre Chorus</family>
<family>Z003</family>
<family>Chancery URW</family>
<family>URW Chancery L</family>
</accept>
</alias>
<alias binding="same">
<family>Palatino</family>
<accept>
<family>Palatino Linotype</family>
<family>TeX Gyre Pagella</family>
<family>P052</family>
<family>Palladio URW</family>
<family>URW Palladio L</family>
</accept>
</alias>
<alias binding="same">
<family>New Century Schoolbook</family>
<accept>
<family>Century Schoolbook</family>
<family>TeX Gyre Schola</family>
<family>C059</family>
<family>Century SchoolBook URW</family>
<family>Century Schoolbook L</family>
</accept>
</alias>
<!-- Microsoft -->
<alias binding="same">
<family>Arial</family>
<accept>
<family>Arimo</family>
<family>Liberation Sans</family>
<family>Albany</family>
<family>Albany AMT</family>
</accept>
</alias>
<alias binding="same">
<family>Arial Narrow</family>
<accept>
<family>Liberation Sans Narrow</family>
</accept>
</alias>
<alias binding="same">
<family>Times New Roman</family>
<accept>
<family>Tinos</family>
<family>Liberation Serif</family>
<family>Thorndale</family>
<family>Thorndale AMT</family>
</accept>
</alias>
<alias binding="same">
<family>Courier New</family>
<accept>
<family>Cousine</family>
<family>Liberation Mono</family>
<family>Cumberland</family>
<family>Cumberland AMT</family>
</accept>
</alias>
<alias binding="same">
<family>Georgia</family>
<accept>
<family>Gelasio</family>
</accept>
</alias>
<alias binding="same">
<family>Cambria</family>
<accept>
<family>Caladea</family>
</accept>
</alias>
<alias binding="same">
<family>Calibri</family>
<accept>
<family>Carlito</family>
</accept>
</alias>
<alias binding="same">
<family>Symbol</family>
<accept>
<family>SymbolNeu</family>
</accept>
</alias>
</fontconfig>

View File

@ -0,0 +1,33 @@
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<!--
URW provides metric and shape compatible fonts for some Adobe families.
Most of these are handled in 30-metric-aliases.conf.
-->
<alias binding="same">
<family>Zapf Dingbats</family>
<accept>
<family>D050000L</family>
<family>Dingbats</family>
</accept>
</alias>
<alias binding="same">
<family>ITC Zapf Dingbats</family>
<accept>
<family>D050000L</family>
<family>Dingbats</family>
</accept>
</alias>
<match target="pattern">
<test name="family" compare="eq" ignore-blanks="true">
<string>Symbol</string>
</test>
<edit name="family" mode="append" binding="same">
<string>Standard Symbols PS</string>
</edit>
<edit name="family" mode="append" binding="same">
<string>Standard Symbols L</string>
</edit>
</match>
</fontconfig>

View File

@ -0,0 +1,231 @@
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<!--
Mark common families with their generics so we'll get
something reasonable
-->
<!--
Serif faces
-->
<alias>
<family>Nazli</family>
<default><family>serif</family></default>
</alias>
<alias>
<family>Lotoos</family>
<default><family>serif</family></default>
</alias>
<alias>
<family>Mitra</family>
<default><family>serif</family></default>
</alias>
<alias>
<family>Ferdosi</family>
<default><family>serif</family></default>
</alias>
<alias>
<family>Badr</family>
<default><family>serif</family></default>
</alias>
<alias>
<family>Zar</family>
<default><family>serif</family></default>
</alias>
<alias>
<family>Titr</family>
<default><family>serif</family></default>
</alias>
<alias>
<family>Jadid</family>
<default><family>serif</family></default>
</alias>
<alias>
<family>Kochi Mincho</family>
<default><family>serif</family></default>
</alias>
<alias>
<family>AR PL SungtiL GB</family>
<default><family>serif</family></default>
</alias>
<alias>
<family>AR PL Mingti2L Big5</family>
<default><family>serif</family></default>
</alias>
<alias>
<family> 明朝</family>
<default><family>serif</family></default>
</alias>
<alias>
<family>NanumMyeongjo</family>
<default><family>serif</family></default>
</alias>
<alias>
<family>UnBatang</family>
<default><family>serif</family></default>
</alias>
<alias>
<family>Baekmuk Batang</family>
<default><family>serif</family></default>
</alias>
<alias>
<family>MgOpen Canonica</family>
<default><family>serif</family></default>
</alias>
<alias>
<family>Sazanami Mincho</family>
<default><family>serif</family></default>
</alias>
<alias>
<family>AR PL ZenKai Uni</family>
<default><family>serif</family></default>
</alias>
<alias>
<family>ZYSong18030</family>
<default><family>serif</family></default>
</alias>
<alias>
<family>FreeSerif</family>
<default><family>serif</family></default>
</alias>
<alias>
<family>SimSun</family>
<default><family>serif</family></default>
</alias>
<!--
Sans-serif faces
-->
<alias>
<family>Arshia</family>
<default><family>sans-serif</family></default>
</alias>
<alias>
<family>Elham</family>
<default><family>sans-serif</family></default>
</alias>
<alias>
<family>Farnaz</family>
<default><family>sans-serif</family></default>
</alias>
<alias>
<family>Nasim</family>
<default><family>sans-serif</family></default>
</alias>
<alias>
<family>Sina</family>
<default><family>sans-serif</family></default>
</alias>
<alias>
<family>Roya</family>
<default><family>sans-serif</family></default>
</alias>
<alias>
<family>Koodak</family>
<default><family>sans-serif</family></default>
</alias>
<alias>
<family>Terafik</family>
<default><family>sans-serif</family></default>
</alias>
<alias>
<family>Kochi Gothic</family>
<default><family>sans-serif</family></default>
</alias>
<alias>
<family>AR PL KaitiM GB</family>
<default><family>sans-serif</family></default>
</alias>
<alias>
<family>AR PL KaitiM Big5</family>
<default><family>sans-serif</family></default>
</alias>
<alias>
<family> ゴシック</family>
<default><family>sans-serif</family></default>
</alias>
<alias>
<family>NanumGothic</family>
<default><family>sans-serif</family></default>
</alias>
<alias>
<family>UnDotum</family>
<default><family>sans-serif</family></default>
</alias>
<alias>
<family>Baekmuk Dotum</family>
<default><family>sans-serif</family></default>
</alias>
<alias>
<family>MgOpen Modata</family>
<default><family>sans-serif</family></default>
</alias>
<alias>
<family>Sazanami Gothic</family>
<default><family>sans-serif</family></default>
</alias>
<alias>
<family>AR PL ShanHeiSun Uni</family>
<default><family>sans-serif</family></default>
</alias>
<alias>
<family>ZYSong18030</family>
<default><family>sans-serif</family></default>
</alias>
<alias>
<family>FreeSans</family>
<default><family>sans-serif</family></default>
</alias>
<!--
Monospace faces
-->
<alias>
<family>NSimSun</family>
<default><family>monospace</family></default>
</alias>
<alias>
<family>ZYSong18030</family>
<default><family>monospace</family></default>
</alias>
<alias>
<family>NanumGothicCoding</family>
<default><family>monospace</family></default>
</alias>
<alias>
<family>FreeMono</family>
<default><family>monospace</family></default>
</alias>
<!--
Fantasy faces
-->
<alias>
<family>Homa</family>
<default><family>fantasy</family></default>
</alias>
<alias>
<family>Kamran</family>
<default><family>fantasy</family></default>
</alias>
<alias>
<family>Fantezi</family>
<default><family>fantasy</family></default>
</alias>
<alias>
<family>Tabassom</family>
<default><family>fantasy</family></default>
</alias>
<!--
Cursive faces
-->
<alias>
<family>IranNastaliq</family>
<default><family>cursive</family></default>
</alias>
<alias>
<family>Nafees Nastaleeq</family>
<default><family>cursive</family></default>
</alias>
</fontconfig>

View File

@ -0,0 +1,273 @@
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<!--
Mark common families with their generics so we'll get
something reasonable
-->
<!--
Serif faces
-->
<alias>
<family>Bitstream Vera Serif</family>
<default><family>serif</family></default>
</alias>
<alias>
<family>Cambria</family>
<default><family>serif</family></default>
</alias>
<alias>
<family>Constantia</family>
<default><family>serif</family></default>
</alias>
<alias>
<family>DejaVu Serif</family>
<default><family>serif</family></default>
</alias>
<alias>
<family>Elephant</family>
<default><family>serif</family></default>
</alias>
<alias>
<family>Garamond</family>
<default><family>serif</family></default>
</alias>
<alias>
<family>Georgia</family>
<default><family>serif</family></default>
</alias>
<alias>
<family>Liberation Serif</family>
<default><family>serif</family></default>
</alias>
<alias>
<family>Luxi Serif</family>
<default><family>serif</family></default>
</alias>
<alias>
<family>MS Serif</family>
<default><family>serif</family></default>
</alias>
<alias>
<family>Nimbus Roman No9 L</family>
<default><family>serif</family></default>
</alias>
<alias>
<family>Nimbus Roman</family>
<default><family>serif</family></default>
</alias>
<alias>
<family>Palatino Linotype</family>
<default><family>serif</family></default>
</alias>
<alias>
<family>Thorndale AMT</family>
<default><family>serif</family></default>
</alias>
<alias>
<family>Thorndale</family>
<default><family>serif</family></default>
</alias>
<alias>
<family>Times New Roman</family>
<default><family>serif</family></default>
</alias>
<alias>
<family>Times</family>
<default><family>serif</family></default>
</alias>
<!--
Sans-serif faces
-->
<alias>
<family>Albany AMT</family>
<default><family>sans-serif</family></default>
</alias>
<alias>
<family>Albany</family>
<default><family>sans-serif</family></default>
</alias>
<alias>
<family>Arial Unicode MS</family>
<default><family>sans-serif</family></default>
</alias>
<alias>
<family>Arial</family>
<default><family>sans-serif</family></default>
</alias>
<alias>
<family>Bitstream Vera Sans</family>
<default><family>sans-serif</family></default>
</alias>
<alias>
<family>Britannic</family>
<default><family>sans-serif</family></default>
</alias>
<alias>
<family>Calibri</family>
<default><family>sans-serif</family></default>
</alias>
<alias>
<family>Candara</family>
<default><family>sans-serif</family></default>
</alias>
<alias>
<family>Century Gothic</family>
<default><family>sans-serif</family></default>
</alias>
<alias>
<family>Corbel</family>
<default><family>sans-serif</family></default>
</alias>
<alias>
<family>DejaVu Sans</family>
<default><family>sans-serif</family></default>
</alias>
<alias>
<family>Helvetica</family>
<default><family>sans-serif</family></default>
</alias>
<alias>
<family>Haettenschweiler</family>
<default><family>sans-serif</family></default>
</alias>
<alias>
<family>Liberation Sans</family>
<default><family>sans-serif</family></default>
</alias>
<alias>
<family>MS Sans Serif</family>
<default><family>sans-serif</family></default>
</alias>
<alias>
<family>Nimbus Sans L</family>
<default><family>sans-serif</family></default>
</alias>
<alias>
<family>Nimbus Sans</family>
<default><family>sans-serif</family></default>
</alias>
<alias>
<family>Luxi Sans</family>
<default><family>sans-serif</family></default>
</alias>
<alias>
<family>Tahoma</family>
<default><family>sans-serif</family></default>
</alias>
<alias>
<family>Trebuchet MS</family>
<default><family>sans-serif</family></default>
</alias>
<alias>
<family>Twentieth Century</family>
<default><family>sans-serif</family></default>
</alias>
<alias>
<family>Verdana</family>
<default><family>sans-serif</family></default>
</alias>
<!--
Monospace faces
-->
<alias>
<family>Andale Mono</family>
<default><family>monospace</family></default>
</alias>
<alias>
<family>Bitstream Vera Sans Mono</family>
<default><family>monospace</family></default>
</alias>
<alias>
<family>Consolas</family>
<default><family>monospace</family></default>
</alias>
<alias>
<family>Courier New</family>
<default><family>monospace</family></default>
</alias>
<alias>
<family>Courier</family>
<default><family>monospace</family></default>
</alias>
<alias>
<family>Cumberland AMT</family>
<default><family>monospace</family></default>
</alias>
<alias>
<family>Cumberland</family>
<default><family>monospace</family></default>
</alias>
<alias>
<family>DejaVu Sans Mono</family>
<default><family>monospace</family></default>
</alias>
<alias>
<family>Fixedsys</family>
<default><family>monospace</family></default>
</alias>
<alias>
<family>Inconsolata</family>
<default><family>monospace</family></default>
</alias>
<alias>
<family>Liberation Mono</family>
<default><family>monospace</family></default>
</alias>
<alias>
<family>Luxi Mono</family>
<default><family>monospace</family></default>
</alias>
<alias>
<family>Nimbus Mono L</family>
<default><family>monospace</family></default>
</alias>
<alias>
<family>Nimbus Mono</family>
<default><family>monospace</family></default>
</alias>
<alias>
<family>Nimbus Mono PS</family>
<default><family>monospace</family></default>
</alias>
<alias>
<family>Terminal</family>
<default><family>monospace</family></default>
</alias>
<!--
Fantasy faces
-->
<alias>
<family>Bauhaus Std</family>
<default><family>fantasy</family></default>
</alias>
<alias>
<family>Cooper Std</family>
<default><family>fantasy</family></default>
</alias>
<alias>
<family>Copperplate Gothic Std</family>
<default><family>fantasy</family></default>
</alias>
<alias>
<family>Impact</family>
<default><family>fantasy</family></default>
</alias>
<!--
Cursive faces
-->
<alias>
<family>Comic Sans MS</family>
<default><family>cursive</family></default>
</alias>
<alias>
<family>ITC Zapf Chancery Std</family>
<default><family>cursive</family></default>
</alias>
<alias>
<family>Zapfino</family>
<default><family>cursive</family></default>
</alias>
</fontconfig>

View File

@ -0,0 +1,21 @@
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<!--
If the font still has no generic name, add sans-serif
-->
<match target="pattern">
<test qual="all" name="family" compare="not_eq">
<string>sans-serif</string>
</test>
<test qual="all" name="family" compare="not_eq">
<string>serif</string>
</test>
<test qual="all" name="family" compare="not_eq">
<string>monospace</string>
</test>
<edit name="family" mode="append_last">
<string>sans-serif</string>
</edit>
</match>
</fontconfig>

View File

@ -0,0 +1,15 @@
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<!--
Load per-user customization files where stored on XDG Base Directory
specification compliant places. it should be usually:
$HOME/.config/fontconfig/conf.d
$HOME/.config/fontconfig/fonts.conf
-->
<include ignore_missing="yes" prefix="xdg">fontconfig/conf.d</include>
<include ignore_missing="yes" prefix="xdg">fontconfig/fonts.conf</include>
<!-- the following elements will be removed in the future -->
<include ignore_missing="yes" deprecated="yes">~/.fonts.conf.d</include>
<include ignore_missing="yes" deprecated="yes">~/.fonts.conf</include>
</fontconfig>

View File

@ -0,0 +1,6 @@
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<!-- Load local system customization file -->
<include ignore_missing="yes">local.conf</include>
</fontconfig>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<match>
<edit name="family" mode="prepend" binding="weak">
<string>Twitter Color Emoji</string>
</edit>
</match>
</fontconfig>

View File

@ -0,0 +1,74 @@
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<alias>
<family>serif</family>
<prefer>
<family>Bitstream Vera Serif</family>
<family>DejaVu Serif</family>
<family>Times New Roman</family>
<family>Thorndale AMT</family>
<family>Luxi Serif</family>
<family>Nimbus Roman No9 L</family>
<family>Nimbus Roman</family>
<family>Times</family>
</prefer>
</alias>
<alias>
<family>sans-serif</family>
<prefer>
<family>Bitstream Vera Sans</family>
<family>DejaVu Sans</family>
<family>Verdana</family>
<family>Arial</family>
<family>Albany AMT</family>
<family>Luxi Sans</family>
<family>Nimbus Sans L</family>
<family>Nimbus Sans</family>
<family>Helvetica</family>
<family>Lucida Sans Unicode</family>
<family>BPG Glaho International</family> <!-- lat,cyr,arab,geor -->
<family>Tahoma</family> <!-- lat,cyr,greek,heb,arab,thai -->
</prefer>
</alias>
<alias>
<family>monospace</family>
<prefer>
<family>Bitstream Vera Sans Mono</family>
<family>DejaVu Sans Mono</family>
<family>Inconsolata</family>
<family>Andale Mono</family>
<family>Courier New</family>
<family>Cumberland AMT</family>
<family>Luxi Mono</family>
<family>Nimbus Mono L</family>
<family>Nimbus Mono</family>
<family>Nimbus Mono PS</family>
<family>Courier</family>
</prefer>
</alias>
<!--
Fantasy faces
-->
<alias>
<family>fantasy</family>
<prefer>
<family>Impact</family>
<family>Copperplate Gothic Std</family>
<family>Cooper Std</family>
<family>Bauhaus Std</family>
</prefer>
</alias>
<!--
Cursive faces
-->
<alias>
<family>cursive</family>
<prefer>
<family>ITC Zapf Chancery Std</family>
<family>Zapfino</family>
<family>Comic Sans MS</family>
</prefer>
</alias>
</fontconfig>

View File

@ -0,0 +1,419 @@
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<!--
fonts-persian.conf
To configure Persian fonts from The FarsiWeb Project.
Copyright (C) 2005 Sharif FarsiWeb, Inc. <license@farsiweb.info>
Permission to use, copy, modify, distribute, and sell this software and its
documentation for any purpose is hereby granted without fee, provided that
the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation, and that the name of Sharif FarsiWeb, Inc. not be used in
advertising or publicity pertaining to distribution of the software without
specific, written prior permission. Sharif FarsiWeb, Inc. makes no
representations about the suitability of this software for any purpose. It
is provided "as is" without express or implied warranty.
SHARIF FARSIWEB, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
ChangeLog:
2005-04-03 Behdad Esfahbod: Initial revision.
2005-10-09 Behdad Esfahbod: Turned off back-slant and Tahoma sections.
2005-11-30 Behdad Esfahbod: Set Titr susbtitution size to 24 points.
2008 Behdad Esfahbod: Cleanup. Add fantasy and cursive.
-->
<fontconfig>
<!-- Deprecated fonts are discouraged -->
<!-- Nesf[2] is officially deprecated and has problematic tables -->
<alias binding="same">
<family>Nesf</family>
<accept><family>Nesf2</family></accept>
</alias>
<alias binding="same">
<family>Nesf2</family>
<accept><family>Persian_sansserif_default</family></accept>
</alias>
<!-- Name changes and spelling variant aliases -->
<alias binding="same">
<family>Nazanin</family>
<accept><family>Nazli</family></accept>
</alias>
<alias binding="same">
<family>Lotus</family>
<accept><family>Lotoos</family></accept>
</alias>
<alias binding="same">
<family>Yaqut</family>
<accept><family>Yaghoot</family></accept>
</alias>
<alias binding="same">
<family>Yaghut</family>
<accept><family>Yaghoot</family></accept>
</alias>
<alias binding="same">
<family>Traffic</family>
<accept><family>Terafik</family></accept>
</alias>
<alias binding="same">
<family>Ferdowsi</family>
<accept><family>Ferdosi</family></accept>
</alias>
<alias binding="same">
<family>Fantezy</family>
<accept><family>Fantezi</family></accept>
</alias>
<!-- Classify fonts. -->
<!-- Persian_title class -->
<alias binding="same">
<family>Jadid</family>
<accept><family>Persian_title</family></accept>
</alias>
<alias binding="same">
<family>Titr</family>
<accept><family>Persian_title</family></accept>
</alias>
<!-- Persian_fantasy class -->
<alias binding="same">
<family>Kamran</family>
<accept>
<family>Persian_fantasy</family>
<family>Homa</family>
</accept>
</alias>
<alias binding="same">
<family>Homa</family>
<accept>
<family>Persian_fantasy</family>
<family>Kamran</family>
</accept>
</alias>
<alias binding="same">
<family>Fantezi</family>
<accept><family>Persian_fantasy</family></accept>
</alias>
<alias binding="same">
<family>Tabassom</family>
<accept><family>Persian_fantasy</family></accept>
</alias>
<!-- Persian_square class -->
<alias binding="same">
<family>Arshia</family>
<accept><family>Persian_square</family></accept>
</alias>
<alias binding="same">
<family>Nasim</family>
<accept><family>Persian_square</family></accept>
</alias>
<alias binding="same">
<family>Elham</family>
<accept>
<family>Persian_square</family>
<family>Farnaz</family>
</accept>
</alias>
<alias binding="same">
<family>Farnaz</family>
<accept>
<family>Persian_square</family>
<family>Elham</family>
</accept>
</alias>
<alias binding="same">
<family>Sina</family>
<accept><family>Persian_square</family></accept>
</alias>
<!-- Font ordering per class -->
<!-- Persian_title class -->
<alias binding="same">
<family>Persian_title</family>
<accept>
<family>Titr</family>
<family>Jadid</family>
<family>Persian_serif</family>
</accept>
</alias>
<!-- Persian_fantasy class -->
<alias binding="same">
<family>Persian_fantasy</family>
<accept>
<family>Homa</family>
<family>Kamran</family>
<family>Fantezi</family>
<family>Tabassom</family>
<family>Persian_square</family>
</accept>
</alias>
<!-- Persian_square class -->
<alias binding="same">
<family>Persian_square</family>
<accept>
<family>Arshia</family>
<family>Elham</family>
<family>Farnaz</family>
<family>Nasim</family>
<family>Sina</family>
<family>Persian_serif</family>
</accept>
</alias>
<!-- Register the fonts that we actually do have -->
<match target="scan">
<test name="family" compare="eq" ignore-blanks="true">
<string>Elham</string>
</test>
<edit name="foundry">
<string>farsiweb</string>
</edit>
</match>
<match target="scan">
<test name="family" compare="eq" ignore-blanks="true">
<string>Homa</string>
</test>
<edit name="foundry">
<string>farsiweb</string>
</edit>
</match>
<match target="scan">
<test name="family" compare="eq" ignore-blanks="true">
<string>Koodak</string>
</test>
<edit name="foundry">
<string>farsiweb</string>
</edit>
</match>
<match target="scan">
<test name="family" compare="eq" ignore-blanks="true">
<string>Nazli</string>
</test>
<edit name="foundry">
<string>farsiweb</string>
</edit>
</match>
<match target="scan">
<test name="family" compare="eq" ignore-blanks="true">
<string>Roya</string>
</test>
<edit name="foundry">
<string>farsiweb</string>
</edit>
</match>
<match target="scan">
<test name="family" compare="eq" ignore-blanks="true">
<string>Terafik</string>
</test>
<edit name="foundry">
<string>farsiweb</string>
</edit>
</match>
<match target="scan">
<test name="family" compare="eq" ignore-blanks="true">
<string>Titr</string>
</test>
<edit name="foundry">
<string>farsiweb</string>
</edit>
</match>
<!-- Our fonts should oblique to the other side (TURNED-OFF) -->
<match target="font">
<test name="foundry">
<!--string>farsiweb</string-->
<string>TURNED-OFF</string>
</test>
<test name="foundry">
<string>farsiweb</string>
</test>
<!-- check to see if the font is roman -->
<test name="slant">
<const>roman</const>
</test>
<!-- check to see if the pattern requested non-roman -->
<test target="pattern" name="slant" compare="not_eq">
<const>roman</const>
</test>
<!-- multiply the matrix to slant the font -->
<edit name="matrix" mode="assign">
<times>
<name>matrix</name>
<matrix><double>1</double><double>-0.2</double>
<double>0</double><double>1</double>
</matrix>
</times>
</edit>
<!-- pretend the font is oblique now -->
<edit name="slant" mode="assign">
<const>oblique</const>
</edit>
</match>
<!--
We can't hint our fonts well, so turn off hinting.
Moreover, the bitmaps we have designed (well, they
have designed), suck, so disable them too.
-->
<match target="font">
<test name="foundry">
<string>farsiweb</string>
</test>
<edit name="autohint">
<bool>false</bool>
</edit>
<edit name="hinting">
<bool>false</bool>
</edit>
<edit name="embeddedbitmap">
<bool>false</bool>
</edit>
</match>
<!-- Alias our fonts to common families -->
<!-- Persian serif fonts -->
<alias>
<family>serif</family>
<accept>
<family>Nazli</family>
<family>Lotoos</family>
<family>Mitra</family>
<family>Ferdosi</family>
<family>Badr</family>
<family>Zar</family>
</accept>
</alias>
<!-- Persian sans-serif fonts -->
<alias>
<family>sans-serif</family>
<accept>
<family>Roya</family>
<family>Koodak</family>
<family>Terafik</family>
</accept>
</alias>
<!-- Persian monospace fonts -->
<alias>
<family>monospace</family>
<accept>
<!-- Not really monospace -->
<family>Terafik</family>
</accept>
</alias>
<!-- Persian fantasy fonts -->
<alias>
<family>fantasy</family>
<accept>
<family>Homa</family>
<family>Kamran</family>
<family>Fantezi</family>
<family>Tabassom</family>
</accept>
</alias>
<!-- Persian (and Urdu) Nastaliq/cursive fonts -->
<alias>
<family>cursive</family>
<accept>
<family>IranNastaliq</family>
<family>Nafees Nastaleeq</family>
</accept>
</alias>
<!-- Use Titr in titles -->
<!-- Both serif... -->
<match>
<test name="family">
<string>serif</string>
</test>
<test name="weight" compare="more_eq">
<int>200</int>
</test>
<test name="size" compare="more_eq">
<double>24</double>
</test>
<edit name="family" mode="prepend">
<string>Titr</string>
</edit>
</match>
<!-- and sans-serif. -->
<match>
<test name="family">
<string>sans-serif</string>
</test>
<test name="weight" compare="more_eq">
<int>200</int>
</test>
<test name="size" compare="more_eq">
<double>24</double>
</test>
<edit name="family" mode="prepend">
<string>Titr</string>
</edit>
</match>
<!-- and more. -->
<match>
<test name="family">
<string>Persian_sansserif_default</string>
</test>
<test name="weight" compare="more_eq">
<int>200</int>
</test>
<test name="size" compare="more_eq">
<double>24</double>
</test>
<edit name="family" mode="prepend" binding="same">
<string>Titr</string>
</edit>
</match>
<!-- Default substituted for deprecated sans-serif fonts -->
<match>
<test name="family">
<string>Persian_sansserif_default</string>
</test>
<edit name="family" mode="assign" binding="same">
<string>Roya</string>
</edit>
</match>
</fontconfig>

View File

@ -0,0 +1,16 @@
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<alias>
<family>serif</family>
<prefer>
<family>Khmer OS"</family>
</prefer>
</alias>
<alias>
<family>sans-serif</family>
<prefer>
<family>Khmer OS"</family>
</prefer>
</alias>
</fontconfig>

View File

@ -0,0 +1,196 @@
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<alias>
<family>serif</family>
<prefer>
<family>Artsounk</family> <!-- armenian -->
<family>BPG UTF8 M</family> <!-- georgian -->
<family>Kinnari</family> <!-- thai -->
<family>Norasi</family> <!-- thai -->
<family>Frank Ruehl</family> <!-- hebrew -->
<family>Dror</family> <!-- hebrew -->
<family>JG LaoTimes</family> <!-- lao -->
<family>Saysettha Unicode</family> <!-- lao -->
<family>Pigiarniq</family> <!-- canadian syllabics -->
<family>B Davat</family> <!-- arabic (fa) -->
<family>B Compset</family> <!-- arabic (fa) -->
<family>Kacst-Qr</family> <!-- arabic (ar) -->
<family>Urdu Nastaliq Unicode</family> <!-- arabic (ur) -->
<family>Raghindi</family> <!-- devanagari -->
<family>Mukti Narrow</family> <!-- bengali -->
<family>malayalam</family> <!-- malayalam -->
<family>Sampige</family> <!-- kannada -->
<family>padmaa</family> <!-- gujarati -->
<family>Hapax Berbère</family> <!-- tifinagh -->
<family>MS Mincho</family> <!-- han (ja) -->
<family>SimSun</family> <!-- han (zh-cn,zh-tw) -->
<family>PMingLiu</family> <!-- han (zh-tw) -->
<family>WenQuanYi Zen Hei</family> <!-- han (zh-cn,zh-tw) -->
<family>WenQuanYi Bitmap Song</family> <!-- han (zh-cn,zh-tw) -->
<family>AR PL ShanHeiSun Uni</family> <!-- han (ja,zh-cn,zh-tw) -->
<family>AR PL New Sung</family> <!-- han (zh-cn,zh-tw) -->
<family>ZYSong18030</family> <!-- han (zh-cn,zh-tw) -->
<family>HanyiSong</family> <!-- han (zh-cn,zh-tw) -->
<family>MgOpen Canonica</family>
<family>Sazanami Mincho</family>
<family>IPAMonaMincho</family>
<family>IPAMincho</family>
<family>Kochi Mincho</family>
<family>AR PL SungtiL GB</family>
<family>AR PL Mingti2L Big5</family>
<family>AR PL Zenkai Uni</family>
<family> 明朝</family>
<family>ZYSong18030</family>
<family>NanumMyeongjo</family> <!-- hangul (ko) -->
<family>UnBatang</family> <!-- hangul (ko) -->
<family>Baekmuk Batang</family> <!-- hangul (ko) -->
<family>KacstQura</family>
<family>Frank Ruehl CLM</family>
<family>Lohit Bengali</family>
<family>Lohit Gujarati</family>
<family>Lohit Hindi</family>
<family>Lohit Marathi</family>
<family>Lohit Maithili</family>
<family>Lohit Kashmiri</family>
<family>Lohit Konkani</family>
<family>Lohit Nepali</family>
<family>Lohit Sindhi</family>
<family>Lohit Punjabi</family>
<family>Lohit Tamil</family>
<family>Meera</family>
<family>Lohit Malayalam</family>
<family>Lohit Kannada</family>
<family>Lohit Telugu</family>
<family>Lohit Oriya</family>
<family>LKLUG</family>
</prefer>
</alias>
<alias>
<family>sans-serif</family>
<prefer>
<family>Nachlieli</family> <!-- hebrew -->
<family>Lucida Sans Unicode</family>
<family>Yudit Unicode</family>
<family>Kerkis</family> <!-- greek -->
<family>ArmNet Helvetica</family> <!-- armenian -->
<family>Artsounk</family> <!-- armenian -->
<family>BPG UTF8 M</family> <!-- georgian -->
<family>Waree</family> <!-- thai -->
<family>Loma</family> <!-- thai -->
<family>Garuda</family> <!-- thai -->
<family>Umpush</family> <!-- thai -->
<family>Saysettha Unicode</family> <!-- lao? -->
<family>JG Lao Old Arial</family> <!-- lao -->
<family>GF Zemen Unicode</family> <!-- ethiopic -->
<family>Pigiarniq</family> <!-- canadian syllabics -->
<family>B Davat</family> <!-- arabic (fa) -->
<family>B Compset</family> <!-- arabic (fa) -->
<family>Kacst-Qr</family> <!-- arabic (ar) -->
<family>Urdu Nastaliq Unicode</family> <!-- arabic (ur) -->
<family>Raghindi</family> <!-- devanagari -->
<family>Mukti Narrow</family> <!-- bengali -->
<family>malayalam</family> <!-- malayalam -->
<family>Sampige</family> <!-- kannada -->
<family>padmaa</family> <!-- gujarati -->
<family>Hapax Berbère</family> <!-- tifinagh -->
<family>MS Gothic</family> <!-- han (ja) -->
<family>UmePlus P Gothic</family> <!-- han (ja) -->
<!-- chinese fonts are actually serifed -->
<family>SimSun</family> <!-- han (zh-cn,zh-tw) -->
<family>PMingLiu</family> <!-- han (zh-tw) -->
<family>WenQuanYi Zen Hei</family> <!-- han (zh-cn,zh-tw) -->
<family>WenQuanYi Bitmap Song</family> <!-- han (zh-cn,zh-tw) -->
<family>AR PL ShanHeiSun Uni</family> <!--han (ja,zh-cn,zh-tw) -->
<family>AR PL New Sung</family> <!-- han (zh-cn,zh-tw) -->
<family>MgOpen Modata</family>
<family>VL Gothic</family>
<family>IPAMonaGothic</family>
<family>IPAGothic</family>
<family>Sazanami Gothic</family>
<family>Kochi Gothic</family>
<family>AR PL KaitiM GB</family>
<family>AR PL KaitiM Big5</family>
<family>AR PL ShanHeiSun Uni</family>
<family>AR PL SungtiL GB</family>
<family>AR PL Mingti2L Big5</family>
<family> ゴシック</family>
<family>ZYSong18030</family> <!-- han (zh-cn,zh-tw) -->
<family>TSCu_Paranar</family> <!-- tamil -->
<family>NanumGothic</family> <!-- hangul (ko) -->
<family>UnDotum</family> <!-- hangul (ko) -->
<family>Baekmuk Dotum</family> <!-- hangul (ko) -->
<family>Baekmuk Gulim</family> <!-- hangul (ko) -->
<family>KacstQura</family>
<family>Lohit Bengali</family>
<family>Lohit Gujarati</family>
<family>Lohit Hindi</family>
<family>Lohit Marathi</family>
<family>Lohit Maithili</family>
<family>Lohit Kashmiri</family>
<family>Lohit Konkani</family>
<family>Lohit Nepali</family>
<family>Lohit Sindhi</family>
<family>Lohit Punjabi</family>
<family>Lohit Tamil</family>
<family>Meera</family>
<family>Lohit Malayalam</family>
<family>Lohit Kannada</family>
<family>Lohit Telugu</family>
<family>Lohit Oriya</family>
<family>LKLUG</family>
</prefer>
</alias>
<alias>
<family>monospace</family>
<prefer>
<family>Miriam Mono</family> <!-- hebrew -->
<family>VL Gothic</family>
<family>IPAMonaGothic</family>
<family>IPAGothic</family>
<family>Sazanami Gothic</family>
<family>Kochi Gothic</family>
<family>AR PL KaitiM GB</family>
<family>MS Gothic</family> <!-- han (ja) -->
<family>UmePlus Gothic</family> <!-- han (ja) -->
<family>NSimSun</family> <!-- han (zh-cn,zh-tw) -->
<family>MingLiu</family> <!-- han (zh-tw) -->
<family>AR PL ShanHeiSun Uni</family> <!-- han (ja,zh-cn,zh-tw) -->
<family>AR PL New Sung Mono</family> <!-- han (zh-cn,zh-tw) -->
<family>HanyiSong</family> <!-- han (zh-cn) -->
<family>AR PL SungtiL GB</family>
<family>AR PL Mingti2L Big5</family>
<family>ZYSong18030</family> <!-- han (zh-cn,zh-tw) -->
<family>NanumGothicCoding</family> <!-- hangul (ko) -->
<family>NanumGothic</family> <!-- hangul (ko) -->
<family>UnDotum</family> <!-- hangul (ko) -->
<family>Baekmuk Dotum</family> <!-- hangul (ko) -->
<family>Baekmuk Gulim</family> <!-- hangul (ko) -->
<family>TlwgTypo</family> <!-- thai -->
<family>TlwgTypist</family> <!-- thai -->
<family>TlwgTypewriter</family> <!-- thai -->
<family>TlwgMono</family> <!-- thai -->
<family>Hasida</family> <!-- hebrew -->
<family>Mitra Mono</family> <!-- bengali -->
<family>GF Zemen Unicode</family> <!-- ethiopic -->
<family>Hapax Berbère</family> <!-- tifinagh -->
<family>Lohit Bengali</family>
<family>Lohit Gujarati</family>
<family>Lohit Hindi</family>
<family>Lohit Marathi</family>
<family>Lohit Maithili</family>
<family>Lohit Kashmiri</family>
<family>Lohit Konkani</family>
<family>Lohit Nepali</family>
<family>Lohit Sindhi</family>
<family>Lohit Punjabi</family>
<family>Lohit Tamil</family>
<family>Meera</family>
<family>Lohit Malayalam</family>
<family>Lohit Kannada</family>
<family>Lohit Telugu</family>
<family>Lohit Oriya</family>
<family>LKLUG</family>
</prefer>
</alias>
</fontconfig>

View File

@ -0,0 +1,28 @@
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<alias>
<family>serif</family>
<prefer>
<family>FreeSerif</family>
<family>Code2000</family>
<family>Code2001</family> <!-- plane1 and beyond -->
</prefer>
</alias>
<alias>
<family>sans-serif</family>
<prefer>
<family>FreeSans</family>
<family>Arial Unicode MS</family>
<family>Arial Unicode</family>
<family>Code2000</family> <!-- almost everything; serif actually -->
<family>Code2001</family> <!-- plane1 and beyond -->
</prefer>
</alias>
<alias>
<family>monospace</family>
<prefer>
<family>FreeMono</family>
</prefer>
</alias>
</fontconfig>

View File

@ -0,0 +1,12 @@
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<!-- Accept bitmap fonts -->
<selectfont>
<acceptfont>
<pattern>
<patelt name="scalable"><bool>false</bool></patelt>
</pattern>
</acceptfont>
</selectfont>
</fontconfig>

View File

@ -0,0 +1,19 @@
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<!-- Fix-ups for Delicious family -->
<!-- Delicious 'heavy' variant says its Medium weight -->
<match target="scan">
<test name="family" compare="eq" ignore-blanks="true">
<string>Delicious</string>
</test>
<test name="style">
<string>Heavy</string>
</test>
<edit name="weight">
<const>heavy</const>
</edit>
</match>
</fontconfig>

View File

@ -0,0 +1,64 @@
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<!--
Artificial oblique for fonts without an italic or oblique version
-->
<match target="font">
<!-- check to see if the font is roman -->
<test name="slant">
<const>roman</const>
</test>
<!-- check to see if the pattern requested non-roman -->
<test target="pattern" name="slant" compare="not_eq">
<const>roman</const>
</test>
<!-- multiply the matrix to slant the font -->
<edit name="matrix" mode="assign">
<times>
<name>matrix</name>
<matrix><double>1</double><double>0.2</double>
<double>0</double><double>1</double>
</matrix>
</times>
</edit>
<!-- pretend the font is oblique now -->
<edit name="slant" mode="assign">
<const>oblique</const>
</edit>
<!-- and disable embedded bitmaps for artificial oblique -->
<edit name="embeddedbitmap" mode="assign">
<bool>false</bool>
</edit>
</match>
<!--
Synthetic emboldening for fonts that do not have bold face available
-->
<match target="font">
<!-- check to see if the font is just regular -->
<test name="weight" compare="less_eq">
<const>medium</const>
</test>
<!-- check to see if the pattern requests bold -->
<test target="pattern" name="weight" compare="more">
<const>medium</const>
</test>
<!--
set the embolden flag
needed for applications using cairo, e.g. gucharmap, gedit, ...
-->
<edit name="embolden" mode="assign">
<bool>true</bool>
</edit>
<!--
set weight to bold
needed for applications using Xft directly, e.g. Firefox, ...
-->
<edit name="weight" mode="assign">
<const>bold</const>
</edit>
</match>
</fontconfig>

View File

@ -0,0 +1,89 @@
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<!-- /etc/fonts/fonts.conf file to configure system font access -->
<fontconfig>
<!--
DO NOT EDIT THIS FILE.
IT WILL BE REPLACED WHEN FONTCONFIG IS UPDATED.
LOCAL CHANGES BELONG IN 'local.conf'.
The intent of this standard configuration file is to be adequate for
most environments. If you have a reasonably normal environment and
have found problems with this configuration, they are probably
things that others will also want fixed. Please submit any
problems to the fontconfig bugzilla system located at fontconfig.org
Note that the normal 'make install' procedure for fontconfig is to
replace any existing fonts.conf file with the new version. Place
any local customizations in local.conf which this file references.
Keith Packard
-->
<!-- Font directory list -->
<dir>WINDOWSFONTDIR</dir>
<dir prefix="xdg">fonts</dir>
<!-- the following element will be removed in the future -->
<dir>~/.fonts</dir>
<!--
Accept deprecated 'mono' alias, replacing it with 'monospace'
-->
<match target="pattern">
<test qual="any" name="family">
<string>mono</string>
</test>
<edit name="family" mode="assign" binding="same">
<string>monospace</string>
</edit>
</match>
<!--
Accept alternate 'sans serif' spelling, replacing it with 'sans-serif'
-->
<match target="pattern">
<test qual="any" name="family">
<string>sans serif</string>
</test>
<edit name="family" mode="assign" binding="same">
<string>sans-serif</string>
</edit>
</match>
<!--
Accept deprecated 'sans' alias, replacing it with 'sans-serif'
-->
<match target="pattern">
<test qual="any" name="family">
<string>sans</string>
</test>
<edit name="family" mode="assign" binding="same">
<string>sans-serif</string>
</edit>
</match>
<!--
Load local system customization file
-->
<!--(CONFD)-->
<!-- Font cache directory list -->
<cachedir>LOCAL_APPDATA_FONTCONFIG_CACHE</cachedir>
<cachedir prefix="xdg">fontconfig</cachedir>
<!-- the following element will be removed in the future -->
<cachedir>~/.fontconfig</cachedir>
<config>
<!--
Rescan configuration every 30 seconds when FcFontSetList is called
-->
<rescan>
<int>30</int>
</rescan>
</config>
</fontconfig>

View File

Before

Width:  |  Height:  |  Size: 7.9 KiB

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

View File

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

View File

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

View File

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

View File

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 8.2 KiB

View File

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

View File

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 7.0 KiB

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

View File

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

View File

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

View File

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

View File

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

Some files were not shown because too many files have changed in this diff Show More