Merge lp:~renatofilho/unity/unity-lp876017 into lp:unity

Proposed by Renato Araujo Oliveira Filho
Status: Merged
Approved by: Renato Araujo Oliveira Filho
Approved revision: no longer in the source branch.
Merged at revision: 2650
Proposed branch: lp:~renatofilho/unity/unity-lp876017
Merge into: lp:unity
Diff against target: 729 lines (+507/-31)
6 files modified
CMakeLists.txt (+1/-2)
plugins/unityshell/CMakeLists.txt (+1/-1)
plugins/unityshell/src/unityshell.cpp (+428/-0)
plugins/unityshell/src/unityshell.h (+39/-1)
unity-shared/PanelStyle.cpp (+37/-27)
unity-shared/PanelStyle.h (+1/-0)
To merge this branch: bzr merge lp:~renatofilho/unity/unity-lp876017
Reviewer Review Type Date Requested Status
Sam Spilsbury (community) Approve
Review via email: mp+120450@code.launchpad.net

Commit message

UnityWindow now implements ScaleWindowInterface.
Implemented support to close window during the scale plugin.
Fake windows decoration rendering using panel code as base.

Description of the change

UnityWindow now implements ScaleWindowInterface.
Implemented support to close window during the scale plugin.
Fake windows decoration rendering using panel code as base.

To post a comment you must log in.
Revision history for this message
Sam Spilsbury (smspillaz) wrote :
Download full text (3.7 KiB)

Right approach, some pointers:

76 +// Based on Scale plugin code
77 +CompWindow* UnityScreen::checkForWindowAt (int x, int y)
78 +{
79 + int x1, y1, x2, y2;
80 + CompWindowList::reverse_iterator rit = screen->windows ().rbegin ();
81 +
82 + for (; rit != screen->windows ().rend (); ++rit)
83 + {
84 + CompWindow *w = *rit;
85 + SCALE_WINDOW (w);
86 +
87 + ScalePosition pos = sw->getCurrentPosition ();
88 + if (sw->hasSlot ())
89 + {
90 + x1 = w->x () - w->input ().left * pos.scale;
91 + y1 = w->y () - w->input ().top * pos.scale;
92 + x2 = w->x () + (w->width () + w->input ().right) * pos.scale;
93 + y2 = w->y () + (w->height () + w->input ().bottom) * pos.scale;
94 + x1 += pos.x ();
95 + y1 += pos.y ();
96 + x2 += pos.x ();
97 + y2 += pos.y ();
98 + if (x1 <= x && y1 <= y && x2 > x && y2 > y)
99 + return w;
100 + }
101 + }
102 + return NULL;
103 +}

Is this necessary?

I think you can just overload scaleSelectWindow to determine what the currently hovered window is. From there you will need to damage and re-render both the new and old window. Have a look at the scaleaddon plugin.

151 + gWindow->geometry ().reset ();
152 + if (width && height)
153 + gWindow->glAddGeometry (ml, iconReg, iconReg);
154 +
155 + if (gWindow->geometry ().vCount)
156 + {
157 + GLFragment::Attrib fragment (attrib);
158 + GLMatrix wTransform (transform);
159 +
160 + wTransform.translate (x, y, 0.0f);
161 +
162 + glPushMatrix ();
163 + glLoadMatrixf (wTransform.getMatrix ());
164 + gWindow->glDrawTexture (icon, fragment, mask);
165 + glPopMatrix ();
166 + }

You will need to put this inside of #if USE_MODERN_COMPIZ_GL ifdefs. Sorry :( Here's how to do it:

#ifdef USE_MODERN_COMPIZ_GL
gWindow->vertexBuffer ()->begin ();
#else
151 + gWindow->geometry ().reset ();
#endif
152 + if (width && height)
153 + gWindow->glAddGeometry (ml, iconReg, iconReg);
154 +
#ifdef USE_MODERN_COMPIZ_GL
gWindow->vertexBuffer ().end ();
if (gWindow->vertexBuffer ().countVertices ())
#else
155 + if (gWindow->geometry ().vCount)
#endif
156 + {
#ifdef USE_MODERN_COMPIZ_GL
157 + GLFragment::Attrib fragment (attrib);
#endif
158 + GLMatrix wTransform (transform);
159 +
160 + wTransform.translate (x, y, 0.0f);
161 +
#ifdef USE_MODERN_COMPIZ_GL
gWindow->glDrawTexture (icon, wTransform, attrib, mask);
#else
162 + glPushMatrix ();
163 + glLoadMatrixf (wTransform.getMatrix ());
164 + gWindow->glDrawTexture (icon, fragment, mask);
165 + glPopMatrix ();
#endif
166 + }

172 + // BG
173 + glColor3f (0.0f, 0.0f, 0.0f);
174 + glRectf (x, y2, x2, y);

Preferably use client side buffers for this, eg

#ifndef USE_MODERN_COMPIZ_GL
172 + // BG
173 + glColor3f (0.0f, 0.0f, 0.0f);
174 + glRectf (x, y2, x2, y);
#else
GLVertexBuffer *vertexBuffer = GLVertexBuffer::streamingBuffer ();
vertexBuffer->begin (GL_TRIANGLE_STRIP)
const GLfloat vertices[] =
{
    x, y2, 0.0f,
    x, y, 0.0f,
    x2, y, 0.0f,
    x2, y2, 0.0f
};

vertexBuffer->addVertices (4, vertices);
vertexBuffer->color4f (0.0f, 0.0f, 0.0f, 1.0f);
vertexBuffer->end ();
vertexBuffer->render (transform, attrib);

209 + x + CLOSE_ICON_SPACE, iconY,
210 + maxWidth , maxHeight);

Make this a constant

190 + if (!sWindow->hasSlot() || // animation finished
191 + ...

Read more...

review: Needs Fixing
Revision history for this message
Renato Araujo Oliveira Filho (renatofilho) wrote :

> I think you can just overload scaleSelectWindow to determine what the
> currently hovered window is. From there you will need to damage and re-render
> both the new and old window. Have a look at the scaleaddon plugin.
> #ifdef USE_MODERN_COMPIZ_GL
> gWindow->vertexBuffer ()->begin ();
> #else
> 151 + gWindow->geometry ().reset ();
> #endif
> 152 + if (width && height)
> 153 + gWindow->glAddGeometry (ml, iconReg, iconReg);
> 154 +
> #ifdef USE_MODERN_COMPIZ_GL
> gWindow->vertexBuffer ().end ();
> if (gWindow->vertexBuffer ().countVertices ())
> #else
> 155 + if (gWindow->geometry ().vCount)
> #endif
> 156 + {
> #ifdef USE_MODERN_COMPIZ_GL
> 157 + GLFragment::Attrib fragment (attrib);
> #endif
> 158 + GLMatrix wTransform (transform);
> 159 +
> 160 + wTransform.translate (x, y, 0.0f);
> 161 +
> #ifdef USE_MODERN_COMPIZ_GL
> gWindow->glDrawTexture (icon, wTransform, attrib, mask);
> #else
> 162 + glPushMatrix ();
> 163 + glLoadMatrixf (wTransform.getMatrix ());
> 164 + gWindow->glDrawTexture (icon, fragment, mask);
> 165 + glPopMatrix ();
> #endif
> 166 + }
Fixed on rev: 2577
I have implemented the "scaleSelectWindow" based on scaleaddon plugin, but I did not understand why I need this code. (The implementation is working well without this)

>
> 172 + // BG
> 173 + glColor3f (0.0f, 0.0f, 0.0f);
> 174 + glRectf (x, y2, x2, y);
>
> Preferably use client side buffers for this
Fixed on rev: 2574
Thanks for the example code.

> Make this a constant
Fixed on rev: 2575

>
> Also avoid the 65535, use OPAQUE
Fixed on rev: 2576

>
> 121 + CompString name (PKGDATADIR"/close_dash.png");
>
> Is that the correct asset?
Based on designer docs, yes this is the correct icon.

>
> That needs to be under test.
Any suggestion or example how to test it?

Revision history for this message
Renato Araujo Oliveira Filho (renatofilho) wrote :

> > That needs to be under test.
My suggestion to make the code testable is split unityshell.(h/cpp) file into different files (UnityWindow/UnityWindowPrivate, UntiyScree/UnityScreenPrivate and UnityShell), with this we can instantiate only the private class inside of the tests and call/test the "private" functions.

What do you think?

Revision history for this message
Sam Spilsbury (smspillaz) wrote :

> > I think you can just overload scaleSelectWindow to determine what the
> > currently hovered window is. From there you will need to damage and re-
> render
> > both the new and old window. Have a look at the scaleaddon plugin.
> > #ifdef USE_MODERN_COMPIZ_GL
> > gWindow->vertexBuffer ()->begin ();
> > #else
> > 151 + gWindow->geometry ().reset ();
> > #endif
> > 152 + if (width && height)
> > 153 + gWindow->glAddGeometry (ml, iconReg, iconReg);
> > 154 +
> > #ifdef USE_MODERN_COMPIZ_GL
> > gWindow->vertexBuffer ().end ();
> > if (gWindow->vertexBuffer ().countVertices ())
> > #else
> > 155 + if (gWindow->geometry ().vCount)
> > #endif
> > 156 + {
> > #ifdef USE_MODERN_COMPIZ_GL
> > 157 + GLFragment::Attrib fragment (attrib);
> > #endif
> > 158 + GLMatrix wTransform (transform);
> > 159 +
> > 160 + wTransform.translate (x, y, 0.0f);
> > 161 +
> > #ifdef USE_MODERN_COMPIZ_GL
> > gWindow->glDrawTexture (icon, wTransform, attrib, mask);
> > #else
> > 162 + glPushMatrix ();
> > 163 + glLoadMatrixf (wTransform.getMatrix ());
> > 164 + gWindow->glDrawTexture (icon, fragment, mask);
> > 165 + glPopMatrix ();
> > #endif
> > 166 + }
> Fixed on rev: 2577
> I have implemented the "scaleSelectWindow" based on scaleaddon plugin, but I
> did not understand why I need this code. (The implementation is working well
> without this)

Hmm, what do you mean by this? If you're saying that you don't need either I guess you can remove them both? Its just that overriding scaleSelectWindow is the preferred way to finding out the currently highlighted window as opposed to reimplementing checkForWindowAt.

>
> >
> > 172 + // BG
> > 173 + glColor3f (0.0f, 0.0f, 0.0f);
> > 174 + glRectf (x, y2, x2, y);
> >
> > Preferably use client side buffers for this
> Fixed on rev: 2574
> Thanks for the example code.
>
> > Make this a constant
> Fixed on rev: 2575
>
> >
> > Also avoid the 65535, use OPAQUE
> Fixed on rev: 2576

Thanks.

>
> >
> > 121 + CompString name (PKGDATADIR"/close_dash.png");
> >
> > Is that the correct asset?
> Based on designer docs, yes this is the correct icon.

+1

>
> >
> > That needs to be under test.
> Any suggestion or example how to test it?

My suggestion to make the code testable is split unityshell.(h/cpp) file into different files (UnityWindow/UnityWindowPrivate, UntiyScree/UnityScreenPrivate and UnityShell), with this we can instantiate only the private class inside of the tests and call/test the "private" functions.

What do you think?

^ This suggestion is the right way to do it :)

Revision history for this message
Renato Araujo Oliveira Filho (renatofilho) wrote :

> Hmm, what do you mean by this? If you're saying that you don't need either I
> guess you can remove them both? Its just that overriding scaleSelectWindow is
> the preferred way to finding out the currently highlighted window as opposed
> to reimplementing checkForWindowAt.

I have implemented "scaleSelectWindow" but I did not use all the code you suggested, what I did was:

+void UnityWindow::scaleSelectWindow ()
210 +{
211 + UnityScreen* us = UnityScreen::get(screen);
212 +
213 + if (us->highlighted_window_ != window->id ())
214 + {
215 + CompositeWindow *cWindow = CompositeWindow::get (window);
216 + if (cWindow)
217 + cWindow->addDamage ();
218 +
219 + cWindow = 0;
220 + CompWindow *old_window = screen->findWindow (us->highlighted_window_);
221 + if (old_window)
222 + cWindow = CompositeWindow::get (old_window);
223 +
224 + if (cWindow)
225 + cWindow->addDamage ();
226 +
227 + us->highlighted_window_ = window->id ();
228 + }
229 +
230 + ScaleWindow *sWindow = ScaleWindow::get (window);
231 + if (sWindow)
232 + sWindow->scaleSelectWindow ();

Revision history for this message
Renato Araujo Oliveira Filho (renatofilho) wrote :

> > >
> > > That needs to be under test.
> > Any suggestion or example how to test it?
>
> My suggestion to make the code testable is split unityshell.(h/cpp) file into
> different files (UnityWindow/UnityWindowPrivate, UntiyScree/UnityScreenPrivate
> and UnityShell), with this we can instantiate only the private class inside of
> the tests and call/test the "private" functions.
>
> What do you think?
>
> ^ This suggestion is the right way to do it :)

This will be a big change in the code, because of that me and Olivier think this is not the best moment to do it, since this is our last week working on Unity bug fixes, and the code is already in feature freeze.

Revision history for this message
Sam Spilsbury (smspillaz) wrote :

This looks good. I don't know how much of this is testable, but I agree at this point its probably better in than out. I'll put my +1 here and hopefully someone can give a second opinion in the next few hours.

review: Approve
Revision history for this message
Sam Spilsbury (smspillaz) :
review: Approve
Revision history for this message
Unity Merger (unity-merger) wrote :

No commit message specified.

Revision history for this message
Unity Merger (unity-merger) wrote :

The Jenkins job https://jenkins.qa.ubuntu.com/job/automerge-unity/1164/console reported an error when processing this lp:~renatofilho/unity/unity-lp876017 branch.
Not merging it.

Revision history for this message
Sam Spilsbury (smspillaz) wrote :

Hey renato.

You need to add xrender to the pkgconfig deps in the top level cmakelists file.

Sent from Samsung Mobile

 Unity Merger <email address hidden> wrote:

The Jenkins job https://jenkins.qa.ubuntu.com/job/automerge-unity/1164/console reported an error when processing this lp:~renatofilho/unity/unity-lp876017 branch.
Not merging it.
--
https://code.launchpad.net/~renatofilho/unity/unity-lp876017/+merge/120450
You are reviewing the proposed merge of lp:~renatofilho/unity/unity-lp876017 into lp:unity.

Revision history for this message
Unity Merger (unity-merger) wrote :

There are additional revisions which have not been approved in review. Please seek review and approval of these new revisions.

Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote :

64 + WindowCairoContext ()

When you have some time, could you please update this code to match the unity coding stiles (i.e. no spaces between methods and brackets)

Instead of GetTextProperty and GetTextProperty why not just using gdk_x11_get_xatom_by_name?
Also, these functions should actually be in WindowManager class (implemented by PluginAdapterCompiz).

441 + if (window_header_style_)
442 + g_object_unref (window_header_style_);

You should have used glib::Object for this, and try to get rid of some manual deletion using smart pointers.

Revision history for this message
Renato Araujo Oliveira Filho (renatofilho) wrote :

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 2012-08-30 12:52:53 +0000
3+++ CMakeLists.txt 2012-08-31 13:28:34 +0000
4@@ -130,8 +130,7 @@
5 #
6 # Compiz Plugins
7 #
8-
9-set (UNITY_PLUGIN_DEPS "compiz;nux-3.0>=3.0.0;libbamf3;dee-1.0;gio-2.0;gio-unix-2.0;gmodule-2.0;dbusmenu-glib-0.4;x11;libstartup-notification-1.0;gthread-2.0;indicator3-0.4>=0.4.90;atk;unity-misc>=0.4.0;dbus-glib-1;gtk+-3.0>=3.1;sigc++-2.0;json-glib-1.0;libnotify;xfixes;unity-protocol-private>=5.95.1;libgeis")
10+set (UNITY_PLUGIN_DEPS "compiz;nux-3.0>=3.0.0;libbamf3;dee-1.0;gio-2.0;gio-unix-2.0;gmodule-2.0;dbusmenu-glib-0.4;x11;libstartup-notification-1.0;gthread-2.0;indicator3-0.4>=0.4.90;atk;unity-misc>=0.4.0;dbus-glib-1;gtk+-3.0>=3.1;sigc++-2.0;json-glib-1.0;libnotify;xfixes;unity-protocol-private>=5.95.1;libgeis;xrender>=0.9")
11 set (UNITY_PROTOCOL_PRIVATE_DEPS "unity-protocol-private>=5.95.1")
12
13 find_package (PkgConfig)
14
15=== modified file 'plugins/unityshell/CMakeLists.txt'
16--- plugins/unityshell/CMakeLists.txt 2012-08-03 12:51:02 +0000
17+++ plugins/unityshell/CMakeLists.txt 2012-08-31 13:28:34 +0000
18@@ -6,7 +6,7 @@
19
20 compiz_plugin (unityshell
21 PKGDEPS ${UNITY_PLUGIN_DEPS}
22- PLUGINDEPS composite opengl compiztoolbox
23+ PLUGINDEPS composite opengl compiztoolbox scale
24 CFLAGSADD "-DINSTALLPREFIX='\"${CMAKE_INSTALL_PREFIX}\"' -DPKGDATADIR='\"${PKGDATADIR}\"' -I${CMAKE_BINARY_DIR} -I${CMAKE_SOURCE_DIR} ${BOOT_LOGGER_FLAG} -DGETTEXT_PACKAGE='\"unity\"' ${MAINTAINER_CFLAGS} -I${CMAKE_SOURCE_DIR}/dash/ -I${CMAKE_SOURCE_DIR}/launcher/ -I${CMAKE_SOURCE_DIR}/hud/ -I${CMAKE_SOURCE_DIR}/panel/ -I${CMAKE_SOURCE_DIR}/shortcuts/ -I${CMAKE_SOURCE_DIR}/unity-shared/"
25 LIBDIRS "${CMAKE_BINARY_DIR}/UnityCore"
26 )
27
28=== modified file 'plugins/unityshell/src/unityshell.cpp'
29--- plugins/unityshell/src/unityshell.cpp 2012-08-31 09:15:33 +0000
30+++ plugins/unityshell/src/unityshell.cpp 2012-08-31 13:28:34 +0000
31@@ -43,6 +43,9 @@
32 #include <gdk/gdk.h>
33 #include <gdk/gdkx.h>
34 #include <libnotify/notify.h>
35+#include <cairo-xlib-xrender.h>
36+
37+#include <text/text.h>
38
39 #include <sstream>
40 #include <memory>
41@@ -80,6 +83,10 @@
42
43 UnityScreen* uScreen = 0;
44
45+static unsigned int CLOSE_ICON_SIZE = 19;
46+static unsigned int CLOSE_ICON_SPACE = 5;
47+static unsigned int SCALE_WINDOW_TITLE_SIZE = 28;
48+
49 void reset_glib_logging();
50 void configure_logging();
51 void capture_g_log_calls(const gchar* log_domain,
52@@ -100,6 +107,34 @@
53 } // namespace local
54 } // anon namespace
55
56+class WindowCairoContext
57+{
58+ public:
59+ Pixmap pixmap_;
60+ cairo_surface_t* surface_;
61+ GLTexture::List texture_;
62+ cairo_t *cr_;
63+
64+ WindowCairoContext ()
65+ : pixmap_ (0), surface_ (0), cr_ (0)
66+ {
67+ }
68+
69+ ~WindowCairoContext ()
70+ {
71+ if (cr_)
72+ cairo_destroy (cr_);
73+
74+ if (surface_)
75+ cairo_surface_destroy (surface_);
76+
77+ texture_.clear ();
78+
79+ if (pixmap_)
80+ XFreePixmap (screen->dpy (), pixmap_);
81+ }
82+};
83+
84 UnityScreen::UnityScreen(CompScreen* screen)
85 : BaseSwitchScreen (screen)
86 , PluginClassHandler <UnityScreen, CompScreen> (screen)
87@@ -128,6 +163,7 @@
88 , panel_texture_has_changed_(true)
89 , paint_panel_(false)
90 , scale_just_activated_(false)
91+ , highlighted_window_(0)
92 , minimize_speed_controller(new WindowMinimizeSpeedController())
93 {
94 Timer timer;
95@@ -1221,6 +1257,11 @@
96 }
97 }
98
99+CompRect UnityWindow::closeButtonArea ()
100+{
101+ return close_button_area_;
102+}
103+
104 bool UnityScreen::shellCouldBeHidden(CompOutput const& output)
105 {
106 std::vector<Window> const& nuxwins(nux::XInputWindow::NativeHandleList());
107@@ -1588,6 +1629,24 @@
108 launcher_controller_->KeyNavTerminate(false);
109 EnableCancelAction(CancelActionTarget::LAUNCHER_SWITCHER, false);
110 }
111+ if (PluginAdapter::Default()->IsScaleActive() &&
112+ event->xbutton.button == Button1 &&
113+ highlighted_window_ != 0)
114+ {
115+ CompWindow *w = screen->findWindow (highlighted_window_);
116+ if (w)
117+ {
118+ UnityWindow *uw = UnityWindow::get (w);
119+ CompPoint pointer (pointerX, pointerY);
120+ if (uw->closeButtonArea ().contains (pointer))
121+ {
122+ w->close (0);
123+ skip_other_plugins = true;
124+ }
125+ }
126+
127+ }
128+
129 break;
130 case ButtonRelease:
131 if (switcher_controller_ && switcher_controller_->Visible())
132@@ -3409,9 +3468,11 @@
133 , gWindow(GLWindow::get(window))
134 , mMinimizeHandler()
135 , mShowdesktopHandler(nullptr)
136+ , window_header_style_(0)
137 {
138 WindowInterface::setHandler(window);
139 GLWindowInterface::setHandler(gWindow);
140+ ScaleWindowInterface::setHandler (ScaleWindow::get (window));
141
142 if (UnityScreen::get (screen)->optionGetShowMinimizedWindows () &&
143 window->mapNum ())
144@@ -3456,6 +3517,292 @@
145 }
146 }
147
148+void UnityWindow::DrawTexture (GLTexture* icon,
149+ const GLWindowPaintAttrib& attrib,
150+ const GLMatrix& transform,
151+ unsigned int mask,
152+ float x, float y,
153+ int &maxWidth, int &maxHeight)
154+{
155+ if (icon)
156+ {
157+ int width, height;
158+ width = icon->width ();
159+ height = icon->height ();
160+
161+ if (height > maxHeight)
162+ maxHeight = height;
163+
164+ if (width > maxWidth)
165+ maxWidth = width;
166+
167+ CompRegion iconReg (0, 0, width, height);
168+ GLTexture::MatrixList ml (1);
169+
170+ ml[0] = icon->matrix ();
171+ gWindow->vertexBuffer ()->begin ();
172+ if (width && height)
173+ gWindow->glAddGeometry (ml, iconReg, iconReg);
174+
175+ if (gWindow->vertexBuffer ()->end ())
176+ {
177+ GLMatrix wTransform (transform);
178+
179+ wTransform.translate (x, y, 0.0f);
180+
181+ gWindow->glDrawTexture (icon, wTransform, attrib, mask);
182+ }
183+ }
184+}
185+
186+WindowCairoContext* UnityWindow::CreateCairoContext (float width, float height)
187+{
188+ XRenderPictFormat *format;
189+ Screen *xScreen;
190+ WindowCairoContext *context = new WindowCairoContext();
191+
192+ xScreen = ScreenOfDisplay (screen->dpy (), screen->screenNum ());
193+
194+ format = XRenderFindStandardFormat (screen->dpy (), PictStandardARGB32);
195+ context->pixmap_ = XCreatePixmap (screen->dpy (),
196+ screen->root (),
197+ width, height, 32);
198+
199+ context->texture_ = GLTexture::bindPixmapToTexture (context->pixmap_,
200+ width, height,
201+ 32);
202+ if (context->texture_.empty ())
203+ {
204+ delete context;
205+ return 0;
206+ }
207+
208+ context->surface_ = cairo_xlib_surface_create_with_xrender_format (screen->dpy (),
209+ context->pixmap_,
210+ xScreen,
211+ format,
212+ width,
213+ height);
214+ context->cr_ = cairo_create (context->surface_);
215+
216+ // clear
217+ cairo_save (context->cr_);
218+ cairo_set_operator (context->cr_, CAIRO_OPERATOR_CLEAR);
219+ cairo_paint (context->cr_);
220+ cairo_restore (context->cr_);
221+
222+ return context;
223+}
224+
225+void UnityWindow::RenderText (WindowCairoContext *context,
226+ float x, float y,
227+ float maxWidth, float maxHeight)
228+{
229+ PangoFontDescription* font = pango_font_description_new ();
230+ pango_font_description_set_family (font, "sans");
231+ pango_font_description_set_absolute_size (font, 12 * PANGO_SCALE);
232+ pango_font_description_set_style (font, PANGO_STYLE_NORMAL);
233+ pango_font_description_set_weight (font, PANGO_WEIGHT_BOLD);
234+
235+ PangoLayout* layout = pango_cairo_create_layout (context->cr_);
236+ pango_layout_set_font_description (layout, font);
237+ pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END);
238+ pango_layout_set_height (layout, maxHeight);
239+
240+ pango_layout_set_auto_dir (layout, false);
241+ pango_layout_set_text (layout,
242+ GetWindowName (window->id ()).c_str (),
243+ -1);
244+
245+ /* update the size of the pango layout */
246+ pango_layout_set_width (layout, maxWidth * PANGO_SCALE);
247+ pango_cairo_update_layout (context->cr_, layout);
248+
249+ cairo_set_operator (context->cr_, CAIRO_OPERATOR_OVER);
250+
251+ cairo_set_source_rgba (context->cr_,
252+ 1.0,
253+ 1.0,
254+ 1.0,
255+ 1.0);
256+
257+ // alignment
258+ int lWidth, lHeight;
259+ pango_layout_get_pixel_size (layout, &lWidth, &lHeight);
260+
261+ y = ((maxHeight - lHeight) / 2.0) + y;
262+ cairo_translate (context->cr_, x, y);
263+ pango_cairo_show_layout (context->cr_, layout);
264+}
265+
266+void UnityWindow::DrawWindowTitle (const GLWindowPaintAttrib& attrib,
267+ const GLMatrix& transform,
268+ unsigned int mask,
269+ float x, float y, float x2, float y2)
270+{
271+ const float width = x2 - x;
272+
273+ // Paint a fake window decoration
274+ WindowCairoContext *context = CreateCairoContext (width, SCALE_WINDOW_TITLE_SIZE);
275+
276+ cairo_save (context->cr_);
277+ cairo_push_group (context->cr_);
278+
279+ // Round window decoration top border
280+ const double height = SCALE_WINDOW_TITLE_SIZE;
281+ const double aspect = 1.0;
282+ const double corner_radius = height / 10.0;
283+ const double radius = corner_radius / aspect;
284+ const double degrees = M_PI / 180.0;
285+
286+ cairo_new_sub_path (context->cr_);
287+
288+ cairo_arc (context->cr_, radius, radius, radius, 180 * degrees, 270 * degrees);
289+ cairo_arc (context->cr_, width - radius, radius, radius, -90 * degrees, 0 * degrees);
290+ cairo_line_to (context->cr_, width, height);
291+ cairo_line_to (context->cr_, 0, height);
292+
293+ cairo_close_path (context->cr_);
294+ cairo_clip (context->cr_);
295+
296+ // Draw window decoration abased on gtk style
297+ gtk_render_background (window_header_style_, context->cr_, 0, 0, width, SCALE_WINDOW_TITLE_SIZE);
298+ gtk_render_frame (window_header_style_, context->cr_, 0, 0, width, SCALE_WINDOW_TITLE_SIZE);
299+
300+ cairo_pop_group_to_source (context->cr_);
301+
302+ cairo_paint_with_alpha (context->cr_, 1.0);
303+ cairo_restore (context->cr_);
304+
305+ // Draw windows title
306+ RenderText (context,
307+ CLOSE_ICON_SPACE * 2 + CLOSE_ICON_SIZE,
308+ 0.0,
309+ width, SCALE_WINDOW_TITLE_SIZE);
310+
311+ mask |= PAINT_WINDOW_BLEND_MASK;
312+ int maxWidth, maxHeight;
313+ foreach(GLTexture *icon, context->texture_)
314+ {
315+ DrawTexture (icon, attrib, transform, mask,
316+ x, y,
317+ maxWidth , maxHeight);
318+ }
319+
320+ delete context;
321+}
322+
323+void UnityWindow::scalePaintDecoration (const GLWindowPaintAttrib& attrib,
324+ const GLMatrix& transform,
325+ const CompRegion& region,
326+ unsigned int mask)
327+{
328+ ScaleWindow *sWindow = ScaleWindow::get (window);
329+ if (!sWindow)
330+ return;
331+
332+ sWindow->scalePaintDecoration (attrib, transform, region, mask);
333+
334+ if (!sWindow->hasSlot()) // animation not finished
335+ return;
336+
337+ if (!window_header_style_)
338+ {
339+ GtkWidgetPath* widget_path = gtk_widget_path_new ();
340+ gint pos = gtk_widget_path_append_type (widget_path, GTK_TYPE_WINDOW);
341+ gtk_widget_path_iter_set_name (widget_path, pos, "UnityPanelWidget");
342+
343+ window_header_style_ = gtk_style_context_new ();
344+ gtk_style_context_set_path (window_header_style_, widget_path);
345+ gtk_style_context_add_class (window_header_style_, "gnome-panel-menu-bar");
346+ gtk_style_context_add_class (window_header_style_, "unity-panel");
347+
348+ // get close button
349+ panel::Style& style = panel::Style::Instance();
350+
351+ std::vector<std::string> files = style.GetWindowButtonFileNames (panel::WindowButtonType::CLOSE,
352+ panel::WindowState::NORMAL);
353+
354+ CompString pName ("unityshell");
355+ foreach (std::string file, files)
356+ {
357+ CompString fileName (file.c_str ());
358+ CompSize size (CLOSE_ICON_SIZE, CLOSE_ICON_SIZE);
359+ close_icon_ = GLTexture::readImageToTexture (fileName,
360+ pName,
361+ size);
362+ if (close_icon_.size () != 0)
363+ break;
364+ }
365+
366+ if (close_icon_.size () == 0)
367+ {
368+ CompString fileName (PKGDATADIR"/close_dash.png");
369+ CompSize size (CLOSE_ICON_SIZE, CLOSE_ICON_SIZE);
370+ close_icon_ = GLTexture::readImageToTexture (fileName,
371+ pName,
372+ size);
373+ }
374+ }
375+
376+ // Make the windows header opaque to override the original
377+ GLWindowPaintAttrib sAttrib (attrib);
378+ sAttrib.opacity = OPAQUE;
379+
380+ ScalePosition pos = sWindow->getCurrentPosition ();
381+ int maxHeight, maxWidth;
382+ // Use "2" as margin to make sure to cover all originial decoration
383+ const float width = (window->width () + 4) * pos.scale;
384+ const float x = pos.x () + window->x () - (2 * pos.scale);
385+ const float y = pos.y () + window->y () - SCALE_WINDOW_TITLE_SIZE;
386+ const float iconX = x + CLOSE_ICON_SPACE;
387+ const float iconY = y + ((SCALE_WINDOW_TITLE_SIZE - CLOSE_ICON_SIZE) / 2.0);
388+
389+ maxHeight = maxWidth = 0;
390+
391+ DrawWindowTitle (sAttrib,
392+ transform,
393+ mask,
394+ x, y,
395+ x + width, y + SCALE_WINDOW_TITLE_SIZE);
396+
397+ mask |= PAINT_WINDOW_BLEND_MASK;
398+ foreach(GLTexture *icon, close_icon_)
399+ {
400+ DrawTexture (icon, sAttrib, transform, mask,
401+ iconX, iconY,
402+ maxWidth , maxHeight);
403+ }
404+
405+ close_button_area_ = CompRect (iconX, iconY, maxWidth, maxHeight);
406+}
407+
408+void UnityWindow::scaleSelectWindow ()
409+{
410+ UnityScreen* us = UnityScreen::get(screen);
411+
412+ if (us->highlighted_window_ != window->id ())
413+ {
414+ CompositeWindow *cWindow = CompositeWindow::get (window);
415+ if (cWindow)
416+ cWindow->addDamage ();
417+
418+ cWindow = 0;
419+ CompWindow *old_window = screen->findWindow (us->highlighted_window_);
420+ if (old_window)
421+ cWindow = CompositeWindow::get (old_window);
422+
423+ if (cWindow)
424+ cWindow->addDamage ();
425+
426+ us->highlighted_window_ = window->id ();
427+ }
428+
429+ ScaleWindow *sWindow = ScaleWindow::get (window);
430+ if (sWindow)
431+ sWindow->scaleSelectWindow ();
432+}
433+
434 UnityWindow::~UnityWindow()
435 {
436 UnityScreen* us = UnityScreen::get(screen);
437@@ -3474,6 +3821,9 @@
438 window->minimize ();
439 }
440
441+ if (window_header_style_)
442+ g_object_unref (window_header_style_);
443+
444 ShowdesktopHandler::animating_windows.remove (static_cast <ShowdesktopHandlerWindowInterface *> (this));
445
446 if (mShowdesktopHandler)
447@@ -3513,6 +3863,84 @@
448 return true;
449 }
450
451+CompString UnityWindow::GetUtf8Property (Window id,
452+ Atom atom)
453+{
454+ Atom type;
455+ int result, format;
456+ unsigned long nItems, bytesAfter;
457+ char *val;
458+ CompString retval;
459+ Atom utf8StringAtom;
460+
461+ utf8StringAtom = XInternAtom (screen->dpy (), "UTF8_STRING", 0);
462+ result = XGetWindowProperty (screen->dpy (), id, atom, 0L, 65536, False,
463+ utf8StringAtom, &type, &format, &nItems,
464+ &bytesAfter, (unsigned char **) &val);
465+
466+ if (result != Success)
467+ return retval;
468+
469+ if (type == utf8StringAtom && format == 8 && val && nItems > 0)
470+ {
471+ char valueString[nItems + 1];
472+ strncpy (valueString, val, nItems);
473+ valueString[nItems] = 0;
474+ retval = valueString;
475+ }
476+ if (val)
477+ XFree (val);
478+
479+ return retval;
480+}
481+
482+CompString UnityWindow::GetTextProperty (Window id,
483+ Atom atom)
484+{
485+ XTextProperty text;
486+ CompString retval;
487+
488+ text.nitems = 0;
489+ if (XGetTextProperty (screen->dpy (), id, &text, atom))
490+ {
491+ if (text.value)
492+ {
493+ char valueString[text.nitems + 1];
494+
495+ strncpy (valueString, (char *) text.value, text.nitems);
496+ valueString[text.nitems] = 0;
497+
498+ retval = valueString;
499+
500+ XFree (text.value);
501+ }
502+ }
503+
504+ return retval;
505+}
506+
507+
508+CompString UnityWindow::GetWindowName (Window id)
509+{
510+ CompString name;
511+ Atom visibleNameAtom;
512+
513+ visibleNameAtom = XInternAtom (screen->dpy (), "_NET_WM_VISIBLE_NAME", 0);
514+ name = GetUtf8Property (id, visibleNameAtom);
515+ if (name.empty ())
516+ {
517+ Atom wmNameAtom = XInternAtom (screen->dpy (), "_NET_WM_NAME", 0);
518+ name = GetUtf8Property (id, wmNameAtom);
519+ }
520+
521+
522+ if (name.empty ())
523+ name = GetTextProperty (id, XA_WM_NAME);
524+
525+ return name;
526+}
527+
528+
529
530 namespace
531 {
532
533=== modified file 'plugins/unityshell/src/unityshell.h'
534--- plugins/unityshell/src/unityshell.h 2012-08-27 13:51:29 +0000
535+++ plugins/unityshell/src/unityshell.h 2012-08-31 13:28:34 +0000
536@@ -29,6 +29,7 @@
537 #include <sigc++/sigc++.h>
538 #include <boost/shared_ptr.hpp>
539
540+#include <scale/scale.h>
541 #include <core/core.h>
542 #include <core/pluginclasshandler.h>
543 #include <composite/composite.h>
544@@ -70,6 +71,8 @@
545 namespace unity
546 {
547
548+class WindowCairoContext;
549+
550 /* base screen class */
551 class UnityScreen :
552 public unity::debug::Introspectable,
553@@ -344,8 +347,9 @@
554 glib::SourceManager sources_;
555 unity::ThumbnailGenerator thumb_generator;
556
557+ Window highlighted_window_;
558+
559 WindowMinimizeSpeedController* minimize_speed_controller;
560-
561 friend class UnityWindow;
562 };
563
564@@ -354,6 +358,7 @@
565 public GLWindowInterface,
566 public ShowdesktopHandlerWindowInterface,
567 public compiz::WindowInputRemoverLockAcquireInterface,
568+ public WrapableHandler<ScaleWindowInterface, 4>,
569 public BaseSwitchWindow,
570 public PluginClassHandler <UnityWindow, CompWindow>
571 {
572@@ -414,6 +419,8 @@
573
574 void handleEvent (XEvent *event);
575
576+ CompRect closeButtonArea ();
577+
578 typedef compiz::CompizMinimizedWindowHandler<UnityScreen, UnityWindow>
579 UnityMinimizedHandler;
580 std::unique_ptr <UnityMinimizedHandler> mMinimizeHandler;
581@@ -422,6 +429,13 @@
582
583 //! Emited when CompWindowNotifyBeforeDestroy is received
584 sigc::signal<void> being_destroyed;
585+
586+ void scaleSelectWindow ();
587+ void scalePaintDecoration (const GLWindowPaintAttrib &,
588+ const GLMatrix &,
589+ const CompRegion &,
590+ unsigned int);
591+
592 private:
593 void DoEnableFocus ();
594 void DoDisableFocus ();
595@@ -453,8 +467,32 @@
596
597 compiz::WindowInputRemoverLock::Ptr GetInputRemover ();
598
599+ void DrawWindowTitle (const GLWindowPaintAttrib& attrib,
600+ const GLMatrix& transform,
601+ unsigned int mask,
602+ float x, float y, float x2, float y2);
603+ void DrawTexture (GLTexture *icon,
604+ const GLWindowPaintAttrib& attrib,
605+ const GLMatrix& transform,
606+ unsigned int mask,
607+ float x, float y,
608+ int &maxWidth, int &maxHeight);
609+ void RenderText (WindowCairoContext *context,
610+ float x, float y,
611+ float maxWidth, float maxHeight);
612+ WindowCairoContext* CreateCairoContext (float width, float height);
613+
614+ // based on compiz text plugin
615+ CompString GetWindowName (Window id);
616+ CompString GetUtf8Property (Window id, Atom atom);
617+ CompString GetTextProperty (Window id, Atom atom);
618+
619 compiz::WindowInputRemoverLock::Weak input_remover_;
620 glib::Source::UniquePtr focus_desktop_timeout_;
621+
622+ GLTexture::List close_icon_;
623+ CompRect close_button_area_;
624+ GtkStyleContext* window_header_style_;
625 };
626
627
628
629=== modified file 'unity-shared/PanelStyle.cpp'
630--- unity-shared/PanelStyle.cpp 2012-08-01 20:46:31 +0000
631+++ unity-shared/PanelStyle.cpp 2012-08-31 13:28:34 +0000
632@@ -182,9 +182,17 @@
633 return context.GetBitmap();
634 }
635
636-nux::BaseTexture* Style::GetWindowButton(WindowButtonType type, WindowState state)
637+/*!
638+ Return a vector with the possible file names sorted by priority
639+
640+ @param type The type of the button.
641+ @param state The button state.
642+
643+ @return A vector of strings with the possible file names sorted by priority.
644+*/
645+std::vector<std::string> Style::GetWindowButtonFileNames(WindowButtonType type, WindowState state)
646 {
647- nux::BaseTexture* texture = NULL;
648+ std::vector<std::string> files;
649 std::string names[] = { "close", "minimize", "unmaximize", "maximize" };
650 std::string states[] = { "", "_focused_prelight", "_focused_pressed", "_unfocused",
651 "_unfocused", "_unfocused_prelight", "_unfocused_pressed"};
652@@ -200,38 +208,40 @@
653 glib::String filename(g_build_filename(home_dir, ".themes", _theme_name.c_str(), subpath.str().c_str(), NULL));
654
655 if (g_file_test(filename.Value(), G_FILE_TEST_EXISTS))
656- {
657- glib::Error error;
658-
659- // Found a file, try loading the pixbuf
660- glib::Object<GdkPixbuf> pixbuf(gdk_pixbuf_new_from_file(filename.Value(), &error));
661- if (error)
662- LOG_WARNING(logger) << "Unable to load window button " << filename.Value() << ": " << error.Message();
663- else
664- texture = nux::CreateTexture2DFromPixbuf(pixbuf, true);
665- }
666+ files.push_back (filename.Value());
667 }
668
669- // texture is NULL if the pixbuf is not loaded
670- if (!texture)
671+ const char* var = g_getenv("GTK_DATA_PREFIX");
672+ if (!var)
673+ var = "/usr";
674+
675+ glib::String filename(g_build_filename(var, "share", "themes", _theme_name.c_str(), subpath.str().c_str(), NULL));
676+ if (g_file_test(filename.Value(), G_FILE_TEST_EXISTS))
677+ files.push_back (filename.Value());
678+
679+ return files;
680+}
681+
682+nux::BaseTexture* Style::GetWindowButton(WindowButtonType type, WindowState state)
683+{
684+ nux::BaseTexture* texture = NULL;
685+
686+ std::vector<std::string> files = GetWindowButtonFileNames (type, state);
687+ for (unsigned int i=0; i < files.size(); i++)
688 {
689- const char* var = g_getenv("GTK_DATA_PREFIX");
690- if (!var)
691- var = "/usr";
692-
693- glib::String filename(g_build_filename(var, "share", "themes", _theme_name.c_str(), subpath.str().c_str(), NULL));
694-
695- if (g_file_test(filename.Value(), G_FILE_TEST_EXISTS))
696- {
697 glib::Error error;
698-
699- // Found a file, try loading the pixbuf
700- glib::Object<GdkPixbuf> pixbuf(gdk_pixbuf_new_from_file(filename.Value(), &error));
701+ // Try loading the pixbuf
702+ glib::Object<GdkPixbuf> pixbuf(gdk_pixbuf_new_from_file(files[i].c_str (), &error));
703 if (error)
704- LOG_WARNING(logger) << "Unable to load window button " << filename.Value() << ": " << error.Message();
705+ {
706+ LOG_WARNING(logger) << "Unable to load window button " << files[i] << ": " << error.Message();
707+ }
708 else
709+ {
710 texture = nux::CreateTexture2DFromPixbuf(pixbuf, true);
711- }
712+ if (texture)
713+ break;
714+ }
715 }
716
717 if (!texture)
718
719=== modified file 'unity-shared/PanelStyle.h'
720--- unity-shared/PanelStyle.h 2012-08-01 20:46:31 +0000
721+++ unity-shared/PanelStyle.h 2012-08-31 13:28:34 +0000
722@@ -71,6 +71,7 @@
723 GtkStyleContext* GetStyleContext();
724 nux::NBitmapData* GetBackground(int width, int height, float opacity);
725 nux::BaseTexture* GetWindowButton(WindowButtonType type, WindowState state);
726+ std::vector<std::string> GetWindowButtonFileNames(WindowButtonType type, WindowState state);
727 nux::BaseTexture* GetFallbackWindowButton(WindowButtonType type, WindowState state);
728 glib::Object<GdkPixbuf> GetHomeButton();
729 std::string GetFontDescription(PanelItem item);