Philipp Hörist pushed to branch master at gajim / gajim

Commits:

23 changed files:

Changes:

  • gajim/common/configpaths.py
    ... ... @@ -125,7 +125,6 @@ def __init__(self) -> None:
    125 125
             source_paths = [
    
    126 126
                 ('DATA', basedir / 'data'),
    
    127 127
                 ('STYLE', basedir / 'data' / 'style'),
    
    128
    -            ('EMOTICONS', basedir / 'data' / 'emoticons'),
    
    129 128
                 ('GUI', basedir / 'data' / 'gui'),
    
    130 129
                 ('ICONS', basedir / 'data' / 'icons'),
    
    131 130
                 ('HOME', Path.home()),
    
    ... ... @@ -216,8 +215,6 @@ def init(self):
    216 215
                 ('PLUGINS_IMAGES', 'plugins_images',
    
    217 216
                  PathLocation.CACHE, PathType.FOLDER),
    
    218 217
                 ('PLUGINS_USER', 'plugins', PathLocation.DATA, PathType.FOLDER),
    
    219
    -            ('MY_EMOTS',
    
    220
    -             'emoticons', PathLocation.DATA, PathType.FOLDER_OPTIONAL),
    
    221 218
                 ('MY_ICONSETS',
    
    222 219
                  'iconsets', PathLocation.DATA, PathType.FOLDER_OPTIONAL),
    
    223 220
     
    

  • gajim/common/helpers.py
    ... ... @@ -766,22 +766,6 @@ def version_condition(current_version: str, required_version: str) -> bool:
    766 766
         return True
    
    767 767
     
    
    768 768
     
    
    769
    -def get_available_emoticon_themes() -> list[str]:
    
    770
    -    files: list[Path] = []
    
    771
    -    for folder in configpaths.get('EMOTICONS').iterdir():
    
    772
    -        if not folder.is_dir():
    
    773
    -            continue
    
    774
    -        files += [theme for theme in folder.iterdir() if theme.is_file()]
    
    775
    -
    
    776
    -    my_emots = configpaths.get('MY_EMOTS')
    
    777
    -    if my_emots.is_dir():
    
    778
    -        files += list(my_emots.iterdir())
    
    779
    -
    
    780
    -    emoticons_themes = ['font']
    
    781
    -    emoticons_themes += [file.stem for file in files if file.suffix == '.png']
    
    782
    -    return sorted(emoticons_themes)
    
    783
    -
    
    784
    -
    
    785 769
     def call_counter(func):
    
    786 770
         def helper(self, restart=False):
    
    787 771
             if restart:
    

  • gajim/common/setting_values.py
    ... ... @@ -49,7 +49,6 @@ class _ACCOUNT_DEFAULT:
    49 49
         'confirm_close_muc',
    
    50 50
         'confirm_on_window_delete',
    
    51 51
         'dev_force_bookmark_2',
    
    52
    -    'dev_use_message_label',
    
    53 52
         'developer_modus',
    
    54 53
         'enable_emoji_shortcodes',
    
    55 54
         'enable_negative_priority',
    
    ... ... @@ -137,7 +136,6 @@ class _ACCOUNT_DEFAULT:
    137 136
         'date_format',
    
    138 137
         'date_time_format',
    
    139 138
         'dictionary_url',
    
    140
    -    'emoticons_theme',
    
    141 139
         'gc_refer_to_nick_char',
    
    142 140
         'global_proxy',
    
    143 141
         'last_save_dir',
    
    ... ... @@ -194,7 +192,6 @@ class _ACCOUNT_DEFAULT:
    194 192
         'dev_use_message_label': True,
    
    195 193
         'developer_modus': False,
    
    196 194
         'dictionary_url': 'WIKTIONARY',
    
    197
    -    'emoticons_theme': 'noto-emoticons',
    
    198 195
         'enable_emoji_shortcodes': True,
    
    199 196
         'enable_negative_priority': False,
    
    200 197
         'enable_file_preview': True,
    

  • gajim/common/settings.py
    ... ... @@ -237,11 +237,6 @@ def _setup_installation_defaults() -> None:
    237 237
             if IS_PORTABLE:
    
    238 238
                 APP_SETTINGS['use_keyring'] = False
    
    239 239
     
    
    240
    -        if sys.platform in ('win32', 'darwin'):
    
    241
    -            # Cairo does not support color emojis fonts on
    
    242
    -            # Windows and MacOS
    
    243
    -            APP_SETTINGS['dev_use_message_label'] = False
    
    244
    -
    
    245 240
         def _load_app_overrides(self) -> None:
    
    246 241
             if not OVERRIDES_PATH.exists():
    
    247 242
                 return
    

  • gajim/common/styling.py
    ... ... @@ -19,7 +19,6 @@
    19 19
     from typing import Optional
    
    20 20
     
    
    21 21
     import string
    
    22
    -import sys
    
    23 22
     import re
    
    24 23
     from dataclasses import dataclass
    
    25 24
     from dataclasses import field
    
    ... ... @@ -31,7 +30,6 @@
    31 30
     from gajim.common.helpers import parse_uri as analyze_uri
    
    32 31
     from gajim.common.helpers import validate_jid
    
    33 32
     from gajim.common.text_helpers import jid_to_iri
    
    34
    -from gajim.gui.emoji_data import emoji_data
    
    35 33
     
    
    36 34
     PRE = '`'
    
    37 35
     STRONG = '*'
    
    ... ... @@ -53,9 +51,6 @@
    53 51
     URI_OR_JID_RX = re.compile(
    
    54 52
         fr'(?P<uri>(?<![\w+.-]){regex.IRI})|(?P<jid>{regex.XMPP.jid})')
    
    55 53
     
    
    56
    -EMOJI_RX = emoji_data.get_regex()
    
    57
    -EMOJI_RX = re.compile(EMOJI_RX)
    
    58
    -
    
    59 54
     SD = 0
    
    60 55
     SD_POS = 1
    
    61 56
     MAX_QUOTE_LEVEL = 20
    
    ... ... @@ -97,11 +92,6 @@ class MailAddress(BaseHyperlink):
    97 92
         name: str = field(default='mailadr', init=False)
    
    98 93
     
    
    99 94
     
    
    100
    -@dataclass
    
    101
    -class Emoji(StyleObject):
    
    102
    -    name: str = field(default='emoji', init=False)
    
    103
    -
    
    104
    -
    
    105 95
     @dataclass
    
    106 96
     class Block(StyleObject):
    
    107 97
     
    
    ... ... @@ -117,7 +107,6 @@ class PlainBlock(Block):
    117 107
         name: str = field(default='plain', init=False)
    
    118 108
         spans: list[Span] = field(default_factory=list)
    
    119 109
         uris: list[BaseHyperlink] = field(default_factory=list)
    
    120
    -    emojis: list[Emoji] = field(default_factory=list)
    
    121 110
     
    
    122 111
         @classmethod
    
    123 112
         def from_quote_match(cls, match: Match[str]) -> PlainBlock:
    
    ... ... @@ -208,10 +197,6 @@ def process(text: Union[str, bytes], level: int = 0) -> ParsingResult:
    208 197
                 for line in block.text.splitlines(keepends=True):
    
    209 198
                     block.spans += _parse_line(line, offset, offset_bytes)
    
    210 199
                     block.uris += _parse_uris(line, offset, offset_bytes)
    
    211
    -                if sys.platform == 'darwin':
    
    212
    -                    # block.emojis is used for replacing emojis with Gtk.Images
    
    213
    -                    # Necessary for MessageTextview (darwin) only
    
    214
    -                    block.emojis += _parse_emojis(line, offset)
    
    215 200
     
    
    216 201
                     offset += len(line)
    
    217 202
                     offset_bytes += len(line.encode())
    
    ... ... @@ -361,22 +346,6 @@ def make(start: int, end: int, is_jid: bool) -> Optional[BaseHyperlink]:
    361 346
         return uris
    
    362 347
     
    
    363 348
     
    
    364
    -def _parse_emojis(line: str, offset: int) -> list[Emoji]:
    
    365
    -    emojis: list[Emoji] = []
    
    366
    -
    
    367
    -    def make(match: Match[str]) -> Emoji:
    
    368
    -        return _make_emoji(line,
    
    369
    -                           match.start(),
    
    370
    -                           match.end() - 1,
    
    371
    -                           offset)
    
    372
    -
    
    373
    -    for match in EMOJI_RX.finditer(line):
    
    374
    -        emoji = make(match)
    
    375
    -        emojis.append(emoji)
    
    376
    -
    
    377
    -    return emojis
    
    378
    -
    
    379
    -
    
    380 349
     def _handle_pre_span(line: str,
    
    381 350
                          index: int,
    
    382 351
                          offset: int,
    
    ... ... @@ -464,18 +433,6 @@ def _make_hyperlink(line: str,
    464 433
                     text=text)
    
    465 434
     
    
    466 435
     
    
    467
    -def _make_emoji(line: str,
    
    468
    -                start: int,
    
    469
    -                end: int,
    
    470
    -                offset: int) -> Emoji:
    
    471
    -    text = line[start:end + 1]
    
    472
    -    start += offset
    
    473
    -    end += offset + 1
    
    474
    -    return Emoji(start=start,
    
    475
    -                 end=end,
    
    476
    -                 text=text)
    
    477
    -
    
    478
    -
    
    479 436
     def _is_span_empty(sd: str, index: int, stack: list[tuple[str, int]]) -> bool:
    
    480 437
         start_sd = stack[-1][SD]
    
    481 438
         if start_sd != sd:
    

  • gajim/data/emoticons/noto/LICENSE deleted
    1
    -                                 Apache License
    
    2
    -                           Version 2.0, January 2004
    
    3
    -                        http://www.apache.org/licenses/
    
    4
    -
    
    5
    -   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
    
    6
    -
    
    7
    -   1. Definitions.
    
    8
    -
    
    9
    -      "License" shall mean the terms and conditions for use, reproduction,
    
    10
    -      and distribution as defined by Sections 1 through 9 of this document.
    
    11
    -
    
    12
    -      "Licensor" shall mean the copyright owner or entity authorized by
    
    13
    -      the copyright owner that is granting the License.
    
    14
    -
    
    15
    -      "Legal Entity" shall mean the union of the acting entity and all
    
    16
    -      other entities that control, are controlled by, or are under common
    
    17
    -      control with that entity. For the purposes of this definition,
    
    18
    -      "control" means (i) the power, direct or indirect, to cause the
    
    19
    -      direction or management of such entity, whether by contract or
    
    20
    -      otherwise, or (ii) ownership of fifty percent (50%) or more of the
    
    21
    -      outstanding shares, or (iii) beneficial ownership of such entity.
    
    22
    -
    
    23
    -      "You" (or "Your") shall mean an individual or Legal Entity
    
    24
    -      exercising permissions granted by this License.
    
    25
    -
    
    26
    -      "Source" form shall mean the preferred form for making modifications,
    
    27
    -      including but not limited to software source code, documentation
    
    28
    -      source, and configuration files.
    
    29
    -
    
    30
    -      "Object" form shall mean any form resulting from mechanical
    
    31
    -      transformation or translation of a Source form, including but
    
    32
    -      not limited to compiled object code, generated documentation,
    
    33
    -      and conversions to other media types.
    
    34
    -
    
    35
    -      "Work" shall mean the work of authorship, whether in Source or
    
    36
    -      Object form, made available under the License, as indicated by a
    
    37
    -      copyright notice that is included in or attached to the work
    
    38
    -      (an example is provided in the Appendix below).
    
    39
    -
    
    40
    -      "Derivative Works" shall mean any work, whether in Source or Object
    
    41
    -      form, that is based on (or derived from) the Work and for which the
    
    42
    -      editorial revisions, annotations, elaborations, or other modifications
    
    43
    -      represent, as a whole, an original work of authorship. For the purposes
    
    44
    -      of this License, Derivative Works shall not include works that remain
    
    45
    -      separable from, or merely link (or bind by name) to the interfaces of,
    
    46
    -      the Work and Derivative Works thereof.
    
    47
    -
    
    48
    -      "Contribution" shall mean any work of authorship, including
    
    49
    -      the original version of the Work and any modifications or additions
    
    50
    -      to that Work or Derivative Works thereof, that is intentionally
    
    51
    -      submitted to Licensor for inclusion in the Work by the copyright owner
    
    52
    -      or by an individual or Legal Entity authorized to submit on behalf of
    
    53
    -      the copyright owner. For the purposes of this definition, "submitted"
    
    54
    -      means any form of electronic, verbal, or written communication sent
    
    55
    -      to the Licensor or its representatives, including but not limited to
    
    56
    -      communication on electronic mailing lists, source code control systems,
    
    57
    -      and issue tracking systems that are managed by, or on behalf of, the
    
    58
    -      Licensor for the purpose of discussing and improving the Work, but
    
    59
    -      excluding communication that is conspicuously marked or otherwise
    
    60
    -      designated in writing by the copyright owner as "Not a Contribution."
    
    61
    -
    
    62
    -      "Contributor" shall mean Licensor and any individual or Legal Entity
    
    63
    -      on behalf of whom a Contribution has been received by Licensor and
    
    64
    -      subsequently incorporated within the Work.
    
    65
    -
    
    66
    -   2. Grant of Copyright License. Subject to the terms and conditions of
    
    67
    -      this License, each Contributor hereby grants to You a perpetual,
    
    68
    -      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
    
    69
    -      copyright license to reproduce, prepare Derivative Works of,
    
    70
    -      publicly display, publicly perform, sublicense, and distribute the
    
    71
    -      Work and such Derivative Works in Source or Object form.
    
    72
    -
    
    73
    -   3. Grant of Patent License. Subject to the terms and conditions of
    
    74
    -      this License, each Contributor hereby grants to You a perpetual,
    
    75
    -      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
    
    76
    -      (except as stated in this section) patent license to make, have made,
    
    77
    -      use, offer to sell, sell, import, and otherwise transfer the Work,
    
    78
    -      where such license applies only to those patent claims licensable
    
    79
    -      by such Contributor that are necessarily infringed by their
    
    80
    -      Contribution(s) alone or by combination of their Contribution(s)
    
    81
    -      with the Work to which such Contribution(s) was submitted. If You
    
    82
    -      institute patent litigation against any entity (including a
    
    83
    -      cross-claim or counterclaim in a lawsuit) alleging that the Work
    
    84
    -      or a Contribution incorporated within the Work constitutes direct
    
    85
    -      or contributory patent infringement, then any patent licenses
    
    86
    -      granted to You under this License for that Work shall terminate
    
    87
    -      as of the date such litigation is filed.
    
    88
    -
    
    89
    -   4. Redistribution. You may reproduce and distribute copies of the
    
    90
    -      Work or Derivative Works thereof in any medium, with or without
    
    91
    -      modifications, and in Source or Object form, provided that You
    
    92
    -      meet the following conditions:
    
    93
    -
    
    94
    -      (a) You must give any other recipients of the Work or
    
    95
    -          Derivative Works a copy of this License; and
    
    96
    -
    
    97
    -      (b) You must cause any modified files to carry prominent notices
    
    98
    -          stating that You changed the files; and
    
    99
    -
    
    100
    -      (c) You must retain, in the Source form of any Derivative Works
    
    101
    -          that You distribute, all copyright, patent, trademark, and
    
    102
    -          attribution notices from the Source form of the Work,
    
    103
    -          excluding those notices that do not pertain to any part of
    
    104
    -          the Derivative Works; and
    
    105
    -
    
    106
    -      (d) If the Work includes a "NOTICE" text file as part of its
    
    107
    -          distribution, then any Derivative Works that You distribute must
    
    108
    -          include a readable copy of the attribution notices contained
    
    109
    -          within such NOTICE file, excluding those notices that do not
    
    110
    -          pertain to any part of the Derivative Works, in at least one
    
    111
    -          of the following places: within a NOTICE text file distributed
    
    112
    -          as part of the Derivative Works; within the Source form or
    
    113
    -          documentation, if provided along with the Derivative Works; or,
    
    114
    -          within a display generated by the Derivative Works, if and
    
    115
    -          wherever such third-party notices normally appear. The contents
    
    116
    -          of the NOTICE file are for informational purposes only and
    
    117
    -          do not modify the License. You may add Your own attribution
    
    118
    -          notices within Derivative Works that You distribute, alongside
    
    119
    -          or as an addendum to the NOTICE text from the Work, provided
    
    120
    -          that such additional attribution notices cannot be construed
    
    121
    -          as modifying the License.
    
    122
    -
    
    123
    -      You may add Your own copyright statement to Your modifications and
    
    124
    -      may provide additional or different license terms and conditions
    
    125
    -      for use, reproduction, or distribution of Your modifications, or
    
    126
    -      for any such Derivative Works as a whole, provided Your use,
    
    127
    -      reproduction, and distribution of the Work otherwise complies with
    
    128
    -      the conditions stated in this License.
    
    129
    -
    
    130
    -   5. Submission of Contributions. Unless You explicitly state otherwise,
    
    131
    -      any Contribution intentionally submitted for inclusion in the Work
    
    132
    -      by You to the Licensor shall be under the terms and conditions of
    
    133
    -      this License, without any additional terms or conditions.
    
    134
    -      Notwithstanding the above, nothing herein shall supersede or modify
    
    135
    -      the terms of any separate license agreement you may have executed
    
    136
    -      with Licensor regarding such Contributions.
    
    137
    -
    
    138
    -   6. Trademarks. This License does not grant permission to use the trade
    
    139
    -      names, trademarks, service marks, or product names of the Licensor,
    
    140
    -      except as required for reasonable and customary use in describing the
    
    141
    -      origin of the Work and reproducing the content of the NOTICE file.
    
    142
    -
    
    143
    -   7. Disclaimer of Warranty. Unless required by applicable law or
    
    144
    -      agreed to in writing, Licensor provides the Work (and each
    
    145
    -      Contributor provides its Contributions) on an "AS IS" BASIS,
    
    146
    -      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
    
    147
    -      implied, including, without limitation, any warranties or conditions
    
    148
    -      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
    
    149
    -      PARTICULAR PURPOSE. You are solely responsible for determining the
    
    150
    -      appropriateness of using or redistributing the Work and assume any
    
    151
    -      risks associated with Your exercise of permissions under this License.
    
    152
    -
    
    153
    -   8. Limitation of Liability. In no event and under no legal theory,
    
    154
    -      whether in tort (including negligence), contract, or otherwise,
    
    155
    -      unless required by applicable law (such as deliberate and grossly
    
    156
    -      negligent acts) or agreed to in writing, shall any Contributor be
    
    157
    -      liable to You for damages, including any direct, indirect, special,
    
    158
    -      incidental, or consequential damages of any character arising as a
    
    159
    -      result of this License or out of the use or inability to use the
    
    160
    -      Work (including but not limited to damages for loss of goodwill,
    
    161
    -      work stoppage, computer failure or malfunction, or any and all
    
    162
    -      other commercial damages or losses), even if such Contributor
    
    163
    -      has been advised of the possibility of such damages.
    
    164
    -
    
    165
    -   9. Accepting Warranty or Additional Liability. While redistributing
    
    166
    -      the Work or Derivative Works thereof, You may choose to offer,
    
    167
    -      and charge a fee for, acceptance of support, warranty, indemnity,
    
    168
    -      or other liability obligations and/or rights consistent with this
    
    169
    -      License. However, in accepting such obligations, You may act only
    
    170
    -      on Your own behalf and on Your sole responsibility, not on behalf
    
    171
    -      of any other Contributor, and only if You agree to indemnify,
    
    172
    -      defend, and hold each Contributor harmless for any liability
    
    173
    -      incurred by, or claims asserted against, such Contributor by reason
    
    174
    -      of your accepting any such warranty or additional liability.
    
    175
    -
    
    176
    -   END OF TERMS AND CONDITIONS
    
    177
    -
    
    178
    -   APPENDIX: How to apply the Apache License to your work.
    
    179
    -
    
    180
    -      To apply the Apache License to your work, attach the following
    
    181
    -      boilerplate notice, with the fields enclosed by brackets "[]"
    
    182
    -      replaced with your own identifying information. (Don't include
    
    183
    -      the brackets!)  The text should be enclosed in the appropriate
    
    184
    -      comment syntax for the file format. We also recommend that a
    
    185
    -      file or class name and description of purpose be included on the
    
    186
    -      same "printed page" as the copyright notice for easier
    
    187
    -      identification within third-party archives.
    
    188
    -
    
    189
    -   Copyright [yyyy] [name of copyright owner]
    
    190
    -
    
    191
    -   Licensed under the Apache License, Version 2.0 (the "License");
    
    192
    -   you may not use this file except in compliance with the License.
    
    193
    -   You may obtain a copy of the License at
    
    194
    -
    
    195
    -       http://www.apache.org/licenses/LICENSE-2.0
    
    196
    -
    
    197
    -   Unless required by applicable law or agreed to in writing, software
    
    198
    -   distributed under the License is distributed on an "AS IS" BASIS,
    
    199
    -   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    
    200
    -   See the License for the specific language governing permissions and
    
    201
    -   limitations under the License.

  • gajim/data/emoticons/noto/noto.png deleted
    No preview for this file type
  • gajim/data/emoticons/twemoji/LICENSE deleted
    1
    -Attribution 4.0 International
    
    2
    -
    
    3
    -=======================================================================
    
    4
    -
    
    5
    -Creative Commons Corporation ("Creative Commons") is not a law firm and
    
    6
    -does not provide legal services or legal advice. Distribution of
    
    7
    -Creative Commons public licenses does not create a lawyer-client or
    
    8
    -other relationship. Creative Commons makes its licenses and related
    
    9
    -information available on an "as-is" basis. Creative Commons gives no
    
    10
    -warranties regarding its licenses, any material licensed under their
    
    11
    -terms and conditions, or any related information. Creative Commons
    
    12
    -disclaims all liability for damages resulting from their use to the
    
    13
    -fullest extent possible.
    
    14
    -
    
    15
    -Using Creative Commons Public Licenses
    
    16
    -
    
    17
    -Creative Commons public licenses provide a standard set of terms and
    
    18
    -conditions that creators and other rights holders may use to share
    
    19
    -original works of authorship and other material subject to copyright
    
    20
    -and certain other rights specified in the public license below. The
    
    21
    -following considerations are for informational purposes only, are not
    
    22
    -exhaustive, and do not form part of our licenses.
    
    23
    -
    
    24
    -     Considerations for licensors: Our public licenses are
    
    25
    -     intended for use by those authorized to give the public
    
    26
    -     permission to use material in ways otherwise restricted by
    
    27
    -     copyright and certain other rights. Our licenses are
    
    28
    -     irrevocable. Licensors should read and understand the terms
    
    29
    -     and conditions of the license they choose before applying it.
    
    30
    -     Licensors should also secure all rights necessary before
    
    31
    -     applying our licenses so that the public can reuse the
    
    32
    -     material as expected. Licensors should clearly mark any
    
    33
    -     material not subject to the license. This includes other CC-
    
    34
    -     licensed material, or material used under an exception or
    
    35
    -     limitation to copyright. More considerations for licensors:
    
    36
    -    wiki.creativecommons.org/Considerations_for_licensors
    
    37
    -
    
    38
    -     Considerations for the public: By using one of our public
    
    39
    -     licenses, a licensor grants the public permission to use the
    
    40
    -     licensed material under specified terms and conditions. If
    
    41
    -     the licensor's permission is not necessary for any reason--for
    
    42
    -     example, because of any applicable exception or limitation to
    
    43
    -     copyright--then that use is not regulated by the license. Our
    
    44
    -     licenses grant only permissions under copyright and certain
    
    45
    -     other rights that a licensor has authority to grant. Use of
    
    46
    -     the licensed material may still be restricted for other
    
    47
    -     reasons, including because others have copyright or other
    
    48
    -     rights in the material. A licensor may make special requests,
    
    49
    -     such as asking that all changes be marked or described.
    
    50
    -     Although not required by our licenses, you are encouraged to
    
    51
    -     respect those requests where reasonable. More_considerations
    
    52
    -     for the public: 
    
    53
    -    wiki.creativecommons.org/Considerations_for_licensees
    
    54
    -
    
    55
    -=======================================================================
    
    56
    -
    
    57
    -Creative Commons Attribution 4.0 International Public License
    
    58
    -
    
    59
    -By exercising the Licensed Rights (defined below), You accept and agree
    
    60
    -to be bound by the terms and conditions of this Creative Commons
    
    61
    -Attribution 4.0 International Public License ("Public License"). To the
    
    62
    -extent this Public License may be interpreted as a contract, You are
    
    63
    -granted the Licensed Rights in consideration of Your acceptance of
    
    64
    -these terms and conditions, and the Licensor grants You such rights in
    
    65
    -consideration of benefits the Licensor receives from making the
    
    66
    -Licensed Material available under these terms and conditions.
    
    67
    -
    
    68
    -
    
    69
    -Section 1 -- Definitions.
    
    70
    -
    
    71
    -  a. Adapted Material means material subject to Copyright and Similar
    
    72
    -     Rights that is derived from or based upon the Licensed Material
    
    73
    -     and in which the Licensed Material is translated, altered,
    
    74
    -     arranged, transformed, or otherwise modified in a manner requiring
    
    75
    -     permission under the Copyright and Similar Rights held by the
    
    76
    -     Licensor. For purposes of this Public License, where the Licensed
    
    77
    -     Material is a musical work, performance, or sound recording,
    
    78
    -     Adapted Material is always produced where the Licensed Material is
    
    79
    -     synched in timed relation with a moving image.
    
    80
    -
    
    81
    -  b. Adapter's License means the license You apply to Your Copyright
    
    82
    -     and Similar Rights in Your contributions to Adapted Material in
    
    83
    -     accordance with the terms and conditions of this Public License.
    
    84
    -
    
    85
    -  c. Copyright and Similar Rights means copyright and/or similar rights
    
    86
    -     closely related to copyright including, without limitation,
    
    87
    -     performance, broadcast, sound recording, and Sui Generis Database
    
    88
    -     Rights, without regard to how the rights are labeled or
    
    89
    -     categorized. For purposes of this Public License, the rights
    
    90
    -     specified in Section 2(b)(1)-(2) are not Copyright and Similar
    
    91
    -     Rights.
    
    92
    -
    
    93
    -  d. Effective Technological Measures means those measures that, in the
    
    94
    -     absence of proper authority, may not be circumvented under laws
    
    95
    -     fulfilling obligations under Article 11 of the WIPO Copyright
    
    96
    -     Treaty adopted on December 20, 1996, and/or similar international
    
    97
    -     agreements.
    
    98
    -
    
    99
    -  e. Exceptions and Limitations means fair use, fair dealing, and/or
    
    100
    -     any other exception or limitation to Copyright and Similar Rights
    
    101
    -     that applies to Your use of the Licensed Material.
    
    102
    -
    
    103
    -  f. Licensed Material means the artistic or literary work, database,
    
    104
    -     or other material to which the Licensor applied this Public
    
    105
    -     License.
    
    106
    -
    
    107
    -  g. Licensed Rights means the rights granted to You subject to the
    
    108
    -     terms and conditions of this Public License, which are limited to
    
    109
    -     all Copyright and Similar Rights that apply to Your use of the
    
    110
    -     Licensed Material and that the Licensor has authority to license.
    
    111
    -
    
    112
    -  h. Licensor means the individual(s) or entity(ies) granting rights
    
    113
    -     under this Public License.
    
    114
    -
    
    115
    -  i. Share means to provide material to the public by any means or
    
    116
    -     process that requires permission under the Licensed Rights, such
    
    117
    -     as reproduction, public display, public performance, distribution,
    
    118
    -     dissemination, communication, or importation, and to make material
    
    119
    -     available to the public including in ways that members of the
    
    120
    -     public may access the material from a place and at a time
    
    121
    -     individually chosen by them.
    
    122
    -
    
    123
    -  j. Sui Generis Database Rights means rights other than copyright
    
    124
    -     resulting from Directive 96/9/EC of the European Parliament and of
    
    125
    -     the Council of 11 March 1996 on the legal protection of databases,
    
    126
    -     as amended and/or succeeded, as well as other essentially
    
    127
    -     equivalent rights anywhere in the world.
    
    128
    -
    
    129
    -  k. You means the individual or entity exercising the Licensed Rights
    
    130
    -     under this Public License. Your has a corresponding meaning.
    
    131
    -
    
    132
    -
    
    133
    -Section 2 -- Scope.
    
    134
    -
    
    135
    -  a. License grant.
    
    136
    -
    
    137
    -       1. Subject to the terms and conditions of this Public License,
    
    138
    -          the Licensor hereby grants You a worldwide, royalty-free,
    
    139
    -          non-sublicensable, non-exclusive, irrevocable license to
    
    140
    -          exercise the Licensed Rights in the Licensed Material to:
    
    141
    -
    
    142
    -            a. reproduce and Share the Licensed Material, in whole or
    
    143
    -               in part; and
    
    144
    -
    
    145
    -            b. produce, reproduce, and Share Adapted Material.
    
    146
    -
    
    147
    -       2. Exceptions and Limitations. For the avoidance of doubt, where
    
    148
    -          Exceptions and Limitations apply to Your use, this Public
    
    149
    -          License does not apply, and You do not need to comply with
    
    150
    -          its terms and conditions.
    
    151
    -
    
    152
    -       3. Term. The term of this Public License is specified in Section
    
    153
    -          6(a).
    
    154
    -
    
    155
    -       4. Media and formats; technical modifications allowed. The
    
    156
    -          Licensor authorizes You to exercise the Licensed Rights in
    
    157
    -          all media and formats whether now known or hereafter created,
    
    158
    -          and to make technical modifications necessary to do so. The
    
    159
    -          Licensor waives and/or agrees not to assert any right or
    
    160
    -          authority to forbid You from making technical modifications
    
    161
    -          necessary to exercise the Licensed Rights, including
    
    162
    -          technical modifications necessary to circumvent Effective
    
    163
    -          Technological Measures. For purposes of this Public License,
    
    164
    -          simply making modifications authorized by this Section 2(a)
    
    165
    -          (4) never produces Adapted Material.
    
    166
    -
    
    167
    -       5. Downstream recipients.
    
    168
    -
    
    169
    -            a. Offer from the Licensor -- Licensed Material. Every
    
    170
    -               recipient of the Licensed Material automatically
    
    171
    -               receives an offer from the Licensor to exercise the
    
    172
    -               Licensed Rights under the terms and conditions of this
    
    173
    -               Public License.
    
    174
    -
    
    175
    -            b. No downstream restrictions. You may not offer or impose
    
    176
    -               any additional or different terms or conditions on, or
    
    177
    -               apply any Effective Technological Measures to, the
    
    178
    -               Licensed Material if doing so restricts exercise of the
    
    179
    -               Licensed Rights by any recipient of the Licensed
    
    180
    -               Material.
    
    181
    -
    
    182
    -       6. No endorsement. Nothing in this Public License constitutes or
    
    183
    -          may be construed as permission to assert or imply that You
    
    184
    -          are, or that Your use of the Licensed Material is, connected
    
    185
    -          with, or sponsored, endorsed, or granted official status by,
    
    186
    -          the Licensor or others designated to receive attribution as
    
    187
    -          provided in Section 3(a)(1)(A)(i).
    
    188
    -
    
    189
    -  b. Other rights.
    
    190
    -
    
    191
    -       1. Moral rights, such as the right of integrity, are not
    
    192
    -          licensed under this Public License, nor are publicity,
    
    193
    -          privacy, and/or other similar personality rights; however, to
    
    194
    -          the extent possible, the Licensor waives and/or agrees not to
    
    195
    -          assert any such rights held by the Licensor to the limited
    
    196
    -          extent necessary to allow You to exercise the Licensed
    
    197
    -          Rights, but not otherwise.
    
    198
    -
    
    199
    -       2. Patent and trademark rights are not licensed under this
    
    200
    -          Public License.
    
    201
    -
    
    202
    -       3. To the extent possible, the Licensor waives any right to
    
    203
    -          collect royalties from You for the exercise of the Licensed
    
    204
    -          Rights, whether directly or through a collecting society
    
    205
    -          under any voluntary or waivable statutory or compulsory
    
    206
    -          licensing scheme. In all other cases the Licensor expressly
    
    207
    -          reserves any right to collect such royalties.
    
    208
    -
    
    209
    -
    
    210
    -Section 3 -- License Conditions.
    
    211
    -
    
    212
    -Your exercise of the Licensed Rights is expressly made subject to the
    
    213
    -following conditions.
    
    214
    -
    
    215
    -  a. Attribution.
    
    216
    -
    
    217
    -       1. If You Share the Licensed Material (including in modified
    
    218
    -          form), You must:
    
    219
    -
    
    220
    -            a. retain the following if it is supplied by the Licensor
    
    221
    -               with the Licensed Material:
    
    222
    -
    
    223
    -                 i. identification of the creator(s) of the Licensed
    
    224
    -                    Material and any others designated to receive
    
    225
    -                    attribution, in any reasonable manner requested by
    
    226
    -                    the Licensor (including by pseudonym if
    
    227
    -                    designated);
    
    228
    -
    
    229
    -                ii. a copyright notice;
    
    230
    -
    
    231
    -               iii. a notice that refers to this Public License;
    
    232
    -
    
    233
    -                iv. a notice that refers to the disclaimer of
    
    234
    -                    warranties;
    
    235
    -
    
    236
    -                 v. a URI or hyperlink to the Licensed Material to the
    
    237
    -                    extent reasonably practicable;
    
    238
    -
    
    239
    -            b. indicate if You modified the Licensed Material and
    
    240
    -               retain an indication of any previous modifications; and
    
    241
    -
    
    242
    -            c. indicate the Licensed Material is licensed under this
    
    243
    -               Public License, and include the text of, or the URI or
    
    244
    -               hyperlink to, this Public License.
    
    245
    -
    
    246
    -       2. You may satisfy the conditions in Section 3(a)(1) in any
    
    247
    -          reasonable manner based on the medium, means, and context in
    
    248
    -          which You Share the Licensed Material. For example, it may be
    
    249
    -          reasonable to satisfy the conditions by providing a URI or
    
    250
    -          hyperlink to a resource that includes the required
    
    251
    -          information.
    
    252
    -
    
    253
    -       3. If requested by the Licensor, You must remove any of the
    
    254
    -          information required by Section 3(a)(1)(A) to the extent
    
    255
    -          reasonably practicable.
    
    256
    -
    
    257
    -       4. If You Share Adapted Material You produce, the Adapter's
    
    258
    -          License You apply must not prevent recipients of the Adapted
    
    259
    -          Material from complying with this Public License.
    
    260
    -
    
    261
    -
    
    262
    -Section 4 -- Sui Generis Database Rights.
    
    263
    -
    
    264
    -Where the Licensed Rights include Sui Generis Database Rights that
    
    265
    -apply to Your use of the Licensed Material:
    
    266
    -
    
    267
    -  a. for the avoidance of doubt, Section 2(a)(1) grants You the right
    
    268
    -     to extract, reuse, reproduce, and Share all or a substantial
    
    269
    -     portion of the contents of the database;
    
    270
    -
    
    271
    -  b. if You include all or a substantial portion of the database
    
    272
    -     contents in a database in which You have Sui Generis Database
    
    273
    -     Rights, then the database in which You have Sui Generis Database
    
    274
    -     Rights (but not its individual contents) is Adapted Material; and
    
    275
    -
    
    276
    -  c. You must comply with the conditions in Section 3(a) if You Share
    
    277
    -     all or a substantial portion of the contents of the database.
    
    278
    -
    
    279
    -For the avoidance of doubt, this Section 4 supplements and does not
    
    280
    -replace Your obligations under this Public License where the Licensed
    
    281
    -Rights include other Copyright and Similar Rights.
    
    282
    -
    
    283
    -
    
    284
    -Section 5 -- Disclaimer of Warranties and Limitation of Liability.
    
    285
    -
    
    286
    -  a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
    
    287
    -     EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
    
    288
    -     AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
    
    289
    -     ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
    
    290
    -     IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
    
    291
    -     WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
    
    292
    -     PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
    
    293
    -     ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
    
    294
    -     KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
    
    295
    -     ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
    
    296
    -
    
    297
    -  b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
    
    298
    -     TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
    
    299
    -     NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
    
    300
    -     INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
    
    301
    -     COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
    
    302
    -     USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
    
    303
    -     ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
    
    304
    -     DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
    
    305
    -     IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
    
    306
    -
    
    307
    -  c. The disclaimer of warranties and limitation of liability provided
    
    308
    -     above shall be interpreted in a manner that, to the extent
    
    309
    -     possible, most closely approximates an absolute disclaimer and
    
    310
    -     waiver of all liability.
    
    311
    -
    
    312
    -
    
    313
    -Section 6 -- Term and Termination.
    
    314
    -
    
    315
    -  a. This Public License applies for the term of the Copyright and
    
    316
    -     Similar Rights licensed here. However, if You fail to comply with
    
    317
    -     this Public License, then Your rights under this Public License
    
    318
    -     terminate automatically.
    
    319
    -
    
    320
    -  b. Where Your right to use the Licensed Material has terminated under
    
    321
    -     Section 6(a), it reinstates:
    
    322
    -
    
    323
    -       1. automatically as of the date the violation is cured, provided
    
    324
    -          it is cured within 30 days of Your discovery of the
    
    325
    -          violation; or
    
    326
    -
    
    327
    -       2. upon express reinstatement by the Licensor.
    
    328
    -
    
    329
    -     For the avoidance of doubt, this Section 6(b) does not affect any
    
    330
    -     right the Licensor may have to seek remedies for Your violations
    
    331
    -     of this Public License.
    
    332
    -
    
    333
    -  c. For the avoidance of doubt, the Licensor may also offer the
    
    334
    -     Licensed Material under separate terms or conditions or stop
    
    335
    -     distributing the Licensed Material at any time; however, doing so
    
    336
    -     will not terminate this Public License.
    
    337
    -
    
    338
    -  d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
    
    339
    -     License.
    
    340
    -
    
    341
    -
    
    342
    -Section 7 -- Other Terms and Conditions.
    
    343
    -
    
    344
    -  a. The Licensor shall not be bound by any additional or different
    
    345
    -     terms or conditions communicated by You unless expressly agreed.
    
    346
    -
    
    347
    -  b. Any arrangements, understandings, or agreements regarding the
    
    348
    -     Licensed Material not stated herein are separate from and
    
    349
    -     independent of the terms and conditions of this Public License.
    
    350
    -
    
    351
    -
    
    352
    -Section 8 -- Interpretation.
    
    353
    -
    
    354
    -  a. For the avoidance of doubt, this Public License does not, and
    
    355
    -     shall not be interpreted to, reduce, limit, restrict, or impose
    
    356
    -     conditions on any use of the Licensed Material that could lawfully
    
    357
    -     be made without permission under this Public License.
    
    358
    -
    
    359
    -  b. To the extent possible, if any provision of this Public License is
    
    360
    -     deemed unenforceable, it shall be automatically reformed to the
    
    361
    -     minimum extent necessary to make it enforceable. If the provision
    
    362
    -     cannot be reformed, it shall be severed from this Public License
    
    363
    -     without affecting the enforceability of the remaining terms and
    
    364
    -     conditions.
    
    365
    -
    
    366
    -  c. No term or condition of this Public License will be waived and no
    
    367
    -     failure to comply consented to unless expressly agreed to by the
    
    368
    -     Licensor.
    
    369
    -
    
    370
    -  d. Nothing in this Public License constitutes or may be interpreted
    
    371
    -     as a limitation upon, or waiver of, any privileges and immunities
    
    372
    -     that apply to the Licensor or You, including from the legal
    
    373
    -     processes of any jurisdiction or authority.
    
    374
    -
    
    375
    -
    
    376
    -=======================================================================
    
    377
    -
    
    378
    -Creative Commons is not a party to its public licenses.
    
    379
    -Notwithstanding, Creative Commons may elect to apply one of its public
    
    380
    -licenses to material it publishes and in those instances will be
    
    381
    -considered the "Licensor." Except for the limited purpose of indicating
    
    382
    -that material is shared under a Creative Commons public license or as
    
    383
    -otherwise permitted by the Creative Commons policies published at
    
    384
    -creativecommons.org/policies, Creative Commons does not authorize the
    
    385
    -use of the trademark "Creative Commons" or any other trademark or logo
    
    386
    -of Creative Commons without its prior written consent including,
    
    387
    -without limitation, in connection with any unauthorized modifications
    
    388
    -to any of its public licenses or any other arrangements,
    
    389
    -understandings, or agreements concerning use of licensed material. For
    
    390
    -the avoidance of doubt, this paragraph does not form part of the public
    
    391
    -licenses.
    
    392
    -
    
    393
    -Creative Commons may be contacted at creativecommons.org.
    \ No newline at end of file

  • gajim/data/emoticons/twemoji/twemoji.png deleted
    No preview for this file type
  • gajim/data/gui/message_actions_box.ui
    ... ... @@ -143,6 +143,7 @@
    143 143
             <property name="can-focus">True</property>
    
    144 144
             <property name="receives-default">True</property>
    
    145 145
             <property name="tooltip-text" translatable="yes">Show a list of emojis</property>
    
    146
    +        <property name="action-name">win.show-emoji-chooser</property>
    
    146 147
             <property name="relief">none</property>
    
    147 148
             <child>
    
    148 149
               <object class="GtkImage">
    

  • gajim/data/gui/preferences.ui
    ... ... @@ -688,57 +688,7 @@
    688 688
                           </packing>
    
    689 689
                         </child>
    
    690 690
                         <child>
    
    691
    -                      <!-- n-columns=3 n-rows=3 -->
    
    692
    -                      <object class="GtkGrid" id="emoji">
    
    693
    -                        <property name="visible">True</property>
    
    694
    -                        <property name="can-focus">False</property>
    
    695
    -                        <property name="orientation">vertical</property>
    
    696
    -                        <property name="row-spacing">12</property>
    
    697
    -                        <child>
    
    698
    -                          <object class="GtkLabel">
    
    699
    -                            <property name="visible">True</property>
    
    700
    -                            <property name="can-focus">False</property>
    
    701
    -                            <property name="label" translatable="yes">Emoji</property>
    
    702
    -                            <property name="xalign">0</property>
    
    703
    -                            <style>
    
    704
    -                              <class name="bold"/>
    
    705
    -                            </style>
    
    706
    -                          </object>
    
    707
    -                          <packing>
    
    708
    -                            <property name="left-attach">0</property>
    
    709
    -                            <property name="top-attach">0</property>
    
    710
    -                          </packing>
    
    711
    -                        </child>
    
    712
    -                        <child>
    
    713
    -                          <placeholder/>
    
    714
    -                        </child>
    
    715
    -                        <child>
    
    716
    -                          <placeholder/>
    
    717
    -                        </child>
    
    718
    -                        <child>
    
    719
    -                          <placeholder/>
    
    720
    -                        </child>
    
    721
    -                        <child>
    
    722
    -                          <placeholder/>
    
    723
    -                        </child>
    
    724
    -                        <child>
    
    725
    -                          <placeholder/>
    
    726
    -                        </child>
    
    727
    -                        <child>
    
    728
    -                          <placeholder/>
    
    729
    -                        </child>
    
    730
    -                        <child>
    
    731
    -                          <placeholder/>
    
    732
    -                        </child>
    
    733
    -                        <child>
    
    734
    -                          <placeholder/>
    
    735
    -                        </child>
    
    736
    -                      </object>
    
    737
    -                      <packing>
    
    738
    -                        <property name="expand">False</property>
    
    739
    -                        <property name="fill">True</property>
    
    740
    -                        <property name="position">1</property>
    
    741
    -                      </packing>
    
    691
    +                      <placeholder/>
    
    742 692
                         </child>
    
    743 693
                       </object>
    
    744 694
                     </child>
    

  • gajim/data/style/gajim.css
    ... ... @@ -748,18 +748,6 @@ #NotificationPopupTitle {
    748 748
         font-weight: bold;
    
    749 749
     }
    
    750 750
     
    
    751
    -/* Emoticon Popover (ModifierChooser) */
    
    752
    -popover#EmoticonPopover button { background: none; border: none; box-shadow:none; padding: 0px;}
    
    753
    -popover#EmoticonPopover button > label { font-size: 2.0rem; }
    
    754
    -popover#EmoticonPopover flowboxchild > label { font-size: 2.0rem; }
    
    755
    -popover#EmoticonPopover flowboxchild { padding-top: 5px; padding-bottom: 5px; }
    
    756
    -popover#EmoticonPopover scrolledwindow { border: none; }
    
    757
    -popover#EmoticonPopover { padding: 5px; background-color: @theme_unfocused_base_color; }
    
    758
    -
    
    759
    -.emoji-chooser-heading { font-size: 1.15rem; font-weight: bold; padding: 5px;}
    
    760
    -.emoji-chooser-flowbox { padding-left: 5px; padding-right: 11px; }
    
    761
    -.emoji-modifier-chooser-flowbox { padding-left: 5px; }
    
    762
    -
    
    763 751
     /* Settings widgets ======================================================== */
    
    764 752
     
    
    765 753
     /* SettingsBox */
    

  • gajim/gtk/application.py
    ... ... @@ -244,12 +244,6 @@ def _startup(self) -> None:
    244 244
             idle.Monitor.set_interval(app.settings.get('autoawaytime') * 60,
    
    245 245
                                       app.settings.get('autoxatime') * 60)
    
    246 246
     
    
    247
    -        if sys.platform == 'darwin':
    
    248
    -            # TODO: Remove if colored emoji rendering works well on
    
    249
    -            # Windows and MacOS
    
    250
    -            from gajim.gui.emoji_chooser import emoji_chooser
    
    251
    -            emoji_chooser.load()
    
    252
    -
    
    253 247
             from gajim.gui_interface import Interface
    
    254 248
     
    
    255 249
             self.interface = Interface()
    

  • gajim/gtk/chat_stack.py
    ... ... @@ -712,7 +712,6 @@ def _on_function_message(self,
    712 712
             self._chat_control.add_info_message(message)
    
    713 713
     
    
    714 714
         def _on_send_message(self) -> None:
    
    715
    -        self._message_action_box.msg_textview.replace_emojis()
    
    716 715
             message = self._message_action_box.msg_textview.get_text()
    
    717 716
             if message.startswith('//'):
    
    718 717
                 # Escape sequence for chat commands
    

  • gajim/gtk/conversation/plain_widget.py
    ... ... @@ -14,32 +14,19 @@
    14 14
     
    
    15 15
     from __future__ import annotations
    
    16 16
     
    
    17
    -from typing import Any
    
    18
    -
    
    19 17
     import logging
    
    20
    -import sys
    
    21 18
     
    
    22 19
     from gi.repository import Gtk
    
    23 20
     from gi.repository import Pango
    
    24 21
     from gi.repository import Gdk
    
    25
    -from gi.repository import GdkPixbuf
    
    26 22
     from gi.repository import GLib
    
    27
    -from gi.repository import GObject
    
    28 23
     
    
    29
    -from gajim.common import app
    
    30
    -from gajim.common.const import StyleAttr
    
    31 24
     from gajim.common.helpers import open_uri
    
    32
    -from gajim.common.helpers import parse_uri
    
    33
    -from gajim.common.structs import URI
    
    34 25
     from gajim.common.styling import BaseHyperlink
    
    35 26
     from gajim.common.styling import PlainBlock
    
    36 27
     from gajim.common.styling import process_uris
    
    37 28
     
    
    38 29
     from ..menus import get_conv_action_context_menu
    
    39
    -from ..menus import get_conv_uri_context_menu
    
    40
    -from ..emoji_data import emoji_pixbufs
    
    41
    -from ..emoji_data import get_emoji_pixbuf
    
    42
    -from ..util import get_cursor
    
    43 30
     from ..util import make_pango_attributes
    
    44 31
     
    
    45 32
     log = logging.getLogger('gajim.gui.conversaion.plain_widget')
    
    ... ... @@ -55,22 +42,11 @@ def __init__(self, account: str, selectable: bool) -> None:
    55 42
     
    
    56 43
             self._account = account
    
    57 44
     
    
    58
    -        # We use a Gtk.Textview on MacOS, since there is no support
    
    59
    -        # for rendering color fonts (Emojis) on MacOS yet, see:
    
    60
    -        # https://gitlab.freedesktop.org/cairo/cairo/-/merge_requests/289
    
    61
    -        # https://gitlab.freedesktop.org/cairo/cairo/-/merge_requests/9
    
    62
    -        if sys.platform == 'darwin':
    
    63
    -            if app.settings.get('dev_use_message_label'):
    
    64
    -                self._text_widget = MessageLabel(self._account, selectable)
    
    65
    -            else:
    
    66
    -                self._text_widget = MessageTextview(self._account)
    
    67
    -        else:
    
    68
    -            self._text_widget = MessageLabel(self._account, selectable)
    
    45
    +        self._text_widget = MessageLabel(self._account, selectable)
    
    69 46
             self.add(self._text_widget)
    
    70 47
     
    
    71 48
         def set_selectable(self, selectable: bool) -> None:
    
    72
    -        if isinstance(self._text_widget, MessageLabel):
    
    73
    -            self._text_widget.set_selectable(selectable)
    
    49
    +        self._text_widget.set_selectable(selectable)
    
    74 50
     
    
    75 51
         def add_content(self, block: PlainBlock) -> None:
    
    76 52
             self._text_widget.print_text_with_styling(block)
    
    ... ... @@ -152,295 +128,3 @@ def _on_focus_out(widget: MessageLabel,
    152 128
                           _event: Gdk.EventFocus
    
    153 129
                           ) -> None:
    
    154 130
             widget.get_style_context().add_class('transparent-selection')
    155
    -
    
    156
    -
    
    157
    -class MessageTextview(Gtk.TextView):
    
    158
    -    def __init__(self, account: str) -> None:
    
    159
    -        Gtk.TextView.__init__(self)
    
    160
    -        self.set_hexpand(True)
    
    161
    -        self.set_margin_start(0)
    
    162
    -        self.set_margin_end(0)
    
    163
    -        self.set_border_width(0)
    
    164
    -        self.set_left_margin(0)
    
    165
    -        self.set_right_margin(0)
    
    166
    -        self.set_has_tooltip(True)
    
    167
    -        self.set_editable(False)
    
    168
    -        self.set_cursor_visible(False)
    
    169
    -        self.set_wrap_mode(Gtk.WrapMode.WORD_CHAR)
    
    170
    -
    
    171
    -        self._handlers: dict[int, MessageTextview] = {}
    
    172
    -
    
    173
    -        id_ = self.connect('query-tooltip', self._query_tooltip)
    
    174
    -        self._handlers[id_] = self
    
    175
    -        id_ = self.connect('button-press-event', self._on_button_press)
    
    176
    -        self._handlers[id_] = self
    
    177
    -        id_ = self.connect('populate-popup', self._on_populate_popup)
    
    178
    -        self._handlers[id_] = self
    
    179
    -
    
    180
    -        self._account = account
    
    181
    -
    
    182
    -        # Used for changing the mouse pointer when hovering clickable URIs
    
    183
    -        self._cursor_changed: bool = False
    
    184
    -
    
    185
    -        # Keeps text selections for quoting and search actions
    
    186
    -        self._selected_text: str = ''
    
    187
    -
    
    188
    -        self.get_style_context().add_class('gajim-conversation-text')
    
    189
    -
    
    190
    -        # Create Tags
    
    191
    -        self._create_url_tags()
    
    192
    -        self.get_buffer().create_tag('strong', weight=Pango.Weight.BOLD)
    
    193
    -        self.get_buffer().create_tag('emphasis', style=Pango.Style.ITALIC)
    
    194
    -        self.get_buffer().create_tag('strike', strikethrough=True)
    
    195
    -        self.get_buffer().create_tag('pre', family='monospace')
    
    196
    -
    
    197
    -        self.connect('destroy', self._on_destroy)
    
    198
    -
    
    199
    -    def _on_destroy(self, *args: Any) -> None:
    
    200
    -        for id_, widget in self._handlers.items():
    
    201
    -            if widget.handler_is_connected(id_):
    
    202
    -                widget.disconnect(id_)
    
    203
    -        self._handlers.clear()
    
    204
    -
    
    205
    -    def _create_url_tags(self) -> None:
    
    206
    -        color = app.css_config.get_value('.gajim-url', StyleAttr.COLOR)
    
    207
    -        for name in URI_TAGS:
    
    208
    -            tag = self.get_buffer().create_tag(name,
    
    209
    -                                               foreground=color,
    
    210
    -                                               underline=Pango.Underline.SINGLE)
    
    211
    -            tag.connect('event', self._on_uri_clicked, tag)
    
    212
    -
    
    213
    -    def clear(self) -> None:
    
    214
    -        buffer_ = self.get_buffer()
    
    215
    -        start, end = buffer_.get_bounds()
    
    216
    -        buffer_.delete(start, end)
    
    217
    -
    
    218
    -    def get_text(self) -> str:
    
    219
    -        buffer_ = self.get_buffer()
    
    220
    -        start, end = buffer_.get_bounds()
    
    221
    -        return buffer_.get_text(start, end, False)
    
    222
    -
    
    223
    -    def print_text_with_styling(self, block: PlainBlock) -> None:
    
    224
    -        buffer_ = self.get_buffer()
    
    225
    -        buffer_.insert(buffer_.get_start_iter(), block.text.strip())
    
    226
    -
    
    227
    -        if len(self.get_text()) > 10000:
    
    228
    -            # Limit message styling processing
    
    229
    -            return
    
    230
    -
    
    231
    -        for span in block.spans:
    
    232
    -            start_iter = buffer_.get_iter_at_offset(span.start)
    
    233
    -            end_iter = buffer_.get_iter_at_offset(span.end)
    
    234
    -            buffer_.apply_tag_by_name(span.name, start_iter, end_iter)
    
    235
    -
    
    236
    -        for uri in block.uris:
    
    237
    -            start_iter = buffer_.get_iter_at_offset(uri.start)
    
    238
    -            end_iter = buffer_.get_iter_at_offset(uri.end)
    
    239
    -            buffer_.apply_tag_by_name(uri.name, start_iter, end_iter)
    
    240
    -
    
    241
    -        for emoji in block.emojis:
    
    242
    -            start_iter = buffer_.get_iter_at_offset(emoji.start)
    
    243
    -            end_iter = buffer_.get_iter_at_offset(emoji.end)
    
    244
    -            if emoji_pixbufs.complete:
    
    245
    -                # Only search for pixbuf if loading is completed
    
    246
    -                pixbuf = get_emoji_pixbuf(emoji.text)
    
    247
    -                if pixbuf is None:
    
    248
    -                    buffer_.insert(end_iter, emoji.text)
    
    249
    -                else:
    
    250
    -                    pixbuf = pixbuf.copy()
    
    251
    -                    anchor = buffer_.create_child_anchor(end_iter)
    
    252
    -                    anchor.plaintext = emoji.text  # type: ignore
    
    253
    -                    img = Gtk.Image.new_from_pixbuf(pixbuf)
    
    254
    -                    img.show()
    
    255
    -                    self.add_child_at_anchor(img, anchor)
    
    256
    -                    buffer_.delete(
    
    257
    -                        buffer_.get_iter_at_offset(emoji.start),
    
    258
    -                        buffer_.get_iter_at_offset(emoji.end))
    
    259
    -            else:
    
    260
    -                # Set marks and save them so we can replace emojis
    
    261
    -                # once loading is complete
    
    262
    -                start_mark = buffer_.create_mark(None, end_iter, True)
    
    263
    -                buffer_.insert(end_iter, emoji.text)
    
    264
    -                end_mark = buffer_.create_mark(None, end_iter, True)
    
    265
    -                emoji_pixbufs.append_marks(
    
    266
    -                    self, start_mark, end_mark, emoji.text)
    
    267
    -
    
    268
    -    def replace_emoji(self,
    
    269
    -                      start_mark: Gtk.TextMark,
    
    270
    -                      end_mark: Gtk.TextMark,
    
    271
    -                      pixbuf: GdkPixbuf.Pixbuf,
    
    272
    -                      codepoint: str
    
    273
    -                      ) -> None:
    
    274
    -        buffer_ = self.get_buffer()
    
    275
    -        start_iter = buffer_.get_iter_at_mark(start_mark)
    
    276
    -        end_iter = buffer_.get_iter_at_mark(end_mark)
    
    277
    -        buffer_.delete(start_iter, end_iter)
    
    278
    -
    
    279
    -        anchor = buffer_.create_child_anchor(start_iter)
    
    280
    -        anchor.plaintext = codepoint  # type: ignore
    
    281
    -        img = Gtk.Image.new_from_pixbuf(pixbuf)
    
    282
    -        img.show()
    
    283
    -        self.add_child_at_anchor(img, anchor)
    
    284
    -        buffer_.delete_mark(start_mark)
    
    285
    -        buffer_.delete_mark(end_mark)
    
    286
    -
    
    287
    -    def add_action_phrase(self, text: str, nickname: str) -> None:
    
    288
    -        text = text.replace('/me', f'* {nickname}', 1)
    
    289
    -
    
    290
    -        buffer_ = self.get_buffer()
    
    291
    -        buffer_.insert(buffer_.get_start_iter(), text.strip())
    
    292
    -
    
    293
    -        uris = process_uris(text)
    
    294
    -        for uri in uris:
    
    295
    -            start_iter = buffer_.get_iter_at_offset(uri.start)
    
    296
    -            end_iter = buffer_.get_iter_at_offset(uri.end)
    
    297
    -            buffer_.apply_tag_by_name(uri.name, start_iter, end_iter)
    
    298
    -
    
    299
    -        start_iter = buffer_.get_start_iter()
    
    300
    -        end_iter = buffer_.get_end_iter()
    
    301
    -        buffer_.apply_tag_by_name('emphasis', start_iter, end_iter)
    
    302
    -
    
    303
    -    def _query_tooltip(self,
    
    304
    -                       widget: Gtk.TextView,
    
    305
    -                       x_pos: int,
    
    306
    -                       y_pos: int,
    
    307
    -                       _keyboard_mode: bool,
    
    308
    -                       _tooltip: Gtk.Tooltip
    
    309
    -                       ) -> bool:
    
    310
    -
    
    311
    -        window = widget.get_window(Gtk.TextWindowType.TEXT)
    
    312
    -        assert window is not None
    
    313
    -        x_pos, y_pos = self.window_to_buffer_coords(
    
    314
    -            Gtk.TextWindowType.TEXT, x_pos, y_pos)
    
    315
    -
    
    316
    -        iter_ = self.get_iter_at_position(x_pos, y_pos)[1]
    
    317
    -        for tag in iter_.get_tags():
    
    318
    -            tag_name = tag.get_property('name')
    
    319
    -            if tag_name in URI_TAGS:
    
    320
    -                window.set_cursor(get_cursor('pointer'))
    
    321
    -                self._cursor_changed = True
    
    322
    -                return False
    
    323
    -
    
    324
    -        if self._cursor_changed:
    
    325
    -            window.set_cursor(get_cursor('text'))
    
    326
    -            self._cursor_changed = False
    
    327
    -        return False
    
    328
    -
    
    329
    -    def _on_button_press(self, _widget: Any, event: Gdk.EventButton) -> bool:
    
    330
    -        '''
    
    331
    -        We don’t open the standard context menu when receiving
    
    332
    -        a click on tagged text.
    
    333
    -        If it’s untagged text, check if something is selected
    
    334
    -        '''
    
    335
    -        self._selected_text = ''
    
    336
    -
    
    337
    -        if event.button != 3:
    
    338
    -            # If it’s not a right click
    
    339
    -            return False
    
    340
    -
    
    341
    -        x_pos, y_pos = self.window_to_buffer_coords(
    
    342
    -            Gtk.TextWindowType.TEXT,
    
    343
    -            int(event.x),
    
    344
    -            int(event.y))
    
    345
    -        _, iter_ = self.get_iter_at_location(x_pos, y_pos)
    
    346
    -        tags = iter_.get_tags()
    
    347
    -
    
    348
    -        if tags:
    
    349
    -            # A tagged text fragment has been clicked
    
    350
    -            for tag in tags:
    
    351
    -                if tag.get_property('name') in URI_TAGS:
    
    352
    -                    # Block regular context menu
    
    353
    -                    return True
    
    354
    -
    
    355
    -        # Check if there is a selection and make it available for
    
    356
    -        # _on_populate_popup
    
    357
    -        buffer_ = self.get_buffer()
    
    358
    -        return_val = buffer_.get_selection_bounds()
    
    359
    -        if return_val:
    
    360
    -            # Something has been selected, get the text
    
    361
    -            start_sel, finish_sel = return_val[0], return_val[1]
    
    362
    -            self._selected_text = buffer_.get_text(
    
    363
    -                start_sel, finish_sel, True)
    
    364
    -        elif iter_.get_char() and ord(iter_.get_char()) > 31:
    
    365
    -            # Clicked on a word, take whole word for selection
    
    366
    -            start_sel = iter_.copy()
    
    367
    -            if not start_sel.starts_word():
    
    368
    -                start_sel.backward_word_start()
    
    369
    -            finish_sel = iter_.copy()
    
    370
    -            if not finish_sel.ends_word():
    
    371
    -                finish_sel.forward_word_end()
    
    372
    -            self._selected_text = buffer_.get_text(
    
    373
    -                start_sel, finish_sel, True)
    
    374
    -        return False
    
    375
    -
    
    376
    -    def _on_populate_popup(self,
    
    377
    -                           _textview: Gtk.TextView,
    
    378
    -                           menu: Gtk.Menu
    
    379
    -                           ) -> None:
    
    380
    -        '''
    
    381
    -        Overrides the default context menu.
    
    382
    -        If text is selected, a submenu with actions on the selection is added.
    
    383
    -        (see _on_button_press)
    
    384
    -        '''
    
    385
    -        if not self._selected_text:
    
    386
    -            menu.show_all()
    
    387
    -            return
    
    388
    -
    
    389
    -        action_menu_item = get_conv_action_context_menu(
    
    390
    -            self._account, self._selected_text)
    
    391
    -        menu.prepend(action_menu_item)
    
    392
    -        menu.show_all()
    
    393
    -
    
    394
    -    def _on_uri_clicked(self,
    
    395
    -                        texttag: Gtk.TextTag,
    
    396
    -                        _widget: Any,
    
    397
    -                        event: Gdk.Event,
    
    398
    -                        iter_: Gtk.TextIter,
    
    399
    -                        _kind: Gtk.TextTag
    
    400
    -                        ) -> int:
    
    401
    -        if event.type != Gdk.EventType.BUTTON_PRESS:
    
    402
    -            return Gdk.EVENT_PROPAGATE
    
    403
    -
    
    404
    -        begin_iter = iter_.copy()
    
    405
    -        # we get the beginning of the tag
    
    406
    -        while not begin_iter.starts_tag(texttag):
    
    407
    -            begin_iter.backward_char()
    
    408
    -        end_iter = iter_.copy()
    
    409
    -        # we get the end of the tag
    
    410
    -        while not end_iter.ends_tag(texttag):
    
    411
    -            end_iter.forward_char()
    
    412
    -
    
    413
    -        # Detect XHTML-IM link
    
    414
    -        word = getattr(texttag, 'href', None)
    
    415
    -        if not word:
    
    416
    -            word = self.get_buffer().get_text(begin_iter, end_iter, True)
    
    417
    -
    
    418
    -        uri = parse_uri(word)
    
    419
    -        if event.button.button == 3:  # right click
    
    420
    -            self._show_uri_context_menu(uri)
    
    421
    -            return Gdk.EVENT_STOP
    
    422
    -
    
    423
    -        # TODO:
    
    424
    -        # self.plugin_modified = False
    
    425
    -        # app.plugin_manager.extension_point(
    
    426
    -        #     'hyperlink_handler', uri, self, self.get_toplevel())
    
    427
    -        # if self.plugin_modified:
    
    428
    -        #     return Gdk.EVENT_STOP
    
    429
    -
    
    430
    -        open_uri(uri, account=self._account)
    
    431
    -        return Gdk.EVENT_STOP
    
    432
    -
    
    433
    -    def _show_uri_context_menu(self, uri: URI) -> None:
    
    434
    -        menu = get_conv_uri_context_menu(self._account, uri)
    
    435
    -        if menu is None:
    
    436
    -            log.warning('No handler for URI type: %s', uri)
    
    437
    -            return
    
    438
    -
    
    439
    -        def _destroy(menu: Gtk.Menu, _pspec: GObject.ParamSpec) -> None:
    
    440
    -            visible = menu.get_property('visible')
    
    441
    -            if not visible:
    
    442
    -                GLib.idle_add(menu.destroy)
    
    443
    -
    
    444
    -        menu.attach_to_widget(self, None)
    
    445
    -        menu.connect('notify::visible', _destroy)
    
    446
    -        menu.popup_at_pointer()

  • gajim/gtk/emoji_chooser.py deleted
    1
    -# This file is part of Gajim.
    
    2
    -#
    
    3
    -# Gajim is free software; you can redistribute it and/or modify
    
    4
    -# it under the terms of the GNU General Public License as published
    
    5
    -# by the Free Software Foundation; version 3 only.
    
    6
    -#
    
    7
    -# Gajim is distributed in the hope that it will be useful,
    
    8
    -# but WITHOUT ANY WARRANTY; without even the implied warranty of
    
    9
    -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    
    10
    -# GNU General Public License for more details.
    
    11
    -#
    
    12
    -# You should have received a copy of the GNU General Public License
    
    13
    -# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
    
    14
    -
    
    15
    -import logging
    
    16
    -import weakref
    
    17
    -from collections import OrderedDict
    
    18
    -
    
    19
    -from gi.repository import Gtk
    
    20
    -from gi.repository import GLib
    
    21
    -from gi.repository import GdkPixbuf
    
    22
    -from gi.repository import Pango
    
    23
    -
    
    24
    -from gajim.common import app
    
    25
    -from gajim.common import helpers
    
    26
    -from gajim.common import configpaths
    
    27
    -
    
    28
    -from .builder import get_builder
    
    29
    -from .emoji_data import emoji_data
    
    30
    -from .emoji_data import emoji_pixbufs
    
    31
    -from .emoji_data import Emoji
    
    32
    -
    
    33
    -MODIFIER_MAX_CHILDREN_PER_LINE = 6
    
    34
    -MAX_CHILDREN_PER_LINE = 10
    
    35
    -
    
    36
    -log = logging.getLogger('gajim.emoji')
    
    37
    -
    
    38
    -
    
    39
    -class Section(Gtk.Box):
    
    40
    -    def __init__(self, name, search_entry, press_cb, chooser):
    
    41
    -        Gtk.Box.__init__(self, orientation=Gtk.Orientation.VERTICAL)
    
    42
    -        self._chooser = chooser
    
    43
    -        self._press_cb = press_cb
    
    44
    -        self.pixbuf_generator = None
    
    45
    -        self.heading = Gtk.Label(label=name)
    
    46
    -        self.heading.set_halign(Gtk.Align.START)
    
    47
    -        self.heading.get_style_context().add_class('emoji-chooser-heading')
    
    48
    -        self.add(self.heading)
    
    49
    -
    
    50
    -        self.flowbox = Gtk.FlowBox()
    
    51
    -        self.flowbox.get_style_context().add_class('emoji-chooser-flowbox')
    
    52
    -        self.flowbox.set_max_children_per_line(MAX_CHILDREN_PER_LINE)
    
    53
    -        self.flowbox.set_filter_func(self._filter_func, search_entry)
    
    54
    -        self.flowbox.connect('child-activated', press_cb)
    
    55
    -
    
    56
    -        self.add(self.flowbox)
    
    57
    -        self.show_all()
    
    58
    -
    
    59
    -    def _filter_func(self, child, search_entry):
    
    60
    -        name = search_entry.get_text()
    
    61
    -        if not name:
    
    62
    -            self.show()
    
    63
    -            return True
    
    64
    -
    
    65
    -        if name in child.desc:
    
    66
    -            self.show()
    
    67
    -            return True
    
    68
    -        return False
    
    69
    -
    
    70
    -    def add_emoji(self, codepoint, attrs):
    
    71
    -        # Return always True, this method is used for the emoji factory
    
    72
    -        # called by GLib.idle_add()
    
    73
    -        pixbuf = self._get_next_pixbuf()
    
    74
    -
    
    75
    -        variations = attrs.get('variations', None)
    
    76
    -        if variations is None:
    
    77
    -            if pixbuf is None:
    
    78
    -                return True
    
    79
    -            self.flowbox.add(EmojiChild(codepoint, pixbuf, attrs['desc']))
    
    80
    -            if pixbuf != 'font':
    
    81
    -                # We save the pixbuf for fast access if we need to
    
    82
    -                # replace a codepoint in the textview
    
    83
    -                emoji_pixbufs[codepoint] = pixbuf
    
    84
    -        else:
    
    85
    -            if pixbuf is not None:
    
    86
    -                chooser = ModifierChooser()
    
    87
    -
    
    88
    -                # Iterate over the variations and add the codepoints
    
    89
    -                for codepoint_ in variations.keys():
    
    90
    -                    pixbuf_ = self._get_next_pixbuf()
    
    91
    -                    if pixbuf_ is None:
    
    92
    -                        continue
    
    93
    -
    
    94
    -                    if pixbuf_ == 'font':
    
    95
    -                        if not self._chooser.font_supports_codepoint(
    
    96
    -                                codepoint_):
    
    97
    -                            continue
    
    98
    -                    else:
    
    99
    -                        emoji_pixbufs[codepoint_] = pixbuf_
    
    100
    -
    
    101
    -                    # Only codepoints are added which the
    
    102
    -                    # font or theme supports
    
    103
    -                    chooser.add_emoji(codepoint_, pixbuf_)
    
    104
    -
    
    105
    -                # Check if we successfully added codepoints with modifiers
    
    106
    -                if chooser.has_child:
    
    107
    -                    # If we have children then add a button
    
    108
    -                    # and set the popover
    
    109
    -                    child = EmojiModifierChild(
    
    110
    -                        codepoint, pixbuf, attrs['desc'])
    
    111
    -                    child.button.set_popover(chooser)
    
    112
    -                    chooser.flowbox.connect(
    
    113
    -                        'child-activated', self._press_cb)
    
    114
    -                else:
    
    115
    -                    # If no children were added, destroy the chooser
    
    116
    -                    # and add a EmojiChild instead of a EmojiModifierChild
    
    117
    -                    chooser.destroy()
    
    118
    -                    child = EmojiChild(codepoint, pixbuf, attrs['desc'])
    
    119
    -
    
    120
    -                if pixbuf != 'font':
    
    121
    -                    emoji_pixbufs[codepoint] = pixbuf
    
    122
    -
    
    123
    -                self.flowbox.add(child)
    
    124
    -            else:
    
    125
    -                # We don’t have a image for the base codepoint
    
    126
    -                # so skip all modifiers of it
    
    127
    -                for _entry in variations:
    
    128
    -                    pixbuf = self._get_next_pixbuf()
    
    129
    -        return True
    
    130
    -
    
    131
    -    def clear_emojis(self):
    
    132
    -        def _remove_emoji(emoji):
    
    133
    -            self.flowbox.remove(emoji)
    
    134
    -            emoji.destroy()
    
    135
    -        self.flowbox.foreach(_remove_emoji)
    
    136
    -
    
    137
    -    def _get_next_pixbuf(self):
    
    138
    -        if self.pixbuf_generator is None:
    
    139
    -            return 'font'
    
    140
    -        return next(self.pixbuf_generator, False)
    
    141
    -
    
    142
    -
    
    143
    -class EmojiChild(Gtk.FlowBoxChild):
    
    144
    -    def __init__(self, codepoint, pixbuf, desc):
    
    145
    -        Gtk.FlowBoxChild.__init__(self)
    
    146
    -        self.desc = desc
    
    147
    -        self.codepoint = codepoint
    
    148
    -        self.pixbuf = pixbuf
    
    149
    -        if pixbuf == 'font':
    
    150
    -            self.add(Gtk.Label(label=codepoint))
    
    151
    -        else:
    
    152
    -            self.add(Gtk.Image.new_from_pixbuf(pixbuf))
    
    153
    -        self.set_tooltip_text(desc)
    
    154
    -        self.show_all()
    
    155
    -
    
    156
    -    def get_emoji(self):
    
    157
    -        if self.pixbuf != 'font':
    
    158
    -            pixbuf = self.get_child().get_pixbuf()
    
    159
    -            pixbuf = pixbuf.scale_simple(Emoji.INPUT_SIZE,
    
    160
    -                                         Emoji.INPUT_SIZE,
    
    161
    -                                         GdkPixbuf.InterpType.HYPER)
    
    162
    -            return self.codepoint, pixbuf
    
    163
    -        return self.codepoint, None
    
    164
    -
    
    165
    -
    
    166
    -class EmojiModifierChild(Gtk.FlowBoxChild):
    
    167
    -    def __init__(self, codepoint, pixbuf, desc):
    
    168
    -        Gtk.FlowBoxChild.__init__(self)
    
    169
    -        self.desc = desc
    
    170
    -        self.codepoint = codepoint
    
    171
    -        self.pixbuf = pixbuf
    
    172
    -
    
    173
    -        self.button = Gtk.MenuButton()
    
    174
    -        self.button.set_relief(Gtk.ReliefStyle.NONE)
    
    175
    -        self.button.connect('button-press-event', self._button_press)
    
    176
    -
    
    177
    -        if pixbuf == 'font':
    
    178
    -            self.button.remove(self.button.get_child())
    
    179
    -            label = Gtk.Label(label=codepoint)
    
    180
    -            self.button.add(label)
    
    181
    -        else:
    
    182
    -            self.button.get_child().set_from_pixbuf(pixbuf)
    
    183
    -
    
    184
    -        self.set_tooltip_text(desc)
    
    185
    -        self.add(self.button)
    
    186
    -        self.show_all()
    
    187
    -
    
    188
    -    def _button_press(self, button, event):
    
    189
    -        if event.button == 3:
    
    190
    -            button.get_popover().show()
    
    191
    -            button.get_popover().get_child().unselect_all()
    
    192
    -            return True
    
    193
    -        if event.button == 1:
    
    194
    -            self.get_parent().emit('child-activated', self)
    
    195
    -            return True
    
    196
    -        return False
    
    197
    -
    
    198
    -    def get_emoji(self):
    
    199
    -        if self.pixbuf != 'font':
    
    200
    -            pixbuf = self.button.get_child().get_pixbuf()
    
    201
    -            pixbuf = pixbuf.scale_simple(Emoji.INPUT_SIZE,
    
    202
    -                                         Emoji.INPUT_SIZE,
    
    203
    -                                         GdkPixbuf.InterpType.HYPER)
    
    204
    -            return self.codepoint, pixbuf
    
    205
    -        return self.codepoint, None
    
    206
    -
    
    207
    -
    
    208
    -class ModifierChooser(Gtk.Popover):
    
    209
    -    def __init__(self):
    
    210
    -        Gtk.Popover.__init__(self)
    
    211
    -        self.set_name('EmoticonPopover')
    
    212
    -        self._has_child = False
    
    213
    -
    
    214
    -        self.flowbox = Gtk.FlowBox()
    
    215
    -        self.flowbox.get_style_context().add_class(
    
    216
    -            'emoji-modifier-chooser-flowbox')
    
    217
    -        self.flowbox.set_size_request(200, -1)
    
    218
    -        self.flowbox.set_max_children_per_line(MODIFIER_MAX_CHILDREN_PER_LINE)
    
    219
    -        self.flowbox.show()
    
    220
    -        self.add(self.flowbox)
    
    221
    -
    
    222
    -    @property
    
    223
    -    def has_child(self):
    
    224
    -        return self._has_child
    
    225
    -
    
    226
    -    def add_emoji(self, codepoint, pixbuf):
    
    227
    -        self.flowbox.add(EmojiChild(codepoint, pixbuf, None))
    
    228
    -        self._has_child = True
    
    229
    -
    
    230
    -
    
    231
    -class EmojiChooser(Gtk.Popover):
    
    232
    -
    
    233
    -    _section_names = [
    
    234
    -        'Smileys & People',
    
    235
    -        'Animals & Nature',
    
    236
    -        'Food & Drink',
    
    237
    -        'Travel & Places',
    
    238
    -        'Activities',
    
    239
    -        'Objects',
    
    240
    -        'Symbols',
    
    241
    -        'Flags'
    
    242
    -    ]
    
    243
    -
    
    244
    -    def __init__(self):
    
    245
    -        super().__init__()
    
    246
    -        self.set_name('EmoticonPopover')
    
    247
    -        self._text_widget = None
    
    248
    -        self._load_source_id = None
    
    249
    -        self._pango_layout = Pango.Layout(self.get_pango_context())
    
    250
    -
    
    251
    -        self._builder = get_builder('emoji_chooser.ui')
    
    252
    -        self._search = self._builder.get_object('search')
    
    253
    -        self._stack = self._builder.get_object('stack')
    
    254
    -
    
    255
    -        self._sections = OrderedDict()
    
    256
    -        for name in self._section_names:
    
    257
    -            self._sections[name] = Section(
    
    258
    -                name, self._search, self._on_emoticon_press, self)
    
    259
    -
    
    260
    -        section_box = self._builder.get_object('section_box')
    
    261
    -        for section in self._sections.values():
    
    262
    -            section_box.add(section)
    
    263
    -
    
    264
    -        self.add(self._builder.get_object('box'))
    
    265
    -
    
    266
    -        self.connect('key-press-event', self._key_press)
    
    267
    -        self._builder.connect_signals(self)
    
    268
    -
    
    269
    -    @property
    
    270
    -    def text_widget(self):
    
    271
    -        return self._text_widget
    
    272
    -
    
    273
    -    @text_widget.setter
    
    274
    -    def text_widget(self, value):
    
    275
    -        # Hold only a weak reference so if we can destroy
    
    276
    -        # the ChatControl
    
    277
    -        self._text_widget = weakref.ref(value)
    
    278
    -
    
    279
    -    def _key_press(self, _widget, event):
    
    280
    -        return self._search.handle_event(event)
    
    281
    -
    
    282
    -    def _search_changed(self, _entry):
    
    283
    -        for section in self._sections.values():
    
    284
    -            section.hide()
    
    285
    -            section.flowbox.invalidate_filter()
    
    286
    -        self._switch_stack()
    
    287
    -
    
    288
    -    def _clear_sections(self):
    
    289
    -        for section in self._sections.values():
    
    290
    -            section.clear_emojis()
    
    291
    -
    
    292
    -    def _switch_stack(self):
    
    293
    -        for section in self._sections.values():
    
    294
    -            if section.is_visible():
    
    295
    -                self._stack.set_visible_child_name('list')
    
    296
    -                return
    
    297
    -        self._stack.set_visible_child_name('not-found')
    
    298
    -
    
    299
    -    @staticmethod
    
    300
    -    def _get_current_theme():
    
    301
    -        theme = app.settings.get('emoticons_theme')
    
    302
    -        themes = helpers.get_available_emoticon_themes()
    
    303
    -        if theme not in themes:
    
    304
    -            app.settings.set('emoticons_theme', 'noto')
    
    305
    -            theme = 'noto'
    
    306
    -        return theme
    
    307
    -
    
    308
    -    @staticmethod
    
    309
    -    def _get_emoji_theme_path(theme):
    
    310
    -        if theme == 'font':
    
    311
    -            return 'font'
    
    312
    -
    
    313
    -        base_path = configpaths.get('EMOTICONS')
    
    314
    -        emoticons_data_path = base_path / theme / f'{theme}.png'
    
    315
    -        if emoticons_data_path.exists():
    
    316
    -            return emoticons_data_path
    
    317
    -
    
    318
    -        emoticons_user_path = configpaths.get('MY_EMOTS') / f'{theme}.png'
    
    319
    -        if emoticons_user_path.exists():
    
    320
    -            return emoticons_user_path
    
    321
    -
    
    322
    -        log.warning('Could not find emoji theme: %s', theme)
    
    323
    -        return None
    
    324
    -
    
    325
    -    def load(self):
    
    326
    -        theme = self._get_current_theme()
    
    327
    -        path = self._get_emoji_theme_path(theme)
    
    328
    -        if not theme or path is None:
    
    329
    -            self._clear_sections()
    
    330
    -            emoji_pixbufs.clear()
    
    331
    -            return
    
    332
    -
    
    333
    -        # Attach pixbuf generator
    
    334
    -        pixbuf_generator = None
    
    335
    -        if theme != 'font':
    
    336
    -            pixbuf_generator = self._get_next_pixbuf(path)
    
    337
    -        for section in self._sections.values():
    
    338
    -            section.pixbuf_generator = pixbuf_generator
    
    339
    -
    
    340
    -        if self._load_source_id is not None:
    
    341
    -            GLib.source_remove(self._load_source_id)
    
    342
    -
    
    343
    -        # When we change emoji theme
    
    344
    -        self._clear_sections()
    
    345
    -        emoji_pixbufs.clear()
    
    346
    -
    
    347
    -        factory = self._emoji_factory(theme == 'font')
    
    348
    -        self._load_source_id = GLib.idle_add(lambda: next(factory, False),
    
    349
    -                                             priority=GLib.PRIORITY_LOW)
    
    350
    -
    
    351
    -    def _emoji_factory(self, font):
    
    352
    -        for codepoint, attrs in emoji_data.items():
    
    353
    -            if not attrs['fully-qualified']:
    
    354
    -                # We don’t add these to the UI
    
    355
    -                continue
    
    356
    -
    
    357
    -            if font and not self.font_supports_codepoint(codepoint):
    
    358
    -                continue
    
    359
    -
    
    360
    -            section = self._sections[attrs['group']]
    
    361
    -            yield section.add_emoji(codepoint, attrs)
    
    362
    -        self._load_source_id = None
    
    363
    -        emoji_pixbufs.complete = True
    
    364
    -
    
    365
    -    def font_supports_codepoint(self, codepoint):
    
    366
    -        self._pango_layout.set_text(codepoint, -1)
    
    367
    -        if self._pango_layout.get_unknown_glyphs_count():
    
    368
    -            return False
    
    369
    -        if len(codepoint) > 1:
    
    370
    -            # The font supports each of the codepoints
    
    371
    -            # Check if the rendered glyph is more than one char
    
    372
    -            if self._pango_layout.get_size()[0] > 19000:
    
    373
    -                return False
    
    374
    -        return True
    
    375
    -
    
    376
    -    @staticmethod
    
    377
    -    def _get_next_pixbuf(path):
    
    378
    -        src_x = src_y = cur_column = 0
    
    379
    -        atlas = GdkPixbuf.Pixbuf.new_from_file(str(path))
    
    380
    -
    
    381
    -        while True:
    
    382
    -            src_x = cur_column * Emoji.PARSE_WIDTH
    
    383
    -            subpixbuf = atlas.new_subpixbuf(src_x, src_y,
    
    384
    -                                            Emoji.PARSE_WIDTH,
    
    385
    -                                            Emoji.PARSE_HEIGHT)
    
    386
    -
    
    387
    -            if list(subpixbuf.get_pixels())[0:4] == [0, 0, 0, 255]:
    
    388
    -                # top left corner is a black pixel means image is missing
    
    389
    -                subpixbuf = None
    
    390
    -
    
    391
    -            if cur_column == Emoji.PARSE_COLUMNS - 1:
    
    392
    -                src_y += Emoji.PARSE_WIDTH
    
    393
    -                cur_column = 0
    
    394
    -            else:
    
    395
    -                cur_column += 1
    
    396
    -
    
    397
    -            yield subpixbuf
    
    398
    -
    
    399
    -    def _on_emoticon_press(self, flowbox, child):
    
    400
    -        GLib.timeout_add(100, flowbox.unselect_child, child)
    
    401
    -        codepoint, pixbuf = child.get_emoji()
    
    402
    -        self._text_widget().insert_emoji(codepoint, pixbuf)
    
    403
    -        self._text_widget().grab_focus()
    
    404
    -
    
    405
    -    def do_destroy(self):
    
    406
    -        # Remove the references we hold to other objects
    
    407
    -        self._text_widget = None
    
    408
    -        # Never destroy, creating a new EmoticonPopover is expensive
    
    409
    -        return True
    
    410
    -
    
    411
    -
    
    412
    -emoji_chooser = EmojiChooser()

  • gajim/gtk/emoji_data.py deleted The diff for this file was not included because it is too large.
  • gajim/gtk/emoji_data.pyi deleted
    1
    -# This file is part of Gajim.
    
    2
    -#
    
    3
    -# Gajim is free software; you can redistribute it and/or modify
    
    4
    -# it under the terms of the GNU General Public License as published
    
    5
    -# by the Free Software Foundation; version 3 only.
    
    6
    -#
    
    7
    -# Gajim is distributed in the hope that it will be useful,
    
    8
    -# but WITHOUT ANY WARRANTY; without even the implied warranty of
    
    9
    -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    
    10
    -# GNU General Public License for more details.
    
    11
    -#
    
    12
    -# You should have received a copy of the GNU General Public License
    
    13
    -# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
    
    14
    -
    
    15
    -from enum import IntEnum
    
    16
    -from collections import OrderedDict
    
    17
    -
    
    18
    -from gi.repository import GdkPixbuf
    
    19
    -from gi.repository import Gtk
    
    20
    -
    
    21
    -class Emoji(IntEnum):
    
    22
    -    ...
    
    23
    -
    
    24
    -def is_emoji(codepoints: str) -> bool: ...
    
    25
    -def get_emoji_pixbuf(codepoints: str) -> GdkPixbuf.Pixbuf: ...
    
    26
    -
    
    27
    -class EmojiData(OrderedDict):
    
    28
    -    def get_regex(self) -> str: ...
    
    29
    -
    
    30
    -class EmojiPixbufs(dict):
    
    31
    -    @property
    
    32
    -    def complete(self) -> bool: ...
    
    33
    -    @complete.setter
    
    34
    -    def complete(self, value: bool) -> None: ...
    
    35
    -    def clear(self) -> None: ...
    
    36
    -    def append_marks(self,
    
    37
    -                     textview: Gtk.TextView,
    
    38
    -                     start: Gtk.TextMark,
    
    39
    -                     end: Gtk.TextMark,
    
    40
    -                     codepoint: str) -> None: ...
    
    41
    -
    
    42
    -emoji_pixbufs: EmojiPixbufs
    
    43
    -emoji_ascii_data: dict[str, str]
    
    44
    -emoji_data: EmojiData

  • gajim/gtk/message_actions_box.py
    ... ... @@ -18,7 +18,6 @@
    18 18
     from typing import Optional
    
    19 19
     
    
    20 20
     import os
    
    21
    -import sys
    
    22 21
     import tempfile
    
    23 22
     import logging
    
    24 23
     import uuid
    
    ... ... @@ -45,7 +44,6 @@
    45 44
     
    
    46 45
     from .builder import get_builder
    
    47 46
     from .dialogs import ErrorDialog
    
    48
    -from .emoji_chooser import emoji_chooser
    
    49 47
     from .menus import get_encryption_menu
    
    50 48
     from .menus import get_format_menu
    
    51 49
     from .menus import get_groupchat_menu
    
    ... ... @@ -98,8 +96,6 @@ def __init__(self) -> None:
    98 96
     
    
    99 97
             self._ui.quick_invite_button.set_action_name('win.muc-invite')
    
    100 98
     
    
    101
    -        self._init_emoticon_popover()
    
    102
    -
    
    103 99
             self.show_all()
    
    104 100
             self._ui.connect_signals(self)
    
    105 101
     
    
    ... ... @@ -157,7 +153,7 @@ def _on_action(self,
    157 153
                 self._on_format(action_name)
    
    158 154
     
    
    159 155
             elif action_name == 'show-emoji-chooser':
    
    160
    -            self._on_show_emoji_chooser()
    
    156
    +            self.msg_textview.emit('insert-emoji')
    
    161 157
     
    
    162 158
             elif action_name == 'quote':
    
    163 159
                 assert param
    
    ... ... @@ -389,31 +385,6 @@ def _set_settings_menu(self, contact: ChatContactT) -> None:
    389 385
                 menu = get_singlechat_menu(contact)
    
    390 386
             self._ui.settings_menu.set_menu_model(menu)
    
    391 387
     
    
    392
    -    def _init_emoticon_popover(self) -> None:
    
    393
    -        if not app.settings.get('emoticons_theme'):
    
    394
    -            return
    
    395
    -
    
    396
    -        if sys.platform == 'darwin':
    
    397
    -            emoji_chooser.text_widget = self.msg_textview
    
    398
    -            self._ui.emoticons_button.set_popover(emoji_chooser)
    
    399
    -            return
    
    400
    -
    
    401
    -        self._ui.emoticons_button.set_sensitive(True)
    
    402
    -        self._ui.emoticons_button.connect('clicked',
    
    403
    -                                          self._on_emoticon_button_clicked)
    
    404
    -
    
    405
    -    def toggle_emoticons(self) -> None:
    
    406
    -        if app.settings.get('emoticons_theme'):
    
    407
    -            self._ui.emoticons_button.set_no_show_all(False)
    
    408
    -            self._ui.emoticons_button.show()
    
    409
    -        else:
    
    410
    -            self._ui.emoticons_button.set_no_show_all(True)
    
    411
    -            self._ui.emoticons_button.hide()
    
    412
    -
    
    413
    -    def _on_emoticon_button_clicked(self, _widget: Gtk.Button) -> None:
    
    414
    -        self.msg_textview.emit('insert-emoji')
    
    415
    -        self._ui.emoticons_button.set_active(False)
    
    416
    -
    
    417 388
         def _on_format(self, name: str) -> None:
    
    418 389
             name = name.removeprefix('input-')
    
    419 390
             self.msg_textview.apply_formatting(name)
    
    ... ... @@ -421,14 +392,6 @@ def _on_format(self, name: str) -> None:
    421 392
         def _on_clear(self) -> None:
    
    422 393
             self.msg_textview.clear()
    
    423 394
     
    
    424
    -    def _on_show_emoji_chooser(self) -> None:
    
    425
    -        if sys.platform == 'darwin':
    
    426
    -            popover = self._ui.emoticons_button.get_popover()
    
    427
    -            assert popover
    
    428
    -            popover.show()
    
    429
    -        else:
    
    430
    -            self.msg_textview.emit('insert-emoji')
    
    431
    -
    
    432 395
         def _on_send_file_enabled_changed(self,
    
    433 396
                                           action: Gio.SimpleAction,
    
    434 397
                                           _param: GObject.ParamSpec) -> None:
    

  • gajim/gtk/message_input.py
    ... ... @@ -25,11 +25,9 @@
    25 25
     from collections import defaultdict
    
    26 26
     
    
    27 27
     import logging
    
    28
    -import sys
    
    29 28
     
    
    30 29
     from gi.repository import Gtk
    
    31 30
     from gi.repository import Gdk
    
    32
    -from gi.repository import GdkPixbuf
    
    33 31
     from gi.repository import GLib
    
    34 32
     from gi.repository import Pango
    
    35 33
     
    
    ... ... @@ -420,60 +418,6 @@ def apply_formatting(self, formatting: str) -> None:
    420 418
                 buf.get_iter_at_offset(start_offset),
    
    421 419
                 buf.get_iter_at_offset(end_offset + 2))
    
    422 420
     
    
    423
    -    def replace_emojis(self) -> None:
    
    424
    -        if sys.platform != 'darwin':
    
    425
    -            # TODO: Remove if colored emoji rendering works well on MacOS
    
    426
    -            return
    
    427
    -
    
    428
    -        theme = app.settings.get('emoticons_theme')
    
    429
    -        if not theme or theme == 'font':
    
    430
    -            return
    
    431
    -
    
    432
    -        def _replace(anchor: Gtk.TextChildAnchor) -> None:
    
    433
    -            if anchor is None:
    
    434
    -                return
    
    435
    -            image = anchor.get_widgets()[0]
    
    436
    -            if hasattr(image, 'codepoint'):
    
    437
    -                # found emoji
    
    438
    -                codepoint = getattr(image, 'codepoint')
    
    439
    -                self._replace_char_at_iter(iter_, codepoint)
    
    440
    -                image.destroy()
    
    441
    -
    
    442
    -        iter_ = self.get_buffer().get_start_iter()
    
    443
    -        _replace(iter_.get_child_anchor())
    
    444
    -
    
    445
    -        while iter_.forward_char():
    
    446
    -            _replace(iter_.get_child_anchor())
    
    447
    -
    
    448
    -    def _replace_char_at_iter(self,
    
    449
    -                              iter_: Gtk.TextIter,
    
    450
    -                              new_char: str
    
    451
    -                              ) -> None:
    
    452
    -        buf = self.get_buffer()
    
    453
    -        iter_2 = iter_.copy()
    
    454
    -        iter_2.forward_char()
    
    455
    -        buf.delete(iter_, iter_2)
    
    456
    -        buf.insert(iter_, new_char)
    
    457
    -
    
    458
    -    def insert_emoji(self, codepoint: str, pixbuf: GdkPixbuf.Pixbuf) -> None:
    
    459
    -        buf = self.get_buffer()
    
    460
    -        if buf.get_char_count():
    
    461
    -            # buffer contains text
    
    462
    -            buf.insert_at_cursor(' ')
    
    463
    -
    
    464
    -        insert_mark = buf.get_insert()
    
    465
    -        insert_iter = buf.get_iter_at_mark(insert_mark)
    
    466
    -
    
    467
    -        if pixbuf is None:
    
    468
    -            buf.insert(insert_iter, codepoint)
    
    469
    -        else:
    
    470
    -            anchor = buf.create_child_anchor(insert_iter)
    
    471
    -            image = Gtk.Image.new_from_pixbuf(pixbuf)
    
    472
    -            setattr(image, 'codepoint', codepoint)
    
    473
    -            image.show()
    
    474
    -            self.add_child_at_anchor(image, anchor)
    
    475
    -        buf.insert_at_cursor(' ')
    
    476
    -
    
    477 421
         def clear(self, *args: Any) -> None:
    
    478 422
             buf = self.get_buffer()
    
    479 423
             start, end = buf.get_bounds()
    

  • gajim/gtk/preferences.py
    ... ... @@ -26,7 +26,6 @@
    26 26
     
    
    27 27
     from gajim.common import app
    
    28 28
     from gajim.common import configpaths
    
    29
    -from gajim.common import helpers
    
    30 29
     from gajim.common.const import THRESHOLD_OPTIONS
    
    31 30
     from gajim.common.i18n import _
    
    32 31
     from gajim.common.helpers import open_file
    
    ... ... @@ -42,7 +41,6 @@
    42 41
     from .const import SettingType
    
    43 42
     from .dialogs import DialogButton
    
    44 43
     from .dialogs import ConfirmationDialog
    
    45
    -from .emoji_chooser import emoji_chooser
    
    46 44
     from .settings import PopoverSetting
    
    47 45
     from .settings import SettingsBox
    
    48 46
     from .settings import SettingsDialog
    
    ... ... @@ -81,8 +79,6 @@ def __init__(self) -> None:
    81 79
     
    
    82 80
             self.add(self._ui.grid)
    
    83 81
     
    
    84
    -        self._check_emoji_theme()
    
    85
    -
    
    86 82
             prefs: list[tuple[str, Type[PreferenceBox]]] = [
    
    87 83
                 ('window_behaviour', WindowBehaviour),
    
    88 84
                 ('plugins', Plugins),
    
    ... ... @@ -95,7 +91,6 @@ def __init__(self) -> None:
    95 91
                 ('status_message', StatusMessage),
    
    96 92
                 ('automatic_status', AutomaticStatus),
    
    97 93
                 ('themes', Themes),
    
    98
    -            ('emoji', Emoji),
    
    99 94
                 ('server', Server),
    
    100 95
                 ('audio', Audio),
    
    101 96
                 ('video', Video),
    
    ... ... @@ -117,10 +112,6 @@ def __init__(self) -> None:
    117 112
             self._ui.connect_signals(self)
    
    118 113
     
    
    119 114
             self.show_all()
    
    120
    -        if sys.platform != 'darwin':
    
    121
    -            # TODO: Remove if colored emoji rendering works well on
    
    122
    -            # Windows and MacOS
    
    123
    -            self._ui.emoji.hide()
    
    124 115
     
    
    125 116
         def get_ui(self):
    
    126 117
             return self._ui
    
    ... ... @@ -157,14 +148,6 @@ def update_proxy_list(self) -> None:
    157 148
             miscellaneous = cast(Miscellaneous, self._prefs['miscellaneous'])
    
    158 149
             miscellaneous.update_proxy_list()
    
    159 150
     
    
    160
    -    @staticmethod
    
    161
    -    def _check_emoji_theme() -> None:
    
    162
    -        # Ensure selected emoji theme is valid
    
    163
    -        emoji_themes = helpers.get_available_emoticon_themes()
    
    164
    -        settings_theme = app.settings.get('emoticons_theme')
    
    165
    -        if settings_theme not in emoji_themes:
    
    166
    -            app.settings.set('emoticons_theme', 'font')
    
    167
    -
    
    168 151
         def _on_destroy(self, _widget: Gtk.Widget) -> None:
    
    169 152
             self._prefs.clear()
    
    170 153
             app.check_finalize(self)
    
    ... ... @@ -704,42 +687,6 @@ def _on_dark_theme(value: str, *args: Any) -> None:
    704 687
             app.ged.raise_event(StyleChanged())
    
    705 688
     
    
    706 689
     
    
    707
    -class Emoji(PreferenceBox):
    
    708
    -    def __init__(self, *args: Any) -> None:
    
    709
    -        if sys.platform != 'darwin':
    
    710
    -            # TODO: Remove if colored emoji rendering works well on
    
    711
    -            # Windows and MacOS
    
    712
    -            PreferenceBox.__init__(self, [])
    
    713
    -            return
    
    714
    -
    
    715
    -        emoji_themes_items: list[str] = []
    
    716
    -        for theme in helpers.get_available_emoticon_themes():
    
    717
    -            emoji_themes_items.append(theme)
    
    718
    -
    
    719
    -        settings = [
    
    720
    -            Setting(SettingKind.POPOVER,
    
    721
    -                    _('Emoji Theme'),
    
    722
    -                    SettingType.CONFIG,
    
    723
    -                    'emoticons_theme',
    
    724
    -                    desc=_('Choose from various emoji styles'),
    
    725
    -                    props={'entries': emoji_themes_items},
    
    726
    -                    callback=self._on_emoticons_theme)
    
    727
    -        ]
    
    728
    -
    
    729
    -        PreferenceBox.__init__(self, settings)
    
    730
    -
    
    731
    -    def _on_emoticons_theme(self, *args: Any) -> None:
    
    732
    -        emoji_chooser.load()
    
    733
    -        self._toggle_emoticons()
    
    734
    -
    
    735
    -    @staticmethod
    
    736
    -    def _toggle_emoticons() -> None:
    
    737
    -        # TODO
    
    738
    -        # for ctrl in app.window.get_controls():
    
    739
    -        #     ctrl.toggle_emoticons()
    
    740
    -        pass
    
    741
    -
    
    742
    -
    
    743 690
     class Server(PreferenceBox):
    
    744 691
         def __init__(self, *args: Any) -> None:
    
    745 692
     
    

  • pyproject.toml
    ... ... @@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
    6 6
     
    
    7 7
     
    
    8 8
     [tool.codespell]
    
    9
    -skip = "*__pycache__*,gajim/gui,gajim/data/icons,gajim/data/sounds,gajim/data/emoticons"
    
    9
    +skip = "*__pycache__*,gajim/gui,gajim/data/icons,gajim/data/sounds"
    
    10 10
     ignore-words-list = "claus,pres,ser,trough"
    
    11 11
     
    
    12 12
     
    

  • setup.cfg
    ... ... @@ -49,8 +49,6 @@ install_requires =
    49 49
     
    
    50 50
     [options.package_data]
    
    51 51
     gajim =
    
    52
    -    data/emoticons/*/*.png
    
    53
    -    data/emoticons/*/LICENSE
    
    54 52
         data/gui/*.ui
    
    55 53
         data/icons/hicolor/*/*/*.png
    
    56 54
         data/icons/hicolor/*/*/*.svg