Merge ~3v1n0/ubuntu/+source/gnome-calculator:ubuntu/bionic-xubuntu-cancel-search into ~ubuntu-desktop/ubuntu/+source/gnome-calculator:ubuntu/bionic

Proposed by Marco Trevisan (Treviño)
Status: Merged
Merged at revision: 3b2a861e9c0ef946f7bbc64ead0e6411cd665e5a
Proposed branch: ~3v1n0/ubuntu/+source/gnome-calculator:ubuntu/bionic-xubuntu-cancel-search
Merge into: ~ubuntu-desktop/ubuntu/+source/gnome-calculator:ubuntu/bionic
Prerequisite: ~3v1n0/ubuntu/+source/gnome-calculator:ubuntu/bionic
Diff against target: 1129 lines (+1026/-2)
15 files modified
debian/changelog (+28/-0)
debian/control (+2/-1)
debian/control.in (+2/-1)
debian/patches/Use-GLib.List.deep_copy-to-fix-type-argument-mismatch.patch (+25/-0)
debian/patches/search-provider-Handle-errors-gracefully.patch (+108/-0)
debian/patches/search-provider-Use-async-calls-cancel-search-on-inactivi.patch (+233/-0)
debian/patches/search-provider-Use-lower-inactivity-timeout.patch (+30/-0)
debian/patches/search-provider-cache-equations-avoiding-spawning-calcula.patch (+171/-0)
debian/patches/search-provider-cache-only-a-limited-number-of-equations.patch (+45/-0)
debian/patches/search-provider-cancel-the-current-process-on-new-calcula.patch (+30/-0)
debian/patches/search-provider-renew-inactivity-timeout-at-each-calculat.patch (+61/-0)
debian/patches/search-provider-simplify-solve_subprocess.patch (+114/-0)
debian/patches/search-provider-stop-normalizing-the-equation-twice.patch (+48/-0)
debian/patches/series (+11/-0)
debian/patches/ubuntu/search-provider-Cancel-operations-on-XUbuntuCancel.patch (+118/-0)
Reviewer Review Type Date Requested Status
Ubuntu Desktop Pending
Review via email: mp+354335@code.launchpad.net
To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/debian/changelog b/debian/changelog
2index 44dd584..9da064b 100644
3--- a/debian/changelog
4+++ b/debian/changelog
5@@ -1,3 +1,31 @@
6+gnome-calculator (1:3.28.2-1~ubuntu18.04.3) UNRELEASED; urgency=medium
7+
8+ * d/p/search-provider-stop-normalizing-the-equation-twice.patch:
9+ - Don't normalize multiple times an equation, fixing issues with decimal
10+ numbers computations (fixes a regression introduced with previous
11+ patch set in order to fix LP: #1756826)
12+ * d/p/Use-GLib.List.deep_copy-to-fix-type-argument-mismatch.patch:
13+ - Fix a build issue when compiling with vala 0.40.17 (LP: #1857005)
14+
15+ -- Marco Trevisan (Treviño) <marco@ubuntu.com> Wed, 18 Dec 2019 21:10:54 +0100
16+
17+gnome-calculator (1:3.28.2-1~ubuntu18.04.2) bionic; urgency=medium
18+
19+ * d/p/search-provider-Use-async-calls-cancel-search-on-inactivi.patch,
20+ d/p/search-provider-renew-inactivity-timeout-at-each-calculat.patch,
21+ d/p/search-provider-Use-lower-inactivity-timeout.patch,
22+ d/p/search-provider-simplify-solve_subprocess.patch,
23+ d/p/search-provider-cache-equations-avoiding-spawning-calcula.patch,
24+ d/p/search-provider-cancel-the-current-process-on-new-calcula.patch,
25+ d/p/search-provider-cache-only-a-limited-number-of-equations.patch,
26+ d/p/search-provider-Handle-errors-gracefully.patch,
27+ d/p/ubuntu/search-provider-Cancel-operations-on-XUbuntuCancel.patch:
28+ - Make search provider async and support XUbuntuCancel method to
29+ stop expensive operations that might lead to an unresponsive
30+ process (LP: #1756826)
31+
32+ -- Marco Trevisan (Treviño) <marco@ubuntu.com> Thu, 08 Nov 2018 01:34:07 -0500
33+
34 gnome-calculator (1:3.28.2-1~ubuntu18.04.1) bionic; urgency=medium
35
36 * New upstream stable release (LP: #1790876)
37diff --git a/debian/control b/debian/control
38index cd4706c..0782192 100644
39--- a/debian/control
40+++ b/debian/control
41@@ -5,7 +5,8 @@
42 Source: gnome-calculator
43 Section: math
44 Priority: optional
45-Maintainer: Debian GNOME Maintainers <pkg-gnome-maintainers@lists.alioth.debian.org>
46+Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
47+XSBC-Original-Maintainer: Debian GNOME Maintainers <pkg-gnome-maintainers@lists.alioth.debian.org>
48 Uploaders: Jeremy Bicha <jbicha@debian.org>, Laurent Bigonville <bigon@debian.org>, Michael Biebl <biebl@debian.org>
49 Build-Depends: appstream-util,
50 debhelper (>= 11.1.3),
51diff --git a/debian/control.in b/debian/control.in
52index b5194ee..d9e0327 100644
53--- a/debian/control.in
54+++ b/debian/control.in
55@@ -1,7 +1,8 @@
56 Source: gnome-calculator
57 Section: math
58 Priority: optional
59-Maintainer: Debian GNOME Maintainers <pkg-gnome-maintainers@lists.alioth.debian.org>
60+Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
61+XSBC-Original-Maintainer: Debian GNOME Maintainers <pkg-gnome-maintainers@lists.alioth.debian.org>
62 Uploaders: @GNOME_TEAM@
63 Build-Depends: appstream-util,
64 debhelper (>= 11.1.3),
65diff --git a/debian/patches/Use-GLib.List.deep_copy-to-fix-type-argument-mismatch.patch b/debian/patches/Use-GLib.List.deep_copy-to-fix-type-argument-mismatch.patch
66new file mode 100644
67index 0000000..0810e88
68--- /dev/null
69+++ b/debian/patches/Use-GLib.List.deep_copy-to-fix-type-argument-mismatch.patch
70@@ -0,0 +1,25 @@
71+From: Rico Tzschichholz <ricotz@ubuntu.com>
72+Date: Sun, 4 Nov 2018 19:41:23 +0100
73+Subject: Use GLib.List.deep_copy() to fix type-argument mismatch
74+
75+Origin: https://gitlab.gnome.org/GNOME/gnome-calculator/commit/d89466a7
76+Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/gnome-calculator/+bug/1857005
77+Applied-Upstream: 3.31.2
78+
79+---
80+ lib/equation-parser.vala | 2 +-
81+ 1 file changed, 1 insertion(+), 1 deletion(-)
82+
83+diff --git a/lib/equation-parser.vala b/lib/equation-parser.vala
84+index 668e1cd..d16e5b1 100644
85+--- a/lib/equation-parser.vala
86++++ b/lib/equation-parser.vala
87+@@ -76,7 +76,7 @@ public class ParseNode : Object
88+ public ParseNode.WithList (Parser parser, List<LexerToken> token_list, uint precedence, Associativity associativity, string? value = null)
89+ {
90+ this.parser = parser;
91+- this.token_list = token_list.copy();
92++ this.token_list = token_list.copy_deep((CopyFunc) Object.ref);
93+ this.precedence = precedence;
94+ this.associativity = associativity;
95+ this.value = value;
96diff --git a/debian/patches/search-provider-Handle-errors-gracefully.patch b/debian/patches/search-provider-Handle-errors-gracefully.patch
97new file mode 100644
98index 0000000..f78c54b
99--- /dev/null
100+++ b/debian/patches/search-provider-Handle-errors-gracefully.patch
101@@ -0,0 +1,108 @@
102+From: =?utf-8?b?Ik1hcmNvIFRyZXZpc2FuIChUcmV2acOxbyki?= <mail@3v1n0.net>
103+Date: Wed, 5 Sep 2018 17:11:27 +0200
104+Subject: search-provider: Handle errors gracefully
105+
106+Instead of exiting immediately if a spawn error occurred, inform our dbus
107+client about it with a proper spawn error.
108+
109+As bonus, get rid of the compile warning.
110+
111+Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/gnome-calculator/+bug/1795399
112+Forwarded: https://gitlab.gnome.org/GNOME/gnome-calculator/merge_requests/10
113+Applied-Upstream: yes, 3.31.1
114+---
115+ search-provider/search-provider.vala | 24 +++++++++++++-----------
116+ 1 file changed, 13 insertions(+), 11 deletions(-)
117+
118+diff --git a/search-provider/search-provider.vala b/search-provider/search-provider.vala
119+index fc72128..a48c440 100644
120+--- a/search-provider/search-provider.vala
121++++ b/search-provider/search-provider.vala
122+@@ -63,7 +63,7 @@ public class SearchProvider : Object
123+ }
124+ catch (Error e)
125+ {
126+- error ("Failed to spawn Calculator: %s", e.message);
127++ throw e;
128+ }
129+
130+ if (cancellable == null)
131+@@ -79,7 +79,7 @@ public class SearchProvider : Object
132+ return subprocess;
133+ }
134+
135+- private async bool solve_equation (string equation)
136++ private async bool solve_equation (string equation) throws DBusError
137+ {
138+ string? result;
139+
140+@@ -112,7 +112,8 @@ public class SearchProvider : Object
141+ }
142+ catch (SpawnError e)
143+ {
144+- error ("Failed to spawn Calculator: %s", e.message);
145++ critical ("Failed to spawn Calculator: %s", e.message);
146++ throw new DBusError.SPAWN_FAILED (e.message);
147+ }
148+ catch (Error e)
149+ {
150+@@ -128,7 +129,7 @@ public class SearchProvider : Object
151+ return true;
152+ }
153+
154+- private async string[] get_result_identifier (string[] terms)
155++ private async string[] get_result_identifier (string[] terms) throws Error
156+ {
157+ /* We have at most one result: the search terms as one string */
158+ var equation = terms_to_equation (terms);
159+@@ -138,17 +139,17 @@ public class SearchProvider : Object
160+ return new string[0];
161+ }
162+
163+- public async string[] get_initial_result_set (string[] terms)
164++ public async string[] get_initial_result_set (string[] terms) throws Error
165+ {
166+ return yield get_result_identifier (terms);
167+ }
168+
169+- public async string[] get_subsearch_result_set (string[] previous_results, string[] terms)
170++ public async string[] get_subsearch_result_set (string[] previous_results, string[] terms) throws Error
171+ {
172+ return yield get_result_identifier (terms);
173+ }
174+
175+- public async HashTable<string, Variant>[] get_result_metas (string[] results, GLib.BusName sender)
176++ public async HashTable<string, Variant>[] get_result_metas (string[] results, GLib.BusName sender) throws Error
177+ requires (results.length == 1)
178+ {
179+ string equation;
180+@@ -171,7 +172,7 @@ public class SearchProvider : Object
181+ return metadata;
182+ }
183+
184+- private static void spawn_and_display_equation (string[] terms)
185++ private static void spawn_and_display_equation (string[] terms) throws Error
186+ {
187+ try
188+ {
189+@@ -180,16 +181,17 @@ public class SearchProvider : Object
190+ }
191+ catch (SpawnError e)
192+ {
193+- error ("Failed to spawn Calculator: %s", e.message);
194++ critical ("Failed to spawn Calculator: %s", e.message);
195++ throw new DBusError.SPAWN_FAILED (e.message);
196+ }
197+ }
198+
199+- public void activate_result (string result, string[] terms, uint32 timestamp)
200++ public void activate_result (string result, string[] terms, uint32 timestamp) throws Error
201+ {
202+ spawn_and_display_equation (terms);
203+ }
204+
205+- public void launch_search (string[] terms, uint32 timestamp)
206++ public void launch_search (string[] terms, uint32 timestamp) throws Error
207+ {
208+ spawn_and_display_equation (terms);
209+ }
210diff --git a/debian/patches/search-provider-Use-async-calls-cancel-search-on-inactivi.patch b/debian/patches/search-provider-Use-async-calls-cancel-search-on-inactivi.patch
211new file mode 100644
212index 0000000..d8e38be
213--- /dev/null
214+++ b/debian/patches/search-provider-Use-async-calls-cancel-search-on-inactivi.patch
215@@ -0,0 +1,233 @@
216+From: =?utf-8?b?Ik1hcmNvIFRyZXZpc2FuIChUcmV2acOxbyki?= <mail@3v1n0.net>
217+Date: Fri, 24 Aug 2018 06:57:03 +0200
218+Subject: search-provider: Use async calls, cancel search on inactivity
219+
220+Move to async methods everywhere and factorize the `solve` calls to a single
221+method that only uses Subprocess and that can be cancelled.
222+
223+As per this, if the the search-provider is trying to compute some complex
224+operation, the daemon won't hang and once the applications' inactivity
225+timeout is hit, any running instance of gnome-calculator will be killed and
226+the daemon will return accordingly.
227+
228+This reduces the impact of an issue that can cause gnome-calculator to keep
229+running forever if a complex computation is required (10!!!) from the shell,
230+and won't ever be killed (see GNOME/gnome-shell#183).
231+
232+This is also a prerequisite for supporting the search Cancellation that is
233+going to be available on next version of the Search provider protocol
234+(as per GNOME/gnome-shell#436)
235+
236+Bug-Ubuntu: https://launchpad.net/bugs/1756826
237+Bug-GNOME: https://gitlab.gnome.org/GNOME/gnome-shell/issues/183
238+Forwarded: https://gitlab.gnome.org/GNOME/gnome-calculator/merge_requests/10
239+Applied-Upstream: yes, 3.31.1
240+---
241+ search-provider/search-provider.vala | 126 +++++++++++++++++++++++++----------
242+ 1 file changed, 89 insertions(+), 37 deletions(-)
243+
244+diff --git a/search-provider/search-provider.vala b/search-provider/search-provider.vala
245+index 26c72af..659f73d 100644
246+--- a/search-provider/search-provider.vala
247++++ b/search-provider/search-provider.vala
248+@@ -1,6 +1,7 @@
249+ /* -*- Mode: vala; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
250+ *
251+ * Copyright (C) 2014 Michael Catanzaro
252++ * Copyright (C) 2018 Marco Trevisan
253+ *
254+ * This program is free software: you can redistribute it and/or modify it under
255+ * the terms of the GNU General Public License as published by the Free Software
256+@@ -12,17 +13,85 @@
257+ [DBus (name = "org.gnome.Shell.SearchProvider2")]
258+ public class SearchProvider : Object
259+ {
260++ private Cancellable cancellable = new Cancellable ();
261++
262++ ~SearchProvider ()
263++ {
264++ cancel ();
265++ }
266++
267++ [DBus (visible = false)]
268++ public void cancel ()
269++ {
270++ if (cancellable != null)
271++ {
272++ cancellable.cancel ();
273++ }
274++ }
275++
276+ private static string terms_to_equation (string[] terms)
277+ {
278+ return string.joinv (" ", terms);
279+ }
280+
281+- private static bool can_parse (string[] terms)
282++ private async Subprocess solve_subprocess (string equation, bool return_solution = false, out string? solution_buf = null) throws Error
283+ {
284++ Subprocess subprocess;
285++ string[] argv = {"gnome-calculator", "--solve"};
286++ argv += equation;
287++ argv += null;
288++
289++ debug (@"Trying to solve $(equation)");
290++
291+ try
292+ {
293+- int exit_status;
294++ // Eat output so that it doesn't wind up in the journal. It's
295++ // expected that most searches are not valid calculator input.
296++ var flags = SubprocessFlags.STDERR_PIPE;
297++
298++ if (return_solution)
299++ {
300++ flags |= SubprocessFlags.STDOUT_PIPE;
301++ }
302++
303++ subprocess = new Subprocess.newv (argv, flags);
304++ }
305++ catch (Error e)
306++ {
307++ error ("Failed to spawn Calculator: %s", e.message);
308++ }
309++
310++ try
311++ {
312++ string stderr_buf;
313++
314++ cancellable = new Cancellable ();
315++ cancellable.cancelled.connect (() => {
316++ subprocess.force_exit ();
317++ cancellable = null;
318++ });
319++
320++ yield subprocess.communicate_utf8_async (null, cancellable, out solution_buf, out stderr_buf);
321++ }
322++ catch (Error e)
323++ {
324++ if (e is IOError.CANCELLED)
325++ {
326++ throw e;
327++ }
328++ else
329++ {
330++ error ("Failed reading result: %s", e.message);
331++ }
332++ }
333+
334++ return subprocess;
335++ }
336++
337++ private async bool can_parse (string[] terms)
338++ {
339++ try
340++ {
341+ var tsep_string = Posix.nl_langinfo (Posix.NLItem.THOUSEP);
342+ if (tsep_string == null || tsep_string == "")
343+ tsep_string = " ";
344+@@ -39,14 +108,8 @@ public class SearchProvider : Object
345+ return false;
346+ }
347+
348+- // Eat output so that it doesn't wind up in the journal. It's
349+- // expected that most searches are not valid calculator input.
350+- string stdout_buf;
351+- string stderr_buf;
352+- Process.spawn_command_line_sync (
353+- "gnome-calculator --solve " + Shell.quote (equation),
354+- out stdout_buf, out stderr_buf, out exit_status);
355+- Process.check_exit_status (exit_status);
356++ var subprocess = yield solve_subprocess (equation);
357++ yield subprocess.wait_check_async ();
358+ }
359+ catch (SpawnError e)
360+ {
361+@@ -60,54 +123,37 @@ public class SearchProvider : Object
362+ return true;
363+ }
364+
365+- private static string[] get_result_identifier (string[] terms)
366+- ensures (result.length == 0 || result.length == 1)
367++ private async string[] get_result_identifier (string[] terms)
368+ {
369+ /* We have at most one result: the search terms as one string */
370+- if (can_parse (terms))
371++ if (yield can_parse (terms))
372+ return { terms_to_equation (terms) };
373+ else
374+ return new string[0];
375+ }
376+
377+- public string[] get_initial_result_set (string[] terms)
378++ public async string[] get_initial_result_set (string[] terms)
379+ {
380+- return get_result_identifier (terms);
381++ return yield get_result_identifier (terms);
382+ }
383+
384+- public string[] get_subsearch_result_set (string[] previous_results, string[] terms)
385++ public async string[] get_subsearch_result_set (string[] previous_results, string[] terms)
386+ {
387+- return get_result_identifier (terms);
388++ return yield get_result_identifier (terms);
389+ }
390+
391+- public HashTable<string, Variant>[] get_result_metas (string[] results)
392++ public async HashTable<string, Variant>[] get_result_metas (string[] results, GLib.BusName sender)
393+ requires (results.length == 1)
394+- ensures (result.length == 1)
395+ {
396+- Subprocess subprocess;
397+ string stdout_buf;
398+- string stderr_buf;
399+-
400+- string[] argv = {"gnome-calculator", "--solve"};
401+- argv += results[0];
402+- argv += null;
403+-
404+- try
405+- {
406+- subprocess = new Subprocess.newv (argv, SubprocessFlags.STDOUT_PIPE | SubprocessFlags.STDERR_PIPE);
407+- }
408+- catch (Error e)
409+- {
410+- error ("Failed to spawn Calculator: %s", e.message);
411+- }
412+
413+ try
414+ {
415+- subprocess.communicate_utf8 (null, null, out stdout_buf, out stderr_buf);
416++ yield solve_subprocess (results[0], true, out stdout_buf);
417+ }
418+ catch (Error e)
419+ {
420+- error ("Failed reading result: %s", e.message);
421++ return new HashTable<string, Variant>[0];
422+ }
423+
424+ var metadata = new HashTable<string, Variant>[1];
425+@@ -155,9 +201,11 @@ public class SearchProviderApp : Application
426+
427+ public override bool dbus_register (DBusConnection connection, string object_path)
428+ {
429++ SearchProvider search_provider = new SearchProvider ();
430++
431+ try
432+ {
433+- connection.register_object (object_path, new SearchProvider ());
434++ connection.register_object (object_path, search_provider);
435+ }
436+ catch (IOError error)
437+ {
438+@@ -165,6 +213,10 @@ public class SearchProviderApp : Application
439+ quit ();
440+ }
441+
442++ shutdown.connect (() => {
443++ search_provider.cancel ();
444++ });
445++
446+ return true;
447+ }
448+ }
449diff --git a/debian/patches/search-provider-Use-lower-inactivity-timeout.patch b/debian/patches/search-provider-Use-lower-inactivity-timeout.patch
450new file mode 100644
451index 0000000..5008fe5
452--- /dev/null
453+++ b/debian/patches/search-provider-Use-lower-inactivity-timeout.patch
454@@ -0,0 +1,30 @@
455+From: =?utf-8?b?Ik1hcmNvIFRyZXZpc2FuIChUcmV2acOxbyki?= <mail@3v1n0.net>
456+Date: Fri, 24 Aug 2018 07:12:12 +0200
457+Subject: search-provider: Use lower inactivity timeout
458+
459+Since we're renewing it at every call involving a process call, we can just
460+set it to a lower value than the default dbus proxy timeout, so that the provider
461+will return invalid values before that the timeout has been hit.
462+
463+Bug-Ubuntu: https://launchpad.net/bugs/1756826
464+Bug-GNOME: https://gitlab.gnome.org/GNOME/gnome-shell/issues/183
465+Forwarded: https://gitlab.gnome.org/GNOME/gnome-calculator/merge_requests/10
466+Applied-Upstream: yes, 3.31.1
467+---
468+ search-provider/search-provider.vala | 3 ++-
469+ 1 file changed, 2 insertions(+), 1 deletion(-)
470+
471+diff --git a/search-provider/search-provider.vala b/search-provider/search-provider.vala
472+index 7e54fa6..9035c58 100644
473+--- a/search-provider/search-provider.vala
474++++ b/search-provider/search-provider.vala
475+@@ -203,7 +203,8 @@ public class SearchProviderApp : Application
476+ {
477+ Object (application_id: "org.gnome.Calculator.SearchProvider",
478+ flags: ApplicationFlags.IS_SERVICE,
479+- inactivity_timeout: 60000);
480++ inactivity_timeout: 20000);
481++ }
482+
483+ public void renew_inactivity_timeout ()
484+ {
485diff --git a/debian/patches/search-provider-cache-equations-avoiding-spawning-calcula.patch b/debian/patches/search-provider-cache-equations-avoiding-spawning-calcula.patch
486new file mode 100644
487index 0000000..85d83ce
488--- /dev/null
489+++ b/debian/patches/search-provider-cache-equations-avoiding-spawning-calcula.patch
490@@ -0,0 +1,171 @@
491+From: =?utf-8?b?Ik1hcmNvIFRyZXZpc2FuIChUcmV2acOxbyki?= <mail@3v1n0.net>
492+Date: Mon, 27 Aug 2018 18:45:34 +0200
493+Subject: search-provider: cache equations avoiding spawning calculator twice
494+
495+Currently we spawn the calculator two times for each operation, one to check
496+if the search provider is valid for such syntax, the other time to actually
497+present the results. But since these results are just available at first
498+call, we can just keep them around and return them if the shell requires them.
499+
500+Since the search provider deamon is kept alive for just few moments, there's
501+no real need to cleanup the cache using a queue.
502+
503+In case of multiple async calls, reuse cancellable instead so that we can
504+just kill all the related processes one time at once.
505+
506+Bug-Ubuntu: https://launchpad.net/bugs/1756826
507+Bug-GNOME: https://gitlab.gnome.org/GNOME/gnome-shell/issues/183
508+Forwarded: https://gitlab.gnome.org/GNOME/gnome-calculator/merge_requests/10
509+Applied-Upstream: yes, 3.31.1
510+---
511+ search-provider/search-provider.vala | 79 ++++++++++++++++++++----------------
512+ 1 file changed, 45 insertions(+), 34 deletions(-)
513+
514+diff --git a/search-provider/search-provider.vala b/search-provider/search-provider.vala
515+index a3c57f7..af2779e 100644
516+--- a/search-provider/search-provider.vala
517++++ b/search-provider/search-provider.vala
518+@@ -14,10 +14,13 @@
519+ public class SearchProvider : Object
520+ {
521+ private unowned SearchProviderApp application;
522+- private Cancellable cancellable = new Cancellable ();
523++ private Cancellable cancellable;
524++
525++ private HashTable<string, string> cached_equations;
526+ public SearchProvider (SearchProviderApp app)
527+ {
528+ application = app;
529++ cached_equations = new HashTable<string, string> (str_hash, str_equal);
530+ }
531+
532+ ~SearchProvider ()
533+@@ -29,9 +32,7 @@ public class SearchProvider : Object
534+ public void cancel ()
535+ {
536+ if (cancellable != null)
537+- {
538+ cancellable.cancel ();
539+- }
540+ }
541+
542+ private static string terms_to_equation (string[] terms)
543+@@ -60,7 +61,9 @@ public class SearchProvider : Object
544+ error ("Failed to spawn Calculator: %s", e.message);
545+ }
546+
547+- cancellable = new Cancellable ();
548++ if (cancellable == null)
549++ cancellable = new Cancellable ();
550++
551+ cancellable.cancelled.connect (() => {
552+ subprocess.force_exit ();
553+ cancellable = null;
554+@@ -71,29 +74,36 @@ public class SearchProvider : Object
555+ return subprocess;
556+ }
557+
558+- private async bool can_parse (string[] terms)
559++ private async bool solve_equation (string equation)
560+ {
561+- try
562+- {
563+- var tsep_string = Posix.nl_langinfo (Posix.NLItem.THOUSEP);
564+- if (tsep_string == null || tsep_string == "")
565+- tsep_string = " ";
566++ string? result;
567+
568+- var decimal = Posix.nl_langinfo (Posix.NLItem.RADIXCHAR);
569+- if (decimal == null)
570+- decimal = "";
571++ cancel();
572+
573+- // "normalize" input to a format known to double.try_parse
574+- var equation = terms_to_equation (terms).replace (tsep_string, "").replace (decimal, ".");
575++ var tsep_string = Posix.nl_langinfo (Posix.NLItem.THOUSEP);
576++ if (tsep_string == null || tsep_string == "")
577++ tsep_string = " ";
578+
579+- cancel();
580++ var decimal = Posix.nl_langinfo (Posix.NLItem.RADIXCHAR);
581++ if (decimal == null)
582++ decimal = "";
583+
584+- // if the search is a plain number, don't process it
585+- if (double.try_parse (equation)) {
586+- return false;
587+- }
588++ // "normalize" input to a format known to double.try_parse
589++ var normalized_equation = equation.replace (tsep_string, "").replace (decimal, ".");
590+
591+- (yield solve_subprocess (equation)).wait_check (cancellable);
592++ // if the search is a plain number, don't process it
593++ if (double.try_parse (normalized_equation)) {
594++ return false;
595++ }
596++
597++ if (cached_equations.lookup (equation) != null)
598++ return true;
599++
600++ try
601++ {
602++ var subprocess = yield solve_subprocess (normalized_equation);
603++ yield subprocess.communicate_utf8_async (null, cancellable, out result, null);
604++ subprocess.wait_check (cancellable);
605+ }
606+ catch (SpawnError e)
607+ {
608+@@ -104,14 +114,17 @@ public class SearchProvider : Object
609+ return false;
610+ }
611+
612++ cached_equations.insert (equation, result.strip ());
613++
614+ return true;
615+ }
616+
617+ private async string[] get_result_identifier (string[] terms)
618+ {
619+ /* We have at most one result: the search terms as one string */
620+- if (yield can_parse (terms))
621+- return { terms_to_equation (terms) };
622++ var equation = terms_to_equation (terms);
623++ if (yield solve_equation (equation))
624++ return { equation };
625+ else
626+ return new string[0];
627+ }
628+@@ -129,24 +142,22 @@ public class SearchProvider : Object
629+ public async HashTable<string, Variant>[] get_result_metas (string[] results, GLib.BusName sender)
630+ requires (results.length == 1)
631+ {
632+- string stdout_buf;
633+- string stderr_buf;
634++ string equation;
635++ string result;
636+
637+- try
638+- {
639+- var subprocess = yield solve_subprocess (results[0]);
640+- yield subprocess.communicate_utf8_async (null, cancellable, out stdout_buf, out stderr_buf);
641+- }
642+- catch (Error e)
643+- {
644++ equation = terms_to_equation (results);
645++
646++ if (!yield solve_equation (equation))
647+ return new HashTable<string, Variant>[0];
648+- }
649++
650++ result = cached_equations.lookup (equation);
651++ assert (result != null);
652+
653+ var metadata = new HashTable<string, Variant>[1];
654+ metadata[0] = new HashTable<string, Variant>(str_hash, str_equal);
655+ metadata[0].insert ("id", results[0]);
656+ metadata[0].insert ("name", results[0] );
657+- metadata[0].insert ("description", " = " + stdout_buf.strip ());
658++ metadata[0].insert ("description", @" = $result");
659+
660+ return metadata;
661+ }
662diff --git a/debian/patches/search-provider-cache-only-a-limited-number-of-equations.patch b/debian/patches/search-provider-cache-only-a-limited-number-of-equations.patch
663new file mode 100644
664index 0000000..651aa28
665--- /dev/null
666+++ b/debian/patches/search-provider-cache-only-a-limited-number-of-equations.patch
667@@ -0,0 +1,45 @@
668+From: =?utf-8?b?Ik1hcmNvIFRyZXZpc2FuIChUcmV2acOxbyki?= <mail@3v1n0.net>
669+Date: Mon, 27 Aug 2018 18:56:09 +0200
670+Subject: search-provider: cache only a limited number of equations
671+
672+Bug-Ubuntu: https://launchpad.net/bugs/1756826
673+Bug-GNOME: https://gitlab.gnome.org/GNOME/gnome-shell/issues/183
674+Forwarded: https://gitlab.gnome.org/GNOME/gnome-calculator/merge_requests/10
675+Applied-Upstream: yes, 3.31.1
676+---
677+ search-provider/search-provider.vala | 9 +++++++++
678+ 1 file changed, 9 insertions(+)
679+
680+diff --git a/search-provider/search-provider.vala b/search-provider/search-provider.vala
681+index af2779e..fc72128 100644
682+--- a/search-provider/search-provider.vala
683++++ b/search-provider/search-provider.vala
684+@@ -16,10 +16,15 @@ public class SearchProvider : Object
685+ private unowned SearchProviderApp application;
686+ private Cancellable cancellable;
687+
688++ private const int MAX_CACHED_OPERATIONS = 10;
689++ private Queue<string> queued_equations;
690+ private HashTable<string, string> cached_equations;
691++
692+ public SearchProvider (SearchProviderApp app)
693+ {
694+ application = app;
695++
696++ queued_equations = new Queue<string> ();
697+ cached_equations = new HashTable<string, string> (str_hash, str_equal);
698+ }
699+
700+@@ -114,8 +119,12 @@ public class SearchProvider : Object
701+ return false;
702+ }
703+
704++ queued_equations.push_tail (equation);
705+ cached_equations.insert (equation, result.strip ());
706+
707++ if (queued_equations.length > MAX_CACHED_OPERATIONS)
708++ cached_equations.remove (queued_equations.pop_head ());
709++
710+ return true;
711+ }
712+
713diff --git a/debian/patches/search-provider-cancel-the-current-process-on-new-calcula.patch b/debian/patches/search-provider-cancel-the-current-process-on-new-calcula.patch
714new file mode 100644
715index 0000000..26435e2
716--- /dev/null
717+++ b/debian/patches/search-provider-cancel-the-current-process-on-new-calcula.patch
718@@ -0,0 +1,30 @@
719+From: =?utf-8?b?Ik1hcmNvIFRyZXZpc2FuIChUcmV2acOxbyki?= <mail@3v1n0.net>
720+Date: Thu, 30 Aug 2018 18:47:16 +0200
721+Subject: search-provider: cancel the current process on new calculation
722+ request
723+
724+As there's just one shell running at time, there's no point of supporting
725+parallel calls, we can just safely refer to the last equation as the only one
726+we need to compute.
727+
728+Bug-Ubuntu: https://launchpad.net/bugs/1756826
729+Bug-GNOME: https://gitlab.gnome.org/GNOME/gnome-shell/issues/183
730+Forwarded: https://gitlab.gnome.org/GNOME/gnome-calculator/merge_requests/10
731+Applied-Upstream: yes, 3.31.1
732+---
733+ search-provider/search-provider.vala | 2 ++
734+ 1 file changed, 2 insertions(+)
735+
736+diff --git a/search-provider/search-provider.vala b/search-provider/search-provider.vala
737+index df37b86..a3c57f7 100644
738+--- a/search-provider/search-provider.vala
739++++ b/search-provider/search-provider.vala
740+@@ -86,6 +86,8 @@ public class SearchProvider : Object
741+ // "normalize" input to a format known to double.try_parse
742+ var equation = terms_to_equation (terms).replace (tsep_string, "").replace (decimal, ".");
743+
744++ cancel();
745++
746+ // if the search is a plain number, don't process it
747+ if (double.try_parse (equation)) {
748+ return false;
749diff --git a/debian/patches/search-provider-renew-inactivity-timeout-at-each-calculat.patch b/debian/patches/search-provider-renew-inactivity-timeout-at-each-calculat.patch
750new file mode 100644
751index 0000000..274aae1
752--- /dev/null
753+++ b/debian/patches/search-provider-renew-inactivity-timeout-at-each-calculat.patch
754@@ -0,0 +1,61 @@
755+From: =?utf-8?b?Ik1hcmNvIFRyZXZpc2FuIChUcmV2acOxbyki?= <mail@3v1n0.net>
756+Date: Fri, 24 Aug 2018 07:10:17 +0200
757+Subject: search-provider: renew inactivity timeout at each calculator run
758+
759+As per the async rewrite, now the daemon inactivity timeout might happen
760+when another call has just been done, while we don't want this to be the case.
761+
762+So, everytime we do a subprocess call, let's renew the application timeout.
763+
764+Bug-Ubuntu: https://launchpad.net/bugs/1756826
765+Bug-GNOME: https://gitlab.gnome.org/GNOME/gnome-shell/issues/183
766+Forwarded: https://gitlab.gnome.org/GNOME/gnome-calculator/merge_requests/100
767+Applied-Upstream: yes, 3.31.1
768+---
769+ search-provider/search-provider.vala | 14 +++++++++++++-
770+ 1 file changed, 13 insertions(+), 1 deletion(-)
771+
772+diff --git a/search-provider/search-provider.vala b/search-provider/search-provider.vala
773+index 659f73d..7e54fa6 100644
774+--- a/search-provider/search-provider.vala
775++++ b/search-provider/search-provider.vala
776+@@ -13,7 +13,12 @@
777+ [DBus (name = "org.gnome.Shell.SearchProvider2")]
778+ public class SearchProvider : Object
779+ {
780++ private unowned SearchProviderApp application;
781+ private Cancellable cancellable = new Cancellable ();
782++ public SearchProvider (SearchProviderApp app)
783++ {
784++ application = app;
785++ }
786+
787+ ~SearchProvider ()
788+ {
789+@@ -71,6 +76,8 @@ public class SearchProvider : Object
790+ cancellable = null;
791+ });
792+
793++ application.renew_inactivity_timeout ();
794++
795+ yield subprocess.communicate_utf8_async (null, cancellable, out solution_buf, out stderr_buf);
796+ }
797+ catch (Error e)
798+@@ -197,11 +204,16 @@ public class SearchProviderApp : Application
799+ Object (application_id: "org.gnome.Calculator.SearchProvider",
800+ flags: ApplicationFlags.IS_SERVICE,
801+ inactivity_timeout: 60000);
802++
803++ public void renew_inactivity_timeout ()
804++ {
805++ this.hold ();
806++ this.release ();
807+ }
808+
809+ public override bool dbus_register (DBusConnection connection, string object_path)
810+ {
811+- SearchProvider search_provider = new SearchProvider ();
812++ SearchProvider search_provider = new SearchProvider (this);
813+
814+ try
815+ {
816diff --git a/debian/patches/search-provider-simplify-solve_subprocess.patch b/debian/patches/search-provider-simplify-solve_subprocess.patch
817new file mode 100644
818index 0000000..4f9cde8
819--- /dev/null
820+++ b/debian/patches/search-provider-simplify-solve_subprocess.patch
821@@ -0,0 +1,114 @@
822+From: =?utf-8?b?Ik1hcmNvIFRyZXZpc2FuIChUcmV2acOxbyki?= <mail@3v1n0.net>
823+Date: Fri, 24 Aug 2018 07:31:37 +0200
824+Subject: search-provider: simplify solve_subprocess
825+
826+Only return a subprocess in solve_subprocess and make the callers deal with
827+the actual operation to perform.
828+
829+Bug-Ubuntu: https://launchpad.net/bugs/1756826
830+Bug-GNOME: https://gitlab.gnome.org/GNOME/gnome-shell/issues/183
831+Forwarded: https://gitlab.gnome.org/GNOME/gnome-calculator/merge_requests/10
832+Applied-Upstream: yes, 3.31.1
833+---
834+ search-provider/search-provider.vala | 49 ++++++++++--------------------------
835+ 1 file changed, 13 insertions(+), 36 deletions(-)
836+
837+diff --git a/search-provider/search-provider.vala b/search-provider/search-provider.vala
838+index 9035c58..df37b86 100644
839+--- a/search-provider/search-provider.vala
840++++ b/search-provider/search-provider.vala
841+@@ -39,7 +39,7 @@ public class SearchProvider : Object
842+ return string.joinv (" ", terms);
843+ }
844+
845+- private async Subprocess solve_subprocess (string equation, bool return_solution = false, out string? solution_buf = null) throws Error
846++ private async Subprocess solve_subprocess (string equation) throws Error
847+ {
848+ Subprocess subprocess;
849+ string[] argv = {"gnome-calculator", "--solve"};
850+@@ -52,13 +52,7 @@ public class SearchProvider : Object
851+ {
852+ // Eat output so that it doesn't wind up in the journal. It's
853+ // expected that most searches are not valid calculator input.
854+- var flags = SubprocessFlags.STDERR_PIPE;
855+-
856+- if (return_solution)
857+- {
858+- flags |= SubprocessFlags.STDOUT_PIPE;
859+- }
860+-
861++ var flags = SubprocessFlags.STDOUT_PIPE | SubprocessFlags.STDERR_PIPE;
862+ subprocess = new Subprocess.newv (argv, flags);
863+ }
864+ catch (Error e)
865+@@ -66,31 +60,13 @@ public class SearchProvider : Object
866+ error ("Failed to spawn Calculator: %s", e.message);
867+ }
868+
869+- try
870+- {
871+- string stderr_buf;
872+-
873+- cancellable = new Cancellable ();
874+- cancellable.cancelled.connect (() => {
875+- subprocess.force_exit ();
876+- cancellable = null;
877+- });
878+-
879+- application.renew_inactivity_timeout ();
880++ cancellable = new Cancellable ();
881++ cancellable.cancelled.connect (() => {
882++ subprocess.force_exit ();
883++ cancellable = null;
884++ });
885+
886+- yield subprocess.communicate_utf8_async (null, cancellable, out solution_buf, out stderr_buf);
887+- }
888+- catch (Error e)
889+- {
890+- if (e is IOError.CANCELLED)
891+- {
892+- throw e;
893+- }
894+- else
895+- {
896+- error ("Failed reading result: %s", e.message);
897+- }
898+- }
899++ application.renew_inactivity_timeout ();
900+
901+ return subprocess;
902+ }
903+@@ -115,8 +91,7 @@ public class SearchProvider : Object
904+ return false;
905+ }
906+
907+- var subprocess = yield solve_subprocess (equation);
908+- yield subprocess.wait_check_async ();
909++ (yield solve_subprocess (equation)).wait_check (cancellable);
910+ }
911+ catch (SpawnError e)
912+ {
913+@@ -153,10 +128,12 @@ public class SearchProvider : Object
914+ requires (results.length == 1)
915+ {
916+ string stdout_buf;
917++ string stderr_buf;
918+
919+ try
920+ {
921+- yield solve_subprocess (results[0], true, out stdout_buf);
922++ var subprocess = yield solve_subprocess (results[0]);
923++ yield subprocess.communicate_utf8_async (null, cancellable, out stdout_buf, out stderr_buf);
924+ }
925+ catch (Error e)
926+ {
927+@@ -167,7 +144,7 @@ public class SearchProvider : Object
928+ metadata[0] = new HashTable<string, Variant>(str_hash, str_equal);
929+ metadata[0].insert ("id", results[0]);
930+ metadata[0].insert ("name", results[0] );
931+- metadata[0].insert ("description", " = " + stdout_buf.strip() );
932++ metadata[0].insert ("description", " = " + stdout_buf.strip ());
933+
934+ return metadata;
935+ }
936diff --git a/debian/patches/search-provider-stop-normalizing-the-equation-twice.patch b/debian/patches/search-provider-stop-normalizing-the-equation-twice.patch
937new file mode 100644
938index 0000000..6882583
939--- /dev/null
940+++ b/debian/patches/search-provider-stop-normalizing-the-equation-twice.patch
941@@ -0,0 +1,48 @@
942+From: Pascal Nowack <Pascal.Nowack@gmx.de>
943+Date: Sun, 31 Mar 2019 14:11:16 +0200
944+Subject: search-provider: stop normalizing the equation twice
945+
946+When an equation is given by the g-s overview, g-c
947+will solve this equation, where it will be first
948+normalized and then solved.
949+This is done by running a subprocess, where g-c
950+will call g-c in this subprocess with the
951+"--solve" argument.
952+With this "--solve" argument, the equation will
953+also be normalized.
954+However, when an equation is given by the g-s
955+overview, it will also be normalized in a check,
956+that happens before the solve process, to not to
957+process single numbers given by the g-s overview.
958+This normalized equation will then be used to
959+invoke the subprocess to solve the equation,
960+leading into normalizing the already normalized
961+equation and therefore resulting into wrong
962+results when the equation itself contains
963+decimal numbers.
964+
965+Solve this issue, by invoking the subprocess with
966+the unnormalized equation, instead of the
967+normalized one, to not to normalize the
968+equation twice.
969+
970+Closes: https://gitlab.gnome.org/GNOME/gnome-calculator/issues/104
971+
972+Bug-GNOME: https://gitlab.gnome.org/GNOME/gnome-shell/issues/104
973+---
974+ search-provider/search-provider.vala | 2 +-
975+ 1 file changed, 1 insertion(+), 1 deletion(-)
976+
977+diff --git a/search-provider/search-provider.vala b/search-provider/search-provider.vala
978+index 9823ef7..7f9f51e 100644
979+--- a/search-provider/search-provider.vala
980++++ b/search-provider/search-provider.vala
981+@@ -129,7 +129,7 @@ public class SearchProvider : Object
982+
983+ try
984+ {
985+- var subprocess = yield solve_subprocess (normalized_equation);
986++ var subprocess = yield solve_subprocess (equation);
987+ yield subprocess.communicate_utf8_async (null, cancellable, out result, null);
988+ subprocess.wait_check (cancellable);
989+ }
990diff --git a/debian/patches/series b/debian/patches/series
991index e69de29..f088177 100644
992--- a/debian/patches/series
993+++ b/debian/patches/series
994@@ -0,0 +1,11 @@
995+search-provider-Use-async-calls-cancel-search-on-inactivi.patch
996+search-provider-renew-inactivity-timeout-at-each-calculat.patch
997+search-provider-Use-lower-inactivity-timeout.patch
998+search-provider-simplify-solve_subprocess.patch
999+search-provider-cancel-the-current-process-on-new-calcula.patch
1000+search-provider-cache-equations-avoiding-spawning-calcula.patch
1001+search-provider-cache-only-a-limited-number-of-equations.patch
1002+search-provider-Handle-errors-gracefully.patch
1003+ubuntu/search-provider-Cancel-operations-on-XUbuntuCancel.patch
1004+search-provider-stop-normalizing-the-equation-twice.patch
1005+Use-GLib.List.deep_copy-to-fix-type-argument-mismatch.patch
1006diff --git a/debian/patches/ubuntu/search-provider-Cancel-operations-on-XUbuntuCancel.patch b/debian/patches/ubuntu/search-provider-Cancel-operations-on-XUbuntuCancel.patch
1007new file mode 100644
1008index 0000000..edc9419
1009--- /dev/null
1010+++ b/debian/patches/ubuntu/search-provider-Cancel-operations-on-XUbuntuCancel.patch
1011@@ -0,0 +1,118 @@
1012+From: =?utf-8?b?Ik1hcmNvIFRyZXZpc2FuIChUcmV2acOxbyki?= <mail@3v1n0.net>
1013+Date: Tue, 28 Aug 2018 04:12:20 +0200
1014+Subject: search-provider: Cancel operations on XUbuntuCancel
1015+
1016+Stop process and any computation on XUbuntuCancel method, if the caller
1017+was the same triggering the last operation.
1018+
1019+Fixes LP: #1756826
1020+
1021+Bug-Ubuntu: https://launchpad.net/bugs/1756826
1022+Bug-GNOME: https://gitlab.gnome.org/GNOME/gnome-shell/issues/183
1023+Forwarded: not-needed
1024+---
1025+ search-provider/search-provider.vala | 46 ++++++++++++++++++++++++++++++++----
1026+ 1 file changed, 41 insertions(+), 5 deletions(-)
1027+
1028+diff --git a/search-provider/search-provider.vala b/search-provider/search-provider.vala
1029+index a48c440..9823ef7 100644
1030+--- a/search-provider/search-provider.vala
1031++++ b/search-provider/search-provider.vala
1032+@@ -10,11 +10,33 @@
1033+ * license.
1034+ */
1035+
1036++public class CallerTracker : Object
1037++{
1038++ public BusName? bus { get; set; }
1039++}
1040++
1041++public class Caller
1042++{
1043++ private CallerTracker caller_tracker;
1044++
1045++ public Caller (CallerTracker c, BusName sender)
1046++ {
1047++ caller_tracker = c;
1048++ caller_tracker.bus = sender;
1049++ }
1050++
1051++ ~Caller ()
1052++ {
1053++ caller_tracker.bus = null;
1054++ }
1055++}
1056++
1057+ [DBus (name = "org.gnome.Shell.SearchProvider2")]
1058+ public class SearchProvider : Object
1059+ {
1060+ private unowned SearchProviderApp application;
1061+ private Cancellable cancellable;
1062++ private CallerTracker caller_tracker;
1063+
1064+ private const int MAX_CACHED_OPERATIONS = 10;
1065+ private Queue<string> queued_equations;
1066+@@ -24,6 +46,7 @@ public class SearchProvider : Object
1067+ {
1068+ application = app;
1069+
1070++ caller_tracker = new CallerTracker ();
1071+ queued_equations = new Queue<string> ();
1072+ cached_equations = new HashTable<string, string> (str_hash, str_equal);
1073+ }
1074+@@ -129,8 +152,10 @@ public class SearchProvider : Object
1075+ return true;
1076+ }
1077+
1078+- private async string[] get_result_identifier (string[] terms) throws Error
1079++ private async string[] get_result_identifier (string[] terms, GLib.BusName sender) throws Error
1080+ {
1081++ var owner = new Caller (caller_tracker, sender); (void) owner;
1082++
1083+ /* We have at most one result: the search terms as one string */
1084+ var equation = terms_to_equation (terms);
1085+ if (yield solve_equation (equation))
1086+@@ -139,14 +164,14 @@ public class SearchProvider : Object
1087+ return new string[0];
1088+ }
1089+
1090+- public async string[] get_initial_result_set (string[] terms) throws Error
1091++ public async string[] get_initial_result_set (string[] terms, GLib.BusName sender) throws Error
1092+ {
1093+- return yield get_result_identifier (terms);
1094++ return yield get_result_identifier (terms, sender);
1095+ }
1096+
1097+- public async string[] get_subsearch_result_set (string[] previous_results, string[] terms) throws Error
1098++ public async string[] get_subsearch_result_set (string[] previous_results, string[] terms, GLib.BusName sender) throws Error
1099+ {
1100+- return yield get_result_identifier (terms);
1101++ return yield get_result_identifier (terms, sender);
1102+ }
1103+
1104+ public async HashTable<string, Variant>[] get_result_metas (string[] results, GLib.BusName sender) throws Error
1105+@@ -155,6 +180,8 @@ public class SearchProvider : Object
1106+ string equation;
1107+ string result;
1108+
1109++ var owner = new Caller (caller_tracker, sender); (void) owner;
1110++
1111+ equation = terms_to_equation (results);
1112+
1113+ if (!yield solve_equation (equation))
1114+@@ -172,6 +199,15 @@ public class SearchProvider : Object
1115+ return metadata;
1116+ }
1117+
1118++ public async void x_ubuntu_cancel (BusName sender)
1119++ {
1120++ if (caller_tracker.bus == sender)
1121++ {
1122++ debug ("Cancelling Request");
1123++ cancel ();
1124++ }
1125++ }
1126++
1127+ private static void spawn_and_display_equation (string[] terms) throws Error
1128+ {
1129+ try

Subscribers

People subscribed via source and target branches