Merge lp:~3v1n0/unity/forcequit-dialog into lp:unity

Proposed by Marco Trevisan (Treviño)
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
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 SheetStyleDialog(.unity-force-quit) and that by default uses the standard decoration settings.
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?"

To post a comment you must log in.
Revision history for this message
Christopher Townsend (townsend) wrote :

LGTM

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Eleni Maria Stea (hikiko) wrote :

LGTM :)

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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>