├── data ├── play.png ├── play@2.png ├── no_avatar.png ├── no_banner.png ├── verified-large.png ├── verified-small.png ├── verified-large@2.png ├── verified-small@2.png ├── protected-account-large.png ├── protected-account-small.png ├── protected-account-large@2.png ├── protected-account-small@2.png ├── uk.co.ibboard.cawbird.service.in ├── hicolor │ ├── 16x16 │ │ └── apps │ │ │ └── uk.co.ibboard.cawbird.png │ ├── 24x24 │ │ └── apps │ │ │ └── uk.co.ibboard.cawbird.png │ ├── 32x32 │ │ └── apps │ │ │ └── uk.co.ibboard.cawbird.png │ ├── 48x48 │ │ └── apps │ │ │ └── uk.co.ibboard.cawbird.png │ ├── 64x64 │ │ └── apps │ │ │ └── uk.co.ibboard.cawbird.png │ └── 96x96 │ │ └── apps │ │ └── uk.co.ibboard.cawbird.png ├── symbolic │ └── apps │ │ ├── cawbird-favorite-symbolic.svg │ │ ├── cawbird-profile-symbolic.svg │ │ ├── cawbird-filter-symbolic.svg │ │ ├── cawbird-conversation-symbolic.svg │ │ ├── cawbird-compose-symbolic.svg │ │ ├── cawbird-new-window-symbolic.svg │ │ └── cawbird-reply-symbolic.svg ├── meson_post_install.py ├── render-icons.sh ├── uk.co.ibboard.cawbird.desktop.in ├── meson.build ├── cawbird.1 ├── play.svg └── verified.svg ├── screenshot1.jpg ├── ._vimrc ├── sql ├── accounts │ ├── Create.3.sql │ ├── Create.7.sql │ ├── Create.2.sql │ ├── Create.4.sql │ ├── Create.6.sql │ ├── Create.5.sql │ └── Create.1.sql └── init │ ├── Create.3.sql │ ├── Create.1.sql │ └── Create.2.sql ├── .gitignore ├── examples ├── meson.build └── accountdialog.vala ├── meson_options.txt ├── .tx └── config ├── vapi ├── config.vapi └── libtl.vapi ├── po ├── LINGUAS ├── meson.build ├── POTFILES.skip └── POTFILES.in ├── .github ├── workflows │ └── main.yml └── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── tests ├── meson.build ├── twitteritem.vala ├── avatarcache.vala ├── friends.vala ├── avatardownload.vala └── bundlehistory.vala ├── src ├── widgets │ ├── DoubleTapButton.vala │ ├── LazyMenuButton.vala │ ├── ReplyEntry.vala │ ├── AvatarBannerWidget.vala │ ├── ImpostorWidget.vala │ ├── TextButton.vala │ ├── DMPlaceholderBox.vala │ ├── ChildSizedScroller.vala │ ├── BadgeRadioButton.vala │ ├── FollowButton.vala │ └── PixbufButton.vala ├── main.vala ├── util │ ├── Benchmark.vala │ ├── ListUtils.vala │ ├── UserCompletion.vala │ └── Dirs.vala ├── OAuthProxyCallWithBody.vala ├── list │ ├── AddListEntry.vala │ ├── SnippetRow.vala │ ├── DMThreadEntry.vala │ ├── FilterListEntry.vala │ └── UserFilterEntry.vala ├── IPage.vala ├── CbMessageReceiver.c ├── CbMediaImageWidget.h ├── CbFilter.h ├── OAuthProxyCallWithQueryString.vala ├── CbMessageReceiver.h ├── async │ ├── Collect.vala │ └── CollectById.vala ├── CbSurfaceProgress.h ├── CbTextTransform.h ├── CbMediaVideoWidget.h ├── CbDeltaUpdater.h ├── CbEmojiChooser.h ├── CbTwitterItem.h ├── CbUserCompletionModel.h ├── sql │ ├── DeleteStatement.vala │ ├── BaseStatement.vala │ ├── SelectStatement.vala │ ├── UpdateStatement.vala │ └── InsertStatement.vala ├── CbGtkCompat.h ├── CbBundleHistory.h ├── CbBundle.h ├── NotificationManager.vala ├── CbMedia.h ├── libtl │ └── libtweetlength.h ├── CbUserCounter.h ├── ComposedTweet.vala ├── CbTwitterItem.c ├── CbSnippetManager.h ├── CbFilter.c ├── CbAvatarCache.h ├── CbMediaDownloader.h ├── CbUserStream.h ├── CbDeltaUpdater.c ├── CbUtils.h ├── MediaUpload.vala └── FavoritesTimeline.vala ├── ui ├── list │ ├── snippet-row.ui │ └── user-row.ui └── widget │ └── avatar-banner-widget.ui ├── config.h.meson └── flatpak └── uk.co.ibboard.cawbird.json /data/play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodedOre/cawbird/handyport/data/play.png -------------------------------------------------------------------------------- /data/play@2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodedOre/cawbird/handyport/data/play@2.png -------------------------------------------------------------------------------- /screenshot1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodedOre/cawbird/handyport/screenshot1.jpg -------------------------------------------------------------------------------- /data/no_avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodedOre/cawbird/handyport/data/no_avatar.png -------------------------------------------------------------------------------- /data/no_banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodedOre/cawbird/handyport/data/no_banner.png -------------------------------------------------------------------------------- /data/verified-large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodedOre/cawbird/handyport/data/verified-large.png -------------------------------------------------------------------------------- /data/verified-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodedOre/cawbird/handyport/data/verified-small.png -------------------------------------------------------------------------------- /data/verified-large@2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodedOre/cawbird/handyport/data/verified-large@2.png -------------------------------------------------------------------------------- /data/verified-small@2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodedOre/cawbird/handyport/data/verified-small@2.png -------------------------------------------------------------------------------- /._vimrc: -------------------------------------------------------------------------------- 1 | set wildignore+=*.c,*\~,CMakeFiles,Makefile,*.lo,test-driver,*.trs,*.stamp,Makefile.in,*.la,*.svg 2 | -------------------------------------------------------------------------------- /sql/accounts/Create.3.sql: -------------------------------------------------------------------------------- 1 | PRAGMA user_version = 3; 2 | 3 | ALTER TABLE `info` 4 | ADD last_tweet VARCHAR(255) 5 | -------------------------------------------------------------------------------- /sql/accounts/Create.7.sql: -------------------------------------------------------------------------------- 1 | PRAGMA user_version = 7; 2 | 3 | ALTER TABLE `dms` 4 | ADD message_json TEXT DEFAULT ''; -------------------------------------------------------------------------------- /data/protected-account-large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodedOre/cawbird/handyport/data/protected-account-large.png -------------------------------------------------------------------------------- /data/protected-account-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodedOre/cawbird/handyport/data/protected-account-small.png -------------------------------------------------------------------------------- /data/protected-account-large@2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodedOre/cawbird/handyport/data/protected-account-large@2.png -------------------------------------------------------------------------------- /data/protected-account-small@2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodedOre/cawbird/handyport/data/protected-account-small@2.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Build Directories 2 | build/ 3 | _build/ 4 | libcorebird.vapi 5 | flatpak/_build 6 | flatpak/.flatpak-builder 7 | valgrind* -------------------------------------------------------------------------------- /data/uk.co.ibboard.cawbird.service.in: -------------------------------------------------------------------------------- 1 | [D-BUS Service] 2 | Name=uk.co.ibboard.cawbird 3 | Exec=@bindir@/cawbird --gapplication-service 4 | -------------------------------------------------------------------------------- /data/hicolor/16x16/apps/uk.co.ibboard.cawbird.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodedOre/cawbird/handyport/data/hicolor/16x16/apps/uk.co.ibboard.cawbird.png -------------------------------------------------------------------------------- /data/hicolor/24x24/apps/uk.co.ibboard.cawbird.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodedOre/cawbird/handyport/data/hicolor/24x24/apps/uk.co.ibboard.cawbird.png -------------------------------------------------------------------------------- /data/hicolor/32x32/apps/uk.co.ibboard.cawbird.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodedOre/cawbird/handyport/data/hicolor/32x32/apps/uk.co.ibboard.cawbird.png -------------------------------------------------------------------------------- /data/hicolor/48x48/apps/uk.co.ibboard.cawbird.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodedOre/cawbird/handyport/data/hicolor/48x48/apps/uk.co.ibboard.cawbird.png -------------------------------------------------------------------------------- /data/hicolor/64x64/apps/uk.co.ibboard.cawbird.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodedOre/cawbird/handyport/data/hicolor/64x64/apps/uk.co.ibboard.cawbird.png -------------------------------------------------------------------------------- /data/hicolor/96x96/apps/uk.co.ibboard.cawbird.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodedOre/cawbird/handyport/data/hicolor/96x96/apps/uk.co.ibboard.cawbird.png -------------------------------------------------------------------------------- /sql/accounts/Create.2.sql: -------------------------------------------------------------------------------- 1 | PRAGMA user_version = 2; 2 | 3 | CREATE TABLE IF NOT EXISTS `filters`( 4 | id INTEGER PRIMARY KEY AUTOINCREMENT, 5 | content VARCHAR(100) 6 | ); 7 | -------------------------------------------------------------------------------- /sql/accounts/Create.4.sql: -------------------------------------------------------------------------------- 1 | PRAGMA user_version = 4; 2 | 3 | ALTER TABLE `info` 4 | ADD last_tweet_reply_id NUMERIC(19,0) DEFAULT 0; 5 | 6 | ALTER TABLE `info` 7 | ADD last_tweet_quote_id NUMERIC(19,0) DEFAULT 0; 8 | 9 | -------------------------------------------------------------------------------- /sql/accounts/Create.6.sql: -------------------------------------------------------------------------------- 1 | PRAGMA user_version = 6; 2 | 3 | ALTER TABLE `user_cache` 4 | ADD verified INTEGER(1) NOT NULL DEFAULT 0; 5 | 6 | ALTER TABLE `user_cache` 7 | ADD protected_account TINYINT NOT NULL DEFAULT 0; -------------------------------------------------------------------------------- /sql/init/Create.3.sql: -------------------------------------------------------------------------------- 1 | PRAGMA user_version = 3; 2 | 3 | ALTER TABLE `accounts` 4 | ADD migrated INT DEFAULT 0; 5 | 6 | CREATE TABLE IF NOT EXISTS `info`( 7 | key VARCHAR(40) PRIMARY KEY, 8 | value VARCHAR(255) 9 | ); -------------------------------------------------------------------------------- /sql/init/Create.1.sql: -------------------------------------------------------------------------------- 1 | 2 | PRAGMA user_version = 1; 3 | 4 | CREATE TABLE IF NOT EXISTS `accounts`( 5 | id NUMERIC(19,0) PRIMARY KEY, 6 | screen_name VARCHAR(30), 7 | name VARCHAR(30), 8 | avatar_url VARCHAR(255) 9 | ); 10 | -------------------------------------------------------------------------------- /examples/meson.build: -------------------------------------------------------------------------------- 1 | executable('tweetstates', 2 | 'tweetstates.vala', 3 | cb_resources, 4 | dependencies: cb_dep, 5 | vala_args: [ 6 | meson.source_root() + '/vapi/cawbird-internal.vapi', 7 | '--gresources=' + meson.source_root() + '/cawbird.gresource.xml', 8 | ] 9 | ) 10 | -------------------------------------------------------------------------------- /meson_options.txt: -------------------------------------------------------------------------------- 1 | option('video', type: 'boolean', value: 'true') 2 | option('spellcheck', type: 'boolean', value: 'true') 3 | option('examples', type: 'boolean', value: 'false') 4 | option('appdata', type: 'boolean', value: 'true') 5 | option('x11', type: 'boolean', value: 'true') 6 | -------------------------------------------------------------------------------- /.tx/config: -------------------------------------------------------------------------------- 1 | [main] 2 | host = https://transifex.com 3 | 4 | [corebird.corebirdpot] 5 | file_filter = po/.po 6 | host = https://transifex.com 7 | source_file = po/corebird.pot 8 | source_lang = en 9 | type = PO 10 | lang_map = id_ID: id, ro_RO: ro, pt_PT: pt, ko_KR: ko, hi_IN: hi, ja_JP: ja, tr_TR: tr 11 | 12 | -------------------------------------------------------------------------------- /vapi/config.vapi: -------------------------------------------------------------------------------- 1 | [CCode (cprefix = "", lower_case_cprefix = "", cheader_filename = "config.h")] 2 | namespace Config { 3 | public const string GETTEXT_PACKAGE; 4 | public const string PACKAGE; 5 | public const string PACKAGE_NAME; 6 | 7 | public const string DATADIR; 8 | public const string PKGDATADIR; 9 | } 10 | -------------------------------------------------------------------------------- /data/symbolic/apps/cawbird-favorite-symbolic.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /po/LINGUAS: -------------------------------------------------------------------------------- 1 | ar 2 | ast 3 | ca 4 | ca@valencia 5 | da 6 | de 7 | de_DE 8 | eo 9 | es 10 | es_419 11 | es_MX 12 | es_VE 13 | fa 14 | fi 15 | fr 16 | ga 17 | gl 18 | hi 19 | hu 20 | id 21 | it 22 | ja 23 | ko 24 | lt 25 | nb 26 | nl 27 | pl 28 | pt 29 | pt_BR 30 | ro 31 | ru 32 | sr 33 | sr_BA@latin 34 | tr 35 | uk_UA 36 | zh_CN 37 | zh_TW -------------------------------------------------------------------------------- /examples/accountdialog.vala: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | void main (string[] args) { 5 | Gtk.init (ref args); 6 | 7 | Utils.load_custom_css (); 8 | Settings.init (); 9 | var acc = new Account (1337, "Some Screen Name", "Some Name"); 10 | var dialog = new AccountDialog (acc); 11 | dialog.show_all (); 12 | 13 | 14 | Gtk.main (); 15 | } 16 | -------------------------------------------------------------------------------- /data/meson_post_install.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import subprocess 5 | 6 | schemadir = os.path.join(os.environ['MESON_INSTALL_PREFIX'], 'share', 'glib-2.0', 'schemas') 7 | 8 | if not os.environ.get('DESTDIR'): 9 | print('Compiling gsettings schemas...') 10 | subprocess.call(['glib-compile-schemas', schemadir]) 11 | -------------------------------------------------------------------------------- /sql/accounts/Create.5.sql: -------------------------------------------------------------------------------- 1 | PRAGMA user_version = 5; 2 | 3 | ALTER TABLE `info` 4 | ADD last_tweet_image_1 TEXT NOT NULL DEFAULT ""; 5 | 6 | ALTER TABLE `info` 7 | ADD last_tweet_image_2 TEXT NOT NULL DEFAULT ""; 8 | 9 | ALTER TABLE `info` 10 | ADD last_tweet_image_3 TEXT NOT NULL DEFAULT ""; 11 | 12 | ALTER TABLE `info` 13 | ADD last_tweet_image_4 TEXT NOT NULL DEFAULT ""; -------------------------------------------------------------------------------- /sql/init/Create.2.sql: -------------------------------------------------------------------------------- 1 | 2 | PRAGMA user_version = 2; 3 | 4 | CREATE TABLE IF NOT EXISTS `snippets`( 5 | id INTEGER PRIMARY KEY AUTOINCREMENT, 6 | key VARCHAR(20), 7 | value VARCHAR(200) 8 | ); 9 | 10 | INSERT INTO `snippets` (key, value) VALUES ('dealwithit', '(•_•) ( •_•)>⌐■-■ (⌐■_■)'); 11 | INSERT INTO `snippets` (key, value) VALUES ('tableflip', '(╯°□°)╯︵ ┻━┻'); 12 | 13 | -------------------------------------------------------------------------------- /data/render-icons.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sizes=(16 24 32 48 64 96) 4 | 5 | for size in ${sizes[@]} 6 | do 7 | rsvg-convert ./uk.co.ibboard.cawbird.svg --width="${size}" --height="${size}" \ 8 | --format=png -o "./hicolor/${size}x${size}/apps/uk.co.ibboard.cawbird.png" 9 | done 10 | 11 | cp ./uk.co.ibboard.cawbird.svg ./hicolor/scalable/apps/uk.co.ibboard.cawbird.svg 12 | -------------------------------------------------------------------------------- /po/meson.build: -------------------------------------------------------------------------------- 1 | i18n = import('i18n') 2 | 3 | i18n.gettext('cawbird', args: [ 4 | '--keyword=_', 5 | '--keyword=N_', 6 | '--flag=N_:1:pass-c-format', 7 | '--from-code=UTF-8', 8 | '--add-comments=TRANSLATORS', 9 | '--no-location', 10 | '--msgid-bugs-address=https://github.com/ibboard/cawbird/issues/new', 11 | '--copyright-holder=2013-2018 Timm Bäder, 2018-2020 IBBoard' 12 | ]) 13 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: GitHub Polls Actions Bot 2 | 3 | on: 4 | issue_comment: 5 | types: [created, edited] # issue comment is created or edited 6 | issues: 7 | types: [opened, edited] # issue is opened or edited 8 | 9 | jobs: 10 | polls: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: imjohnbo/gh-polls-bot-action@master 14 | env: 15 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 16 | -------------------------------------------------------------------------------- /data/uk.co.ibboard.cawbird.desktop.in: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=Cawbird 3 | GenericName=Twitter Client 4 | Comment=Use Twitter from within a normal desktop application 5 | # TRANSLATORS: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! 6 | Keywords=twitter; 7 | Exec=cawbird 8 | Type=Application 9 | # TRANSLATORS: Do NOT translate or transliterate this text (this is an icon file name)! 10 | Icon=uk.co.ibboard.cawbird 11 | Categories=Network;GTK; 12 | DBusActivatable=true 13 | StartupWMClass=cawbird 14 | # TRANSLATORS: Do NOT translate or transliterate this text (these are enum types)! 15 | X-Purism-FormFactor=Workstation;Mobile; 16 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for a change or new feature 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /tests/meson.build: -------------------------------------------------------------------------------- 1 | 2 | tests = [ 3 | 'avatarcache', 4 | 'avatardownload', 5 | 'bundlehistory', 6 | 'dmmanager', 7 | 'filters', 8 | 'friends', 9 | 'inlinemediadownloader', 10 | 'texttransform', 11 | 'tweetmodel', 12 | 'tweetparsing', 13 | 'twitteritem', 14 | 'usercompletionmodel', 15 | 'usercounter', 16 | 'utils', 17 | ] 18 | 19 | foreach test_name : tests 20 | testcase = executable( 21 | test_name, 22 | test_name + '.vala', 23 | meson.source_root() + '/vapi/cawbird-internal.vapi', 24 | cb_resources, 25 | dependencies: cb_dep, 26 | vala_args: [ 27 | '--gresources=' + meson.source_root() + '/cawbird.gresource.xml', 28 | ], 29 | ) 30 | test(test_name, testcase) 31 | endforeach 32 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us fix problems and errors 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **System details:** 27 | - OS: [e.g. Ubuntu 18.04] 28 | - Version: [e.g. 1.0.4-61.2] 29 | - Package type: [e.g. Official RPM/Deb, Snap, Flatpak, distro package, or custom build] 30 | 31 | **Additional context** 32 | Add any other context about the problem here. 33 | 34 | Running `G_MESSAGES_DEBUG=cawbird cawbird` can give useful debug output. 35 | -------------------------------------------------------------------------------- /po/POTFILES.skip: -------------------------------------------------------------------------------- 1 | # List of source files that should *not* be translated. 2 | # Please keep this file sorted alphabetically. 3 | src/DefaultTimeline.c 4 | src/DMPage.c 5 | src/DMThreadsPage.c 6 | src/FavoritesTimeline.c 7 | src/FilterPage.c 8 | src/HomeTimeline.c 9 | src/list/DMThreadEntry.c 10 | src/list/FavImageRow.c 11 | src/ListsPage.c 12 | src/ListStatusesPage.c 13 | src/list/TweetListEntry.c 14 | src/MainWindow.c 15 | src/MentionsTimeline.c 16 | src/ProfilePage.c 17 | src/SearchPage.c 18 | src/TweetInfoPage.c 19 | src/UserEventReceiver.c 20 | src/util/Utils.c 21 | src/widgets/AccountCreateWidget.c 22 | src/widgets/AvatarBannerWidget.c 23 | src/widgets/CompletionTextView.c 24 | src/widgets/FavImageView.c 25 | src/widgets/FollowButton.c 26 | src/widgets/MediaButton.c 27 | src/widgets/PixbufButton.c 28 | src/widgets/TweetListBox.c 29 | src/window/AccountDialog.c 30 | src/window/ComposeTweetWindow.c 31 | src/window/ModifyFilterDialog.c 32 | src/window/ModifySnippetDialog.c 33 | src/window/SettingsDialog.c 34 | src/window/UserListDialog.c 35 | -------------------------------------------------------------------------------- /src/widgets/DoubleTapButton.vala: -------------------------------------------------------------------------------- 1 | 2 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 3 | * Copyright (C) 2013 Timm Bäder (Corebird) 4 | * 5 | * Cawbird is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Cawbird is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with cawbird. If not, see . 17 | */ 18 | class DoubleTapButton : Gtk.ToggleButton { 19 | private bool first_step = false; 20 | 21 | 22 | public void reset () { 23 | first_step = false; 24 | } 25 | 26 | public void tap () { 27 | if (!first_step) { 28 | first_step = true; 29 | return; 30 | } 31 | this.active = !this.active; 32 | first_step = false; 33 | } 34 | } 35 | 36 | -------------------------------------------------------------------------------- /src/widgets/LazyMenuButton.vala: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2013 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | public class LazyMenuButton : Gtk.Button { 19 | public GLib.Menu menu_model { get; set; } 20 | 21 | public override void clicked () { 22 | var popover = new Gtk.Popover.from_model (this, this.menu_model); 23 | popover.position = Gtk.PositionType.BOTTOM; 24 | #if GTK322 25 | popover.popup (); 26 | #else 27 | popover.show (); 28 | #endif 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /ui/list/snippet-row.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 28 | 29 | -------------------------------------------------------------------------------- /sql/accounts/Create.1.sql: -------------------------------------------------------------------------------- 1 | PRAGMA user_version = 1; 2 | 3 | -- SQL schema for an account database 4 | CREATE TABLE IF NOT EXISTS `common`( 5 | token VARCHAR(100), 6 | token_secret VARCHAR(100) 7 | ); 8 | 9 | 10 | CREATE TABLE IF NOT EXISTS `info`( 11 | id NUMERIC(19,0) PRIMARY KEY, 12 | screen_name VARCHAR(30), 13 | name VARCHAR(30) 14 | ); 15 | 16 | 17 | CREATE TABLE IF NOT EXISTS `dm_threads`( 18 | user_id NUMERIC(19,0) PRIMARY KEY, 19 | name VARCHAR(40), 20 | screen_name VARCHAR(30), 21 | last_message VARCHAR(250), 22 | last_message_id NUMERIC(19,0), 23 | avatar_url VARCHAR (250) 24 | ); 25 | 26 | CREATE TABLE IF NOT EXISTS `dms` ( 27 | from_id NUMERIC(19,0), 28 | to_id NUMERIC(19,0), 29 | from_screen_name VARCHAR(30), 30 | to_screen_name VARCHAR(40), 31 | from_name VARCHAR(30), 32 | to_name VARCHAR(30), 33 | timestamp INTEGER(11), 34 | avatar_url VARCHAR(250), 35 | id NUMERIC (19,0) PRIMARY KEY, 36 | text TEXT 37 | ); 38 | 39 | CREATE TABLE IF NOT EXISTS `user_cache`( 40 | id NUMERIC(19,0) PRIMARY KEY, 41 | screen_name VARCHAR(30), 42 | user_name VARCHAR (40), 43 | score INTEGER (11) 44 | ); 45 | 46 | INSERT INTO `user_cache` (id, screen_name, name, score) VALUES ('1154759406329966593', 'cawbirdclient', 'Cawbird', 10); 47 | -------------------------------------------------------------------------------- /src/widgets/ReplyEntry.vala: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2013 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | class ReplyEntry : Gtk.Entry { 19 | [Signal (action = true)] 20 | public signal void cancelled (); 21 | 22 | 23 | 24 | 25 | public ReplyEntry () {} 26 | 27 | static construct { 28 | unowned Gtk.BindingSet binding_set = Gtk.BindingSet.by_class ((GLib.ObjectClass)typeof (ReplyEntry).class_ref ()); 29 | 30 | Gtk.BindingEntry.add_signal (binding_set, Gdk.Key.Escape, 0, "cancelled", 0, null); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/widgets/AvatarBannerWidget.vala: -------------------------------------------------------------------------------- 1 | /* AvatarBannerWidget.vala 2 | * 3 | * This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 4 | * Copyright 2020 Frederick Schenk 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | * SPDX-License-Identifier: GPL-3.0-or-later 20 | */ 21 | 22 | [GtkTemplate (ui = "/uk/co/ibboard/cawbird/ui/widget/avatar-banner-widget.ui")] 23 | class AvatarBannerWidget : Gtk.Bin { 24 | // UI-Elements of AvatarBannerWidget 25 | [GtkChild] 26 | private PixbufButton avatar_widget; 27 | [GtkChild] 28 | private PixbufButton banner_widget; 29 | 30 | public AvatarBannerWidget () { 31 | } 32 | 33 | public void set_account (Account account) { 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /vapi/libtl.vapi: -------------------------------------------------------------------------------- 1 | namespace Tl { 2 | [CCode (cprefix = "TL_ENT_", cheader_filename = "libtl/libtweetlength.h")] 3 | enum EntityType { 4 | TEXT = 1, 5 | HASHTAG, 6 | LINK, 7 | MENTION, 8 | WHITESPACE 9 | } 10 | 11 | [CCode (cprefix = "TlEntity_", lower_case_cprefix = "tl_entity_", cheader_filename = "libtl/libtweetlength.h")] 12 | struct Entity { 13 | EntityType type; 14 | string *start; 15 | size_t start_character_index; 16 | size_t length_in_characters; 17 | size_t length_in_bytes; 18 | size_t length_in_weighted_characters; 19 | } 20 | 21 | 22 | [CCode (cprefix = "tl_", lower_case_cprefix = "tl_", cheader_filename = "libtl/libtweetlength.h")] 23 | size_t count_characters (string input); 24 | 25 | [CCode (cprefix = "tl_", lower_case_cprefix = "tl_", cheader_filename = "libtl/libtweetlength.h")] 26 | size_t count_weighted_characters (string input, bool use_short_link = true); 27 | 28 | [CCode (cprefix = "tl_", lower_case_cprefix = "tl_", cheader_filename = "libtl/libtweetlength.h", 29 | array_length_pos = 1)] 30 | Entity[]? extract_entities (string input, out size_t text_length); 31 | 32 | [CCode (cprefix = "tl_", lower_case_cprefix = "tl_", cheader_filename = "libtl/libtweetlength.h", 33 | array_length_pos = 1)] 34 | Entity[]? extract_entities_and_text (string input, out size_t text_length); 35 | } 36 | -------------------------------------------------------------------------------- /src/main.vala: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2013 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | int main (string[] args) { 19 | #if X11 20 | X.init_threads(); 21 | #endif 22 | #if VIDEO 23 | Gst.init (ref args); 24 | #endif 25 | 26 | //no initialisation of static fields :( 27 | Settings.init (); 28 | var cawbird = new Cawbird (); 29 | int ret = cawbird.run (args); 30 | 31 | #if DEBUG 32 | var list = Gtk.Window.list_toplevels (); 33 | debug ("Toplevels Left: %u", list.length ()); 34 | foreach (var w in list) { 35 | debug ("Toplevel: %s", __class_name (w)); 36 | w.destroy (); 37 | } 38 | #endif 39 | 40 | return ret; 41 | } 42 | -------------------------------------------------------------------------------- /src/util/Benchmark.vala: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2016 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | namespace Benchmark { 19 | public class Bench { 20 | public string name; 21 | public GLib.DateTime first; 22 | public void stop () { 23 | #if DEBUG 24 | var ts = new GLib.DateTime.now_local ().difference (first); 25 | int64 ms = (ts / 1000); 26 | 27 | debug (@"$(this.name) took $ms ms ($ts us)"); 28 | #endif 29 | } 30 | } 31 | 32 | 33 | public Bench start (string name) { 34 | var b = new Bench (); 35 | 36 | #if DEBUG 37 | b.name = name; 38 | b.first = new GLib.DateTime.now_local (); 39 | #endif 40 | return b; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/OAuthProxyCallWithBody.vala: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2013 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | public class OAuthProxyCallWithBody : Rest.OAuthProxyCall { 19 | private string message_content = ""; 20 | 21 | public OAuthProxyCallWithBody(Rest.Proxy proxy, string content) { 22 | Object(proxy: proxy); 23 | message_content = content; 24 | } 25 | 26 | public override bool serialize_params (out string content_type, out string content, out size_t content_len) throws Error { 27 | content_type = "application/json"; 28 | content = this.message_content; 29 | content_len = this.message_content.length; 30 | return true; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/list/AddListEntry.vala: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2013 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | class AddListEntry : Gtk.ListBoxRow { 19 | public AddListEntry (string label) { 20 | var box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 5); 21 | var img = new Gtk.Image.from_icon_name ("list-add-symbolic", Gtk.IconSize.DIALOG); 22 | img.pixel_size = 32; 23 | img.margin_start = 10; 24 | img.hexpand = true; 25 | img.halign = Gtk.Align.END; 26 | box.add (img); 27 | var l = new Gtk.Label (label); 28 | l.hexpand = true; 29 | l.halign = Gtk.Align.START; 30 | box.add (l); 31 | box.margin_bottom = 4; 32 | box.margin_top = 4; 33 | add (box); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/IPage.vala: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2013 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | public interface IPage : Gtk.Widget { 19 | public abstract int id { get; set; } 20 | public abstract void on_join(int page_id, Cb.Bundle? args); 21 | public abstract void on_leave (); 22 | public abstract void create_radio_button(Gtk.RadioButton? group); 23 | public abstract Gtk.RadioButton? get_radio_button(); 24 | public abstract string get_title (); 25 | public abstract unowned MainWindow window { set; } 26 | 27 | 28 | public virtual bool handles_double_open () { 29 | return false; 30 | } 31 | 32 | public virtual void double_open () {} 33 | 34 | public virtual void rerun_filters () {} 35 | } 36 | -------------------------------------------------------------------------------- /data/meson.build: -------------------------------------------------------------------------------- 1 | i18n = import('i18n') 2 | 3 | install_data( 4 | 'uk.co.ibboard.cawbird.gschema.xml', 5 | install_dir: join_paths(get_option('datadir'), 'glib-2.0', 'schemas') 6 | ) 7 | meson.add_install_script('meson_post_install.py') 8 | 9 | i18n.merge_file( 10 | input: 'uk.co.ibboard.cawbird.desktop.in', 11 | output: 'uk.co.ibboard.cawbird.desktop', 12 | po_dir: '../po/', 13 | type: 'desktop', 14 | install: true, 15 | install_dir: join_paths(get_option('datadir'), 'applications') 16 | ) 17 | 18 | if get_option('appdata') 19 | i18n.merge_file( 20 | input: 'uk.co.ibboard.cawbird.appdata.xml.in', 21 | output: 'uk.co.ibboard.cawbird.appdata.xml', 22 | po_dir: '../po/', 23 | type: 'xml', 24 | install: true, 25 | install_dir: join_paths(get_option('datadir'), 'metainfo') 26 | ) 27 | endif 28 | 29 | install_man('cawbird.1') 30 | 31 | conf = configuration_data() 32 | conf.set('bindir', join_paths(get_option('prefix'), 'bin')) 33 | 34 | configure_file( 35 | input: 'uk.co.ibboard.cawbird.service.in', 36 | output: 'uk.co.ibboard.cawbird.service', 37 | configuration: conf, 38 | install_dir: join_paths(get_option('datadir'), 'dbus-1/services') 39 | ) 40 | 41 | gnome.compile_schemas( 42 | build_by_default: true, 43 | depend_files: ['uk.co.ibboard.cawbird.gschema.xml'] 44 | ) 45 | 46 | # Install all application icons in one go 47 | install_subdir( 48 | 'hicolor', 49 | install_dir: join_paths(get_option('datadir'), 'icons') 50 | ) 51 | -------------------------------------------------------------------------------- /tests/twitteritem.vala: -------------------------------------------------------------------------------- 1 | 2 | class TestItem : GLib.Object, Cb.TwitterItem { 3 | int64 timestamp; 4 | int64 sort_factor; 5 | GLib.TimeSpan last_timediff; 6 | 7 | public TestItem (int64 a, int64 b) { 8 | timestamp = a; 9 | sort_factor = b; 10 | } 11 | 12 | public int64 get_sort_factor () { 13 | return sort_factor; 14 | } 15 | 16 | public int64 get_timestamp () { 17 | return timestamp; 18 | } 19 | 20 | public int update_time_delta (GLib.DateTime? now = null) { 21 | return 0; 22 | } 23 | 24 | public void set_last_set_timediff (GLib.TimeSpan span) { 25 | this.last_timediff = span; 26 | } 27 | 28 | public GLib.TimeSpan get_last_set_timediff () { 29 | return this.last_timediff; 30 | } 31 | } 32 | 33 | 34 | void simple () { 35 | var a = new TestItem (1, 2); 36 | var b = new TestItem (10, 20); 37 | 38 | assert (a.get_timestamp () == 1); 39 | assert (a.get_sort_factor () == 2); 40 | 41 | assert (b.get_timestamp () == 10); 42 | assert (b.get_sort_factor () == 20); 43 | 44 | a.set_last_set_timediff (100); 45 | b.set_last_set_timediff (1000); 46 | 47 | message ("a: %s", a.get_last_set_timediff ().to_string ()); 48 | message ("b: %s", b.get_last_set_timediff ().to_string ()); 49 | 50 | assert (a.get_last_set_timediff () == 100); 51 | assert (b.get_last_set_timediff () == 1000); 52 | } 53 | 54 | int main (string[] args) { 55 | GLib.Test.init (ref args); 56 | GLib.Test.add_func ("/tweetitem/simple", simple); 57 | 58 | return GLib.Test.run (); 59 | } 60 | -------------------------------------------------------------------------------- /data/cawbird.1: -------------------------------------------------------------------------------- 1 | .TH "cawbird" "1" "08. Feb. 2014" "man page by Malcolm J Lewis" "" 2 | .SH NAME 3 | .B 4 | cawbird 5 | - Native Gtk+ Twitter client for the Linux desktop. 6 | 7 | .SH SYNOPSIS 8 | .B 9 | cawbird [--tweet=@screen_name] 10 | 11 | .SH DESCRIPTION 12 | - Cawbird is a native GTK+ twitter client that provides vital features such as Direct Messages (DMs), tweet notifications, conversation views. 13 | 14 | - Additional features include the ability to change to the GTK+ dark theme, searching and media uploads. 15 | 16 | .SH KEYBOARD SHORTCUTS [command] 17 | .B 18 | [Ctrl + t] - 19 | Compose tweet 20 | 21 | .B 22 | [Back] - 23 | Go one page back (this can be triggered via the back button on the keyboard, the back thumb button on the mouse or [Alt + Left]) 24 | 25 | .B 26 | [Forward] - 27 | Go one page forward(this can be triggered via the forward button on the keyboard, the forward thumb button on the mouse or [Alt + Right]) 28 | 29 | .B 30 | [Alt + num] - 31 | Go to page [num] (between 1 and 5 at the moment) 32 | 33 | .B 34 | [Ctrl + Shift + s] - 35 | Show/Hide sidebar 36 | 37 | .B 38 | When a tweet is focused (via keynav) 39 | 40 | .B 41 | [r] - 42 | Reply 43 | 44 | .B 45 | [tt] - 46 | Retweet 47 | 48 | .B 49 | [f] - 50 | Favorite 51 | 52 | .B 53 | [dd] - 54 | Delete 55 | 56 | .B 57 | [Return] - 58 | Show tweet details 59 | 60 | .SH AUTHOR 61 | Updated by IBBoard. 62 | Originally written as Corebird by Timm Bäder. 63 | 64 | .SH HOMEPAGE 65 | https://ibboard.co.uk/cawbird/ 66 | 67 | .SH REPORTING BUGS 68 | https://github.com/ibboard/cawbird/issues 69 | -------------------------------------------------------------------------------- /src/CbMessageReceiver.c: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2017 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | #include "CbMessageReceiver.h" 19 | 20 | G_DEFINE_INTERFACE (CbMessageReceiver, cb_message_receiver, G_TYPE_OBJECT); 21 | 22 | static void 23 | cb_message_receiver_default_init (CbMessageReceiverInterface *self) 24 | { 25 | self->stream_message_received = NULL; 26 | } 27 | 28 | void 29 | cb_message_receiver_stream_message_received (CbMessageReceiver *self, 30 | CbStreamMessageType type, 31 | JsonNode *node) 32 | { 33 | CbMessageReceiverInterface *iface; 34 | 35 | g_return_if_fail (CB_IS_MESSAGE_RECEIVER (self)); 36 | 37 | iface = CB_MESSAGE_RECEIVER_GET_IFACE (self); 38 | 39 | return iface->stream_message_received (self, type, node); 40 | } 41 | -------------------------------------------------------------------------------- /tests/avatarcache.vala: -------------------------------------------------------------------------------- 1 | void simple () { 2 | var surface = new Cairo.ImageSurface (Cairo.Format.A8, 2, 2); 3 | var cache = new Cb.AvatarCache (); 4 | 5 | assert (cache.get_n_entries () == 0); 6 | cache.add (1337, surface, "some_url"); 7 | assert (cache.get_n_entries () == 1); 8 | 9 | cache.increase_refcount_for_surface (surface); 10 | assert (cache.get_n_entries () == 1); 11 | 12 | cache.decrease_refcount_for_surface (surface); 13 | assert (cache.get_n_entries () == 0); 14 | } 15 | 16 | void deferred_surface () { 17 | var surface = new Cairo.ImageSurface (Cairo.Format.A8, 2, 2); 18 | var cache = new Cb.AvatarCache (); 19 | 20 | cache.add (1337, null, "some_url"); 21 | assert (cache.get_n_entries () == 1); 22 | 23 | bool found; 24 | var cached_surface = cache.get_surface_for_id (1337, out found); 25 | assert (cached_surface == null); 26 | assert (found); 27 | 28 | cache.set_avatar (1337, surface, "some_url"); 29 | assert (cache.get_n_entries () == 1); 30 | cache.increase_refcount_for_surface (surface); 31 | 32 | cached_surface = cache.get_surface_for_id (1337, out found); 33 | assert (cached_surface == surface); 34 | assert (found); 35 | 36 | cache.decrease_refcount_for_surface (surface); 37 | assert (cache.get_n_entries () == 0); 38 | 39 | cached_surface = cache.get_surface_for_id (1337, out found); 40 | assert (cached_surface == null); 41 | assert (!found); 42 | } 43 | 44 | int main (string[] args) { 45 | GLib.Test.init (ref args); 46 | 47 | GLib.Test.add_func ("/avatarcache/simple", simple); 48 | GLib.Test.add_func ("/avatarcache/deferred_surface", deferred_surface); 49 | 50 | return GLib.Test.run (); 51 | } 52 | -------------------------------------------------------------------------------- /src/CbMediaImageWidget.h: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2017 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | #ifndef _CB_MEDIA_IMAGE_WIDGET_H_ 19 | #define _CB_MEDIA_IMAGE_WIDGET_H_ 20 | 21 | #include 22 | #include "CbMedia.h" 23 | #include "CbMediaDownloader.h" 24 | 25 | #define CB_TYPE_MEDIA_IMAGE_WIDGET cb_media_image_widget_get_type () 26 | G_DECLARE_FINAL_TYPE (CbMediaImageWidget, cb_media_image_widget, CB, MEDIA_IMAGE_WIDGET, GtkScrolledWindow); 27 | 28 | struct _CbMediaImageWidget 29 | { 30 | GtkScrolledWindow parent_instance; 31 | 32 | GtkWidget *image; 33 | GtkGesture *drag_gesture; 34 | 35 | cairo_surface_t *image_surface; 36 | 37 | double drag_start_hvalue; 38 | double drag_start_vvalue; 39 | 40 | CbMedia *media; 41 | gulong hires_progress_id; 42 | }; 43 | typedef struct _CbMediaImageWidget CbMediaImageWidget; 44 | 45 | GtkWidget * cb_media_image_widget_new (CbMedia *media, GdkRectangle *max_dimensions); 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /src/util/ListUtils.vala: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2020 IBBoard 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | namespace ListUtils { 19 | async void delete_list (Account account, 20 | int64 to_rename) throws GLib.Error { 21 | var call = account.proxy.new_call (); 22 | call.set_method ("POST"); 23 | call.set_function ("1.1/lists/subscribers/create.json"); 24 | call.add_param ("list_id", to_rename.to_string ()); 25 | GLib.Error? err = null; 26 | 27 | call.invoke_async.begin (null, (obj, res) => { 28 | try { 29 | call.invoke_async.end (res); 30 | } catch (GLib.Error e) { 31 | var tmp_err = TweetUtils.failed_request_to_error (call, e); 32 | 33 | if (tmp_err.domain != TweetUtils.get_error_domain() || tmp_err.code != 34) { 34 | err = tmp_err; 35 | } 36 | } 37 | delete_list.callback(); 38 | }); 39 | yield; 40 | if (err != null) { 41 | throw err; 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /src/CbFilter.h: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2017 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | #ifndef FILTER_H 19 | #define FILTER_H 20 | 21 | #include 22 | 23 | G_BEGIN_DECLS 24 | 25 | typedef struct _CbFilter CbFilter; 26 | struct _CbFilter 27 | { 28 | GObject parent_instance; 29 | 30 | int id; 31 | char *contents; 32 | GRegex *regex; 33 | }; 34 | 35 | #define CB_TYPE_FILTER cb_filter_get_type () 36 | G_DECLARE_FINAL_TYPE (CbFilter, cb_filter, CB, FILTER, GObject); 37 | 38 | 39 | GType cb_filter_get_type (void) G_GNUC_CONST; 40 | CbFilter *cb_filter_new (const char *expr); 41 | void cb_filter_reset (CbFilter *filter, const char *expr); 42 | gboolean cb_filter_matches (CbFilter *filter, const char *text); 43 | const char *cb_filter_get_contents (CbFilter *filter); 44 | int cb_filter_get_id (CbFilter *filter); 45 | void cb_filter_set_id (CbFilter *filter, int id); 46 | 47 | G_END_DECLS 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /src/OAuthProxyCallWithQueryString.vala: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2013 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | public class OAuthProxyCallWithQueryString : Rest.OAuthProxyCall { 19 | public OAuthProxyCallWithQueryString(Rest.Proxy proxy) { 20 | Object(proxy: proxy); 21 | } 22 | 23 | public override bool serialize_params (out string content_type, out string content, out size_t content_len) throws Error { 24 | var call_params = this.get_params().as_string_hash_table(); 25 | string[] parts = new string[call_params.length]; 26 | int pos = 0; 27 | call_params.foreach((key, value) => { 28 | parts[pos] = "%s=%s".printf(key, value); 29 | pos++; 30 | }); 31 | string query_string = string.joinv("&", parts); 32 | this.set_function("%s?%s".printf(this.get_function(), query_string)); 33 | content_type = "text/plain"; 34 | content = ""; 35 | content_len = 0; 36 | return true; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/CbMessageReceiver.h: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2017 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | #ifndef __CB_MESSAGE_RECEIVER_H__ 19 | #define __CB_MESSAGE_RECEIVER_H__ 20 | 21 | #include 22 | #include 23 | #include "CbTypes.h" 24 | 25 | #define CB_TYPE_MESSAGE_RECEIVER (cb_message_receiver_get_type()) 26 | 27 | G_DECLARE_INTERFACE (CbMessageReceiver, cb_message_receiver, CB, MESSAGE_RECEIVER, GObject) 28 | 29 | struct _CbMessageReceiverInterface 30 | { 31 | GTypeInterface base_iface; 32 | 33 | void (*stream_message_received) (CbMessageReceiver *self, 34 | CbStreamMessageType type, 35 | JsonNode *node); 36 | }; 37 | 38 | void cb_message_receiver_stream_message_received (CbMessageReceiver *self, 39 | CbStreamMessageType type, 40 | JsonNode *node); 41 | 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /src/async/Collect.vala: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2013 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | public class Collect : GLib.Object { 19 | private int cur = 0; 20 | private int max; 21 | private GLib.Error? error = null; 22 | public bool done { 23 | get { 24 | return this.cur == this.max; 25 | } 26 | } 27 | 28 | 29 | public signal void finished (GLib.Error? error); 30 | 31 | public Collect (int max) 32 | requires (max >= 0) 33 | { 34 | this.max = max; 35 | } 36 | 37 | public void emit (GLib.Error? error = null) 38 | requires (cur < max) 39 | { 40 | /* If our global error is set, something previously went wrong and we ignore 41 | this call to emit(); */ 42 | if (this.error != null) 43 | return; 44 | 45 | /* If error is set, we call finished() with that error and ignore all 46 | following calls to emit() */ 47 | if (error != null) { 48 | finished (error); 49 | this.error = error; 50 | return; 51 | } 52 | 53 | cur++; 54 | if (cur == max) { 55 | finished (null); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/CbSurfaceProgress.h: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2017 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | #ifndef _CB_SURFACE_PROGRESS_H_ 18 | #define _CB_SURFACE_PROGRESS_H_ 19 | 20 | #include 21 | 22 | #define CB_TYPE_SURFACE_PROGRESS cb_surface_progress_get_type () 23 | G_DECLARE_FINAL_TYPE (CbSurfaceProgress, cb_surface_progress, CB, SURFACE_PROGRESS, GtkWidget); 24 | 25 | struct _CbSurfaceProgress 26 | { 27 | GtkWidget parent_instance; 28 | 29 | cairo_surface_t *surface; 30 | double progress; 31 | }; 32 | typedef struct _CbSurfaceProgress CbSurfaceProgress; 33 | 34 | GtkWidget * cb_surface_progress_new (void); 35 | double cb_surface_progress_get_progress (CbSurfaceProgress *self); 36 | void cb_surface_progress_set_progress (CbSurfaceProgress *self, 37 | double progress); 38 | cairo_surface_t * cb_surface_progress_get_surface (CbSurfaceProgress *self); 39 | void cb_surface_progress_set_surface (CbSurfaceProgress *self, 40 | cairo_surface_t *surface); 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /src/CbTextTransform.h: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2017 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | #ifndef __TEXT_TRANSFORM_H 19 | #define __TEXT_TRANSFORM_H 20 | 21 | #include 22 | #include "CbTypes.h" 23 | 24 | typedef enum { 25 | CB_TEXT_TRANSFORM_REMOVE_MEDIA_LINKS = 1 << 0, 26 | CB_TEXT_TRANSFORM_REMOVE_TRAILING_HASHTAGS = 1 << 1, 27 | CB_TEXT_TRANSFORM_EXPAND_LINKS = 1 << 2 28 | } CbTransformFlags; 29 | 30 | 31 | 32 | char *cb_text_transform_tweet (const CbMiniTweet *tweet, 33 | guint flags, 34 | guint64 quote_id); 35 | 36 | 37 | char *cb_text_transform_text (const char *text, 38 | CbTextEntity *entities, 39 | gsize n_entities, 40 | guint flags, 41 | gsize n_medias, 42 | gint64 quote_id, 43 | guint display_range_start); 44 | 45 | char *cb_text_transform_fix_encoding (const char *text); 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /src/widgets/ImpostorWidget.vala: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2013 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | class ImpostorWidget : Gtk.Image { 19 | private new Cairo.Surface? surface = null; 20 | 21 | 22 | public ImpostorWidget () { 23 | this.halign = Gtk.Align.FILL; 24 | this.valign = Gtk.Align.FILL; 25 | } 26 | 27 | 28 | 29 | public override bool draw (Cairo.Context ct) { 30 | if (this.surface == null) 31 | return false; 32 | 33 | ct.set_source_surface (this.surface, 0, 0); 34 | ct.rectangle (0, 0, this.get_allocated_width (), this.get_allocated_height ()); 35 | ct.fill (); 36 | return false; 37 | } 38 | 39 | 40 | public void clone (Gtk.Widget widget) { 41 | int widget_width = widget.get_allocated_width (); 42 | int widget_height = widget.get_allocated_height (); 43 | 44 | this.surface = widget.get_window ().create_similar_surface (Cairo.Content.COLOR_ALPHA, 45 | widget_width, 46 | widget_height); 47 | var ct = new Cairo.Context (surface); 48 | widget.draw (ct); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /tests/friends.vala: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | void set () { 6 | Account account = new Account (1337, "Name", "Screen Name"); 7 | Json.Array friends = new Json.Array (); 8 | for (int i = 10; i <= 17; i ++) { 9 | friends.add_int_element (i); 10 | } 11 | 12 | account.set_friends (friends); 13 | 14 | for (int i = 10; i <= 17; i ++) { 15 | assert (account.follows_id (i)); 16 | } 17 | 18 | } 19 | 20 | 21 | void add () { 22 | Account account = new Account (1337, "Name", "Screen Name"); 23 | Json.Array friends = new Json.Array (); 24 | for (int i = 10; i <= 17; i ++) { 25 | friends.add_int_element (i); 26 | } 27 | 28 | account.set_friends (friends); 29 | 30 | account.follow_id (1337); 31 | 32 | assert (account.follows_id (1337)); 33 | 34 | for (int i = 10; i <= 17; i ++) { 35 | assert (account.follows_id (i)); 36 | } 37 | } 38 | 39 | void _remove () { 40 | Account account = new Account (1337, "Name", "Screen Name"); 41 | Json.Array friends = new Json.Array (); 42 | for (int i = 10; i <= 17; i ++) { 43 | friends.add_int_element (i); 44 | } 45 | 46 | account.set_friends (friends); 47 | 48 | account.unfollow_id (10); 49 | account.unfollow_id (11); 50 | account.unfollow_id (12); 51 | 52 | for (int i = 13; i <= 17; i ++) { 53 | assert (account.follows_id (i)); 54 | } 55 | 56 | assert (!account.follows_id (10)); 57 | assert (!account.follows_id (11)); 58 | assert (!account.follows_id (12)); 59 | 60 | 61 | account.unfollow_id (17); 62 | assert (!account.follows_id (17)); 63 | 64 | account.unfollow_id (17); 65 | assert (!account.follows_id (17)); 66 | 67 | 68 | } 69 | 70 | 71 | int main (string[] args) { 72 | GLib.Test.init (ref args); 73 | Dirs.create_dirs (); 74 | GLib.Test.add_func ("/friends/set", set); 75 | GLib.Test.add_func ("/friends/add", add); 76 | GLib.Test.add_func ("/friends/remove", _remove); 77 | 78 | return GLib.Test.run (); 79 | } 80 | -------------------------------------------------------------------------------- /src/CbMediaVideoWidget.h: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2017 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | #ifndef _CB_MEDIA_VIDEO_WIDGET_H_ 18 | #define _CB_MEDIA_VIDEO_WIDGET_H_ 19 | 20 | #ifdef VIDEO 21 | #include 22 | #endif 23 | #include 24 | #include 25 | #include "CbMedia.h" 26 | #include "CbSurfaceProgress.h" 27 | 28 | #define CB_TYPE_MEDIA_VIDEO_WIDGET cb_media_video_widget_get_type () 29 | G_DECLARE_FINAL_TYPE (CbMediaVideoWidget, cb_media_video_widget, CB, MEDIA_VIDEO_WIDGET, GtkStack); 30 | 31 | struct _CbMediaVideoWidget 32 | { 33 | GtkStack parent_instance; 34 | 35 | #ifdef VIDEO 36 | GstElement *src; 37 | GstElement *sink; 38 | #endif 39 | 40 | SoupSession *session; 41 | SoupMessage *message; 42 | 43 | GtkWidget *area; 44 | GtkWidget *surface_progress; 45 | GtkWidget *video_progress; 46 | GtkWidget *error_label; 47 | 48 | GCancellable *cancellable; 49 | guint video_progress_id; 50 | char *media_url; 51 | }; 52 | typedef struct _CbMediaVideoWidget CbMediaVideoWidget; 53 | 54 | CbMediaVideoWidget * cb_media_video_widget_new (CbMedia *media, GdkRectangle *max_dimensions); 55 | void cb_media_video_widget_start (CbMediaVideoWidget *self); 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /po/POTFILES.in: -------------------------------------------------------------------------------- 1 | # List of source files containing translatable strings. 2 | # Please keep this file sorted alphabetically. 3 | data/uk.co.ibboard.cawbird.appdata.xml.in 4 | data/uk.co.ibboard.cawbird.desktop.in 5 | src/CbUtils.c 6 | src/Cawbird.vala 7 | src/DMPage.vala 8 | src/DMThreadsPage.vala 9 | src/DefaultTimeline.vala 10 | src/FavoritesTimeline.vala 11 | src/FilterPage.vala 12 | src/HomeTimeline.vala 13 | src/ListStatusesPage.vala 14 | src/ListsPage.vala 15 | src/MainWindow.vala 16 | src/MentionsTimeline.vala 17 | src/ProfilePage.vala 18 | src/SearchPage.vala 19 | src/TweetInfoPage.vala 20 | src/UserEventReceiver.vala 21 | src/list/DMThreadEntry.vala 22 | src/list/FavImageRow.vala 23 | src/list/TweetListEntry.vala 24 | src/util/TweetUtils.vala 25 | src/util/Utils.vala 26 | src/widgets/AccountCreateWidget.vala 27 | src/widgets/AvatarBannerWidget.vala 28 | src/widgets/CompletionTextView.vala 29 | src/widgets/FavImageView.vala 30 | src/widgets/FollowButton.vala 31 | src/widgets/MediaButton.vala 32 | src/widgets/PixbufButton.vala 33 | src/widgets/TweetListBox.vala 34 | src/window/AccountDialog.vala 35 | src/window/ComposeTweetWindow.vala 36 | src/window/ImageDescriptionWindow.vala 37 | src/window/MediaDialog.vala 38 | src/window/ModifyFilterDialog.vala 39 | src/window/ModifySnippetDialog.vala 40 | src/window/SettingsDialog.vala 41 | src/window/UserListDialog.vala 42 | ui/about-dialog.ui 43 | ui/account-create-widget.ui 44 | ui/account-dialog.ui 45 | ui/cb-emoji-chooser.ui 46 | ui/compose-window.ui 47 | ui/dm-page.ui 48 | ui/filter-list-entry.ui 49 | ui/filter-page.ui 50 | ui/image-description-window.ui 51 | ui/list-list-entry.ui 52 | ui/list-statuses-page.ui 53 | ui/menus.ui 54 | ui/modify-filter-dialog.ui 55 | ui/modify-snippet-dialog.ui 56 | ui/new-list-entry.ui 57 | ui/profile-page.ui 58 | ui/search-page.ui 59 | ui/settings-dialog.ui 60 | ui/shortcuts-window.ui 61 | ui/start-conversation-entry.ui 62 | ui/tweet-info-page.ui 63 | ui/tweet-list-entry.ui 64 | ui/user-filter-entry.ui 65 | ui/user-list-entry.ui 66 | ui/user-lists-widget.ui 67 | -------------------------------------------------------------------------------- /src/widgets/TextButton.vala: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2013 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | public class TextButton : Gtk.Button { 19 | public TextButton () {} 20 | 21 | construct { 22 | this.get_style_context ().add_class ("text-only-button"); 23 | } 24 | 25 | /** 26 | * Adds a GtkLabel to the Button using the given text as the text. 27 | * If the button already contains another child, that will either be replaced if it's 28 | * no instance of GtkLabel, or - if it's a GtkLabel already - be reused. 29 | * 30 | * @param text The markup to use(see pango markup) 31 | */ 32 | public void set_text (string text) { 33 | Gtk.Label label = null; 34 | Gtk.Widget child = get_child (); 35 | if (child != null) { 36 | if (child is Gtk.Label) { 37 | label = (Gtk.Label)child; 38 | label.set_text (text); 39 | } else { 40 | this.remove (child); 41 | label = new Gtk.Label (text); 42 | } 43 | } else { 44 | label = new Gtk.Label (text); 45 | } 46 | 47 | label.set_justify (Gtk.Justification.CENTER); 48 | label.valign = Gtk.Align.BASELINE; 49 | label.ellipsize = Pango.EllipsizeMode.END; 50 | label.xalign = 0; 51 | 52 | label.visible = true; 53 | if(label.parent == null) 54 | this.add (label); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/util/UserCompletion.vala: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2013 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | class UserCompletion : GLib.Object { 19 | public signal void start_completion (); 20 | public signal void populate_completion (string screen_name, string name); 21 | private unowned GLib.Object obj; 22 | private unowned Account account; 23 | private string name_property_name; 24 | private int num_results; 25 | 26 | public UserCompletion (Account account, int num_results) { 27 | this.account = account; 28 | this.num_results = num_results; 29 | } 30 | 31 | public void connect_to (GLib.Object obj, string name_property_name) { 32 | this.obj = obj; 33 | this.name_property_name = name_property_name; 34 | obj.notify[name_property_name].connect (prop_changed); 35 | } 36 | 37 | private void prop_changed () { 38 | string name; 39 | obj.get (name_property_name, out name); 40 | if (name.has_prefix ("@")) 41 | name = name.substring (1); 42 | start_completion (); 43 | Cb.UserInfo[] names; 44 | account.user_counter.query_by_prefix (account.db.get_sqlite_db (), 45 | name, 10, 46 | out names); 47 | 48 | for (int i = 0; i < names.length; i++) 49 | populate_completion (names[i].screen_name, names[i].user_name); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/CbDeltaUpdater.h: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2017 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | #ifndef DELTA_UPDATER_H 19 | #define DELTA_UPDATER_H 20 | 21 | #include 22 | #include 23 | #include "CbTwitterItem.h" 24 | 25 | typedef struct _CbDeltaUpdater CbDeltaUpdater; 26 | typedef struct _CbDeltaUpdaterClass CbDeltaUpdaterClass; 27 | 28 | #define CB_TYPE_DELTA_UPDATER (cb_delta_updater_get_type ()) 29 | #define CB_DELTA_UPDATER(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, CB_TYPE_DELTA_UPDATER, CbDeltaUpdater)) 30 | #define CB_DELTA_UPDATER_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST(cls, CB_TYPE_DELTA_UPDATER, CbDeltaUpdaterClass)) 31 | #define CB_IS_DELTA_UPDATER(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, CB_TYPE_DELTA_UPDATER)) 32 | #define CB_IS_DELTA_UPDATER_CLASS(cls) (G_TYPE_CHECK_CLASS_TYPE(cls, CB_TYPE_DELTA_UPDATER)) 33 | #define CB_DELTA_UPDATER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS(obj, CB_TYPE_DELTA_UPDATER, CbDeltaUpdaterClass)) 34 | 35 | struct _CbDeltaUpdater 36 | { 37 | GObject parent_instance; 38 | 39 | GtkWidget *listbox; 40 | guint minutely_id; 41 | }; 42 | 43 | struct _CbDeltaUpdaterClass 44 | { 45 | GObjectClass parent_class; 46 | }; 47 | 48 | GType cb_delta_updater_get_type (void) G_GNUC_CONST; 49 | 50 | CbDeltaUpdater * cb_delta_updater_new (GtkWidget *listbox); 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /src/CbEmojiChooser.h: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2017 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | #ifndef __CB_EMOJI_CHOOSER_H__ 19 | #define __CB_EMOJI_CHOOSER_H__ 20 | 21 | #include 22 | 23 | typedef struct { 24 | GtkWidget *box; 25 | GtkWidget *heading; 26 | GtkWidget *button; 27 | const char *first; 28 | gunichar label; 29 | gboolean empty; 30 | } EmojiSection; 31 | 32 | struct _CbEmojiChooser 33 | { 34 | GtkBox parent_instance; 35 | 36 | guint populated : 1; 37 | guint populate_idle_id; 38 | 39 | GtkWidget *search_entry; 40 | GtkWidget *stack; 41 | GtkWidget *scrolled_window; 42 | 43 | EmojiSection recent; 44 | EmojiSection people; 45 | EmojiSection body; 46 | EmojiSection nature; 47 | EmojiSection food; 48 | EmojiSection travel; 49 | EmojiSection activities; 50 | EmojiSection objects; 51 | EmojiSection symbols; 52 | EmojiSection flags; 53 | 54 | GVariant *data; 55 | 56 | GSettings *settings; 57 | }; 58 | typedef struct _CbEmojiChooser CbEmojiChooser; 59 | 60 | #define CB_TYPE_EMOJI_CHOOSER cb_emoji_chooser_get_type () 61 | G_DECLARE_FINAL_TYPE (CbEmojiChooser, cb_emoji_chooser, CB, EMOJI_CHOOSER, GtkBox); 62 | 63 | GtkWidget * cb_emoji_chooser_new (void); 64 | gboolean cb_emoji_chooser_try_init (CbEmojiChooser *self); 65 | void cb_emoji_chooser_populate (CbEmojiChooser *self); 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /src/async/CollectById.vala: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2020 IBBoard 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | public class CollectById : GLib.Object { 19 | private GLib.GenericSet ids; 20 | private GLib.Error? error = null; 21 | 22 | public bool done { 23 | get { 24 | return ids.length == 0; 25 | } 26 | } 27 | 28 | public bool errored { 29 | get { 30 | return error != null; 31 | } 32 | } 33 | 34 | public signal void finished (GLib.Error? error); 35 | 36 | public CollectById () 37 | { 38 | ids = new GLib.GenericSet(GLib.str_hash, GLib.str_equal, null); 39 | } 40 | 41 | public void add(string id) { 42 | ids.add(id); 43 | } 44 | 45 | public void emit (string id, GLib.Error? error = null) 46 | { 47 | /* If our global error is set, something previously went wrong and we ignore 48 | this call to emit(); */ 49 | if (this.error != null) { 50 | return; 51 | } 52 | 53 | /* If error is set, we call finished() with that error and ignore all 54 | following calls to emit() */ 55 | if (error != null) { 56 | finished (error); 57 | this.error = error; 58 | return; 59 | } 60 | 61 | ids.remove(id); 62 | 63 | if (done) { 64 | finished (null); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/CbTwitterItem.h: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2017 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | #ifndef _CB_TWITTER_ITEM_H_ 19 | #define _CB_TWITTER_ITEM_H_ 20 | 21 | #include 22 | 23 | #define CB_TYPE_TWITTER_ITEM (cb_twitter_item_get_type()) 24 | 25 | G_DECLARE_INTERFACE (CbTwitterItem, cb_twitter_item, CB, TWITTER_ITEM, GObject) 26 | 27 | struct _CbTwitterItemInterface 28 | { 29 | GTypeInterface base_iface; 30 | 31 | gint64 (*get_sort_factor) (CbTwitterItem *self); 32 | 33 | int (*update_time_delta) (CbTwitterItem *self, 34 | GDateTime *now); 35 | 36 | gint64 (*get_timestamp) (CbTwitterItem *self); 37 | 38 | void (*set_last_set_timediff) (CbTwitterItem *self, 39 | GTimeSpan span); 40 | 41 | GTimeSpan (*get_last_set_timediff) (CbTwitterItem *self); 42 | }; 43 | 44 | gint64 cb_twitter_item_get_sort_factor (CbTwitterItem *self); 45 | int cb_twitter_item_update_time_delta (CbTwitterItem *self, 46 | GDateTime *now); 47 | gint64 cb_twitter_item_get_timestamp (CbTwitterItem *self); 48 | 49 | /* Basically just for CbDeltaUpdater */ 50 | void cb_twitter_item_set_last_set_timediff (CbTwitterItem *self, 51 | GTimeSpan span); 52 | GTimeSpan cb_twitter_item_get_last_set_timediff (CbTwitterItem *self); 53 | 54 | 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /src/CbUserCompletionModel.h: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2017 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | #ifndef _CB_USER_COMPLETION_MODEL_H 19 | #define _CB_USER_COMPLETION_MODEL_H 20 | 21 | #include "CbTypes.h" 22 | #include "CbUserCounter.h" 23 | #include 24 | #include 25 | 26 | struct _CbUserCompletionModel 27 | { 28 | GObject parent_instance; 29 | 30 | GArray *items; 31 | }; 32 | 33 | typedef struct _CbUserCompletionModel CbUserCompletionModel; 34 | 35 | #define CB_TYPE_USER_COMPLETION_MODEL cb_user_completion_model_get_type () 36 | G_DECLARE_FINAL_TYPE (CbUserCompletionModel, cb_user_completion_model, CB, USER_COMPLETION_MODEL, GObject); 37 | 38 | 39 | CbUserCompletionModel * cb_user_completion_model_new (void); 40 | void cb_user_completion_model_insert_items (CbUserCompletionModel *self, 41 | CbUserIdentity *ids, 42 | guint ids_len); 43 | void cb_user_completion_model_insert_infos (CbUserCompletionModel *self, 44 | CbUserInfo *infos, 45 | guint infos_len); 46 | void cb_user_completion_model_clear (CbUserCompletionModel *self); 47 | 48 | 49 | 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /ui/widget/avatar-banner-widget.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 50 | 51 | -------------------------------------------------------------------------------- /src/list/SnippetRow.vala: -------------------------------------------------------------------------------- 1 | /* SnippetRow.vala 2 | * 3 | * This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 4 | * Copyright 2020 Frederick Schenk 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | * SPDX-License-Identifier: GPL-3.0-or-later 20 | */ 21 | 22 | [GtkTemplate (ui = "/uk/co/ibboard/cawbird/ui/list/snippet-row.ui")] 23 | class SnippetRow : Hdy.ActionRow { 24 | // Non-UI-Elements of SnippetRow 25 | private SettingsDialog settings; 26 | public string keyword { 27 | get { return this.get_subtitle(); } 28 | set { this.set_subtitle(value); } 29 | } 30 | public string replacement { 31 | get { return this.get_title(); } 32 | set { this.set_title(value); } 33 | } 34 | 35 | public SnippetRow (string keyword, string replacement, SettingsDialog settings) { 36 | this.set_subtitle(keyword); 37 | this.set_title(replacement); 38 | this.settings = settings; 39 | } 40 | 41 | [GtkCallback] 42 | private void ui_action_row_clicked () { 43 | ModifySnippetWidget mod_widget = new ModifySnippetWidget(keyword, replacement); 44 | mod_widget.modify_done.connect(close_modifier); 45 | settings.present_subpage(mod_widget); 46 | } 47 | 48 | public void close_modifier (string? new_keyword = null, string? new_replacement = null, bool remove = false) { 49 | if (remove) { 50 | this.destroy(); 51 | } 52 | if (new_keyword != null) { 53 | this.set_subtitle(new_keyword); 54 | } 55 | if (new_replacement != null) { 56 | this.set_title(new_replacement); 57 | } 58 | settings.close_subpage(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/sql/DeleteStatement.vala: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2020 IBBoard 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | namespace Sql { 19 | public class DeleteStatement : Sql.BaseStatement { 20 | private bool ran = false; 21 | 22 | public DeleteStatement (string table_name) { 23 | query_builder.append ("DELETE FROM `").append (table_name).append ("` "); 24 | } 25 | 26 | public int run () { 27 | if (!where_set) { 28 | critical ("Bare DELETE statements are not allowed!"); 29 | return -1; 30 | } 31 | Sqlite.Statement stmt; 32 | query_builder.append(";"); 33 | int ok = db.prepare_v2 (query_builder.str, -1, out stmt); 34 | 35 | if (ok != Sqlite.OK) { 36 | critical (db.errmsg ()); 37 | return -1; 38 | } 39 | for (int i = 0; i < bindings.length; i++) { 40 | stmt.bind_text (i + 1, bindings.get (i)); 41 | } 42 | ok = stmt.step (); 43 | if (ok == Sqlite.ERROR) { 44 | critical (db.errmsg ()); 45 | critical (stmt.sql ()); 46 | return -1; 47 | } 48 | ran = true; 49 | return db.changes (); 50 | } 51 | 52 | #if DEBUG 53 | ~DeleteStatement () { 54 | if (!ran) 55 | critical ("UpdateStatement for %s did not run.", query_builder.str); 56 | } 57 | #endif 58 | } 59 | } -------------------------------------------------------------------------------- /src/CbGtkCompat.h: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2017 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | #ifndef CB_GTK_COMPAT_H 18 | #define CB_GTK_COMPAT_H 19 | 20 | #include 21 | 22 | #if GTK_CHECK_VERSION(3, 9, 1) 23 | void gtk_widget_measure (GtkWidget *widget, 24 | GtkOrientation orientation, 25 | int for_size, 26 | int *minimum, 27 | int *natural, 28 | int *minimum_baseline, 29 | int *natural_baseline) 30 | { 31 | if (orientation == GTK_ORIENTATION_HORIZONTAL) 32 | { 33 | g_assert (minimum_baseline == NULL); 34 | g_assert (natural_baseline == NULL); 35 | if (for_size == -1) 36 | gtk_widget_get_preferred_width (widget, minimum, natural); 37 | else 38 | gtk_widget_get_preferred_width_for_height (widget, for_size, minimum, natural); 39 | } 40 | else /* VERTICAL */ 41 | { 42 | gtk_widget_get_preferred_height_and_baseline_for_width (widget, 43 | for_size, 44 | minimum, 45 | natural, 46 | minimum_baseline, 47 | natural_baseline); 48 | } 49 | } 50 | #endif 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /src/CbBundleHistory.h: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2017 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | #ifndef CB_BUNDLE_HISTORY_H 19 | #define CB_BUNDLE_HISTORY_H 20 | 21 | #include 22 | #include "CbBundle.h" 23 | 24 | #define HISTORY_SIZE 10 25 | 26 | struct _CbBundleHistory 27 | { 28 | GObject parent_instance; 29 | 30 | int pos; 31 | int elements[HISTORY_SIZE]; 32 | CbBundle *bundles[HISTORY_SIZE]; 33 | }; 34 | 35 | typedef struct _CbBundleHistory CbBundleHistory; 36 | 37 | #define CB_TYPE_BUNDLE_HISTORY cb_bundle_history_get_type () 38 | G_DECLARE_FINAL_TYPE (CbBundleHistory, cb_bundle_history, CB, BUNDLE_HISTORY, GObject); 39 | 40 | 41 | CbBundleHistory * cb_bundle_history_new (void); 42 | void cb_bundle_history_push (CbBundleHistory *self, 43 | int v, 44 | CbBundle *bundle); 45 | int cb_bundle_history_back (CbBundleHistory *self); 46 | int cb_bundle_history_forward (CbBundleHistory *self); 47 | gboolean cb_bundle_history_at_start (CbBundleHistory *self); 48 | gboolean cb_bundle_history_at_end (CbBundleHistory *self); 49 | void cb_bundle_history_remove_current (CbBundleHistory *self); 50 | int cb_bundle_history_get_current (CbBundleHistory *self); 51 | CbBundle * cb_bundle_history_get_current_bundle (CbBundleHistory *self); 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /src/util/Dirs.vala: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2013 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | namespace Dirs { 19 | static string? config_dir = null; 20 | static string? corebird_config_dir = null; 21 | 22 | 23 | public void create_dirs () { 24 | create_folder (config ("")); 25 | create_folder (config ("accounts/")); 26 | create_folder (config ("image-favorites/")); 27 | } 28 | 29 | public string corebird_config (string path) { 30 | if (corebird_config_dir == null) { 31 | corebird_config_dir = _config (path, "corebird"); 32 | } 33 | return corebird_config_dir + path; 34 | } 35 | 36 | public string config (string path) { 37 | if (config_dir == null) { 38 | config_dir = _config (path, "cawbird"); 39 | } 40 | return config_dir + path; 41 | } 42 | 43 | private string _config (string path, string app_name) { 44 | string dir = GLib.Environment.get_home_dir () + "/." + app_name + "/"; 45 | if (!GLib.FileUtils.test (dir, GLib.FileTest.EXISTS)) { 46 | dir = GLib.Environment.get_user_config_dir () + "/" + app_name + "/"; 47 | } 48 | return dir; 49 | } 50 | 51 | private void create_folder (string path) { 52 | if (FileUtils.test (path, FileTest.EXISTS)) 53 | return; 54 | 55 | try { 56 | bool success = File.new_for_path (path) 57 | .make_directory (); 58 | if (!success) { 59 | critical("Couldn't create user folder %s", path); 60 | } 61 | } catch (GLib.Error e) { 62 | critical ("%s(%s)", e.message, path); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/widgets/DMPlaceholderBox.vala: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2013 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | class DMPlaceholderBox : Gtk.Box { 19 | private AvatarWidget avatar_image; 20 | private Gtk.Label name_label; 21 | private Gtk.Label screen_name_label; 22 | 23 | public int64 user_id; 24 | 25 | public new string name { 26 | set { 27 | name_label.label = value; 28 | name_label.tooltip_text = value; 29 | } 30 | } 31 | 32 | public string screen_name { 33 | set { 34 | screen_name_label.label = "@" + value; 35 | screen_name_label.tooltip_text = "@" + value; 36 | } 37 | } 38 | 39 | public string avatar_url; 40 | 41 | public void load_avatar () { 42 | Twitter.get ().get_avatar.begin (user_id, avatar_url, avatar_image); 43 | } 44 | 45 | construct { 46 | this.set_opacity (0.8); 47 | this.set_margin_top (60); 48 | this.set_orientation (Gtk.Orientation.VERTICAL); 49 | this.set_spacing (4); 50 | this.avatar_image = new AvatarWidget (); 51 | avatar_image.size = 48; 52 | avatar_image.set_halign (Gtk.Align.CENTER); 53 | this.add (avatar_image); 54 | 55 | this.name_label = new Gtk.Label (""); 56 | var attrs = new Pango.AttrList (); 57 | attrs.insert (Pango.attr_weight_new (Pango.Weight.BOLD)); 58 | name_label.set_attributes (attrs); 59 | this.add (name_label); 60 | 61 | this.screen_name_label = new Gtk.Label (""); 62 | screen_name_label.get_style_context ().add_class ("dim-label"); 63 | this.add (screen_name_label); 64 | 65 | this.show_all (); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/CbBundle.h: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2017 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | #ifndef _CB_BUNDLE_H_ 19 | #define _CB_BUNDLE_H_ 20 | 21 | #include 22 | 23 | /* 24 | * TODO: 25 | * Make every CbBundle instance take a fixed amount of data instead 26 | * of keeping two GArrays around. The keys are already required to be 27 | * integers, so just also require them to be subsequent integers starting 28 | * from 0 and just them as indeces into an array. 29 | */ 30 | 31 | struct _CbBundle 32 | { 33 | GObject parent_instance; 34 | 35 | GArray *values; 36 | GArray *keys; 37 | }; 38 | 39 | typedef struct _CbBundle CbBundle; 40 | 41 | #define CB_TYPE_BUNDLE cb_bundle_get_type () 42 | G_DECLARE_FINAL_TYPE (CbBundle, cb_bundle, CB, BUNDLE, GObject); 43 | 44 | CbBundle * cb_bundle_new (void); 45 | gboolean cb_bundle_equals (CbBundle *self, CbBundle *other); 46 | void cb_bundle_put_string (CbBundle *self, int key, const char *val); 47 | const char * cb_bundle_get_string (CbBundle *self, int key); 48 | void cb_bundle_put_int (CbBundle *self, int key, int val); 49 | int cb_bundle_get_int (CbBundle *self, int key); 50 | void cb_bundle_put_int64 (CbBundle *self, int key, gint64 val); 51 | gint64 cb_bundle_get_int64 (CbBundle *self, int key); 52 | void cb_bundle_put_bool (CbBundle *self, int key, gboolean val); 53 | gboolean cb_bundle_get_bool (CbBundle *self, int key); 54 | void cb_bundle_put_object (CbBundle *self, int key, GObject *object); 55 | GObject * cb_bundle_get_object (CbBundle *self, int key); 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /tests/avatardownload.vala: -------------------------------------------------------------------------------- 1 | 2 | 3 | void simple () { 4 | var loop = new GLib.MainLoop (); 5 | Twitter.get ().init (); 6 | 7 | var avatar_widget = new AvatarWidget (); 8 | Twitter.get ().get_avatar.begin (10, "http://i.imgur.com/GzdoOMu.jpg", 9 | avatar_widget, 48, false, () => { 10 | assert (avatar_widget.surface != null); 11 | 12 | loop.quit (); 13 | }); 14 | 15 | loop.run (); 16 | } 17 | 18 | void cached () { 19 | var loop = new GLib.MainLoop (); 20 | Twitter.get ().init (); 21 | 22 | var avatar_widget = new AvatarWidget (); 23 | var avatar_widget2 = new AvatarWidget (); 24 | Twitter.get ().get_avatar.begin (10, "http://i.imgur.com/GzdoOMu.jpg", 25 | avatar_widget, 48, false, () => { 26 | assert (avatar_widget.surface != null); 27 | 28 | Twitter.get ().get_avatar.begin (10, "http://i.imgur.com/GzdoOMu.jpg", 29 | avatar_widget2, 48, false, () => { 30 | 31 | assert (avatar_widget2.surface != null); 32 | assert (avatar_widget2.surface == avatar_widget.surface); 33 | loop.quit (); 34 | }); 35 | }); 36 | 37 | loop.run (); 38 | } 39 | 40 | void double_download () 41 | { 42 | var loop = new GLib.MainLoop (); 43 | Twitter.get ().init (); 44 | 45 | var avatar_widget = new AvatarWidget (); 46 | var avatar_widget2 = new AvatarWidget (); 47 | Twitter.get ().get_avatar.begin (10, "http://i.imgur.com/GzdoOMu.jpg", 48 | avatar_widget, 48, false, () => { 49 | assert (avatar_widget.surface != null); 50 | loop.quit (); 51 | }); 52 | 53 | Twitter.get ().get_avatar.begin (10, "http://i.imgur.com/GzdoOMu.jpg", 54 | avatar_widget2, 48, false, () => { 55 | assert (avatar_widget2.surface != null); 56 | }); 57 | 58 | loop.run (); 59 | } 60 | 61 | int main (string[] args) { 62 | GLib.Test.init (ref args); 63 | Gtk.init (ref args); 64 | Settings.init (); 65 | Utils.init_soup_session (); 66 | 67 | GLib.Test.add_func ("/avatar-download/simple", simple); 68 | GLib.Test.add_func ("/avatar-download/cached", cached); 69 | GLib.Test.add_func ("/avatar-download/double_download", double_download); 70 | 71 | /* We can't test load_avatar_for_user_id here since we can't 72 | properly use Accounts and their proxies... */ 73 | 74 | 75 | return GLib.Test.run (); 76 | } 77 | -------------------------------------------------------------------------------- /src/NotificationManager.vala: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2013 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | public class NotificationManager : GLib.Object { 19 | private unowned Account account; 20 | 21 | public NotificationManager (Account account) { 22 | this.account = account; 23 | } 24 | 25 | public void withdraw (string id) { 26 | GLib.Application.get_default ().withdraw_notification (id); 27 | } 28 | 29 | public string send (string summary, string body, string? id_suffix = null) { 30 | var n = new GLib.Notification (summary); 31 | n.set_body (body); 32 | 33 | string id = "%s-%s".printf (account.id.to_string (), id_suffix ?? ""); 34 | 35 | /* Default action: Bring the account window to the front */ 36 | n.set_default_action_and_target_value ("app.show-window", account.id); 37 | 38 | GLib.Application.get_default ().send_notification (id, n); 39 | 40 | return id; 41 | } 42 | 43 | public string send_dm (int64 sender_id, 44 | string? existing_id, 45 | string summary, 46 | string text) { 47 | if (existing_id != null) { 48 | this.withdraw (existing_id); 49 | } 50 | 51 | string new_id = "new-dm-%s".printf (sender_id.to_string ()); 52 | 53 | var n = new GLib.Notification (summary); 54 | var value = new GLib.Variant.tuple ({new GLib.Variant.int64 (account.id), 55 | new GLib.Variant.int64 (sender_id)}); 56 | n.set_default_action_and_target_value ("app.show-dm-thread", value); 57 | n.set_body (text); 58 | 59 | GLib.Application.get_default ().send_notification (new_id, n); 60 | 61 | return new_id; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/widgets/ChildSizedScroller.vala: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2018 IBBoard 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | class ChildSizedScroller : Gtk.ScrolledWindow { 19 | public override void get_preferred_height_for_width (int width, 20 | out int minimum, 21 | out int natural) { 22 | int min = 0; 23 | int nat = 0; 24 | foreach (Gtk.Widget w in get_children()) { 25 | int m, n; 26 | w.get_preferred_height_for_width (width, out m, out n); 27 | min = int.max (m, min); 28 | nat = int.max (n, nat); 29 | } 30 | minimum = min; 31 | natural = nat; 32 | } 33 | 34 | public override void get_preferred_height (out int minimum, 35 | out int natural) { 36 | int min = 0; 37 | int nat = 0; 38 | foreach (Gtk.Widget w in get_children()) { 39 | int m, n; 40 | w.get_preferred_height (out m, out n); 41 | min = int.max (m, min); 42 | nat = int.max (n, nat); 43 | } 44 | minimum = min; 45 | natural = nat; 46 | } 47 | 48 | // Don't override get_preferred_width because we specifically *don't* want 49 | // the child's idea of width to stretch everything! 50 | 51 | public override unowned Atk.Object get_accessible() { 52 | unowned Atk.Object accessible = base.get_accessible(); 53 | 54 | foreach (Gtk.Widget child in get_children()) { 55 | if (child.visible) { 56 | accessible = child.get_accessible(); 57 | break; 58 | } 59 | } 60 | 61 | return accessible; 62 | } 63 | } -------------------------------------------------------------------------------- /data/symbolic/apps/cawbird-profile-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 40 | 47 | 48 | 50 | 51 | 53 | image/svg+xml 54 | 56 | 57 | 58 | 59 | 60 | 65 | 67 | 72 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /src/list/DMThreadEntry.vala: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2013 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | [GtkTemplate (ui = "/uk/co/ibboard/cawbird/ui/dm-thread-entry.ui")] 19 | class DMThreadEntry : Gtk.ListBoxRow { 20 | [GtkChild] 21 | private Gtk.Label name_label; 22 | [GtkChild] 23 | private Gtk.Label screen_name_label; 24 | [GtkChild] 25 | private Gtk.Label last_message_label; 26 | [GtkChild] 27 | private AvatarWidget avatar_image; 28 | [GtkChild] 29 | private Gtk.Label unread_count_label; 30 | public int64 user_id; 31 | public new string name { 32 | get { 33 | return name_label.label; 34 | } 35 | set { 36 | name_label.label = value; 37 | name_label.tooltip_text = value; 38 | } 39 | } 40 | public string screen_name { 41 | get { 42 | return screen_name_label.label; 43 | } 44 | set { 45 | screen_name_label.label = "@" + value; 46 | screen_name_label.tooltip_text = "@" + value; 47 | } 48 | } 49 | public string last_message { 50 | set { 51 | last_message_label.label = value; 52 | } 53 | } 54 | public Cairo.Surface? avatar { 55 | set { avatar_image.surface = value;} 56 | } 57 | 58 | private int _unread_count = 0; 59 | public int unread_count { 60 | get { 61 | return this._unread_count; 62 | } 63 | set { 64 | this._unread_count = value; 65 | this.update_unread_count (); 66 | } 67 | } 68 | 69 | public DMThreadEntry (int64 user_id) { 70 | this.user_id = user_id; 71 | update_unread_count (); 72 | } 73 | 74 | private void update_unread_count () { 75 | if (unread_count == 0) 76 | unread_count_label.hide (); 77 | else { 78 | unread_count_label.show (); 79 | unread_count_label.label = ngettext ("(%d unread)", 80 | "(%d unread)", 81 | unread_count).printf(unread_count); 82 | } 83 | } 84 | } 85 | 86 | -------------------------------------------------------------------------------- /src/widgets/BadgeRadioButton.vala: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2013 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | public class BadgeRadioButton : Gtk.RadioButton { 19 | private const int BADGE_SIZE = 10; 20 | private bool _show_badge = false; 21 | public bool show_badge { 22 | set { 23 | debug ("New show_badge value: %s", value ? "true" : "false"); 24 | if (value != this._show_badge) { 25 | this._show_badge = value; 26 | this.queue_draw (); 27 | } 28 | } 29 | get { 30 | return this._show_badge; 31 | } 32 | } 33 | 34 | public BadgeRadioButton (Gtk.RadioButton group, string icon_name, string text="") { 35 | GLib.Object (group: group); 36 | var ctx = this.get_style_context (); 37 | ctx.add_class ("image-button"); 38 | ctx.add_class ("flat"); 39 | var i = new Gtk.Image.from_icon_name (icon_name, Gtk.IconSize.BUTTON); 40 | this.add (i); 41 | this.set_mode (false); 42 | this.focus_on_click = false; 43 | this.hexpand = true; 44 | 45 | if (text != "") { 46 | this.tooltip_text = text; 47 | Atk.Object accessible = this.get_accessible (); 48 | accessible.set_name (text); 49 | } 50 | } 51 | 52 | public override bool draw (Cairo.Context ct) { 53 | base.draw (ct); 54 | if (!show_badge || this.get_child () == null) 55 | return Gdk.EVENT_PROPAGATE; 56 | 57 | 58 | Gtk.Allocation child_allocation; 59 | Gtk.Allocation allocation; 60 | this.get_child ().get_allocation (out child_allocation); 61 | this.get_allocation (out allocation); 62 | 63 | var context = this.get_style_context (); 64 | int x = allocation.x - child_allocation.x + child_allocation.width - BADGE_SIZE; 65 | int y = 5; 66 | 67 | context.save (); 68 | context.add_class ("badge"); 69 | context.render_background (ct, x, y, BADGE_SIZE, BADGE_SIZE); 70 | context.render_frame (ct, x, y, BADGE_SIZE, BADGE_SIZE); 71 | context.restore (); 72 | 73 | return Gdk.EVENT_PROPAGATE; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/sql/BaseStatement.vala: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2020 IBBoard 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | namespace Sql { 19 | public abstract class BaseStatement : GLib.Object { 20 | public unowned Sqlite.Database db; 21 | protected StringBuilder query_builder = new StringBuilder (); 22 | protected GLib.GenericArray bindings = new GLib.GenericArray(); 23 | protected bool where_set = false; 24 | 25 | public STATEMENT_TYPE where (string stmt) { 26 | if (!where_set) { 27 | query_builder.append (" WHERE "); 28 | where_set = true; 29 | } 30 | query_builder.append (stmt); 31 | return this; 32 | } 33 | 34 | public STATEMENT_TYPE where_eq (string field, string val) { 35 | where(@"`$field` = ?"); 36 | bindings.add(val); 37 | return this; 38 | } 39 | 40 | public STATEMENT_TYPE where_eqi (string w, int64 v) { 41 | return where_eq (w, v.to_string()); 42 | } 43 | 44 | public STATEMENT_TYPE where_lt (string field, int64 val) { 45 | where(@"`$field` < ?"); 46 | bindings.add(val.to_string()); 47 | return this; 48 | } 49 | 50 | public STATEMENT_TYPE where_prefix (string field, string prefix) { 51 | where(@"`$field` LIKE ?"); 52 | bindings.add(prefix + "%"); 53 | return this; 54 | } 55 | 56 | public STATEMENT_TYPE where_prefix2 (string field, string prefix) { 57 | return where_prefix(field, prefix); 58 | } 59 | 60 | public STATEMENT_TYPE or () { 61 | query_builder.append (" OR "); 62 | return this; 63 | } 64 | 65 | public STATEMENT_TYPE and () { 66 | query_builder.append (" AND "); 67 | return this; 68 | } 69 | 70 | public STATEMENT_TYPE nocase () { 71 | query_builder.append (" COLLATE NOCASE"); 72 | return this; 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /src/CbMedia.h: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2016 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | #ifndef MEDIA_H 19 | #define MEDIA_H 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | G_BEGIN_DECLS 26 | 27 | typedef enum { 28 | CB_MEDIA_TYPE_IMAGE, 29 | CB_MEDIA_TYPE_GIF, 30 | CB_MEDIA_TYPE_ANIMATED_GIF, 31 | CB_MEDIA_TYPE_TWITTER_VIDEO, 32 | CB_MEDIA_TYPE_INSTAGRAM_VIDEO, 33 | 34 | CB_MEDIA_TYPE_UNKNOWN 35 | } CbMediaType; 36 | 37 | 38 | struct _CbMedia 39 | { 40 | GObject parent_instance; 41 | 42 | char *url; 43 | char *thumb_url; 44 | char *target_url; 45 | char *alt_text; 46 | 47 | int width; 48 | int height; 49 | int thumb_width; 50 | int thumb_height; 51 | 52 | gchar *consumer_key; 53 | gchar *consumer_secret; 54 | gchar *token; 55 | gchar *token_secret; 56 | 57 | CbMediaType type; 58 | guint loading: 1; 59 | guint loaded : 1; 60 | guint loading_hires: 1; 61 | guint loaded_hires : 1; 62 | guint invalid : 1; 63 | double percent_loaded; 64 | double percent_loaded_hires; 65 | 66 | cairo_surface_t *surface; 67 | cairo_surface_t *surface_hires; 68 | GdkPixbufAnimation *animation; 69 | }; 70 | 71 | typedef struct _CbMedia CbMedia; 72 | 73 | #define CB_TYPE_MEDIA cb_media_get_type () 74 | G_DECLARE_FINAL_TYPE (CbMedia, cb_media, CB, MEDIA, GObject); 75 | 76 | CbMedia * cb_media_new (void); 77 | gboolean cb_media_is_video (CbMedia *media); 78 | gboolean cb_media_requires_authentication (CbMedia *media); 79 | void cb_media_loading_finished (CbMedia *media); 80 | void cb_media_update_progress (CbMedia *media, 81 | double progress); 82 | void cb_media_loading_hires_finished (CbMedia *media); 83 | void cb_media_update_hires_progress (CbMedia *media, 84 | double progress); 85 | CbMediaType cb_media_type_from_url (const char *url); 86 | cairo_surface_t * cb_media_get_highest_res_surface (CbMedia *media); 87 | 88 | G_END_DECLS 89 | 90 | #endif 91 | -------------------------------------------------------------------------------- /data/play.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 20 | 38 | 40 | 41 | 43 | image/svg+xml 44 | 46 | 47 | 48 | 49 | 50 | 55 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /data/symbolic/apps/cawbird-filter-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 20 | 41 | 48 | 49 | 51 | 52 | 54 | image/svg+xml 55 | 57 | 58 | 59 | 60 | 61 | 66 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /config.h.meson: -------------------------------------------------------------------------------- 1 | /* config.h.in. Generated from configure.ac by autoheader. */ 2 | 3 | /* Define to 1 if translation of program messages to the user's native 4 | language is requested. */ 5 | #mesondefine ENABLE_NLS 6 | 7 | /* Gettext Package */ 8 | #mesondefine GETTEXT_PACKAGE 9 | 10 | /* Define to 1 if you have the Mac OS X function CFLocaleCopyCurrent in the 11 | CoreFoundation framework. */ 12 | #mesondefine HAVE_CFLOCALECOPYCURRENT 13 | 14 | /* Define to 1 if you have the Mac OS X function CFPreferencesCopyAppValue in 15 | the CoreFoundation framework. */ 16 | #mesondefine HAVE_CFPREFERENCESCOPYAPPVALUE 17 | 18 | /* Define if the GNU dcgettext() function is already present or preinstalled. 19 | */ 20 | #mesondefine HAVE_DCGETTEXT 21 | 22 | /* Define to 1 if you have the header file. */ 23 | #mesondefine HAVE_DLFCN_H 24 | 25 | /* Define if the GNU gettext() function is already present or preinstalled. */ 26 | #mesondefine HAVE_GETTEXT 27 | 28 | /* Define if you have the iconv() function and it works. */ 29 | #mesondefine HAVE_ICONV 30 | 31 | /* Define to 1 if you have the header file. */ 32 | #mesondefine HAVE_INTTYPES_H 33 | 34 | /* Define to 1 if you have the header file. */ 35 | #mesondefine HAVE_MEMORY_H 36 | 37 | /* Define to 1 if you have the header file. */ 38 | #mesondefine HAVE_STDINT_H 39 | 40 | /* Define to 1 if you have the header file. */ 41 | #mesondefine HAVE_STDLIB_H 42 | 43 | /* Define to 1 if you have the header file. */ 44 | #mesondefine HAVE_STRINGS_H 45 | 46 | /* Define to 1 if you have the header file. */ 47 | #mesondefine HAVE_STRING_H 48 | 49 | /* Define to 1 if you have the header file. */ 50 | #mesondefine HAVE_SYS_STAT_H 51 | 52 | /* Define to 1 if you have the header file. */ 53 | #mesondefine HAVE_SYS_TYPES_H 54 | 55 | /* Define to 1 if you have the header file. */ 56 | #mesondefine HAVE_UNISTD_H 57 | 58 | /* Define to the sub-directory where libtool stores uninstalled libraries. */ 59 | #mesondefine LT_OBJDIR 60 | 61 | /* Name of package */ 62 | #mesondefine PACKAGE 63 | 64 | /* Define to the address where bug reports for this package should be sent. */ 65 | #mesondefine PACKAGE_BUGREPORT 66 | 67 | /* Define to the full name of this package. */ 68 | #mesondefine PACKAGE_NAME 69 | 70 | /* Define to the full name and version of this package. */ 71 | #mesondefine PACKAGE_STRING 72 | 73 | /* Define to the one symbol short name of this package. */ 74 | #mesondefine PACKAGE_TARNAME 75 | 76 | /* Define to the home page for this package. */ 77 | #mesondefine PACKAGE_URL 78 | 79 | /* Define to the version of this package. */ 80 | #mesondefine PACKAGE_VERSION 81 | 82 | /* Define to 1 if you have the ANSI C header files. */ 83 | #mesondefine STDC_HEADERS 84 | 85 | /* Version number of package */ 86 | #mesondefine VERSION 87 | -------------------------------------------------------------------------------- /src/widgets/FollowButton.vala: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2013 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | class FollowButton : Gtk.Button { 19 | private bool _following = false; 20 | public bool following { 21 | get { return _following; } 22 | set { 23 | var sc = this.get_style_context (); 24 | if (value) { 25 | sc.remove_class ("suggested-action"); 26 | sc.add_class ("destructive-action"); 27 | this.stack.visible_child = unfollow_label; 28 | get_accessible().set_name(_("Unfollow")); 29 | } else { 30 | sc.remove_class ("destructive-action"); 31 | sc.add_class ("suggested-action"); 32 | this.stack.visible_child = follow_label; 33 | get_accessible().set_name(_("Follow")); 34 | } 35 | this._following = value; 36 | } 37 | } 38 | private Gtk.Stack stack; 39 | private Gtk.Label follow_label; 40 | private Gtk.Label unfollow_label; 41 | private bool _compact = false; 42 | public bool compact { 43 | get { return _compact; } 44 | set { 45 | _compact = value; 46 | if (_compact) { 47 | this.follow_label.label = "+"; 48 | this.unfollow_label.label = "-"; 49 | } 50 | else { 51 | this.follow_label.label = _("Follow"); 52 | this.unfollow_label.label = _("Unfollow"); 53 | } 54 | } 55 | } 56 | 57 | construct { 58 | this.stack = new Gtk.Stack (); 59 | 60 | this.follow_label = new Gtk.Label (_("Follow")); 61 | this.unfollow_label = new Gtk.Label (_("Unfollow")); 62 | this.follow_label.get_accessible().set_name(_("Follow")); 63 | this.unfollow_label.get_accessible().set_name(_("Unfollow")); 64 | 65 | stack.add (follow_label); 66 | stack.add (unfollow_label); 67 | stack.set_interpolate_size (true); 68 | stack.transition_type = Gtk.StackTransitionType.CROSSFADE; 69 | stack.hhomogeneous = false; 70 | stack.vhomogeneous = true; 71 | 72 | this.add (stack); 73 | this.get_style_context ().add_class ("text-button"); 74 | this.get_style_context ().add_class ("suggested-action"); /* Default is false */ 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /src/libtl/libtweetlength.h: -------------------------------------------------------------------------------- 1 | /* This file is part of libtweetlength 2 | * Copyright (C) 2017 Timm Bäder 3 | * 4 | * libtweetlength is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * libtweetlength is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with libtweetlength. If not, see . 16 | */ 17 | 18 | #ifndef __LIBTWEETLENGTH_H__ 19 | #define __LIBTWEETLENGTH_H__ 20 | 21 | #include 22 | 23 | struct _TlEntity { 24 | guint type; 25 | const char *start; 26 | gsize length_in_bytes; 27 | 28 | gsize start_character_index; 29 | gsize length_in_characters; 30 | gsize length_in_weighted_characters; 31 | }; 32 | typedef struct _TlEntity TlEntity; 33 | 34 | typedef enum { 35 | TL_ENT_TEXT = 1, 36 | TL_ENT_HASHTAG = 2, 37 | TL_ENT_LINK = 3, 38 | TL_ENT_MENTION = 4, 39 | TL_ENT_WHITESPACE = 5, 40 | } TlEntityType; 41 | 42 | gsize tl_count_characters (const char *input); 43 | gsize tl_count_characters_n (const char *input, 44 | gsize length_in_bytes); 45 | gsize tl_count_weighted_characters (const char *input, 46 | gboolean use_short_link); 47 | gsize tl_count_weighted_characters_n (const char *input, 48 | gsize length_in_bytes); 49 | TlEntity * tl_extract_entities (const char *input, 50 | gsize *out_n_entities, 51 | gsize *out_text_length); 52 | TlEntity * tl_extract_entities_n (const char *input, 53 | gsize length_in_bytes, 54 | gsize *out_n_entities, 55 | gsize *out_text_length); 56 | TlEntity * tl_extract_entities_and_text (const char *input, 57 | gsize *out_n_entities, 58 | gsize *out_text_length); 59 | TlEntity * tl_extract_entities_and_text_n (const char *input, 60 | gsize length_in_bytes, 61 | gsize *out_n_entities, 62 | gsize *out_text_length); 63 | 64 | 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /data/symbolic/apps/cawbird-conversation-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 20 | 41 | 48 | 49 | 51 | 52 | 54 | image/svg+xml 55 | 57 | 58 | 59 | 60 | 61 | 66 | 72 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /src/list/FilterListEntry.vala: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2013 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | [GtkTemplate (ui = "/uk/co/ibboard/cawbird/ui/filter-list-entry.ui")] 18 | class FilterListEntry : Gtk.ListBoxRow { 19 | [GtkChild] 20 | private Gtk.Label content_label; 21 | [GtkChild] 22 | private Gtk.Revealer revealer; 23 | [GtkChild] 24 | private Gtk.Stack stack; 25 | [GtkChild] 26 | private Gtk.Grid normal_box; 27 | [GtkChild] 28 | private Gtk.Box delete_box; 29 | 30 | private unowned Cb.Filter _filter; 31 | public unowned Cb.Filter filter { 32 | set { 33 | content_label.label = value.get_contents (); 34 | _filter = value; 35 | } 36 | get { 37 | return _filter; 38 | } 39 | } 40 | public string content { 41 | set { 42 | content_label.label = value; 43 | } 44 | get { 45 | return content_label.label; 46 | } 47 | } 48 | private unowned Account account; 49 | private unowned MainWindow main_window; 50 | 51 | public FilterListEntry (Cb.Filter f, 52 | Account account, 53 | MainWindow main_window) { 54 | this.filter = f; 55 | this.account = account; 56 | this.main_window = main_window; 57 | } 58 | 59 | construct { 60 | revealer.notify["child-revealed"].connect (() => { 61 | if (!revealer.child_revealed) { 62 | ((Gtk.Container)this.get_parent ()).remove (this); 63 | } 64 | }); 65 | } 66 | 67 | [GtkCallback] 68 | private void menu_button_clicked_cb () { 69 | stack.visible_child = delete_box; 70 | this.activatable = false; 71 | } 72 | 73 | [GtkCallback] 74 | private void cancel_button_clicked_cb () { 75 | stack.visible_child = normal_box; 76 | this.activatable = true; 77 | } 78 | 79 | [GtkCallback] 80 | private void delete_button_clicked_cb () { 81 | for (int i = 0; i < account.filters.length; i ++) { 82 | var f = account.filters.get (i); 83 | if (f.get_id () == this.filter.get_id ()) { 84 | account.filters.remove (f); 85 | account.db.exec ("DELETE FROM `filters` WHERE `id`='%d'".printf (f.get_id ())); 86 | revealer.reveal_child = false; 87 | main_window.rerun_filters (); 88 | return; 89 | } 90 | } 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /src/CbUserCounter.h: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2017 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | #ifndef USER_COUNTER_H 19 | #define USER_COUNTER_H 20 | 21 | #include 22 | #include 23 | 24 | #include "CbTypes.h" 25 | 26 | G_BEGIN_DECLS 27 | 28 | 29 | typedef struct _CbUserInfo CbUserInfo; 30 | struct _CbUserInfo 31 | { 32 | gint64 user_id; 33 | char *screen_name; 34 | char *user_name; 35 | guint score; 36 | guint changed : 1; 37 | guint verified : 1; 38 | guint protected_account : 1; 39 | }; 40 | 41 | 42 | typedef struct _CbUserCounter CbUserCOunter; 43 | struct _CbUserCounter 44 | { 45 | GObject parent_instance; 46 | 47 | guint changed : 1; 48 | GArray *user_infos; 49 | }; 50 | 51 | #define CB_TYPE_USER_COUNTER cb_user_counter_get_type () 52 | G_DECLARE_FINAL_TYPE (CbUserCounter, cb_user_counter, CB, USER_COUNTER, GObject); 53 | 54 | 55 | GType cb_user_counter_get_type (void) G_GNUC_CONST; 56 | 57 | CbUserCounter * cb_user_counter_new (void); 58 | 59 | void cb_user_counter_id_seen (CbUserCounter *counter, 60 | const CbUserIdentity *id); 61 | 62 | void cb_user_counter_user_seen (CbUserCounter *counter, 63 | gint64 user_id, 64 | const char *screen_name, 65 | const char *user_name); 66 | 67 | void cb_user_counter_user_seen_full (CbUserCounter *counter, 68 | gint64 user_id, 69 | const char *screen_name, 70 | const char *user_name, 71 | gboolean verified, 72 | gboolean protected_account); 73 | 74 | int cb_user_counter_save (CbUserCounter *counter, sqlite3 *db); 75 | 76 | void cb_user_counter_query_by_prefix (CbUserCounter *counter, 77 | sqlite3 *db, 78 | const char *prefix, 79 | int max_results, 80 | CbUserInfo **results, 81 | int *n_results); 82 | 83 | /* CbUserInfo */ 84 | void cb_user_info_destroy (CbUserInfo *info); 85 | 86 | G_END_DECLS 87 | 88 | #endif 89 | 90 | -------------------------------------------------------------------------------- /src/ComposedTweet.vala: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2020 IBBoard 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | class ComposedTweet { 19 | private string _text; 20 | private GLib.GenericArray _uploads; 21 | private int64 _reply_to_id = -1; 22 | public int64 reply_to_id { 23 | get { 24 | return _reply_to_id; 25 | } 26 | set { 27 | assert(_quoted_tweet_url == null); 28 | _reply_to_id = value; 29 | } 30 | } 31 | private string? _quoted_tweet_url; 32 | 33 | public signal void ready(); 34 | 35 | public ComposedTweet(string text) { 36 | _text = text; 37 | _uploads = new GLib.GenericArray(4); 38 | } 39 | 40 | public void add_attachment(MediaUpload upload) { 41 | upload.progress_complete.connect((message) => { 42 | if (message == null) { 43 | this.ready(); 44 | } 45 | }); 46 | _uploads.add(upload); 47 | } 48 | 49 | public MediaUpload[] get_attachments() { 50 | return _uploads.data; 51 | } 52 | 53 | public string get_text() { 54 | if (_quoted_tweet_url != null && _uploads.length > 0) { 55 | return "%s %s".printf(_text, get_quoted_url()); 56 | } 57 | else { 58 | return _text; 59 | } 60 | } 61 | 62 | public bool has_quote_attachment() { 63 | return _quoted_tweet_url != null && _uploads.length == 0; 64 | } 65 | 66 | public void set_quoted_tweet(Cb.Tweet tweet) { 67 | assert(reply_to_id == -1); 68 | 69 | // We can't do this with a ternary to get the relevant mini tweet and then have one format string for that because 70 | // it somehow causes segfaults when the minitweet ends up having gibberish values (like an ID of 0 and thousands of media attachments!) 71 | if (tweet.retweeted_tweet != null) { 72 | _quoted_tweet_url = "https://twitter.com/%s/status/%s".printf(tweet.retweeted_tweet.author.screen_name, tweet.retweeted_tweet.id.to_string()); 73 | } 74 | else { 75 | _quoted_tweet_url = "https://twitter.com/%s/status/%s".printf(tweet.source_tweet.author.screen_name, tweet.source_tweet.id.to_string()); 76 | } 77 | } 78 | 79 | public string get_quoted_url() { 80 | return _quoted_tweet_url == null ? "" : _quoted_tweet_url; 81 | } 82 | } -------------------------------------------------------------------------------- /src/CbTwitterItem.c: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2017 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | #include "CbTwitterItem.h" 19 | 20 | 21 | G_DEFINE_INTERFACE (CbTwitterItem, cb_twitter_item, G_TYPE_OBJECT); 22 | 23 | 24 | static int 25 | default_update_time_delta (CbTwitterItem *self, 26 | GDateTime *now) 27 | { 28 | /* NOPE */ 29 | return 0; 30 | } 31 | 32 | static void 33 | cb_twitter_item_default_init (CbTwitterItemInterface *self) 34 | { 35 | self->get_sort_factor = NULL; 36 | self->update_time_delta = default_update_time_delta; 37 | self->get_timestamp = NULL; 38 | self->set_last_set_timediff = NULL; 39 | self->get_last_set_timediff = NULL; 40 | } 41 | 42 | gint64 43 | cb_twitter_item_get_sort_factor (CbTwitterItem *self) 44 | { 45 | CbTwitterItemInterface *iface; 46 | 47 | g_return_val_if_fail (CB_IS_TWITTER_ITEM (self), 0); 48 | 49 | iface = CB_TWITTER_ITEM_GET_IFACE (self); 50 | 51 | return iface->get_sort_factor (self); 52 | } 53 | 54 | int 55 | cb_twitter_item_update_time_delta (CbTwitterItem *self, 56 | GDateTime *now) 57 | { 58 | CbTwitterItemInterface *iface; 59 | 60 | g_return_val_if_fail (CB_IS_TWITTER_ITEM (self), 0); 61 | 62 | iface = CB_TWITTER_ITEM_GET_IFACE (self); 63 | 64 | return iface->update_time_delta (self, now); 65 | } 66 | 67 | gint64 68 | cb_twitter_item_get_timestamp (CbTwitterItem *self) 69 | { 70 | CbTwitterItemInterface *iface; 71 | 72 | g_return_val_if_fail (CB_IS_TWITTER_ITEM (self), 0); 73 | 74 | iface = CB_TWITTER_ITEM_GET_IFACE (self); 75 | 76 | return iface->get_timestamp (self); 77 | } 78 | 79 | void 80 | cb_twitter_item_set_last_set_timediff (CbTwitterItem *self, 81 | GTimeSpan span) 82 | { 83 | CbTwitterItemInterface *iface; 84 | 85 | g_return_if_fail (CB_IS_TWITTER_ITEM (self)); 86 | 87 | iface = CB_TWITTER_ITEM_GET_IFACE (self); 88 | 89 | iface->set_last_set_timediff (self, span); 90 | } 91 | 92 | GTimeSpan 93 | cb_twitter_item_get_last_set_timediff (CbTwitterItem *self) 94 | { 95 | CbTwitterItemInterface *iface; 96 | 97 | g_return_val_if_fail (CB_IS_TWITTER_ITEM (self), 0); 98 | 99 | iface = CB_TWITTER_ITEM_GET_IFACE (self); 100 | 101 | return iface->get_last_set_timediff (self); 102 | } 103 | -------------------------------------------------------------------------------- /src/CbSnippetManager.h: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2017 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | #ifndef CB_SNIPPET_MANAGER_H 18 | #define CB_SNIPPET_MANAGER_H 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | 25 | struct _CbSnippetManager 26 | { 27 | GObject parent_instance; 28 | 29 | GHashTable *snippets; 30 | sqlite3 *db; 31 | guint inited : 1; 32 | }; 33 | typedef struct _CbSnippetManager CbSnippetManager; 34 | 35 | #define CB_TYPE_SNIPPET_MANAGER cb_snippet_manager_get_type() 36 | G_DECLARE_FINAL_TYPE (CbSnippetManager, cb_snippet_manager, CB, SNIPPET_MANAGER, GObject); 37 | 38 | /* 39 | * TODO: This is only a GObject because we can bind that properly in the vapi, 40 | * but a SnippetManager exists only once and for the entire lifetime of the GtkApplication 41 | * object we have... 42 | */ 43 | 44 | CbSnippetManager * cb_snippet_manager_new (sqlite3 *db); 45 | guint cb_snippet_manager_n_snippets (CbSnippetManager *self); 46 | void cb_snippet_manager_remove_snippet (CbSnippetManager *self, 47 | const char *snippet_key); 48 | void cb_snippet_manager_insert_snippet (CbSnippetManager *self, 49 | const char *key, 50 | const char *value); 51 | gboolean cb_snippet_manager_has_snippet_n (CbSnippetManager *self, 52 | const char *key, 53 | gsize key_length_in_bytes); 54 | const char * cb_snippet_manager_get_snippet (CbSnippetManager *self, 55 | const char *key); 56 | void cb_snippet_manager_query_snippets (CbSnippetManager *self, 57 | GHFunc func, 58 | gpointer user_data); 59 | void cb_snippet_manager_set_snippet (CbSnippetManager *self, 60 | const char *old_key, 61 | const char *key, 62 | const char *value); 63 | #endif 64 | -------------------------------------------------------------------------------- /data/symbolic/apps/cawbird-compose-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 20 | 41 | 48 | 49 | 51 | 52 | 54 | image/svg+xml 55 | 57 | 58 | 59 | 60 | 61 | 66 | 69 | 77 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /src/CbFilter.c: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2017 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | #include "CbFilter.h" 19 | 20 | 21 | G_DEFINE_TYPE (CbFilter, cb_filter, G_TYPE_OBJECT); 22 | 23 | static void 24 | cb_filter_finalize (GObject *obj) 25 | { 26 | CbFilter *filter = CB_FILTER (obj); 27 | 28 | g_free (filter->contents); 29 | if (filter->regex != NULL) 30 | g_regex_unref (filter->regex); 31 | 32 | G_OBJECT_CLASS (cb_filter_parent_class)->finalize (obj); 33 | } 34 | 35 | static void 36 | cb_filter_init (CbFilter *filter) 37 | { 38 | filter->contents = NULL; 39 | filter->regex = NULL; 40 | } 41 | 42 | static void 43 | cb_filter_class_init (CbFilterClass *klass) 44 | { 45 | GObjectClass *object_class = G_OBJECT_CLASS (klass); 46 | 47 | object_class->finalize = cb_filter_finalize; 48 | } 49 | 50 | CbFilter * 51 | cb_filter_new (const char *expr) 52 | { 53 | CbFilter *filter = CB_FILTER (g_object_new (CB_TYPE_FILTER, NULL)); 54 | 55 | cb_filter_reset (filter, expr); 56 | 57 | return filter; 58 | } 59 | 60 | void 61 | cb_filter_reset (CbFilter *filter, const char *expr) 62 | { 63 | g_return_if_fail (CB_IS_FILTER (filter)); 64 | g_return_if_fail (expr != NULL); 65 | 66 | filter->regex = g_regex_new (expr, 67 | G_REGEX_CASELESS, 68 | 0, /* No match flags */ 69 | NULL); 70 | filter->contents = g_strdup (expr); 71 | } 72 | 73 | gboolean 74 | cb_filter_matches (CbFilter *filter, const char *text) 75 | { 76 | g_return_val_if_fail (CB_IS_FILTER (filter), FALSE); 77 | g_return_val_if_fail (text != NULL, FALSE); 78 | 79 | if (filter->regex == NULL) 80 | return FALSE; 81 | 82 | return g_regex_match (filter->regex, 83 | text, 84 | 0, 85 | NULL); 86 | } 87 | 88 | 89 | const char * 90 | cb_filter_get_contents (CbFilter *filter) 91 | { 92 | g_return_val_if_fail (CB_IS_FILTER (filter), ""); 93 | 94 | return filter->contents; 95 | } 96 | 97 | int 98 | cb_filter_get_id (CbFilter *filter) 99 | { 100 | g_return_val_if_fail (CB_IS_FILTER (filter), 0); 101 | 102 | return filter->id; 103 | } 104 | 105 | void 106 | cb_filter_set_id (CbFilter *filter, int id) 107 | { 108 | g_return_if_fail (CB_IS_FILTER (filter)); 109 | g_return_if_fail (id >= 0); 110 | 111 | filter->id = id; 112 | } 113 | -------------------------------------------------------------------------------- /src/CbAvatarCache.h: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2016 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | #ifndef AVATAR_CACHE_H 19 | #define AVATAR_CACHE_H 20 | 21 | #include 22 | #include 23 | 24 | G_BEGIN_DECLS 25 | 26 | typedef struct _CbAvatarCache CbAvatarCache; 27 | struct _CbAvatarCache 28 | { 29 | GObject parent_instance; 30 | 31 | GArray *entries; 32 | }; 33 | 34 | #define CB_TYPE_AVATAR_CACHE cb_avatar_cache_get_type () 35 | G_DECLARE_FINAL_TYPE (CbAvatarCache, cb_avatar_cache, CB, AVATAR_CACHE, GObject); 36 | 37 | CbAvatarCache *cb_avatar_cache_new (void); 38 | void cb_avatar_cache_decrease_refcount_for_surface (CbAvatarCache *self, 39 | cairo_surface_t *surface); 40 | void cb_avatar_cache_increase_refcount_for_surface (CbAvatarCache *self, 41 | cairo_surface_t *surface); 42 | void cb_avatar_cache_add (CbAvatarCache *self, 43 | gint64 user_id, 44 | cairo_surface_t *surface, 45 | const char *url); 46 | void cb_avatar_cache_set_avatar (CbAvatarCache *self, 47 | gint64 user_id, 48 | cairo_surface_t *surface, 49 | const char *url); 50 | cairo_surface_t * cb_avatar_cache_get_surface_for_id (CbAvatarCache *self, 51 | gint64 user_id, 52 | gboolean *out_found); 53 | const char * cb_avatar_cache_get_url_for_id (CbAvatarCache *self, 54 | gint64 user_id); 55 | guint cb_avatar_cache_get_n_entries (CbAvatarCache *self); 56 | void cb_avatar_cache_set_url (CbAvatarCache *self, 57 | gint64 user_id, 58 | const char *url); 59 | G_END_DECLS 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /ui/list/user-row.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 75 | 76 | -------------------------------------------------------------------------------- /data/verified.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 21 | 23 | 24 | 26 | image/svg+xml 27 | 29 | 30 | 31 | 32 | 33 | 35 | 72 | 83 | 89 | 90 | -------------------------------------------------------------------------------- /src/CbMediaDownloader.h: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2016 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | #ifndef _CB_INLINE_MEDIA_DOWNLOADER_H_ 19 | #define _CB_INLINE_MEDIA_DOWNLOADER_H_ 20 | 21 | #include 22 | #include 23 | #include "CbMedia.h" 24 | #include "CbTypes.h" 25 | 26 | G_BEGIN_DECLS 27 | 28 | struct _CbMediaDownloader 29 | { 30 | GObject parent_instance; 31 | 32 | GCancellable *cancellable; 33 | guint disabled : 1; 34 | }; 35 | 36 | typedef struct _CbMediaDownloader CbMediaDownloader; 37 | 38 | #define CB_TYPE_MEDIA_DOWNLOADER (cb_media_downloader_get_type ()) 39 | G_DECLARE_FINAL_TYPE (CbMediaDownloader, cb_media_downloader, CB, MEDIA_DOWNLOADER, GObject); 40 | 41 | CbMediaDownloader * cb_media_downloader_get_default (void); 42 | void cb_media_downloader_load_all (CbMediaDownloader *downloader, 43 | CbMiniTweet *t); 44 | void cb_media_downloader_load_async (CbMediaDownloader *downloader, 45 | CbMedia *media, 46 | GAsyncReadyCallback callback, 47 | gpointer user_data); 48 | void cb_media_downloader_load_hires_async (CbMediaDownloader *downloader, 49 | CbMedia *media, 50 | GAsyncReadyCallback callback, 51 | gpointer user_data); 52 | gboolean cb_media_downloader_load_finish (CbMediaDownloader *downloader, 53 | GAsyncResult *result, 54 | GError **error); 55 | void cb_media_downloader_disable (CbMediaDownloader *downloader); 56 | void cb_media_downloader_shutdown (CbMediaDownloader *downloader); 57 | gboolean is_media_candidate (const char *url); 58 | gboolean is_twitter_media_candidate (const char *url); 59 | 60 | G_END_DECLS 61 | 62 | typedef enum { 63 | CB_MEDIA_DOWNLOADER_ERROR_UNKNOWN, 64 | CB_MEDIA_DOWNLOADER_ERROR_SOUP_MESSAGE_NEW 65 | // We also use all SOUP_STATUS_... codes 66 | } CbMediaDownloaderErrorCode; 67 | 68 | #define CB_MEDIA_DOWNLOADER_ERROR cb_media_downloader_error_quark() 69 | GQuark cb_media_downloader_error_quark (void); 70 | 71 | #endif 72 | -------------------------------------------------------------------------------- /flatpak/uk.co.ibboard.cawbird.json: -------------------------------------------------------------------------------- 1 | { 2 | "app-id":"uk.co.ibboard.cawbird", 3 | "runtime":"org.gnome.Platform", 4 | "runtime-version":"3.38", 5 | "sdk":"org.gnome.Sdk", 6 | "command":"cawbird", 7 | "desktop-file-name-prefix":"(Development) ", 8 | "finish-args":[ 9 | "--share=ipc", 10 | "--share=network", 11 | "--socket=fallback-x11", 12 | "--socket=wayland", 13 | "--socket=pulseaudio" 14 | ], 15 | "cleanup":[ 16 | "/include", 17 | "/share/gir-1.0", 18 | "/lib/pkgconfig", 19 | "/lib/girepository-1.0", 20 | "/share/vala-0.34", 21 | "/bin/vala*", 22 | "/bin/vapi*", 23 | "/share/devhelp", 24 | "/share/aclocal", 25 | "/lib/*.la", 26 | "/lib/libvala*", 27 | "/lib/vala-0.34", 28 | "/share/gtk-doc", 29 | "/share/man", 30 | "/share/vala" 31 | ], 32 | "modules":[ 33 | { 34 | "name" : "libhandy", 35 | "buildsystem" : "meson", 36 | "config-opts" : [ 37 | "-Dprofiling=false", 38 | "-Dintrospection=enabled", 39 | "-Dgtk_doc=false", 40 | "-Dtests=false", 41 | "-Dexamples=false", 42 | "-Dglade_catalog=disabled" 43 | ], 44 | "sources" : [ 45 | { 46 | "type" : "archive", 47 | "url" : "https://download.gnome.org/sources/libhandy/1.0/libhandy-1.0.0.tar.xz", 48 | "sha256": "a9398582f47b7d729205d6eac0c068fef35aaf249fdd57eea3724f8518d26699" 49 | } 50 | ] 51 | }, 52 | { 53 | "name":"enchant", 54 | "config-opts":[ 55 | "--disable-static", 56 | "--with-myspell-dir=/usr/share/hunspell" 57 | ], 58 | "cleanup":[ 59 | "/bin" 60 | ], 61 | "sources":[ 62 | { 63 | "type":"archive", 64 | "url":"https://github.com/AbiWord/enchant/releases/download/v2.2.13/enchant-2.2.13.tar.gz", 65 | "sha256":"eab9f90d79039133660029616e2a684644bd524be5dc43340d4cfc3fb3c68a20" 66 | } 67 | ] 68 | }, 69 | { 70 | "name":"rest", 71 | "sources":[ 72 | { 73 | "type":"archive", 74 | "url":"https://download.gnome.org/sources/rest/0.8/rest-0.8.1.tar.xz", 75 | "sha256":"0513aad38e5d3cedd4ae3c551634e3be1b9baaa79775e53b2dba9456f15b01c9" 76 | } 77 | ] 78 | }, 79 | { 80 | "name":"gspell", 81 | "config-opts":[ 82 | "--enable-vala=yes" 83 | ], 84 | "sources":[ 85 | { 86 | "type":"archive", 87 | "url":"https://download.gnome.org/sources/gspell/1.9/gspell-1.9.1.tar.xz", 88 | "sha256":"dcbb769dfdde8e3c0a8ed3102ce7e661abbf7ddf85df08b29915e92cd723abdd" 89 | } 90 | ] 91 | }, 92 | { 93 | "name":"oauth", 94 | "config-opts":[ 95 | "--enable-nss" 96 | ], 97 | "sources":[ 98 | { 99 | "type":"archive", 100 | "url":"http://downloads.sourceforge.net/liboauth/liboauth-1.0.3.tar.gz", 101 | "sha256":"0df60157b052f0e774ade8a8bac59d6e8d4b464058cc55f9208d72e41156811f" 102 | } 103 | ] 104 | }, 105 | { 106 | "name":"cawbird", 107 | "buildsystem":"meson", 108 | "config-opts": [ 109 | "--buildtype=debug" 110 | ], 111 | "sources":[ 112 | { 113 | "type":"dir", 114 | "path":".." 115 | } 116 | ] 117 | } 118 | ] 119 | } 120 | -------------------------------------------------------------------------------- /src/sql/SelectStatement.vala: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2013 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | namespace Sql { 19 | public delegate bool SelectCallback (string[] vals); 20 | 21 | public class SelectStatement : Sql.BaseStatement { 22 | private string table_name; 23 | 24 | public SelectStatement (string table_name) { 25 | query_builder.append ("SELECT "); 26 | this.table_name = table_name; 27 | } 28 | public SelectStatement cols (string first, ...) { 29 | var arg_list = va_list (); 30 | query_builder.append ("`").append (first).append ("`"); 31 | for (string? arg = arg_list.arg (); arg != null; arg = arg_list.arg ()) { 32 | query_builder.append (", `").append (arg).append ("`"); 33 | } 34 | query_builder.append (" FROM `").append (table_name).append ("`"); 35 | return this; 36 | } 37 | 38 | public SelectStatement count (string col) { 39 | query_builder.append ("count(`").append (col).append ("`)"); 40 | query_builder.append (" FROM `").append (table_name).append ("`"); 41 | return this; 42 | } 43 | 44 | public SelectStatement order (string order_by) { 45 | query_builder.append (" ORDER BY ").append (order_by); 46 | return this; 47 | } 48 | 49 | public SelectStatement limit (int limit) { 50 | query_builder.append (" LIMIT ").append (limit.to_string ()); 51 | return this; 52 | } 53 | 54 | public int run (SelectCallback callback) { 55 | Sqlite.Statement stmt; 56 | int ok = db.prepare_v2 (query_builder.str, -1, out stmt); 57 | if (ok != Sqlite.OK) { 58 | critical (db.errmsg ()); 59 | critical (query_builder.str); 60 | return 0; 61 | } 62 | for (int i = 0; i < bindings.length; i++) { 63 | stmt.bind_text (i + 1, bindings.get (i)); 64 | } 65 | bool next = true; 66 | int n_cols = stmt.column_count (); 67 | int n_rows = 0; 68 | while (stmt.step () == Sqlite.ROW && next) { 69 | string[] vals = new string[n_cols]; 70 | for (int i = 0; i < n_cols; i++) 71 | vals[i] = stmt.column_text (i); 72 | next = callback (vals); 73 | n_rows ++; 74 | } 75 | return n_rows; 76 | } 77 | 78 | public int64 once_i64 () { 79 | int64 back = -1; 80 | this.run ((vals) => { 81 | back = int64.parse (vals[0]); 82 | return false; 83 | }); 84 | return back; 85 | } 86 | 87 | public string? once_string () { 88 | string? back = null; 89 | this.run ((vals) => { 90 | back = vals[0]; 91 | return false; 92 | }); 93 | return back; 94 | } 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /src/sql/UpdateStatement.vala: -------------------------------------------------------------------------------- 1 | 2 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 3 | * Copyright (C) 2013 Timm Bäder (Corebird) 4 | * 5 | * Cawbird is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Cawbird is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with cawbird. If not, see . 17 | */ 18 | 19 | namespace Sql { 20 | 21 | public class UpdateStatement : GLib.Object { 22 | public unowned Sqlite.Database db; 23 | private StringBuilder query_builder = new StringBuilder (); 24 | private GLib.GenericArray bindings = new GLib.GenericArray (); 25 | private bool ran = false; 26 | 27 | public UpdateStatement (string table_name) { 28 | query_builder.append ("UPDATE `").append (table_name).append ("` SET "); 29 | } 30 | 31 | public int64 run () { 32 | Sqlite.Statement stmt; 33 | query_builder.append(";"); 34 | int ok = db.prepare_v2 (query_builder.str, -1, out stmt); 35 | 36 | if (ok != Sqlite.OK) { 37 | critical (db.errmsg ()); 38 | return -1; 39 | } 40 | for (int i = 0; i < bindings.length; i++) { 41 | stmt.bind_text (i + 1, bindings.get (i)); 42 | } 43 | ok = stmt.step (); 44 | if (ok == Sqlite.ERROR) { 45 | critical (db.errmsg ()); 46 | critical (stmt.sql ()); 47 | return -1; 48 | } 49 | ran = true; 50 | return db.last_insert_rowid (); 51 | } 52 | 53 | public UpdateStatement where (string where) { 54 | query_builder.append (" WHERE ").append (where); 55 | return this; 56 | } 57 | 58 | public UpdateStatement where_eq (string col, string value) { 59 | query_builder.append (" WHERE `").append (col).append ("`= ?"); 60 | bindings.add (value); 61 | return this; 62 | } 63 | 64 | public UpdateStatement where_eqi (string col, int64 iv) { 65 | return where_eq (col, iv.to_string ()); 66 | } 67 | 68 | public UpdateStatement val (string col_name, string col_value) { 69 | if (bindings.length > 0) 70 | query_builder.append (", "); 71 | query_builder.append ("`").append (col_name).append ("` = ?"); 72 | bindings.add (col_value); 73 | return this; 74 | } 75 | 76 | public UpdateStatement vali (string col_name, int col_value) { 77 | return val (col_name, col_value.to_string ()); 78 | } 79 | 80 | public UpdateStatement vali64 (string col_name, int64 col_value) { 81 | return val (col_name, col_value.to_string ()); 82 | } 83 | 84 | public UpdateStatement valb (string col_name, bool col_value) { 85 | return val (col_name, col_value ? "1" : "0"); 86 | } 87 | #if DEBUG 88 | ~UpdateStatement () { 89 | if (!ran) 90 | critical ("UpdateStatement for %s did not run.", query_builder.str); 91 | } 92 | #endif 93 | 94 | 95 | } 96 | 97 | } 98 | 99 | 100 | -------------------------------------------------------------------------------- /src/CbUserStream.h: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2017 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | #ifndef __CB_USER_STREAM_H__ 19 | #define __CB_USER_STREAM_H__ 20 | 21 | #include 22 | #include 23 | #include 24 | #include "CbMessageReceiver.h" 25 | #include "CbTypes.h" 26 | 27 | G_BEGIN_DECLS 28 | 29 | #define CB_TYPE_USER_STREAM (cb_user_stream_get_type ()) 30 | G_DECLARE_FINAL_TYPE (CbUserStream, cb_user_stream, CB, USER_STREAM, GObject); 31 | 32 | struct _CbUserStream 33 | { 34 | GObject parent_instance; 35 | 36 | GPtrArray *receivers; 37 | RestProxy *proxy; 38 | GNetworkMonitor *network_monitor; 39 | 40 | guint network_timeout_id; 41 | guint heartbeat_timeout_id; 42 | guint network_changed_id; 43 | 44 | gint64 last_home_id; 45 | guint timeline_timeout; 46 | GCancellable *home_cancellable; 47 | 48 | gint64 last_mentions_id; 49 | guint mentions_timeout; 50 | GCancellable *mentions_cancellable; 51 | 52 | gint64 last_favourited_id; 53 | guint favourited_timeout; 54 | GCancellable *favourited_cancellable; 55 | 56 | gint64 first_dm_id; 57 | gint64 last_dm_id; 58 | gint64 new_last_dm_id; // Placeholder for the next value of last_dm_id so that we can page back if lots of tweets came in 59 | unsigned char dm_recursions; 60 | guint dm_timeout; 61 | GCancellable *dm_cancellable; 62 | 63 | char *account_name; 64 | 65 | guint state; 66 | guint restarting : 1; 67 | guint proxy_data_set : 1; 68 | guint network_available: 1; 69 | }; 70 | typedef struct _CbUserStream CbUserStream; 71 | 72 | CbUserStream * cb_user_stream_new (const char *account_name, 73 | OAuthProxy *proxy); 74 | void cb_user_stream_set_proxy_data (CbUserStream *self, 75 | const char *token, 76 | const char *token_secret); 77 | void cb_user_stream_register (CbUserStream *self, 78 | CbMessageReceiver *receiver); 79 | void cb_user_stream_unregister (CbUserStream *self, 80 | CbMessageReceiver *receiver); 81 | void cb_user_stream_start (CbUserStream *self); 82 | void cb_user_stream_stop (CbUserStream *self); 83 | void cb_user_stream_push_data (CbUserStream *self, 84 | const char *data); 85 | void cb_user_stream_inject_tweet (CbUserStream *self, 86 | CbStreamMessageType message_type, 87 | const gchar *content) 88 | 89 | G_END_DECLS; 90 | 91 | #endif 92 | -------------------------------------------------------------------------------- /src/widgets/PixbufButton.vala: -------------------------------------------------------------------------------- 1 | /* PixbufButton.vala 2 | * 3 | * This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 4 | * Copyright 2020 Frederick Schenk 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | * 19 | * SPDX-License-Identifier: GPL-3.0-or-later 20 | */ 21 | 22 | class PixbufButton : Gtk.Button { 23 | private Cairo.ImageSurface bg; 24 | private bool _round = false; 25 | public bool round { 26 | get { 27 | return _round; 28 | } 29 | set { 30 | if (value) { 31 | this.get_style_context ().add_class ("pixbuf-button-round"); 32 | } else { 33 | this.get_style_context ().remove_class ("pixbuf-button-round"); 34 | } 35 | _round = value; 36 | } 37 | } 38 | 39 | construct { 40 | this.border_width = 0; 41 | get_style_context ().add_class ("pixbuf-button"); 42 | } 43 | 44 | public PixbufButton () {} 45 | 46 | public override bool draw (Cairo.Context ct) { 47 | var sc = this.get_style_context (); 48 | int widget_width = this.get_allocated_width (); 49 | int widget_height = this.get_allocated_height (); 50 | 51 | 52 | if (bg != null) { 53 | 54 | var surface = new Cairo.Surface.similar (ct.get_target (), 55 | Cairo.Content.COLOR_ALPHA, 56 | widget_width, widget_height); 57 | var ctx = new Cairo.Context (surface); 58 | 59 | ctx.rectangle (0, 0, widget_width, widget_height); 60 | 61 | double scale_x = (double)widget_width / bg.get_width (); 62 | double scale_y = (double)widget_height / bg.get_height (); 63 | ctx.save (); 64 | ctx.scale (scale_x, scale_y); 65 | ctx.set_source_surface (bg, 0, 0); 66 | ctx.fill (); 67 | ctx.restore (); 68 | 69 | 70 | 71 | if (_round) { 72 | // make it round 73 | ctx.set_operator (Cairo.Operator.DEST_IN); 74 | ctx.translate (widget_width / 2, widget_height / 2); 75 | ctx.arc (0, 0, widget_width / 2, 0, 2 * Math.PI); 76 | ctx.fill (); 77 | 78 | // draw outline 79 | sc.render_frame (ct, 0, 0, widget_width, widget_height); 80 | } 81 | 82 | ct.rectangle (0, 0, widget_width, widget_height); 83 | ct.set_source_surface (surface, 0, 0); 84 | ct.fill (); 85 | } 86 | 87 | // The css-styled background should be transparent. 88 | base.draw (ct); 89 | return GLib.Source.CONTINUE; 90 | } 91 | 92 | public void set_bg (Cairo.ImageSurface bg) { 93 | this.bg = bg; 94 | this.set_size_request (bg.get_width(), bg.get_height()); 95 | this.queue_draw (); 96 | } 97 | 98 | public void set_pixbuf (Gdk.Pixbuf pixbuf) { 99 | this.bg = (Cairo.ImageSurface)Gdk.cairo_surface_create_from_pixbuf (pixbuf, 1, null); 100 | this.queue_draw (); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /data/symbolic/apps/cawbird-new-window-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 20 | 38 | 40 | 41 | 43 | image/svg+xml 44 | 46 | 47 | 48 | 49 | 50 | 55 | 61 | 66 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /src/list/UserFilterEntry.vala: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2013 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | [GtkTemplate (ui = "/uk/co/ibboard/cawbird/ui/user-filter-entry.ui")] 19 | class UserFilterEntry : Gtk.ListBoxRow, Cb.TwitterItem { 20 | [GtkChild] 21 | private Gtk.Label name_label; 22 | [GtkChild] 23 | private Gtk.Label screen_name_label; 24 | [GtkChild] 25 | private AvatarWidget avatar_image; 26 | [GtkChild] 27 | private Gtk.Stack stack; 28 | [GtkChild] 29 | private Gtk.Box delete_box; 30 | [GtkChild] 31 | private Gtk.Grid grid; 32 | [GtkChild] 33 | private Gtk.Revealer revealer; 34 | [GtkChild] 35 | private Gtk.Button delete_button; 36 | 37 | public new string name { 38 | set { 39 | name_label.label = value; 40 | name_label.set_tooltip_text(value); 41 | } 42 | } 43 | 44 | public string screen_name { 45 | set { screen_name_label.label = "@" + value; } 46 | } 47 | 48 | public string avatar_url { 49 | set { real_set_avatar (value); } 50 | } 51 | 52 | public bool seen { 53 | get { return true; } 54 | set {} 55 | } 56 | 57 | public int64 user_id; 58 | 59 | public signal void deleted (int64 id); 60 | 61 | private bool _muted = false; 62 | private bool _blocked = false; 63 | 64 | public bool muted { 65 | get { return _muted; } 66 | set { 67 | _muted = value; 68 | if (muted && !blocked) { 69 | delete_button.label = _("Unmute"); 70 | } 71 | // Else the blocking takes priority 72 | } 73 | } 74 | public bool blocked { 75 | get { return _blocked; } 76 | set { 77 | _blocked = value; 78 | if (blocked) { 79 | delete_button.label = _("Unblock"); 80 | } 81 | } 82 | } 83 | private GLib.TimeSpan last_timediff; 84 | 85 | private void real_set_avatar (string avatar_url) { 86 | Twitter.get ().get_avatar.begin (user_id, avatar_url, avatar_image, 48 * this.get_scale_factor ()); 87 | } 88 | 89 | public int update_time_delta (GLib.DateTime? now = null) {return 0;} 90 | public int64 get_sort_factor () { return 2; } 91 | public int64 get_timestamp () { return 0; } 92 | 93 | public GLib.TimeSpan get_last_set_timediff () { 94 | return this.last_timediff; 95 | } 96 | 97 | public void set_last_set_timediff (GLib.TimeSpan span) { 98 | this.last_timediff = span; 99 | } 100 | 101 | [GtkCallback] 102 | private void menu_button_clicked_cb () { 103 | stack.visible_child = delete_box; 104 | } 105 | 106 | [GtkCallback] 107 | private void cancel_button_clicked_cb () { 108 | stack.visible_child = grid; 109 | } 110 | 111 | [GtkCallback] 112 | private void delete_button_clicked_cb () { 113 | revealer.reveal_child = false; 114 | revealer.notify["child-revealed"].connect (() => { 115 | deleted (user_id); 116 | }); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/CbDeltaUpdater.c: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2017 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | #include "CbDeltaUpdater.h" 19 | 20 | G_DEFINE_TYPE(CbDeltaUpdater, cb_delta_updater, G_TYPE_OBJECT) 21 | 22 | 23 | static gboolean 24 | minutely_cb (gpointer user_data) 25 | { 26 | CbDeltaUpdater *self = user_data; 27 | GDateTime *now; 28 | GList *widgets; 29 | GList *l; 30 | 31 | if (!GTK_IS_WIDGET (self->listbox)) 32 | return G_SOURCE_REMOVE; 33 | 34 | widgets = gtk_container_get_children (GTK_CONTAINER (self->listbox)); 35 | now = g_date_time_new_now_local (); 36 | 37 | for (l = widgets; l != NULL; l = l->next) 38 | { 39 | GtkWidget *row = GTK_WIDGET (l->data); 40 | 41 | if (CB_IS_TWITTER_ITEM (row)) 42 | { 43 | CbTwitterItem *item = CB_TWITTER_ITEM (row); 44 | gint64 timestamp = cb_twitter_item_get_timestamp (item); 45 | gint64 last_set_timediff = cb_twitter_item_get_last_set_timediff (item); 46 | GDateTime *item_time = g_date_time_new_from_unix_local (timestamp); 47 | GTimeSpan time_diff = g_date_time_difference (now, item_time); 48 | int seconds = time_diff / 1000 / 1000; 49 | 50 | 51 | if (last_set_timediff < 60) 52 | { 53 | /* New minute */ 54 | cb_twitter_item_update_time_delta (item, now); 55 | cb_twitter_item_set_last_set_timediff (item, seconds / 60); 56 | } 57 | else if (seconds > last_set_timediff + 60) 58 | { 59 | /* New hour */ 60 | cb_twitter_item_update_time_delta (item, now); 61 | cb_twitter_item_set_last_set_timediff (item, seconds / 60); 62 | } 63 | 64 | g_date_time_unref (item_time); 65 | } 66 | } 67 | 68 | 69 | g_date_time_unref (now); 70 | g_list_free (widgets); 71 | 72 | return G_SOURCE_CONTINUE; 73 | } 74 | 75 | static void 76 | cb_delta_updater_finalize (GObject *object) 77 | { 78 | CbDeltaUpdater *self = CB_DELTA_UPDATER (object); 79 | 80 | if (self->minutely_id != 0) 81 | g_source_remove (self->minutely_id); 82 | 83 | G_OBJECT_CLASS (cb_delta_updater_parent_class)->finalize (object); 84 | } 85 | 86 | static void 87 | cb_delta_updater_init (CbDeltaUpdater *self) 88 | { 89 | self->minutely_id = g_timeout_add (1000 * 60, minutely_cb, self); 90 | } 91 | 92 | static void 93 | cb_delta_updater_class_init (CbDeltaUpdaterClass *klass) 94 | { 95 | GObjectClass *object_class = G_OBJECT_CLASS (klass); 96 | 97 | object_class->finalize = cb_delta_updater_finalize; 98 | } 99 | 100 | CbDeltaUpdater * 101 | cb_delta_updater_new (GtkWidget *listbox) 102 | { 103 | CbDeltaUpdater *self = g_object_new (CB_TYPE_DELTA_UPDATER, NULL); 104 | 105 | g_return_val_if_fail (GTK_IS_LIST_BOX (listbox), self); 106 | 107 | self->listbox = listbox; 108 | 109 | return self; 110 | } 111 | -------------------------------------------------------------------------------- /src/CbUtils.h: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2017 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | #ifndef _CB_UTILS_H_ 19 | #define _CB_UTILS_H_ 20 | 21 | #include 22 | #ifdef GDK_WINDOWING_X11 23 | #include 24 | #endif 25 | //#ifdef GDK_WINDOWING_WAYLAND 26 | //#include 27 | //#endif 28 | #include 29 | #include "CbTypes.h" 30 | #include 31 | #include 32 | 33 | typedef GtkWidget * (*CbUtilsCreateWidgetFunc) (gpointer *data, gpointer *user_data); 34 | 35 | 36 | void cb_utils_bind_model (GtkWidget *listbox, 37 | GListModel *model, 38 | GtkListBoxCreateWidgetFunc func, 39 | void *data); 40 | 41 | void cb_utils_bind_non_gobject_model (GtkWidget *listbox, 42 | GListModel *model, 43 | CbUtilsCreateWidgetFunc func, 44 | gpointer *user_data); 45 | 46 | void cb_utils_unbind_non_gobject_model (GtkWidget *listbox, 47 | GListModel *model); 48 | 49 | void cb_utils_linkify_user (const CbUserIdentity *user, 50 | GString *str); 51 | 52 | void cb_utils_write_reply_text (const CbMiniTweet *t, 53 | GString *str); 54 | 55 | char * cb_utils_escape_quotes (const char *in); 56 | char * cb_utils_escape_ampersands (const char *in); 57 | 58 | GDateTime * cb_utils_parse_date (const char *_in); 59 | 60 | char * cb_utils_get_file_type (const char *url); 61 | char * cb_utils_rest_proxy_call_to_string (RestProxyCall *call); 62 | 63 | void cb_utils_load_threaded_async (RestProxyCall *call, 64 | GCancellable *cancellable, 65 | GAsyncReadyCallback callback, 66 | gpointer user_data); 67 | 68 | JsonNode *cb_utils_load_threaded_finish (GAsyncResult *result, 69 | GError **error); 70 | 71 | void cb_utils_query_users_async (RestProxy *proxy, 72 | const char *query, 73 | GCancellable *cancellable, 74 | GAsyncReadyCallback callback, 75 | gpointer user_data); 76 | CbUserIdentity * cb_utils_query_users_finish (GAsyncResult *result, 77 | int *out_length, 78 | GError **error); 79 | 80 | void cb_utils_init_gui (gint *argc, gchar ***argv); 81 | 82 | static inline void 83 | cb_clear_source (guint *id) 84 | { 85 | if (*id == 0) 86 | return; 87 | 88 | g_source_remove (*id); 89 | *id = 0; 90 | } 91 | 92 | 93 | #endif 94 | -------------------------------------------------------------------------------- /src/MediaUpload.vala: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2020 IBBoard 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | class MediaUpload : GLib.Object { 19 | public string id { get; private set; } 20 | public string? filepath { 21 | owned get { 22 | return file.get_path(); 23 | } 24 | } 25 | public string filetype { 26 | get { 27 | return fileinfo.get_content_type (); 28 | } 29 | } 30 | private string? cat; 31 | public string media_category { 32 | owned get { 33 | if (cat == null) { 34 | var prefix = dm ? "dm" : "tweet"; 35 | if (filetype.has_prefix("video/")) { 36 | cat = "%s_video".printf(prefix); 37 | } 38 | else if (filetype == "image/gif") { 39 | // Animated GIFs are "blah_gif" but static GIFs are "blah_image" 40 | if (Utils.is_animated_gif(filepath)) { 41 | cat = "%s_gif".printf(prefix); 42 | } 43 | else { 44 | cat = "%s_image".printf(prefix); 45 | } 46 | } 47 | else { 48 | cat = "%s_image".printf(prefix); 49 | } 50 | } 51 | return cat; 52 | } 53 | } 54 | private int64 _media_id = -1; 55 | public int64 media_id { 56 | get { return _media_id; } 57 | set { 58 | _media_id = value; 59 | media_id_assigned(); 60 | } 61 | } 62 | private File file; 63 | private FileInfo fileinfo; 64 | private bool dm; 65 | public int64 filesize { 66 | get { 67 | return fileinfo.get_size(); 68 | } 69 | } 70 | private double _progress = 0; 71 | public double progress { 72 | get { 73 | return _progress; 74 | } 75 | set { 76 | _progress = value; 77 | progress_updated(_progress); 78 | } 79 | } 80 | private bool upload_finalized; 81 | public GLib.Cancellable cancellable { get; private set; } 82 | public signal void progress_updated(double progress); 83 | public signal void progress_complete(GLib.Error? error = null); 84 | public signal void media_id_assigned(); 85 | 86 | public MediaUpload(string filepath, bool for_dm = false) throws GLib.Error { 87 | id = GLib.Uuid.string_random(); 88 | file = File.new_for_path(filepath); 89 | fileinfo = file.query_info(GLib.FileAttribute.STANDARD_TYPE + "," + 90 | GLib.FileAttribute.STANDARD_CONTENT_TYPE + "," + 91 | GLib.FileAttribute.STANDARD_SIZE, 0); 92 | dm = for_dm; 93 | cancellable = new GLib.Cancellable(); 94 | } 95 | 96 | public FileInputStream read() throws GLib.Error { 97 | return file.read(); 98 | } 99 | 100 | public void finalize_upload() { 101 | debug("Finalizing upload"); 102 | progress = 1.0; 103 | upload_finalized = true; 104 | progress_complete(); 105 | } 106 | 107 | public bool is_uploaded() { 108 | return upload_finalized; 109 | } 110 | } -------------------------------------------------------------------------------- /src/FavoritesTimeline.vala: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2013 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | class FavoritesTimeline : Cb.MessageReceiver, DefaultTimeline { 19 | protected override string function { 20 | get { 21 | return "1.1/favorites/list.json"; 22 | } 23 | } 24 | 25 | protected override string accessibility_name { 26 | get { 27 | return _("Favourites timeline"); 28 | } 29 | } 30 | 31 | public FavoritesTimeline (int id, Account account) { 32 | base (id); 33 | this.account = account; 34 | this.tweet_list.account = account; 35 | } 36 | 37 | protected override void stream_message_received (Cb.StreamMessageType type, Json.Node root) { 38 | if (type == Cb.StreamMessageType.TWEET) { 39 | if (root.get_object ().has_member ("retweeted_status")) { 40 | Utils.set_rt_from_tweet (root, this.tweet_list.model, this.account); 41 | } 42 | } else if (type == Cb.StreamMessageType.DELETE) { 43 | int64 id = root.get_object ().get_object_member ("delete") 44 | .get_object_member ("status").get_int_member ("id"); 45 | delete_tweet (id); 46 | } else if (type == Cb.StreamMessageType.RT_DELETE) { 47 | Utils.unrt_tweet (root, this.tweet_list.model); 48 | } else if (type == Cb.StreamMessageType.EVENT_FAVORITE) { 49 | Json.Node tweet_obj = root; 50 | int64 tweet_id = tweet_obj.get_object ().get_int_member ("id"); 51 | 52 | Cb.Tweet? existing_tweet = this.tweet_list.model.get_for_id (tweet_id, 0); 53 | if (existing_tweet != null) { 54 | /* This tweet is already in the model, so just mark it as favorited */ 55 | tweet_list.model.set_tweet_flag (existing_tweet, Cb.TweetState.FAVORITED); 56 | return; 57 | } 58 | 59 | var tweet = new Cb.Tweet (); 60 | tweet.load_from_json (tweet_obj, account.id, new GLib.DateTime.now_local ()); 61 | tweet.set_flag (Cb.TweetState.FAVORITED); 62 | this.tweet_list.model.add (tweet); 63 | } else if (type == Cb.StreamMessageType.EVENT_UNFAVORITE) { 64 | int64 id = root.get_object ().get_object_member ("target_object").get_int_member ("id"); 65 | toggle_favorite (id, false); 66 | } 67 | else { 68 | // We don't do a full fall back to DefaultTimeline here because we want to keep content 69 | // we liked from people we then blocked/muted so that we can remove it 70 | handle_core_stream_messages (type, root); 71 | } 72 | } 73 | 74 | 75 | public override void on_leave () { 76 | for (uint i = 0; i < tweet_list.model.get_n_items (); i ++) { 77 | var tweet = (Cb.Tweet) tweet_list.model.get_item (i); 78 | if (!tweet.is_flag_set (Cb.TweetState.FAVORITED)) { 79 | tweet_list.model.remove_tweet (tweet); 80 | i --; 81 | } 82 | } 83 | 84 | base.on_leave (); 85 | } 86 | 87 | public override string get_title () { 88 | return _("Favorites"); 89 | } 90 | 91 | public override void create_radio_button (Gtk.RadioButton? group) { 92 | radio_button = new BadgeRadioButton(group, "cawbird-favorite-symbolic", _("Favorites")); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/sql/InsertStatement.vala: -------------------------------------------------------------------------------- 1 | /* This file is part of Cawbird, a Gtk+ linux Twitter client forked from Corebird. 2 | * Copyright (C) 2013 Timm Bäder (Corebird) 3 | * 4 | * Cawbird is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * Cawbird is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with cawbird. If not, see . 16 | */ 17 | 18 | namespace Sql { 19 | /** 20 | * What to do in case of key collision during INSERT - fail, replace or ignore 21 | */ 22 | public enum InsertType { 23 | FAIL, 24 | REPLACE, 25 | IGNORE 26 | } 27 | 28 | public class InsertStatement : GLib.Object { 29 | public unowned Sqlite.Database db; 30 | private StringBuilder query_builder = new StringBuilder (); 31 | private GLib.GenericArray bindings = new GLib.GenericArray(); 32 | private bool ran = false; 33 | 34 | public InsertStatement (string table_name, InsertType ins_type) { 35 | if (ins_type == InsertType.REPLACE) { 36 | query_builder.append ("INSERT OR REPLACE INTO `"); 37 | } else if (ins_type == InsertType.IGNORE) { 38 | query_builder.append ("INSERT OR IGNORE INTO `"); 39 | } else { 40 | query_builder.append ("INSERT INTO `"); 41 | } 42 | query_builder.append (table_name).append ("` ("); 43 | } 44 | 45 | public int64 run () { 46 | query_builder.append (") VALUES ("); 47 | query_builder.append ("?"); 48 | for (int i = 0; i < bindings.length -1; i++) 49 | query_builder.append (",?"); 50 | query_builder.append (");"); 51 | 52 | 53 | Sqlite.Statement stmt; 54 | int ok = db.prepare_v2 (query_builder.str, -1, out stmt); 55 | 56 | if (ok != Sqlite.OK) { 57 | critical (db.errmsg ()); 58 | return -1; 59 | } 60 | 61 | for (int i = 0; i < bindings.length; i++) { 62 | stmt.bind_text (i + 1, bindings.get (i)); 63 | } 64 | ok = stmt.step (); 65 | if (ok != Sqlite.DONE) { 66 | critical (db.errmsg ()); 67 | StringBuilder err_msg = new StringBuilder (); 68 | err_msg.append (stmt.sql ()).append (" --- "); 69 | for (int i = 0; i < bindings.length; i++) { 70 | err_msg.append (bindings.get (i)).append (", "); 71 | } 72 | critical (err_msg.str); 73 | } 74 | ran = true; 75 | return db.last_insert_rowid (); 76 | } 77 | 78 | public InsertStatement val (string col_name, string col_value) { 79 | if (bindings.length > 0) 80 | query_builder.append (", "); 81 | query_builder.append ("`").append (col_name).append ("`"); 82 | bindings.add (col_value); 83 | return this; 84 | } 85 | 86 | public InsertStatement vali (string col_name, int col_value) { 87 | return val (col_name, col_value.to_string ()); 88 | } 89 | 90 | public InsertStatement vali64 (string col_name, int64 col_value) { 91 | return val (col_name, col_value.to_string ()); 92 | } 93 | 94 | public InsertStatement valb (string col_name, bool col_value) { 95 | return val (col_name, col_value ? "1" : "0"); 96 | } 97 | 98 | #if DEBUG 99 | ~InsertStatement () { 100 | if (!ran) 101 | critical ("InsertStatement for %s did not run.", query_builder.str); 102 | } 103 | #endif 104 | } 105 | 106 | } 107 | 108 | -------------------------------------------------------------------------------- /data/symbolic/apps/cawbird-reply-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 45 | 48 | 49 | 51 | 52 | 54 | image/svg+xml 55 | 57 | 58 | 59 | 60 | 61 | 66 | 73 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /tests/bundlehistory.vala: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | void all () { 7 | 8 | var history = new Cb.BundleHistory (); 9 | history.push (1, null); 10 | history.push (2, null); 11 | history.push (3, null); 12 | history.push (4, null); 13 | history.push (5, null); 14 | assert (history.get_current () == 5); 15 | 16 | history.back (); 17 | assert (history.get_current () == 4); 18 | 19 | history.back (); 20 | assert (history.get_current () == 3); 21 | 22 | history.forward (); 23 | assert (history.get_current () == 4); 24 | 25 | history.push (10, null); 26 | assert (history.get_current () == 10); 27 | 28 | //history.forward (); 29 | //assert (history.get_current () == 10); 30 | 31 | //history.forward (); 32 | //assert (history.get_current () == 10); 33 | } 34 | 35 | 36 | 37 | void end () { 38 | var history = new Cb.BundleHistory (); 39 | assert (history.at_end ()); 40 | 41 | history.push (1, null); 42 | assert (history.at_end ()); 43 | 44 | history.push (2, null); 45 | assert (history.at_end ()); 46 | 47 | history.back (); 48 | assert (!history.at_end ()); 49 | 50 | } 51 | 52 | void equals () { 53 | var bundle1 = new Cb.Bundle (); 54 | bundle1.put_string (0, "1"); 55 | bundle1.put_string (1, "3"); 56 | 57 | var bundle2 = new Cb.Bundle (); 58 | bundle2.put_string (1, "3"); 59 | bundle2.put_string (0, "1"); 60 | 61 | assert (bundle1.equals (bundle2)); 62 | assert (!bundle1.equals (null)); 63 | 64 | var bundle3 = new Cb.Bundle (); 65 | assert (!bundle3.equals (bundle1)); 66 | } 67 | 68 | void remove_current () { 69 | var history = new Cb.BundleHistory (); 70 | 71 | var bundle1 = new Cb.Bundle (); 72 | bundle1.put_string (0, "a"); 73 | bundle1.put_string (1, "b"); 74 | history.push (1, bundle1); 75 | 76 | var bundle2 = new Cb.Bundle (); 77 | bundle2.put_string (3, "c"); 78 | bundle2.put_string (4, "d"); 79 | history.push (2, bundle2); 80 | 81 | // push advances 82 | assert (history.at_end()); 83 | assert (history.get_current_bundle () == bundle2); 84 | assert (history.get_current () == 2); 85 | 86 | 87 | // remove_current deletes the current bundle but doesn't 88 | // to back 89 | history.remove_current (); 90 | assert (history.get_current_bundle () == null); 91 | assert (history.get_current () == -1); 92 | 93 | // This should bring us to bundle1 94 | history.back (); 95 | assert (history.get_current_bundle () == bundle1); 96 | assert (history.get_current () == 1); 97 | 98 | 99 | history.remove_current (); 100 | assert (history.get_current_bundle () == null); 101 | assert (history.get_current () == -1); 102 | 103 | history.back (); 104 | assert (history.at_start ()); 105 | 106 | // Shouldn't do anything significant even if at_start() == true 107 | history.remove_current (); 108 | history.remove_current (); 109 | 110 | 111 | // Empty! 112 | assert (history.at_end ()); 113 | assert (history.at_start ()); 114 | 115 | var bundle3 = new Cb.Bundle (); 116 | bundle3.put_string (0, "_"); 117 | var bundle4 = new Cb.Bundle (); 118 | bundle4.put_string (7, "__"); 119 | var bundle5 = new Cb.Bundle (); 120 | bundle5.put_string (10, "___"); 121 | 122 | history.push (3, bundle3); 123 | history.push (4, bundle4); 124 | history.push (5, bundle5); 125 | 126 | assert (history.get_current () == 5); 127 | history.back (); 128 | assert (history.get_current () == 4); 129 | 130 | history.remove_current (); 131 | assert (history.get_current () == 5); // everything after 4 was moved one to the front 132 | assert (history.get_current_bundle () == bundle5); 133 | assert (history.at_end ()); 134 | 135 | } 136 | 137 | int main (string[] args) { 138 | GLib.Test.init (ref args); 139 | GLib.Test.add_func ("/bundlehistory/all", all); 140 | GLib.Test.add_func ("/bundlehistory/end", end); 141 | GLib.Test.add_func ("/bundlehistory/equals", equals); 142 | GLib.Test.add_func ("/bundlehistory/remove-current", remove_current); 143 | 144 | return GLib.Test.run (); 145 | } 146 | --------------------------------------------------------------------------------