Merge lp:~3v1n0/unity/unity-decorations 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: 3632
Proposed branch: lp:~3v1n0/unity/unity-decorations
Merge into: lp:unity
Diff against target: 10234 lines (+6824/-1487)
64 files modified
CMakeLists.txt (+5/-0)
config.h.cmake (+1/-0)
decorations/CMakeLists.txt (+38/-0)
decorations/DecoratedWindow.cpp (+654/-0)
decorations/DecoratedWindow.h (+73/-0)
decorations/DecorationsDataPool.cpp (+153/-0)
decorations/DecorationsDataPool.h (+59/-0)
decorations/DecorationsEdge.cpp (+137/-0)
decorations/DecorationsEdge.h (+64/-0)
decorations/DecorationsEdgeBorders.cpp (+99/-0)
decorations/DecorationsEdgeBorders.h (+43/-0)
decorations/DecorationsGrabEdge.cpp (+102/-0)
decorations/DecorationsGrabEdge.h (+53/-0)
decorations/DecorationsInputMixer.cpp (+176/-0)
decorations/DecorationsInputMixer.h (+66/-0)
decorations/DecorationsManager.cpp (+386/-0)
decorations/DecorationsManager.h (+74/-0)
decorations/DecorationsPriv.h (+165/-0)
decorations/DecorationsTitle.cpp (+116/-0)
decorations/DecorationsTitle.h (+61/-0)
decorations/DecorationsWidgets.cpp (+493/-0)
decorations/DecorationsWidgets.h (+190/-0)
decorations/DecorationsWindowButton.cpp (+216/-0)
decorations/DecorationsWindowButton.h (+58/-0)
decorations/pch/decorations_pch.hh (+39/-0)
panel/PanelMenuView.cpp (+116/-254)
panel/PanelMenuView.h (+9/-14)
plugins/unityshell/CMakeLists.txt (+27/-2)
plugins/unityshell/src/unityshell.cpp (+291/-412)
plugins/unityshell/src/unityshell.h (+29/-17)
plugins/unityshell/src/unityshell_glow.cpp (+4/-9)
plugins/unityshell/unityshell.xml.in (+69/-1)
tests/CMakeLists.txt (+14/-9)
tests/decoration_mock_item.h (+88/-0)
tests/test_decorations_input_mixer.cpp (+493/-0)
tests/test_decorations_widgets.cpp (+512/-0)
tests/test_texture_cache.cpp (+16/-1)
tests/test_unity_window_style.cpp (+3/-3)
unity-shared/CMakeLists.txt (+14/-1)
unity-shared/CompizUtils.cpp (+181/-0)
unity-shared/CompizUtils.h (+116/-0)
unity-shared/DebugDBusInterface.cpp (+6/-1)
unity-shared/DecorationStyle.cpp (+640/-0)
unity-shared/DecorationStyle.h (+141/-0)
unity-shared/Introspectable.cpp (+4/-1)
unity-shared/IntrospectionData.cpp (+21/-0)
unity-shared/IntrospectionData.h (+8/-0)
unity-shared/PanelStyle.cpp (+58/-259)
unity-shared/PanelStyle.h (+16/-38)
unity-shared/PluginAdapter.cpp (+28/-311)
unity-shared/PluginAdapter.h (+0/-22)
unity-shared/StandaloneDecorationStyle.cpp (+146/-0)
unity-shared/StandaloneWindowManager.cpp (+15/-20)
unity-shared/StandaloneWindowManager.h (+2/-3)
unity-shared/TextureCache.cpp (+6/-3)
unity-shared/TextureCache.h (+3/-2)
unity-shared/UnityWindowStyle.cpp (+1/-1)
unity-shared/UnityWindowStyle.h (+1/-1)
unity-shared/WindowButtonPriv.h (+1/-0)
unity-shared/WindowButtons.cpp (+69/-79)
unity-shared/WindowButtons.h (+1/-0)
unity-shared/WindowManager.h (+4/-5)
unity-shared/XWindowManager.cpp (+146/-11)
unity-shared/XWindowManager.h (+4/-7)
To merge this branch: bzr merge lp:~3v1n0/unity/unity-decorations
Reviewer Review Type Date Requested Status
Christopher Townsend Approve
Brandon Schaefer (community) Approve
PS Jenkins bot (community) continuous-integration Approve
Review via email: mp+202582@code.launchpad.net

Commit message

decorations: added new unity-decorations fully gtk-css-themed inside unity

Description of the change

Added new decorations to unity, inside unity itself instead of depending on the
compiz "decor" plugin and on a decorator (gtk-window-decorator).
My mission: «Everything changes, but nothing changes»; so completely new backend,
same results.

- Support for full Gtk3 Theming (https://wiki.ubuntu.com/Unity/Theming)
- Improved resizing speed when using "Normal Resize" in compiz
- Removed duplicated textures, IPC between compiz and the decorator
- Anti aliased corners!!

Screenshot:
 - Ambiance: http://ubuntuone.com/0QIWISIXmf1zRJfDiIqLHz
 - Radiance: http://ubuntuone.com/1CfUWwRj0xICU3otSfjTyY

Things to do:
- Add right-click window menu support
- Add "force quit" dialog

Not supported:
- Window buttons positions (we want a consistent user experience in unity, that
  covers both the windows and the top panel and here the window buttons are, by
  design on the top left corner of a window. Always).
- Custom actions on bar clicks (maybe to be supported later)
- Different decorators, just use themes.

This branch needs has a "soft dependency" on lp:~3v1n0/ubuntu-themes/unity-decorations
(for proper theming) and on lp:~3v1n0/compiz/disable-decor-with-unity to disable
decor plugin on settings.

=================

Technical details (use a better diff visualizer for review, like bzr qdiff):

- Added DecorationsManager: that handles all the windows, creates them and
  redirect to the proper target the relative events.
- DecoratedWindow: wraps a CompWindow, set the extents, generates the background
  textures, the top layout and draws them on screen.

Both DecorationsManager is allocated and controlled by UnityScreen (that redirects
the events to it), while each UnityWindow controls a DecoratedWindow, and redirects
to it the relevant compiz calls.

As for the decoration widgets, since I needed a simple way to handle textures and
to create a simple layout for displaying them, depending on the window size and
positioning, I've decided to write a small "widgets library" used to paint elements
and handle input events. What I called decoration::Item is basically a simple
widget with a geometry and that can be added into a container and managed by it.
Also, I've built an "InputMixer" (event compositor) that has the role to redirect
events to the proper widget that it manages.

So, with these tools, I've built all the widgets that are in a decoration:
 - A DecorationsEdgeBorders, that is a container of DecorationsGrabEdge, that are
   input-only widgets that care about mouse events, draw the right mouse pointers
   and allow to resize and move a window (now the GrabEdge has the same logic of
   the PanelGrabArea).
 - A Layout containing the window buttons and the window title.

To properly theme the decorations I've built a decoration::Style class that
defines custom gtk-css parameters for an "UnityDecoration" widget that is used
for theming the whole decorations; read the values, caches the relevant settings
and emits signals when theme or font parameters changes. panel::Style has been
rewritten to use decoration::Style as its main source.

Other aspects:
- Removed all the unneeded code for decorating, undecorating and monitoring
  decorations from PluginAdapter.
- Moved some XLib-only calls from PluginAdapter to XWindowManager and optimized
  GetWindowName using the new GetStringProperty.
- Removing the unneeded code from PanelMenuView that was handling the decorations
  and use decoration::Style on it; also remove a lot of unneeded redraws.
- Use decoration::Style for painting fake-decorations in UnityWindow.
- Added CompizUtils to unity-shared-compiz, that contains some structs, classes
  and functions that are useful for other components that are handling things
  with compiz (allows removing duplicated code from UnityWindow as well).
- Added decoration::DataPool utility class to load and cache shared resources
- Shadows are based on simple pixmaps that are generated through cairo just
  once per session (or when the shadow settings change) and shared by all
  the windows.
- Fixed linking of standalone components (and tests) against libunity-protocol-private
  (now the library dir is added to dpath, no need to use LD_LIBRARY_PATH any more).
- Added compiz settings to override theme shadow parameters.
- Improved fallback window buttons (now they're filled with foreground color).
- All the decoration objects support debug introspection for autopilot tests.
- Added unit tests for decoration::Item and InputMixer, more tests to come later.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Brandon Schaefer (brandontschaefer) wrote :

On a side note this only causes 4 conflicts in my panel high dpi code!

Text conflict in unity-shared/PanelStyle.cpp
Text conflict in unity-shared/PanelStyle.h
Text conflict in unity-shared/WindowButtonPriv.h
Text conflict in unity-shared/WindowButtons.cpp
4 conflicts encountered.

So it shouldn't be to bad to merge those over this. Ill get on that tomorrow after I finish going through this!

Revision history for this message
Brandon Schaefer (brandontschaefer) wrote :
Download full text (6.5 KiB)

Ignore what I already sent you! Im at about 7-8k (The test looked good!) What I have so far:

You shouldn't need the ';' but i could be wrong

+ set(UNITY_STANDALONE_LADD ${UNITY_STANDALONE_LADD};${UNITY_PROTOCOL_PRIVATE_LIB})

----

To make things a but more readable, we should split this function into 2 smaller functions that accept the frame_geo as an arguments:

+void Window::Impl::UpdateFrame()

1, + if (!frame_), should then just call CreateNewFrame(frame_geo);

2, + if (frame_geo_ != frame_geo), UpdateFrameGeo(frame_geo) ... or something like that, so the function will just look like:

+void Window::Impl::UpdateFrame()
+{
+ auto const& input = win_->input();
+ auto const& server = win_->serverGeometry();
+ nux::Geometry frame_geo(0, 0, server.widthIncBorders() + input.left + input.right,
+ server.heightIncBorders() + input.top + input.bottom);
+
+ if (win_->shaded())
+ frame_geo.height = input.top + input.bottom;
+
+ if (!frame_)
+ CreateNewFrame(frame_geo);
+
+ if (frame_geo_ != frame_geo)
+ UpdateFrameGeo(frame_geo);
+}

Just makes things a bit more readable, imo.

----

An if statement is a bit more readable here.

+ return active() || parent_->scaled() ? mi->active_shadow_pixmap_->texture() : mi->inactive_shadow_pixmap_->texture();

+ return active() || parent_->scaled() ? manager_->active_shadow_radius() : manager_->inactive_shadow_radius();

----

Should be a const pointer, or rather could be a const pointer to const data:

auto const* const texture.

+ auto* texture = ShadowTexture();

+ auto* win = impl_->win_;

----

Are these just for testing? As I see a lot of friend classes...which kind of defeats the purpose of encapsulation. It'll make it hard to track down bugs when all these other classes have access to the private members.... I would much rather provide an access function to these for Read only if thats whats needed. (Vs having read/write of private members.)

+ friend class Manager;

+ friend class Window;

+ friend class Window;
+ friend struct Manager::Impl;

+ friend class Manager;
+ friend struct Window::Impl;

+ friend class InputMixer;

+ friend class Item;

+ friend class decoration::Manager;

+ friend class decoration::Window;
+ friend class decoration::Manager;

----

Why make a global read/write variable for this? This should be part of the class.

+Display* dpy = nullptr;

----

You can simply this:

+EdgeBorders::EdgeBorders(CompWindow* win)
+{
+ items_.resize(size_t(Edge::Type::Size));
+
+ auto item = std::make_shared<Edge>(win, Edge::Type::TOP);
+ items_[unsigned(Edge::Type::TOP)] = item;
+
+ item = std::make_shared<Edge>(win, Edge::Type::TOP_LEFT);
+ items_[unsigned(Edge::Type::TOP_LEFT)] = item;
+
+ item = std::make_shared<Edge>(win, Edge::Type::TOP_RIGHT);
+ items_[unsigned(Edge::Type::TOP_RIGHT)] = item;
+
+ item = std::make_shared<Edge>(win, Edge::Type::LEFT);
+ items_[unsigned(Edge::Type::LEFT)] = item;
+
+ item = std::make_shared<Edge>(win, Edge::Type::RIGHT);
+ items_[unsigned(Edge::Type::RIGHT)] = item;
+
+ item = std::make_shared<Edge>(win, Edge::Type::BOTTOM);
+ items_[unsigned(Edge::Type::BOTTOM)] = item;
+
+ item = std::...

Read more...

Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote :
Download full text (8.3 KiB)

> You shouldn't need the ';' but i could be wrong
>
> + set(UNITY_STANDALONE_LADD ${UNITY_STANDALONE_LADD};${UNITY_PROTOCOL_PRIVATE_LIB})

Oh, I thought I had a linking error without it, but it seems to go...
So, I've removed it. This is with gold btw.

> To make things a but more readable, we should split this function into 2 smaller
> functions that accept the frame_geo as an arguements:
>
> +void Window::Impl::UpdateFrame()
>
> 1, + if (!frame_), should then just call CreateNewFrame(frame_geo);

> 2, + if (frame_geo_ != frame_geo), UpdateFrameGeo(frame_geo) ... or something like that, so the function will just look like:
>
> +void Window::Impl::UpdateFrame()
> +{
> + auto const& input = win_->input();
> + auto const& server = win_->serverGeometry();
> + nux::Geometry frame_geo(0, 0, server.widthIncBorders() + input.left + input.right,
> + server.heightIncBorders() + input.top + input.bottom);
> +
> + if (win_->shaded())
> + frame_geo.height = input.top + input.bottom;
> +
> + if (!frame_)
> + CreateNewFrame(frame_geo);
> +
> + if (frame_geo_ != frame_geo)
> + UpdateFrameGeo(frame_geo);
> +}
>

Ok, sounds good!
I didn't that to keep the frame_geo in the same function without passing it, and
not to reclare input, in UpdateFrameGeo, but it's not really a problem.
I think you're right.

> An if statement is a bit more readable here.

> + return active() || parent_->scaled() ? mi->active_shadow_pixmap_->texture() : mi->inactive_shadow_pixmap_->texture();

> + return active() || parent_->scaled() ? manager_->active_shadow_radius() : manager_->inactive_shadow_radius();

Agreedo, it was smaller at the beginning, then it got bigger :P.

> Should be a const pointer, or rather could be a const pointer to const data:
>
> auto const* const texture.
>
> + auto* texture = ShadowTexture();
>
> + auto* win = impl_->win_;
>
> ----

It doesn't change much, but ok.

> Are these just for testing? As I see a lot of friend classes...which kind of
> defeats the purpose of encaspulation. It'll make it hard to track down bugs when
> all these other classes have access to the private members.... I would much rather
> provide an access funtion to these for Read only if thats whats needed. (Vs having
> read/write of private members.)
>
> + friend class Manager;

Unfortunately I need these to make possible to a Window to access to Impl
functions that are private, but not for manager... I mean, decoration::Manager
is strictly connected to the windows and it has to access to some methods that I
don't want to make visible to everyone... So, unfortunately here we can't use
protected in the way is in java or other languages (access to the members of the
"package"), so I need to use this way... That I don't like, but it's the only
method we have to access to private methods in very limited cases.
For sure the friendship with UnityScreen/UnityWindow can be removed (it was there
for testing), and I could also remove the friendship with the Impl structs, by
just adding some more "public" methods to them, so that there's no private write
access to the members... That's what already happens in fact, but if we want to
protect more I...

Read more...

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Brandon Schaefer (brandontschaefer) wrote :

I've been using this branch for about a week now, and its working well!

Would like at lease one more person to go through the code, as this is a larger branch!

review: Approve
Revision history for this message
Christopher Townsend (townsend) wrote :

This works well for me too and I have nothing to add on the code itself. Well done!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2014-01-03 16:26:42 +0000
3+++ CMakeLists.txt 2014-01-23 15:21:26 +0000
4@@ -157,6 +157,7 @@
5 set (TESTDATADIR "${CMAKE_CURRENT_SOURCE_DIR}/tests/data")
6
7 find_package (PkgConfig)
8+execute_process (COMMAND ${PKG_CONFIG_EXECUTABLE} gtk+-3.0 --variable prefix OUTPUT_VARIABLE GTK_PREFIX OUTPUT_STRIP_TRAILING_WHITESPACE)
9 execute_process (COMMAND ${PKG_CONFIG_EXECUTABLE} unity --variable lensesdir OUTPUT_VARIABLE LENSES_DIR OUTPUT_STRIP_TRAILING_WHITESPACE)
10 execute_process (COMMAND ${PKG_CONFIG_EXECUTABLE} indicator3-0.4 --variable indicatordir OUTPUT_VARIABLE INDICATORDIR OUTPUT_STRIP_TRAILING_WHITESPACE)
11 execute_process (COMMAND ${PKG_CONFIG_EXECUTABLE} indicator3-0.4 --variable iconsdir OUTPUT_VARIABLE INDICATORICONDIR OUTPUT_STRIP_TRAILING_WHITESPACE)
12@@ -253,12 +254,16 @@
13
14 pkg_check_modules (CACHED_UNITY_DEPS REQUIRED ${UNITY_PLUGIN_DEPS})
15 pkg_check_modules (CACHED_UNITY_PRIVATE_DEPS REQUIRED ${UNITY_PROTOCOL_PRIVATE_DEPS})
16+find_library (UNITY_PROTOCOL_PRIVATE_LIB unity-protocol-private ${CACHED_UNITY_PRIVATE_DEPS_LIBDIR} ${CACHED_UNITY_PRIVATE_DEPS_LIBRARY_DIRS})
17+set(UNITY_STANDALONE_LADD ${UNITY_STANDALONE_LADD} ${UNITY_PROTOCOL_PRIVATE_LIB})
18+
19 add_subdirectory(unity-shared)
20 add_subdirectory(dash)
21 add_subdirectory(launcher)
22 if (ENABLE_X_SUPPORT)
23 add_subdirectory(hud)
24 add_subdirectory(panel)
25+ add_subdirectory(decorations)
26 add_subdirectory(plugins/unityshell)
27 add_subdirectory(plugins/networkarearegion)
28 add_subdirectory(plugins/unitydialog)
29
30=== modified file 'config.h.cmake'
31--- config.h.cmake 2013-07-22 17:11:47 +0000
32+++ config.h.cmake 2014-01-23 15:21:26 +0000
33@@ -11,6 +11,7 @@
34 #cmakedefine TESTDATADIR "@TESTDIRDIR@"
35 #cmakedefine GETTEXT_PACKAGE "@GETTEXT_PACKAGE@"
36 #cmakedefine LENSES_DIR "@LENSES_DIR@"
37+#cmakedefine GTK_PREFIX "@GTK_PREFIX@"
38 #ifndef INDICATORDIR
39 #cmakedefine INDICATORDIR "@INDICATORDIR@"
40 #endif
41
42=== added directory 'decorations'
43=== added file 'decorations/CMakeLists.txt'
44--- decorations/CMakeLists.txt 1970-01-01 00:00:00 +0000
45+++ decorations/CMakeLists.txt 2014-01-23 15:21:26 +0000
46@@ -0,0 +1,38 @@
47+find_package (PkgConfig)
48+pkg_check_modules (COMPIZ_COMPOSITE REQUIRED "compiz-composite")
49+
50+set (CFLAGS
51+ ${COMPIZ_COMPOSITE_CFLAGS}
52+ ${CACHED_UNITY_DEPS_CFLAGS}
53+ ${CACHED_UNITY_DEPS_CFLAGS_OTHER}
54+ ${PIC_FLAGS}
55+ )
56+
57+string (REPLACE ";" " " CFLAGS "${CFLAGS}")
58+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CFLAGS}")
59+include_directories (.. ../UnityCore ../unity-shared ${CMAKE_BINARY_DIR})
60+
61+# This makes linker to include library dir in RUNPATH
62+find_library (COMPIZ_COMPOSITE_LIB composite ${COMPIZ_COMPOSITE_LIBDIR})
63+set (LIBS ${CACHED_UNITY_DEPS_LDFLAGS} ${COMPIZ_COMPOSITE_LIB} ${COMPIZ_COMPOSITE_LDFLAGS} unity-shared-compiz)
64+
65+#
66+# Headers & Sources
67+#
68+set (DECORATION_SOURCES
69+ DecorationsManager.cpp
70+ DecoratedWindow.cpp
71+ DecorationsWidgets.cpp
72+ DecorationsWindowButton.cpp
73+ DecorationsEdge.cpp
74+ DecorationsGrabEdge.cpp
75+ DecorationsEdgeBorders.cpp
76+ DecorationsTitle.cpp
77+ DecorationsInputMixer.cpp
78+ DecorationsDataPool.cpp
79+ )
80+
81+add_library (decorations-lib STATIC ${DECORATION_SOURCES})
82+target_link_libraries (decorations-lib ${LIBS})
83+add_dependencies (decorations-lib unity-core-${UNITY_API_VERSION} unity-shared-compiz)
84+add_pch(pch/decorations_pch.hh decorations-lib)
85
86=== added file 'decorations/DecoratedWindow.cpp'
87--- decorations/DecoratedWindow.cpp 1970-01-01 00:00:00 +0000
88+++ decorations/DecoratedWindow.cpp 2014-01-23 15:21:26 +0000
89@@ -0,0 +1,654 @@
90+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
91+/*
92+ * Copyright (C) 2013 Canonical Ltd
93+ *
94+ * This program is free software: you can redistribute it and/or modify
95+ * it under the terms of the GNU General Public License version 3 as
96+ * published by the Free Software Foundation.
97+ *
98+ * This program is distributed in the hope that it will be useful,
99+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
100+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
101+ * GNU General Public License for more details.
102+ *
103+ * You should have received a copy of the GNU General Public License
104+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
105+ *
106+ * Authored by: Marco Trevisan <marco.trevisan@canonical.com>
107+ */
108+
109+#include <NuxCore/Logger.h>
110+#include "DecorationsPriv.h"
111+#include "DecorationsWindowButton.h"
112+#include "DecorationsEdgeBorders.h"
113+#include "DecorationsGrabEdge.h"
114+#include "WindowManager.h"
115+
116+namespace unity
117+{
118+namespace decoration
119+{
120+namespace
121+{
122+DECLARE_LOGGER(logger, "unity.decoration.window");
123+}
124+
125+Window::Impl::Impl(Window* parent, CompWindow* win)
126+ : active(false)
127+ , parent_(parent)
128+ , win_(win)
129+ , cwin_(CompositeWindow::get(win_))
130+ , glwin_(GLWindow::get(win_))
131+ , frame_(0)
132+ , dirty_geo_(true)
133+{
134+ active.changed.connect([this] (bool active) {
135+ bg_textures_.clear();
136+ if (top_layout_) top_layout_->focused = active;
137+ RedrawDecorations();
138+ });
139+
140+ parent->title.SetGetterFunction([this] {
141+ if (title_)
142+ return title_->text();
143+
144+ if (last_title_.empty())
145+ last_title_ = WindowManager::Default().GetWindowName(win_->id());
146+
147+ return last_title_;
148+ });
149+
150+ parent->title.SetSetterFunction([this] (std::string const& new_title) {
151+ if (!title_)
152+ {
153+ if (last_title_ != new_title)
154+ {
155+ last_title_ = new_title;
156+ return true;
157+ }
158+
159+ return false;
160+ }
161+
162+ if (new_title == title_->text())
163+ return false;
164+
165+ title_->text = new_title;
166+ return true;
167+ });
168+
169+ parent->scaled.changed.connect(sigc::hide(sigc::mem_fun(this, &Impl::Update)));
170+
171+ if (win_->isViewable() || win_->shaded())
172+ Update();
173+}
174+
175+Window::Impl::~Impl()
176+{
177+ Undecorate();
178+}
179+
180+void Window::Impl::Update()
181+{
182+ ShouldBeDecorated() ? Decorate() : Undecorate();
183+}
184+
185+void Window::Impl::Decorate()
186+{
187+ SetupExtents();
188+ UpdateFrame();
189+ SetupWindowControls();
190+}
191+
192+void Window::Impl::Undecorate()
193+{
194+ UnsetExtents();
195+ UnsetFrame();
196+ CleanupWindowControls();
197+ bg_textures_.clear();
198+}
199+
200+void Window::Impl::UnsetExtents()
201+{
202+ if (win_->hasUnmapReference())
203+ return;
204+
205+ CompWindowExtents empty(0, 0, 0, 0);
206+
207+ if (win_->border() != empty || win_->input() != empty)
208+ win_->setWindowFrameExtents(&empty, &empty);
209+}
210+
211+void Window::Impl::SetupExtents()
212+{
213+ if (win_->hasUnmapReference())
214+ return;
215+
216+ auto const& sb = Style::Get()->Border();
217+ CompWindowExtents border(sb.left, sb.right, sb.top, sb.bottom);
218+
219+ auto const& ib = Style::Get()->InputBorder();
220+ CompWindowExtents input(sb.left + ib.left, sb.right + ib.right,
221+ sb.top + ib.top, sb.bottom + ib.bottom);
222+
223+ if (win_->border() != border || win_->input() != input)
224+ win_->setWindowFrameExtents(&border, &input);
225+}
226+
227+void Window::Impl::UnsetFrame()
228+{
229+ if (!frame_)
230+ return;
231+
232+ XDestroyWindow(screen->dpy(), frame_);
233+ framed.emit(false, frame_);
234+ frame_ = 0;
235+ frame_geo_.Set(0, 0, 0, 0);
236+}
237+
238+void Window::Impl::UpdateFrame()
239+{
240+ auto const& input = win_->input();
241+ auto const& server = win_->serverGeometry();
242+ nux::Geometry frame_geo(0, 0, server.widthIncBorders() + input.left + input.right,
243+ server.heightIncBorders() + input.top + input.bottom);
244+
245+ if (win_->shaded())
246+ frame_geo.height = input.top + input.bottom;
247+
248+ if (!frame_)
249+ CreateFrame(frame_geo);
250+
251+ if (frame_geo_ != frame_geo)
252+ UpdateFrameGeo(frame_geo);
253+}
254+
255+void Window::Impl::CreateFrame(nux::Geometry const& frame_geo)
256+{
257+ /* Since we're reparenting windows here, we need to grab the server
258+ * which sucks, but its necessary */
259+ Display* dpy = screen->dpy();
260+ XGrabServer(dpy);
261+
262+ XSetWindowAttributes attr;
263+ attr.event_mask = StructureNotifyMask | ButtonPressMask | ButtonReleaseMask |
264+ EnterWindowMask | LeaveWindowMask | PointerMotionMask;
265+ attr.override_redirect = True;
266+
267+ auto parent = win_->frame();
268+ frame_ = XCreateWindow(dpy, parent, frame_geo.x, frame_geo.y,
269+ frame_geo.width, frame_geo.height, 0, CopyFromParent,
270+ InputOnly, CopyFromParent, CWOverrideRedirect | CWEventMask, &attr);
271+
272+ if (screen->XShape())
273+ XShapeSelectInput(dpy, frame_, ShapeNotifyMask);
274+
275+ XMapWindow(dpy, frame_);
276+ framed.emit(true, frame_);
277+
278+ XUngrabServer(dpy);
279+}
280+
281+void Window::Impl::UpdateFrameGeo(nux::Geometry const& frame_geo)
282+{
283+ auto const& input = win_->input();
284+ Display* dpy = screen->dpy();
285+ XMoveResizeWindow(dpy, frame_, frame_geo.x, frame_geo.y, frame_geo.width, frame_geo.height);
286+ XLowerWindow(dpy, frame_);
287+
288+ int i = 0;
289+ XRectangle rects[4];
290+
291+ rects[i].x = 0;
292+ rects[i].y = 0;
293+ rects[i].width = frame_geo.width;
294+ rects[i].height = input.top;
295+
296+ if (rects[i].width && rects[i].height)
297+ i++;
298+
299+ rects[i].x = 0;
300+ rects[i].y = input.top;
301+ rects[i].width = input.left;
302+ rects[i].height = frame_geo.height - input.top - input.bottom;
303+
304+ if (rects[i].width && rects[i].height)
305+ i++;
306+
307+ rects[i].x = frame_geo.width - input.right;
308+ rects[i].y = input.top;
309+ rects[i].width = input.right;
310+ rects[i].height = frame_geo.height - input.top - input.bottom;
311+
312+ if (rects[i].width && rects[i].height)
313+ i++;
314+
315+ rects[i].x = 0;
316+ rects[i].y = frame_geo.height - input.bottom;
317+ rects[i].width = frame_geo.width;
318+ rects[i].height = input.bottom;
319+
320+ if (rects[i].width && rects[i].height)
321+ i++;
322+
323+ XShapeCombineRectangles(dpy, frame_, ShapeBounding, 0, 0, rects, i, ShapeSet, YXBanded);
324+
325+ frame_geo_ = frame_geo;
326+ SyncXShapeWithFrameRegion();
327+}
328+
329+void Window::Impl::SyncXShapeWithFrameRegion()
330+{
331+ frame_region_ = CompRegion();
332+
333+ int n = 0;
334+ int order = 0;
335+ XRectangle *rects = nullptr;
336+
337+ rects = XShapeGetRectangles(screen->dpy(), frame_, ShapeInput, &n, &order);
338+ if (!rects)
339+ return;
340+
341+ for (int i = 0; i < n; ++i)
342+ {
343+ auto& rect = rects[i];
344+ frame_region_ += CompRegion(rect.x, rect.y, rect.width, rect.height);
345+ }
346+
347+ XFree(rects);
348+
349+ win_->updateFrameRegion();
350+}
351+
352+void Window::Impl::SetupWindowControls()
353+{
354+ if (top_layout_)
355+ return;
356+
357+ auto const& style = Style::Get();
358+ theme_changed_ = style->theme.changed.connect([this] (std::string const&) {
359+ Undecorate();
360+ Decorate();
361+ });
362+
363+ input_mixer_ = std::make_shared<InputMixer>();
364+
365+ if (win_->actions() & CompWindowActionResizeMask)
366+ edge_borders_ = std::make_shared<EdgeBorders>(win_);
367+ else if (win_->actions() & CompWindowActionMoveMask)
368+ edge_borders_ = std::make_shared<GrabEdge>(win_);
369+ else
370+ edge_borders_.reset();
371+
372+ input_mixer_->PushToFront(edge_borders_);
373+
374+ auto padding = style->Padding(Side::TOP);
375+ top_layout_ = std::make_shared<Layout>();
376+ top_layout_->left_padding = padding.left;
377+ top_layout_->right_padding = padding.right;
378+ top_layout_->top_padding = padding.top;
379+ top_layout_->focused = active();
380+
381+ if (win_->actions() & CompWindowActionCloseMask)
382+ top_layout_->Append(std::make_shared<WindowButton>(win_, WindowButtonType::CLOSE));
383+
384+ if (win_->actions() & CompWindowActionMinimizeMask)
385+ top_layout_->Append(std::make_shared<WindowButton>(win_, WindowButtonType::MINIMIZE));
386+
387+ if (win_->actions() & (CompWindowActionMaximizeHorzMask|CompWindowActionMaximizeVertMask))
388+ top_layout_->Append(std::make_shared<WindowButton>(win_, WindowButtonType::MAXIMIZE));
389+
390+ title_ = std::make_shared<Title>();
391+ title_->text = last_title_.empty() ? WindowManager::Default().GetWindowName(win_->id()) : last_title_;
392+ title_->sensitive = false;
393+ last_title_.clear();
394+
395+ auto title_layout = std::make_shared<Layout>();
396+ title_layout->left_padding = style->TitleIndent();
397+ title_layout->Append(title_);
398+ top_layout_->Append(title_layout);
399+
400+ input_mixer_->PushToFront(top_layout_);
401+
402+ RedrawDecorations();
403+}
404+
405+void Window::Impl::CleanupWindowControls()
406+{
407+ if (title_)
408+ last_title_ = title_->text();
409+
410+ theme_changed_->disconnect();
411+ title_.reset();
412+ top_layout_.reset();
413+ input_mixer_.reset();
414+ edge_borders_.reset();
415+}
416+
417+bool Window::Impl::IsMaximized() const
418+{
419+ return (win_->state() & MAXIMIZE_STATE) == MAXIMIZE_STATE;
420+}
421+
422+bool Window::Impl::ShadowDecorated() const
423+{
424+ if (!parent_->scaled() && IsMaximized())
425+ return false;
426+
427+ if (!cu::IsWindowShadowDecorable(win_))
428+ return false;
429+
430+ return true;
431+}
432+
433+bool Window::Impl::FullyDecorated() const
434+{
435+ if (!parent_->scaled() && IsMaximized())
436+ return false;
437+
438+ if (!cu::IsWindowFullyDecorable(win_))
439+ return false;
440+
441+ return true;
442+}
443+
444+bool Window::Impl::ShouldBeDecorated() const
445+{
446+ return (win_->frame() || win_->hasUnmapReference()) && FullyDecorated();
447+}
448+
449+GLTexture* Window::Impl::ShadowTexture() const
450+{
451+ auto const& mi = manager_->impl_;
452+ if (active() || parent_->scaled())
453+ return mi->active_shadow_pixmap_->texture();
454+
455+ return mi->inactive_shadow_pixmap_->texture();
456+}
457+
458+unsigned Window::Impl::ShadowRadius() const
459+{
460+ if (active() || parent_->scaled())
461+ return manager_->active_shadow_radius();
462+
463+ return manager_->inactive_shadow_radius();
464+}
465+
466+void Window::Impl::RenderDecorationTexture(Side s, nux::Geometry const& geo)
467+{
468+ auto& deco_tex = bg_textures_[unsigned(s)];
469+
470+ if (deco_tex.quad.box.width() != geo.width || deco_tex.quad.box.height() != geo.height)
471+ {
472+ cu::CairoContext ctx(geo.width, geo.height);
473+ auto ws = active() ? WidgetState::NORMAL : WidgetState::BACKDROP;
474+ Style::Get()->DrawSide(s, ws, ctx, geo.width, geo.height);
475+ deco_tex.SetTexture(ctx);
476+ }
477+
478+ deco_tex.SetCoords(geo.x, geo.y);
479+}
480+
481+void Window::Impl::UpdateDecorationTextures()
482+{
483+ if (!FullyDecorated())
484+ {
485+ bg_textures_.clear();
486+ return;
487+ }
488+
489+ auto const& geo = win_->borderRect();
490+ auto const& input = win_->inputRect();
491+ auto const& border = win_->border();
492+
493+ bg_textures_.resize(4);
494+ RenderDecorationTexture(Side::TOP, {geo.x(), geo.y(), geo.width(), border.top});
495+ RenderDecorationTexture(Side::LEFT, {geo.x(), geo.y() + border.top, border.left, geo.height() - border.top - border.bottom});
496+ RenderDecorationTexture(Side::RIGHT, {geo.x2() - border.right, geo.y() + border.top, border.right, geo.height() - border.top - border.bottom});
497+ RenderDecorationTexture(Side::BOTTOM, {geo.x(), geo.y2() - border.bottom, geo.width(), border.bottom});
498+
499+ top_layout_->SetCoords(geo.x(), geo.y());
500+ top_layout_->SetSize(geo.width(), border.top);
501+
502+ if (edge_borders_)
503+ {
504+ edge_borders_->SetCoords(input.x(), input.y());
505+ edge_borders_->SetSize(input.width(), input.height());
506+ }
507+}
508+
509+void Window::Impl::ComputeShadowQuads()
510+{
511+ if (!ShadowDecorated())
512+ return;
513+
514+ const auto* texture = ShadowTexture();
515+
516+ if (!texture || !texture->width() || !texture->height())
517+ return;
518+
519+ Quads& quads = shadow_quads_;
520+ auto const& tex_matrix = texture->matrix();
521+ auto const& border = win_->borderRect();
522+ auto const& offset = manager_->shadow_offset();
523+ int texture_offset = ShadowRadius() * 2;
524+
525+ /* Top left quad */
526+ auto* quad = &quads[Quads::Pos::TOP_LEFT];
527+ quad->box.setGeometry(border.x() + offset.x - texture_offset,
528+ border.y() + offset.y - texture_offset,
529+ border.width() + offset.x + texture_offset * 2 - texture->width(),
530+ border.height() + offset.y + texture_offset * 2 - texture->height());
531+
532+ quad->matrix = tex_matrix;
533+ quad->matrix.x0 = 0.0f - COMP_TEX_COORD_X(quad->matrix, quad->box.x1());
534+ quad->matrix.y0 = 0.0f - COMP_TEX_COORD_Y(quad->matrix, quad->box.y1());
535+
536+ /* Top right quad */
537+ quad = &quads[Quads::Pos::TOP_RIGHT];
538+ quad->box.setGeometry(quads[Quads::Pos::TOP_LEFT].box.x2(),
539+ quads[Quads::Pos::TOP_LEFT].box.y1(),
540+ texture->width(),
541+ quads[Quads::Pos::TOP_LEFT].box.height());
542+
543+ quad->matrix = tex_matrix;
544+ quad->matrix.xx = -1.0f / texture->width();
545+ quad->matrix.x0 = 1.0f - COMP_TEX_COORD_X(quad->matrix, quad->box.x1());
546+ quad->matrix.y0 = 0.0f - COMP_TEX_COORD_Y(quad->matrix, quad->box.y1());
547+
548+ /* Bottom left */
549+ quad = &quads[Quads::Pos::BOTTOM_LEFT];
550+ quad->box.setGeometry(quads[Quads::Pos::TOP_LEFT].box.x1(),
551+ quads[Quads::Pos::TOP_LEFT].box.y2(),
552+ quads[Quads::Pos::TOP_LEFT].box.width(),
553+ texture->height());
554+
555+ quad->matrix = tex_matrix;
556+ quad->matrix.yy = -1.0f / texture->height();
557+ quad->matrix.x0 = 0.0f - COMP_TEX_COORD_X(quad->matrix, quad->box.x1());
558+ quad->matrix.y0 = 1.0f - COMP_TEX_COORD_Y(quad->matrix, quad->box.y1());
559+
560+ /* Bottom right */
561+ quad = &quads[Quads::Pos::BOTTOM_RIGHT];
562+ quad->box.setGeometry(quads[Quads::Pos::BOTTOM_LEFT].box.x2(),
563+ quads[Quads::Pos::TOP_RIGHT].box.y2(),
564+ texture->width(),
565+ texture->height());
566+
567+ quad->matrix = tex_matrix;
568+ quad->matrix.xx = -1.0f / texture->width();
569+ quad->matrix.yy = -1.0f / texture->height();
570+ quad->matrix.x0 = 1.0f - COMP_TEX_COORD_X(quad->matrix, quad->box.x1());
571+ quad->matrix.y0 = 1.0f - COMP_TEX_COORD_Y(quad->matrix, quad->box.y1());
572+
573+ /* Fix the quads if the texture is actually bigger than the area */
574+ if (texture->width() > border.width())
575+ {
576+ int half = win_->x() + win_->width() / 2.0f;
577+ quads[Quads::Pos::TOP_LEFT].box.setRight(half);
578+ quads[Quads::Pos::TOP_RIGHT].box.setLeft(half);
579+ quads[Quads::Pos::BOTTOM_LEFT].box.setRight(half);
580+ quads[Quads::Pos::BOTTOM_RIGHT].box.setLeft(half);
581+ }
582+
583+ if (texture->height() > border.height())
584+ {
585+ int half = win_->y() + win_->height() / 2.0f;
586+ quads[Quads::Pos::TOP_LEFT].box.setBottom(half);
587+ quads[Quads::Pos::TOP_RIGHT].box.setBottom(half);
588+ quads[Quads::Pos::BOTTOM_LEFT].box.setTop(half);
589+ quads[Quads::Pos::BOTTOM_RIGHT].box.setTop(half);
590+ }
591+
592+ CompRect shadows_rect;
593+ shadows_rect.setLeft(quads[Quads::Pos::TOP_LEFT].box.x1());
594+ shadows_rect.setTop(quads[Quads::Pos::TOP_LEFT].box.y1());
595+ shadows_rect.setRight(quads[Quads::Pos::TOP_RIGHT].box.x2());
596+ shadows_rect.setBottom(quads[Quads::Pos::BOTTOM_LEFT].box.y2());
597+
598+ if (shadows_rect != last_shadow_rect_)
599+ {
600+ last_shadow_rect_ = shadows_rect;
601+ win_->updateWindowOutputExtents();
602+ }
603+}
604+
605+void Window::Impl::Draw(GLMatrix const& transformation,
606+ GLWindowPaintAttrib const& attrib,
607+ CompRegion const& region, unsigned mask)
608+{
609+ if (!ShadowDecorated())
610+ return;
611+
612+ auto const& clip_region = (mask & PAINT_WINDOW_TRANSFORMED_MASK) ? infiniteRegion : region;
613+ mask |= PAINT_WINDOW_BLEND_MASK;
614+
615+ if (dirty_geo_)
616+ parent_->UpdateDecorationPosition();
617+
618+ glwin_->vertexBuffer()->begin();
619+
620+ for (unsigned i = 0; i < shadow_quads_.size(); ++i)
621+ {
622+ auto& quad = shadow_quads_[Quads::Pos(i)];
623+ glwin_->glAddGeometry({quad.matrix}, CompRegion(quad.box) - win_->region(), clip_region);
624+ }
625+
626+ if (glwin_->vertexBuffer()->end())
627+ glwin_->glDrawTexture(ShadowTexture(), transformation, attrib, mask);
628+
629+ for (auto const& dtex : bg_textures_)
630+ {
631+ glwin_->vertexBuffer()->begin();
632+ glwin_->glAddGeometry({dtex.quad.matrix}, dtex.quad.box, clip_region);
633+
634+ if (glwin_->vertexBuffer()->end())
635+ glwin_->glDrawTexture(dtex, transformation, attrib, mask);
636+ }
637+
638+ if (top_layout_)
639+ top_layout_->Draw(glwin_, transformation, attrib, region, mask);
640+}
641+
642+void Window::Impl::RedrawDecorations()
643+{
644+ dirty_geo_ = true;
645+ cwin_->damageOutputExtents();
646+}
647+
648+// Public APIs
649+
650+Window::Window(CompWindow* cwin)
651+ : scaled(false)
652+ , impl_(new Impl(this, cwin))
653+{}
654+
655+void Window::Update()
656+{
657+ impl_->Update();
658+}
659+
660+void Window::UpdateFrameRegion(CompRegion& r)
661+{
662+ if (impl_->frame_region_.isEmpty())
663+ return;
664+
665+ auto const& geo = impl_->win_->geometry();
666+ auto const& input = impl_->win_->input();
667+
668+ r += impl_->frame_region_.translated(geo.x() - input.left, geo.y() - input.top);
669+ UpdateDecorationPositionDelayed();
670+}
671+
672+void Window::UpdateOutputExtents(compiz::window::extents::Extents& output)
673+{
674+ const auto* win = impl_->win_;
675+ auto const& shadow = impl_->last_shadow_rect_;
676+ output.top = std::max(output.top, win->y() - shadow.y1());
677+ output.left = std::max(output.left, win->x() - shadow.x1());
678+ output.right = std::max(output.right, shadow.x2() - win->width() - win->x());
679+ output.bottom = std::max(output.bottom, shadow.y2() - win->height() - win->y());
680+}
681+
682+void Window::Draw(GLMatrix const& matrix, GLWindowPaintAttrib const& attrib,
683+ CompRegion const& region, unsigned mask)
684+{
685+ impl_->Draw(matrix, attrib, region, mask);
686+}
687+
688+void Window::Undecorate()
689+{
690+ impl_->Undecorate();
691+}
692+
693+void Window::UpdateDecorationPosition()
694+{
695+ impl_->ComputeShadowQuads();
696+ impl_->UpdateDecorationTextures();
697+ impl_->dirty_geo_ = false;
698+}
699+
700+void Window::UpdateDecorationPositionDelayed()
701+{
702+ impl_->dirty_geo_ = true;
703+}
704+
705+std::string Window::GetName() const
706+{
707+ return "DecoratedWindow";
708+}
709+
710+void Window::AddProperties(debug::IntrospectionData& data)
711+{
712+ data.add(impl_->win_->borderRect())
713+ .add("input_geo", impl_->win_->inputRect())
714+ .add("content_geo", impl_->win_->region().boundingRect())
715+ .add("title", title())
716+ .add("active", impl_->active())
717+ .add("scaled", scaled())
718+ .add("xid", impl_->win_->id())
719+ .add("fully_decorable", cu::IsWindowFullyDecorable(impl_->win_))
720+ .add("shadow_decorable", cu::IsWindowShadowDecorable(impl_->win_))
721+ .add("shadow_decorated", impl_->ShadowDecorated())
722+ .add("fully_decorated", impl_->FullyDecorated())
723+ .add("should_be_decorated", impl_->ShouldBeDecorated())
724+ .add("framed", (impl_->frame_ != 0))
725+ .add("frame_geo", impl_->frame_geo_)
726+ .add("shadow_rect", impl_->last_shadow_rect_)
727+ .add("maximized", impl_->IsMaximized())
728+ .add("v_maximized", (impl_->win_->state() & CompWindowStateMaximizedVertMask))
729+ .add("h_maximized", (impl_->win_->state() & CompWindowStateMaximizedHorzMask))
730+ .add("resizable", (impl_->win_->actions() & CompWindowActionResizeMask))
731+ .add("movable", (impl_->win_->actions() & CompWindowActionMoveMask))
732+ .add("closable", (impl_->win_->actions() & CompWindowActionCloseMask))
733+ .add("minimizable", (impl_->win_->actions() & CompWindowActionMinimizeMask))
734+ .add("maximizable", (impl_->win_->actions() & (CompWindowActionMaximizeHorzMask|CompWindowActionMaximizeVertMask)));
735+}
736+
737+debug::Introspectable::IntrospectableList Window::GetIntrospectableChildren()
738+{
739+ return IntrospectableList({impl_->top_layout_.get(), impl_->edge_borders_.get()});
740+}
741+
742+} // decoration namespace
743+} // unity namespace
744
745=== added file 'decorations/DecoratedWindow.h'
746--- decorations/DecoratedWindow.h 1970-01-01 00:00:00 +0000
747+++ decorations/DecoratedWindow.h 2014-01-23 15:21:26 +0000
748@@ -0,0 +1,73 @@
749+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
750+/*
751+ * Copyright (C) 2013 Canonical Ltd
752+ *
753+ * This program is free software: you can redistribute it and/or modify
754+ * it under the terms of the GNU General Public License version 3 as
755+ * published by the Free Software Foundation.
756+ *
757+ * This program is distributed in the hope that it will be useful,
758+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
759+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
760+ * GNU General Public License for more details.
761+ *
762+ * You should have received a copy of the GNU General Public License
763+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
764+ *
765+ * Authored by: Marco Trevisan <marco.trevisan@canonical.com>
766+ */
767+
768+#ifndef UNITY_DECORATED_WINDOW
769+#define UNITY_DECORATED_WINDOW
770+
771+#include "Introspectable.h"
772+#include <memory>
773+
774+class CompRegion;
775+class CompWindow;
776+class GLWindowPaintAttrib;
777+class GLMatrix;
778+namespace compiz { namespace window { namespace extents { class Extents; } } }
779+
780+namespace unity
781+{
782+namespace decoration
783+{
784+class Window : public debug::Introspectable
785+{
786+public:
787+ typedef std::shared_ptr<Window> Ptr;
788+
789+ Window(CompWindow*);
790+ virtual ~Window() = default;
791+
792+ nux::RWProperty<std::string> title;
793+ nux::Property<bool> scaled;
794+
795+ void Update();
796+ void Undecorate();
797+ void UpdateDecorationPosition();
798+ void UpdateDecorationPositionDelayed();
799+ void UpdateFrameRegion(CompRegion&);
800+ void UpdateOutputExtents(compiz::window::extents::Extents&);
801+ void Draw(GLMatrix const&, GLWindowPaintAttrib const&, CompRegion const&, unsigned mask);
802+
803+protected:
804+ std::string GetName() const;
805+ void AddProperties(debug::IntrospectionData&);
806+ IntrospectableList GetIntrospectableChildren();
807+
808+private:
809+ Window(Window const&) = delete;
810+ Window& operator=(Window const&) = delete;
811+
812+ friend class Manager;
813+
814+ struct Impl;
815+ std::unique_ptr<Impl> impl_;
816+};
817+
818+} // decoration namespace
819+} // unity namespace
820+
821+#endif
822
823=== added file 'decorations/DecorationsDataPool.cpp'
824--- decorations/DecorationsDataPool.cpp 1970-01-01 00:00:00 +0000
825+++ decorations/DecorationsDataPool.cpp 2014-01-23 15:21:26 +0000
826@@ -0,0 +1,153 @@
827+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
828+/*
829+ * Copyright (C) 2013 Canonical Ltd
830+ *
831+ * This program is free software: you can redistribute it and/or modify
832+ * it under the terms of the GNU General Public License version 3 as
833+ * published by the Free Software Foundation.
834+ *
835+ * This program is distributed in the hope that it will be useful,
836+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
837+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
838+ * GNU General Public License for more details.
839+ *
840+ * You should have received a copy of the GNU General Public License
841+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
842+ *
843+ * Authored by: Marco Trevisan <marco.trevisan@canonical.com>
844+ */
845+
846+#include <NuxCore/Logger.h>
847+#include <X11/cursorfont.h>
848+#include <sigc++/adaptors/hide.h>
849+#include "glow_texture.h"
850+#include "DecorationsDataPool.h"
851+
852+namespace unity
853+{
854+namespace decoration
855+{
856+namespace
857+{
858+DECLARE_LOGGER(logger, "unity.decoration.datapool");
859+const std::string PLUGIN_NAME = "unityshell";
860+const int BUTTONS_SIZE = 16;
861+const int BUTTONS_PADDING = 1;
862+const cu::SimpleTexture::Ptr EMPTY_BUTTON;
863+Display* dpy = nullptr;
864+
865+unsigned EdgeTypeToCursorShape(Edge::Type type)
866+{
867+ switch (type)
868+ {
869+ case Edge::Type::TOP:
870+ return XC_top_side;
871+ case Edge::Type::TOP_LEFT:
872+ return XC_top_left_corner;
873+ case Edge::Type::TOP_RIGHT:
874+ return XC_top_right_corner;
875+ case Edge::Type::LEFT:
876+ return XC_left_side;
877+ case Edge::Type::RIGHT:
878+ return XC_right_side;
879+ case Edge::Type::BOTTOM:
880+ return XC_bottom_side;
881+ case Edge::Type::BOTTOM_LEFT:
882+ return XC_bottom_left_corner;
883+ case Edge::Type::BOTTOM_RIGHT:
884+ return XC_bottom_right_corner;
885+ default:
886+ return XC_left_ptr;
887+ }
888+}
889+
890+}
891+
892+DataPool::DataPool()
893+{
894+ dpy = screen->dpy();
895+ SetupCursors();
896+ SetupTextures();
897+
898+ auto cb = sigc::hide(sigc::mem_fun(this, &DataPool::SetupTextures));
899+ Style::Get()->theme.changed.connect(cb);
900+}
901+
902+DataPool::~DataPool()
903+{
904+ for (auto cursor : edge_cursors_)
905+ XFreeCursor(dpy, cursor);
906+}
907+
908+DataPool::Ptr const& DataPool::Get()
909+{
910+ static DataPool::Ptr data_pool(new DataPool());
911+ return data_pool;
912+}
913+
914+void DataPool::SetupCursors()
915+{
916+ for (unsigned c = 0; c < edge_cursors_.size(); ++c)
917+ edge_cursors_[c] = XCreateFontCursor(dpy, EdgeTypeToCursorShape(Edge::Type(c)));
918+}
919+
920+Cursor DataPool::EdgeCursor(Edge::Type type) const
921+{
922+ return edge_cursors_[unsigned(type)];
923+}
924+
925+void DataPool::SetupTextures()
926+{
927+ CompSize size;
928+ CompString plugin_name(PLUGIN_NAME);
929+ auto const& style = Style::Get();
930+
931+ for (unsigned button = 0; button < window_buttons_.size(); ++button)
932+ {
933+ for (unsigned state = 0; state < window_buttons_[button].size(); ++state)
934+ {
935+ auto file = style->WindowButtonFile(WindowButtonType(button), WidgetState(state));
936+ auto const& tex_list = GLTexture::readImageToTexture(file, plugin_name, size);
937+
938+ if (!tex_list.empty())
939+ {
940+ LOG_DEBUG(logger) << "Loading texture " << file;
941+ window_buttons_[button][state] = std::make_shared<cu::SimpleTexture>(tex_list);
942+ }
943+ else
944+ {
945+ LOG_WARN(logger) << "Impossible to load local button texture file; "
946+ << "falling back to cairo generated one";
947+
948+ cu::CairoContext ctx(BUTTONS_SIZE + BUTTONS_PADDING*2, BUTTONS_SIZE + BUTTONS_PADDING*2);
949+ cairo_translate(ctx, BUTTONS_PADDING, BUTTONS_PADDING);
950+ style->DrawWindowButton(WindowButtonType(button), WidgetState(state), ctx, BUTTONS_SIZE, BUTTONS_SIZE);
951+ window_buttons_[button][state] = ctx;
952+ }
953+ }
954+ }
955+
956+ CompSize glow_size(texture::GLOW_SIZE, texture::GLOW_SIZE);
957+ glow_texture_ = std::make_shared<cu::SimpleTexture>(GLTexture::imageDataToTexture(texture::GLOW, glow_size, GL_RGBA, GL_UNSIGNED_BYTE));
958+}
959+
960+cu::SimpleTexture::Ptr const& DataPool::GlowTexture() const
961+{
962+ return glow_texture_;
963+}
964+
965+cu::SimpleTexture::Ptr const& DataPool::ButtonTexture(WindowButtonType wbt, WidgetState ws) const
966+{
967+ if (wbt >= WindowButtonType::Size || ws >= WidgetState::Size)
968+ {
969+ LOG_ERROR(logger) << "It has been requested an invalid button texture "
970+ << "WindowButtonType: " << unsigned(wbt) << ", WidgetState: "
971+ << unsigned(ws);
972+ return EMPTY_BUTTON;
973+ }
974+
975+ return window_buttons_[unsigned(wbt)][unsigned(ws)];
976+}
977+
978+} // decoration namespace
979+} // unity namespace
980
981=== added file 'decorations/DecorationsDataPool.h'
982--- decorations/DecorationsDataPool.h 1970-01-01 00:00:00 +0000
983+++ decorations/DecorationsDataPool.h 2014-01-23 15:21:26 +0000
984@@ -0,0 +1,59 @@
985+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
986+/*
987+ * Copyright (C) 2013 Canonical Ltd
988+ *
989+ * This program is free software: you can redistribute it and/or modify
990+ * it under the terms of the GNU General Public License version 3 as
991+ * published by the Free Software Foundation.
992+ *
993+ * This program is distributed in the hope that it will be useful,
994+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
995+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
996+ * GNU General Public License for more details.
997+ *
998+ * You should have received a copy of the GNU General Public License
999+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1000+ *
1001+ * Authored by: Marco Trevisan <marco.trevisan@canonical.com>
1002+ */
1003+
1004+#ifndef UNITY_DECORATIONS_DATA_POOL
1005+#define UNITY_DECORATIONS_DATA_POOL
1006+
1007+#include "DecorationStyle.h"
1008+#include "DecorationsEdge.h"
1009+
1010+namespace unity
1011+{
1012+namespace decoration
1013+{
1014+
1015+class DataPool : public sigc::trackable
1016+{
1017+public:
1018+ typedef std::shared_ptr<DataPool> Ptr;
1019+
1020+ static DataPool::Ptr const& Get();
1021+ virtual ~DataPool();
1022+
1023+ Cursor EdgeCursor(Edge::Type) const;
1024+ cu::SimpleTexture::Ptr const& GlowTexture() const;
1025+ cu::SimpleTexture::Ptr const& ButtonTexture(WindowButtonType, WidgetState) const;
1026+
1027+private:
1028+ DataPool();
1029+ DataPool(DataPool const&) = delete;
1030+ DataPool& operator=(DataPool const&) = delete;
1031+
1032+ void SetupCursors();
1033+ void SetupTextures();
1034+
1035+ std::array<Cursor, size_t(Edge::Type::Size)> edge_cursors_;
1036+ cu::SimpleTexture::Ptr glow_texture_;
1037+ std::array<std::array<cu::SimpleTexture::Ptr, size_t(WidgetState::Size)>, size_t(WindowButtonType::Size)> window_buttons_;
1038+};
1039+
1040+} // decoration namespace
1041+} // unity namespace
1042+
1043+#endif // UNITY_DECORATIONS_DATA_POOL
1044
1045=== added file 'decorations/DecorationsEdge.cpp'
1046--- decorations/DecorationsEdge.cpp 1970-01-01 00:00:00 +0000
1047+++ decorations/DecorationsEdge.cpp 2014-01-23 15:21:26 +0000
1048@@ -0,0 +1,137 @@
1049+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
1050+/*
1051+ * Copyright (C) 2013 Canonical Ltd
1052+ *
1053+ * This program is free software: you can redistribute it and/or modify
1054+ * it under the terms of the GNU General Public License version 3 as
1055+ * published by the Free Software Foundation.
1056+ *
1057+ * This program is distributed in the hope that it will be useful,
1058+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1059+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1060+ * GNU General Public License for more details.
1061+ *
1062+ * You should have received a copy of the GNU General Public License
1063+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1064+ *
1065+ * Authored by: Marco Trevisan <marco.trevisan@canonical.com>
1066+ */
1067+
1068+#include <core/atoms.h>
1069+#include "DecorationsEdge.h"
1070+#include "DecorationsDataPool.h"
1071+
1072+namespace unity
1073+{
1074+namespace decoration
1075+{
1076+namespace
1077+{
1078+
1079+unsigned TypeToDirection(Edge::Type type)
1080+{
1081+ switch (type)
1082+ {
1083+ case Edge::Type::TOP:
1084+ return WmMoveResizeSizeTop;
1085+ case Edge::Type::TOP_LEFT:
1086+ return WmMoveResizeSizeTopLeft;
1087+ case Edge::Type::TOP_RIGHT:
1088+ return WmMoveResizeSizeTopRight;
1089+ case Edge::Type::LEFT:
1090+ return WmMoveResizeSizeLeft;
1091+ case Edge::Type::RIGHT:
1092+ return WmMoveResizeSizeRight;
1093+ case Edge::Type::BOTTOM:
1094+ return WmMoveResizeSizeBottom;
1095+ case Edge::Type::BOTTOM_LEFT:
1096+ return WmMoveResizeSizeBottomLeft;
1097+ case Edge::Type::BOTTOM_RIGHT:
1098+ return WmMoveResizeSizeBottomRight;
1099+ case Edge::Type::GRAB:
1100+ return WmMoveResizeMove;
1101+ default:
1102+ return WmMoveResizeCancel;
1103+ }
1104+}
1105+
1106+}
1107+
1108+Edge::Edge(CompWindow* win, Type t)
1109+ : win_(win)
1110+ , type_(t)
1111+{
1112+ unsigned mask = (t == Type::GRAB) ? CompWindowActionMoveMask : CompWindowActionResizeMask;
1113+ sensitive = (win_->actions() & mask);
1114+ mouse_owner.changed.connect([this] (bool over) {
1115+ if (over)
1116+ XDefineCursor(screen->dpy(), win_->frame(), DataPool::Get()->EdgeCursor(type_));
1117+ else
1118+ XUndefineCursor(screen->dpy(), win_->frame());
1119+ });
1120+}
1121+
1122+Edge::Type Edge::GetType() const
1123+{
1124+ return type_;
1125+}
1126+
1127+void Edge::ButtonDownEvent(CompPoint const& p, unsigned button)
1128+{
1129+ XEvent ev;
1130+ auto* dpy = screen->dpy();
1131+
1132+ ev.xclient.type = ClientMessage;
1133+ ev.xclient.display = screen->dpy();
1134+
1135+ ev.xclient.serial = 0;
1136+ ev.xclient.send_event = True;
1137+
1138+ ev.xclient.window = win_->id();
1139+ ev.xclient.message_type = Atoms::wmMoveResize;
1140+ ev.xclient.format = 32;
1141+
1142+ ev.xclient.data.l[0] = p.x();
1143+ ev.xclient.data.l[1] = p.y();
1144+ ev.xclient.data.l[2] = TypeToDirection(type_);
1145+ ev.xclient.data.l[3] = button;
1146+ ev.xclient.data.l[4] = 1;
1147+
1148+ XUngrabPointer(dpy, screen->getCurrentTime());
1149+ XUngrabKeyboard(dpy, screen->getCurrentTime());
1150+
1151+ auto mask = SubstructureRedirectMask | SubstructureNotifyMask;
1152+ XSendEvent(dpy, screen->root(), False, mask, &ev);
1153+
1154+ XSync(dpy, False);
1155+}
1156+
1157+std::string Edge::GetName() const
1158+{
1159+ switch (type_)
1160+ {
1161+ case Type::TOP:
1162+ return "TopEdge";
1163+ case Type::TOP_LEFT:
1164+ return "TopLeftEdge";
1165+ case Type::TOP_RIGHT:
1166+ return "TopRightEdge";
1167+ case Type::LEFT:
1168+ return "LeftEdge";
1169+ case Type::RIGHT:
1170+ return "RightEdge";
1171+ case Type::BOTTOM:
1172+ return "BottomEdge";
1173+ case Type::BOTTOM_LEFT:
1174+ return "BottomLeftEdge";
1175+ case Type::BOTTOM_RIGHT:
1176+ return "BottomRightEdge";
1177+ case Type::GRAB:
1178+ return "GrabEdge";
1179+ default:
1180+ return "Edge";
1181+ }
1182+}
1183+
1184+} // decoration namespace
1185+} // unity namespace
1186
1187=== added file 'decorations/DecorationsEdge.h'
1188--- decorations/DecorationsEdge.h 1970-01-01 00:00:00 +0000
1189+++ decorations/DecorationsEdge.h 2014-01-23 15:21:26 +0000
1190@@ -0,0 +1,64 @@
1191+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
1192+/*
1193+ * Copyright (C) 2013 Canonical Ltd
1194+ *
1195+ * This program is free software: you can redistribute it and/or modify
1196+ * it under the terms of the GNU General Public License version 3 as
1197+ * published by the Free Software Foundation.
1198+ *
1199+ * This program is distributed in the hope that it will be useful,
1200+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1201+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1202+ * GNU General Public License for more details.
1203+ *
1204+ * You should have received a copy of the GNU General Public License
1205+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1206+ *
1207+ * Authored by: Marco Trevisan <marco.trevisan@canonical.com>
1208+ */
1209+
1210+#ifndef UNITY_DECORATIONS_EDGE
1211+#define UNITY_DECORATIONS_EDGE
1212+
1213+#include "DecorationsWidgets.h"
1214+
1215+namespace unity
1216+{
1217+namespace decoration
1218+{
1219+
1220+class Edge : public SimpleItem
1221+{
1222+public:
1223+ enum class Type
1224+ {
1225+ // The order of this enum is important to define the priority of each Edge
1226+ // when parsing the input events (in case two areas overlap)
1227+ GRAB = 0,
1228+ TOP_LEFT,
1229+ TOP_RIGHT,
1230+ TOP,
1231+ BOTTOM_LEFT,
1232+ BOTTOM_RIGHT,
1233+ BOTTOM,
1234+ LEFT,
1235+ RIGHT,
1236+ Size
1237+ };
1238+
1239+ Edge(CompWindow* win, Type t);
1240+
1241+ Type GetType() const;
1242+ void ButtonDownEvent(CompPoint const&, unsigned button);
1243+
1244+protected:
1245+ std::string GetName() const;
1246+
1247+ CompWindow* win_;
1248+ Type type_;
1249+};
1250+
1251+} // decoration namespace
1252+} // unity namespace
1253+
1254+#endif // UNITY_DECORATIONS_EDGE
1255
1256=== added file 'decorations/DecorationsEdgeBorders.cpp'
1257--- decorations/DecorationsEdgeBorders.cpp 1970-01-01 00:00:00 +0000
1258+++ decorations/DecorationsEdgeBorders.cpp 2014-01-23 15:21:26 +0000
1259@@ -0,0 +1,99 @@
1260+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
1261+/*
1262+ * Copyright (C) 2013 Canonical Ltd
1263+ *
1264+ * This program is free software: you can redistribute it and/or modify
1265+ * it under the terms of the GNU General Public License version 3 as
1266+ * published by the Free Software Foundation.
1267+ *
1268+ * This program is distributed in the hope that it will be useful,
1269+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1270+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1271+ * GNU General Public License for more details.
1272+ *
1273+ * You should have received a copy of the GNU General Public License
1274+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1275+ *
1276+ * Authored by: Marco Trevisan <marco.trevisan@canonical.com>
1277+ */
1278+
1279+#include "DecorationStyle.h"
1280+#include "DecorationsEdgeBorders.h"
1281+#include "DecorationsEdge.h"
1282+#include "DecorationsGrabEdge.h"
1283+
1284+namespace unity
1285+{
1286+namespace decoration
1287+{
1288+namespace
1289+{
1290+const int MIN_CORNER_EDGE = 10;
1291+}
1292+
1293+EdgeBorders::EdgeBorders(CompWindow* win)
1294+{
1295+ items_.resize(size_t(Edge::Type::Size));
1296+
1297+ for (unsigned i = 0; i < unsigned(Edge::Type::Size); ++i)
1298+ {
1299+ auto type = Edge::Type(i);
1300+
1301+ if (type == Edge::Type::GRAB)
1302+ items_[i] = std::make_shared<GrabEdge>(win);
1303+ else
1304+ items_[i] = std::make_shared<Edge>(win, type);
1305+ }
1306+
1307+ Relayout();
1308+}
1309+
1310+void EdgeBorders::Relayout()
1311+{
1312+ auto const& b = Style::Get()->Border();
1313+ auto const& ib = Style::Get()->InputBorder();
1314+
1315+ Border edges(std::max(b.top, MIN_CORNER_EDGE) + ib.top,
1316+ std::max(b.left, MIN_CORNER_EDGE) + ib.left,
1317+ std::max(b.right, MIN_CORNER_EDGE) + ib.right,
1318+ std::max(b.bottom, MIN_CORNER_EDGE) + ib.bottom);
1319+
1320+ auto item = items_[unsigned(Edge::Type::TOP)];
1321+ item->SetCoords(rect_.x() + edges.left, rect_.y());
1322+ item->SetSize(rect_.width() - edges.left - edges.right, edges.top - b.top);
1323+
1324+ item = items_[unsigned(Edge::Type::TOP_LEFT)];
1325+ item->SetCoords(rect_.x(), rect_.y());
1326+ item->SetSize(edges.left, edges.top);
1327+
1328+ item = items_[unsigned(Edge::Type::TOP_RIGHT)];
1329+ item->SetCoords(rect_.x2() - edges.right, rect_.y());
1330+ item->SetSize(edges.right, edges.top);
1331+
1332+ item = items_[unsigned(Edge::Type::LEFT)];
1333+ item->SetCoords(rect_.x(), rect_.y() + edges.top);
1334+ item->SetSize(edges.left, rect_.height() - edges.top - edges.bottom);
1335+
1336+ item = items_[unsigned(Edge::Type::RIGHT)];
1337+ item->SetCoords(rect_.x2() - edges.right, rect_.y() + edges.top);
1338+ item->SetSize(edges.right, rect_.height() - edges.top - edges.bottom);
1339+
1340+ item = items_[unsigned(Edge::Type::BOTTOM)];
1341+ item->SetCoords(rect_.x() + edges.left, rect_.y2() - edges.bottom);
1342+ item->SetSize(rect_.width() - edges.left - edges.right, edges.bottom);
1343+
1344+ item = items_[unsigned(Edge::Type::BOTTOM_LEFT)];
1345+ item->SetCoords(rect_.x(), rect_.y2() - edges.bottom);
1346+ item->SetSize(edges.left, edges.bottom);
1347+
1348+ item = items_[unsigned(Edge::Type::BOTTOM_RIGHT)];
1349+ item->SetCoords(rect_.x2() - edges.right, rect_.y2() - edges.bottom);
1350+ item->SetSize(edges.right, edges.bottom);
1351+
1352+ item = items_[unsigned(Edge::Type::GRAB)];
1353+ item->SetCoords(rect_.x() + ib.left, rect_.y() + ib.top);
1354+ item->SetSize(rect_.width() - ib.left - ib.right, b.top);
1355+}
1356+
1357+} // decoration namespace
1358+} // unity namespace
1359
1360=== added file 'decorations/DecorationsEdgeBorders.h'
1361--- decorations/DecorationsEdgeBorders.h 1970-01-01 00:00:00 +0000
1362+++ decorations/DecorationsEdgeBorders.h 2014-01-23 15:21:26 +0000
1363@@ -0,0 +1,43 @@
1364+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
1365+/*
1366+ * Copyright (C) 2013 Canonical Ltd
1367+ *
1368+ * This program is free software: you can redistribute it and/or modify
1369+ * it under the terms of the GNU General Public License version 3 as
1370+ * published by the Free Software Foundation.
1371+ *
1372+ * This program is distributed in the hope that it will be useful,
1373+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1374+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1375+ * GNU General Public License for more details.
1376+ *
1377+ * You should have received a copy of the GNU General Public License
1378+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1379+ *
1380+ * Authored by: Marco Trevisan <marco.trevisan@canonical.com>
1381+ */
1382+
1383+#ifndef UNITY_DECORATIONS_EDGES
1384+#define UNITY_DECORATIONS_EDGES
1385+
1386+#include "DecorationsWidgets.h"
1387+
1388+namespace unity
1389+{
1390+namespace decoration
1391+{
1392+
1393+class EdgeBorders : public BasicContainer
1394+{
1395+public:
1396+ EdgeBorders(CompWindow* win);
1397+ void Relayout();
1398+
1399+protected:
1400+ std::string GetName() const { return "EdgeBorders"; }
1401+};
1402+
1403+} // decoration namespace
1404+} // unity namespace
1405+
1406+#endif // UNITY_DECORATIONS_EDGES
1407
1408=== added file 'decorations/DecorationsGrabEdge.cpp'
1409--- decorations/DecorationsGrabEdge.cpp 1970-01-01 00:00:00 +0000
1410+++ decorations/DecorationsGrabEdge.cpp 2014-01-23 15:21:26 +0000
1411@@ -0,0 +1,102 @@
1412+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
1413+/*
1414+ * Copyright (C) 2013 Canonical Ltd
1415+ *
1416+ * This program is free software: you can redistribute it and/or modify
1417+ * it under the terms of the GNU General Public License version 3 as
1418+ * published by the Free Software Foundation.
1419+ *
1420+ * This program is distributed in the hope that it will be useful,
1421+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1422+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1423+ * GNU General Public License for more details.
1424+ *
1425+ * You should have received a copy of the GNU General Public License
1426+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1427+ *
1428+ * Authored by: Marco Trevisan <marco.trevisan@canonical.com>
1429+ */
1430+
1431+#include "DecorationsGrabEdge.h"
1432+#include "DecorationStyle.h"
1433+
1434+namespace unity
1435+{
1436+namespace decoration
1437+{
1438+namespace
1439+{
1440+const int MOUSE_DOWN_TIMEOUT = 150;
1441+}
1442+
1443+GrabEdge::GrabEdge(CompWindow* win)
1444+ : Edge(win, Edge::Type::GRAB)
1445+ , last_click_time_(0)
1446+ , button_down_(-1)
1447+{}
1448+
1449+void GrabEdge::ButtonDownEvent(CompPoint const& p, unsigned button)
1450+{
1451+ if (button != 1)
1452+ return;
1453+
1454+ if (!(win_->actions() & (CompWindowActionMaximizeHorzMask|CompWindowActionMaximizeVertMask)))
1455+ {
1456+ Edge::ButtonDownEvent(p, button);
1457+ return;
1458+ }
1459+
1460+ auto const& style = Style::Get();
1461+ unsigned max_time_delta = std::max(0, style->DoubleClickMaxTimeDelta());
1462+ bool maximized = false;
1463+
1464+ if (screen->getCurrentTime() - last_click_time_ < max_time_delta)
1465+ {
1466+ int max_distance = style->DoubleClickMaxDistance();
1467+
1468+ if (std::abs(p.x() - last_click_pos_.x()) < max_distance &&
1469+ std::abs(p.y() - last_click_pos_.y()) < max_distance)
1470+ {
1471+ win_->maximize(MAXIMIZE_STATE);
1472+ maximized = true;
1473+ button_down_timer_.reset();
1474+ }
1475+ }
1476+
1477+ if (!maximized)
1478+ {
1479+ button_down_timer_.reset(new glib::Timeout(MOUSE_DOWN_TIMEOUT));
1480+ button_down_timer_->Run([this] {
1481+ Edge::ButtonDownEvent(CompPoint(pointerX, pointerY), button_down_);
1482+ button_down_timer_.reset();
1483+ return false;
1484+ });
1485+ }
1486+
1487+ button_down_ = button;
1488+ last_click_pos_ = p;
1489+ last_click_time_ = screen->getCurrentTime();
1490+}
1491+
1492+void GrabEdge::MotionEvent(CompPoint const& p)
1493+{
1494+ if (button_down_timer_)
1495+ {
1496+ button_down_timer_.reset();
1497+ Edge::ButtonDownEvent(p, button_down_);
1498+ }
1499+}
1500+
1501+void GrabEdge::ButtonUpEvent(CompPoint const&, unsigned button)
1502+{
1503+ button_down_timer_.reset();
1504+}
1505+
1506+void GrabEdge::AddProperties(debug::IntrospectionData& data)
1507+{
1508+ Edge::AddProperties(data);
1509+ data.add("button_down", button_down_);
1510+}
1511+
1512+} // decoration namespace
1513+} // unity namespace
1514
1515=== added file 'decorations/DecorationsGrabEdge.h'
1516--- decorations/DecorationsGrabEdge.h 1970-01-01 00:00:00 +0000
1517+++ decorations/DecorationsGrabEdge.h 2014-01-23 15:21:26 +0000
1518@@ -0,0 +1,53 @@
1519+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
1520+/*
1521+ * Copyright (C) 2013 Canonical Ltd
1522+ *
1523+ * This program is free software: you can redistribute it and/or modify
1524+ * it under the terms of the GNU General Public License version 3 as
1525+ * published by the Free Software Foundation.
1526+ *
1527+ * This program is distributed in the hope that it will be useful,
1528+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1529+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1530+ * GNU General Public License for more details.
1531+ *
1532+ * You should have received a copy of the GNU General Public License
1533+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1534+ *
1535+ * Authored by: Marco Trevisan <marco.trevisan@canonical.com>
1536+ */
1537+
1538+#ifndef UNITY_DECORATIONS_GRAB_EDGE
1539+#define UNITY_DECORATIONS_GRAB_EDGE
1540+
1541+#include <UnityCore/GLibSource.h>
1542+#include "DecorationsEdge.h"
1543+
1544+namespace unity
1545+{
1546+namespace decoration
1547+{
1548+
1549+class GrabEdge : public Edge
1550+{
1551+public:
1552+ GrabEdge(CompWindow* win);
1553+
1554+ void ButtonDownEvent(CompPoint const&, unsigned button);
1555+ void ButtonUpEvent(CompPoint const&, unsigned button);
1556+ void MotionEvent(CompPoint const&);
1557+
1558+protected:
1559+ void AddProperties(debug::IntrospectionData&);
1560+
1561+private:
1562+ Time last_click_time_;
1563+ CompPoint last_click_pos_;
1564+ int button_down_;
1565+ glib::Source::UniquePtr button_down_timer_;
1566+};
1567+
1568+} // decoration namespace
1569+} // unity namespace
1570+
1571+#endif // UNITY_DECORATIONS_GRAB_EDGE
1572
1573=== added file 'decorations/DecorationsInputMixer.cpp'
1574--- decorations/DecorationsInputMixer.cpp 1970-01-01 00:00:00 +0000
1575+++ decorations/DecorationsInputMixer.cpp 2014-01-23 15:21:26 +0000
1576@@ -0,0 +1,176 @@
1577+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
1578+/*
1579+ * Copyright (C) 2013 Canonical Ltd
1580+ *
1581+ * This program is free software: you can redistribute it and/or modify
1582+ * it under the terms of the GNU General Public License version 3 as
1583+ * published by the Free Software Foundation.
1584+ *
1585+ * This program is distributed in the hope that it will be useful,
1586+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1587+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1588+ * GNU General Public License for more details.
1589+ *
1590+ * You should have received a copy of the GNU General Public License
1591+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1592+ *
1593+ * Authored by: Marco Trevisan <marco.trevisan@canonical.com>
1594+ */
1595+
1596+#include <NuxCore/Logger.h>
1597+#include "DecorationsInputMixer.h"
1598+
1599+namespace unity
1600+{
1601+namespace decoration
1602+{
1603+namespace
1604+{
1605+DECLARE_LOGGER(logger, "unity.decorations.inputmixer");
1606+}
1607+
1608+InputMixer::InputMixer()
1609+ : mouse_down_(false)
1610+{}
1611+
1612+void InputMixer::PushToFront(Item::Ptr const& item)
1613+{
1614+ if (!item)
1615+ return;
1616+
1617+ auto it = std::find(items_.begin(), items_.end(), item);
1618+ if (it != items_.end())
1619+ items_.erase(it);
1620+
1621+ items_.push_front(item);
1622+}
1623+
1624+void InputMixer::PushToBack(Item::Ptr const& item)
1625+{
1626+ if (!item)
1627+ return;
1628+
1629+ auto it = std::find(items_.begin(), items_.end(), item);
1630+ if (it != items_.end())
1631+ items_.erase(it);
1632+
1633+ items_.push_back(item);
1634+}
1635+
1636+void InputMixer::Remove(Item::Ptr const& item)
1637+{
1638+ if (item == last_mouse_owner_)
1639+ UnsetMouseOwner();
1640+
1641+ auto it = std::find(items_.begin(), items_.end(), item);
1642+ if (it != items_.end())
1643+ items_.erase(it);
1644+}
1645+
1646+Item::List const& InputMixer::Items() const
1647+{
1648+ return items_;
1649+}
1650+
1651+Item::Ptr InputMixer::GetMatchingItemRecursive(Item::List const& items, CompPoint const& point)
1652+{
1653+ for (auto const& item : items)
1654+ {
1655+ if (item->visible() && item->Geometry().contains(point))
1656+ {
1657+ if (!item->IsContainer())
1658+ return item->sensitive() ? item : nullptr;
1659+
1660+ auto const& container = std::static_pointer_cast<BasicContainer>(item);
1661+ auto const& child = GetMatchingItemRecursive(container->Items(), point);
1662+
1663+ if (child)
1664+ return child;
1665+ }
1666+ }
1667+
1668+ return nullptr;
1669+}
1670+
1671+Item::Ptr InputMixer::GetMatchingItem(CompPoint const& point)
1672+{
1673+ return GetMatchingItemRecursive(items_, point);
1674+}
1675+
1676+void InputMixer::UpdateMouseOwner(CompPoint const& point)
1677+{
1678+ if (Item::Ptr const& item = GetMatchingItem(point))
1679+ {
1680+ if (item != last_mouse_owner_)
1681+ {
1682+ UnsetMouseOwner();
1683+ last_mouse_owner_ = item;
1684+ item->mouse_owner = true;
1685+ }
1686+ }
1687+ else
1688+ {
1689+ UnsetMouseOwner();
1690+ }
1691+}
1692+
1693+void InputMixer::UnsetMouseOwner()
1694+{
1695+ if (!last_mouse_owner_)
1696+ return;
1697+
1698+ last_mouse_owner_->mouse_owner = false;
1699+ last_mouse_owner_ = nullptr;
1700+}
1701+
1702+Item::Ptr const& InputMixer::GetMouseOwner() const
1703+{
1704+ return last_mouse_owner_;
1705+};
1706+
1707+void InputMixer::EnterEvent(CompPoint const& point)
1708+{
1709+ if (!mouse_down_)
1710+ UpdateMouseOwner(point);
1711+}
1712+
1713+void InputMixer::LeaveEvent(CompPoint const& point)
1714+{
1715+ if (!mouse_down_)
1716+ UnsetMouseOwner();
1717+}
1718+
1719+void InputMixer::MotionEvent(CompPoint const& point)
1720+{
1721+ if (!mouse_down_)
1722+ UpdateMouseOwner(point);
1723+
1724+ if (last_mouse_owner_)
1725+ last_mouse_owner_->MotionEvent(point);
1726+}
1727+
1728+void InputMixer::ButtonDownEvent(CompPoint const& point, unsigned button)
1729+{
1730+ mouse_down_ = true;
1731+
1732+ if (last_mouse_owner_)
1733+ last_mouse_owner_->ButtonDownEvent(point, button);
1734+}
1735+
1736+void InputMixer::ButtonUpEvent(CompPoint const& point, unsigned button)
1737+{
1738+ mouse_down_ = false;
1739+
1740+ if (last_mouse_owner_)
1741+ {
1742+ // This event might cause the InputMixer to be deleted, so we protect using a weak_ptr
1743+ std::weak_ptr<Item> weak_last_mouse_owner(last_mouse_owner_);
1744+ last_mouse_owner_->ButtonUpEvent(point, button);
1745+
1746+ if (!weak_last_mouse_owner.expired() && !last_mouse_owner_->Geometry().contains(point))
1747+ UpdateMouseOwner(point);
1748+ }
1749+}
1750+
1751+} // decoration namespace
1752+} // unity namespace
1753
1754=== added file 'decorations/DecorationsInputMixer.h'
1755--- decorations/DecorationsInputMixer.h 1970-01-01 00:00:00 +0000
1756+++ decorations/DecorationsInputMixer.h 2014-01-23 15:21:26 +0000
1757@@ -0,0 +1,66 @@
1758+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
1759+/*
1760+ * Copyright (C) 2013 Canonical Ltd
1761+ *
1762+ * This program is free software: you can redistribute it and/or modify
1763+ * it under the terms of the GNU General Public License version 3 as
1764+ * published by the Free Software Foundation.
1765+ *
1766+ * This program is distributed in the hope that it will be useful,
1767+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1768+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1769+ * GNU General Public License for more details.
1770+ *
1771+ * You should have received a copy of the GNU General Public License
1772+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1773+ *
1774+ * Authored by: Marco Trevisan <marco.trevisan@canonical.com>
1775+ */
1776+
1777+#ifndef UNITY_DECORATION_INPUT_MIXER
1778+#define UNITY_DECORATION_INPUT_MIXER
1779+
1780+#include "DecorationsWidgets.h"
1781+
1782+namespace unity
1783+{
1784+namespace decoration
1785+{
1786+
1787+class InputMixer
1788+{
1789+public:
1790+ typedef std::shared_ptr<InputMixer> Ptr;
1791+ InputMixer();
1792+
1793+ void PushToFront(Item::Ptr const&);
1794+ void PushToBack(Item::Ptr const&);
1795+ void Remove(Item::Ptr const&);
1796+
1797+ Item::List const& Items() const;
1798+ Item::Ptr const& GetMouseOwner() const;
1799+
1800+ void EnterEvent(CompPoint const&);
1801+ void MotionEvent(CompPoint const&);
1802+ void LeaveEvent(CompPoint const&);
1803+ void ButtonDownEvent(CompPoint const&, unsigned button);
1804+ void ButtonUpEvent(CompPoint const&, unsigned button);
1805+
1806+private:
1807+ InputMixer(InputMixer const&) = delete;
1808+ InputMixer& operator=(InputMixer const&) = delete;
1809+
1810+ void UpdateMouseOwner(CompPoint const&);
1811+ void UnsetMouseOwner();
1812+ Item::Ptr GetMatchingItem(CompPoint const&);
1813+ Item::Ptr GetMatchingItemRecursive(Item::List const&, CompPoint const&);
1814+
1815+ Item::List items_;
1816+ Item::Ptr last_mouse_owner_;
1817+ bool mouse_down_;
1818+};
1819+
1820+} // decoration namespace
1821+} // unity namespace
1822+
1823+#endif
1824
1825=== added file 'decorations/DecorationsManager.cpp'
1826--- decorations/DecorationsManager.cpp 1970-01-01 00:00:00 +0000
1827+++ decorations/DecorationsManager.cpp 2014-01-23 15:21:26 +0000
1828@@ -0,0 +1,386 @@
1829+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
1830+/*
1831+ * Copyright (C) 2013 Canonical Ltd
1832+ *
1833+ * This program is free software: you can redistribute it and/or modify
1834+ * it under the terms of the GNU General Public License version 3 as
1835+ * published by the Free Software Foundation.
1836+ *
1837+ * This program is distributed in the hope that it will be useful,
1838+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1839+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1840+ * GNU General Public License for more details.
1841+ *
1842+ * You should have received a copy of the GNU General Public License
1843+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1844+ *
1845+ * Authored by: Marco Trevisan <marco.trevisan@canonical.com>
1846+ */
1847+
1848+#include "DecorationsPriv.h"
1849+
1850+#include <core/atoms.h>
1851+#include <NuxCore/Logger.h>
1852+#include <NuxGraphics/CairoGraphics.h>
1853+#include <X11/Xatom.h>
1854+#include "WindowManager.h"
1855+
1856+namespace unity
1857+{
1858+namespace decoration
1859+{
1860+Manager* manager_ = nullptr;
1861+
1862+namespace
1863+{
1864+DECLARE_LOGGER(logger, "unity.decoration.manager");
1865+
1866+namespace atom
1867+{
1868+Atom _NET_REQUEST_FRAME_EXTENTS = 0;
1869+Atom _NET_WM_VISIBLE_NAME = 0;
1870+}
1871+}
1872+
1873+Manager::Impl::Impl(decoration::Manager* parent)
1874+ : active_window_(0)
1875+ , enable_add_supported_atoms_(true)
1876+ , data_pool_(DataPool::Get())
1877+{
1878+ if (!manager_)
1879+ manager_ = parent;
1880+
1881+ Display* dpy = screen->dpy();
1882+ atom::_NET_REQUEST_FRAME_EXTENTS = XInternAtom(dpy, "_NET_REQUEST_FRAME_EXTENTS", False);
1883+ atom::_NET_WM_VISIBLE_NAME = XInternAtom(dpy, "_NET_WM_VISIBLE_NAME", False);
1884+ screen->updateSupportedWmHints();
1885+
1886+ auto rebuild_cb = sigc::mem_fun(this, &Impl::OnShadowOptionsChanged);
1887+ manager_->active_shadow_color.changed.connect(sigc::hide(sigc::bind(rebuild_cb, true)));
1888+ manager_->active_shadow_radius.changed.connect(sigc::hide(sigc::bind(rebuild_cb, true)));
1889+ manager_->inactive_shadow_color.changed.connect(sigc::hide(sigc::bind(rebuild_cb, false)));
1890+ manager_->inactive_shadow_radius.changed.connect(sigc::hide(sigc::bind(rebuild_cb, false)));
1891+ manager_->shadow_offset.changed.connect(sigc::hide(sigc::mem_fun(this, &Impl::UpdateWindowsExtents)));
1892+
1893+ BuildInactiveShadowTexture();
1894+ BuildActiveShadowTexture();
1895+}
1896+
1897+Manager::Impl::~Impl()
1898+{
1899+ enable_add_supported_atoms_ = false;
1900+ screen->updateSupportedWmHints();
1901+}
1902+
1903+cu::PixmapTexture::Ptr Manager::Impl::BuildShadowTexture(unsigned radius, nux::Color const& color)
1904+{
1905+ int tex_size = radius * 4;
1906+
1907+ nux::CairoGraphics dummy(CAIRO_FORMAT_ARGB32, tex_size, tex_size);
1908+ auto* dummy_ctx = dummy.GetInternalContext();
1909+ cairo_rectangle(dummy_ctx, radius*2, radius*2, tex_size, tex_size);
1910+ cairo_set_source_rgba(dummy_ctx, color.red, color.green, color.blue, color.alpha);
1911+ cairo_fill(dummy_ctx);
1912+ dummy.BlurSurface(radius);
1913+
1914+ cu::CairoContext shadow_ctx(tex_size, tex_size);
1915+ cairo_set_source_surface(shadow_ctx, dummy.GetSurface(), 0, 0);
1916+ cairo_paint(shadow_ctx);
1917+ return shadow_ctx;
1918+}
1919+
1920+void Manager::Impl::BuildActiveShadowTexture()
1921+{
1922+ active_shadow_pixmap_ = BuildShadowTexture(manager_->active_shadow_radius(), manager_->active_shadow_color());
1923+}
1924+
1925+void Manager::Impl::BuildInactiveShadowTexture()
1926+{
1927+ inactive_shadow_pixmap_ = BuildShadowTexture(manager_->inactive_shadow_radius(), manager_->inactive_shadow_color());
1928+}
1929+
1930+void Manager::Impl::OnShadowOptionsChanged(bool active)
1931+{
1932+ if (active)
1933+ BuildActiveShadowTexture();
1934+ else
1935+ BuildInactiveShadowTexture();
1936+
1937+ UpdateWindowsExtents();
1938+}
1939+
1940+void Manager::Impl::UpdateWindowsExtents()
1941+{
1942+ for (auto const& win : windows_)
1943+ win.second->impl_->RedrawDecorations();
1944+}
1945+
1946+bool Manager::Impl::UpdateWindow(::Window xid)
1947+{
1948+ auto const& win = GetWindowByXid(xid);
1949+
1950+ if (win && !win->impl_->win_->hasUnmapReference())
1951+ {
1952+ win->Update();
1953+ return true;
1954+ }
1955+
1956+ return false;
1957+}
1958+
1959+Window::Ptr Manager::Impl::GetWindowByXid(::Window xid) const
1960+{
1961+ for (auto const& pair : windows_)
1962+ {
1963+ if (pair.first->id() == xid)
1964+ return pair.second;
1965+ }
1966+
1967+ return nullptr;
1968+}
1969+
1970+Window::Ptr Manager::Impl::GetWindowByFrame(::Window xid) const
1971+{
1972+ auto it = framed_windows_.find(xid);
1973+ if (it == framed_windows_.end())
1974+ return nullptr;
1975+
1976+ return it->second.lock();
1977+}
1978+
1979+bool Manager::Impl::HandleEventBefore(XEvent* event)
1980+{
1981+ active_window_ = screen->activeWindow();
1982+ switch (event->type)
1983+ {
1984+ case ClientMessage:
1985+ if (event->xclient.message_type == atom::_NET_REQUEST_FRAME_EXTENTS)
1986+ {
1987+ if (Window::Ptr const& win = GetWindowByXid(event->xclient.window))
1988+ win->impl_->Decorate();
1989+ }
1990+ break;
1991+ case MotionNotify:
1992+ case EnterNotify:
1993+ case LeaveNotify:
1994+ case ButtonPress:
1995+ case ButtonRelease:
1996+ if (HandleFrameEvent(event))
1997+ return true;
1998+ break;
1999+ }
2000+
2001+ return false;
2002+}
2003+
2004+bool Manager::Impl::HandleEventAfter(XEvent* event)
2005+{
2006+ if (screen->activeWindow() != active_window_)
2007+ {
2008+ // Do this when _NET_ACTIVE_WINDOW changes on root!
2009+ auto const& old_active = GetWindowByXid(active_window_);
2010+
2011+ if (old_active)
2012+ old_active->impl_->active = false;
2013+
2014+ active_window_ = screen->activeWindow();
2015+
2016+ auto const& new_active = GetWindowByXid(active_window_);
2017+
2018+ if (new_active)
2019+ new_active->impl_->active = true;
2020+ }
2021+
2022+ switch (event->type)
2023+ {
2024+ case PropertyNotify:
2025+ {
2026+ if (event->xproperty.atom == Atoms::mwmHints)
2027+ {
2028+ if (Window::Ptr const& win = GetWindowByXid(event->xproperty.window))
2029+ {
2030+ win->impl_->CleanupWindowControls();
2031+ win->Update();
2032+ }
2033+ }
2034+ else if (event->xproperty.atom == XA_WM_NAME ||
2035+ event->xproperty.atom == Atoms::wmName ||
2036+ event->xproperty.atom == atom::_NET_WM_VISIBLE_NAME)
2037+ {
2038+ if (Window::Ptr const& win = GetWindowByXid(event->xproperty.window))
2039+ {
2040+ auto& wm = WindowManager::Default();
2041+ win->title = wm.GetStringProperty(event->xproperty.window, event->xproperty.atom);
2042+ }
2043+ }
2044+ break;
2045+ }
2046+ case ConfigureNotify:
2047+ UpdateWindow(event->xconfigure.window);
2048+ break;
2049+ default:
2050+ if (screen->XShape() && event->type == screen->shapeEvent() + ShapeNotify)
2051+ {
2052+ auto window = reinterpret_cast<XShapeEvent*>(event)->window;
2053+ if (!UpdateWindow(window))
2054+ {
2055+ if (Window::Ptr const& win = GetWindowByFrame(window))
2056+ win->impl_->SyncXShapeWithFrameRegion();
2057+ }
2058+ }
2059+ break;
2060+ }
2061+
2062+ return false;
2063+}
2064+
2065+bool Manager::Impl::HandleFrameEvent(XEvent* event)
2066+{
2067+ auto const& win = GetWindowByFrame(event->xany.window);
2068+
2069+ // ButtonRelease events might happen also outside the frame window, in this
2070+ // case we must unset the mouse owner, wherever the event happens.
2071+ if (!win && event->type != ButtonRelease)
2072+ return false;
2073+
2074+ auto const& input_mixer = win ? win->impl_->input_mixer_ : last_mouse_owner_.lock();
2075+
2076+ if (!input_mixer)
2077+ return false;
2078+
2079+ switch (event->type)
2080+ {
2081+ case MotionNotify:
2082+ {
2083+ input_mixer->MotionEvent(CompPoint(event->xmotion.x_root, event->xmotion.y_root));
2084+ break;
2085+ }
2086+ case EnterNotify:
2087+ {
2088+ input_mixer->EnterEvent(CompPoint(event->xcrossing.x_root, event->xcrossing.y_root));
2089+ break;
2090+ }
2091+ case LeaveNotify:
2092+ {
2093+ input_mixer->LeaveEvent(CompPoint(event->xcrossing.x_root, event->xcrossing.y_root));
2094+ break;
2095+ }
2096+ case ButtonPress:
2097+ {
2098+ input_mixer->ButtonDownEvent(CompPoint(event->xbutton.x_root, event->xbutton.y_root), event->xbutton.button);
2099+ if (input_mixer->GetMouseOwner())
2100+ last_mouse_owner_ = input_mixer;
2101+ break;
2102+ }
2103+ case ButtonRelease:
2104+ {
2105+ input_mixer->ButtonUpEvent(CompPoint(event->xbutton.x_root, event->xbutton.y_root), event->xbutton.button);
2106+ last_mouse_owner_.reset();
2107+ break;
2108+ }
2109+ }
2110+
2111+ // This causes the Alt+Move not to work, we should probably return this value based on the actual handled state
2112+ // return true;
2113+ return false;
2114+}
2115+
2116+Window::Ptr Manager::Impl::HandleWindow(CompWindow* cwin)
2117+{
2118+ auto win = std::make_shared<Window>(cwin);
2119+ auto* wimpl = win->impl_.get();
2120+
2121+ std::weak_ptr<decoration::Window> weak_win(win);
2122+ wimpl->framed.connect(sigc::bind(sigc::mem_fun(this, &Impl::OnWindowFrameChanged), weak_win));
2123+ windows_[cwin] = win;
2124+
2125+ if (wimpl->frame_)
2126+ framed_windows_[wimpl->frame_] = win;
2127+
2128+ return win;
2129+}
2130+
2131+void Manager::Impl::OnWindowFrameChanged(bool framed, ::Window frame, std::weak_ptr<decoration::Window> const& window)
2132+{
2133+ if (!framed || !frame)
2134+ framed_windows_.erase(frame);
2135+ else
2136+ framed_windows_[frame] = window;
2137+}
2138+
2139+// Public APIs
2140+
2141+Manager::Manager()
2142+ : shadow_offset(Style::Get()->ShadowOffset())
2143+ , active_shadow_color(Style::Get()->ActiveShadowColor())
2144+ , active_shadow_radius(Style::Get()->ActiveShadowRadius())
2145+ , inactive_shadow_color(Style::Get()->InactiveShadowColor())
2146+ , inactive_shadow_radius(Style::Get()->InactiveShadowRadius())
2147+ , impl_(new Impl(this))
2148+{}
2149+
2150+Manager::~Manager()
2151+{
2152+ if (manager_ == this)
2153+ manager_ = nullptr;
2154+}
2155+
2156+void Manager::AddSupportedAtoms(std::vector<Atom>& atoms) const
2157+{
2158+ if (impl_->enable_add_supported_atoms_)
2159+ atoms.push_back(atom::_NET_REQUEST_FRAME_EXTENTS);
2160+}
2161+
2162+bool Manager::HandleEventBefore(XEvent* xevent)
2163+{
2164+ return impl_->HandleEventBefore(xevent);
2165+}
2166+
2167+bool Manager::HandleEventAfter(XEvent* xevent)
2168+{
2169+ return impl_->HandleEventAfter(xevent);
2170+}
2171+
2172+Window::Ptr Manager::HandleWindow(CompWindow* cwin)
2173+{
2174+ return impl_->HandleWindow(cwin);
2175+}
2176+
2177+void Manager::UnHandleWindow(CompWindow* cwin)
2178+{
2179+ impl_->windows_.erase(cwin);
2180+}
2181+
2182+Window::Ptr Manager::GetWindowByXid(::Window xid)
2183+{
2184+ return impl_->GetWindowByXid(xid);
2185+}
2186+
2187+std::string Manager::GetName() const
2188+{
2189+ return "DecorationsManager";
2190+}
2191+
2192+void Manager::AddProperties(debug::IntrospectionData& data)
2193+{
2194+ data.add("shadow_offset", shadow_offset())
2195+ .add("active_shadow_color", active_shadow_color())
2196+ .add("active_shadow_radius", active_shadow_radius())
2197+ .add("inactive_shadow_color", inactive_shadow_color())
2198+ .add("inactive_shadow_radius", inactive_shadow_radius())
2199+ .add("active_window", impl_->active_window_);
2200+}
2201+
2202+debug::Introspectable::IntrospectableList Manager::GetIntrospectableChildren()
2203+{
2204+ IntrospectableList children;
2205+
2206+ for (auto const& win : impl_->windows_)
2207+ children.push_back(win.second.get());
2208+
2209+ return children;
2210+}
2211+
2212+
2213+} // decoration namespace
2214+} // unity namespace
2215
2216=== added file 'decorations/DecorationsManager.h'
2217--- decorations/DecorationsManager.h 1970-01-01 00:00:00 +0000
2218+++ decorations/DecorationsManager.h 2014-01-23 15:21:26 +0000
2219@@ -0,0 +1,74 @@
2220+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
2221+/*
2222+ * Copyright (C) 2013 Canonical Ltd
2223+ *
2224+ * This program is free software: you can redistribute it and/or modify
2225+ * it under the terms of the GNU General Public License version 3 as
2226+ * published by the Free Software Foundation.
2227+ *
2228+ * This program is distributed in the hope that it will be useful,
2229+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2230+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2231+ * GNU General Public License for more details.
2232+ *
2233+ * You should have received a copy of the GNU General Public License
2234+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2235+ *
2236+ * Authored by: Marco Trevisan <marco.trevisan@canonical.com>
2237+ */
2238+
2239+#ifndef UNITY_DECORATION_MANAGER
2240+#define UNITY_DECORATION_MANAGER
2241+
2242+#include <NuxCore/Property.h>
2243+#include "DecoratedWindow.h"
2244+
2245+class CompWindow;
2246+class CompManager;
2247+
2248+namespace unity
2249+{
2250+namespace decoration
2251+{
2252+class Manager : public debug::Introspectable
2253+{
2254+public:
2255+ typedef std::shared_ptr<Manager> Ptr;
2256+
2257+ Manager();
2258+ virtual ~Manager();
2259+
2260+ nux::Property<nux::Point> shadow_offset;
2261+ nux::Property<nux::Color> active_shadow_color;
2262+ nux::Property<unsigned> active_shadow_radius;
2263+ nux::Property<nux::Color> inactive_shadow_color;
2264+ nux::Property<unsigned> inactive_shadow_radius;
2265+
2266+ void AddSupportedAtoms(std::vector<Atom>& atoms) const;
2267+ bool HandleEventBefore(XEvent*);
2268+ bool HandleEventAfter(XEvent*);
2269+
2270+ Window::Ptr HandleWindow(CompWindow*);
2271+ void UnHandleWindow(CompWindow*);
2272+
2273+ Window::Ptr GetWindowByXid(::Window);
2274+
2275+protected:
2276+ std::string GetName() const;
2277+ void AddProperties(debug::IntrospectionData&);
2278+ IntrospectableList GetIntrospectableChildren();
2279+
2280+private:
2281+ Manager(Manager const&) = delete;
2282+ Manager& operator=(Manager const&) = delete;
2283+
2284+ friend class Window;
2285+
2286+ struct Impl;
2287+ std::unique_ptr<Impl> impl_;
2288+};
2289+
2290+} // decoration namespace
2291+} // unity namespace
2292+
2293+#endif
2294
2295=== added file 'decorations/DecorationsPriv.h'
2296--- decorations/DecorationsPriv.h 1970-01-01 00:00:00 +0000
2297+++ decorations/DecorationsPriv.h 2014-01-23 15:21:26 +0000
2298@@ -0,0 +1,165 @@
2299+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
2300+/*
2301+ * Copyright (C) 2013 Canonical Ltd
2302+ *
2303+ * This program is free software: you can redistribute it and/or modify
2304+ * it under the terms of the GNU General Public License version 3 as
2305+ * published by the Free Software Foundation.
2306+ *
2307+ * This program is distributed in the hope that it will be useful,
2308+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2309+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2310+ * GNU General Public License for more details.
2311+ *
2312+ * You should have received a copy of the GNU General Public License
2313+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2314+ *
2315+ * Authored by: Marco Trevisan <marco.trevisan@canonical.com>
2316+ */
2317+
2318+#ifndef UNITY_DECORATION_MANAGER_PRIV
2319+#define UNITY_DECORATION_MANAGER_PRIV
2320+
2321+#include <unordered_map>
2322+#include <NuxCore/NuxCore.h>
2323+#include <NuxCore/Rect.h>
2324+#include <UnityCore/ConnectionManager.h>
2325+#include <core/core.h>
2326+#include <opengl/opengl.h>
2327+#include <composite/composite.h>
2328+#include <X11/extensions/shape.h>
2329+
2330+#include "DecorationsDataPool.h"
2331+#include "DecorationsManager.h"
2332+#include "DecorationsTitle.h"
2333+#include "DecorationsInputMixer.h"
2334+
2335+class CompRegion;
2336+
2337+namespace unity
2338+{
2339+namespace decoration
2340+{
2341+namespace cu = compiz_utils;
2342+
2343+extern Manager* manager_;
2344+
2345+struct Quads
2346+{
2347+ enum class Pos
2348+ {
2349+ TOP_LEFT = 0,
2350+ TOP_RIGHT,
2351+ BOTTOM_LEFT,
2352+ BOTTOM_RIGHT,
2353+ Size
2354+ };
2355+
2356+ cu::TextureQuad& operator[](Pos position) { return inner_vector_[unsigned(position)]; }
2357+ cu::TextureQuad const& operator[](Pos position) const { return inner_vector_[unsigned(position)]; }
2358+ std::size_t size() const { return inner_vector_.size(); }
2359+
2360+private:
2361+ std::array<cu::TextureQuad, size_t(Pos::Size)> inner_vector_;
2362+};
2363+
2364+struct Window::Impl
2365+{
2366+ Impl(decoration::Window*, CompWindow*);
2367+ ~Impl();
2368+
2369+ nux::Property<bool> active;
2370+ sigc::signal<void, bool, ::Window> framed;
2371+
2372+ void Update();
2373+ void Decorate();
2374+ void Undecorate();
2375+ bool IsMaximized() const;
2376+ bool FullyDecorated() const;
2377+ bool ShadowDecorated() const;
2378+ void RedrawDecorations();
2379+
2380+private:
2381+ void UnsetExtents();
2382+ void SetupExtents();
2383+ void UpdateFrame();
2384+ void CreateFrame(nux::Geometry const&);
2385+ void UpdateFrameGeo(nux::Geometry const&);
2386+ void UnsetFrame();
2387+ void SetupWindowControls();
2388+ void CleanupWindowControls();
2389+ void SyncXShapeWithFrameRegion();
2390+ bool ShouldBeDecorated() const;
2391+ GLTexture* ShadowTexture() const;
2392+ unsigned ShadowRadius() const;
2393+
2394+ void ComputeShadowQuads();
2395+ void UpdateDecorationTextures();
2396+ void RenderDecorationTexture(Side, nux::Geometry const&);
2397+ void Draw(GLMatrix const&, GLWindowPaintAttrib const&, CompRegion const&, unsigned mask);
2398+
2399+ friend class Window;
2400+ friend struct Manager::Impl;
2401+
2402+ decoration::Window *parent_;
2403+ ::CompWindow* win_;
2404+ ::CompositeWindow* cwin_;
2405+ ::GLWindow* glwin_;
2406+ ::Window frame_;
2407+ bool dirty_geo_;
2408+
2409+ CompRect last_shadow_rect_;
2410+ Quads shadow_quads_;
2411+ nux::Geometry frame_geo_;
2412+ CompRegion frame_region_;
2413+ connection::Wrapper theme_changed_;
2414+ std::string last_title_;
2415+ std::vector<cu::SimpleTextureQuad> bg_textures_;
2416+ InputMixer::Ptr input_mixer_;
2417+ Layout::Ptr top_layout_;
2418+ Title::Ptr title_;
2419+ Item::Ptr edge_borders_;
2420+};
2421+
2422+struct Manager::Impl : sigc::trackable
2423+{
2424+ Impl(decoration::Manager*);
2425+ ~Impl();
2426+
2427+ Window::Ptr HandleWindow(CompWindow* cwin);
2428+ bool HandleEventBefore(XEvent*);
2429+ bool HandleEventAfter(XEvent*);
2430+ bool HandleFrameEvent(XEvent*);
2431+
2432+private:
2433+ Window::Ptr GetWindowByXid(::Window) const;
2434+ Window::Ptr GetWindowByFrame(::Window) const;
2435+
2436+ bool UpdateWindow(::Window);
2437+ void UpdateWindowsExtents();
2438+
2439+ void BuildActiveShadowTexture();
2440+ void BuildInactiveShadowTexture();
2441+ cu::PixmapTexture::Ptr BuildShadowTexture(unsigned radius, nux::Color const&);
2442+ void OnShadowOptionsChanged(bool active);
2443+ void OnWindowFrameChanged(bool, ::Window, std::weak_ptr<decoration::Window> const&);
2444+
2445+ friend class Manager;
2446+ friend struct Window::Impl;
2447+
2448+ ::Window active_window_;
2449+ bool enable_add_supported_atoms_;
2450+
2451+ DataPool::Ptr data_pool_;
2452+ cu::PixmapTexture::Ptr active_shadow_pixmap_;
2453+ cu::PixmapTexture::Ptr inactive_shadow_pixmap_;
2454+
2455+ std::weak_ptr<InputMixer> last_mouse_owner_;
2456+ std::map<CompWindow*, decoration::Window::Ptr> windows_;
2457+ std::unordered_map<::Window, std::weak_ptr<decoration::Window>> framed_windows_;
2458+};
2459+
2460+} // decoration namespace
2461+} // unity namespace
2462+
2463+#endif
2464
2465=== added file 'decorations/DecorationsTitle.cpp'
2466--- decorations/DecorationsTitle.cpp 1970-01-01 00:00:00 +0000
2467+++ decorations/DecorationsTitle.cpp 2014-01-23 15:21:26 +0000
2468@@ -0,0 +1,116 @@
2469+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
2470+/*
2471+ * Copyright (C) 2013 Canonical Ltd
2472+ *
2473+ * This program is free software: you can redistribute it and/or modify
2474+ * it under the terms of the GNU General Public License version 3 as
2475+ * published by the Free Software Foundation.
2476+ *
2477+ * This program is distributed in the hope that it will be useful,
2478+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2479+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2480+ * GNU General Public License for more details.
2481+ *
2482+ * You should have received a copy of the GNU General Public License
2483+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2484+ *
2485+ * Authored by: Marco Trevisan <marco.trevisan@canonical.com>
2486+ */
2487+
2488+#include <sigc++/adaptors/hide.h>
2489+#include "DecorationsTitle.h"
2490+#include "DecorationStyle.h"
2491+
2492+namespace unity
2493+{
2494+namespace decoration
2495+{
2496+
2497+Title::Title()
2498+{
2499+ text.changed.connect(sigc::mem_fun(this, &Title::OnTextChanged));
2500+ focused.changed.connect(sigc::hide(sigc::mem_fun(this, &Title::RenderTexture)));
2501+ Style::Get()->title_font.changed.connect(sigc::mem_fun(this, &Title::OnFontChanged));
2502+}
2503+
2504+void Title::OnTextChanged(std::string const& new_text)
2505+{
2506+ bool damaged = false;
2507+ auto real_size = Style::Get()->TitleNaturalSize(new_text);
2508+
2509+ if (GetNaturalWidth() > real_size.width || GetNaturalHeight() > real_size.height)
2510+ {
2511+ Damage();
2512+ damaged = true;
2513+ }
2514+
2515+ SetSize(real_size.width, real_size.height);
2516+ texture_size_ = nux::Size();
2517+
2518+ if (!damaged)
2519+ Damage();
2520+}
2521+
2522+void Title::OnFontChanged(std::string const&)
2523+{
2524+ text.changed.emit(text());
2525+}
2526+
2527+void Title::RenderTexture()
2528+{
2529+ auto state = focused() ? WidgetState::NORMAL : WidgetState::BACKDROP;
2530+ cu::CairoContext text_ctx(texture_size_.width, texture_size_.height);
2531+ Style::Get()->DrawTitle(text(), state, text_ctx, texture_size_.width, texture_size_.height);
2532+ SetTexture(text_ctx);
2533+}
2534+
2535+void Title::SetX(int x)
2536+{
2537+ float alignment = Style::Get()->TitleAlignmentValue();
2538+
2539+ if (alignment > 0)
2540+ {
2541+ if (BasicContainer::Ptr const& top = GetTopParent())
2542+ {
2543+ auto const& top_geo = top->ContentGeometry();
2544+ x = std::max<int>(x, top_geo.x() + (top_geo.width() - GetNaturalWidth()) * alignment);
2545+ }
2546+ }
2547+
2548+ TexturedItem::SetX(x);
2549+}
2550+
2551+int Title::GetNaturalWidth() const
2552+{
2553+ return Item::GetNaturalWidth();
2554+}
2555+
2556+int Title::GetNaturalHeight() const
2557+{
2558+ return Item::GetNaturalHeight();
2559+}
2560+
2561+void Title::Draw(GLWindow* ctx, GLMatrix const& transformation, GLWindowPaintAttrib const& attrib,
2562+ CompRegion const& clip, unsigned mask)
2563+{
2564+ auto const& geo = Geometry();
2565+ nux::Size tex_size(geo.width(), geo.height());
2566+
2567+ if (texture_size_ != tex_size)
2568+ {
2569+ texture_size_ = tex_size;
2570+ RenderTexture();
2571+ }
2572+
2573+ TexturedItem::Draw(ctx, transformation, attrib, clip, mask);
2574+}
2575+
2576+void Title::AddProperties(debug::IntrospectionData& data)
2577+{
2578+ TexturedItem::AddProperties(data);
2579+ data.add("text", text())
2580+ .add("texture_size", texture_size_);
2581+}
2582+
2583+} // decoration namespace
2584+} // unity namespace
2585
2586=== added file 'decorations/DecorationsTitle.h'
2587--- decorations/DecorationsTitle.h 1970-01-01 00:00:00 +0000
2588+++ decorations/DecorationsTitle.h 2014-01-23 15:21:26 +0000
2589@@ -0,0 +1,61 @@
2590+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
2591+/*
2592+ * Copyright (C) 2013 Canonical Ltd
2593+ *
2594+ * This program is free software: you can redistribute it and/or modify
2595+ * it under the terms of the GNU General Public License version 3 as
2596+ * published by the Free Software Foundation.
2597+ *
2598+ * This program is distributed in the hope that it will be useful,
2599+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2600+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2601+ * GNU General Public License for more details.
2602+ *
2603+ * You should have received a copy of the GNU General Public License
2604+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2605+ *
2606+ * Authored by: Marco Trevisan <marco.trevisan@canonical.com>
2607+ */
2608+
2609+#ifndef UNITY_DECORATIONS_TITLE
2610+#define UNITY_DECORATIONS_TITLE
2611+
2612+#include "DecorationsWidgets.h"
2613+
2614+namespace unity
2615+{
2616+namespace decoration
2617+{
2618+
2619+class Title : public TexturedItem
2620+{
2621+public:
2622+ typedef std::shared_ptr<Title> Ptr;
2623+
2624+ nux::Property<std::string> text;
2625+
2626+ Title();
2627+
2628+ void SetX(int);
2629+ int GetNaturalWidth() const;
2630+ int GetNaturalHeight() const;
2631+
2632+ void Draw(GLWindow*, GLMatrix const&, GLWindowPaintAttrib const&, CompRegion const&, unsigned mask);
2633+
2634+protected:
2635+ std::string GetName() const { return "Title"; }
2636+ void AddProperties(debug::IntrospectionData&);
2637+
2638+private:
2639+ void OnFontChanged(std::string const&);
2640+ void OnTextChanged(std::string const& new_text);
2641+ void RenderTexture();
2642+
2643+ bool render_texture_;
2644+ nux::Size texture_size_;
2645+};
2646+
2647+} // decoration namespace
2648+} // unity namespace
2649+
2650+#endif // UNITY_DECORATIONS_TITLE
2651
2652=== added file 'decorations/DecorationsWidgets.cpp'
2653--- decorations/DecorationsWidgets.cpp 1970-01-01 00:00:00 +0000
2654+++ decorations/DecorationsWidgets.cpp 2014-01-23 15:21:26 +0000
2655@@ -0,0 +1,493 @@
2656+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
2657+/*
2658+ * Copyright (C) 2013 Canonical Ltd
2659+ *
2660+ * This program is free software: you can redistribute it and/or modify
2661+ * it under the terms of the GNU General Public License version 3 as
2662+ * published by the Free Software Foundation.
2663+ *
2664+ * This program is distributed in the hope that it will be useful,
2665+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2666+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2667+ * GNU General Public License for more details.
2668+ *
2669+ * You should have received a copy of the GNU General Public License
2670+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2671+ *
2672+ * Authored by: Marco Trevisan <marco.trevisan@canonical.com>
2673+ */
2674+
2675+#include <NuxCore/Logger.h>
2676+#include <composite/composite.h>
2677+#include <boost/range/adaptor/reversed.hpp>
2678+#include "DecorationsWidgets.h"
2679+
2680+namespace unity
2681+{
2682+namespace decoration
2683+{
2684+namespace
2685+{
2686+DECLARE_LOGGER(logger, "unity.decoration.widgets");
2687+CompositeScreen* cscreen_ = CompositeScreen::get(screen);
2688+
2689+template <typename T> constexpr T max(T a, T b) { return (a > b) ? a : b; }
2690+template <typename T> constexpr T min(T a, T b) { return (a < b) ? a : b; }
2691+constexpr int clamp_size(int v) { return min<int>(max(0, v), std::numeric_limits<short>::max()); }
2692+}
2693+
2694+Item::Item()
2695+ : visible(true)
2696+ , focused(false)
2697+ , sensitive(true)
2698+ , mouse_owner(false)
2699+ , max_(std::numeric_limits<short>::max(), std::numeric_limits<short>::max())
2700+{
2701+ auto parent_relayout_cb = sigc::mem_fun(this, &Item::RequestRelayout);
2702+ visible.changed.connect(sigc::hide(parent_relayout_cb));
2703+ geo_parameters_changed.connect(parent_relayout_cb);
2704+}
2705+
2706+void Item::SetSize(int width, int height)
2707+{
2708+ natural_.width = clamp_size(width);
2709+ natural_.height = clamp_size(height);
2710+ SetMinWidth(width);
2711+ SetMaxWidth(width);
2712+ SetMinHeight(height);
2713+ SetMaxHeight(height);
2714+}
2715+
2716+void Item::SetCoords(int x, int y)
2717+{
2718+ auto& geo = InternalGeo();
2719+
2720+ if (geo.x() == x && geo.y() == y)
2721+ return;
2722+
2723+ geo.setX(x);
2724+ geo.setY(y);
2725+ geo_parameters_changed.emit();
2726+}
2727+
2728+int Item::GetNaturalWidth() const
2729+{
2730+ return natural_.width;
2731+}
2732+
2733+int Item::GetNaturalHeight() const
2734+{
2735+ return natural_.height;
2736+}
2737+
2738+int Item::GetMaxWidth() const
2739+{
2740+ return max_.width;
2741+};
2742+
2743+int Item::GetMaxHeight() const
2744+{
2745+ return max_.height;
2746+};
2747+
2748+int Item::GetMinWidth() const
2749+{
2750+ return min_.width;
2751+};
2752+
2753+int Item::GetMinHeight() const
2754+{
2755+ return min_.height;
2756+};
2757+
2758+void Item::SetMaxWidth(int value)
2759+{
2760+ int clamped = clamp_size(value);
2761+
2762+ if (max_.width == clamped)
2763+ return;
2764+
2765+ max_.width = clamped;
2766+ min_.width = min(min_.width, max_.width);
2767+
2768+ if (Geometry().width() > max_.width)
2769+ InternalGeo().setWidth(min(GetNaturalWidth(), max_.width));
2770+
2771+ geo_parameters_changed.emit();
2772+}
2773+
2774+void Item::SetMinWidth(int value)
2775+{
2776+ int clamped = clamp_size(value);
2777+
2778+ if (min_.width == clamped)
2779+ return;
2780+
2781+ min_.width = clamped;
2782+ max_.width = max(min_.width, max_.width);
2783+
2784+ if (Geometry().width() < min_.width)
2785+ InternalGeo().setWidth(min_.width);
2786+
2787+ geo_parameters_changed.emit();
2788+}
2789+
2790+void Item::SetMaxHeight(int value)
2791+{
2792+ int clamped = clamp_size(value);
2793+
2794+ if (max_.height == clamped)
2795+ return;
2796+
2797+ max_.height = clamped;
2798+ min_.height = min(min_.height, max_.height);
2799+
2800+ if (Geometry().height() > max_.height)
2801+ InternalGeo().setHeight(min(GetNaturalHeight(), max_.height));
2802+
2803+ geo_parameters_changed.emit();
2804+}
2805+
2806+void Item::SetMinHeight(int value)
2807+{
2808+ int clamped = clamp_size(value);
2809+
2810+ if (min_.height == clamped)
2811+ return;
2812+
2813+ min_.height = clamped;
2814+ max_.height = max(min_.height, max_.height);
2815+
2816+ if (Geometry().height() < min_.height)
2817+ InternalGeo().setHeight(min_.height);
2818+
2819+ geo_parameters_changed.emit();
2820+}
2821+
2822+void Item::Damage()
2823+{
2824+ cscreen_->damageRegion(Geometry());
2825+}
2826+
2827+CompRect const& Item::Geometry() const
2828+{
2829+ return const_cast<Item*>(this)->InternalGeo();
2830+}
2831+
2832+void Item::SetParent(BasicContainer::Ptr const& parent)
2833+{
2834+ if (parent && !parent_.expired())
2835+ {
2836+ LOG_ERROR(logger) << "This item has already a parent!";
2837+ return;
2838+ }
2839+
2840+ parent_ = parent;
2841+}
2842+
2843+BasicContainer::Ptr Item::GetParent() const
2844+{
2845+ return parent_.lock();
2846+}
2847+
2848+BasicContainer::Ptr Item::GetTopParent() const
2849+{
2850+ BasicContainer::Ptr parent = GetParent();
2851+
2852+ while (parent)
2853+ {
2854+ if (parent->parent_.expired())
2855+ return parent;
2856+
2857+ parent = parent->GetParent();
2858+ }
2859+
2860+ return parent;
2861+}
2862+
2863+void Item::RequestRelayout()
2864+{
2865+ if (BasicContainer::Ptr const& parent = parent_.lock())
2866+ parent->Relayout();
2867+}
2868+
2869+void Item::AddProperties(debug::IntrospectionData& data)
2870+{
2871+ data.add(Geometry())
2872+ .add("max_size", max_)
2873+ .add("min_size", min_)
2874+ .add("natural_size", nux::Size(GetNaturalWidth(), GetNaturalHeight()))
2875+ .add("visible", visible())
2876+ .add("focused", focused())
2877+ .add("sensitive", sensitive())
2878+ .add("mouse_owner", mouse_owner())
2879+ .add("is_container", IsContainer());
2880+}
2881+
2882+//
2883+
2884+void TexturedItem::SetTexture(cu::SimpleTexture::Ptr const& tex)
2885+{
2886+ if (texture_.st == tex)
2887+ return;
2888+
2889+ auto prev_geo = Geometry();
2890+ texture_.SetTexture(tex);
2891+ auto const& actual_geo = Geometry();
2892+
2893+ if (prev_geo != actual_geo)
2894+ {
2895+ max_ = { actual_geo.width(), actual_geo.height() };
2896+ min_ = max_;
2897+ geo_parameters_changed.emit();
2898+
2899+ if (!actual_geo.contains(prev_geo))
2900+ cscreen_->damageRegion(prev_geo);
2901+ }
2902+
2903+ Damage();
2904+}
2905+
2906+void TexturedItem::Draw(GLWindow* ctx, GLMatrix const& transformation, GLWindowPaintAttrib const& attrib,
2907+ CompRegion const& clip, unsigned mask)
2908+{
2909+ if (!visible || Geometry().isEmpty() || !texture_)
2910+ return;
2911+
2912+ ctx->vertexBuffer()->begin();
2913+ ctx->glAddGeometry({texture_.quad.matrix}, texture_.quad.box, clip);
2914+
2915+ if (ctx->vertexBuffer()->end())
2916+ ctx->glDrawTexture(texture_, transformation, attrib, mask);
2917+}
2918+
2919+int TexturedItem::GetNaturalWidth() const
2920+{
2921+ return (texture_) ? texture_.st->width() : Item::GetNaturalWidth();
2922+}
2923+
2924+int TexturedItem::GetNaturalHeight() const
2925+{
2926+ return (texture_) ? texture_.st->height() : Item::GetNaturalHeight();
2927+}
2928+
2929+CompRect& TexturedItem::InternalGeo()
2930+{
2931+ return texture_.quad.box;
2932+}
2933+
2934+void TexturedItem::SetCoords(int x, int y)
2935+{
2936+ texture_.SetCoords(x, y);
2937+}
2938+
2939+//
2940+
2941+BasicContainer::BasicContainer()
2942+{
2943+ geo_parameters_changed.connect(sigc::mem_fun(this, &BasicContainer::Relayout));
2944+ focused.changed.connect([this] (bool focused) {
2945+ for (auto const& item : items_)
2946+ item->focused = focused;
2947+ });
2948+}
2949+
2950+CompRect BasicContainer::ContentGeometry() const
2951+{
2952+ return Geometry();
2953+}
2954+
2955+void BasicContainer::AddProperties(debug::IntrospectionData& data)
2956+{
2957+ Item::AddProperties(data);
2958+ data.add(ContentGeometry());
2959+}
2960+
2961+debug::Introspectable::IntrospectableList BasicContainer::GetIntrospectableChildren()
2962+{
2963+ IntrospectableList children;
2964+
2965+ for (auto const& item : items_)
2966+ children.push_back(item.get());
2967+
2968+ return children;
2969+}
2970+
2971+//
2972+
2973+Layout::Layout()
2974+ : inner_padding(0, sigc::mem_fun(this, &Layout::SetPadding))
2975+ , left_padding(0, sigc::mem_fun(this, &Layout::SetPadding))
2976+ , right_padding(0, sigc::mem_fun(this, &Layout::SetPadding))
2977+ , top_padding(0, sigc::mem_fun(this, &Layout::SetPadding))
2978+ , bottom_padding(0, sigc::mem_fun(this, &Layout::SetPadding))
2979+ , relayouting_(false)
2980+{}
2981+
2982+void Layout::Append(Item::Ptr const& item)
2983+{
2984+ if (!item || std::find(items_.begin(), items_.end(), item) != items_.end())
2985+ return;
2986+
2987+ if (item->GetParent())
2988+ {
2989+ LOG_ERROR(logger) << "Impossible to add an item that has already a parent";
2990+ return;
2991+ }
2992+
2993+ items_.push_back(item);
2994+ item->focused = focused();
2995+ item->SetParent(shared_from_this());
2996+ Relayout();
2997+}
2998+
2999+void Layout::Remove(Item::Ptr const& item)
3000+{
3001+ auto it = std::find(items_.begin(), items_.end(), item);
3002+
3003+ if (it == items_.end())
3004+ return;
3005+
3006+ item->SetParent(nullptr);
3007+ items_.erase(it);
3008+ Relayout();
3009+}
3010+
3011+CompRect Layout::ContentGeometry() const
3012+{
3013+ return CompRect(rect_.x() + min(left_padding(), rect_.width()),
3014+ rect_.y() + min(top_padding(), rect_.height()),
3015+ clamp_size(rect_.width() - left_padding - right_padding),
3016+ clamp_size(rect_.height() - top_padding - bottom_padding));
3017+}
3018+
3019+void Layout::Relayout()
3020+{
3021+ if (relayouting_)
3022+ return;
3023+
3024+ relayouting_ = true;
3025+ int loop = 0;
3026+ CompRect old_geo(rect_);
3027+
3028+ nux::Size available_space(clamp_size(max_.width - left_padding - right_padding),
3029+ clamp_size(max_.height - top_padding - bottom_padding));
3030+
3031+ do
3032+ {
3033+ nux::Size content(min(left_padding(), max_.width), 0);
3034+
3035+ for (auto const& item : items_)
3036+ {
3037+ if (!item->visible())
3038+ continue;
3039+
3040+ if (loop == 0)
3041+ {
3042+ item->SetMinWidth(item->GetNaturalWidth());
3043+ item->SetMaxWidth(available_space.width);
3044+ item->SetMinHeight(min(available_space.height, item->GetNaturalHeight()));
3045+ item->SetMaxHeight(available_space.height);
3046+ }
3047+
3048+ auto const& item_geo = item->Geometry();
3049+ content.height = max(content.height, item_geo.height());
3050+ item->SetX(rect_.x() + content.width);
3051+
3052+ if (item_geo.width() > 0)
3053+ content.width += item_geo.width() + inner_padding;
3054+ }
3055+
3056+ if (!items_.empty() && content.width > inner_padding)
3057+ content.width -= inner_padding;
3058+
3059+ int actual_right_padding = max(0, min(right_padding(), max_.width - content.width));
3060+ int vertical_padding = top_padding + bottom_padding;
3061+
3062+ content.width += actual_right_padding;
3063+ content.height += min(vertical_padding, max_.height);
3064+
3065+ if (content.width < min_.width)
3066+ content.width = min_.width;
3067+
3068+ if (content.height < min_.height)
3069+ content.height = min_.height;
3070+
3071+ int exceeding_width = content.width - max_.width + inner_padding + right_padding - actual_right_padding;
3072+ int content_y = rect_.y() + top_padding;
3073+
3074+ for (auto const& item : boost::adaptors::reverse(items_))
3075+ {
3076+ if (!item->visible())
3077+ continue;
3078+
3079+ auto const& item_geo = item->Geometry();
3080+
3081+ if (exceeding_width > 0)
3082+ exceeding_width -= inner_padding;
3083+
3084+ if (exceeding_width > 0 && item_geo.width() > 0)
3085+ {
3086+ int old_width = item_geo.width();
3087+ int max_item_width = clamp_size(old_width - exceeding_width);
3088+ item->SetMaxWidth(max_item_width);
3089+ exceeding_width -= (old_width - max_item_width);
3090+ }
3091+
3092+ item->SetY(content_y + (content.height - vertical_padding - item_geo.height()) / 2);
3093+ }
3094+
3095+ rect_.setWidth(content.width);
3096+ rect_.setHeight(content.height);
3097+
3098+ if (loop > 1)
3099+ {
3100+ LOG_ERROR(logger) << "Relayouting is taking more than expected, process should be completed in maximum two loops!";
3101+ break;
3102+ }
3103+
3104+ ++loop;
3105+ }
3106+ while (rect_.width() > max_.width || rect_.height() > max_.height);
3107+
3108+ relayouting_ = false;
3109+
3110+ if (old_geo != rect_)
3111+ geo_parameters_changed.emit();
3112+}
3113+
3114+void Layout::Draw(GLWindow* ctx, GLMatrix const& transformation, GLWindowPaintAttrib const& attrib,
3115+ CompRegion const& clip, unsigned mask)
3116+{
3117+ for (auto const& item : items_)
3118+ {
3119+ if (item->visible())
3120+ item->Draw(ctx, transformation, attrib, clip, mask);
3121+ }
3122+}
3123+
3124+bool Layout::SetPadding(int& target, int new_value)
3125+{
3126+ int padding = clamp_size(new_value);
3127+
3128+ if (padding == target)
3129+ return false;
3130+
3131+ target = padding;
3132+ Relayout();
3133+
3134+ return true;
3135+}
3136+
3137+void Layout::AddProperties(debug::IntrospectionData& data)
3138+{
3139+ Item::AddProperties(data);
3140+ data.add("inner_padding", inner_padding())
3141+ .add("left_padding", left_padding())
3142+ .add("right_padding", right_padding())
3143+ .add("top_padding", top_padding())
3144+ .add("bottom_padding", bottom_padding());
3145+}
3146+
3147+} // decoration namespace
3148+} // unity namespace
3149
3150=== added file 'decorations/DecorationsWidgets.h'
3151--- decorations/DecorationsWidgets.h 1970-01-01 00:00:00 +0000
3152+++ decorations/DecorationsWidgets.h 2014-01-23 15:21:26 +0000
3153@@ -0,0 +1,190 @@
3154+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
3155+/*
3156+ * Copyright (C) 2013 Canonical Ltd
3157+ *
3158+ * This program is free software: you can redistribute it and/or modify
3159+ * it under the terms of the GNU General Public License version 3 as
3160+ * published by the Free Software Foundation.
3161+ *
3162+ * This program is distributed in the hope that it will be useful,
3163+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3164+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3165+ * GNU General Public License for more details.
3166+ *
3167+ * You should have received a copy of the GNU General Public License
3168+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3169+ *
3170+ * Authored by: Marco Trevisan <marco.trevisan@canonical.com>
3171+ */
3172+
3173+#ifndef UNITY_DECORATION_WIDGETS
3174+#define UNITY_DECORATION_WIDGETS
3175+
3176+#include <deque>
3177+#include <NuxCore/Size.h>
3178+#include <NuxCore/Property.h>
3179+#include "Introspectable.h"
3180+#include "CompizUtils.h"
3181+
3182+namespace unity
3183+{
3184+namespace decoration
3185+{
3186+namespace cu = compiz_utils;
3187+
3188+class BasicContainer;
3189+
3190+class Item : public sigc::trackable, public debug::Introspectable
3191+{
3192+public:
3193+ typedef std::shared_ptr<Item> Ptr;
3194+ typedef std::deque<Item::Ptr> List;
3195+
3196+ Item();
3197+ virtual ~Item() = default;
3198+
3199+ nux::Property<bool> visible;
3200+ nux::Property<bool> focused;
3201+ nux::Property<bool> sensitive;
3202+ nux::Property<bool> mouse_owner;
3203+
3204+ CompRect const& Geometry() const;
3205+ virtual int GetNaturalWidth() const;
3206+ virtual int GetNaturalHeight() const;
3207+
3208+ virtual void SetCoords(int x, int y);
3209+ virtual void SetX(int x) { SetCoords(x, Geometry().y()); }
3210+ virtual void SetY(int y) { SetCoords(Geometry().x(), y); }
3211+ virtual void SetSize(int width, int height);
3212+ virtual void SetWidth(int width) { SetSize(width, Geometry().height()); }
3213+ virtual void SetHeight(int height) { SetSize(Geometry().width(), height); };
3214+
3215+ virtual void SetMaxWidth(int max_width);
3216+ virtual void SetMaxHeight(int max_height);
3217+ virtual void SetMinWidth(int min_width);
3218+ virtual void SetMinHeight(int min_height);
3219+
3220+ int GetMaxWidth() const;
3221+ int GetMaxHeight() const;
3222+ int GetMinWidth() const;
3223+ int GetMinHeight() const;
3224+
3225+ void SetParent(std::shared_ptr<BasicContainer> const&);
3226+ std::shared_ptr<BasicContainer> GetParent() const;
3227+ std::shared_ptr<BasicContainer> GetTopParent() const;
3228+
3229+ void Damage();
3230+ virtual void Draw(GLWindow*, GLMatrix const&, GLWindowPaintAttrib const&, CompRegion const&, unsigned mask) {}
3231+
3232+protected:
3233+ virtual CompRect& InternalGeo() = 0;
3234+ sigc::signal<void> geo_parameters_changed;
3235+
3236+ virtual bool IsContainer() const { return false; }
3237+ void RequestRelayout();
3238+
3239+ friend class InputMixer;
3240+ virtual void MotionEvent(CompPoint const&) {}
3241+ virtual void ButtonDownEvent(CompPoint const&, unsigned button) {}
3242+ virtual void ButtonUpEvent(CompPoint const&, unsigned button) {}
3243+
3244+ std::string GetName() const { return "Item"; }
3245+ void AddProperties(debug::IntrospectionData&);
3246+
3247+private:
3248+ Item(Item const&) = delete;
3249+ Item& operator=(Item const&) = delete;
3250+
3251+protected:
3252+ nux::Size max_;
3253+ nux::Size min_;
3254+ nux::Size natural_;
3255+
3256+private:
3257+ std::weak_ptr<BasicContainer> parent_;
3258+};
3259+
3260+class SimpleItem : public Item
3261+{
3262+protected:
3263+ CompRect& InternalGeo() { return rect_; }
3264+ CompRect rect_;
3265+};
3266+
3267+
3268+class TexturedItem : public Item
3269+{
3270+public:
3271+ typedef std::shared_ptr<TexturedItem> Ptr;
3272+
3273+ void SetTexture(cu::SimpleTexture::Ptr const&);
3274+ void Draw(GLWindow*, GLMatrix const&, GLWindowPaintAttrib const&, CompRegion const&, unsigned mask);
3275+ void SetCoords(int x, int y);
3276+
3277+ int GetNaturalWidth() const;
3278+ int GetNaturalHeight() const;
3279+
3280+protected:
3281+ std::string GetName() const { return "TexturedItem"; }
3282+
3283+ CompRect& InternalGeo();
3284+ cu::SimpleTextureQuad texture_;
3285+};
3286+
3287+
3288+class BasicContainer : public SimpleItem
3289+{
3290+public:
3291+ typedef std::shared_ptr<BasicContainer> Ptr;
3292+
3293+ BasicContainer();
3294+ Item::List const& Items() const { return items_; }
3295+
3296+ virtual CompRect ContentGeometry() const;
3297+
3298+protected:
3299+ friend class Item;
3300+ virtual void Relayout() = 0;
3301+ bool IsContainer() const { return true; }
3302+
3303+ std::string GetName() const { return "BasicContainer"; }
3304+ void AddProperties(debug::IntrospectionData&);
3305+ IntrospectableList GetIntrospectableChildren();
3306+
3307+ Item::List items_;
3308+};
3309+
3310+
3311+class Layout : public std::enable_shared_from_this<Layout>, public BasicContainer
3312+{
3313+public:
3314+ typedef std::shared_ptr<Layout> Ptr;
3315+
3316+ Layout();
3317+
3318+ nux::Property<int> inner_padding;
3319+ nux::Property<int> left_padding;
3320+ nux::Property<int> right_padding;
3321+ nux::Property<int> top_padding;
3322+ nux::Property<int> bottom_padding;
3323+
3324+ void Append(Item::Ptr const&);
3325+ void Remove(Item::Ptr const&);
3326+
3327+ CompRect ContentGeometry() const;
3328+ void Draw(GLWindow*, GLMatrix const&, GLWindowPaintAttrib const&, CompRegion const&, unsigned mask);
3329+
3330+protected:
3331+ void Relayout();
3332+ std::string GetName() const { return "Layout"; }
3333+ void AddProperties(debug::IntrospectionData&);
3334+
3335+private:
3336+ bool SetPadding(int& target, int new_value);
3337+ bool relayouting_;
3338+};
3339+
3340+} // decoration namespace
3341+} // unity namespace
3342+
3343+#endif
3344
3345=== added file 'decorations/DecorationsWindowButton.cpp'
3346--- decorations/DecorationsWindowButton.cpp 1970-01-01 00:00:00 +0000
3347+++ decorations/DecorationsWindowButton.cpp 2014-01-23 15:21:26 +0000
3348@@ -0,0 +1,216 @@
3349+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
3350+/*
3351+ * Copyright (C) 2013 Canonical Ltd
3352+ *
3353+ * This program is free software: you can redistribute it and/or modify
3354+ * it under the terms of the GNU General Public License version 3 as
3355+ * published by the Free Software Foundation.
3356+ *
3357+ * This program is distributed in the hope that it will be useful,
3358+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3359+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3360+ * GNU General Public License for more details.
3361+ *
3362+ * You should have received a copy of the GNU General Public License
3363+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3364+ *
3365+ * Authored by: Marco Trevisan <marco.trevisan@canonical.com>
3366+ */
3367+
3368+#include <sigc++/adaptors/hide.h>
3369+#include "DecorationsWindowButton.h"
3370+#include "DecorationsDataPool.h"
3371+
3372+namespace unity
3373+{
3374+namespace decoration
3375+{
3376+
3377+WindowButton::WindowButton(CompWindow* win, WindowButtonType type)
3378+ : type_(type)
3379+ , pressed_(false)
3380+ , was_pressed_(false)
3381+ , win_(win)
3382+{
3383+ auto cb = sigc::hide(sigc::mem_fun(this, &WindowButton::UpdateTexture));
3384+ mouse_owner.changed.connect(cb);
3385+ focused.changed.connect(cb);
3386+ UpdateTexture();
3387+}
3388+
3389+void WindowButton::UpdateTexture()
3390+{
3391+ SetTexture(DataPool::Get()->ButtonTexture(type_, GetCurrentState()));
3392+}
3393+
3394+WidgetState WindowButton::GetCurrentState() const
3395+{
3396+ if (focused())
3397+ {
3398+ if (mouse_owner() && pressed_)
3399+ {
3400+ return WidgetState::PRESSED;
3401+ }
3402+ else if (mouse_owner() && !was_pressed_)
3403+ {
3404+ return WidgetState::PRELIGHT;
3405+ }
3406+ else
3407+ {
3408+ return WidgetState::NORMAL;
3409+ }
3410+ }
3411+ else
3412+ {
3413+ if (mouse_owner() && pressed_)
3414+ {
3415+ return WidgetState::BACKDROP_PRESSED;
3416+ }
3417+ else if (mouse_owner() && !was_pressed_)
3418+ {
3419+ return WidgetState::BACKDROP_PRELIGHT;
3420+ }
3421+ else
3422+ {
3423+ return WidgetState::BACKDROP;
3424+ }
3425+ }
3426+}
3427+
3428+void WindowButton::ButtonDownEvent(CompPoint const& p, unsigned button)
3429+{
3430+ if (!pressed_ && button <= Button3)
3431+ {
3432+ pressed_ = true;
3433+ was_pressed_ = true;
3434+ UpdateTexture();
3435+ }
3436+}
3437+
3438+void WindowButton::ButtonUpEvent(CompPoint const& p, unsigned button)
3439+{
3440+ if (pressed_ && button <= Button3)
3441+ {
3442+ pressed_ = false;
3443+ UpdateTexture();
3444+
3445+ switch (type_)
3446+ {
3447+ case WindowButtonType::CLOSE:
3448+ if (win_->actions() & CompWindowActionCloseMask)
3449+ win_->close(screen->getCurrentTime());
3450+ break;
3451+ case WindowButtonType::MINIMIZE:
3452+ if (win_->actions() & CompWindowActionMinimizeMask)
3453+ win_->minimize();
3454+ break;
3455+ case WindowButtonType::MAXIMIZE:
3456+ switch (button)
3457+ {
3458+ case Button1:
3459+ if ((win_->state() & CompWindowStateMaximizedVertMask) ||
3460+ (win_->state() & CompWindowStateMaximizedHorzMask))
3461+ win_->maximize(0);
3462+ else if (win_->actions() & (CompWindowActionMaximizeHorzMask|CompWindowActionMaximizeVertMask))
3463+ win_->maximize(MAXIMIZE_STATE);
3464+ break;
3465+ case Button2:
3466+ if (win_->actions() & CompWindowActionMaximizeVertMask)
3467+ {
3468+ if (!(win_->state() & CompWindowStateMaximizedVertMask))
3469+ win_->maximize(CompWindowStateMaximizedVertMask);
3470+ else
3471+ win_->maximize(0);
3472+ }
3473+ break;
3474+ case Button3:
3475+ if (win_->actions() & CompWindowActionMaximizeHorzMask)
3476+ {
3477+ if (!(win_->state() & CompWindowStateMaximizedHorzMask))
3478+ win_->maximize(CompWindowStateMaximizedHorzMask);
3479+ else
3480+ win_->maximize(0);
3481+ }
3482+ break;
3483+ }
3484+ break;
3485+ default:
3486+ break;
3487+ }
3488+ }
3489+
3490+ was_pressed_ = false;
3491+}
3492+
3493+void WindowButton::MotionEvent(CompPoint const& p)
3494+{
3495+ if (pressed_)
3496+ {
3497+ if (!Geometry().contains(p))
3498+ {
3499+ pressed_ = false;
3500+ UpdateTexture();
3501+ }
3502+ }
3503+ else if (was_pressed_)
3504+ {
3505+ if (Geometry().contains(p))
3506+ {
3507+ pressed_ = true;
3508+ UpdateTexture();
3509+ }
3510+ }
3511+}
3512+
3513+std::string WindowButton::GetName() const
3514+{
3515+ switch (type_)
3516+ {
3517+ case WindowButtonType::CLOSE:
3518+ return "CloseWindowButton";
3519+ case WindowButtonType::MINIMIZE:
3520+ return "MinimizeWindowButton";
3521+ case WindowButtonType::MAXIMIZE:
3522+ return "MaximizeWindowButton";
3523+ case WindowButtonType::UNMAXIMIZE:
3524+ return "UnmaximizeWindowButton";
3525+ default:
3526+ return "WindowButton";
3527+ }
3528+}
3529+
3530+void WindowButton::AddProperties(debug::IntrospectionData& data)
3531+{
3532+ TexturedItem::AddProperties(data);
3533+ data.add("pressed", pressed_);
3534+
3535+ switch(GetCurrentState())
3536+ {
3537+ case WidgetState::NORMAL:
3538+ data.add("state", "normal");
3539+ break;
3540+ case WidgetState::PRELIGHT:
3541+ data.add("state", "prelight");
3542+ break;
3543+ case WidgetState::PRESSED:
3544+ data.add("state", "pressed");
3545+ break;
3546+ case WidgetState::DISABLED:
3547+ data.add("state", "disabled");
3548+ break;
3549+ case WidgetState::BACKDROP:
3550+ data.add("state", "backdrop");
3551+ break;
3552+ case WidgetState::BACKDROP_PRELIGHT:
3553+ data.add("state", "backdrop_prelight");
3554+ break;
3555+ case WidgetState::BACKDROP_PRESSED:
3556+ data.add("state", "backdrop_pressed");
3557+ break;
3558+ default:
3559+ data.add("state", "unknown");
3560+ }
3561+}
3562+
3563+} // decoration namespace
3564+} // unity namespace
3565
3566=== added file 'decorations/DecorationsWindowButton.h'
3567--- decorations/DecorationsWindowButton.h 1970-01-01 00:00:00 +0000
3568+++ decorations/DecorationsWindowButton.h 2014-01-23 15:21:26 +0000
3569@@ -0,0 +1,58 @@
3570+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
3571+/*
3572+ * Copyright (C) 2013 Canonical Ltd
3573+ *
3574+ * This program is free software: you can redistribute it and/or modify
3575+ * it under the terms of the GNU General Public License version 3 as
3576+ * published by the Free Software Foundation.
3577+ *
3578+ * This program is distributed in the hope that it will be useful,
3579+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3580+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3581+ * GNU General Public License for more details.
3582+ *
3583+ * You should have received a copy of the GNU General Public License
3584+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3585+ *
3586+ * Authored by: Marco Trevisan <marco.trevisan@canonical.com>
3587+ */
3588+
3589+#ifndef UNITY_DECORATION_WINDOW_BUTTON
3590+#define UNITY_DECORATION_WINDOW_BUTTON
3591+
3592+#include "DecorationStyle.h"
3593+#include "DecorationsWidgets.h"
3594+
3595+namespace unity
3596+{
3597+namespace decoration
3598+{
3599+
3600+class WindowButton : public TexturedItem
3601+{
3602+public:
3603+ WindowButton(CompWindow*, WindowButtonType type);
3604+
3605+ WidgetState GetCurrentState() const;
3606+
3607+protected:
3608+ void ButtonDownEvent(CompPoint const&, unsigned button);
3609+ void ButtonUpEvent(CompPoint const&, unsigned button);
3610+ void MotionEvent(CompPoint const&);
3611+
3612+ std::string GetName() const;
3613+ void AddProperties(debug::IntrospectionData&);
3614+
3615+private:
3616+ void UpdateTexture();
3617+
3618+ WindowButtonType type_;
3619+ bool pressed_;
3620+ bool was_pressed_;
3621+ CompWindow* win_;
3622+};
3623+
3624+} // decoration namespace
3625+} // unity namespace
3626+
3627+#endif // UNITY_DECORATION_WINDOW_BUTTON
3628
3629=== renamed file 'plugins/unityshell/src/glow_texture.h' => 'decorations/glow_texture.h'
3630=== added directory 'decorations/pch'
3631=== added file 'decorations/pch/decorations_pch.hh'
3632--- decorations/pch/decorations_pch.hh 1970-01-01 00:00:00 +0000
3633+++ decorations/pch/decorations_pch.hh 2014-01-23 15:21:26 +0000
3634@@ -0,0 +1,39 @@
3635+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
3636+/*
3637+ * Copyright (C) 2013 Canonical Ltd
3638+ *
3639+ * This program is free software: you can redistribute it and/or modify
3640+ * it under the terms of the GNU General Public License version 3 as
3641+ * published by the Free Software Foundation.
3642+ *
3643+ * This program is distributed in the hope that it will be useful,
3644+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3645+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3646+ * GNU General Public License for more details.
3647+ *
3648+ * You should have received a copy of the GNU General Public License
3649+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3650+ *
3651+ * Authored by: Marco Trevisan <marco.trevisan@canonical.com>
3652+ */
3653+
3654+/*
3655+ * These are the precompiled header includes for this module.
3656+ * Only system header files can be listed here.
3657+ */
3658+
3659+#include <deque>
3660+#include <memory>
3661+#include <unordered_map>
3662+
3663+#include <sigc++/sigc++.h>
3664+#include <cairo/cairo.h>
3665+
3666+#include <core/core.h>
3667+#include <opengl/opengl.h>
3668+#include <composite/composite.h>
3669+
3670+#include <NuxCore/NuxCore.h>
3671+#include <NuxCore/Property.h>
3672+#include <NuxCore/Rect.h>
3673+#include <NuxCore/Size.h>
3674
3675=== modified file 'panel/PanelMenuView.cpp'
3676--- panel/PanelMenuView.cpp 2013-11-19 18:48:35 +0000
3677+++ panel/PanelMenuView.cpp 2014-01-23 15:21:26 +0000
3678@@ -24,6 +24,7 @@
3679 #include "PanelMenuView.h"
3680 #include "unity-shared/AnimationUtils.h"
3681 #include "unity-shared/CairoTexture.h"
3682+#include "unity-shared/DecorationStyle.h"
3683 #include "unity-shared/PanelStyle.h"
3684 #include "unity-shared/UnitySettings.h"
3685 #include "unity-shared/UBusMessages.h"
3686@@ -98,8 +99,8 @@
3687
3688 opacity = 0.0f;
3689
3690- Refresh();
3691- FullRedraw();
3692+ if (Refresh())
3693+ FullRedraw();
3694 }
3695
3696 PanelMenuView::~PanelMenuView()
3697@@ -179,8 +180,6 @@
3698 wm.window_mapped.connect(sigc::mem_fun(this, &PanelMenuView::OnWindowMapped));
3699 wm.window_moved.connect(sigc::mem_fun(this, &PanelMenuView::OnWindowMoved));
3700 wm.window_resized.connect(sigc::mem_fun(this, &PanelMenuView::OnWindowMoved));
3701- wm.window_decorated.connect(sigc::mem_fun(this, &PanelMenuView::OnWindowDecorated));
3702- wm.window_undecorated.connect(sigc::mem_fun(this, &PanelMenuView::OnWindowUndecorated));
3703 wm.initiate_spread.connect(sigc::mem_fun(this, &PanelMenuView::OnSpreadInitiate));
3704 wm.terminate_spread.connect(sigc::mem_fun(this, &PanelMenuView::OnSpreadTerminate));
3705 wm.initiate_expo.connect(sigc::mem_fun(this, &PanelMenuView::OnExpoInitiate));
3706@@ -334,15 +333,17 @@
3707
3708 bool PanelMenuView::ShouldDrawMenus() const
3709 {
3710- WindowManager& wm = WindowManager::Default();
3711- bool screen_grabbed = (wm.IsExpoActive() || wm.IsScaleActive());
3712-
3713- if (we_control_active_ && !screen_grabbed &&
3714- !switcher_showing_ && !launcher_keynav_ && !entries_.empty())
3715+ if (we_control_active_ && !switcher_showing_ && !launcher_keynav_ && !entries_.empty())
3716 {
3717- if (is_inside_ || last_active_view_ || show_now_activated_ || new_application_)
3718+ WindowManager& wm = WindowManager::Default();
3719+
3720+ if (!wm.IsExpoActive() && !wm.IsScaleActive())
3721 {
3722- return true;
3723+ if (is_inside_ || last_active_view_ || show_now_activated_ || new_application_)
3724+ return true;
3725+
3726+ if (is_maximized_)
3727+ return (window_buttons_->IsMouseOwner() || titlebar_grab_area_->IsMouseOwner());
3728 }
3729 }
3730
3731@@ -351,15 +352,17 @@
3732
3733 bool PanelMenuView::ShouldDrawButtons() const
3734 {
3735- WindowManager& wm = WindowManager::Default();
3736- bool screen_grabbed = (wm.IsExpoActive() || wm.IsScaleActive());
3737-
3738- if (we_control_active_ && is_maximized_ && !screen_grabbed &&
3739- !launcher_keynav_ && !switcher_showing_)
3740+ if (we_control_active_ && is_maximized_ && !launcher_keynav_ && !switcher_showing_)
3741 {
3742- if (is_inside_ || show_now_activated_ || new_application_)
3743+ WindowManager& wm = WindowManager::Default();
3744+
3745+ if (!wm.IsExpoActive() && !wm.IsScaleActive())
3746 {
3747- return true;
3748+ if (is_inside_ || show_now_activated_ || new_application_)
3749+ return true;
3750+
3751+ if (window_buttons_->IsMouseOwner() || titlebar_grab_area_->IsMouseOwner())
3752+ return true;
3753 }
3754 }
3755
3756@@ -709,84 +712,17 @@
3757 return label;
3758 }
3759
3760-void PanelMenuView::UpdateTitleTexture(cairo_t *cr_real, nux::Geometry const& geo, std::string const& label) const
3761+void PanelMenuView::UpdateTitleTexture(cairo_t *cr, nux::Geometry const& geo, std::string const& label) const
3762 {
3763- using namespace panel;
3764- cairo_t* cr;
3765+ using namespace decoration;
3766+ auto const& style = Style::Get();
3767+ auto text_size = style->TitleNaturalSize(label);
3768 int x = MAIN_LEFT_PADDING + TITLE_PADDING + geo.x;
3769- int y = geo.y;
3770-
3771- int text_width = 0;
3772- int text_height = 0;
3773- int text_space = 0;
3774-
3775- // Find out dimensions first
3776- GdkScreen* screen = gdk_screen_get_default();
3777- PangoContext* cxt;
3778- PangoRectangle log_rect;
3779- PangoFontDescription* desc;
3780-
3781- nux::CairoGraphics util_cg(CAIRO_FORMAT_ARGB32, 1, 1);
3782- cr = util_cg.GetInternalContext();
3783-
3784- int dpi = Style::Instance().GetTextDPI();
3785-
3786- std::string font_description(Style::Instance().GetFontDescription(PanelItem::TITLE));
3787- desc = pango_font_description_from_string(font_description.c_str());
3788-
3789- glib::Object<PangoLayout> layout(pango_cairo_create_layout(cr));
3790- pango_layout_set_font_description(layout, desc);
3791- pango_layout_set_markup(layout, label.c_str(), -1);
3792-
3793- cxt = pango_layout_get_context(layout);
3794- pango_cairo_context_set_font_options(cxt, gdk_screen_get_font_options(screen));
3795- pango_cairo_context_set_resolution(cxt, dpi / static_cast<float>(PANGO_SCALE));
3796- pango_layout_context_changed(layout);
3797-
3798- pango_layout_get_extents(layout, nullptr, &log_rect);
3799- text_width = log_rect.width / PANGO_SCALE;
3800- text_height = log_rect.height / PANGO_SCALE;
3801-
3802- pango_font_description_free(desc);
3803-
3804- // Draw the text
3805- GtkStyleContext* style_context = Style::Instance().GetStyleContext();
3806- text_space = geo.width - x;
3807- cr = cr_real;
3808- cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
3809-
3810- gtk_style_context_save(style_context);
3811- gtk_style_context_add_class(style_context, GTK_STYLE_CLASS_MENUBAR);
3812- gtk_style_context_add_class(style_context, GTK_STYLE_CLASS_MENUITEM);
3813-
3814- y += (geo.height - text_height) / 2;
3815-
3816- pango_cairo_update_layout(cr, layout);
3817-
3818- if (text_width > text_space)
3819- {
3820- cairo_pattern_t* linpat;
3821- int out_pixels = text_width - text_space;
3822- const int fading_pixels = 35;
3823- int fading_width = out_pixels < fading_pixels ? out_pixels : fading_pixels;
3824-
3825- cairo_push_group(cr);
3826- gtk_render_layout(style_context, cr, x, y, layout);
3827- cairo_pop_group_to_source(cr);
3828-
3829- linpat = cairo_pattern_create_linear(geo.width - fading_width, y, geo.width, y);
3830- cairo_pattern_add_color_stop_rgba(linpat, 0, 0, 0, 0, 1);
3831- cairo_pattern_add_color_stop_rgba(linpat, 1, 0, 0, 0, 0);
3832- cairo_mask(cr, linpat);
3833-
3834- cairo_pattern_destroy(linpat);
3835- }
3836- else
3837- {
3838- gtk_render_layout(style_context, cr, x, y, layout);
3839- }
3840-
3841- gtk_style_context_restore(style_context);
3842+
3843+ cairo_save(cr);
3844+ cairo_translate(cr, x, geo.y + (geo.height - text_size.height) / 2);
3845+ style->DrawTitle(label, WidgetState::NORMAL, cr, geo.width - x, geo.height);
3846+ cairo_restore(cr);
3847 }
3848
3849 std::string PanelMenuView::GetCurrentTitle() const
3850@@ -809,7 +745,7 @@
3851 }
3852 else if (!we_control_active_)
3853 {
3854- new_title = "";
3855+ new_title.clear();
3856 }
3857 else
3858 {
3859@@ -829,40 +765,36 @@
3860 }
3861 }
3862
3863-void PanelMenuView::Refresh(bool force)
3864+bool PanelMenuView::Refresh(bool force)
3865 {
3866 nux::Geometry const& geo = GetGeometry();
3867
3868 // We can get into a race that causes the geometry to be wrong as there hasn't been a
3869 // layout cycle before the first callback. This is to protect from that.
3870 if (geo.width > monitor_geo_.width)
3871- return;
3872+ return false;
3873
3874 const std::string& new_title = GetCurrentTitle();
3875 if (new_title == panel_title_ && !force && last_geo_ == geo && title_texture_)
3876 {
3877 // No need to redraw the title, let's save some CPU time!
3878- return;
3879+ return false;
3880 }
3881+
3882 panel_title_ = new_title;
3883
3884 if (panel_title_.empty())
3885 {
3886 title_texture_ = nullptr;
3887- return;
3888+ return true;
3889 }
3890
3891 nux::CairoGraphics cairo_graphics(CAIRO_FORMAT_ARGB32, geo.width, geo.height);
3892- cairo_t* cr = cairo_graphics.GetContext();
3893-
3894- cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
3895- cairo_paint(cr);
3896-
3897+ cairo_t* cr = cairo_graphics.GetInternalContext();
3898 UpdateTitleTexture(cr, geo, panel_title_);
3899-
3900- cairo_destroy(cr);
3901-
3902 title_texture_ = texture_ptr_from_cairo_graphics(cairo_graphics);
3903+
3904+ return true;
3905 }
3906
3907 void PanelMenuView::OnActiveChanged(PanelIndicatorEntryView* view, bool is_active)
3908@@ -879,8 +811,8 @@
3909 }
3910 }
3911
3912- Refresh();
3913- FullRedraw();
3914+ if (Refresh())
3915+ FullRedraw();
3916 }
3917
3918 void PanelMenuView::OnEntryAdded(indicator::Entry::Ptr const& entry)
3919@@ -908,8 +840,8 @@
3920
3921 void PanelMenuView::OnNameChanged(BamfView* bamf_view, gchar* new_name, gchar* old_name)
3922 {
3923- Refresh();
3924- FullRedraw();
3925+ if (Refresh())
3926+ FullRedraw();
3927 }
3928
3929 bool PanelMenuView::OnNewAppShow()
3930@@ -1032,9 +964,7 @@
3931 }
3932 }
3933
3934-void PanelMenuView::OnActiveWindowChanged(BamfMatcher *matcher,
3935- BamfView* old_view,
3936- BamfView* new_view)
3937+void PanelMenuView::OnActiveWindowChanged(BamfMatcher *matcher, BamfView* old_view, BamfView* new_view)
3938 {
3939 show_now_activated_ = false;
3940 is_maximized_ = false;
3941@@ -1044,30 +974,17 @@
3942
3943 if (BAMF_IS_WINDOW(new_view))
3944 {
3945- WindowManager& wm = WindowManager::Default();
3946 BamfWindow* window = reinterpret_cast<BamfWindow*>(new_view);
3947- guint32 xid = bamf_window_get_xid(window);
3948- active_xid_ = xid;
3949- is_maximized_ = wm.IsWindowMaximized(xid);
3950+ active_xid_ = bamf_window_get_xid(window);
3951+ is_maximized_ = (bamf_window_maximized(window) == BAMF_WINDOW_MAXIMIZED);
3952
3953 if (bamf_window_get_window_type(window) == BAMF_WINDOW_DESKTOP)
3954 we_control_active_ = true;
3955 else
3956- we_control_active_ = IsWindowUnderOurControl(xid);
3957-
3958- if (decor_map_.find(xid) == decor_map_.end())
3959- {
3960- decor_map_[xid] = true;
3961-
3962- // if we've just started tracking this window and it is maximized, let's
3963- // make sure it's undecorated just in case it slipped by us earlier
3964- // (I'm looking at you, Chromium!)
3965- if (is_maximized_ && wm.HasWindowDecorations(xid))
3966- {
3967- wm.Undecorate(xid);
3968- maximized_set_.insert(xid);
3969- }
3970- }
3971+ we_control_active_ = IsWindowUnderOurControl(active_xid_);
3972+
3973+ if (is_maximized_)
3974+ maximized_set_.insert(active_xid_);
3975
3976 // first see if we need to remove and old callback
3977 view_name_changed_signal_.Disconnect();
3978@@ -1078,152 +995,112 @@
3979 window_buttons_->controlled_window = (is_maximized_) ? active_xid_ : 0;
3980 }
3981
3982- Refresh();
3983- FullRedraw();
3984+ if (Refresh())
3985+ FullRedraw();
3986 }
3987
3988 void PanelMenuView::OnSpreadInitiate()
3989 {
3990- Refresh();
3991- QueueDraw();
3992+ if (Refresh())
3993+ QueueDraw();
3994 }
3995
3996 void PanelMenuView::OnSpreadTerminate()
3997 {
3998- Refresh();
3999- QueueDraw();
4000+ if (Refresh())
4001+ QueueDraw();
4002 }
4003
4004 void PanelMenuView::OnExpoInitiate()
4005 {
4006- Refresh();
4007- QueueDraw();
4008+ if (Refresh())
4009+ QueueDraw();
4010 }
4011
4012 void PanelMenuView::OnExpoTerminate()
4013 {
4014- Refresh();
4015- QueueDraw();
4016-}
4017-
4018-void PanelMenuView::OnWindowMinimized(guint32 xid)
4019-{
4020- WindowManager& wm = WindowManager::Default();
4021- if (wm.IsWindowMaximized(xid))
4022- {
4023- wm.Decorate(xid);
4024- maximized_set_.erase(xid);
4025-
4026- Refresh();
4027+ if (Refresh())
4028 QueueDraw();
4029+}
4030+
4031+void PanelMenuView::OnWindowMinimized(Window xid)
4032+{
4033+ maximized_set_.erase(xid);
4034+
4035+ if (xid == active_xid_)
4036+ {
4037+ if (Refresh())
4038+ QueueDraw();
4039 }
4040 }
4041
4042-void PanelMenuView::OnWindowUnminimized(guint32 xid)
4043+void PanelMenuView::OnWindowUnminimized(Window xid)
4044 {
4045- WindowManager& wm = WindowManager::Default();
4046- if (wm.IsWindowMaximized(xid))
4047- {
4048- wm.Undecorate(xid);
4049+ if (WindowManager::Default().IsWindowMaximized(xid))
4050 maximized_set_.insert(xid);
4051
4052- Refresh();
4053- QueueDraw();
4054+ if (xid == active_xid_)
4055+ {
4056+ if (Refresh())
4057+ QueueDraw();
4058 }
4059 }
4060
4061-void PanelMenuView::OnWindowUnmapped(guint32 xid)
4062+void PanelMenuView::OnWindowUnmapped(Window xid)
4063 {
4064 // FIXME: compiz doesn't give us a valid xid (is always 0 on unmap)
4065 // we need to do this again on BamfView closed signal.
4066- if (maximized_set_.find(xid) != maximized_set_.end())
4067+ maximized_set_.erase(xid);
4068+
4069+ if (xid == active_xid_)
4070 {
4071- WindowManager::Default().Decorate(xid);
4072- maximized_set_.erase(xid);
4073- decor_map_.erase(xid);
4074-
4075- Refresh();
4076- QueueDraw();
4077+ if (Refresh())
4078+ QueueDraw();
4079 }
4080 }
4081
4082-void PanelMenuView::OnWindowMapped(guint32 xid)
4083+void PanelMenuView::OnWindowMapped(Window xid)
4084 {
4085- WindowManager& wm = WindowManager::Default();
4086- if (wm.IsWindowMaximized(xid))
4087+ if (WindowManager::Default().IsWindowMaximized(xid))
4088 {
4089- wm.Undecorate(xid);
4090 maximized_set_.insert(xid);
4091
4092- Refresh();
4093- QueueDraw();
4094- }
4095-}
4096-
4097-void PanelMenuView::OnWindowDecorated(guint32 xid)
4098-{
4099- decor_map_[xid] = true;
4100-
4101- if (maximized_set_.find(xid) != maximized_set_.end ())
4102- {
4103- WindowManager::Default().Undecorate(xid);
4104- }
4105-}
4106-
4107-void PanelMenuView::OnWindowUndecorated(guint32 xid)
4108-{
4109- decor_map_[xid] = false;
4110-}
4111-
4112-void PanelMenuView::OnWindowMaximized(guint xid)
4113-{
4114- bool updated = false;
4115- bool is_active = (active_xid_ == xid);
4116-
4117- if (is_active)
4118+ if (xid == active_xid_)
4119+ {
4120+ if (Refresh())
4121+ QueueDraw();
4122+ }
4123+ }
4124+}
4125+
4126+void PanelMenuView::OnWindowMaximized(Window xid)
4127+{
4128+ maximized_set_.insert(xid);
4129+
4130+ if (xid == active_xid_)
4131 {
4132 // We need to update the is_inside_ state in the case of maximization by grab
4133 auto mouse = nux::GetGraphicsDisplay()->GetMouseScreenCoord();
4134 is_inside_ = GetAbsoluteGeometry().IsInside(mouse);
4135-
4136 is_maximized_ = true;
4137- updated = true;
4138- }
4139-
4140- // update the state of the window in the decor_map_
4141- WindowManager& wm = WindowManager::Default();
4142- decor_map_[xid] = wm.HasWindowDecorations(xid);
4143-
4144- if (decor_map_[xid])
4145- wm.Undecorate(xid);
4146-
4147- maximized_set_.insert(xid);
4148-
4149- if (updated)
4150- {
4151- Refresh();
4152- FullRedraw();
4153+
4154+ if (Refresh())
4155+ FullRedraw();
4156 }
4157 }
4158
4159-void PanelMenuView::OnWindowRestored(guint xid)
4160+void PanelMenuView::OnWindowRestored(Window xid)
4161 {
4162- if (maximized_set_.find(xid) == maximized_set_.end())
4163- return;
4164+ maximized_set_.erase(xid);
4165
4166 if (active_xid_ == xid)
4167 {
4168 is_maximized_ = false;
4169 is_grabbed_ = false;
4170+
4171+ if (Refresh())
4172+ FullRedraw();
4173 }
4174-
4175- if (decor_map_[xid])
4176- WindowManager::Default().Decorate(xid);
4177-
4178- maximized_set_.erase(xid);
4179-
4180- Refresh();
4181- FullRedraw();
4182 }
4183
4184 bool PanelMenuView::UpdateActiveWindowPosition()
4185@@ -1234,14 +1111,14 @@
4186 {
4187 we_control_active_ = we_control_window;
4188
4189- Refresh();
4190- QueueDraw();
4191+ if (Refresh())
4192+ QueueDraw();
4193 }
4194
4195 return false;
4196 }
4197
4198-void PanelMenuView::OnWindowMoved(guint xid)
4199+void PanelMenuView::OnWindowMoved(Window xid)
4200 {
4201 if (active_xid_ == xid)
4202 {
4203@@ -1468,8 +1345,8 @@
4204
4205 is_inside_ = true;
4206 is_grabbed_ = true;
4207- Refresh();
4208- FullRedraw();
4209+ if (Refresh())
4210+ FullRedraw();
4211
4212 /* Ungrab the pointer and start the X move, to make the decorator handle it */
4213 titlebar_grab_area_->SetGrabbed(false);
4214@@ -1489,8 +1366,8 @@
4215 if (!is_inside_)
4216 is_grabbed_ = false;
4217
4218- Refresh();
4219- FullRedraw();
4220+ if (Refresh())
4221+ FullRedraw();
4222 }
4223
4224 // Introspectable
4225@@ -1546,8 +1423,8 @@
4226 show_now_activated_ = false;
4227 }
4228
4229- Refresh();
4230- QueueDraw();
4231+ if (Refresh())
4232+ QueueDraw();
4233 }
4234
4235 void PanelMenuView::OnLauncherKeyNavStarted(GVariant* data)
4236@@ -1572,8 +1449,8 @@
4237 auto mouse = nux::GetGraphicsDisplay()->GetMouseScreenCoord();
4238 is_inside_ = GetAbsoluteGeometry().IsInside(mouse);
4239
4240- Refresh();
4241- QueueDraw();
4242+ if (Refresh())
4243+ QueueDraw();
4244 }
4245
4246 void PanelMenuView::OnLauncherSelectionChanged(GVariant* data)
4247@@ -1642,7 +1519,6 @@
4248 maximized_set_.clear();
4249 GList* windows = bamf_matcher_get_window_stack_for_monitor(matcher_, monitor_);
4250
4251- WindowManager& wm = WindowManager::Default();
4252 for (GList* l = windows; l; l = l->next)
4253 {
4254 if (!BAMF_IS_WINDOW(l->data))
4255@@ -1652,21 +1528,10 @@
4256 auto view = static_cast<BamfView*>(l->data);
4257
4258 if (bamf_view_is_active(view))
4259- {
4260 active_xid_ = bamf_window_get_xid(window);
4261- }
4262
4263 if (bamf_window_maximized(window) == BAMF_WINDOW_MAXIMIZED)
4264- {
4265- Window xid = bamf_window_get_xid(window);
4266-
4267- decor_map_[xid] = wm.HasWindowDecorations(xid);
4268-
4269- if (decor_map_[xid])
4270- wm.Undecorate(xid);
4271-
4272- maximized_set_.insert(xid);
4273- }
4274+ maximized_set_.insert(bamf_window_get_xid(window));
4275 }
4276
4277 Window maximized = GetMaximizedWindow();
4278@@ -1705,9 +1570,6 @@
4279 }
4280 }
4281
4282-void PanelMenuView::OnPanelViewMouseMove(int x, int y, int dx, int dy, unsigned long mouse_button_state, unsigned long special_keys_state)
4283-{}
4284-
4285 void PanelMenuView::SetMousePosition(int x, int y)
4286 {
4287 if (last_active_view_ ||
4288
4289=== modified file 'panel/PanelMenuView.h'
4290--- panel/PanelMenuView.h 2013-09-19 16:44:03 +0000
4291+++ panel/PanelMenuView.h 2014-01-23 15:21:26 +0000
4292@@ -92,15 +92,13 @@
4293 void OnSpreadTerminate();
4294 void OnExpoInitiate();
4295 void OnExpoTerminate();
4296- void OnWindowMinimized(guint32 xid);
4297- void OnWindowUnminimized(guint32 xid);
4298- void OnWindowUnmapped(guint32 xid);
4299- void OnWindowMapped(guint32 xid);
4300- void OnWindowMaximized(guint32 xid);
4301- void OnWindowRestored(guint32 xid);
4302- void OnWindowMoved(guint32 xid);
4303- void OnWindowDecorated(guint32 xid);
4304- void OnWindowUndecorated(guint32 xid);
4305+ void OnWindowMinimized(Window xid);
4306+ void OnWindowUnminimized(Window xid);
4307+ void OnWindowUnmapped(Window xid);
4308+ void OnWindowMapped(Window xid);
4309+ void OnWindowMaximized(Window xid);
4310+ void OnWindowRestored(Window xid);
4311+ void OnWindowMoved(Window xid);
4312
4313 void OnMaximizedActivate(int x, int y);
4314 void OnMaximizedRestore(int x, int y);
4315@@ -111,7 +109,7 @@
4316
4317 void FullRedraw();
4318 std::string GetCurrentTitle() const;
4319- void Refresh(bool force = false);
4320+ bool Refresh(bool force = false);
4321
4322 void UpdateTitleTexture(cairo_t *cr_real, nux::Geometry const& geo, std::string const& label) const;
4323
4324@@ -120,7 +118,6 @@
4325
4326 void OnPanelViewMouseEnter(int x, int y, unsigned long mouse_button_state, unsigned long special_keys_state);
4327 void OnPanelViewMouseLeave(int x, int y, unsigned long mouse_button_state, unsigned long special_keys_state);
4328- void OnPanelViewMouseMove(int x, int y, int dx, int dy, unsigned long mouse_button_state, unsigned long special_keys_state);
4329
4330 BamfWindow* GetBamfWindowForXid(Window xid) const;
4331
4332@@ -163,10 +160,8 @@
4333 bool is_maximized_;
4334
4335 PanelIndicatorEntryView* last_active_view_;
4336+ std::set<Window> maximized_set_;
4337 glib::Object<BamfApplication> new_application_;
4338-
4339- std::map<Window, bool> decor_map_;
4340- std::set<Window> maximized_set_;
4341 std::list<glib::Object<BamfApplication>> new_apps_;
4342 std::string panel_title_;
4343 nux::Geometry last_geo_;
4344
4345=== modified file 'plugins/unityshell/CMakeLists.txt'
4346--- plugins/unityshell/CMakeLists.txt 2013-02-13 02:09:35 +0000
4347+++ plugins/unityshell/CMakeLists.txt 2014-01-23 15:21:26 +0000
4348@@ -21,8 +21,33 @@
4349 set (CMAKE_BUILD_TYPE "" CACHE STRING "Build type (Debug/Release/RelWithDebInfo/MinSizeRe)" FORCE)
4350 endif()
4351
4352-add_dependencies(unityshell unity-core-${UNITY_API_VERSION} dash-lib launcher-lib switcher-lib hud-lib panel-lib shortcuts-lib shutdown-lib unity-shared unity-shared-compiz)
4353-target_link_libraries(unityshell unity-core-${UNITY_API_VERSION} launcher-lib dash-lib switcher-lib hud-lib panel-lib shortcuts-lib shutdown-lib unity-shared unity-shared-bamf unity-shared-compiz)
4354+add_dependencies(unityshell
4355+ dash-lib
4356+ decorations-lib
4357+ hud-lib
4358+ launcher-lib
4359+ panel-lib
4360+ shortcuts-lib
4361+ shutdown-lib
4362+ switcher-lib
4363+ unity-core-${UNITY_API_VERSION}
4364+ unity-shared
4365+ unity-shared-compiz)
4366+
4367+target_link_libraries(unityshell
4368+ dash-lib
4369+ decorations-lib
4370+ hud-lib
4371+ launcher-lib
4372+ panel-lib
4373+ shortcuts-lib
4374+ shutdown-lib
4375+ switcher-lib
4376+ unity-core-${UNITY_API_VERSION}
4377+ unity-shared
4378+ unity-shared-bamf
4379+ unity-shared-compiz)
4380+
4381 set_target_properties(unityshell
4382 PROPERTIES INSTALL_RPATH "${CACHED_UNITY_PRIVATE_DEPS_LIBRARY_DIRS}"
4383 INSTALL_RPATH_USE_LINK_PATH TRUE)
4384
4385=== modified file 'plugins/unityshell/src/unityshell.cpp'
4386--- plugins/unityshell/src/unityshell.cpp 2014-01-14 16:07:59 +0000
4387+++ plugins/unityshell/src/unityshell.cpp 2014-01-23 15:21:26 +0000
4388@@ -28,6 +28,7 @@
4389 #include <UnityCore/ScopeProxyInterface.h>
4390 #include <UnityCore/GnomeSessionManager.h>
4391
4392+#include "CompizUtils.h"
4393 #include "BaseWindowRaiserImp.h"
4394 #include "IconRenderer.h"
4395 #include "Launcher.h"
4396@@ -41,7 +42,6 @@
4397 #include "StartupNotifyService.h"
4398 #include "Timer.h"
4399 #include "XKeyboardUtil.h"
4400-#include "glow_texture.h"
4401 #include "unityshell.h"
4402 #include "BackgroundEffectHelper.h"
4403 #include "UnityGestureBroker.h"
4404@@ -51,6 +51,9 @@
4405 #include "launcher/XdndStartStopNotifierImp.h"
4406 #include "CompizShortcutModeller.h"
4407
4408+#include "decorations/DecorationsDataPool.h"
4409+#include "decorations/DecorationsManager.h"
4410+
4411 #include <glib/gi18n-lib.h>
4412 #include <gtk/gtk.h>
4413 #include <gdk/gdk.h>
4414@@ -119,6 +122,11 @@
4415 return nux::Geometry(rect.x(), rect.y(), rect.width(), rect.height());
4416 }
4417
4418+inline nux::Color NuxColorFromCompizColor(unsigned short * color)
4419+{
4420+ return nux::Color(color[0]/65535.0f, color[1]/65535.0f, color[2]/65535.0f, color[3]/65535.0f);
4421+}
4422+
4423 namespace local
4424 {
4425 // Tap duration in milliseconds.
4426@@ -131,18 +139,6 @@
4427 const std::string RELAYOUT_TIMEOUT = "relayout-timeout";
4428 } // namespace local
4429
4430-namespace win
4431-{
4432-namespace decoration
4433-{
4434-const unsigned CLOSE_SIZE = 19;
4435-const unsigned ITEMS_PADDING = 5;
4436-const unsigned RADIUS = 8;
4437-const unsigned GLOW = 5;
4438-const nux::Color GLOW_COLOR(221, 72, 20);
4439-} // decoration namespace
4440-} // win namespace
4441-
4442 } // anon namespace
4443
4444 UnityScreen::UnityScreen(CompScreen* screen)
4445@@ -151,6 +147,7 @@
4446 , screen(screen)
4447 , cScreen(CompositeScreen::get(screen))
4448 , gScreen(GLScreen::get(screen))
4449+ , deco_manager_(std::make_shared<decoration::Manager>())
4450 , debugger_(this)
4451 , needsRelayout(false)
4452 , super_keypressed_(false)
4453@@ -302,7 +299,13 @@
4454 uScreen = this;
4455
4456 optionSetLockScreenInitiate(boost::bind(&UnityScreen::LockScreenInitiate, this, _1, _2, _3));
4457-
4458+ optionSetOverrideDecorationThemeNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
4459+ optionSetShadowXOffsetNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
4460+ optionSetShadowYOffsetNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
4461+ optionSetActiveShadowRadiusNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
4462+ optionSetInactiveShadowRadiusNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
4463+ optionSetActiveShadowColorNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
4464+ optionSetInactiveShadowColorNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
4465 optionSetShowHudInitiate(boost::bind(&UnityScreen::ShowHudInitiate, this, _1, _2, _3));
4466 optionSetShowHudTerminate(boost::bind(&UnityScreen::ShowHudTerminate, this, _1, _2, _3));
4467 optionSetBackgroundColorNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
4468@@ -377,9 +380,6 @@
4469 ubus_manager_.RegisterInterest(UBUS_LAUNCHER_END_KEY_SWITCHER,
4470 sigc::mem_fun(this, &UnityScreen::OnLauncherEndKeyNav));
4471
4472- ubus_manager_.RegisterInterest(UBUS_SWITCHER_START,
4473- sigc::mem_fun(this, &UnityScreen::OnSwitcherStart));
4474-
4475 ubus_manager_.RegisterInterest(UBUS_SWITCHER_END,
4476 sigc::mem_fun(this, &UnityScreen::OnSwitcherEnd));
4477
4478@@ -416,7 +416,11 @@
4479 force_draw_countdown_ += local::FRAMES_TO_REDRAW_ON_RESUME;
4480 });
4481
4482- panel::Style::Instance().changed.connect(sigc::mem_fun(this, &UnityScreen::OnPanelStyleChanged));
4483+ Introspectable::AddChild(deco_manager_.get());
4484+ auto const& deco_style = decoration::Style::Get();
4485+ auto deco_style_cb = sigc::hide(sigc::mem_fun(this, &UnityScreen::OnDecorationStyleChanged));
4486+ deco_style->theme.changed.connect(deco_style_cb);
4487+ deco_style->title_font.changed.connect(deco_style_cb);
4488
4489 minimize_speed_controller_.DurationChanged.connect(
4490 sigc::mem_fun(this, &UnityScreen::OnMinimizeDurationChanged)
4491@@ -502,8 +506,6 @@
4492
4493 void UnityScreen::OnInitiateSpread()
4494 {
4495- UnityWindow::SetupSharedTextures();
4496-
4497 for (auto const& swin : ScaleScreen::get(screen)->getWindows())
4498 UnityWindow::get(swin->window)->OnInitiateSpread();
4499 }
4500@@ -512,8 +514,6 @@
4501 {
4502 for (auto const& swin : ScaleScreen::get(screen)->getWindows())
4503 UnityWindow::get(swin->window)->OnTerminateSpread();
4504-
4505- UnityWindow::CleanupSharedTextures();
4506 }
4507
4508 void UnityScreen::DamagePanelShadow()
4509@@ -727,18 +727,17 @@
4510 wy = y + (last_bound.height - height) / 2;
4511 }
4512
4513-void UnityScreen::OnPanelStyleChanged()
4514+void UnityScreen::OnDecorationStyleChanged()
4515 {
4516- // Reload the windows themed textures
4517- UnityWindow::CleanupSharedTextures();
4518-
4519- if (!fake_decorated_windows_.empty())
4520- {
4521- UnityWindow::SetupSharedTextures();
4522-
4523- for (UnityWindow* uwin : fake_decorated_windows_)
4524- uwin->CleanupCachedTextures();
4525- }
4526+ for (UnityWindow* uwin : fake_decorated_windows_)
4527+ uwin->CleanupCachedTextures();
4528+
4529+ auto const& style = decoration::Style::Get();
4530+ deco_manager_->shadow_offset = style->ShadowOffset();
4531+ deco_manager_->active_shadow_color = style->ActiveShadowColor();
4532+ deco_manager_->active_shadow_radius = style->ActiveShadowRadius();
4533+ deco_manager_->inactive_shadow_color = style->InactiveShadowColor();
4534+ deco_manager_->inactive_shadow_radius = style->InactiveShadowRadius();
4535 }
4536
4537 void UnityScreen::DamageBlurUpdateRegion(nux::Geometry const& blur_update)
4538@@ -1141,13 +1140,14 @@
4539 return window->minimized ();
4540 }
4541
4542-void UnityWindow::DoOverrideFrameRegion (CompRegion &region)
4543+void UnityWindow::DoOverrideFrameRegion(CompRegion &region)
4544 {
4545- unsigned int oldUpdateFrameRegionIndex = window->updateFrameRegionGetCurrentIndex ();
4546+ unsigned int oldUpdateFrameRegionIndex = window->updateFrameRegionGetCurrentIndex();
4547
4548- window->updateFrameRegionSetCurrentIndex (MAXSHORT);
4549- window->updateFrameRegion (region);
4550- window->updateFrameRegionSetCurrentIndex (oldUpdateFrameRegionIndex);
4551+ window->updateFrameRegionSetCurrentIndex(MAXSHORT);
4552+ window->updateFrameRegion(region);
4553+ deco_win_->UpdateFrameRegion(region);
4554+ window->updateFrameRegionSetCurrentIndex(oldUpdateFrameRegionIndex);
4555 }
4556
4557 void UnityWindow::DoHide ()
4558@@ -1194,7 +1194,7 @@
4559 {
4560 mShowdesktopHandler.reset();
4561
4562- window->updateFrameRegion ();
4563+ window->updateFrameRegion();
4564 }
4565
4566 compiz::WindowInputRemoverLock::Ptr
4567@@ -1225,17 +1225,17 @@
4568 switch(event->type)
4569 {
4570 case MotionNotify:
4571- if (close_icon_state_ != panel::WindowState::PRESSED)
4572+ if (close_icon_state_ != decoration::WidgetState::PRESSED)
4573 {
4574- panel::WindowState old_state = close_icon_state_;
4575+ auto old_state = close_icon_state_;
4576
4577 if (close_button_geo_.IsPointInside(event->xmotion.x_root, event->xmotion.y_root))
4578 {
4579- close_icon_state_ = panel::WindowState::PRELIGHT;
4580+ close_icon_state_ = decoration::WidgetState::PRELIGHT;
4581 }
4582 else
4583 {
4584- close_icon_state_ = panel::WindowState::NORMAL;
4585+ close_icon_state_ = decoration::WidgetState::NORMAL;
4586 }
4587
4588 if (old_state != close_icon_state_)
4589@@ -1249,7 +1249,7 @@
4590 if (event->xbutton.button == Button1 &&
4591 close_button_geo_.IsPointInside(event->xbutton.x_root, event->xbutton.y_root))
4592 {
4593- close_icon_state_ = panel::WindowState::PRESSED;
4594+ close_icon_state_ = decoration::WidgetState::PRESSED;
4595 cWindow->addDamageRect(CompRectFromNuxGeo(close_button_geo_));
4596 handled = true;
4597 }
4598@@ -1264,11 +1264,11 @@
4599
4600 case ButtonRelease:
4601 {
4602- bool was_pressed = (close_icon_state_ == panel::WindowState::PRESSED);
4603+ bool was_pressed = (close_icon_state_ == decoration::WidgetState::PRESSED);
4604
4605- if (close_icon_state_ != panel::WindowState::NORMAL)
4606+ if (close_icon_state_ != decoration::WidgetState::NORMAL)
4607 {
4608- close_icon_state_ = panel::WindowState::NORMAL;
4609+ close_icon_state_ = decoration::WidgetState::NORMAL;
4610 cWindow->addDamageRect(CompRectFromNuxGeo(close_button_geo_));
4611 }
4612
4613@@ -1636,12 +1636,21 @@
4614 }
4615 }
4616
4617+void UnityScreen::addSupportedAtoms(std::vector<Atom>& atoms)
4618+{
4619+ screen->addSupportedAtoms(atoms);
4620+ deco_manager_->AddSupportedAtoms(atoms);
4621+}
4622+
4623 /* handle X Events */
4624 void UnityScreen::handleEvent(XEvent* event)
4625 {
4626 bool skip_other_plugins = false;
4627 PluginAdapter& wm = PluginAdapter::Default();
4628
4629+ if (deco_manager_->HandleEventBefore(event))
4630+ return;
4631+
4632 switch (event->type)
4633 {
4634 case FocusIn:
4635@@ -1873,14 +1882,11 @@
4636 if (!skip_other_plugins)
4637 screen->handleEvent(event);
4638
4639+ if (deco_manager_->HandleEventAfter(event))
4640+ return;
4641+
4642 switch (event->type)
4643 {
4644- case PropertyNotify:
4645- if (event->xproperty.atom == Atoms::mwmHints)
4646- {
4647- PluginAdapter::Default().NotifyNewDecorationState(event->xproperty.window);
4648- }
4649- break;
4650 case MapRequest:
4651 ShowdesktopHandler::AllowLeaveShowdesktopMode(event->xmaprequest.window);
4652 break;
4653@@ -2121,7 +2127,6 @@
4654 show_mode = switcher::ShowMode::CURRENT_VIEWPORT;
4655 }
4656
4657- UnityWindow::SetupSharedTextures();
4658 SetUpAndShowSwitcher(show_mode);
4659
4660 return true;
4661@@ -2323,20 +2328,14 @@
4662 PluginAdapter::Default().RestoreInputFocus();
4663 }
4664
4665-void UnityScreen::OnSwitcherStart(GVariant* data)
4666-{
4667- if (switcher_controller_->Visible())
4668- {
4669- UnityWindow::SetupSharedTextures();
4670- }
4671-}
4672-
4673 void UnityScreen::OnSwitcherEnd(GVariant* data)
4674 {
4675- UnityWindow::CleanupSharedTextures();
4676-
4677 for (UnityWindow* uwin : fake_decorated_windows_)
4678+ {
4679+ uwin->close_icon_state_ = decoration::WidgetState::NORMAL;
4680+ uwin->middle_clicked_ = false;
4681 uwin->CleanupCachedTextures();
4682+ }
4683 }
4684
4685 bool UnityScreen::SaveInputThenFocus(const guint xid)
4686@@ -2507,9 +2506,7 @@
4687 {
4688 PluginAdapter& adapter = PluginAdapter::Default();
4689
4690- CompPlugin* p = CompPlugin::find("core");
4691-
4692- if (p)
4693+ if (CompPlugin* p = CompPlugin::find("core"))
4694 {
4695 for (CompOption& option : p->vTable->getOptions())
4696 {
4697@@ -2521,9 +2518,7 @@
4698 }
4699 }
4700
4701- p = CompPlugin::find("expo");
4702-
4703- if (p)
4704+ if (CompPlugin* p = CompPlugin::find("expo"))
4705 {
4706 MultiActionList expoActions;
4707
4708@@ -2549,9 +2544,7 @@
4709 adapter.SetExpoAction(expoActions);
4710 }
4711
4712- p = CompPlugin::find("scale");
4713-
4714- if (p)
4715+ if (CompPlugin* p = CompPlugin::find("scale"))
4716 {
4717 MultiActionList scaleActions;
4718
4719@@ -2584,9 +2577,7 @@
4720 adapter.SetScaleAction(scaleActions);
4721 }
4722
4723- p = CompPlugin::find("unitymtgrabhandles");
4724-
4725- if (p)
4726+ if (CompPlugin* p = CompPlugin::find("unitymtgrabhandles"))
4727 {
4728 foreach(CompOption & option, p->vTable->getOptions())
4729 {
4730@@ -2599,6 +2590,15 @@
4731 }
4732 }
4733
4734+ if (CompPlugin* p = CompPlugin::find("decor"))
4735+ {
4736+ LOG_ERROR(logger) << "Decoration plugin is active, disabling it...";
4737+ screen->finiPluginForScreen(p);
4738+ p->vTable->finiScreen(screen);
4739+ CompPlugin::getPlugins().remove(p);
4740+ CompPlugin::unload(p);
4741+ }
4742+
4743 return false;
4744 }
4745
4746@@ -2868,6 +2868,7 @@
4747 uScreen->paintPanelShadow(region);
4748
4749 bool ret = gWindow->glDraw(matrix, attrib, region, mask);
4750+ deco_win_->Draw(matrix, attrib, region, mask);
4751
4752 if (draw_panel_shadow == DrawPanelShadow::OVER_WINDOW)
4753 uScreen->paintPanelShadow(region);
4754@@ -2875,19 +2876,26 @@
4755 return ret;
4756 }
4757
4758+bool UnityWindow::damageRect(bool initial, CompRect const& rect)
4759+{
4760+ if (initial)
4761+ deco_win_->Update();
4762+
4763+ return cWindow->damageRect(initial, rect);
4764+}
4765+
4766 void
4767 UnityScreen::OnMinimizeDurationChanged ()
4768 {
4769 /* Update the compiz plugin setting with the new computed speed so that it
4770 * will be used in the following minimizations */
4771- CompPlugin *p = CompPlugin::find("animation");
4772- if (p)
4773+ if (CompPlugin* p = CompPlugin::find("animation"))
4774 {
4775 CompOption::Vector &opts = p->vTable->getOptions();
4776
4777 for (CompOption &o : opts)
4778 {
4779- if (o.name() == std::string("minimize_durations"))
4780+ if (o.name() == "minimize_durations")
4781 {
4782 /* minimize_durations is a list value, but minimize applies only to
4783 * normal windows, so there's always one value */
4784@@ -2979,7 +2987,11 @@
4785 switch (n)
4786 {
4787 case CompWindowNotifyMap:
4788- if (window->type() == CompWindowTypeDesktopMask) {
4789+ deco_win_->Update();
4790+ deco_win_->UpdateDecorationPosition();
4791+
4792+ if (window->type() == CompWindowTypeDesktopMask)
4793+ {
4794 if (!focus_desktop_timeout_)
4795 {
4796 focus_desktop_timeout_.reset(new glib::Timeout(1000, [this] {
4797@@ -3001,8 +3013,7 @@
4798 }
4799 /* Fall through an re-evaluate wraps on map and unmap too */
4800 case CompWindowNotifyUnmap:
4801- if (UnityScreen::get (screen)->optionGetShowMinimizedWindows () &&
4802- window->mapNum () &&
4803+ if (uScreen->optionGetShowMinimizedWindows() && window->mapNum() &&
4804 !window->pendingUnmaps())
4805 {
4806 bool wasMinimized = window->minimized ();
4807@@ -3024,18 +3035,27 @@
4808 window->minimizedSetEnabled (this, false);
4809 }
4810
4811+ deco_win_->Update();
4812+ deco_win_->UpdateDecorationPosition();
4813+
4814 PluginAdapter::Default().UpdateShowDesktopState();
4815- break;
4816- case CompWindowNotifyBeforeDestroy:
4817- being_destroyed.emit();
4818- break;
4819- case CompWindowNotifyMinimize:
4820- /* Updating the count in dconf will trigger a "changed" signal to which
4821- * the method setting the new animation speed is attached */
4822- UnityScreen::get(screen)->minimize_speed_controller_.UpdateCount();
4823- break;
4824- default:
4825- break;
4826+ break;
4827+ case CompWindowNotifyBeforeDestroy:
4828+ being_destroyed.emit();
4829+ break;
4830+ case CompWindowNotifyMinimize:
4831+ /* Updating the count in dconf will trigger a "changed" signal to which
4832+ * the method setting the new animation speed is attached */
4833+ uScreen->minimize_speed_controller_.UpdateCount();
4834+ break;
4835+ case CompWindowNotifyUnreparent:
4836+ deco_win_->Undecorate();
4837+ break;
4838+ case CompWindowNotifyReparent:
4839+ deco_win_->Update();
4840+ break;
4841+ default:
4842+ break;
4843 }
4844
4845
4846@@ -3057,32 +3077,31 @@
4847 // We do this after the notify to ensure input focus has actually been moved.
4848 if (n == CompWindowNotifyFocusChange)
4849 {
4850- UnityScreen* us = UnityScreen::get(screen);
4851-
4852- // If focus gets moved to an external program while the Dash/Hud is open, refocus key input.
4853- if (us)
4854- {
4855- if (us->dash_controller_->IsVisible())
4856- {
4857- us->dash_controller_->ReFocusKeyInput();
4858- }
4859- else if (us->hud_controller_->IsVisible())
4860- {
4861- us->hud_controller_->ReFocusKeyInput();
4862- }
4863+ if (uScreen->dash_controller_->IsVisible())
4864+ {
4865+ uScreen->dash_controller_->ReFocusKeyInput();
4866+ }
4867+ else if (uScreen->hud_controller_->IsVisible())
4868+ {
4869+ uScreen->hud_controller_->ReFocusKeyInput();
4870 }
4871 }
4872 }
4873
4874 void UnityWindow::stateChangeNotify(unsigned int lastState)
4875 {
4876- if (window->state () & CompWindowStateFullscreenMask &&
4877+ if (window->state() & CompWindowStateFullscreenMask &&
4878 !(lastState & CompWindowStateFullscreenMask))
4879- UnityScreen::get (screen)->fullscreen_windows_.push_back(window);
4880+ {
4881+ uScreen->fullscreen_windows_.push_back(window);
4882+ }
4883 else if (lastState & CompWindowStateFullscreenMask &&
4884- !(window->state () & CompWindowStateFullscreenMask))
4885- UnityScreen::get (screen)->fullscreen_windows_.remove(window);
4886+ !(window->state() & CompWindowStateFullscreenMask))
4887+ {
4888+ uScreen->fullscreen_windows_.remove(window);
4889+ }
4890
4891+ deco_win_->Update();
4892 PluginAdapter::Default().NotifyStateChange(window, window->state(), lastState);
4893 window->stateChangeNotify(lastState);
4894 }
4895@@ -3094,29 +3113,43 @@
4896 * does not have a region */
4897
4898 if (mMinimizeHandler)
4899- mMinimizeHandler->updateFrameRegion (region);
4900+ {
4901+ mMinimizeHandler->updateFrameRegion(region);
4902+ }
4903 else if (mShowdesktopHandler)
4904- mShowdesktopHandler->UpdateFrameRegion (region);
4905+ {
4906+ mShowdesktopHandler->UpdateFrameRegion(region);
4907+ }
4908 else
4909- window->updateFrameRegion (region);
4910+ {
4911+ window->updateFrameRegion(region);
4912+ deco_win_->UpdateFrameRegion(region);
4913+ }
4914+}
4915+
4916+void UnityWindow::getOutputExtents(CompWindowExtents& output)
4917+{
4918+ window->getOutputExtents(output);
4919+ deco_win_->UpdateOutputExtents(output);
4920 }
4921
4922 void UnityWindow::moveNotify(int x, int y, bool immediate)
4923 {
4924+ deco_win_->UpdateDecorationPositionDelayed();
4925 PluginAdapter::Default().NotifyMoved(window, x, y);
4926 window->moveNotify(x, y, immediate);
4927 }
4928
4929 void UnityWindow::resizeNotify(int x, int y, int w, int h)
4930 {
4931+ deco_win_->UpdateDecorationPositionDelayed();
4932 PluginAdapter::Default().NotifyResized(window, x, y, w, h);
4933 window->resizeNotify(x, y, w, h);
4934 }
4935
4936 CompPoint UnityWindow::tryNotIntersectUI(CompPoint& pos)
4937 {
4938- UnityScreen* us = UnityScreen::get(screen);
4939- auto window_geo = window->borderRect ();
4940+ auto const& window_geo = window->borderRect();
4941 nux::Geometry target_monitor;
4942 nux::Point result(pos.x(), pos.y());
4943
4944@@ -3131,7 +3164,7 @@
4945 }
4946 }
4947
4948- auto const& launchers = us->launcher_controller_->launchers();
4949+ auto const& launchers = uScreen->launcher_controller_->launchers();
4950
4951 for (auto const& launcher : launchers)
4952 {
4953@@ -3149,7 +3182,7 @@
4954 }
4955 }
4956
4957- for (nux::Geometry const& geo : us->panel_controller_->GetGeometries())
4958+ for (nux::Geometry const& geo : uScreen->panel_controller_->GetGeometries())
4959 {
4960 if (geo.IsInside(result))
4961 {
4962@@ -3172,6 +3205,7 @@
4963
4964 if (!was_maximized)
4965 {
4966+ deco_win_->Update();
4967 bool result = window->place(pos);
4968
4969 if (window->type() & NO_FOCUS_MASK)
4970@@ -3222,23 +3256,55 @@
4971 break;
4972 case UnityshellOptions::BackgroundColor:
4973 {
4974- nux::Color override_color (optionGetBackgroundColorRed() / 65535.0f,
4975- optionGetBackgroundColorGreen() / 65535.0f,
4976- optionGetBackgroundColorBlue() / 65535.0f,
4977- optionGetBackgroundColorAlpha() / 65535.0f);
4978-
4979+ auto override_color = NuxColorFromCompizColor(optionGetBackgroundColor());
4980 override_color.red = override_color.red / override_color.alpha;
4981 override_color.green = override_color.green / override_color.alpha;
4982 override_color.blue = override_color.blue / override_color.alpha;
4983 bghash_->OverrideColor(override_color);
4984 break;
4985 }
4986+ case UnityshellOptions::OverrideDecorationTheme:
4987+ if (optionGetOverrideDecorationTheme())
4988+ {
4989+ deco_manager_->active_shadow_color = NuxColorFromCompizColor(optionGetActiveShadowColor());
4990+ deco_manager_->inactive_shadow_color = NuxColorFromCompizColor(optionGetInactiveShadowColor());
4991+ deco_manager_->active_shadow_radius = optionGetActiveShadowRadius();
4992+ deco_manager_->inactive_shadow_radius = optionGetInactiveShadowRadius();
4993+ deco_manager_->shadow_offset = nux::Point(optionGetShadowXOffset(), optionGetShadowYOffset());
4994+ }
4995+ else
4996+ {
4997+ OnDecorationStyleChanged();
4998+ }
4999+ break;
5000+ case UnityshellOptions::ActiveShadowColor:
The diff has been truncated for viewing.