Merge lp:~3v1n0/unity/fix-load-icon-crash-926658 into lp:unity
- fix-load-icon-crash-926658
- Merge into trunk
Status: | Rejected |
---|---|
Rejected by: | Marco Trevisan (Treviño) |
Proposed branch: | lp:~3v1n0/unity/fix-load-icon-crash-926658 |
Merge into: | lp:unity |
Prerequisite: | lp:~3v1n0/unity/barrier-timeout |
Diff against target: |
641 lines (+150/-144) 7 files modified
UnityCore/ModelRowAdaptor.h (+1/-1) dash/LensView.cpp (+40/-5) dash/LensView.h (+4/-0) dash/ResultRendererTile.cpp (+80/-98) dash/ResultRendererTile.h (+1/-2) dash/ResultView.cpp (+21/-32) dash/ResultView.h (+3/-6) |
To merge this branch: | bzr merge lp:~3v1n0/unity/fix-load-icon-crash-926658 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Michal Hruby (community) | Needs Fixing | ||
Francis Ginther | Abstain | ||
jenkins (community) | continuous-integration | Needs Fixing | |
Review via email: mp+116091@code.launchpad.net |
This proposal supersedes a proposal from 2012-07-20.
Commit message
ResultRendererTile: don't crash in LoadIcon if row.renderer<
Description of the change
In ResultRendererT
The implementation of that depends on dee_model_
So, at this point, even if it would not the best solution, it's better to add a safety check to prevent crashes.
Marco Trevisan (Treviño) (3v1n0) wrote : | # |
Yes, that's true... But according to the stacktraces I got (attached to the bug), the crash is not happening because dee_model_get_tag returns an unreferenced pointer, but because it's returning a null one...
I'm wondering if that could happen that could be happen this:
ResultRendererT
ResultRendererT
ResultRendererT
But it would be weird as all seems done in the same thread...
jenkins (martin-mrazik+qa) wrote : | # |
PASSED: Continuous integration, rev:2540
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
Michal Hruby (mhr3) wrote : | # |
As you alone said in the comment, the renderer is set in Preload(), so the only explanation is that the model is already invalid at that point, but dee notices that and ignores the call (while logging a critical), doing dee_model_
Other times dee doesn't notice that the model is invalid, and crashes inside itself.
jenkins (martin-mrazik+qa) wrote : | # |
PASSED: Continuous integration, rev:2545
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
Marco Trevisan (Treviño) (3v1n0) wrote : | # |
Well, it's the same I thought, but I'm not getting that on the stacktrace...
However, protecting us from possible invalid pointers is something we should do in any case.
jenkins (martin-mrazik+qa) wrote : | # |
PASSED: Continuous integration, rev:2547
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
Marco Trevisan (Treviño) (3v1n0) wrote : | # |
I've reffed the model in ModelRowAdaptor... As you said it's not the full solution, but it's something we can safely do anyway. Let me know if this is better for you.
jenkins (martin-mrazik+qa) wrote : | # |
PASSED: Continuous integration, rev:2551
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
jenkins (martin-mrazik+qa) wrote : | # |
PASSED: Continuous integration, rev:2552
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
Michal Hruby (mhr3) wrote : | # |
> I've reffed the model in ModelRowAdaptor... As you said it's not the full
> solution, but it's something we can safely do anyway. Let me know if this is
> better for you.
As mentioned on IRC, I'd rather see a *single* weak ref on the model in LensView? than this. (since adding a reference for each model row isn't a good idea)
jenkins (martin-mrazik+qa) wrote : | # |
FAILED: Continuous integration, rev:2556
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Francis Ginther (fginther) wrote : | # |
Review was claimed by accident, please ignore.
Michal Hruby (mhr3) wrote : | # |
Discussed on IRC, but so make sure it doesn't get lost:
1) the model can change, you need to listen to changed signal
2) in the weak notify callback you're basically iterating over the model, which you can't since the model is already dead
Preview Diff
1 | === modified file 'UnityCore/ModelRowAdaptor.h' | |||
2 | --- UnityCore/ModelRowAdaptor.h 2012-06-19 16:47:56 +0000 | |||
3 | +++ UnityCore/ModelRowAdaptor.h 2012-08-10 12:37:21 +0000 | |||
4 | @@ -21,8 +21,8 @@ | |||
5 | 21 | #define UNITY_MODEL_ROW_H | 21 | #define UNITY_MODEL_ROW_H |
6 | 22 | 22 | ||
7 | 23 | #include <string> | 23 | #include <string> |
8 | 24 | |||
9 | 25 | #include <dee.h> | 24 | #include <dee.h> |
10 | 25 | #include "GLibWrapper.h" | ||
11 | 26 | 26 | ||
12 | 27 | namespace unity | 27 | namespace unity |
13 | 28 | { | 28 | { |
14 | 29 | 29 | ||
15 | === modified file 'dash/LensView.cpp' | |||
16 | --- dash/LensView.cpp 2012-06-18 02:57:23 +0000 | |||
17 | +++ dash/LensView.cpp 2012-08-10 12:37:21 +0000 | |||
18 | @@ -123,6 +123,7 @@ | |||
19 | 123 | , filters_expanded(false) | 123 | , filters_expanded(false) |
20 | 124 | , can_refine_search(false) | 124 | , can_refine_search(false) |
21 | 125 | , no_results_active_(false) | 125 | , no_results_active_(false) |
22 | 126 | , results_model_(nullptr) | ||
23 | 126 | {} | 127 | {} |
24 | 127 | 128 | ||
25 | 128 | LensView::LensView(Lens::Ptr lens, nux::Area* show_filters) | 129 | LensView::LensView(Lens::Ptr lens, nux::Area* show_filters) |
26 | @@ -132,6 +133,7 @@ | |||
27 | 132 | , lens_(lens) | 133 | , lens_(lens) |
28 | 133 | , initial_activation_(true) | 134 | , initial_activation_(true) |
29 | 134 | , no_results_active_(false) | 135 | , no_results_active_(false) |
30 | 136 | , results_model_(nullptr) | ||
31 | 135 | { | 137 | { |
32 | 136 | SetupViews(show_filters); | 138 | SetupViews(show_filters); |
33 | 137 | SetupCategories(); | 139 | SetupCategories(); |
34 | @@ -175,6 +177,14 @@ | |||
35 | 175 | 177 | ||
36 | 176 | } | 178 | } |
37 | 177 | 179 | ||
38 | 180 | LensView::~LensView() | ||
39 | 181 | { | ||
40 | 182 | if (DEE_IS_MODEL(results_model_)) | ||
41 | 183 | { | ||
42 | 184 | g_object_weak_unref(G_OBJECT(results_model_), (GWeakNotify)LensView::OnModelDestroyed, this); | ||
43 | 185 | } | ||
44 | 186 | } | ||
45 | 187 | |||
46 | 178 | void LensView::SetupViews(nux::Area* show_filters) | 188 | void LensView::SetupViews(nux::Area* show_filters) |
47 | 179 | { | 189 | { |
48 | 180 | dash::Style& style = dash::Style::Instance(); | 190 | dash::Style& style = dash::Style::Instance(); |
49 | @@ -231,12 +241,39 @@ | |||
50 | 231 | OnCategoryAdded(categories->RowAtIndex(i)); | 241 | OnCategoryAdded(categories->RowAtIndex(i)); |
51 | 232 | } | 242 | } |
52 | 233 | 243 | ||
53 | 244 | void LensView::OnModelDestroyed(LensView* self, DeeModel* was_here) | ||
54 | 245 | { | ||
55 | 246 | for (auto group : self->categories_) | ||
56 | 247 | { | ||
57 | 248 | auto grid = static_cast<ResultViewGrid*>(group->GetChildView()); | ||
58 | 249 | self->counts_[group] -= grid->GetResultList().size(); | ||
59 | 250 | grid->ClearResults(); | ||
60 | 251 | self->UpdateCounts(group); | ||
61 | 252 | } | ||
62 | 253 | } | ||
63 | 254 | |||
64 | 234 | void LensView::SetupResults() | 255 | void LensView::SetupResults() |
65 | 235 | { | 256 | { |
66 | 236 | Results::Ptr results = lens_->results; | 257 | Results::Ptr results = lens_->results; |
67 | 237 | results->result_added.connect(sigc::mem_fun(this, &LensView::OnResultAdded)); | 258 | results->result_added.connect(sigc::mem_fun(this, &LensView::OnResultAdded)); |
68 | 238 | results->result_removed.connect(sigc::mem_fun(this, &LensView::OnResultRemoved)); | 259 | results->result_removed.connect(sigc::mem_fun(this, &LensView::OnResultRemoved)); |
69 | 239 | 260 | ||
70 | 261 | results->model.changed.connect([this] (glib::Object<DeeModel> model) | ||
71 | 262 | { | ||
72 | 263 | if (DEE_IS_MODEL(results_model_)) | ||
73 | 264 | { | ||
74 | 265 | g_object_weak_unref(G_OBJECT(results_model_), (GWeakNotify)LensView::OnModelDestroyed, this); | ||
75 | 266 | } | ||
76 | 267 | |||
77 | 268 | results_model_ = nullptr; | ||
78 | 269 | |||
79 | 270 | if (model.IsType(DEE_TYPE_MODEL)) | ||
80 | 271 | { | ||
81 | 272 | results_model_ = model; | ||
82 | 273 | g_object_weak_ref(glib::object_cast<GObject>(model), (GWeakNotify)LensView::OnModelDestroyed, this); | ||
83 | 274 | } | ||
84 | 275 | }); | ||
85 | 276 | |||
86 | 240 | for (unsigned int i = 0; i < results->count(); ++i) | 277 | for (unsigned int i = 0; i < results->count(); ++i) |
87 | 241 | OnResultAdded(results->RowAtIndex(i)); | 278 | OnResultAdded(results->RowAtIndex(i)); |
88 | 242 | } | 279 | } |
89 | @@ -285,7 +322,7 @@ | |||
90 | 285 | grid->SetModelRenderer(new ResultRendererHorizontalTile(NUX_TRACKER_LOCATION)); | 322 | grid->SetModelRenderer(new ResultRendererHorizontalTile(NUX_TRACKER_LOCATION)); |
91 | 286 | grid->horizontal_spacing = CARD_VIEW_GAP_HORIZ; | 323 | grid->horizontal_spacing = CARD_VIEW_GAP_HORIZ; |
92 | 287 | grid->vertical_spacing = CARD_VIEW_GAP_VERT; | 324 | grid->vertical_spacing = CARD_VIEW_GAP_VERT; |
94 | 288 | } | 325 | } |
95 | 289 | else | 326 | else |
96 | 290 | grid->SetModelRenderer(new ResultRendererTile(NUX_TRACKER_LOCATION)); | 327 | grid->SetModelRenderer(new ResultRendererTile(NUX_TRACKER_LOCATION)); |
97 | 291 | 328 | ||
98 | @@ -305,8 +342,7 @@ | |||
99 | 305 | PlacesGroup* group = categories_.at(result.category_index); | 342 | PlacesGroup* group = categories_.at(result.category_index); |
100 | 306 | ResultViewGrid* grid = static_cast<ResultViewGrid*>(group->GetChildView()); | 343 | ResultViewGrid* grid = static_cast<ResultViewGrid*>(group->GetChildView()); |
101 | 307 | 344 | ||
104 | 308 | std::string uri = result.uri; | 345 | LOG_TRACE(logger) << "Result added: " << result.uri(); |
103 | 309 | LOG_TRACE(logger) << "Result added: " << uri; | ||
105 | 310 | 346 | ||
106 | 311 | grid->AddResult(const_cast<Result&>(result)); | 347 | grid->AddResult(const_cast<Result&>(result)); |
107 | 312 | counts_[group]++; | 348 | counts_[group]++; |
108 | @@ -329,8 +365,7 @@ | |||
109 | 329 | PlacesGroup* group = categories_.at(result.category_index); | 365 | PlacesGroup* group = categories_.at(result.category_index); |
110 | 330 | ResultViewGrid* grid = static_cast<ResultViewGrid*>(group->GetChildView()); | 366 | ResultViewGrid* grid = static_cast<ResultViewGrid*>(group->GetChildView()); |
111 | 331 | 367 | ||
114 | 332 | std::string uri = result.uri; | 368 | LOG_TRACE(logger) << "Result removed: " << result.uri(); |
113 | 333 | LOG_TRACE(logger) << "Result removed: " << uri; | ||
115 | 334 | 369 | ||
116 | 335 | grid->RemoveResult(const_cast<Result&>(result)); | 370 | grid->RemoveResult(const_cast<Result&>(result)); |
117 | 336 | counts_[group]--; | 371 | counts_[group]--; |
118 | 337 | 372 | ||
119 | === modified file 'dash/LensView.h' | |||
120 | --- dash/LensView.h 2012-06-18 02:57:23 +0000 | |||
121 | +++ dash/LensView.h 2012-08-10 12:37:21 +0000 | |||
122 | @@ -52,6 +52,7 @@ | |||
123 | 52 | public: | 52 | public: |
124 | 53 | LensView(); | 53 | LensView(); |
125 | 54 | LensView(Lens::Ptr lens, nux::Area* show_filters); | 54 | LensView(Lens::Ptr lens, nux::Area* show_filters); |
126 | 55 | ~LensView(); | ||
127 | 55 | 56 | ||
128 | 56 | CategoryGroups& categories() { return categories_; } | 57 | CategoryGroups& categories() { return categories_; } |
129 | 57 | FilterBar* filter_bar() const { return filter_bar_; } | 58 | FilterBar* filter_bar() const { return filter_bar_; } |
130 | @@ -101,6 +102,8 @@ | |||
131 | 101 | 102 | ||
132 | 102 | std::string get_search_string() const; | 103 | std::string get_search_string() const; |
133 | 103 | 104 | ||
134 | 105 | static void OnModelDestroyed(LensView* self, DeeModel* was_here); | ||
135 | 106 | |||
136 | 104 | private: | 107 | private: |
137 | 105 | Lens::Ptr lens_; | 108 | Lens::Ptr lens_; |
138 | 106 | CategoryGroups categories_; | 109 | CategoryGroups categories_; |
139 | @@ -116,6 +119,7 @@ | |||
140 | 116 | nux::VLayout* fscroll_layout_; | 119 | nux::VLayout* fscroll_layout_; |
141 | 117 | FilterBar* filter_bar_; | 120 | FilterBar* filter_bar_; |
142 | 118 | nux::StaticCairoText* no_results_; | 121 | nux::StaticCairoText* no_results_; |
143 | 122 | DeeModel* results_model_; | ||
144 | 119 | 123 | ||
145 | 120 | UBusManager ubus_manager_; | 124 | UBusManager ubus_manager_; |
146 | 121 | glib::Source::UniquePtr fix_rendering_idle_; | 125 | glib::Source::UniquePtr fix_rendering_idle_; |
147 | 122 | 126 | ||
148 | === modified file 'dash/ResultRendererTile.cpp' | |||
149 | --- dash/ResultRendererTile.cpp 2012-06-18 02:57:23 +0000 | |||
150 | +++ dash/ResultRendererTile.cpp 2012-08-10 12:37:21 +0000 | |||
151 | @@ -21,14 +21,10 @@ | |||
152 | 21 | */ | 21 | */ |
153 | 22 | 22 | ||
154 | 23 | 23 | ||
155 | 24 | #include <sstream> // for ostringstream | ||
156 | 25 | #include "ResultRendererTile.h" | 24 | #include "ResultRendererTile.h" |
157 | 26 | 25 | ||
158 | 27 | #include <boost/algorithm/string.hpp> | ||
159 | 28 | |||
160 | 29 | #include <pango/pango.h> | 26 | #include <pango/pango.h> |
161 | 30 | #include <pango/pangocairo.h> | 27 | #include <pango/pangocairo.h> |
162 | 31 | #include <gdk/gdk.h> | ||
163 | 32 | #include <gtk/gtk.h> | 28 | #include <gtk/gtk.h> |
164 | 33 | 29 | ||
165 | 34 | #include <NuxCore/Logger.h> | 30 | #include <NuxCore/Logger.h> |
166 | @@ -40,19 +36,18 @@ | |||
167 | 40 | #include "unity-shared/IconTexture.h" | 36 | #include "unity-shared/IconTexture.h" |
168 | 41 | #include "unity-shared/TextureCache.h" | 37 | #include "unity-shared/TextureCache.h" |
169 | 42 | 38 | ||
170 | 43 | |||
171 | 44 | namespace | ||
172 | 45 | { | ||
173 | 46 | bool neko; | ||
174 | 47 | } | ||
175 | 48 | |||
176 | 49 | namespace unity | 39 | namespace unity |
177 | 50 | { | 40 | { |
178 | 51 | namespace | 41 | namespace |
179 | 52 | { | 42 | { |
180 | 53 | nux::logging::Logger logger("unity.dash.results"); | 43 | nux::logging::Logger logger("unity.dash.results"); |
181 | 44 | const std::string DEFAULT_GICON = ". GThemedIcon text-x-preview"; | ||
182 | 54 | 45 | ||
183 | 55 | const int FONT_SIZE = 10; | 46 | const int FONT_SIZE = 10; |
184 | 47 | bool neko = false; | ||
185 | 48 | const std::string neko_env = {0x55, 0x4e, 0x49, 0x54, 0x59, 0x5f, 0x4e, 0x45, 0x4b, 0x4f}; | ||
186 | 49 | const std::string neko_src = {0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x6c, 0x61, 0x63, | ||
187 | 50 | 0x65, 0x6b, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x2e, 0x63, 0x6f, 0x6d}; | ||
188 | 56 | } | 51 | } |
189 | 57 | 52 | ||
190 | 58 | namespace dash | 53 | namespace dash |
191 | @@ -69,11 +64,7 @@ | |||
192 | 69 | dash::Style& style = dash::Style::Instance(); | 64 | dash::Style& style = dash::Style::Instance(); |
193 | 70 | width = style.GetTileWidth(); | 65 | width = style.GetTileWidth(); |
194 | 71 | height = style.GetTileHeight(); | 66 | height = style.GetTileHeight(); |
200 | 72 | 67 | neko = g_getenv(neko_env.c_str()); | |
196 | 73 | gsize tmp; | ||
197 | 74 | gchar* tmp1 = (gchar*)g_base64_decode("VU5JVFlfTkVLTw==", &tmp); | ||
198 | 75 | neko = (g_getenv(tmp1)); | ||
199 | 76 | g_free (tmp1); | ||
201 | 77 | 68 | ||
202 | 78 | // pre-load the highlight texture | 69 | // pre-load the highlight texture |
203 | 79 | // try and get a texture from the texture cache | 70 | // try and get a texture from the texture cache |
204 | @@ -84,10 +75,6 @@ | |||
205 | 84 | sigc::mem_fun(this, &ResultRendererTile::DrawHighlight)); | 75 | sigc::mem_fun(this, &ResultRendererTile::DrawHighlight)); |
206 | 85 | } | 76 | } |
207 | 86 | 77 | ||
208 | 87 | ResultRendererTile::~ResultRendererTile() | ||
209 | 88 | { | ||
210 | 89 | } | ||
211 | 90 | |||
212 | 91 | void ResultRendererTile::Render(nux::GraphicsEngine& GfxContext, | 78 | void ResultRendererTile::Render(nux::GraphicsEngine& GfxContext, |
213 | 92 | Result& row, | 79 | Result& row, |
214 | 93 | ResultRendererState state, | 80 | ResultRendererState state, |
215 | @@ -95,7 +82,8 @@ | |||
216 | 95 | int x_offset, int y_offset) | 82 | int x_offset, int y_offset) |
217 | 96 | { | 83 | { |
218 | 97 | TextureContainer* container = row.renderer<TextureContainer*>(); | 84 | TextureContainer* container = row.renderer<TextureContainer*>(); |
220 | 98 | if (container == nullptr) | 85 | |
221 | 86 | if (!container) | ||
222 | 99 | return; | 87 | return; |
223 | 100 | 88 | ||
224 | 101 | dash::Style& style = dash::Style::Instance(); | 89 | dash::Style& style = dash::Style::Instance(); |
225 | @@ -105,7 +93,7 @@ | |||
226 | 105 | nux::TexCoordXForm texxform; | 93 | nux::TexCoordXForm texxform; |
227 | 106 | 94 | ||
228 | 107 | int icon_width, icon_height; | 95 | int icon_width, icon_height; |
230 | 108 | if (container->icon == nullptr) | 96 | if (!container->icon) |
231 | 109 | { | 97 | { |
232 | 110 | icon_width = icon_height = tile_icon_size; | 98 | icon_width = icon_height = tile_icon_size; |
233 | 111 | } | 99 | } |
234 | @@ -230,7 +218,7 @@ | |||
235 | 230 | 218 | ||
236 | 231 | void ResultRendererTile::Preload(Result& row) | 219 | void ResultRendererTile::Preload(Result& row) |
237 | 232 | { | 220 | { |
239 | 233 | if (row.renderer<TextureContainer*>() == nullptr) | 221 | if (!row.renderer<TextureContainer*>()) |
240 | 234 | { | 222 | { |
241 | 235 | row.set_renderer(new TextureContainer()); | 223 | row.set_renderer(new TextureContainer()); |
242 | 236 | LoadIcon(row); | 224 | LoadIcon(row); |
243 | @@ -240,52 +228,53 @@ | |||
244 | 240 | 228 | ||
245 | 241 | void ResultRendererTile::Unload(Result& row) | 229 | void ResultRendererTile::Unload(Result& row) |
246 | 242 | { | 230 | { |
249 | 243 | TextureContainer *container = row.renderer<TextureContainer*>(); | 231 | delete row.renderer<TextureContainer*>(); |
248 | 244 | delete container; | ||
250 | 245 | row.set_renderer<TextureContainer*>(nullptr); | 232 | row.set_renderer<TextureContainer*>(nullptr); |
251 | 246 | } | 233 | } |
252 | 247 | 234 | ||
253 | 248 | void ResultRendererTile::LoadIcon(Result& row) | 235 | void ResultRendererTile::LoadIcon(Result& row) |
254 | 249 | { | 236 | { |
294 | 250 | Style& style = Style::Instance(); | 237 | auto container = row.renderer<TextureContainer*>(); |
295 | 251 | std::string const& icon_hint = row.icon_hint; | 238 | |
296 | 252 | #define DEFAULT_GICON ". GThemedIcon text-x-preview" | 239 | if (!container) |
297 | 253 | std::string icon_name; | 240 | { |
298 | 254 | if (G_UNLIKELY(neko)) | 241 | LOG_ERROR(logger) << "No valid container for Result " << row.name() << " with URI " |
299 | 255 | { | 242 | << row.uri(); |
300 | 256 | int tmp1 = style.GetTileIconSize() + (rand() % 16) - 8; | 243 | return; |
301 | 257 | gsize tmp3; | 244 | } |
302 | 258 | gchar* tmp2 = (gchar*)g_base64_decode("aHR0cDovL3BsYWNla2l0dGVuLmNvbS8laS8laS8=", &tmp3); | 245 | |
303 | 259 | gchar* tmp4 = g_strdup_printf(tmp2, tmp1, tmp1); | 246 | int icon_size = Style::Instance().GetTileIconSize(); |
304 | 260 | icon_name = tmp4; | 247 | std::string icon_name = row.icon_hint(); |
305 | 261 | g_free(tmp4); | 248 | |
306 | 262 | g_free(tmp2); | 249 | if (neko) |
307 | 263 | } | 250 | { |
308 | 264 | else | 251 | auto tmp = std::to_string(icon_size + (rand() % 16) - 8); |
309 | 265 | { | 252 | icon_name = neko_src + '/' + tmp + '/' + tmp; |
310 | 266 | icon_name = !icon_hint.empty() ? icon_hint : DEFAULT_GICON; | 253 | } |
311 | 267 | } | 254 | else if (icon_name.empty()) |
312 | 268 | 255 | { | |
313 | 269 | GIcon* icon = g_icon_new_for_string(icon_name.c_str(), NULL); | 256 | icon_name = DEFAULT_GICON; |
314 | 270 | TextureContainer* container = row.renderer<TextureContainer*>(); | 257 | } |
315 | 271 | 258 | ||
316 | 272 | IconLoader::IconLoaderCallback slot = sigc::bind(sigc::mem_fun(this, &ResultRendererTile::IconLoaded), icon_hint, row); | 259 | auto slot = sigc::bind(sigc::mem_fun(this, &ResultRendererTile::IconLoaded), row); |
317 | 273 | 260 | ||
318 | 274 | if (g_strrstr(icon_name.c_str(), "://")) | 261 | if (icon_name.find("://") != std::string::npos) |
319 | 275 | { | 262 | { |
320 | 276 | container->slot_handle = IconLoader::GetDefault().LoadFromURI(icon_name, style.GetTileIconSize(), slot); | 263 | container->slot_handle = IconLoader::GetDefault().LoadFromURI(icon_name, icon_size, slot); |
321 | 277 | } | 264 | } |
322 | 278 | else if (G_IS_ICON(icon)) | 265 | else |
323 | 279 | { | 266 | { |
324 | 280 | container->slot_handle = IconLoader::GetDefault().LoadFromGIconString(icon_name, style.GetTileIconSize(), slot); | 267 | glib::Object<GIcon> icon(g_icon_new_for_string(icon_name.c_str(), nullptr)); |
325 | 281 | } | 268 | |
326 | 282 | else | 269 | if (icon.IsType(G_TYPE_ICON)) |
327 | 283 | { | 270 | { |
328 | 284 | container->slot_handle = IconLoader::GetDefault().LoadFromIconName(icon_name, style.GetTileIconSize(), slot); | 271 | container->slot_handle = IconLoader::GetDefault().LoadFromGIconString(icon_name, icon_size, slot); |
329 | 285 | } | 272 | } |
330 | 286 | 273 | else | |
331 | 287 | if (icon != NULL) | 274 | { |
332 | 288 | g_object_unref(icon); | 275 | container->slot_handle = IconLoader::GetDefault().LoadFromIconName(icon_name, icon_size, slot); |
333 | 276 | } | ||
334 | 277 | } | ||
335 | 289 | } | 278 | } |
336 | 290 | 279 | ||
337 | 291 | nux::BaseTexture* ResultRendererTile::CreateTextureCallback(std::string const& texid, | 280 | nux::BaseTexture* ResultRendererTile::CreateTextureCallback(std::string const& texid, |
338 | @@ -405,20 +394,20 @@ | |||
339 | 405 | void ResultRendererTile::IconLoaded(std::string const& texid, | 394 | void ResultRendererTile::IconLoaded(std::string const& texid, |
340 | 406 | unsigned size, | 395 | unsigned size, |
341 | 407 | glib::Object<GdkPixbuf> const& pixbuf, | 396 | glib::Object<GdkPixbuf> const& pixbuf, |
342 | 408 | std::string icon_name, | ||
343 | 409 | Result& row) | 397 | Result& row) |
344 | 410 | { | 398 | { |
345 | 411 | TextureContainer *container = row.renderer<TextureContainer*>(); | 399 | TextureContainer *container = row.renderer<TextureContainer*>(); |
347 | 412 | Style& style = Style::Instance(); | 400 | int icon_size = Style::Instance().GetTileIconSize(); |
348 | 413 | 401 | ||
349 | 414 | if (pixbuf && container) | 402 | if (pixbuf && container) |
350 | 415 | { | 403 | { |
351 | 404 | std::string const& icon_name = row.icon_hint(); | ||
352 | 416 | TextureCache& cache = TextureCache::GetDefault(); | 405 | TextureCache& cache = TextureCache::GetDefault(); |
354 | 417 | BaseTexturePtr texture(cache.FindTexture(icon_name, style.GetTileIconSize(), style.GetTileIconSize(), | 406 | BaseTexturePtr texture(cache.FindTexture(icon_name, icon_size, icon_size, |
355 | 418 | sigc::bind(sigc::mem_fun(this, &ResultRendererTile::CreateTextureCallback), pixbuf))); | 407 | sigc::bind(sigc::mem_fun(this, &ResultRendererTile::CreateTextureCallback), pixbuf))); |
356 | 419 | 408 | ||
357 | 420 | std::string blur_texid = icon_name + "_blurred"; | 409 | std::string blur_texid = icon_name + "_blurred"; |
359 | 421 | BaseTexturePtr texture_blurred(cache.FindTexture(blur_texid, style.GetTileIconSize(), style.GetTileIconSize(), | 410 | BaseTexturePtr texture_blurred(cache.FindTexture(blur_texid, icon_size, icon_size, |
360 | 422 | sigc::bind(sigc::mem_fun(this, &ResultRendererTile::CreateBlurredTextureCallback), pixbuf))); | 411 | sigc::bind(sigc::mem_fun(this, &ResultRendererTile::CreateBlurredTextureCallback), pixbuf))); |
361 | 423 | 412 | ||
362 | 424 | BaseTexturePtr texture_prelight(cache.FindTexture("resultview_prelight", texture->GetWidth() + highlight_padding*2, texture->GetHeight() + highlight_padding*2, sigc::mem_fun(this, &ResultRendererTile::DrawHighlight))); | 413 | BaseTexturePtr texture_prelight(cache.FindTexture("resultview_prelight", texture->GetWidth() + highlight_padding*2, texture->GetHeight() + highlight_padding*2, sigc::mem_fun(this, &ResultRendererTile::DrawHighlight))); |
363 | @@ -426,17 +415,15 @@ | |||
364 | 426 | container->icon = texture; | 415 | container->icon = texture; |
365 | 427 | container->blurred_icon = texture_blurred; | 416 | container->blurred_icon = texture_blurred; |
366 | 428 | container->prelight = texture_prelight; | 417 | container->prelight = texture_prelight; |
367 | 418 | container->slot_handle = 0; | ||
368 | 429 | 419 | ||
369 | 430 | NeedsRedraw.emit(); | 420 | NeedsRedraw.emit(); |
370 | 431 | |||
371 | 432 | if (container) | ||
372 | 433 | container->slot_handle = 0; | ||
373 | 434 | } | 421 | } |
374 | 435 | else if (container) | 422 | else if (container) |
375 | 436 | { | 423 | { |
376 | 437 | // we need to load a missing icon | 424 | // we need to load a missing icon |
379 | 438 | IconLoader::IconLoaderCallback slot = sigc::bind(sigc::mem_fun(this, &ResultRendererTile::IconLoaded), icon_name, row); | 425 | IconLoader::IconLoaderCallback slot = sigc::bind(sigc::mem_fun(this, &ResultRendererTile::IconLoaded), row); |
380 | 439 | container->slot_handle = IconLoader::GetDefault().LoadFromGIconString(". GThemedIcon text-x-preview", style.GetTileIconSize(), slot); | 426 | container->slot_handle = IconLoader::GetDefault().LoadFromGIconString(DEFAULT_GICON, icon_size, slot); |
381 | 440 | } | 427 | } |
382 | 441 | 428 | ||
383 | 442 | } | 429 | } |
384 | @@ -444,29 +431,31 @@ | |||
385 | 444 | 431 | ||
386 | 445 | void ResultRendererTile::LoadText(Result& row) | 432 | void ResultRendererTile::LoadText(Result& row) |
387 | 446 | { | 433 | { |
388 | 434 | TextureContainer *container = row.renderer<TextureContainer*>(); | ||
389 | 435 | |||
390 | 436 | if (!container) | ||
391 | 437 | return; | ||
392 | 438 | |||
393 | 439 | GdkScreen* screen = gdk_screen_get_default(); | ||
394 | 447 | Style& style = Style::Instance(); | 440 | Style& style = Style::Instance(); |
395 | 448 | nux::CairoGraphics _cairoGraphics(CAIRO_FORMAT_ARGB32, | 441 | nux::CairoGraphics _cairoGraphics(CAIRO_FORMAT_ARGB32, |
396 | 449 | style.GetTileWidth() - (padding * 2), | 442 | style.GetTileWidth() - (padding * 2), |
397 | 450 | style.GetTileHeight() - style.GetTileIconSize() - spacing); | 443 | style.GetTileHeight() - style.GetTileIconSize() - spacing); |
398 | 451 | 444 | ||
399 | 445 | glib::String font; | ||
400 | 446 | g_object_get(gtk_settings_get_default(), "gtk-font-name", &font, nullptr); | ||
401 | 447 | |||
402 | 448 | int dpi = -1; | ||
403 | 449 | g_object_get(gtk_settings_get_default(), "gtk-xft-dpi", &dpi, nullptr); | ||
404 | 450 | |||
405 | 452 | cairo_t* cr = _cairoGraphics.GetContext(); | 451 | cairo_t* cr = _cairoGraphics.GetContext(); |
406 | 453 | |||
407 | 454 | PangoLayout* layout = NULL; | ||
408 | 455 | PangoFontDescription* desc = NULL; | ||
409 | 456 | PangoContext* pango_context = NULL; | ||
410 | 457 | GdkScreen* screen = gdk_screen_get_default(); // not ref'ed | ||
411 | 458 | glib::String font; | ||
412 | 459 | int dpi = -1; | ||
413 | 460 | |||
414 | 461 | g_object_get(gtk_settings_get_default(), "gtk-font-name", &font, NULL); | ||
415 | 462 | g_object_get(gtk_settings_get_default(), "gtk-xft-dpi", &dpi, NULL); | ||
416 | 463 | |||
417 | 464 | cairo_set_font_options(cr, gdk_screen_get_font_options(screen)); | 452 | cairo_set_font_options(cr, gdk_screen_get_font_options(screen)); |
421 | 465 | layout = pango_cairo_create_layout(cr); | 453 | glib::Object<PangoLayout> layout(pango_cairo_create_layout(cr)); |
422 | 466 | desc = pango_font_description_from_string(font.Value()); | 454 | std::shared_ptr<PangoFontDescription> desc(pango_font_description_from_string(font), |
423 | 467 | pango_font_description_set_size (desc, FONT_SIZE * PANGO_SCALE); | 455 | pango_font_description_free); |
424 | 456 | pango_font_description_set_size (desc.get(), FONT_SIZE * PANGO_SCALE); | ||
425 | 468 | 457 | ||
427 | 469 | pango_layout_set_font_description(layout, desc); | 458 | pango_layout_set_font_description(layout, desc.get()); |
428 | 470 | pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER); | 459 | pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER); |
429 | 471 | 460 | ||
430 | 472 | pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR); | 461 | pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR); |
431 | @@ -474,17 +463,14 @@ | |||
432 | 474 | pango_layout_set_width(layout, (style.GetTileWidth() - (padding * 2))* PANGO_SCALE); | 463 | pango_layout_set_width(layout, (style.GetTileWidth() - (padding * 2))* PANGO_SCALE); |
433 | 475 | pango_layout_set_height(layout, -2); | 464 | pango_layout_set_height(layout, -2); |
434 | 476 | 465 | ||
437 | 477 | char *escaped_text = g_markup_escape_text(row.name().c_str() , -1); | 466 | glib::String escaped_text(g_markup_escape_text(row.name().c_str(), -1)); |
436 | 478 | |||
438 | 479 | pango_layout_set_markup(layout, escaped_text, -1); | 467 | pango_layout_set_markup(layout, escaped_text, -1); |
439 | 480 | 468 | ||
443 | 481 | g_free (escaped_text); | 469 | PangoContext* pango_context = pango_layout_get_context(layout); // is not ref'ed |
441 | 482 | |||
442 | 483 | pango_context = pango_layout_get_context(layout); // is not ref'ed | ||
444 | 484 | pango_cairo_context_set_font_options(pango_context, | 470 | pango_cairo_context_set_font_options(pango_context, |
445 | 485 | gdk_screen_get_font_options(screen)); | 471 | gdk_screen_get_font_options(screen)); |
446 | 486 | pango_cairo_context_set_resolution(pango_context, | 472 | pango_cairo_context_set_resolution(pango_context, |
448 | 487 | dpi == -1 ? 96.0f : dpi/(float) PANGO_SCALE); | 473 | dpi == -1 ? 96.0f : dpi/static_cast<float>(PANGO_SCALE)); |
449 | 488 | pango_layout_context_changed(layout); | 474 | pango_layout_context_changed(layout); |
450 | 489 | 475 | ||
451 | 490 | cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); | 476 | cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); |
452 | @@ -497,13 +483,9 @@ | |||
453 | 497 | pango_cairo_show_layout(cr, layout); | 483 | pango_cairo_show_layout(cr, layout); |
454 | 498 | 484 | ||
455 | 499 | // clean up | 485 | // clean up |
456 | 500 | pango_font_description_free(desc); | ||
457 | 501 | g_object_unref(layout); | ||
458 | 502 | cairo_destroy(cr); | 486 | cairo_destroy(cr); |
459 | 503 | 487 | ||
463 | 504 | TextureContainer *container = row.renderer<TextureContainer*>(); | 488 | container->text = texture_ptr_from_cairo_graphics(_cairoGraphics); |
461 | 505 | if (container) | ||
462 | 506 | container->text = texture_ptr_from_cairo_graphics(_cairoGraphics); | ||
464 | 507 | } | 489 | } |
465 | 508 | 490 | ||
466 | 509 | 491 | ||
467 | 510 | 492 | ||
468 | === modified file 'dash/ResultRendererTile.h' | |||
469 | --- dash/ResultRendererTile.h 2012-07-04 02:37:23 +0000 | |||
470 | +++ dash/ResultRendererTile.h 2012-08-10 12:37:21 +0000 | |||
471 | @@ -67,7 +67,6 @@ | |||
472 | 67 | NUX_DECLARE_OBJECT_TYPE(ResultRendererTile, ResultRenderer); | 67 | NUX_DECLARE_OBJECT_TYPE(ResultRendererTile, ResultRenderer); |
473 | 68 | 68 | ||
474 | 69 | ResultRendererTile(NUX_FILE_LINE_PROTO); | 69 | ResultRendererTile(NUX_FILE_LINE_PROTO); |
475 | 70 | ~ResultRendererTile(); | ||
476 | 71 | 70 | ||
477 | 72 | virtual void Render(nux::GraphicsEngine& GfxContext, | 71 | virtual void Render(nux::GraphicsEngine& GfxContext, |
478 | 73 | Result& row, | 72 | Result& row, |
479 | @@ -93,7 +92,7 @@ | |||
480 | 93 | //icon loading callbacks | 92 | //icon loading callbacks |
481 | 94 | void IconLoaded(std::string const& texid, unsigned size, | 93 | void IconLoaded(std::string const& texid, unsigned size, |
482 | 95 | glib::Object<GdkPixbuf> const& pixbuf, | 94 | glib::Object<GdkPixbuf> const& pixbuf, |
484 | 96 | std::string icon_name, Result& row); | 95 | Result& row); |
485 | 97 | nux::BaseTexture* CreateTextureCallback(std::string const& texid, | 96 | nux::BaseTexture* CreateTextureCallback(std::string const& texid, |
486 | 98 | int width, int height, | 97 | int width, int height, |
487 | 99 | glib::Object<GdkPixbuf> const& pixbuf); | 98 | glib::Object<GdkPixbuf> const& pixbuf); |
488 | 100 | 99 | ||
489 | === modified file 'dash/ResultView.cpp' | |||
490 | --- dash/ResultView.cpp 2012-07-30 16:22:53 +0000 | |||
491 | +++ dash/ResultView.cpp 2012-08-10 12:37:21 +0000 | |||
492 | @@ -24,9 +24,7 @@ | |||
493 | 24 | #include "ResultView.h" | 24 | #include "ResultView.h" |
494 | 25 | #include "unity-shared/IntrospectableWrappers.h" | 25 | #include "unity-shared/IntrospectableWrappers.h" |
495 | 26 | #include <UnityCore/Variant.h> | 26 | #include <UnityCore/Variant.h> |
499 | 27 | #include <Nux/HLayout.h> | 27 | #include <Nux/Layout.h> |
497 | 28 | #include <Nux/VLayout.h> | ||
498 | 29 | #include <Nux/Button.h> | ||
500 | 30 | #include <NuxCore/Logger.h> | 28 | #include <NuxCore/Logger.h> |
501 | 31 | 29 | ||
502 | 32 | namespace unity | 30 | namespace unity |
503 | @@ -43,12 +41,10 @@ | |||
504 | 43 | ResultView::ResultView(NUX_FILE_LINE_DECL) | 41 | ResultView::ResultView(NUX_FILE_LINE_DECL) |
505 | 44 | : View(NUX_FILE_LINE_PARAM) | 42 | : View(NUX_FILE_LINE_PARAM) |
506 | 45 | , expanded(true) | 43 | , expanded(true) |
507 | 46 | , renderer_(NULL) | ||
508 | 47 | { | 44 | { |
509 | 48 | expanded.changed.connect([&](bool value) | 45 | expanded.changed.connect([&](bool value) |
510 | 49 | { | 46 | { |
511 | 50 | QueueRelayout(); | 47 | QueueRelayout(); |
512 | 51 | NeedRedraw(); | ||
513 | 52 | }); | 48 | }); |
514 | 53 | } | 49 | } |
515 | 54 | 50 | ||
516 | @@ -60,28 +56,17 @@ | |||
517 | 60 | { | 56 | { |
518 | 61 | renderer_->Unload(result); | 57 | renderer_->Unload(result); |
519 | 62 | } | 58 | } |
520 | 63 | |||
521 | 64 | renderer_->UnReference(); | ||
522 | 65 | } | 59 | } |
523 | 66 | 60 | ||
524 | 67 | void ResultView::Draw(nux::GraphicsEngine& GfxContext, bool force_draw) | 61 | void ResultView::Draw(nux::GraphicsEngine& GfxContext, bool force_draw) |
528 | 68 | { | 62 | {} |
526 | 69 | |||
527 | 70 | } | ||
529 | 71 | 63 | ||
530 | 72 | void ResultView::SetModelRenderer(ResultRenderer* renderer) | 64 | void ResultView::SetModelRenderer(ResultRenderer* renderer) |
531 | 73 | { | 65 | { |
532 | 74 | if (renderer_ != NULL) | ||
533 | 75 | renderer_->UnReference(); | ||
534 | 76 | |||
535 | 77 | renderer_ = renderer; | 66 | renderer_ = renderer; |
541 | 78 | renderer->NeedsRedraw.connect([&]() | 67 | renderer_->NeedsRedraw.connect(sigc::mem_fun(this, &ResultView::QueueDraw)); |
537 | 79 | { | ||
538 | 80 | NeedRedraw(); | ||
539 | 81 | }); | ||
540 | 82 | renderer_->SinkReference(); | ||
542 | 83 | 68 | ||
544 | 84 | NeedRedraw(); | 69 | QueueDraw(); |
545 | 85 | } | 70 | } |
546 | 86 | 71 | ||
547 | 87 | void ResultView::AddResult(Result& result) | 72 | void ResultView::AddResult(Result& result) |
548 | @@ -89,40 +74,44 @@ | |||
549 | 89 | results_.push_back(result); | 74 | results_.push_back(result); |
550 | 90 | renderer_->Preload(result); | 75 | renderer_->Preload(result); |
551 | 91 | 76 | ||
553 | 92 | NeedRedraw(); | 77 | QueueDraw(); |
554 | 93 | } | 78 | } |
555 | 94 | 79 | ||
556 | 95 | void ResultView::RemoveResult(Result& result) | 80 | void ResultView::RemoveResult(Result& result) |
557 | 96 | { | 81 | { |
560 | 97 | ResultList::iterator it; | 82 | std::string const& uri = result.uri; |
559 | 98 | std::string uri = result.uri; | ||
561 | 99 | 83 | ||
563 | 100 | for (it = results_.begin(); it != results_.end(); ++it) | 84 | for (auto it = results_.begin(); it != results_.end(); ++it) |
564 | 101 | { | 85 | { |
566 | 102 | if (result.uri == (*it).uri) | 86 | if (it->uri == uri) |
567 | 103 | { | 87 | { |
568 | 104 | results_.erase(it); | 88 | results_.erase(it); |
569 | 105 | break; | 89 | break; |
570 | 106 | } | 90 | } |
571 | 107 | } | 91 | } |
572 | 92 | |||
573 | 108 | renderer_->Unload(result); | 93 | renderer_->Unload(result); |
574 | 109 | } | 94 | } |
575 | 110 | 95 | ||
577 | 111 | ResultView::ResultList ResultView::GetResultList() | 96 | void ResultView::ClearResults() |
578 | 97 | { | ||
579 | 98 | for (Result& result : results_) | ||
580 | 99 | { | ||
581 | 100 | renderer_->Unload(result); | ||
582 | 101 | } | ||
583 | 102 | |||
584 | 103 | results_.clear(); | ||
585 | 104 | } | ||
586 | 105 | |||
587 | 106 | ResultView::ResultList const& ResultView::GetResultList() const | ||
588 | 112 | { | 107 | { |
589 | 113 | return results_; | 108 | return results_; |
590 | 114 | } | 109 | } |
591 | 115 | 110 | ||
592 | 116 | 111 | ||
593 | 117 | long ResultView::ComputeContentSize() | ||
594 | 118 | { | ||
595 | 119 | return View::ComputeContentSize(); | ||
596 | 120 | } | ||
597 | 121 | |||
598 | 122 | |||
599 | 123 | void ResultView::DrawContent(nux::GraphicsEngine& GfxContent, bool force_draw) | 112 | void ResultView::DrawContent(nux::GraphicsEngine& GfxContent, bool force_draw) |
600 | 124 | { | 113 | { |
602 | 125 | nux::Geometry base = GetGeometry(); | 114 | nux::Geometry const& base = GetGeometry(); |
603 | 126 | GfxContent.PushClippingRectangle(base); | 115 | GfxContent.PushClippingRectangle(base); |
604 | 127 | 116 | ||
605 | 128 | if (GetCompositionLayout()) | 117 | if (GetCompositionLayout()) |
606 | 129 | 118 | ||
607 | === modified file 'dash/ResultView.h' | |||
608 | --- dash/ResultView.h 2012-07-04 02:37:23 +0000 | |||
609 | +++ dash/ResultView.h 2012-08-10 12:37:21 +0000 | |||
610 | @@ -25,9 +25,6 @@ | |||
611 | 25 | 25 | ||
612 | 26 | #include <Nux/Nux.h> | 26 | #include <Nux/Nux.h> |
613 | 27 | #include <Nux/View.h> | 27 | #include <Nux/View.h> |
614 | 28 | #include <dee.h> | ||
615 | 29 | |||
616 | 30 | #include <UnityCore/GLibSignal.h> | ||
617 | 31 | #include <UnityCore/Results.h> | 28 | #include <UnityCore/Results.h> |
618 | 32 | 29 | ||
619 | 33 | #include "unity-shared/Introspectable.h" | 30 | #include "unity-shared/Introspectable.h" |
620 | @@ -51,8 +48,9 @@ | |||
621 | 51 | 48 | ||
622 | 52 | void AddResult(Result& result); | 49 | void AddResult(Result& result); |
623 | 53 | void RemoveResult(Result& result); | 50 | void RemoveResult(Result& result); |
624 | 51 | void ClearResults(); | ||
625 | 54 | 52 | ||
627 | 55 | ResultList GetResultList (); | 53 | ResultList const& GetResultList() const; |
628 | 56 | 54 | ||
629 | 57 | nux::Property<bool> expanded; | 55 | nux::Property<bool> expanded; |
630 | 58 | nux::Property<int> results_per_row; | 56 | nux::Property<int> results_per_row; |
631 | @@ -66,10 +64,9 @@ | |||
632 | 66 | protected: | 64 | protected: |
633 | 67 | virtual void Draw(nux::GraphicsEngine& GfxContext, bool force_draw); | 65 | virtual void Draw(nux::GraphicsEngine& GfxContext, bool force_draw); |
634 | 68 | virtual void DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw); | 66 | virtual void DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw); |
635 | 69 | virtual long ComputeContentSize(); | ||
636 | 70 | 67 | ||
637 | 71 | // properties | 68 | // properties |
639 | 72 | ResultRenderer* renderer_; | 69 | nux::ObjectPtr<ResultRenderer> renderer_; |
640 | 73 | ResultList results_; | 70 | ResultList results_; |
641 | 74 | IntrospectableList introspectable_children_; | 71 | IntrospectableList introspectable_children_; |
642 | 75 | 72 |
Sorry, but I don't like this one bit, dee_model_get_tag can crash if the passed model is not valid (already unreferenced). IMO guarding against null is not going to help, you'll just push the crash to a different place (in the better case, in worse you'll mask the underlying problem completely and there'll be even more random crashes).