Merge lp:~3v1n0/unity/forcequit-dialog into lp:unity
- forcequit-dialog
- Merge into trunk
Status: | Merged | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Approved by: | Christopher Townsend | ||||||||||||
Approved revision: | no longer in the source branch. | ||||||||||||
Merged at revision: | 3763 | ||||||||||||
Proposed branch: | lp:~3v1n0/unity/forcequit-dialog | ||||||||||||
Merge into: | lp:unity | ||||||||||||
Diff against target: |
1199 lines (+1077/-1) 10 files modified
decorations/CMakeLists.txt (+1/-0) decorations/DecoratedWindow.cpp (+27/-1) decorations/DecorationsForceQuitDialog.cpp (+455/-0) decorations/DecorationsForceQuitDialog.h (+53/-0) decorations/DecorationsManager.cpp (+14/-0) decorations/DecorationsPriv.h (+4/-0) po/POTFILES.in (+1/-0) resources/sheet_style_close_focused.svg (+177/-0) resources/sheet_style_close_focused_prelight.svg (+177/-0) resources/sheet_style_close_focused_pressed.svg (+168/-0) |
||||||||||||
To merge this branch: | bzr merge lp:~3v1n0/unity/forcequit-dialog | ||||||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Eleni Maria Stea (community) | Approve | ||
PS Jenkins bot (community) | continuous-integration | Approve | |
Review via email: mp+213832@code.launchpad.net |
Commit message
ForceQuitDialog: add a new "sheet style" dialog that is shown when a window hangs
Listen to compiz toolkit events and prompt a dialog that allows to force-quit an
hanging application.
Description of the change
The internal implementation is done using a custom gtk dialog that can be themed as SheetStyleDialo
The reason why I've used gtk is that we needed an actual modal window that respects the parent position and stacking (and this can't be done with Nux; while usind DecorationWidgets was possible but it needed too much work).
There are two strings to translate (the others two area already in the langpack):
- "This window is not responding"
- "Do you want to force the application to exit, or wait for it to respond?"
Christopher Townsend (townsend) wrote : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:3762
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Preview Diff
1 | === modified file 'decorations/CMakeLists.txt' |
2 | --- decorations/CMakeLists.txt 2014-02-07 22:24:04 +0000 |
3 | +++ decorations/CMakeLists.txt 2014-04-02 13:15:24 +0000 |
4 | @@ -33,6 +33,7 @@ |
5 | DecorationsMenuLayout.cpp |
6 | DecorationsMenuEntry.cpp |
7 | DecorationsMenuDropdown.cpp |
8 | + DecorationsForceQuitDialog.cpp |
9 | DecorationsDataPool.cpp |
10 | ) |
11 | |
12 | |
13 | === modified file 'decorations/DecoratedWindow.cpp' |
14 | --- decorations/DecoratedWindow.cpp 2014-03-12 21:57:09 +0000 |
15 | +++ decorations/DecoratedWindow.cpp 2014-04-02 13:15:24 +0000 |
16 | @@ -19,6 +19,7 @@ |
17 | |
18 | #include <NuxCore/Logger.h> |
19 | #include "DecorationsPriv.h" |
20 | +#include "DecorationsForceQuitDialog.h" |
21 | #include "DecorationsEdgeBorders.h" |
22 | #include "DecorationsGrabEdge.h" |
23 | #include "DecorationsWindowButton.h" |
24 | @@ -47,7 +48,7 @@ |
25 | , frame_(0) |
26 | , dirty_geo_(true) |
27 | , monitor_(0) |
28 | - , cv_(unity::Settings::Instance().em()) |
29 | + , cv_(Settings::Instance().em()) |
30 | { |
31 | active.changed.connect([this] (bool active) { |
32 | bg_textures_.clear(); |
33 | @@ -709,6 +710,30 @@ |
34 | } |
35 | } |
36 | |
37 | +void Window::Impl::UpdateForceQuitDialogPosition() |
38 | +{ |
39 | + if (force_quit_) |
40 | + force_quit_->UpdateDialogPosition(); |
41 | +} |
42 | + |
43 | +void Window::Impl::ShowForceQuitDialog(bool show, Time time) |
44 | +{ |
45 | + if (show) |
46 | + { |
47 | + if (!force_quit_) |
48 | + { |
49 | + force_quit_ = std::make_shared<ForceQuitDialog>(win_, time); |
50 | + force_quit_->close_request.connect([this] { force_quit_.reset(); }); |
51 | + } |
52 | + |
53 | + force_quit_->time = time; |
54 | + } |
55 | + else |
56 | + { |
57 | + force_quit_.reset(); |
58 | + } |
59 | +} |
60 | + |
61 | // Public APIs |
62 | |
63 | Window::Window(CompWindow* cwin) |
64 | @@ -765,6 +790,7 @@ |
65 | impl_->UpdateMonitor(); |
66 | impl_->ComputeShadowQuads(); |
67 | impl_->UpdateDecorationTextures(); |
68 | + impl_->UpdateForceQuitDialogPosition(); |
69 | impl_->dirty_geo_ = false; |
70 | } |
71 | |
72 | |
73 | === added file 'decorations/DecorationsForceQuitDialog.cpp' |
74 | --- decorations/DecorationsForceQuitDialog.cpp 1970-01-01 00:00:00 +0000 |
75 | +++ decorations/DecorationsForceQuitDialog.cpp 2014-04-02 13:15:24 +0000 |
76 | @@ -0,0 +1,455 @@ |
77 | +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- |
78 | +/* |
79 | + * Copyright (C) 2014 Canonical Ltd |
80 | + * |
81 | + * This program is free software: you can redistribute it and/or modify |
82 | + * it under the terms of the GNU General Public License version 3 as |
83 | + * published by the Free Software Foundation. |
84 | + * |
85 | + * This program is distributed in the hope that it will be useful, |
86 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
87 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
88 | + * GNU General Public License for more details. |
89 | + * |
90 | + * You should have received a copy of the GNU General Public License |
91 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
92 | + * |
93 | + * Authored by: Marco Trevisan <marco.trevisan@canonical.com> |
94 | + */ |
95 | + |
96 | +#include "config.h" |
97 | + |
98 | +#include <gtk/gtk.h> |
99 | +#include <gdk/gdkx.h> |
100 | +#include <glib/gi18n-lib.h> |
101 | +#include <NuxCore/Logger.h> |
102 | +#include <UnityCore/GLibWrapper.h> |
103 | +#include <X11/Xatom.h> |
104 | +#include "DecorationsForceQuitDialog.h" |
105 | +#include "DecorationStyle.h" |
106 | +#include "WindowManager.h" |
107 | + |
108 | +namespace unity |
109 | +{ |
110 | +namespace decoration |
111 | +{ |
112 | +namespace |
113 | +{ |
114 | +DECLARE_LOGGER(logger, "unity.decoration.forcequit.dialog"); |
115 | + |
116 | +const std::string CLOSE_BUTTON_INACTIVE_FILE = "sheet_style_close_focused"; |
117 | +const std::string CLOSE_BUTTON_FOCUSED_FILE = "sheet_style_close_focused_prelight"; |
118 | +const std::string CLOSE_BUTTON_ACTIVE_FILE = "sheet_style_close_focused_pressed"; |
119 | + |
120 | + |
121 | +// Dialog |
122 | +struct SheetStyleWindow |
123 | +{ |
124 | + GtkWindow parent_instance; |
125 | +}; |
126 | + |
127 | +struct SheetStyleWindowClass |
128 | +{ |
129 | + GtkWindowClass parent_class; |
130 | +}; |
131 | + |
132 | +G_DEFINE_TYPE(SheetStyleWindow, sheet_style_window, GTK_TYPE_WINDOW); |
133 | +static void sheet_style_window_init(SheetStyleWindow*) {} |
134 | +static void sheet_style_window_class_init(SheetStyleWindowClass*); |
135 | + |
136 | +// Box |
137 | +struct SheetStyleDialog |
138 | +{ |
139 | + GtkBox parent_instance; |
140 | +}; |
141 | + |
142 | +struct SheetStyleDialogClass |
143 | +{ |
144 | + GtkBoxClass parent_class; |
145 | +}; |
146 | + |
147 | +G_DEFINE_TYPE(SheetStyleDialog, sheet_style_dialog, GTK_TYPE_BOX); |
148 | +GtkWidget* sheet_style_dialog_new(ForceQuitDialog*, Window, long); |
149 | +static void sheet_style_dialog_init(SheetStyleDialog*) {} |
150 | +static void sheet_style_dialog_class_init(SheetStyleDialogClass*); |
151 | + |
152 | +// Close button |
153 | +struct CloseButtonPrivate |
154 | +{ |
155 | + GtkImage* img; |
156 | +}; |
157 | + |
158 | +struct CloseButton |
159 | +{ |
160 | + GtkButton parent_instance; |
161 | + CloseButtonPrivate* priv; |
162 | +}; |
163 | + |
164 | +struct CloseButtonClass |
165 | +{ |
166 | + GtkButtonClass parent_class; |
167 | +}; |
168 | + |
169 | +#define CLOSE_BUTTON(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), close_button_get_type(), CloseButton)) |
170 | + |
171 | +G_DEFINE_TYPE(CloseButton, close_button, GTK_TYPE_BUTTON); |
172 | +GtkWidget* close_button_new(); |
173 | +static void close_button_init(CloseButton*); |
174 | +static void close_button_class_init(CloseButtonClass*); |
175 | + |
176 | +// Window implementation |
177 | +GtkWidget* sheet_style_window_new(ForceQuitDialog* main_dialog, Window parent_xid) |
178 | +{ |
179 | + auto* dpy = gdk_x11_get_default_xdisplay(); |
180 | + auto* self = GTK_WINDOW(g_object_new(sheet_style_window_get_type(), nullptr)); |
181 | + gtk_window_set_skip_taskbar_hint(self, TRUE); |
182 | + gtk_window_set_skip_pager_hint(self, TRUE); |
183 | + gtk_window_set_position(self, GTK_WIN_POS_CENTER_ON_PARENT); |
184 | + gtk_window_set_type_hint(self, GDK_WINDOW_TYPE_HINT_DIALOG); |
185 | + gtk_window_set_decorated(self, FALSE); |
186 | + gtk_window_set_resizable(self, FALSE); |
187 | + gtk_window_set_urgency_hint(self, TRUE); |
188 | + gtk_window_set_deletable(self, FALSE); |
189 | + gtk_window_set_title(self, "Force Quit Dialog"); |
190 | + |
191 | + XClassHint parent_class = {nullptr, nullptr}; |
192 | + XGetClassHint(dpy, parent_xid, &parent_class); |
193 | + gtk_window_set_wmclass(self, parent_class.res_name, parent_class.res_class); |
194 | + XFree(parent_class.res_class); |
195 | + XFree(parent_class.res_name); |
196 | + |
197 | + Atom WM_PID = gdk_x11_get_xatom_by_name("_NET_WM_PID"); |
198 | + Atom WM_CLIENT_MACHINE = gdk_x11_get_xatom_by_name("WM_CLIENT_MACHINE"); |
199 | + |
200 | + auto& wm = WindowManager::Default(); |
201 | + auto parent_hostname = wm.GetStringProperty(parent_xid, WM_CLIENT_MACHINE); |
202 | + long parent_pid = 0; |
203 | + |
204 | + char current_hostname[256]; |
205 | + if (gethostname(current_hostname, sizeof(current_hostname)) > -1) |
206 | + { |
207 | + current_hostname[sizeof(current_hostname)-1] = '\0'; |
208 | + |
209 | + if (current_hostname == parent_hostname) |
210 | + { |
211 | + auto const& pid_list = wm.GetCardinalProperty(parent_xid, WM_PID); |
212 | + |
213 | + if (!pid_list.empty()) |
214 | + parent_pid = pid_list.front(); |
215 | + } |
216 | + } |
217 | + |
218 | + auto const& deco_style = decoration::Style::Get(); |
219 | + auto const& offset = deco_style->ShadowOffset(); |
220 | + int max_offset = std::max(std::abs(offset.x), std::abs(offset.y)); |
221 | + gtk_container_set_border_width(GTK_CONTAINER(self), deco_style->ActiveShadowRadius()+max_offset); |
222 | + |
223 | + auto* screen = gtk_window_get_screen(self); |
224 | + gtk_widget_set_visual(GTK_WIDGET(self), gdk_screen_get_rgba_visual(screen)); |
225 | + gtk_widget_realize(GTK_WIDGET(self)); |
226 | + gtk_widget_override_background_color(GTK_WIDGET(self), GTK_STATE_FLAG_NORMAL, nullptr); |
227 | + |
228 | + gtk_container_add(GTK_CONTAINER(self), sheet_style_dialog_new(main_dialog, parent_xid, parent_pid)); |
229 | + |
230 | + gtk_window_set_modal(self, TRUE); |
231 | + gtk_window_set_destroy_with_parent(self, TRUE); |
232 | + |
233 | + auto* gwindow = gtk_widget_get_window(GTK_WIDGET(self)); |
234 | + gdk_window_set_functions(gwindow, GDK_FUNC_CLOSE); |
235 | + gtk_widget_realize(GTK_WIDGET(self)); |
236 | + |
237 | + gdk_error_trap_push(); |
238 | + auto xid = gdk_x11_window_get_xid(gwindow); |
239 | + XSetTransientForHint(dpy, xid, parent_xid); |
240 | + XSync(dpy, False); |
241 | + |
242 | + if (int error_code = gdk_error_trap_pop()) |
243 | + { |
244 | + gchar tmp[1024]; |
245 | + XGetErrorText(dpy, error_code, tmp, sizeof(tmp) - 1); |
246 | + tmp[sizeof(tmp) - 1] = '\0'; |
247 | + LOG_ERROR(logger) << "Impossible to reparent dialog: " << tmp; |
248 | + } |
249 | + |
250 | + XChangeProperty(dpy, xid, WM_CLIENT_MACHINE, XA_STRING, 8, PropModeReplace, |
251 | + (unsigned char *) parent_hostname.c_str(), parent_hostname.size()); |
252 | + XChangeProperty(dpy, xid, WM_PID, XA_CARDINAL, 32, PropModeReplace, |
253 | + (unsigned char *) &parent_pid, 1); |
254 | + XSync(dpy, False); |
255 | + |
256 | + return GTK_WIDGET(self); |
257 | +} |
258 | + |
259 | +static void sheet_style_window_class_init(SheetStyleWindowClass* klass) |
260 | +{ |
261 | + GTK_WIDGET_CLASS(klass)->delete_event = [] (GtkWidget* self, GdkEventAny*) { |
262 | + // Don't destroy the window on delete event |
263 | + return TRUE; |
264 | + }; |
265 | + |
266 | + GTK_WIDGET_CLASS(klass)->draw = [] (GtkWidget* self, cairo_t* cr) { |
267 | + GtkAllocation a; |
268 | + gtk_widget_get_allocation(self, &a); |
269 | + cairo_rectangle(cr, 0, 0, a.width, a.height); |
270 | + |
271 | + cairo_save(cr); |
272 | + int border = gtk_container_get_border_width(GTK_CONTAINER(self)); |
273 | + cairo_translate(cr, border, border); |
274 | + gtk_container_forall(GTK_CONTAINER(self), [] (GtkWidget* child, gpointer cr) { |
275 | + gtk_widget_draw(child, static_cast<cairo_t*>(cr)); |
276 | + }, cr); |
277 | + cairo_restore(cr); |
278 | + |
279 | + return TRUE; |
280 | + }; |
281 | + |
282 | + GTK_WIDGET_CLASS(klass)->size_allocate = [] (GtkWidget* self, GtkAllocation* a) { |
283 | + GTK_WIDGET_CLASS(sheet_style_window_parent_class)->size_allocate(self, a); |
284 | + |
285 | + int border = gtk_container_get_border_width(GTK_CONTAINER(self)); |
286 | + cairo_rectangle_int_t rect = {border, border, a->width-border*2, a->height-border*2}; |
287 | + |
288 | + auto* region = cairo_region_create_rectangle(&rect); |
289 | + gtk_widget_input_shape_combine_region(GTK_WIDGET(self), region); |
290 | + cairo_region_destroy(region); |
291 | + }; |
292 | +} |
293 | + |
294 | +// Dialog content Implementation |
295 | +void on_force_quit_clicked(GtkButton *button, gint64* kill_data) |
296 | +{ |
297 | + Display* dpy = gdk_x11_get_default_xdisplay(); |
298 | + GtkWidget* top_level = gtk_widget_get_toplevel(GTK_WIDGET(button)); |
299 | + Window parent_xid = kill_data[0]; |
300 | + long parent_pid = kill_data[1]; |
301 | + |
302 | + gtk_widget_hide(top_level); |
303 | + |
304 | + gdk_error_trap_push(); |
305 | + XSync(dpy, False); |
306 | + |
307 | + if (int error_code = gdk_error_trap_pop()) |
308 | + { |
309 | + gchar tmp[1024]; |
310 | + XGetErrorText(dpy, error_code, tmp, sizeof(tmp) - 1); |
311 | + tmp[sizeof(tmp) - 1] = '\0'; |
312 | + LOG_ERROR(logger) << "Impossible to kill window " << parent_xid << ": " << tmp; |
313 | + } |
314 | + |
315 | + XKillClient(dpy, parent_xid); |
316 | + XSync(dpy, False); |
317 | + |
318 | + if (parent_pid > 0) |
319 | + kill(parent_pid, 9); |
320 | +} |
321 | + |
322 | +void on_wait_clicked(GtkButton *button, ForceQuitDialog* main_dialog) |
323 | +{ |
324 | + main_dialog->close_request.emit(); |
325 | +} |
326 | + |
327 | +GtkWidget* sheet_style_dialog_new(ForceQuitDialog* main_dialog, Window parent_xid, long parent_pid) |
328 | +{ |
329 | + auto* self = GTK_WIDGET(g_object_new(sheet_style_dialog_get_type(), nullptr)); |
330 | + gtk_orientable_set_orientation(GTK_ORIENTABLE(self), GTK_ORIENTATION_VERTICAL); |
331 | + |
332 | + glib::Object<GtkCssProvider> style(gtk_css_provider_new()); |
333 | + |
334 | + auto const& deco_style = decoration::Style::Get(); |
335 | + auto const& radius = deco_style->CornerRadius(); |
336 | + auto const& offset = deco_style->ShadowOffset(); |
337 | + auto const& color = deco_style->ActiveShadowColor(); |
338 | + int decoration_radius = std::max({radius.top, radius.left, radius.right, radius.bottom}); |
339 | + |
340 | + gtk_css_provider_load_from_data(style, (R"(SheetStyleDialog { |
341 | + background-color: #f7f6f5; |
342 | + color: #4a4a4a; |
343 | + border-radius: )"+std::to_string(decoration_radius)+R"(px; |
344 | + box-shadow: )"+std::to_string(offset.x)+"px "+std::to_string(offset.y)+"px "+ |
345 | + std::to_string(deco_style->ActiveShadowRadius())+"px "+ |
346 | + "rgba("+std::to_string(int(color.red * 255.0))+", "+ |
347 | + std::to_string(int(color.green * 255.0))+", "+ |
348 | + std::to_string(int(color.blue * 255.0))+", "+ |
349 | + std::to_string(int(color.alpha))+'.'+std::to_string(int(color.alpha*10000.0))+')'+R"(; |
350 | + })").c_str(), -1, nullptr); |
351 | + |
352 | + auto* style_ctx = gtk_widget_get_style_context(self); |
353 | + gtk_style_context_add_provider(style_ctx, glib::object_cast<GtkStyleProvider>(style), GTK_STYLE_PROVIDER_PRIORITY_FALLBACK); |
354 | + gtk_style_context_add_class(style_ctx, "unity-force-quit"); |
355 | + |
356 | + auto* main_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5); |
357 | + gtk_container_set_border_width(GTK_CONTAINER(main_box), 4); |
358 | + |
359 | + auto *close_button = close_button_new(); |
360 | + g_signal_connect(close_button, "clicked", G_CALLBACK(on_wait_clicked), main_dialog); |
361 | + gtk_box_pack_start(GTK_BOX(main_box), close_button, TRUE, TRUE, 0); |
362 | + |
363 | + auto* content_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5); |
364 | + gtk_container_set_border_width(GTK_CONTAINER(content_box), 10); |
365 | + gtk_widget_set_margin_left(content_box, 20); |
366 | + gtk_widget_set_margin_right(content_box, 20); |
367 | + gtk_container_add(GTK_CONTAINER(main_box), content_box); |
368 | + |
369 | + auto* title = gtk_label_new(_("This window is not responding")); |
370 | + auto* font_desc = pango_font_description_from_string("Ubuntu 17"); |
371 | + gtk_widget_override_font(title, font_desc); |
372 | + pango_font_description_free(font_desc); |
373 | + gtk_widget_set_halign(title, GTK_ALIGN_START); |
374 | + gtk_box_pack_start(GTK_BOX(content_box), title, FALSE, FALSE, 0); |
375 | + |
376 | + auto* subtitle = gtk_label_new(_("Do you want to force the application to exit, or wait for it to respond?")); |
377 | + gtk_widget_set_halign(title, GTK_ALIGN_START); |
378 | + gtk_box_pack_start(GTK_BOX(content_box), subtitle, FALSE, FALSE, 0); |
379 | + |
380 | + auto* buttons_box = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL); |
381 | + gtk_box_set_spacing(GTK_BOX(buttons_box), 15); |
382 | + gtk_container_set_border_width(GTK_CONTAINER(buttons_box), 5); |
383 | + gtk_button_box_set_layout(GTK_BUTTON_BOX(buttons_box), GTK_BUTTONBOX_END); |
384 | + |
385 | + auto* wait_button = gtk_button_new_with_mnemonic(_("_Wait")); |
386 | + gtk_container_add(GTK_CONTAINER(buttons_box), wait_button); |
387 | + g_signal_connect(wait_button, "clicked", G_CALLBACK(on_wait_clicked), main_dialog); |
388 | + |
389 | + auto *kill_data = g_new(gint64, 2); |
390 | + kill_data[0] = parent_xid; |
391 | + kill_data[1] = parent_pid; |
392 | + auto* quit_button = gtk_button_new_with_mnemonic(_("_Force Quit")); |
393 | + gtk_container_add(GTK_CONTAINER(buttons_box), quit_button); |
394 | + g_signal_connect_data(quit_button, "clicked", G_CALLBACK(on_force_quit_clicked), |
395 | + kill_data, [] (gpointer data, GClosure*) { g_free(data); }, |
396 | + static_cast<GConnectFlags>(0)); |
397 | + |
398 | + auto* buttons_aligment = gtk_alignment_new(1, 1, 0, 0); |
399 | + gtk_alignment_set_padding(GTK_ALIGNMENT(buttons_aligment), 20, 0, 0, 0); |
400 | + gtk_container_add(GTK_CONTAINER(buttons_aligment), buttons_box); |
401 | + gtk_container_add(GTK_CONTAINER(content_box), buttons_aligment); |
402 | + |
403 | + gtk_container_add(GTK_CONTAINER(self), main_box); |
404 | + |
405 | + return self; |
406 | +} |
407 | + |
408 | +static void sheet_style_dialog_class_init(SheetStyleDialogClass* klass) |
409 | +{ |
410 | + GTK_WIDGET_CLASS(klass)->draw = [] (GtkWidget* self, cairo_t* cr) { |
411 | + GtkAllocation a; |
412 | + gtk_widget_get_allocation(self, &a); |
413 | + gtk_render_background(gtk_widget_get_style_context(self), cr, 0, 0, a.width, a.height); |
414 | + return GTK_WIDGET_CLASS(sheet_style_dialog_parent_class)->draw(self, cr); |
415 | + }; |
416 | +} |
417 | + |
418 | +// Close button |
419 | +GtkWidget* close_button_new() |
420 | +{ |
421 | + auto* self = GTK_WIDGET(g_object_new(close_button_get_type(), nullptr)); |
422 | + gtk_button_set_relief(GTK_BUTTON(self), GTK_RELIEF_NONE); |
423 | + gtk_button_set_focus_on_click(GTK_BUTTON(self), FALSE); |
424 | + gtk_widget_set_can_focus(self, FALSE); |
425 | + gtk_widget_set_halign(self, GTK_ALIGN_START); |
426 | + |
427 | + auto const& file = decoration::Style::Get()->ThemedFilePath(CLOSE_BUTTON_INACTIVE_FILE, {PKGDATADIR"/"}); |
428 | + auto* img = gtk_image_new_from_file(file.c_str()); |
429 | + gtk_container_add(GTK_CONTAINER(self), img); |
430 | + CLOSE_BUTTON(self)->priv->img = GTK_IMAGE(img); |
431 | + |
432 | + glib::Object<GtkCssProvider> style(gtk_css_provider_new()); |
433 | + gtk_css_provider_load_from_data(style, R"( |
434 | + * {padding: 0px 0px 0px 0px; border: 0px; } |
435 | + )", -1, nullptr); |
436 | + |
437 | + auto* style_ctx = gtk_widget_get_style_context(self); |
438 | + gtk_style_context_add_provider(style_ctx, glib::object_cast<GtkStyleProvider>(style), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); |
439 | + |
440 | + return self; |
441 | +} |
442 | + |
443 | +static void close_button_init(CloseButton* self) |
444 | +{ |
445 | + self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, close_button_get_type(), CloseButtonPrivate); |
446 | +} |
447 | + |
448 | +static void close_button_class_init(CloseButtonClass* klass) |
449 | +{ |
450 | + GTK_WIDGET_CLASS(klass)->draw = [] (GtkWidget* self, cairo_t* cr) { |
451 | + gtk_widget_draw(GTK_WIDGET(CLOSE_BUTTON(self)->priv->img), cr); |
452 | + return TRUE; |
453 | + }; |
454 | + |
455 | + GTK_WIDGET_CLASS(klass)->state_flags_changed = [] (GtkWidget* self, GtkStateFlags prev_state) { |
456 | + auto* img = CLOSE_BUTTON(self)->priv->img; |
457 | + if (!img) return; |
458 | + |
459 | + auto new_flags = gtk_widget_get_state_flags(self); |
460 | + auto const& deco_style = decoration::Style::Get(); |
461 | + auto file = deco_style->ThemedFilePath(CLOSE_BUTTON_INACTIVE_FILE, {PKGDATADIR"/"}); |
462 | + |
463 | + if (((new_flags & GTK_STATE_FLAG_PRELIGHT) && !gtk_widget_get_can_focus(self)) || |
464 | + (new_flags & GTK_STATE_FLAG_FOCUSED)) |
465 | + { |
466 | + auto const& basename = (new_flags & GTK_STATE_FLAG_ACTIVE) ? CLOSE_BUTTON_ACTIVE_FILE : CLOSE_BUTTON_FOCUSED_FILE; |
467 | + file = deco_style->ThemedFilePath(basename, {PKGDATADIR"/"}); |
468 | + } |
469 | + |
470 | + gtk_image_set_from_file(img, file.c_str()); |
471 | + |
472 | + return GTK_WIDGET_CLASS(close_button_parent_class)->state_flags_changed(self, prev_state); |
473 | + }; |
474 | + |
475 | + G_OBJECT_CLASS(klass)->finalize = [] (GObject* self) { |
476 | + CLOSE_BUTTON(self)->priv->img = nullptr; |
477 | + return G_OBJECT_CLASS(close_button_parent_class)->finalize(self); |
478 | + }; |
479 | +} |
480 | + |
481 | +} |
482 | + |
483 | +struct ForceQuitDialog::Impl : sigc::trackable |
484 | +{ |
485 | + Impl(ForceQuitDialog* parent, CompWindow* win) |
486 | + : parent_(parent) |
487 | + , win_(win) |
488 | + , dialog_(sheet_style_window_new(parent, win_->id())) |
489 | + { |
490 | + parent_->time.changed.connect(sigc::mem_fun(this, &Impl::UpdateWindowTime)); |
491 | + UpdateWindowTime(parent_->time()); |
492 | + } |
493 | + |
494 | + ~Impl() |
495 | + { |
496 | + gtk_widget_destroy(dialog_); |
497 | + } |
498 | + |
499 | + void UpdateWindowTime(Time time) |
500 | + { |
501 | + gdk_x11_window_set_user_time(gtk_widget_get_window(dialog_), time); |
502 | + gtk_widget_show_all(dialog_); |
503 | + } |
504 | + |
505 | + void UpdateDialogPosition() |
506 | + { |
507 | + auto const& win_geo = win_->inputRect(); |
508 | + nux::Size walloc(gtk_widget_get_allocated_width(dialog_), gtk_widget_get_allocated_height(dialog_)); |
509 | + gtk_window_move(GTK_WINDOW(dialog_), win_geo.centerX() - walloc.width/2, win_geo.centerY() - walloc.height/2); |
510 | + } |
511 | + |
512 | + ForceQuitDialog* parent_; |
513 | + CompWindow* win_; |
514 | + GtkWidget* dialog_; |
515 | +}; |
516 | + |
517 | +ForceQuitDialog::ForceQuitDialog(CompWindow* win, Time tm) |
518 | + : time(tm) |
519 | + , impl_(new Impl(this, win)) |
520 | +{} |
521 | + |
522 | +ForceQuitDialog::~ForceQuitDialog() |
523 | +{} |
524 | + |
525 | +void ForceQuitDialog::UpdateDialogPosition() |
526 | +{ |
527 | + impl_->UpdateDialogPosition(); |
528 | +} |
529 | + |
530 | +} // decoration namespace |
531 | +} // unity namespace |
532 | |
533 | === added file 'decorations/DecorationsForceQuitDialog.h' |
534 | --- decorations/DecorationsForceQuitDialog.h 1970-01-01 00:00:00 +0000 |
535 | +++ decorations/DecorationsForceQuitDialog.h 2014-04-02 13:15:24 +0000 |
536 | @@ -0,0 +1,53 @@ |
537 | +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- |
538 | +/* |
539 | + * Copyright (C) 2014 Canonical Ltd |
540 | + * |
541 | + * This program is free software: you can redistribute it and/or modify |
542 | + * it under the terms of the GNU General Public License version 3 as |
543 | + * published by the Free Software Foundation. |
544 | + * |
545 | + * This program is distributed in the hope that it will be useful, |
546 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
547 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
548 | + * GNU General Public License for more details. |
549 | + * |
550 | + * You should have received a copy of the GNU General Public License |
551 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
552 | + * |
553 | + * Authored by: Marco Trevisan <marco.trevisan@canonical.com> |
554 | + */ |
555 | + |
556 | +#ifndef __UNITY_DECORATIONS_FORCE_QUIT_DIALOG__ |
557 | +#define __UNITY_DECORATIONS_FORCE_QUIT_DIALOG__ |
558 | + |
559 | +#include <NuxCore/Property.h> |
560 | +#include "CompizUtils.h" |
561 | + |
562 | +namespace unity |
563 | +{ |
564 | +namespace decoration |
565 | +{ |
566 | + |
567 | +class ForceQuitDialog |
568 | +{ |
569 | +public: |
570 | + typedef std::shared_ptr<ForceQuitDialog> Ptr; |
571 | + |
572 | + ForceQuitDialog(CompWindow*, Time); |
573 | + ~ForceQuitDialog(); |
574 | + |
575 | + nux::Property<Time> time; |
576 | + |
577 | + void UpdateDialogPosition(); |
578 | + |
579 | + sigc::signal<void> close_request; |
580 | + |
581 | +private: |
582 | + struct Impl; |
583 | + std::unique_ptr<Impl> impl_; |
584 | +}; |
585 | + |
586 | +} // menu namespace |
587 | +} // decoration namespace |
588 | + |
589 | +#endif // __UNITY_DECORATIONS_FORCE_QUIT_DIALOG__ |
590 | |
591 | === modified file 'decorations/DecorationsManager.cpp' |
592 | --- decorations/DecorationsManager.cpp 2014-03-03 19:07:56 +0000 |
593 | +++ decorations/DecorationsManager.cpp 2014-04-02 13:15:24 +0000 |
594 | @@ -218,6 +218,20 @@ |
595 | if (Window::Ptr const& win = GetWindowByXid(event->xclient.window)) |
596 | win->impl_->Decorate(); |
597 | } |
598 | + else if (event->xclient.message_type == Atoms::toolkitAction) |
599 | + { |
600 | + Atom msg = event->xclient.data.l[0]; |
601 | + if (msg == Atoms::toolkitActionForceQuitDialog) |
602 | + { |
603 | + if (Window::Ptr const& win = GetWindowByXid(event->xclient.window)) |
604 | + { |
605 | + Time time = event->xclient.data.l[1]; |
606 | + bool show = event->xclient.data.l[2]; |
607 | + win->impl_->ShowForceQuitDialog(show, time); |
608 | + return true; |
609 | + } |
610 | + } |
611 | + } |
612 | break; |
613 | case MotionNotify: |
614 | case EnterNotify: |
615 | |
616 | === modified file 'decorations/DecorationsPriv.h' |
617 | --- decorations/DecorationsPriv.h 2014-03-03 19:07:56 +0000 |
618 | +++ decorations/DecorationsPriv.h 2014-04-02 13:15:24 +0000 |
619 | @@ -46,6 +46,7 @@ |
620 | class Title; |
621 | class MenuLayout; |
622 | class SlidingLayout; |
623 | +class ForceQuitDialog; |
624 | |
625 | namespace cu = compiz_utils; |
626 | |
627 | @@ -86,6 +87,7 @@ |
628 | void Damage(); |
629 | void SetupAppMenu(); |
630 | bool ActivateMenu(std::string const&); |
631 | + void ShowForceQuitDialog(bool, Time); |
632 | |
633 | private: |
634 | void UnsetExtents(); |
635 | @@ -107,6 +109,7 @@ |
636 | |
637 | void ComputeShadowQuads(); |
638 | void UpdateDecorationTextures(); |
639 | + void UpdateForceQuitDialogPosition(); |
640 | void RenderDecorationTexture(Side, nux::Geometry const&); |
641 | void Paint(GLMatrix const&, GLWindowPaintAttrib const&, CompRegion const&, unsigned mask); |
642 | void Draw(GLMatrix const&, GLWindowPaintAttrib const&, CompRegion const&, unsigned mask); |
643 | @@ -131,6 +134,7 @@ |
644 | connection::Wrapper grab_mouse_changed_; |
645 | std::string last_title_; |
646 | std::vector<cu::SimpleTextureQuad> bg_textures_; |
647 | + std::shared_ptr<ForceQuitDialog> force_quit_; |
648 | InputMixer::Ptr input_mixer_; |
649 | Layout::Ptr top_layout_; |
650 | uweak_ptr<MenuLayout> menus_; |
651 | |
652 | === modified file 'po/POTFILES.in' |
653 | --- po/POTFILES.in 2014-03-12 23:46:10 +0000 |
654 | +++ po/POTFILES.in 2014-04-02 13:15:24 +0000 |
655 | @@ -11,6 +11,7 @@ |
656 | dash/previews/ApplicationPreview.cpp |
657 | dash/previews/PreviewInfoHintWidget.cpp |
658 | dash/previews/SocialPreview.cpp |
659 | +decorations/DecorationsForceQuitDialog.cpp |
660 | hud/HudController.cpp |
661 | hud/HudView.cpp |
662 | launcher/ApplicationLauncherIcon.cpp |
663 | |
664 | === added file 'resources/sheet_style_close_focused.svg' |
665 | --- resources/sheet_style_close_focused.svg 1970-01-01 00:00:00 +0000 |
666 | +++ resources/sheet_style_close_focused.svg 2014-04-02 13:15:24 +0000 |
667 | @@ -0,0 +1,177 @@ |
668 | +<?xml version="1.0" encoding="UTF-8" standalone="no"?> |
669 | +<!-- Created with Inkscape (http://www.inkscape.org/) --> |
670 | + |
671 | +<svg |
672 | + xmlns:dc="http://purl.org/dc/elements/1.1/" |
673 | + xmlns:cc="http://creativecommons.org/ns#" |
674 | + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" |
675 | + xmlns:svg="http://www.w3.org/2000/svg" |
676 | + xmlns="http://www.w3.org/2000/svg" |
677 | + xmlns:xlink="http://www.w3.org/1999/xlink" |
678 | + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" |
679 | + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" |
680 | + width="19" |
681 | + height="19" |
682 | + id="svg4747" |
683 | + version="1.1" |
684 | + inkscape:version="0.48+devel r" |
685 | + viewBox="0 0 19 19" |
686 | + sodipodi:docname="close_focused_normal.svg"> |
687 | + <defs |
688 | + id="defs4749"> |
689 | + <linearGradient |
690 | + inkscape:collect="always" |
691 | + xlink:href="#linearGradient4509" |
692 | + id="linearGradient4787" |
693 | + gradientUnits="userSpaceOnUse" |
694 | + gradientTransform="translate(-1072.3622,-1053.3622)" |
695 | + x1="2.0000153" |
696 | + y1="1062.8622" |
697 | + x2="16.999975" |
698 | + y2="1062.8622" /> |
699 | + <linearGradient |
700 | + inkscape:collect="always" |
701 | + id="linearGradient4509"> |
702 | + <stop |
703 | + style="stop-color:#e77041;stop-opacity:1" |
704 | + offset="0" |
705 | + id="stop4885" /> |
706 | + <stop |
707 | + id="stop4887" |
708 | + offset="0.50001228" |
709 | + style="stop-color:#f17d4e;stop-opacity:1" /> |
710 | + <stop |
711 | + style="stop-color:#f9b39c;stop-opacity:1" |
712 | + offset="1" |
713 | + id="stop4889" /> |
714 | + </linearGradient> |
715 | + <linearGradient |
716 | + inkscape:collect="always" |
717 | + xlink:href="#linearGradient4521" |
718 | + id="linearGradient4789" |
719 | + gradientUnits="userSpaceOnUse" |
720 | + gradientTransform="translate(2125.7244,0)" |
721 | + x1="-1065.3622" |
722 | + y1="9.4999952" |
723 | + x2="-1055.3622" |
724 | + y2="9.4999952" /> |
725 | + <linearGradient |
726 | + id="linearGradient4521" |
727 | + inkscape:collect="always"> |
728 | + <stop |
729 | + id="stop4293" |
730 | + offset="0" |
731 | + style="stop-color:#ffffff;stop-opacity:1;" /> |
732 | + <stop |
733 | + id="stop4295" |
734 | + offset="1" |
735 | + style="stop-color:#ffffff;stop-opacity:0;" /> |
736 | + </linearGradient> |
737 | + <linearGradient |
738 | + inkscape:collect="always" |
739 | + xlink:href="#linearGradient4521" |
740 | + id="linearGradient4791" |
741 | + gradientUnits="userSpaceOnUse" |
742 | + gradientTransform="matrix(1.0357118,0,0,1.0357118,2163.6811,-0.33926172)" |
743 | + x1="-1065.276" |
744 | + y1="9.4999952" |
745 | + x2="-1055.6208" |
746 | + y2="9.4999952" /> |
747 | + </defs> |
748 | + <sodipodi:namedview |
749 | + id="base" |
750 | + pagecolor="#ffffff" |
751 | + bordercolor="#666666" |
752 | + borderopacity="1.0" |
753 | + inkscape:pageopacity="0.0" |
754 | + inkscape:pageshadow="2" |
755 | + inkscape:zoom="15.543122" |
756 | + inkscape:cx="1.5415261" |
757 | + inkscape:cy="18.71954" |
758 | + inkscape:document-units="px" |
759 | + inkscape:current-layer="layer1" |
760 | + showgrid="false" |
761 | + fit-margin-top="0" |
762 | + fit-margin-left="0" |
763 | + fit-margin-right="0" |
764 | + fit-margin-bottom="0" /> |
765 | + <metadata |
766 | + id="metadata4752"> |
767 | + <rdf:RDF> |
768 | + <cc:Work |
769 | + rdf:about=""> |
770 | + <dc:format>image/svg+xml</dc:format> |
771 | + <dc:type |
772 | + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> |
773 | + <dc:title></dc:title> |
774 | + </cc:Work> |
775 | + </rdf:RDF> |
776 | + </metadata> |
777 | + <g |
778 | + inkscape:label="Layer 1" |
779 | + inkscape:groupmode="layer" |
780 | + id="layer1" |
781 | + transform="translate(295.60105,-849.03082)"> |
782 | + <g |
783 | + style="display:inline" |
784 | + id="g4775" |
785 | + inkscape:export-filename="close.png" |
786 | + inkscape:export-xdpi="90" |
787 | + inkscape:export-ydpi="90" |
788 | + transform="translate(-295.60104,-204.33136)"> |
789 | + <circle |
790 | + r="8.5" |
791 | + cy="1062.8622" |
792 | + cx="9.4999924" |
793 | + id="circle4777" |
794 | + style="color:#000000;fill:#d0c7bf;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:8;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" |
795 | + d="m 17.999992,1062.8622 a 8.5,8.5 0 0 1 -8.4999996,8.5 8.5,8.5 0 0 1 -8.50000003,-8.5 8.5,8.5 0 0 1 8.50000003,-8.5 8.5,8.5 0 0 1 8.4999996,8.5 z" /> |
796 | + <circle |
797 | + transform="matrix(0,-1,1,0,0,0)" |
798 | + style="color:#000000;fill:url(#linearGradient4787);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:8;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" |
799 | + id="circle4779" |
800 | + cx="-1062.8622" |
801 | + cy="9.4999952" |
802 | + r="7.49998" |
803 | + d="m -1055.3622,9.4999952 a 7.49998,7.49998 0 0 1 -7.5,7.4999798 7.49998,7.49998 0 0 1 -7.5,-7.4999798 7.49998,7.49998 0 0 1 7.5,-7.4999799 7.49998,7.49998 0 0 1 7.5,7.4999799 z" /> |
804 | + <circle |
805 | + r="6.9999976" |
806 | + cy="9.4999952" |
807 | + cx="1062.8622" |
808 | + id="circle4781" |
809 | + style="opacity:0.25;color:#000000;fill:none;stroke:url(#linearGradient4789);stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" |
810 | + transform="matrix(0,1,1,0,0,0)" |
811 | + d="m 1069.8622,9.4999952 a 6.9999976,6.9999976 0 0 1 -7,6.9999978 6.9999976,6.9999976 0 0 1 -7,-6.9999978 6.9999976,6.9999976 0 0 1 7,-6.9999976 6.9999976,6.9999976 0 0 1 7,6.9999976 z" /> |
812 | + <circle |
813 | + transform="matrix(0,1,1,0,0,0)" |
814 | + style="opacity:0.25;color:#000000;fill:none;stroke:url(#linearGradient4791);stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" |
815 | + id="circle4783" |
816 | + cx="1062.8622" |
817 | + cy="9.4999952" |
818 | + r="7.24998" |
819 | + d="m 1070.1122,9.4999952 a 7.24998,7.24998 0 0 1 -7.25,7.2499798 7.24998,7.24998 0 0 1 -7.25,-7.2499798 7.24998,7.24998 0 0 1 7.25,-7.2499799 7.24998,7.24998 0 0 1 7.25,7.2499799 z" /> |
820 | + <rect |
821 | + y="1053.3622" |
822 | + x="-7.3563765e-06" |
823 | + height="19" |
824 | + width="19" |
825 | + id="rect4785" |
826 | + style="color:#000000;fill:none;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> |
827 | + </g> |
828 | + <path |
829 | + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;opacity:0.25;color:#000000;color-interpolation:sRGB;color-interpolation-filters:linearRGB;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;isolation:auto;mix-blend-mode:normal;enable-background:accumulate;clip-rule:nonzero;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;font-family:sans-serif;-inkscape-font-specification:sans-serif" |
830 | + d="m -288.40183,856.52418 -0.70703,0.707 0.35351,0.3535 1.94727,1.9473 -1.94727,1.9453 -0.35351,0.3535 0.70703,0.707 0.35351,-0.3535 1.94727,-1.9472 1.94726,1.9472 0.35352,0.3535 0.70703,-0.707 -0.35351,-0.3535 -1.94727,-1.9453 1.94727,-1.9473 0.35351,-0.3535 -0.70703,-0.707 -0.35352,0.3535 -1.94726,1.9472 -1.94727,-1.9472 -0.35351,-0.3535 z" |
831 | + id="path4646" |
832 | + inkscape:connector-curvature="0" /> |
833 | + <path |
834 | + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;color-interpolation:sRGB;color-interpolation-filters:linearRGB;fill:#7f4025;fill-opacity:1;stroke:none;stroke-width:1.10000002;marker:none;visibility:visible;display:inline;overflow:visible;isolation:auto;mix-blend-mode:normal;enable-background:accumulate;clip-rule:nonzero;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;font-family:sans-serif;-inkscape-font-specification:sans-serif" |
835 | + d="m -283.80078,855.45312 -0.38867,0.38868 -4.59961,4.59961 -0.39063,0.38867 0.7793,0.7793 0.38867,-0.38868 4.59961,-4.60156 0.38867,-0.38867 -0.77734,-0.77735 z" |
836 | + id="path4535" |
837 | + inkscape:connector-curvature="0" /> |
838 | + <path |
839 | + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;color-interpolation:sRGB;color-interpolation-filters:linearRGB;fill:#7f4025;fill-opacity:1;stroke:none;stroke-width:1.10000002;marker:none;visibility:visible;display:inline;overflow:visible;isolation:auto;mix-blend-mode:normal;enable-background:accumulate;clip-rule:nonzero;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;font-family:sans-serif;-inkscape-font-specification:sans-serif" |
840 | + d="m -288.40039,855.45312 -0.7793,0.77735 0.39063,0.38867 4.59961,4.60156 0.38867,0.38868 0.77734,-0.7793 -0.38867,-0.38867 -4.59961,-4.59961 -0.38867,-0.38868 z" |
841 | + id="path4537" |
842 | + inkscape:connector-curvature="0" /> |
843 | + </g> |
844 | +</svg> |
845 | |
846 | === added file 'resources/sheet_style_close_focused_prelight.svg' |
847 | --- resources/sheet_style_close_focused_prelight.svg 1970-01-01 00:00:00 +0000 |
848 | +++ resources/sheet_style_close_focused_prelight.svg 2014-04-02 13:15:24 +0000 |
849 | @@ -0,0 +1,177 @@ |
850 | +<?xml version="1.0" encoding="UTF-8" standalone="no"?> |
851 | +<!-- Created with Inkscape (http://www.inkscape.org/) --> |
852 | + |
853 | +<svg |
854 | + xmlns:dc="http://purl.org/dc/elements/1.1/" |
855 | + xmlns:cc="http://creativecommons.org/ns#" |
856 | + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" |
857 | + xmlns:svg="http://www.w3.org/2000/svg" |
858 | + xmlns="http://www.w3.org/2000/svg" |
859 | + xmlns:xlink="http://www.w3.org/1999/xlink" |
860 | + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" |
861 | + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" |
862 | + width="19" |
863 | + height="19" |
864 | + id="svg4747" |
865 | + version="1.1" |
866 | + inkscape:version="0.48+devel r" |
867 | + viewBox="0 0 19 19" |
868 | + sodipodi:docname="close_focused_prelight.svg"> |
869 | + <defs |
870 | + id="defs4749"> |
871 | + <linearGradient |
872 | + inkscape:collect="always" |
873 | + xlink:href="#linearGradient4891" |
874 | + id="linearGradient4877" |
875 | + gradientUnits="userSpaceOnUse" |
876 | + gradientTransform="translate(-1072.3622,-1053.3622)" |
877 | + x1="2.0000153" |
878 | + y1="1062.8622" |
879 | + x2="16.999975" |
880 | + y2="1062.8622" /> |
881 | + <linearGradient |
882 | + id="linearGradient4891" |
883 | + inkscape:collect="always"> |
884 | + <stop |
885 | + id="stop4767" |
886 | + offset="0" |
887 | + style="stop-color:#e67144;stop-opacity:1" /> |
888 | + <stop |
889 | + style="stop-color:#ed8b67;stop-opacity:1" |
890 | + offset="0.50001228" |
891 | + id="stop4769" /> |
892 | + <stop |
893 | + id="stop4771" |
894 | + offset="1" |
895 | + style="stop-color:#f9cbbd;stop-opacity:1" /> |
896 | + </linearGradient> |
897 | + <linearGradient |
898 | + inkscape:collect="always" |
899 | + xlink:href="#linearGradient4521" |
900 | + id="linearGradient4879" |
901 | + gradientUnits="userSpaceOnUse" |
902 | + gradientTransform="translate(2125.7244,0)" |
903 | + x1="-1065.3622" |
904 | + y1="9.4999952" |
905 | + x2="-1055.3622" |
906 | + y2="9.4999952" /> |
907 | + <linearGradient |
908 | + id="linearGradient4521" |
909 | + inkscape:collect="always"> |
910 | + <stop |
911 | + id="stop4293" |
912 | + offset="0" |
913 | + style="stop-color:#ffffff;stop-opacity:1;" /> |
914 | + <stop |
915 | + id="stop4295" |
916 | + offset="1" |
917 | + style="stop-color:#ffffff;stop-opacity:0;" /> |
918 | + </linearGradient> |
919 | + <linearGradient |
920 | + inkscape:collect="always" |
921 | + xlink:href="#linearGradient4521" |
922 | + id="linearGradient4881" |
923 | + gradientUnits="userSpaceOnUse" |
924 | + gradientTransform="matrix(1.0357118,0,0,1.0357118,2163.6811,-0.33926172)" |
925 | + x1="-1065.276" |
926 | + y1="9.4999952" |
927 | + x2="-1055.6208" |
928 | + y2="9.4999952" /> |
929 | + </defs> |
930 | + <sodipodi:namedview |
931 | + id="base" |
932 | + pagecolor="#ffffff" |
933 | + bordercolor="#666666" |
934 | + borderopacity="1.0" |
935 | + inkscape:pageopacity="0.0" |
936 | + inkscape:pageshadow="2" |
937 | + inkscape:zoom="0.35" |
938 | + inkscape:cx="-276" |
939 | + inkscape:cy="139" |
940 | + inkscape:document-units="px" |
941 | + inkscape:current-layer="layer1" |
942 | + showgrid="false" |
943 | + fit-margin-top="0" |
944 | + fit-margin-left="0" |
945 | + fit-margin-right="0" |
946 | + fit-margin-bottom="0" /> |
947 | + <metadata |
948 | + id="metadata4752"> |
949 | + <rdf:RDF> |
950 | + <cc:Work |
951 | + rdf:about=""> |
952 | + <dc:format>image/svg+xml</dc:format> |
953 | + <dc:type |
954 | + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> |
955 | + <dc:title></dc:title> |
956 | + </cc:Work> |
957 | + </rdf:RDF> |
958 | + </metadata> |
959 | + <g |
960 | + inkscape:label="Layer 1" |
961 | + inkscape:groupmode="layer" |
962 | + id="layer1" |
963 | + transform="translate(4.7142929,-652.36219)"> |
964 | + <g |
965 | + style="display:inline" |
966 | + transform="translate(-4.7142855,-400.99999)" |
967 | + inkscape:export-ydpi="90" |
968 | + inkscape:export-xdpi="90" |
969 | + inkscape:export-filename="close.png" |
970 | + id="g4865"> |
971 | + <circle |
972 | + style="color:#000000;fill:#d0c7bf;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:8;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" |
973 | + id="circle4867" |
974 | + cx="9.4999924" |
975 | + cy="1062.8622" |
976 | + r="8.5" |
977 | + d="m 17.999992,1062.8622 a 8.5,8.5 0 0 1 -8.4999996,8.5 8.5,8.5 0 0 1 -8.50000003,-8.5 8.5,8.5 0 0 1 8.50000003,-8.5 8.5,8.5 0 0 1 8.4999996,8.5 z" /> |
978 | + <circle |
979 | + r="7.49998" |
980 | + cy="9.4999952" |
981 | + cx="-1062.8622" |
982 | + id="circle4869" |
983 | + style="color:#000000;fill:url(#linearGradient4877);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:8;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" |
984 | + transform="matrix(0,-1,1,0,0,0)" |
985 | + d="m -1055.3622,9.4999952 a 7.49998,7.49998 0 0 1 -7.5,7.4999798 7.49998,7.49998 0 0 1 -7.5,-7.4999798 7.49998,7.49998 0 0 1 7.5,-7.4999799 7.49998,7.49998 0 0 1 7.5,7.4999799 z" /> |
986 | + <circle |
987 | + transform="matrix(0,1,1,0,0,0)" |
988 | + style="opacity:0.25;color:#000000;fill:none;stroke:url(#linearGradient4879);stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" |
989 | + id="circle4871" |
990 | + cx="1062.8622" |
991 | + cy="9.4999952" |
992 | + r="6.9999976" |
993 | + d="m 1069.8622,9.4999952 a 6.9999976,6.9999976 0 0 1 -7,6.9999978 6.9999976,6.9999976 0 0 1 -7,-6.9999978 6.9999976,6.9999976 0 0 1 7,-6.9999976 6.9999976,6.9999976 0 0 1 7,6.9999976 z" /> |
994 | + <circle |
995 | + r="7.24998" |
996 | + cy="9.4999952" |
997 | + cx="1062.8622" |
998 | + id="circle4873" |
999 | + style="opacity:0.25;color:#000000;fill:none;stroke:url(#linearGradient4881);stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" |
1000 | + transform="matrix(0,1,1,0,0,0)" |
1001 | + d="m 1070.1122,9.4999952 a 7.24998,7.24998 0 0 1 -7.25,7.2499798 7.24998,7.24998 0 0 1 -7.25,-7.2499798 7.24998,7.24998 0 0 1 7.25,-7.2499799 7.24998,7.24998 0 0 1 7.25,7.2499799 z" /> |
1002 | + <rect |
1003 | + style="color:#000000;fill:none;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" |
1004 | + id="rect4875" |
1005 | + width="19" |
1006 | + height="19" |
1007 | + x="-7.3563765e-06" |
1008 | + y="1053.3622" /> |
1009 | + </g> |
1010 | + <path |
1011 | + inkscape:connector-curvature="0" |
1012 | + id="path4893" |
1013 | + d="m 2.4849245,659.85555 -0.70703,0.707 0.35351,0.3535 1.94727,1.9473 -1.94727,1.9453 -0.35351,0.3535 0.70703,0.707 0.35351,-0.3535 1.94727,-1.9472 1.94726,1.9472 0.35352,0.3535 0.70703,-0.707 -0.35351,-0.3535 -1.94727,-1.9453 1.94727,-1.9473 0.35351,-0.3535 -0.70703,-0.707 -0.35352,0.3535 -1.94726,1.9472 -1.94727,-1.9472 -0.35351,-0.3535 z" |
1014 | + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;opacity:0.25;color:#000000;color-interpolation:sRGB;color-interpolation-filters:linearRGB;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;isolation:auto;mix-blend-mode:normal;enable-background:accumulate;clip-rule:nonzero;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;font-family:sans-serif;-inkscape-font-specification:sans-serif" /> |
1015 | + <path |
1016 | + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;color-interpolation:sRGB;color-interpolation-filters:linearRGB;fill:#7f4025;fill-opacity:1;stroke:none;stroke-width:1.10000002;marker:none;visibility:visible;display:inline;overflow:visible;isolation:auto;mix-blend-mode:normal;enable-background:accumulate;clip-rule:nonzero;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;font-family:sans-serif;-inkscape-font-specification:sans-serif" |
1017 | + d="m 7.0864845,658.78515 -0.39063,0.3886 -4.5996,4.5996 -0.38868,0.3887 0.77735,0.7774 0.39062,-0.3887 4.59961,-4.5996 0.38867,-0.3887 -0.77734,-0.7773 z" |
1018 | + id="path4895" |
1019 | + inkscape:connector-curvature="0" /> |
1020 | + <path |
1021 | + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;color-interpolation:sRGB;color-interpolation-filters:linearRGB;fill:#7f4025;fill-opacity:1;stroke:none;stroke-width:1.10000002;marker:none;visibility:visible;display:inline;overflow:visible;isolation:auto;mix-blend-mode:normal;enable-background:accumulate;clip-rule:nonzero;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;font-family:sans-serif;-inkscape-font-specification:sans-serif" |
1022 | + d="m 2.4849245,658.78515 -0.77735,0.7773 0.38868,0.3887 4.5996,4.5996 0.39063,0.3887 0.77734,-0.7774 -0.38867,-0.3887 -4.59961,-4.5996 -0.39062,-0.3886 z" |
1023 | + id="path4897" |
1024 | + inkscape:connector-curvature="0" /> |
1025 | + </g> |
1026 | +</svg> |
1027 | |
1028 | === added file 'resources/sheet_style_close_focused_pressed.svg' |
1029 | --- resources/sheet_style_close_focused_pressed.svg 1970-01-01 00:00:00 +0000 |
1030 | +++ resources/sheet_style_close_focused_pressed.svg 2014-04-02 13:15:24 +0000 |
1031 | @@ -0,0 +1,168 @@ |
1032 | +<?xml version="1.0" encoding="UTF-8" standalone="no"?> |
1033 | +<!-- Created with Inkscape (http://www.inkscape.org/) --> |
1034 | + |
1035 | +<svg |
1036 | + xmlns:dc="http://purl.org/dc/elements/1.1/" |
1037 | + xmlns:cc="http://creativecommons.org/ns#" |
1038 | + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" |
1039 | + xmlns:svg="http://www.w3.org/2000/svg" |
1040 | + xmlns="http://www.w3.org/2000/svg" |
1041 | + xmlns:xlink="http://www.w3.org/1999/xlink" |
1042 | + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" |
1043 | + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" |
1044 | + width="19" |
1045 | + height="19" |
1046 | + id="svg4747" |
1047 | + version="1.1" |
1048 | + inkscape:version="0.48+devel r" |
1049 | + viewBox="0 0 19 19" |
1050 | + sodipodi:docname="close_focused_pressed.svg"> |
1051 | + <defs |
1052 | + id="defs4749"> |
1053 | + <linearGradient |
1054 | + inkscape:collect="always" |
1055 | + xlink:href="#linearGradient4564" |
1056 | + id="linearGradient4552" |
1057 | + gradientUnits="userSpaceOnUse" |
1058 | + gradientTransform="translate(-1072.3622,-1053.3622)" |
1059 | + x1="2.0000153" |
1060 | + y1="1062.8622" |
1061 | + x2="16.999975" |
1062 | + y2="1062.8622" /> |
1063 | + <linearGradient |
1064 | + inkscape:collect="always" |
1065 | + id="linearGradient4564"> |
1066 | + <stop |
1067 | + style="stop-color:#f08054;stop-opacity:1" |
1068 | + offset="0" |
1069 | + id="stop4511" /> |
1070 | + <stop |
1071 | + style="stop-color:#f07c4e;stop-opacity:1" |
1072 | + offset="1" |
1073 | + id="stop4513" /> |
1074 | + </linearGradient> |
1075 | + <linearGradient |
1076 | + inkscape:collect="always" |
1077 | + xlink:href="#linearGradient4297" |
1078 | + id="linearGradient4554" |
1079 | + gradientUnits="userSpaceOnUse" |
1080 | + gradientTransform="translate(3.4765625e-5,0)" |
1081 | + x1="-1070.3622" |
1082 | + y1="8.9999962" |
1083 | + x2="-1055.3622" |
1084 | + y2="8.9999962" /> |
1085 | + <linearGradient |
1086 | + inkscape:collect="always" |
1087 | + id="linearGradient4297"> |
1088 | + <stop |
1089 | + style="stop-color:#ffffff;stop-opacity:1;" |
1090 | + offset="0" |
1091 | + id="stop4523" /> |
1092 | + <stop |
1093 | + style="stop-color:#bd9e82;stop-opacity:1" |
1094 | + offset="1" |
1095 | + id="stop4525" /> |
1096 | + </linearGradient> |
1097 | + <linearGradient |
1098 | + inkscape:collect="always" |
1099 | + xlink:href="#linearGradient4297" |
1100 | + id="linearGradient4556" |
1101 | + gradientUnits="userSpaceOnUse" |
1102 | + gradientTransform="matrix(1.0357118,0,0,1.0357118,37.956735,-0.33926172)" |
1103 | + x1="-1070.1036" |
1104 | + y1="9.4999952" |
1105 | + x2="-1055.6208" |
1106 | + y2="9.4999952" /> |
1107 | + </defs> |
1108 | + <sodipodi:namedview |
1109 | + id="base" |
1110 | + pagecolor="#ffffff" |
1111 | + bordercolor="#666666" |
1112 | + borderopacity="1.0" |
1113 | + inkscape:pageopacity="0.0" |
1114 | + inkscape:pageshadow="2" |
1115 | + inkscape:zoom="0.35" |
1116 | + inkscape:cx="130.64286" |
1117 | + inkscape:cy="454.21428" |
1118 | + inkscape:document-units="px" |
1119 | + inkscape:current-layer="layer1" |
1120 | + showgrid="false" |
1121 | + fit-margin-top="0" |
1122 | + fit-margin-left="0" |
1123 | + fit-margin-right="0" |
1124 | + fit-margin-bottom="0" /> |
1125 | + <metadata |
1126 | + id="metadata4752"> |
1127 | + <rdf:RDF> |
1128 | + <cc:Work |
1129 | + rdf:about=""> |
1130 | + <dc:format>image/svg+xml</dc:format> |
1131 | + <dc:type |
1132 | + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> |
1133 | + <dc:title></dc:title> |
1134 | + </cc:Work> |
1135 | + </rdf:RDF> |
1136 | + </metadata> |
1137 | + <g |
1138 | + inkscape:label="Layer 1" |
1139 | + inkscape:groupmode="layer" |
1140 | + id="layer1" |
1141 | + transform="translate(411.35715,-967.57648)"> |
1142 | + <g |
1143 | + style="display:inline" |
1144 | + transform="translate(-411.35714,-85.785707)" |
1145 | + inkscape:export-ydpi="90" |
1146 | + inkscape:export-xdpi="90" |
1147 | + inkscape:export-filename="maximize.png" |
1148 | + id="g4540"> |
1149 | + <circle |
1150 | + style="color:#000000;fill:#d0c7bf;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:8;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" |
1151 | + id="circle4542" |
1152 | + cx="9.4999924" |
1153 | + cy="1062.8622" |
1154 | + r="8.5" |
1155 | + d="m 17.999992,1062.8622 a 8.5,8.5 0 0 1 -8.4999996,8.5 8.5,8.5 0 0 1 -8.50000003,-8.5 8.5,8.5 0 0 1 8.50000003,-8.5 8.5,8.5 0 0 1 8.4999996,8.5 z" /> |
1156 | + <circle |
1157 | + r="7.49998" |
1158 | + cy="9.4999952" |
1159 | + cx="-1062.8622" |
1160 | + id="circle4544" |
1161 | + style="color:#000000;fill:url(#linearGradient4552);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:8;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" |
1162 | + transform="matrix(0,-1,1,0,0,0)" |
1163 | + d="m -1055.3622,9.4999952 a 7.49998,7.49998 0 0 1 -7.5,7.4999798 7.49998,7.49998 0 0 1 -7.5,-7.4999798 7.49998,7.49998 0 0 1 7.5,-7.4999799 7.49998,7.49998 0 0 1 7.5,7.4999799 z" /> |
1164 | + <circle |
1165 | + transform="matrix(0,-1,1,0,0,0)" |
1166 | + style="opacity:0.05;color:#000000;fill:none;stroke:url(#linearGradient4554);stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" |
1167 | + id="circle4546" |
1168 | + cx="-1062.8622" |
1169 | + cy="9.4999952" |
1170 | + r="6.9999976" |
1171 | + d="m -1055.8622,9.4999952 a 6.9999976,6.9999976 0 0 1 -7,6.9999978 6.9999976,6.9999976 0 0 1 -7,-6.9999978 6.9999976,6.9999976 0 0 1 7,-6.9999976 6.9999976,6.9999976 0 0 1 7,6.9999976 z" /> |
1172 | + <circle |
1173 | + r="7.24998" |
1174 | + cy="9.4999952" |
1175 | + cx="-1062.8622" |
1176 | + id="circle4548" |
1177 | + style="opacity:0.05;color:#000000;fill:none;stroke:url(#linearGradient4556);stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" |
1178 | + transform="matrix(0,-1,1,0,0,0)" |
1179 | + d="m -1055.6122,9.4999952 a 7.24998,7.24998 0 0 1 -7.25,7.2499798 7.24998,7.24998 0 0 1 -7.25,-7.2499798 7.24998,7.24998 0 0 1 7.25,-7.2499799 7.24998,7.24998 0 0 1 7.25,7.2499799 z" /> |
1180 | + <rect |
1181 | + style="color:#000000;fill:none;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" |
1182 | + id="rect4550" |
1183 | + width="19" |
1184 | + height="19" |
1185 | + x="-7.3563765e-06" |
1186 | + y="1053.3622" /> |
1187 | + </g> |
1188 | + <path |
1189 | + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;color-interpolation:sRGB;color-interpolation-filters:linearRGB;fill:#7f4025;fill-opacity:1;stroke:none;stroke-width:1.10000002;marker:none;visibility:visible;display:inline;overflow:visible;isolation:auto;mix-blend-mode:normal;enable-background:accumulate;clip-rule:nonzero;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;font-family:sans-serif;-inkscape-font-specification:sans-serif" |
1190 | + d="m -399.55637,973.99943 -0.39063,0.3886 -4.5996,4.5996 -0.38868,0.3887 0.77735,0.7774 0.39062,-0.3887 4.59961,-4.5996 0.38867,-0.3887 -0.77734,-0.7773 z" |
1191 | + id="path4989" |
1192 | + inkscape:connector-curvature="0" /> |
1193 | + <path |
1194 | + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;color-interpolation:sRGB;color-interpolation-filters:linearRGB;fill:#7f4025;fill-opacity:1;stroke:none;stroke-width:1.10000002;marker:none;visibility:visible;display:inline;overflow:visible;isolation:auto;mix-blend-mode:normal;enable-background:accumulate;clip-rule:nonzero;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;font-family:sans-serif;-inkscape-font-specification:sans-serif" |
1195 | + d="m -404.15793,973.99943 -0.77735,0.7773 0.38868,0.3887 4.5996,4.5996 0.39063,0.3887 0.77734,-0.7774 -0.38867,-0.3887 -4.59961,-4.5996 -0.39062,-0.3886 z" |
1196 | + id="path4991" |
1197 | + inkscape:connector-curvature="0" /> |
1198 | + </g> |
1199 | +</svg> |
LGTM