@@ -18,169 +18,188 @@ Command="
1818 copyq triggerGlobalShortcut {COMMAND_NAME}
1919
2020 On Gnome, clipboard monitor is executed as X11 app using XWayland.
21+
22+ Links:
23+ - https://github.com/ReimuNotMoe/ydotool
24+ - https://github.com/emersion/grim
25+ - https://github.com/emersion/slurp
2126 */
2227
2328 function isSway() {
24- return env('SWAYSOCK').length != 0
29+ return env('SWAYSOCK').length != 0;
2530 }
2631
2732 function isHyprland() {
28- return env('HYPRLAND_CMD').length != 0
33+ return env('HYPRLAND_CMD').length != 0;
2934 }
3035
3136 function isKde() {
32- return env('XDG_CURRENT_DESKTOP') == 'KDE'
37+ return env('XDG_CURRENT_DESKTOP') == 'KDE';
3338 }
3439
3540 function isGnome() {
36- return str(env('XAUTHORITY')).includes('mutter-Xwayland')
41+ return str(env('XAUTHORITY')).includes('mutter-Xwayland');
3742 }
3843
3944 function run() {
40- const p = execute.apply(this, arguments)
45+ const p = execute.apply(this, arguments);
4146 if (!p) {
42- throw 'Failed to start ' + arguments[0]
47+ throw 'Failed to start ' + arguments[0];
4348 }
4449 if (p.exit_code !== 0) {
45- throw 'Failed command ' + arguments[0] + ': ' + str(p.stderr)
50+ throw 'Failed command ' + arguments[0] + ': ' + str(p.stderr);
4651 }
47- return p.stdout
52+ return p.stdout;
4853 }
4954
5055 function swayGetTree() {
51- const tree = run('swaymsg', '--raw', '--type', 'get_tree')
52- return JSON.parse(str(tree))
56+ const tree = run('swaymsg', '--raw', '--type', 'get_tree');
57+ return JSON.parse(str(tree));
5358 }
5459
5560 function swayFindFocused(tree) {
56- const nodes = tree['nodes'].concat(tree['floating_nodes'])
61+ const nodes = tree['nodes'].concat(tree['floating_nodes']);
5762 for (const node of nodes) {
58- if (node['focused'])
59- return node
60- const focusedNode = swayFindFocused(node)
61- if (focusedNode)
62- return focusedNode
63+ if (node['focused']) {
64+ return node;
65+ }
66+ const focusedNode = swayFindFocused(node);
67+ if (focusedNode) {
68+ return focusedNode;
69+ }
6370 }
64- return undefined
71+ return undefined;
6572 }
6673
6774 function hyprlandFindFocused() {
68- const window = run('hyprctl', '-j', 'activewindow')
69- return JSON.parse(str(window))
75+ const window = run('hyprctl', '-j', 'activewindow');
76+ return JSON.parse(str(window));
7077 }
7178
7279 function kdeFocused() {
73- return str(run('kdotool', 'getactivewindow', 'getwindowname'))
80+ try {
81+ const window = run('kdotool', 'getactivewindow', 'getwindowname');
82+ return str(window).trim();
83+ } catch (e) {
84+ serverLog(`Failed to call kdotool: ${e}`);
85+ // Avoid storing data since we cannot filter it by window title
86+ removeData(mimeOutputTab);
87+ return '';
88+ }
7489 }
7590
7691 function sendShortcut(...shortcut) {
77- sleep(100)
78- run('ydotool', 'key', ...shortcut)
92+ sleep(100);
93+ run('ydotool', 'key', ...shortcut);
7994 }
8095
81- global.currentWindowTitle = function() {
96+ global.currentWindowTitle = function () {
8297 if (isSway()) {
83- const tree = swayGetTree()
84- const focusedNode = swayFindFocused(tree)
85- return focusedNode ? focusedNode['name'] : ''
98+ const tree = swayGetTree();
99+ const focusedNode = swayFindFocused(tree);
100+ return focusedNode ? focusedNode['name'] : '';
86101 }
87102
88103 if (isHyprland()) {
89- const focusedWindow = hyprlandFindFocused()
90- return focusedWindow ? focusedWindow['title'] : ''
104+ const focusedWindow = hyprlandFindFocused();
105+ return focusedWindow ? focusedWindow['title'] : '';
91106 }
92107
93108 if (isKde()) {
94- return kdeFocused()
109+ return kdeFocused();
95110 }
96111
97- return ''
98- }
112+ return '';
113+ };
99114
100- global.paste = function() {
101- sendShortcut('42:1', '110:1', '110:0', '42:0')
102- }
115+ global.paste = function () {
116+ sendShortcut('42:1', '110:1', '110:0', '42:0');
117+ };
103118
104- const copy_ = global.copy
105- global.copy = function() {
119+ const copy_ = global.copy;
120+ global.copy = function () {
106121 if (arguments.length == 0) {
107- sendShortcut('29:1', '46:1', '46:0', '29:0')
122+ sendShortcut('29:1', '46:1', '46:0', '29:0');
108123 } else {
109- copy_.apply(this, arguments)
124+ copy_.apply(this, arguments);
110125 }
111- }
126+ };
112127
113- global.focusPrevious = function() {
114- hide()
115- }
128+ global.focusPrevious = function () {
129+ hide();
130+ };
116131
117132 function overrideToRunInXWayland(fn) {
118- const oldFn = global[fn]
119- global[fn] = function() {
133+ const oldFn = global[fn];
134+ global[fn] = function () {
120135 if (isGnome() && env('QT_QPA_PLATFORM') != 'xcb') {
121- serverLog(`Starting XWayland ${fn}`)
122- setEnv('QT_QPA_PLATFORM', 'xcb')
123- execute('copyq', '--clipboard-access', fn)
124- serverLog(`Stopping XWayland ${fn}`)
125- return
136+ serverLog(`Starting XWayland ${fn}`);
137+ setEnv('QT_QPA_PLATFORM', 'xcb');
138+ execute('copyq', '--clipboard-access', fn);
139+ serverLog(`Stopping XWayland ${fn}`);
140+ return;
126141 }
127- return oldFn()
142+ return oldFn();
143+ };
144+ }
145+ overrideToRunInXWayland('monitorClipboard');
146+ overrideToRunInXWayland('synchronizeFromSelection');
147+ overrideToRunInXWayland('synchronizeToSelection');
148+
149+ const onClipboardChanged_ = onClipboardChanged;
150+ onClipboardChanged = function () {
151+ const title = currentWindowTitle();
152+ if (title) {
153+ setData(mimeWindowTitle, title);
128154 }
129- }
130- overrideToRunInXWayland('monitorClipboard')
131- overrideToRunInXWayland('synchronizeFromSelection')
132- overrideToRunInXWayland('synchronizeToSelection')
133-
134- const onClipboardChanged_ = onClipboardChanged
135- onClipboardChanged = function() {
136- const title = currentWindowTitle()
137- if (title)
138- setData(mimeWindowTitle, title)
139- onClipboardChanged_()
140- }
155+ onClipboardChanged_();
156+ };
141157
142158 function gnomeScreenshot(arg) {
143- const tmpFile = TemporaryFile()
144- tmpFile.setFileTemplate(Dir().temp().absoluteFilePath('copyq-XXXXXX.png'))
145- tmpFile.openWriteOnly()
146- tmpFile.close()
159+ const tmpFile = TemporaryFile();
160+ tmpFile.setFileTemplate(Dir().temp().absoluteFilePath('copyq-XXXXXX.png'));
161+ tmpFile.openWriteOnly();
162+ tmpFile.close();
147163 run(
148164 'gnome-screenshot',
149165 arg || '--delay=0',
150166 '--include-pointer',
151167 '--file',
152168 tmpFile.fileName(),
153- )
154- const file = File(tmpFile.fileName())
155- file.openReadOnly()
156- const stdout = File('/dev/stdout')
157- stdout.openWriteOnly()
158- stdout.write(file.readAll())
169+ );
170+ const file = File(tmpFile.fileName());
171+ file.openReadOnly();
172+ const stdout = File('/dev/stdout');
173+ stdout.openWriteOnly();
174+ stdout.write(file.readAll());
159175 }
160176
161- screenshot = function(format, screenName) {
162- if (isSway() || isHyprland())
163- return run('grim', '-t', format || 'png', '-')
164- if (isGnome())
165- return gnomeScreenshot()
177+ screenshot = function (format, screenName) {
178+ if (isSway() || isHyprland()) {
179+ return run('grim', '-t', format || 'png', '-');
180+ }
181+ if (isGnome()) {
182+ return gnomeScreenshot();
183+ }
166184 return run(
167185 'spectacle',
168186 '--background',
169187 '--nonotify',
170188 '--pointer',
171189 '--output',
172190 '/dev/stdout',
173- )
174- }
191+ );
192+ };
175193
176- screenshotSelect = function(format, screenName) {
194+ screenshotSelect = function (format, screenName) {
177195 if (isSway() || isHyprland()) {
178- let geometry = run('slurp')
179- geometry = str(geometry).trim()
180- return run('grim', '-c', '-g', geometry, '-t', format || 'png', '-')
196+ let geometry = run('slurp');
197+ geometry = str(geometry).trim();
198+ return run('grim', '-c', '-g', geometry, '-t', format || 'png', '-');
199+ }
200+ if (isGnome()) {
201+ return gnomeScreenshot('--area');
181202 }
182- if (isGnome())
183- return gnomeScreenshot('--area')
184203 return run(
185204 'spectacle',
186205 '--background',
@@ -189,17 +208,17 @@ Command="
189208 '--region',
190209 '--output',
191210 '/dev/stdout',
192- )
193- }
211+ );
212+ };
194213
195- global.triggerGlobalShortcut = function(commandName) {
196- const cmds = commands()
214+ global.triggerGlobalShortcut = function (commandName) {
215+ const cmds = commands();
197216 for (const cmd of cmds) {
198217 if (cmd.isGlobalShortcut && cmd.enable && cmd.name == commandName)
199- return action(cmd.cmd)
218+ return action(cmd.cmd);
200219 }
201- throw 'Failed to find enabled global command with given name'
202- }"
220+ throw 'Failed to find enabled global command with given name';
221+ }; "
203222Icon =
204223IsScript =true
205224Name =Wayland Support
0 commit comments