Skip to content

Commit a59da29

Browse files
committed
v0.5
1 parent f34cb49 commit a59da29

4 files changed

Lines changed: 113 additions & 95 deletions

File tree

README.md

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
# indicator-chars
2+
3+
Original author: Tobias Schlitt <toby@php.net>
4+
This fork: Cyrille37 <cyrille37@gmail.com>
5+
6+
App indicator to provide a menu with (potentially funny UTF-8) characters for simple copying them to clipboard (similar to original characters applet).
7+
8+
Create a file .indicator-chars in your home directory with lines of characters to be selectable.
9+
10+
## Install
11+
12+
- Checkout source code
13+
14+
- Create ~/.indicator-chars (from `conf-example.indicator-chars` file)
15+
- Each row corresponds to a set of chars
16+
- Optional submenu title prefix: `[title]`
17+
- remove any unused spaces
18+
- Make sure to use UTF-8 encoding
19+
- Put indicator-chars.py into `auto start`.
20+
21+
## Open issues
22+
23+
- could not find a solution for this error:
24+
```
25+
(indicator-chars.py:14354): Gdk-CRITICAL **: 10:45:20.374:
26+
gdk_window_thaw_toplevel_updates:
27+
assertion 'window->update_and_descendants_freeze_count > 0' failed
28+
```
29+
30+
# Changes
31+
32+
Cyrille37's fork:
33+
34+
2025-06-10
35+
36+
- reworked the parser with a single regex
37+
- removed non standard unicode chars
38+
- change readme from RST to Markdown
39+
40+
2021-01-25
41+
42+
- Python 3 and Gtk 3, tested on Ubuntu 21.10 with MATE desktop
43+
- `sudo apt-get install gir1.2-appindicator3`
44+
45+
2016-02-03
46+
47+
- Some changes to make indicator-chars works on Ubuntu 12.04LTS with Unity 2D
48+
- replace the custom icon with a theme icon name
49+
- add a char copy into Clipboard(selection="CLIPBOARD")
50+
- use env shebang to find the Python3 engine
51+
- add a configuration file example: "conf-example.indicator-chars"
52+
53+
## Notes
54+
55+
### Unicode / UTF-8
56+
57+
Some non standard chars are present at https://www.amp-what.com/unicode/search/
58+
59+
Some standard sources
60+
- https://unicodeplus.com
61+
- https://unicode-explorer.com
62+
63+
**Caractères originaux**
64+
65+
- La chaîne `s = 'a😞⚠️❓⁉️☠️🌈'` contient des **caractères mal formés** :
66+
- `😞` est en fait **`U+1F61E`** (Disappointed Face), le code l'interprète comme `U+1F61E` (ce qui est correct).
67+
- `⚠️` est en réalité **`U+26A0` (⚠) + `U+FE0F` (Variation Selector-16)**, ce qui n'est pas un emoji standard. Cela explique la présence de `U+FE0F` (VS16).
68+
- `` est **`U+2753`** (Black Question Mark Ornament), le code l'interprète comme `U+2753` (correct).
69+
- `⁉️` est **`U+2049` (Exclamation Question Mark) + `U+FE0F`** (VS16), ce qui n'est pas un emoji standard.
70+
- `☠️` est **`U+2620` (Skull and Bones) + `U+FE0F`** (VS16).
71+
- `🌈` est **`U+1F308`** (Rainbow), correct.
72+
73+
**Nettoyage et normalisation**
74+
75+
- Le nettoyage élimine les caractères de contrôle (comme `U+FE0F`), mais `U+FE0F` n'est pas une **catégorie Cc** (contrôle), il est de catégorie **Me** (Mark, Enclosing) ou **Sk** (Symbol, Modifier). Ainsi, il n'est **pas supprimé** par le nettoyage.
76+
- La normalisation `NFKC` ne supprime pas `U+FE0F`.
77+
78+
**Résultat final**
79+
80+
- La chaîne contient des **caractères non standard** comme `U+FE0F` (VS16).
81+
82+
**Solution**
83+
84+
Pour corriger le problème, vous devez :
85+
1. **Utiliser des emojis standard** (sans VS16).
86+
2. **Éviter les combinaisons non standard**.

README.rst

Lines changed: 0 additions & 63 deletions
This file was deleted.

conf-example.indicator-chars

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1+
’«»💌😩
12
[letters]ÀÇÈÉŒ
2-
[signs]’ ⋅«»”“×ø²¼½¾≠≤≥…™©®—¿
3+
[signs]’ ⋅«»”“×ø²¼½¾≠≤≥…™©®—¿
34
[arrows]↑←→⇕⇙⇓⇘⇒⇔⇐⇖⇑⇗
45
[ok]✅✗💌🦄🤟👌🤩😘😉😜😂🍺💐🌻🪻🍀🌈🐝🚀⭐✨
5-
[fail]😞😩😤⚠️⛔🚷❌❓☠️💣🙊⏳📢
6-
6+
[fail]😞😩😤⛔🚷❌❓💣☠🕱⏳📢

indicator-chars.py

Lines changed: 24 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -58,14 +58,13 @@
5858
from gi.repository import Gtk as gtk, Gdk, GLib, GObject, Gio as gio
5959

6060
APP_NAME = 'indicator-chars'
61-
APP_VERSION = '0.3'
61+
APP_VERSION = '0.4'
6262

6363
class IndicatorChars:
6464
CHARS_PATH = os.path.join(os.getenv('HOME'), '.indicator-chars')
6565
SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
6666

67-
submenu_title_pattern = re.compile(r'\[([^]]+)\] *')
68-
description_pattern = re.compile(r' *(\([^)]+\)) *')
67+
line_pattern = re.compile(r'^(\[(.*)\])?(.*)$')
6968

7069
def __init__(self):
7170
self.ind = appindicator.Indicator.new(
@@ -99,34 +98,30 @@ def update_menu(self, widget = None, data = None):
9998
menu = gtk.Menu()
10099

101100
for charLine in charDef:
102-
charLine = str(charLine).strip()
101+
charLine = charLine.strip()
103102
if charLine == '' :
104103
continue
105-
submenu_match = self.submenu_title_pattern.match(charLine)
106-
if submenu_match:
107-
submenu_title = submenu_match.group(1)
108-
# remove title part from remainder:
109-
charLine = charLine[submenu_match.end():]
110-
else:
111-
submenu_title = ''.join(
112-
self.description_pattern.split(charLine)[::2])
113-
parentItem = self.create_menu_item(submenu_title)
114-
subMenu = gtk.Menu()
115-
while charLine:
116-
char = charLine[0]
117-
charLine = charLine[1:]
118-
description_match = self.description_pattern.match(charLine)
119-
if description_match:
120-
item_title = char + ' ' + description_match.group(1)
121-
# remove description part from remainder:
122-
charLine = charLine[description_match.end():]
123-
else:
124-
item_title = char
125-
subItem = self.create_menu_item(item_title)
126-
subItem.connect("activate", self.on_char_click, char)
127-
subMenu.append(subItem)
128-
parentItem.set_submenu(subMenu)
129-
menu.append(parentItem)
104+
result = self.line_pattern.search(charLine)
105+
if not result :
106+
print('ERROR:','bad line format')
107+
continue
108+
if result.group(2) :
109+
#print('-> in a sub-menu')
110+
submenu_title = result.group(2)
111+
parentItem = self.create_menu_item(submenu_title)
112+
menu.append(parentItem)
113+
subMenu = gtk.Menu()
114+
parentItem.set_submenu(subMenu)
115+
for char in list(result.group(3)) :
116+
subItem = self.create_menu_item(char)
117+
subItem.connect("activate", self.on_char_click, char)
118+
subMenu.append(subItem)
119+
else :
120+
#print('-> in main-menu')
121+
for char in list(result.group(3)) :
122+
subMenu = self.create_menu_item(char)
123+
subMenu.connect("activate", self.on_char_click, char)
124+
menu.append(subMenu)
130125

131126
menu.append(gtk.SeparatorMenuItem())
132127
quit_item = self.create_menu_item('Quit')

0 commit comments

Comments
 (0)