diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2020-09-06 09:27:14 +0300 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2020-09-06 09:27:14 +0300 |
commit | 6bd9fbffec920c103d27bf780d60de314316bbd5 (patch) | |
tree | d87aa9226a1a1ed7a6a77652266aae4bbd78cb14 | |
parent | 8d249e27e6dda6423af93aa4368a81b13cd3f451 (diff) |
Added a LookupWidget with background thread
-rw-r--r-- | CMakeLists.txt | 4 | ||||
-rw-r--r-- | src/history.c | 27 | ||||
-rw-r--r-- | src/lookup.c | 39 | ||||
-rw-r--r-- | src/lookup.h | 46 | ||||
-rw-r--r-- | src/ui/listwidget.c | 9 | ||||
-rw-r--r-- | src/ui/lookupwidget.c | 134 | ||||
-rw-r--r-- | src/ui/lookupwidget.h | 30 | ||||
-rw-r--r-- | src/ui/sidebarwidget.c | 2 | ||||
-rw-r--r-- | src/ui/window.c | 3 |
9 files changed, 289 insertions, 5 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 789e32f9..2018c4c1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt | |||
@@ -61,6 +61,8 @@ set (SOURCES | |||
61 | src/gmutil.h | 61 | src/gmutil.h |
62 | src/history.c | 62 | src/history.c |
63 | src/history.h | 63 | src/history.h |
64 | src/lookup.c | ||
65 | src/lookup.h | ||
64 | src/stb_image.h | 66 | src/stb_image.h |
65 | src/stb_truetype.h | 67 | src/stb_truetype.h |
66 | src/visited.c | 68 | src/visited.c |
@@ -74,6 +76,8 @@ set (SOURCES | |||
74 | src/ui/documentwidget.h | 76 | src/ui/documentwidget.h |
75 | src/ui/listwidget.c | 77 | src/ui/listwidget.c |
76 | src/ui/listwidget.h | 78 | src/ui/listwidget.h |
79 | src/ui/lookupwidget.c | ||
80 | src/ui/lookupwidget.h | ||
77 | src/ui/metrics.c | 81 | src/ui/metrics.c |
78 | src/ui/metrics.h | 82 | src/ui/metrics.h |
79 | src/ui/paint.c | 83 | src/ui/paint.c |
diff --git a/src/history.c b/src/history.c index 6e985903..63fa1104 100644 --- a/src/history.c +++ b/src/history.c | |||
@@ -24,6 +24,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
24 | #include "app.h" | 24 | #include "app.h" |
25 | 25 | ||
26 | #include <the_Foundation/file.h> | 26 | #include <the_Foundation/file.h> |
27 | #include <the_Foundation/mutex.h> | ||
27 | #include <the_Foundation/path.h> | 28 | #include <the_Foundation/path.h> |
28 | 29 | ||
29 | static const size_t maxStack_History_ = 50; /* back/forward navigable items */ | 30 | static const size_t maxStack_History_ = 50; /* back/forward navigable items */ |
@@ -52,6 +53,7 @@ iRecentUrl *copy_RecentUrl(const iRecentUrl *d) { | |||
52 | /*----------------------------------------------------------------------------------------------*/ | 53 | /*----------------------------------------------------------------------------------------------*/ |
53 | 54 | ||
54 | struct Impl_History { | 55 | struct Impl_History { |
56 | iMutex *mtx; | ||
55 | iArray recent; /* TODO: should be specific to a DocumentWidget */ | 57 | iArray recent; /* TODO: should be specific to a DocumentWidget */ |
56 | size_t recentPos; /* zero at the latest item */ | 58 | size_t recentPos; /* zero at the latest item */ |
57 | }; | 59 | }; |
@@ -59,6 +61,7 @@ struct Impl_History { | |||
59 | iDefineTypeConstruction(History) | 61 | iDefineTypeConstruction(History) |
60 | 62 | ||
61 | void init_History(iHistory *d) { | 63 | void init_History(iHistory *d) { |
64 | d->mtx = new_Mutex(); | ||
62 | init_Array(&d->recent, sizeof(iRecentUrl)); | 65 | init_Array(&d->recent, sizeof(iRecentUrl)); |
63 | d->recentPos = 0; | 66 | d->recentPos = 0; |
64 | } | 67 | } |
@@ -66,18 +69,22 @@ void init_History(iHistory *d) { | |||
66 | void deinit_History(iHistory *d) { | 69 | void deinit_History(iHistory *d) { |
67 | clear_History(d); | 70 | clear_History(d); |
68 | deinit_Array(&d->recent); | 71 | deinit_Array(&d->recent); |
72 | delete_Mutex(d->mtx); | ||
69 | } | 73 | } |
70 | 74 | ||
71 | iHistory *copy_History(const iHistory *d) { | 75 | iHistory *copy_History(const iHistory *d) { |
76 | lock_Mutex(d->mtx); | ||
72 | iHistory *copy = new_History(); | 77 | iHistory *copy = new_History(); |
73 | iConstForEach(Array, i, &d->recent) { | 78 | iConstForEach(Array, i, &d->recent) { |
74 | pushBack_Array(©->recent, copy_RecentUrl(i.value)); | 79 | pushBack_Array(©->recent, copy_RecentUrl(i.value)); |
75 | } | 80 | } |
76 | copy->recentPos = d->recentPos; | 81 | copy->recentPos = d->recentPos; |
82 | unlock_Mutex(d->mtx); | ||
77 | return copy; | 83 | return copy; |
78 | } | 84 | } |
79 | 85 | ||
80 | void serialize_History(const iHistory *d, iStream *outs) { | 86 | void serialize_History(const iHistory *d, iStream *outs) { |
87 | lock_Mutex(d->mtx); | ||
81 | writeU16_Stream(outs, d->recentPos); | 88 | writeU16_Stream(outs, d->recentPos); |
82 | writeU16_Stream(outs, size_Array(&d->recent)); | 89 | writeU16_Stream(outs, size_Array(&d->recent)); |
83 | iConstForEach(Array, i, &d->recent) { | 90 | iConstForEach(Array, i, &d->recent) { |
@@ -92,10 +99,12 @@ void serialize_History(const iHistory *d, iStream *outs) { | |||
92 | write8_Stream(outs, 0); | 99 | write8_Stream(outs, 0); |
93 | } | 100 | } |
94 | } | 101 | } |
102 | unlock_Mutex(d->mtx); | ||
95 | } | 103 | } |
96 | 104 | ||
97 | void deserialize_History(iHistory *d, iStream *ins) { | 105 | void deserialize_History(iHistory *d, iStream *ins) { |
98 | clear_History(d); | 106 | clear_History(d); |
107 | lock_Mutex(d->mtx); | ||
99 | d->recentPos = readU16_Stream(ins); | 108 | d->recentPos = readU16_Stream(ins); |
100 | size_t count = readU16_Stream(ins); | 109 | size_t count = readU16_Stream(ins); |
101 | while (count--) { | 110 | while (count--) { |
@@ -109,13 +118,16 @@ void deserialize_History(iHistory *d, iStream *ins) { | |||
109 | } | 118 | } |
110 | pushBack_Array(&d->recent, &item); | 119 | pushBack_Array(&d->recent, &item); |
111 | } | 120 | } |
121 | unlock_Mutex(d->mtx); | ||
112 | } | 122 | } |
113 | 123 | ||
114 | void clear_History(iHistory *d) { | 124 | void clear_History(iHistory *d) { |
125 | lock_Mutex(d->mtx); | ||
115 | iForEach(Array, s, &d->recent) { | 126 | iForEach(Array, s, &d->recent) { |
116 | deinit_RecentUrl(s.value); | 127 | deinit_RecentUrl(s.value); |
117 | } | 128 | } |
118 | clear_Array(&d->recent); | 129 | clear_Array(&d->recent); |
130 | unlock_Mutex(d->mtx); | ||
119 | } | 131 | } |
120 | 132 | ||
121 | iRecentUrl *recentUrl_History(iHistory *d, size_t pos) { | 133 | iRecentUrl *recentUrl_History(iHistory *d, size_t pos) { |
@@ -145,23 +157,29 @@ const iString *url_History(const iHistory *d, size_t pos) { | |||
145 | } | 157 | } |
146 | 158 | ||
147 | iRecentUrl *findUrl_History(iHistory *d, const iString *url) { | 159 | iRecentUrl *findUrl_History(iHistory *d, const iString *url) { |
160 | lock_Mutex(d->mtx); | ||
148 | iReverseForEach(Array, i, &d->recent) { | 161 | iReverseForEach(Array, i, &d->recent) { |
149 | if (cmpStringCase_String(url, &((iRecentUrl *) i.value)->url) == 0) { | 162 | if (cmpStringCase_String(url, &((iRecentUrl *) i.value)->url) == 0) { |
163 | unlock_Mutex(d->mtx); | ||
150 | return i.value; | 164 | return i.value; |
151 | } | 165 | } |
152 | } | 166 | } |
167 | unlock_Mutex(d->mtx); | ||
153 | return NULL; | 168 | return NULL; |
154 | } | 169 | } |
155 | 170 | ||
156 | void replace_History(iHistory *d, const iString *url) { | 171 | void replace_History(iHistory *d, const iString *url) { |
172 | lock_Mutex(d->mtx); | ||
157 | /* Update in the history. */ | 173 | /* Update in the history. */ |
158 | iRecentUrl *item = mostRecentUrl_History(d); | 174 | iRecentUrl *item = mostRecentUrl_History(d); |
159 | if (item) { | 175 | if (item) { |
160 | set_String(&item->url, url); | 176 | set_String(&item->url, url); |
161 | } | 177 | } |
178 | unlock_Mutex(d->mtx); | ||
162 | } | 179 | } |
163 | 180 | ||
164 | void add_History(iHistory *d, const iString *url ){ | 181 | void add_History(iHistory *d, const iString *url ){ |
182 | lock_Mutex(d->mtx); | ||
165 | /* Cut the trailing history items. */ | 183 | /* Cut the trailing history items. */ |
166 | if (d->recentPos > 0) { | 184 | if (d->recentPos > 0) { |
167 | for (size_t i = 0; i < d->recentPos - 1; i++) { | 185 | for (size_t i = 0; i < d->recentPos - 1; i++) { |
@@ -183,27 +201,34 @@ void add_History(iHistory *d, const iString *url ){ | |||
183 | remove_Array(&d->recent, 0); | 201 | remove_Array(&d->recent, 0); |
184 | } | 202 | } |
185 | } | 203 | } |
204 | unlock_Mutex(d->mtx); | ||
186 | } | 205 | } |
187 | 206 | ||
188 | iBool goBack_History(iHistory *d) { | 207 | iBool goBack_History(iHistory *d) { |
208 | lock_Mutex(d->mtx); | ||
189 | if (d->recentPos < size_Array(&d->recent) - 1) { | 209 | if (d->recentPos < size_Array(&d->recent) - 1) { |
190 | d->recentPos++; | 210 | d->recentPos++; |
191 | postCommandf_App("open history:1 scroll:%f url:%s", | 211 | postCommandf_App("open history:1 scroll:%f url:%s", |
192 | mostRecentUrl_History(d)->normScrollY, | 212 | mostRecentUrl_History(d)->normScrollY, |
193 | cstr_String(url_History(d, d->recentPos))); | 213 | cstr_String(url_History(d, d->recentPos))); |
214 | unlock_Mutex(d->mtx); | ||
194 | return iTrue; | 215 | return iTrue; |
195 | } | 216 | } |
217 | unlock_Mutex(d->mtx); | ||
196 | return iFalse; | 218 | return iFalse; |
197 | } | 219 | } |
198 | 220 | ||
199 | iBool goForward_History(iHistory *d) { | 221 | iBool goForward_History(iHistory *d) { |
222 | lock_Mutex(d->mtx); | ||
200 | if (d->recentPos > 0) { | 223 | if (d->recentPos > 0) { |
201 | d->recentPos--; | 224 | d->recentPos--; |
202 | postCommandf_App("open history:1 scroll:%f url:%s", | 225 | postCommandf_App("open history:1 scroll:%f url:%s", |
203 | mostRecentUrl_History(d)->normScrollY, | 226 | mostRecentUrl_History(d)->normScrollY, |
204 | cstr_String(url_History(d, d->recentPos))); | 227 | cstr_String(url_History(d, d->recentPos))); |
228 | unlock_Mutex(d->mtx); | ||
205 | return iTrue; | 229 | return iTrue; |
206 | } | 230 | } |
231 | unlock_Mutex(d->mtx); | ||
207 | return iFalse; | 232 | return iFalse; |
208 | } | 233 | } |
209 | 234 | ||
@@ -213,6 +238,7 @@ const iGmResponse *cachedResponse_History(const iHistory *d) { | |||
213 | } | 238 | } |
214 | 239 | ||
215 | void setCachedResponse_History(iHistory *d, const iGmResponse *response) { | 240 | void setCachedResponse_History(iHistory *d, const iGmResponse *response) { |
241 | lock_Mutex(d->mtx); | ||
216 | iRecentUrl *item = mostRecentUrl_History(d); | 242 | iRecentUrl *item = mostRecentUrl_History(d); |
217 | if (item) { | 243 | if (item) { |
218 | delete_GmResponse(item->cachedResponse); | 244 | delete_GmResponse(item->cachedResponse); |
@@ -221,4 +247,5 @@ void setCachedResponse_History(iHistory *d, const iGmResponse *response) { | |||
221 | item->cachedResponse = copy_GmResponse(response); | 247 | item->cachedResponse = copy_GmResponse(response); |
222 | } | 248 | } |
223 | } | 249 | } |
250 | unlock_Mutex(d->mtx); | ||
224 | } | 251 | } |
diff --git a/src/lookup.c b/src/lookup.c new file mode 100644 index 00000000..4f00a66a --- /dev/null +++ b/src/lookup.c | |||
@@ -0,0 +1,39 @@ | |||
1 | /* Copyright 2020 Jaakko Keränen <jaakko.keranen@iki.fi> | ||
2 | |||
3 | Redistribution and use in source and binary forms, with or without | ||
4 | modification, are permitted provided that the following conditions are met: | ||
5 | |||
6 | 1. Redistributions of source code must retain the above copyright notice, this | ||
7 | list of conditions and the following disclaimer. | ||
8 | 2. Redistributions in binary form must reproduce the above copyright notice, | ||
9 | this list of conditions and the following disclaimer in the documentation | ||
10 | and/or other materials provided with the distribution. | ||
11 | |||
12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | ||
13 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
14 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
15 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR | ||
16 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
17 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
18 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
19 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
20 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
21 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | ||
22 | |||
23 | #include "lookup.h" | ||
24 | |||
25 | iDefineTypeConstruction(LookupResult) | ||
26 | |||
27 | void init_LookupResult(iLookupResult *d) { | ||
28 | d->type = none_LookupResultType; | ||
29 | init_String(&d->label); | ||
30 | init_String(&d->url); | ||
31 | init_String(&d->meta); | ||
32 | iZap(d->when); | ||
33 | } | ||
34 | |||
35 | void deinit_LookupResult(iLookupResult *d) { | ||
36 | deinit_String(&d->meta); | ||
37 | deinit_String(&d->url); | ||
38 | deinit_String(&d->label); | ||
39 | } | ||
diff --git a/src/lookup.h b/src/lookup.h new file mode 100644 index 00000000..ecbe0036 --- /dev/null +++ b/src/lookup.h | |||
@@ -0,0 +1,46 @@ | |||
1 | /* Copyright 2020 Jaakko Keränen <jaakko.keranen@iki.fi> | ||
2 | |||
3 | Redistribution and use in source and binary forms, with or without | ||
4 | modification, are permitted provided that the following conditions are met: | ||
5 | |||
6 | 1. Redistributions of source code must retain the above copyright notice, this | ||
7 | list of conditions and the following disclaimer. | ||
8 | 2. Redistributions in binary form must reproduce the above copyright notice, | ||
9 | this list of conditions and the following disclaimer in the documentation | ||
10 | and/or other materials provided with the distribution. | ||
11 | |||
12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | ||
13 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
14 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
15 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR | ||
16 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
17 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
18 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
19 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
20 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
21 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | ||
22 | |||
23 | #pragma once | ||
24 | |||
25 | #include <the_Foundation/string.h> | ||
26 | #include <the_Foundation/time.h> | ||
27 | |||
28 | iDeclareType(LookupResult) | ||
29 | |||
30 | enum iLookupResultType { | ||
31 | none_LookupResultType, | ||
32 | bookmark_LookupResultType, | ||
33 | history_LookupResultType, /* visited URLs */ | ||
34 | content_LookupResultType, /* one of the pages in history, including current page */ | ||
35 | identity_LookupResultType, | ||
36 | }; | ||
37 | |||
38 | struct Impl_LookupResult { | ||
39 | enum iLookupResultType type; | ||
40 | iString label; | ||
41 | iString url; | ||
42 | iString meta; | ||
43 | iTime when; | ||
44 | }; | ||
45 | |||
46 | iDeclareTypeConstruction(LookupResult) | ||
diff --git a/src/ui/listwidget.c b/src/ui/listwidget.c index 64e509ef..3c061bdc 100644 --- a/src/ui/listwidget.c +++ b/src/ui/listwidget.c | |||
@@ -62,7 +62,6 @@ struct Impl_ListWidget { | |||
62 | SDL_Texture *visBuffer[2]; | 62 | SDL_Texture *visBuffer[2]; |
63 | int visBufferIndex; | 63 | int visBufferIndex; |
64 | int visBufferScrollY; | 64 | int visBufferScrollY; |
65 | // iBool visBufferValid; | ||
66 | enum iBufferValidity visBufferValid; | 65 | enum iBufferValidity visBufferValid; |
67 | }; | 66 | }; |
68 | 67 | ||
@@ -70,6 +69,7 @@ void init_ListWidget(iListWidget *d) { | |||
70 | iWidget *w = as_Widget(d); | 69 | iWidget *w = as_Widget(d); |
71 | init_Widget(w); | 70 | init_Widget(w); |
72 | setId_Widget(w, "list"); | 71 | setId_Widget(w, "list"); |
72 | setBackgroundColor_Widget(w, uiBackground_ColorId); /* needed for filling visbuffer */ | ||
73 | setFlags_Widget(w, hover_WidgetFlag, iTrue); | 73 | setFlags_Widget(w, hover_WidgetFlag, iTrue); |
74 | addChild_Widget(w, iClob(d->scroll = new_ScrollWidget())); | 74 | addChild_Widget(w, iClob(d->scroll = new_ScrollWidget())); |
75 | setThumb_ScrollWidget(d->scroll, 0, 0); | 75 | setThumb_ScrollWidget(d->scroll, 0, 0); |
@@ -150,7 +150,6 @@ int scrollPos_ListWidget(const iListWidget *d) { | |||
150 | void setScrollPos_ListWidget(iListWidget *d, int pos) { | 150 | void setScrollPos_ListWidget(iListWidget *d, int pos) { |
151 | d->scrollY = pos; | 151 | d->scrollY = pos; |
152 | d->hoverItem = iInvalidPos; | 152 | d->hoverItem = iInvalidPos; |
153 | // invalidate_ListWidget(d); | ||
154 | d->visBufferValid = partial_BufferValidity; | 153 | d->visBufferValid = partial_BufferValidity; |
155 | refresh_Widget(as_Widget(d)); | 154 | refresh_Widget(as_Widget(d)); |
156 | } | 155 | } |
@@ -166,7 +165,6 @@ void scrollOffset_ListWidget(iListWidget *d, int offset) { | |||
166 | if (oldScroll != d->scrollY) { | 165 | if (oldScroll != d->scrollY) { |
167 | d->hoverItem = iInvalidPos; | 166 | d->hoverItem = iInvalidPos; |
168 | updateVisible_ListWidget(d); | 167 | updateVisible_ListWidget(d); |
169 | //invalidate_ListWidget(d); | ||
170 | d->visBufferValid = partial_BufferValidity; | 168 | d->visBufferValid = partial_BufferValidity; |
171 | refresh_Widget(as_Widget(d)); | 169 | refresh_Widget(as_Widget(d)); |
172 | } | 170 | } |
@@ -178,6 +176,9 @@ static int visCount_ListWidget_(const iListWidget *d) { | |||
178 | } | 176 | } |
179 | 177 | ||
180 | static iRanges visRange_ListWidget_(const iListWidget *d) { | 178 | static iRanges visRange_ListWidget_(const iListWidget *d) { |
179 | if (d->itemHeight == 0) { | ||
180 | return (iRanges){ 0, 0 }; | ||
181 | } | ||
181 | iRanges vis = { d->scrollY / d->itemHeight, 0 }; | 182 | iRanges vis = { d->scrollY / d->itemHeight, 0 }; |
182 | vis.end = iMin(size_PtrArray(&d->items), vis.start + visCount_ListWidget_(d)); | 183 | vis.end = iMin(size_PtrArray(&d->items), vis.start + visCount_ListWidget_(d)); |
183 | return vis; | 184 | return vis; |
@@ -186,7 +187,7 @@ static iRanges visRange_ListWidget_(const iListWidget *d) { | |||
186 | size_t itemIndex_ListWidget(const iListWidget *d, iInt2 pos) { | 187 | size_t itemIndex_ListWidget(const iListWidget *d, iInt2 pos) { |
187 | const iRect bounds = innerBounds_Widget(constAs_Widget(d)); | 188 | const iRect bounds = innerBounds_Widget(constAs_Widget(d)); |
188 | pos.y -= top_Rect(bounds) - d->scrollY; | 189 | pos.y -= top_Rect(bounds) - d->scrollY; |
189 | if (pos.y < 0) return iInvalidPos; | 190 | if (pos.y < 0 || !d->itemHeight) return iInvalidPos; |
190 | size_t index = pos.y / d->itemHeight; | 191 | size_t index = pos.y / d->itemHeight; |
191 | if (index >= size_Array(&d->items)) return iInvalidPos; | 192 | if (index >= size_Array(&d->items)) return iInvalidPos; |
192 | return index; | 193 | return index; |
diff --git a/src/ui/lookupwidget.c b/src/ui/lookupwidget.c new file mode 100644 index 00000000..d2550c16 --- /dev/null +++ b/src/ui/lookupwidget.c | |||
@@ -0,0 +1,134 @@ | |||
1 | /* Copyright 2020 Jaakko Keränen <jaakko.keranen@iki.fi> | ||
2 | |||
3 | Redistribution and use in source and binary forms, with or without | ||
4 | modification, are permitted provided that the following conditions are met: | ||
5 | |||
6 | 1. Redistributions of source code must retain the above copyright notice, this | ||
7 | list of conditions and the following disclaimer. | ||
8 | 2. Redistributions in binary form must reproduce the above copyright notice, | ||
9 | this list of conditions and the following disclaimer in the documentation | ||
10 | and/or other materials provided with the distribution. | ||
11 | |||
12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | ||
13 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
14 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
15 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR | ||
16 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
17 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
18 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
19 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
20 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
21 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | ||
22 | |||
23 | #include "lookupwidget.h" | ||
24 | #include "lookup.h" | ||
25 | #include "listwidget.h" | ||
26 | |||
27 | #include <the_Foundation/mutex.h> | ||
28 | #include <the_Foundation/thread.h> | ||
29 | |||
30 | iDeclareType(LookupJob) | ||
31 | |||
32 | struct Impl_LookupJob { | ||
33 | iString term; | ||
34 | iPtrArray results; | ||
35 | }; | ||
36 | |||
37 | static void init_LookupJob(iLookupJob *d) { | ||
38 | init_String(&d->term); | ||
39 | init_PtrArray(&d->results); | ||
40 | } | ||
41 | |||
42 | static void deinit_LookupJob(iLookupJob *d) { | ||
43 | iForEach(PtrArray, i, &d->results) { | ||
44 | delete_LookupResult(i.ptr); | ||
45 | } | ||
46 | deinit_PtrArray(&d->results); | ||
47 | deinit_String(&d->term); | ||
48 | } | ||
49 | |||
50 | iDefineTypeConstruction(LookupJob) | ||
51 | |||
52 | struct Impl_LookupWidget { | ||
53 | iWidget widget; | ||
54 | iListWidget *list; | ||
55 | iThread *work; | ||
56 | iCondition jobAvailable; /* wakes up the work thread */ | ||
57 | iMutex *mtx; | ||
58 | iString nextJob; | ||
59 | iLookupJob *finishedJob; | ||
60 | }; | ||
61 | |||
62 | static iThreadResult worker_LookupWidget_(iThread *thread) { | ||
63 | iLookupWidget *d = userData_Thread(thread); | ||
64 | lock_Mutex(d->mtx); | ||
65 | for (;;) { | ||
66 | wait_Condition(&d->jobAvailable, d->mtx); | ||
67 | if (isEmpty_String(&d->nextJob)) { | ||
68 | break; /* Time to quit. */ | ||
69 | } | ||
70 | iLookupJob *job = new_LookupJob(); | ||
71 | set_String(&job->term, &d->nextJob); | ||
72 | clear_String(&d->nextJob); | ||
73 | unlock_Mutex(d->mtx); | ||
74 | /* Do the lookup. */ { | ||
75 | |||
76 | } | ||
77 | /* Submit the result. */ | ||
78 | lock_Mutex(d->mtx); | ||
79 | if (d->finishedJob) { | ||
80 | /* Previous results haven't been taken yet. */ | ||
81 | delete_LookupJob(d->finishedJob); | ||
82 | } | ||
83 | d->finishedJob = job; | ||
84 | } | ||
85 | unlock_Mutex(d->mtx); | ||
86 | printf("[LookupWidget] worker has quit\n"); fflush(stdout); | ||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | iDefineObjectConstruction(LookupWidget) | ||
91 | |||
92 | void init_LookupWidget(iLookupWidget *d) { | ||
93 | iWidget *w = as_Widget(d); | ||
94 | init_Widget(w); | ||
95 | setId_Widget(w, "lookup"); | ||
96 | setFlags_Widget(w, resizeChildren_WidgetFlag, iTrue); | ||
97 | d->list = addChild_Widget(w, iClob(new_ListWidget())); | ||
98 | d->work = new_Thread(worker_LookupWidget_); | ||
99 | setUserData_Thread(d->work, d); | ||
100 | init_Condition(&d->jobAvailable); | ||
101 | d->mtx = new_Mutex(); | ||
102 | init_String(&d->nextJob); | ||
103 | d->finishedJob = NULL; | ||
104 | } | ||
105 | |||
106 | void deinit_LookupWidget(iLookupWidget *d) { | ||
107 | /* Stop the worker. */ { | ||
108 | iGuardMutex(d->mtx, { | ||
109 | clear_String(&d->nextJob); | ||
110 | signal_Condition(&d->jobAvailable); | ||
111 | }); | ||
112 | join_Thread(d->work); | ||
113 | iRelease(d->work); | ||
114 | } | ||
115 | delete_LookupJob(d->finishedJob); | ||
116 | deinit_String(&d->nextJob); | ||
117 | delete_Mutex(d->mtx); | ||
118 | deinit_Condition(&d->jobAvailable); | ||
119 | } | ||
120 | |||
121 | static void draw_LookupWidget_(const iLookupWidget *d) { | ||
122 | const iWidget *w = constAs_Widget(d); | ||
123 | draw_Widget(w); | ||
124 | } | ||
125 | |||
126 | static iBool processEvent_LookupWidget_(iLookupWidget *d, const SDL_Event *ev) { | ||
127 | iWidget *w = as_Widget(d); | ||
128 | return processEvent_Widget(w, ev); | ||
129 | } | ||
130 | |||
131 | iBeginDefineSubclass(LookupWidget, Widget) | ||
132 | .draw = (iAny *) draw_LookupWidget_, | ||
133 | .processEvent = (iAny *) processEvent_LookupWidget_, | ||
134 | iEndDefineSubclass(LookupWidget) | ||
diff --git a/src/ui/lookupwidget.h b/src/ui/lookupwidget.h new file mode 100644 index 00000000..31bcbcb9 --- /dev/null +++ b/src/ui/lookupwidget.h | |||
@@ -0,0 +1,30 @@ | |||
1 | /* Copyright 2020 Jaakko Keränen <jaakko.keranen@iki.fi> | ||
2 | |||
3 | Redistribution and use in source and binary forms, with or without | ||
4 | modification, are permitted provided that the following conditions are met: | ||
5 | |||
6 | 1. Redistributions of source code must retain the above copyright notice, this | ||
7 | list of conditions and the following disclaimer. | ||
8 | 2. Redistributions in binary form must reproduce the above copyright notice, | ||
9 | this list of conditions and the following disclaimer in the documentation | ||
10 | and/or other materials provided with the distribution. | ||
11 | |||
12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | ||
13 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
14 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
15 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR | ||
16 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
17 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
18 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
19 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
20 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
21 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | ||
22 | |||
23 | #pragma once | ||
24 | |||
25 | #include "widget.h" | ||
26 | |||
27 | iDeclareWidgetClass(LookupWidget) | ||
28 | iDeclareObjectConstruction(LookupWidget) | ||
29 | |||
30 | |||
diff --git a/src/ui/sidebarwidget.c b/src/ui/sidebarwidget.c index 50b8ef9b..e84967cc 100644 --- a/src/ui/sidebarwidget.c +++ b/src/ui/sidebarwidget.c | |||
@@ -503,7 +503,7 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev) | |||
503 | const iBool wasChanged = setMode_SidebarWidget(d, arg_Command(cmd)); | 503 | const iBool wasChanged = setMode_SidebarWidget(d, arg_Command(cmd)); |
504 | updateItems_SidebarWidget_(d); | 504 | updateItems_SidebarWidget_(d); |
505 | if ((argLabel_Command(cmd, "show") && !isVisible_Widget(w)) || | 505 | if ((argLabel_Command(cmd, "show") && !isVisible_Widget(w)) || |
506 | (argLabel_Command(cmd, "toggle") && !wasChanged)) { | 506 | (argLabel_Command(cmd, "toggle") && (!isVisible_Widget(w) || !wasChanged))) { |
507 | postCommand_App("sidebar.toggle"); | 507 | postCommand_App("sidebar.toggle"); |
508 | } | 508 | } |
509 | scrollOffset_ListWidget(d->list, 0); | 509 | scrollOffset_ListWidget(d->list, 0); |
diff --git a/src/ui/window.c b/src/ui/window.c index dabf80de..78567bb5 100644 --- a/src/ui/window.c +++ b/src/ui/window.c | |||
@@ -26,6 +26,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
26 | #include "inputwidget.h" | 26 | #include "inputwidget.h" |
27 | #include "documentwidget.h" | 27 | #include "documentwidget.h" |
28 | #include "sidebarwidget.h" | 28 | #include "sidebarwidget.h" |
29 | #include "lookupwidget.h" | ||
29 | #include "embedded.h" | 30 | #include "embedded.h" |
30 | #include "command.h" | 31 | #include "command.h" |
31 | #include "paint.h" | 32 | #include "paint.h" |
@@ -404,6 +405,8 @@ static void setupUserInterface_Window(iWindow *d) { | |||
404 | addChild_Widget(searchBar, iClob(newIcon_LabelWidget(" \u2b9d ", 'g', KMOD_PRIMARY | KMOD_SHIFT, "find.prev"))); | 405 | addChild_Widget(searchBar, iClob(newIcon_LabelWidget(" \u2b9d ", 'g', KMOD_PRIMARY | KMOD_SHIFT, "find.prev"))); |
405 | addChild_Widget(searchBar, iClob(newIcon_LabelWidget("\u2a2f", SDLK_ESCAPE, 0, "find.close"))); | 406 | addChild_Widget(searchBar, iClob(newIcon_LabelWidget("\u2a2f", SDLK_ESCAPE, 0, "find.close"))); |
406 | } | 407 | } |
408 | iLookupWidget *lookup = new_LookupWidget(); | ||
409 | addChildFlags_Widget(d->root, iClob(lookup), hidden_WidgetFlag); | ||
407 | iWidget *tabsMenu = makeMenu_Widget(d->root, | 410 | iWidget *tabsMenu = makeMenu_Widget(d->root, |
408 | (iMenuItem[]){ | 411 | (iMenuItem[]){ |
409 | { "Close Tab", 0, 0, "tabs.close" }, | 412 | { "Close Tab", 0, 0, "tabs.close" }, |