Merge lp:~unity-team/unity/panel-fixes-2010-12-07 into lp:unity

Proposed by Neil J. Patel on 2010-12-17
Status: Merged
Approved by: Gord Allott on 2010-12-17
Approved revision: 707
Merged at revision: 722
Proposed branch: lp:~unity-team/unity/panel-fixes-2010-12-07
Merge into: lp:unity
Diff against target: 1845 lines (+1499/-47)
20 files modified
src/IndicatorObjectEntryProxy.h (+2/-1)
src/IndicatorObjectEntryProxyRemote.cpp (+3/-2)
src/IndicatorObjectFactory.h (+1/-0)
src/IndicatorObjectFactoryRemote.cpp (+3/-1)
src/PanelIndicatorObjectEntryView.cpp (+8/-4)
src/PanelIndicatorObjectEntryView.h (+7/-0)
src/PanelIndicatorObjectView.cpp (+7/-0)
src/PanelIndicatorObjectView.h (+1/-1)
src/PanelMenuView.cpp (+671/-0)
src/PanelMenuView.h (+103/-0)
src/PanelView.cpp (+48/-32)
src/PanelView.h (+3/-0)
src/PluginAdapter.cpp (+77/-4)
src/PluginAdapter.h (+10/-1)
src/WindowButtons.cpp (+254/-0)
src/WindowButtons.h (+63/-0)
src/WindowManager.cpp (+171/-0)
src/WindowManager.h (+57/-0)
src/unity.cpp (+2/-1)
tests/CMakeLists.txt (+8/-0)
To merge this branch: bzr merge lp:~unity-team/unity/panel-fixes-2010-12-07
Reviewer Review Type Date Requested Status
Unity Team 2010-12-17 Pending
Review via email: mp+44015@code.launchpad.net

Description of the change

This implements the panel menubar as per spec.

The things to check for:

1. Unmaximised window + no mouse hover over panel = Application name
2. Unmaximised window + mouse hover over panel = Menus (and they work)
3. Unmaximised window + no mouse hover + Alt+F (or whatever) = Menus show
4. Maximised window + no mouse = no decorations + usable close/min/restore buttons + window *title*
5. Maximised window + mouse = no decs + usable close/min/restore buttons + menu
6. Maximised window + no mouse + Alt+F (i.e.) = no decs + usable buttons + menu
7. Maximised window + click on restore = restored decorations on floating window

Notes:

 - Windows that were already undecorated should be unaffected by max/restore (i.e. restore shouldn't add decorations, chromium with non-system-borders enabled is a good test)
 - Transmission goes weird when trying to restore decorations, need to investigate
 - Interaction is weird with desktop, sometimes you get "Unknown"

To post a comment you must log in.
Neil J. Patel (njpatel) wrote :

Oh, some of the linked bugs are because of reusing the same branch, please ignore that.

707. By Neil J. Patel on 2010-12-17

[merge] trunk

708. By Neil J. Patel on 2010-12-17

don't give window button events unless they are showing

Gord Allott (gordallott) wrote :

noting: Nux: [Object::UnReference] Error on object allocated at /home/gord/canonical/unity/panel-fixes-2010-12-07/src/PanelMenuView.cpp [63]: Nux: Assertion failed: 0 : [Object::UnReference] Never call UnReference on an object with a floating reference. Call Dispose() instead.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/IndicatorObjectEntryProxy.h'
2--- src/IndicatorObjectEntryProxy.h 2010-11-11 15:07:58 +0000
3+++ src/IndicatorObjectEntryProxy.h 2010-12-17 10:43:24 +0000
4@@ -36,7 +36,8 @@
5 virtual void ShowMenu (int x, int y, guint32 timestamp, guint32 button) = 0;
6
7 // Signals
8- sigc::signal<void> Updated;
9+ sigc::signal<void> updated;
10+ sigc::signal<void, bool> active_changed;
11
12 public:
13 bool label_visible;
14
15=== modified file 'src/IndicatorObjectEntryProxyRemote.cpp'
16--- src/IndicatorObjectEntryProxyRemote.cpp 2010-11-17 20:12:42 +0000
17+++ src/IndicatorObjectEntryProxyRemote.cpp 2010-12-17 10:43:24 +0000
18@@ -104,7 +104,8 @@
19
20 _active = active;
21
22- Updated.emit ();
23+ active_changed.emit (active);
24+ updated.emit ();
25 }
26
27 bool
28@@ -141,7 +142,7 @@
29 icon_sensitive = __image_sensitive;
30 icon_visible = __image_visible;
31
32- Updated.emit ();
33+ updated.emit ();
34 }
35
36 const char *
37
38=== modified file 'src/IndicatorObjectFactory.h'
39--- src/IndicatorObjectFactory.h 2010-12-07 13:55:04 +0000
40+++ src/IndicatorObjectFactory.h 2010-12-17 10:43:24 +0000
41@@ -45,6 +45,7 @@
42 sigc::signal<void, IndicatorObjectProxy *> OnObjectRemoved;
43 sigc::signal<void, int, int> OnMenuPointerMoved;
44 sigc::signal<void, const char *> OnEntryActivateRequest;
45+ sigc::signal<void, const char *> OnEntryActivated;
46
47 protected:
48 std::vector<IndicatorObjectProxy *>_indicators;
49
50=== modified file 'src/IndicatorObjectFactoryRemote.cpp'
51--- src/IndicatorObjectFactoryRemote.cpp 2010-12-13 19:53:58 +0000
52+++ src/IndicatorObjectFactoryRemote.cpp 2010-12-17 10:43:24 +0000
53@@ -239,7 +239,9 @@
54
55 entry->SetActive (g_strcmp0 (entry_id, entry->GetId ()) == 0);
56 }
57- }
58+ }
59+
60+ IndicatorObjectFactory::OnEntryActivated.emit (entry_id);
61 }
62
63 void
64
65=== modified file 'src/PanelIndicatorObjectEntryView.cpp'
66--- src/PanelIndicatorObjectEntryView.cpp 2010-12-07 15:01:07 +0000
67+++ src/PanelIndicatorObjectEntryView.cpp 2010-12-17 10:43:24 +0000
68@@ -31,9 +31,6 @@
69 #include <gtk/gtk.h>
70 #include <time.h>
71
72-#define PANEL_HEIGHT 24
73-#define PADDING 6
74-#define SPACING 3
75
76 static void draw_menu_bg (cairo_t *cr, int width, int height);
77
78@@ -43,7 +40,8 @@
79 _proxy (proxy),
80 _util_cg (CAIRO_FORMAT_ARGB32, 1, 1)
81 {
82- _proxy->Updated.connect (sigc::mem_fun (this, &PanelIndicatorObjectEntryView::Refresh));
83+ _proxy->active_changed.connect (sigc::mem_fun (this, &PanelIndicatorObjectEntryView::OnActiveChanged));
84+ _proxy->updated.connect (sigc::mem_fun (this, &PanelIndicatorObjectEntryView::Refresh));
85
86 InputArea::OnMouseDown.connect (sigc::mem_fun (this, &PanelIndicatorObjectEntryView::OnMouseDown));
87
88@@ -55,6 +53,12 @@
89 }
90
91 void
92+PanelIndicatorObjectEntryView::OnActiveChanged (bool is_active)
93+{
94+ active_changed.emit (this, is_active);
95+}
96+
97+void
98 PanelIndicatorObjectEntryView::OnMouseDown (int x, int y, long button_flags, long key_flags)
99 {
100 if (_proxy->GetActive ())
101
102=== modified file 'src/PanelIndicatorObjectEntryView.h'
103--- src/PanelIndicatorObjectEntryView.h 2010-12-07 13:55:04 +0000
104+++ src/PanelIndicatorObjectEntryView.h 2010-12-17 10:43:24 +0000
105@@ -28,6 +28,10 @@
106
107 #include "Introspectable.h"
108
109+#define PANEL_HEIGHT 24
110+#define PADDING 6
111+#define SPACING 3
112+
113 class PanelIndicatorObjectEntryView : public nux::TextureArea, public Introspectable
114 {
115 public:
116@@ -37,10 +41,13 @@
117 void Refresh ();
118 void OnMouseDown (int x, int y, long button_flags, long key_flags);
119 void Activate ();
120+ void OnActiveChanged (bool is_active);
121
122 const gchar * GetName ();
123 void AddProperties (GVariantBuilder *builder);
124
125+ sigc::signal<void, PanelIndicatorObjectEntryView *, bool> active_changed;
126+
127 public:
128 IndicatorObjectEntryProxy *_proxy;
129 private:
130
131=== modified file 'src/PanelIndicatorObjectView.cpp'
132--- src/PanelIndicatorObjectView.cpp 2010-12-02 11:55:02 +0000
133+++ src/PanelIndicatorObjectView.cpp 2010-12-17 10:43:24 +0000
134@@ -30,6 +30,13 @@
135
136 #include <glib.h>
137
138+PanelIndicatorObjectView::PanelIndicatorObjectView ()
139+: View (NUX_TRACKER_LOCATION),
140+ _proxy (NULL),
141+ _entries ()
142+{
143+}
144+
145 PanelIndicatorObjectView::PanelIndicatorObjectView (IndicatorObjectProxy *proxy)
146 : View (NUX_TRACKER_LOCATION),
147 _proxy (proxy),
148
149=== modified file 'src/PanelIndicatorObjectView.h'
150--- src/PanelIndicatorObjectView.h 2010-12-02 11:55:02 +0000
151+++ src/PanelIndicatorObjectView.h 2010-12-17 10:43:24 +0000
152@@ -29,6 +29,7 @@
153 class PanelIndicatorObjectView : public nux::View, public Introspectable
154 {
155 public:
156+ PanelIndicatorObjectView ();
157 PanelIndicatorObjectView (IndicatorObjectProxy *proxy);
158 ~PanelIndicatorObjectView ();
159
160@@ -47,7 +48,6 @@
161 const gchar * GetChildsName ();
162 void AddProperties (GVariantBuilder *builder);
163
164-private:
165 IndicatorObjectProxy *_proxy;
166 std::vector<PanelIndicatorObjectEntryView *> _entries;
167 };
168
169=== added file 'src/PanelMenuView.cpp'
170--- src/PanelMenuView.cpp 1970-01-01 00:00:00 +0000
171+++ src/PanelMenuView.cpp 2010-12-17 10:43:24 +0000
172@@ -0,0 +1,671 @@
173+/*
174+ * Copyright (C) 2010 Canonical Ltd
175+ *
176+ * This program is free software: you can redistribute it and/or modify
177+ * it under the terms of the GNU General Public License version 3 as
178+ * published by the Free Software Foundation.
179+ *
180+ * This program is distributed in the hope that it will be useful,
181+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
182+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
183+ * GNU General Public License for more details.
184+ *
185+ * You should have received a copy of the GNU General Public License
186+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
187+ *
188+ * Authored by: Neil Jagdish Patel <neil.patel@canonical.com>
189+ */
190+#include <glib.h>
191+#include <pango/pangocairo.h>
192+#include <gtk/gtk.h>
193+
194+#include "Nux/Nux.h"
195+#include "Nux/HLayout.h"
196+#include "Nux/VLayout.h"
197+#include <Nux/TextureArea.h>
198+
199+#include "NuxGraphics/GLThread.h"
200+#include "Nux/BaseWindow.h"
201+#include "Nux/WindowCompositor.h"
202+
203+#include "PanelMenuView.h"
204+
205+#include "WindowManager.h"
206+
207+#include "IndicatorObjectEntryProxy.h"
208+
209+#include <gio/gdesktopappinfo.h>
210+
211+#define BUTTONS_WIDTH 72
212+
213+static void on_active_window_changed (BamfMatcher *matcher,
214+ BamfView *old_view,
215+ BamfView *new_view,
216+ PanelMenuView *self);
217+
218+
219+PanelMenuView::PanelMenuView ()
220+: _matcher (NULL),
221+ _title_layer (NULL),
222+ _util_cg (CAIRO_FORMAT_ARGB32, 1, 1),
223+ _gradient_texture (NULL),
224+ _title_tex (NULL),
225+ _is_inside (false),
226+ _is_maximized (false),
227+ _last_active_view (NULL)
228+{
229+ WindowManager *win_manager;
230+
231+ _matcher = bamf_matcher_get_default ();
232+ g_signal_connect (_matcher, "active-window-changed",
233+ G_CALLBACK (on_active_window_changed), this);
234+
235+ _menu_layout = new nux::HLayout ("", NUX_TRACKER_LOCATION);
236+
237+ /* This is for our parent and for PanelView to read indicator entries, we
238+ * shouldn't touch this again
239+ */
240+ _layout = _menu_layout;
241+
242+ _window_buttons = new WindowButtons ();
243+ _window_buttons->NeedRedraw ();
244+ _window_buttons->close_clicked.connect (sigc::mem_fun (this, &PanelMenuView::OnCloseClicked));
245+ _window_buttons->minimize_clicked.connect (sigc::mem_fun (this, &PanelMenuView::OnMinimizeClicked));
246+ _window_buttons->restore_clicked.connect (sigc::mem_fun (this, &PanelMenuView::OnRestoreClicked));
247+ _window_buttons->redraw_signal.connect (sigc::mem_fun (this, &PanelMenuView::OnWindowButtonsRedraw));
248+
249+ win_manager = WindowManager::Default ();
250+ win_manager->window_maximized.connect (sigc::mem_fun (this, &PanelMenuView::OnWindowMaximized));
251+ win_manager->window_restored.connect (sigc::mem_fun (this, &PanelMenuView::OnWindowRestored));
252+ win_manager->window_unmapped.connect (sigc::mem_fun (this, &PanelMenuView::OnWindowUnmapped));
253+
254+ Refresh ();
255+}
256+
257+PanelMenuView::~PanelMenuView ()
258+{
259+ if (_title_layer)
260+ delete _title_layer;
261+ if (_title_tex)
262+ _title_tex->UnReference ();
263+
264+ _menu_layout->UnReference ();
265+ _window_buttons->UnReference ();
266+}
267+
268+void
269+PanelMenuView::FullRedraw ()
270+{
271+ _menu_layout->NeedRedraw ();
272+ _window_buttons->NeedRedraw ();
273+ NeedRedraw ();
274+}
275+
276+void
277+PanelMenuView::SetProxy (IndicatorObjectProxy *proxy)
278+{
279+ _proxy = proxy;
280+ printf ("IndicatorAdded: %s\n", _proxy->GetName ().c_str ());
281+
282+ _proxy->OnEntryAdded.connect (sigc::mem_fun (this, &PanelMenuView::OnEntryAdded));
283+ _proxy->OnEntryMoved.connect (sigc::mem_fun (this, &PanelMenuView::OnEntryMoved));
284+ _proxy->OnEntryRemoved.connect (sigc::mem_fun (this, &PanelMenuView::OnEntryRemoved));
285+}
286+
287+long
288+PanelMenuView::ProcessEvent (nux::IEvent &ievent, long TraverseInfo, long ProcessEventInfo)
289+{
290+ long ret = TraverseInfo;
291+ nux::Geometry geo = GetGeometry ();
292+
293+ if (geo.IsPointInside (ievent.e_x, ievent.e_y))
294+ {
295+ if (_is_inside != true)
296+ {
297+ _is_inside = true;
298+ FullRedraw ();
299+ }
300+ }
301+ else
302+ {
303+ if (_is_inside != false)
304+ {
305+ _is_inside = false;
306+ FullRedraw ();
307+ }
308+ }
309+
310+ if (_is_maximized)
311+ ret = _window_buttons->ProcessEvent (ievent, ret, ProcessEventInfo);
312+ ret = _menu_layout->ProcessEvent (ievent, ret, ProcessEventInfo);
313+
314+ return ret;
315+}
316+
317+long PanelMenuView::PostLayoutManagement (long LayoutResult)
318+{
319+ long res = View::PostLayoutManagement (LayoutResult);
320+ int w = _window_buttons->GetContentWidth ();
321+
322+ nux::Geometry geo = GetGeometry ();
323+
324+ _window_buttons->SetGeometry (geo.x + PADDING, geo.y, w, geo.height);
325+ _window_buttons->ComputeLayout2 ();
326+
327+ /* Explicitly set the size and position of the widgets */
328+ geo.x += PADDING + w + PADDING;
329+ geo.width -= PADDING + w + PADDING;
330+
331+ _menu_layout->SetGeometry (geo.x, geo.y, geo.width, geo.height);
332+ _menu_layout->ComputeLayout2();
333+
334+ Refresh ();
335+
336+ return res;
337+}
338+
339+void
340+PanelMenuView::Draw (nux::GraphicsEngine& GfxContext, bool force_draw)
341+{
342+ nux::Geometry geo = GetGeometry ();
343+ int button_width = PADDING + _window_buttons->GetContentWidth () + PADDING;
344+ float factor = 4;
345+ button_width /= factor;
346+
347+ GfxContext.PushClippingRectangle (geo);
348+
349+ /* "Clear" out the background */
350+ nux::ROPConfig rop;
351+ rop.Blend = true;
352+ rop.SrcBlend = GL_ONE;
353+ rop.DstBlend = GL_ONE_MINUS_SRC_ALPHA;
354+
355+ nux::ColorLayer layer (nux::Color (0x00000000), true, rop);
356+ gPainter.PushDrawLayer (GfxContext, GetGeometry (), &layer);
357+
358+ if (_is_maximized)
359+ {
360+ if (!_is_inside)
361+ gPainter.PushDrawLayer (GfxContext, GetGeometry (), _title_layer);
362+ }
363+ else
364+ {
365+ if (_is_inside || _last_active_view)
366+ {
367+ if (_gradient_texture == NULL)
368+ {
369+ nux::NTextureData texture_data (nux::BITFMT_R8G8B8A8, geo.width, 1, 1);
370+ nux::ImageSurface surface = texture_data.GetSurface (0);
371+ nux::SURFACE_LOCKED_RECT lockrect;
372+ BYTE *dest;
373+ int num_row;
374+
375+ _gradient_texture = nux::GetThreadGLDeviceFactory ()->CreateSystemCapableDeviceTexture (texture_data.GetWidth (), texture_data.GetHeight (), 1, texture_data.GetFormat ());
376+
377+ _gradient_texture->LockRect (0, &lockrect, 0);
378+
379+ dest = (BYTE *) lockrect.pBits;
380+ num_row = surface.GetBlockHeight ();
381+
382+ for (int y = 0; y < num_row; y++)
383+ {
384+ for (int x = 0; x < geo.width; x++)
385+ {
386+ *(dest + y * lockrect.Pitch + 4*x + 0) = 223; //red
387+ *(dest + y * lockrect.Pitch + 4*x + 1) = 219; //green
388+ *(dest + y * lockrect.Pitch + 4*x + 2) = 210; //blue
389+
390+ if (x < button_width * (factor - 1))
391+ {
392+ *(dest + y * lockrect.Pitch + 4*x + 3) = 0xff;
393+ }
394+ else if (x < button_width * factor)
395+ {
396+ *(dest + y * lockrect.Pitch + 4*x + 3) = 255 - 255 * (((float)x-(button_width * (factor -1)))/(float)(button_width));
397+ }
398+ else
399+ {
400+ *(dest + y * lockrect.Pitch + 4*x + 3) = 0x00;
401+ }
402+ }
403+ }
404+ _gradient_texture->UnlockRect (0);
405+ }
406+ GfxContext.GetRenderStates ().SetBlend(true, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
407+
408+ nux::TexCoordXForm texxform0;
409+ nux::TexCoordXForm texxform1;
410+
411+ // Modulate the checkboard and the gradient texture
412+ GfxContext.QRP_2TexMod(geo.x, geo.y,
413+ geo.width, geo.height,
414+ _gradient_texture, texxform0,
415+ nux::Color::White,
416+ _title_tex->GetDeviceTexture (),
417+ texxform1,
418+ nux::Color::White);
419+
420+ GfxContext.GetRenderStates ().SetBlend(false);
421+
422+ // The previous blend is too aggressive on the texture and therefore there
423+ // is a slight loss of clarity. This fixes that
424+ geo.width = button_width * (factor - 1);
425+ gPainter.PushDrawLayer (GfxContext, geo, _title_layer);
426+ geo = GetGeometry ();
427+ }
428+ else
429+ {
430+ gPainter.PushDrawLayer (GfxContext,
431+ geo,
432+ _title_layer);
433+ }
434+ }
435+
436+ gPainter.PopBackground ();
437+
438+ GfxContext.PopClippingRectangle();
439+}
440+
441+void
442+PanelMenuView::DrawContent (nux::GraphicsEngine &GfxContext, bool force_draw)
443+{
444+ nux::Geometry geo = GetGeometry ();
445+
446+ GfxContext.PushClippingRectangle (geo);
447+
448+ if (_is_inside || _last_active_view)
449+ {
450+ _layout->ProcessDraw (GfxContext, force_draw);
451+ }
452+
453+ if (_is_maximized)
454+ {
455+ _window_buttons->ProcessDraw (GfxContext, true);
456+ }
457+
458+ GfxContext.PopClippingRectangle();
459+}
460+
461+gchar *
462+PanelMenuView::GetActiveViewName ()
463+{
464+ gchar *label = NULL;
465+
466+ if (_is_maximized)
467+ {
468+ BamfWindow *window = bamf_matcher_get_active_window (_matcher);
469+
470+ if (BAMF_IS_WINDOW (window))
471+ label = g_strdup (bamf_view_get_name (BAMF_VIEW (window)));
472+ }
473+
474+ if (!label)
475+ {
476+ BamfApplication *app = bamf_matcher_get_active_application (_matcher);
477+ if (BAMF_IS_APPLICATION (app))
478+ {
479+ const gchar *filename;
480+
481+ filename = bamf_application_get_desktop_file (app);
482+
483+ if (filename && g_strcmp0 (filename, "") != 0)
484+ {
485+ GDesktopAppInfo *info;
486+
487+ info = g_desktop_app_info_new_from_filename (bamf_application_get_desktop_file (app));
488+
489+ if (info)
490+ {
491+ label = g_strdup (g_app_info_get_display_name (G_APP_INFO (info)));
492+ g_object_unref (info);
493+ }
494+ else
495+ {
496+ g_warning ("Unable to get GDesktopAppInfo for %s",
497+ bamf_application_get_desktop_file (app));
498+ }
499+ }
500+
501+ if (label == NULL)
502+ {
503+ BamfView *active_view;
504+
505+ active_view = (BamfView *)bamf_matcher_get_active_window (_matcher);
506+ if (BAMF_IS_VIEW (active_view))
507+ label = g_strdup (bamf_view_get_name (active_view));
508+ else
509+ label = g_strdup ("");
510+ }
511+ }
512+ else
513+ {
514+ label = g_strdup (" ");
515+ }
516+ }
517+
518+ return label;
519+}
520+
521+void
522+PanelMenuView::Refresh ()
523+{
524+ nux::Geometry geo = GetGeometry ();
525+ char *label = GetActiveViewName ();
526+ PangoLayout *layout = NULL;
527+ PangoFontDescription *desc = NULL;
528+ GtkSettings *settings = gtk_settings_get_default ();
529+ cairo_t *cr;
530+ char *font_description = NULL;
531+ GdkScreen *screen = gdk_screen_get_default ();
532+ int dpi = 0;
533+
534+ int x = 0;
535+ int y = 0;
536+ int width = geo.width;
537+ int height = geo.height;
538+ int text_width = 0;
539+ int text_height = 0;
540+
541+ if (label)
542+ {
543+ PangoContext *cxt;
544+ PangoRectangle log_rect;
545+
546+ cr = _util_cg.GetContext ();
547+
548+ g_object_get (settings,
549+ "gtk-font-name", &font_description,
550+ "gtk-xft-dpi", &dpi,
551+ NULL);
552+ desc = pango_font_description_from_string (font_description);
553+ pango_font_description_set_weight (desc, PANGO_WEIGHT_BOLD);
554+
555+ layout = pango_cairo_create_layout (cr);
556+ pango_layout_set_font_description (layout, desc);
557+ pango_layout_set_text (layout, label, -1);
558+
559+ cxt = pango_layout_get_context (layout);
560+ pango_cairo_context_set_font_options (cxt, gdk_screen_get_font_options (screen));
561+ pango_cairo_context_set_resolution (cxt, (float)dpi/(float)PANGO_SCALE);
562+ pango_layout_context_changed (layout);
563+
564+ pango_layout_get_extents (layout, NULL, &log_rect);
565+ text_width = log_rect.width / PANGO_SCALE;
566+ text_height = log_rect.height / PANGO_SCALE;
567+
568+ pango_font_description_free (desc);
569+ g_free (font_description);
570+ cairo_destroy (cr);
571+ }
572+
573+ nux::CairoGraphics cairo_graphics(CAIRO_FORMAT_ARGB32, width, height);
574+ cr = cairo_graphics.GetContext();
575+ cairo_set_line_width (cr, 1);
576+
577+ x = PADDING;
578+ y = 0;
579+
580+ if (_is_maximized)
581+ x += _window_buttons->GetContentWidth () + PADDING + PADDING;
582+
583+ if (label)
584+ {
585+ pango_cairo_update_layout (cr, layout);
586+
587+ // Once for the homies that couldn't be here
588+ cairo_set_source_rgb (cr, 50/255.0f, 50/255.0f, 45/255.0f);
589+ cairo_move_to (cr, x, ((height - text_height)/2)-1);
590+ pango_cairo_show_layout (cr, layout);
591+ cairo_stroke (cr);
592+
593+ // Once again for the homies that could
594+ cairo_set_source_rgba (cr, 223/255.0f, 219/255.0f, 210/255.0f, 1.0f);
595+ cairo_move_to (cr, x, (height - text_height)/2);
596+ pango_cairo_show_layout (cr, layout);
597+ cairo_stroke (cr);
598+ }
599+
600+ cairo_destroy (cr);
601+ if (layout)
602+ g_object_unref (layout);
603+
604+ nux::NBitmapData* bitmap = cairo_graphics.GetBitmap();
605+
606+ // The Texture is created with a reference count of 1.
607+ nux::BaseTexture* texture2D = nux::GetThreadGLDeviceFactory ()->CreateSystemCapableTexture ();
608+ texture2D->Update(bitmap);
609+ delete bitmap;
610+
611+ if (_title_layer)
612+ delete _title_layer;
613+
614+ nux::TexCoordXForm texxform;
615+ texxform.SetTexCoordType (nux::TexCoordXForm::OFFSET_COORD);
616+ texxform.SetWrap (nux::TEXWRAP_REPEAT, nux::TEXWRAP_REPEAT);
617+
618+ nux::ROPConfig rop;
619+ rop.Blend = true;
620+ rop.SrcBlend = GL_ONE;
621+ rop.DstBlend = GL_ONE_MINUS_SRC_ALPHA;
622+ _title_layer = new nux::TextureLayer (texture2D->GetDeviceTexture(),
623+ texxform,
624+ nux::Color::White,
625+ false,
626+ rop);
627+
628+
629+ if (_title_tex)
630+ _title_tex->UnReference ();
631+
632+ _title_tex = texture2D;
633+
634+ g_free (label);
635+}
636+
637+void
638+PanelMenuView::OnActiveChanged (PanelIndicatorObjectEntryView *view,
639+ bool is_active)
640+{
641+ if (is_active)
642+ _last_active_view = view;
643+ else
644+ {
645+ if (_last_active_view == view)
646+ {
647+ _last_active_view = NULL;
648+ }
649+ }
650+ FullRedraw ();
651+}
652+
653+void
654+PanelMenuView::OnEntryAdded (IndicatorObjectEntryProxy *proxy)
655+{
656+ PanelIndicatorObjectEntryView *view = new PanelIndicatorObjectEntryView (proxy);
657+ view->active_changed.connect (sigc::mem_fun (this, &PanelMenuView::OnActiveChanged));
658+ _menu_layout->AddView (view, 0, nux::eCenter, nux::eFull);
659+ _menu_layout->SetContentDistribution (nux::eStackLeft);
660+
661+ _entries.push_back (view);
662+
663+ AddChild (view);
664+
665+ this->ComputeChildLayout ();
666+ NeedRedraw ();
667+}
668+
669+void
670+PanelMenuView::OnEntryMoved (IndicatorObjectEntryProxy *proxy)
671+{
672+ printf ("ERROR: Moving IndicatorObjectEntry not supported\n");
673+}
674+
675+void
676+PanelMenuView::OnEntryRemoved(IndicatorObjectEntryProxy *proxy)
677+{
678+ std::vector<PanelIndicatorObjectEntryView *>::iterator it;
679+
680+ for (it = _entries.begin(); it != _entries.end(); it++)
681+ {
682+ PanelIndicatorObjectEntryView *view = static_cast<PanelIndicatorObjectEntryView *> (*it);
683+ if (view->_proxy == proxy)
684+ {
685+ RemoveChild (view);
686+ _entries.erase (it);
687+ _menu_layout->RemoveChildObject (view);
688+
689+ break;
690+ }
691+ }
692+
693+ this->ComputeChildLayout ();
694+ NeedRedraw ();
695+}
696+
697+void
698+PanelMenuView::AllMenusClosed ()
699+{
700+ _is_inside = false;
701+ _last_active_view = false;
702+
703+ FullRedraw ();
704+}
705+
706+void
707+PanelMenuView::OnActiveWindowChanged (BamfView *old_view,
708+ BamfView *new_view)
709+{
710+ _is_maximized = false;
711+
712+ if (BAMF_IS_WINDOW (new_view))
713+ {
714+ BamfWindow *window = BAMF_WINDOW (new_view);
715+ _is_maximized = WindowManager::Default ()->IsWindowMaximized (bamf_window_get_xid (window));
716+ }
717+
718+ Refresh ();
719+ FullRedraw ();
720+}
721+
722+void
723+PanelMenuView::OnWindowUnmapped (guint32 xid)
724+{
725+ _decor_map.erase (xid);
726+}
727+
728+void
729+PanelMenuView::OnWindowMaximized (guint xid)
730+{
731+ BamfWindow *window;
732+
733+ window = bamf_matcher_get_active_window (_matcher);
734+ if (BAMF_IS_WINDOW (window) && bamf_window_get_xid (window) == xid)
735+ {
736+ // We could probably just check if a key is available, but who wants to do that
737+ if (_decor_map.find (xid) == _decor_map.end ())
738+ _decor_map[xid] = WindowManager::Default ()->IsWindowDecorated (xid);
739+
740+ if (_decor_map[xid])
741+ {
742+ WindowManager::Default ()->Undecorate (xid);
743+ }
744+
745+ _is_maximized = true;
746+
747+ Refresh ();
748+ FullRedraw ();
749+ }
750+}
751+
752+void
753+PanelMenuView::OnWindowRestored (guint xid)
754+{
755+ BamfWindow *window;
756+
757+ window = bamf_matcher_get_active_window (_matcher);
758+ if (BAMF_IS_WINDOW (window) && bamf_window_get_xid (window) == xid)
759+ {
760+ _is_maximized = false;
761+
762+ if (_decor_map[xid])
763+ {
764+ WindowManager::Default ()->Decorate (xid);
765+ }
766+
767+ Refresh ();
768+ FullRedraw ();
769+ }
770+}
771+
772+void
773+PanelMenuView::OnCloseClicked ()
774+{
775+ BamfWindow *window;
776+
777+ window = bamf_matcher_get_active_window (_matcher);
778+ if (BAMF_IS_WINDOW (window))
779+ WindowManager::Default ()->Close (bamf_window_get_xid (window));
780+}
781+
782+void
783+PanelMenuView::OnMinimizeClicked ()
784+{
785+ BamfWindow *window;
786+
787+ window = bamf_matcher_get_active_window (_matcher);
788+ if (BAMF_IS_WINDOW (window))
789+ WindowManager::Default ()->Minimize (bamf_window_get_xid (window));
790+}
791+
792+void
793+PanelMenuView::OnRestoreClicked ()
794+{
795+ BamfWindow *window;
796+
797+ window = bamf_matcher_get_active_window (_matcher);
798+ if (BAMF_IS_WINDOW (window))
799+ WindowManager::Default ()->Restore (bamf_window_get_xid (window));
800+}
801+
802+void
803+PanelMenuView::OnWindowButtonsRedraw ()
804+{
805+ FullRedraw ();
806+}
807+
808+// Introspectable
809+const gchar *
810+PanelMenuView::GetName ()
811+{
812+ return "MenuView";
813+}
814+
815+const gchar *
816+PanelMenuView::GetChildsName ()
817+{
818+ return "entries";
819+}
820+
821+void
822+PanelMenuView::AddProperties (GVariantBuilder *builder)
823+{
824+ nux::Geometry geo = GetGeometry ();
825+
826+ /* Now some props from ourselves */
827+ g_variant_builder_add (builder, "{sv}", "x", g_variant_new_int32 (geo.x));
828+ g_variant_builder_add (builder, "{sv}", "y", g_variant_new_int32 (geo.y));
829+ g_variant_builder_add (builder, "{sv}", "width", g_variant_new_int32 (geo.width));
830+ g_variant_builder_add (builder, "{sv}", "height", g_variant_new_int32 (geo.height));
831+}
832+
833+/*
834+ * C code for callbacks
835+ */
836+static void
837+on_active_window_changed (BamfMatcher *matcher,
838+ BamfView *old_view,
839+ BamfView *new_view,
840+ PanelMenuView *self)
841+{
842+ self->OnActiveWindowChanged (old_view, new_view);
843+}
844
845=== added file 'src/PanelMenuView.h'
846--- src/PanelMenuView.h 1970-01-01 00:00:00 +0000
847+++ src/PanelMenuView.h 2010-12-17 10:43:24 +0000
848@@ -0,0 +1,103 @@
849+/*
850+ * Copyright (C) 2010 Canonical Ltd
851+ *
852+ * This program is free software: you can redistribute it and/or modify
853+ * it under the terms of the GNU General Public License version 3 as
854+ * published by the Free Software Foundation.
855+ *
856+ * This program is distributed in the hope that it will be useful,
857+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
858+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
859+ * GNU General Public License for more details.
860+ *
861+ * You should have received a copy of the GNU General Public License
862+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
863+ *
864+ * Authored by: Neil Jagdish Patel <neil.patel@canonical.com>
865+ */
866+
867+#ifndef PANEL_MENU_VIEW_H
868+#define PANEL_MENU_VIEW_H
869+
870+#include <Nux/View.h>
871+#include <map>
872+
873+#include "IndicatorObjectProxy.h"
874+#include "Introspectable.h"
875+#include "PanelIndicatorObjectView.h"
876+#include "StaticCairoText.h"
877+#include "WindowButtons.h"
878+
879+#include <libbamf/libbamf.h>
880+
881+class PanelMenuView : public PanelIndicatorObjectView
882+{
883+public:
884+ // This contains all the menubar logic for the Panel. Mainly it contains
885+ // the following states:
886+ // 1. Unmaximized window + no mouse hover
887+ // 2. Unmaximized window + mouse hover
888+ // 3. Unmaximized window + active menu (Alt+F/arrow key nav)
889+ // 4. Maximized window + no mouse hover
890+ // 5. Maximized window + mouse hover
891+ // 6. Maximized window + active menu
892+ //
893+ // It also deals with undecorating maximized windows (and redecorating them
894+ // on unmaximize)
895+
896+ PanelMenuView ();
897+ ~PanelMenuView ();
898+
899+ void FullRedraw ();
900+
901+ virtual long ProcessEvent (nux::IEvent &ievent, long TraverseInfo, long ProcessEventInfo);
902+ virtual void Draw (nux::GraphicsEngine& GfxContext, bool force_draw);
903+ virtual void DrawContent (nux::GraphicsEngine &GfxContext, bool force_draw);
904+ virtual long PostLayoutManagement (long LayoutResult);
905+
906+ void SetProxy (IndicatorObjectProxy *proxy);
907+
908+ void OnEntryAdded (IndicatorObjectEntryProxy *proxy);
909+ void OnEntryMoved (IndicatorObjectEntryProxy *proxy);
910+ void OnEntryRemoved (IndicatorObjectEntryProxy *proxy);
911+ void OnActiveChanged (PanelIndicatorObjectEntryView *view, bool is_active);
912+ void OnActiveWindowChanged (BamfView *old_view, BamfView *new_view);
913+
914+ void OnWindowUnmapped (guint xid);
915+ void OnWindowMaximized (guint32 xid);
916+ void OnWindowRestored (guint32 xid);
917+
918+ void Refresh ();
919+ void AllMenusClosed ();
920+
921+ void OnCloseClicked ();
922+ void OnMinimizeClicked ();
923+ void OnRestoreClicked ();
924+ void OnWindowButtonsRedraw ();
925+
926+protected:
927+ const gchar * GetName ();
928+ const gchar * GetChildsName ();
929+ void AddProperties (GVariantBuilder *builder);
930+
931+private:
932+ gchar * GetActiveViewName ();
933+
934+private:
935+ BamfMatcher* _matcher;
936+
937+ nux::AbstractPaintLayer *_title_layer;
938+ nux::HLayout *_menu_layout;
939+ nux::CairoGraphics _util_cg;
940+ nux::IntrusiveSP<nux::IOpenGLBaseTexture> _gradient_texture;
941+ nux::BaseTexture *_title_tex;
942+
943+ bool _is_inside;
944+ bool _is_maximized;
945+ PanelIndicatorObjectEntryView *_last_active_view;
946+
947+ WindowButtons *_window_buttons;
948+
949+ std::map<guint32, bool> _decor_map;
950+};
951+#endif
952
953=== modified file 'src/PanelView.cpp'
954--- src/PanelView.cpp 2010-12-09 17:58:53 +0000
955+++ src/PanelView.cpp 2010-12-17 10:43:24 +0000
956@@ -46,13 +46,17 @@
957 // Home button
958 _home_button = new PanelHomeButton ();
959 _layout->AddView (_home_button, 0, nux::eCenter, nux::eFull);
960-
961 AddChild (_home_button);
962
963+ _menu_view = new PanelMenuView ();
964+ _layout->AddView (_menu_view, 1, nux::eCenter, nux::eFull);
965+ AddChild (_menu_view);
966+
967 _remote = new IndicatorObjectFactoryRemote ();
968 _remote->OnObjectAdded.connect (sigc::mem_fun (this, &PanelView::OnObjectAdded));
969 _remote->OnMenuPointerMoved.connect (sigc::mem_fun (this, &PanelView::OnMenuPointerMoved));
970 _remote->OnEntryActivateRequest.connect (sigc::mem_fun (this, &PanelView::OnEntryActivateRequest));
971+ _remote->IndicatorObjectFactory::OnEntryActivated.connect (sigc::mem_fun (this, &PanelView::OnEntryActivated));
972 }
973
974 PanelView::~PanelView ()
975@@ -204,7 +208,11 @@
976
977 // Appmenu is treated differently as it needs to expand
978 // We could do this in a more special way, but who has the time for special?
979- _layout->AddView (view, (g_strstr_len (proxy->GetName ().c_str (), -1, "appmenu") != NULL), nux::eCenter, nux::eFull);
980+ if (g_strstr_len (proxy->GetName ().c_str (), -1, "appmenu") != NULL)
981+ _menu_view->SetProxy (proxy);
982+ else
983+ _layout->AddView (view, 0, nux::eCenter, nux::eFull);
984+
985 _layout->SetContentDistribution (nux::eStackLeft);
986
987 AddChild (view);
988@@ -224,40 +232,40 @@
989
990 if (x >= geo.x && x <= (geo.x + geo.width)
991 && y >= geo.y && y <= (geo.y + geo.height))
992+ {
993+ std::list<Area *>::iterator it;
994+
995+ std::list<Area *> my_children = _layout->GetChildren ();
996+ for (it = my_children.begin(); it != my_children.end(); it++)
997 {
998- std::list<Area *>::iterator it;
999+ PanelIndicatorObjectView *view = static_cast<PanelIndicatorObjectView *> (*it);
1000+
1001+ if (view->_layout == NULL)
1002+ continue;
1003
1004- std::list<Area *> my_children = _layout->GetChildren ();
1005- for (it = my_children.begin(); it != my_children.end(); it++)
1006+ geo = view->GetGeometry ();
1007+ if (x >= geo.x && x <= (geo.x + geo.width)
1008+ && y >= geo.y && y <= (geo.y + geo.height))
1009 {
1010- PanelIndicatorObjectView *view = static_cast<PanelIndicatorObjectView *> (*it);
1011-
1012- if (view->_layout == NULL)
1013- continue;
1014-
1015- geo = view->GetGeometry ();
1016- if (x >= geo.x && x <= (geo.x + geo.width)
1017- && y >= geo.y && y <= (geo.y + geo.height))
1018+ std::list<Area *>::iterator it2;
1019+
1020+ std::list<Area *> its_children = view->_layout->GetChildren ();
1021+ for (it2 = its_children.begin(); it2 != its_children.end(); it2++)
1022+ {
1023+ PanelIndicatorObjectEntryView *entry = static_cast<PanelIndicatorObjectEntryView *> (*it2);
1024+
1025+ geo = entry->GetGeometry ();
1026+ if (x >= geo.x && x <= (geo.x + geo.width)
1027+ && y >= geo.y && y <= (geo.y + geo.height))
1028 {
1029- std::list<Area *>::iterator it2;
1030-
1031- std::list<Area *> its_children = view->_layout->GetChildren ();
1032- for (it2 = its_children.begin(); it2 != its_children.end(); it2++)
1033- {
1034- PanelIndicatorObjectEntryView *entry = static_cast<PanelIndicatorObjectEntryView *> (*it2);
1035-
1036- geo = entry->GetGeometry ();
1037- if (x >= geo.x && x <= (geo.x + geo.width)
1038- && y >= geo.y && y <= (geo.y + geo.height))
1039- {
1040- entry->OnMouseDown (x, y, 0, 0);
1041- break;
1042- }
1043- }
1044+ entry->OnMouseDown (x, y, 0, 0);
1045 break;
1046 }
1047+ }
1048+ break;
1049 }
1050 }
1051+ }
1052 }
1053
1054 void
1055@@ -281,10 +289,18 @@
1056 PanelIndicatorObjectEntryView *entry = static_cast<PanelIndicatorObjectEntryView *> (*it2);
1057
1058 if (g_strcmp0 (entry->GetName (), entry_id) == 0)
1059- {
1060- entry->Activate ();
1061- break;
1062- }
1063+ {
1064+ g_debug ("%s: Activating: %s", G_STRFUNC, entry_id);
1065+ entry->Activate ();
1066+ break;
1067+ }
1068 }
1069 }
1070 }
1071+
1072+void
1073+PanelView::OnEntryActivated (const char *entry_id)
1074+{
1075+ if (g_strcmp0 (entry_id, "") == 0)
1076+ _menu_view->AllMenusClosed ();
1077+}
1078
1079=== modified file 'src/PanelView.h'
1080--- src/PanelView.h 2010-12-07 13:55:04 +0000
1081+++ src/PanelView.h 2010-12-17 10:43:24 +0000
1082@@ -24,6 +24,7 @@
1083 #include <NuxGraphics/GraphicsEngine.h>
1084
1085 #include "PanelHomeButton.h"
1086+#include "PanelMenuView.h"
1087 #include "IndicatorObjectFactoryRemote.h"
1088 #include "Introspectable.h"
1089
1090@@ -43,6 +44,7 @@
1091 void OnObjectAdded (IndicatorObjectProxy *proxy);
1092 void OnMenuPointerMoved (int x, int y);
1093 void OnEntryActivateRequest (const char *entry_id);
1094+ void OnEntryActivated (const char *entry_id);
1095
1096 PanelHomeButton * HomeButton ();
1097
1098@@ -59,6 +61,7 @@
1099 IndicatorObjectFactoryRemote *_remote;
1100
1101 PanelHomeButton *_home_button;
1102+ PanelMenuView *_menu_view;
1103 nux::AbstractPaintLayer *_bg_layer;
1104 nux::HLayout *_layout;
1105
1106
1107=== modified file 'src/PluginAdapter.cpp'
1108--- src/PluginAdapter.cpp 2010-12-17 10:03:18 +0000
1109+++ src/PluginAdapter.cpp 2010-12-17 10:43:24 +0000
1110@@ -65,9 +65,15 @@
1111 PluginAdapter::NotifyStateChange (CompWindow *window, unsigned int state, unsigned int last_state)
1112 {
1113 if (!(last_state & MAXIMIZE_STATE) && (state & MAXIMIZE_STATE))
1114- window_maximized.emit (window);
1115+ {
1116+ PluginAdapter::window_maximized.emit (window);
1117+ WindowManager::window_maximized.emit (window->id ());
1118+ }
1119 else if ((last_state & MAXIMIZE_STATE) && !(state & MAXIMIZE_STATE))
1120- window_restored.emit (window);
1121+ {
1122+ PluginAdapter::window_restored.emit (window);
1123+ WindowManager::window_restored.emit (window->id ());
1124+ }
1125 }
1126
1127 void
1128@@ -94,10 +100,12 @@
1129 window_shown.emit (window);
1130 break;
1131 case CompWindowNotifyMap:
1132- window_mapped.emit (window);
1133+ PluginAdapter::window_mapped.emit (window);
1134+ WindowManager::window_mapped.emit (window->id ());
1135 break;
1136 case CompWindowNotifyUnmap:
1137- window_unmapped.emit (window);
1138+ PluginAdapter::window_unmapped.emit (window);
1139+ WindowManager::window_unmapped.emit (window->id ());
1140 break;
1141 default:
1142 break;
1143@@ -216,3 +224,68 @@
1144
1145 m_ExpoAction->initiate () (m_ExpoAction, 0, argument);
1146 }
1147+
1148+// WindowManager implementation
1149+bool
1150+PluginAdapter::IsWindowMaximized (guint xid)
1151+{
1152+ Window win = (Window)xid;
1153+ CompWindow *window;
1154+
1155+ window = m_Screen->findWindow (win);
1156+ if (window)
1157+ {
1158+ return window->state () & MAXIMIZE_STATE;
1159+ }
1160+
1161+ return false;
1162+}
1163+
1164+bool
1165+PluginAdapter::IsWindowDecorated (guint32 xid)
1166+{
1167+ Window win = (Window)xid;
1168+ CompWindow *window;
1169+
1170+ window = m_Screen->findWindow (win);
1171+ if (window)
1172+ {
1173+ unsigned int decor = window->mwmDecor ();
1174+
1175+ return decor & (MwmDecorAll | MwmDecorTitle);
1176+ }
1177+ return true;
1178+}
1179+
1180+void
1181+PluginAdapter::Restore (guint32 xid)
1182+{
1183+ Window win = (Window)xid;
1184+ CompWindow *window;
1185+
1186+ window = m_Screen->findWindow (win);
1187+ if (window)
1188+ window->maximize (0);
1189+}
1190+
1191+void
1192+PluginAdapter::Minimize (guint32 xid)
1193+{
1194+ Window win = (Window)xid;
1195+ CompWindow *window;
1196+
1197+ window = m_Screen->findWindow (win);
1198+ if (window)
1199+ window->minimize ();
1200+}
1201+
1202+void
1203+PluginAdapter::Close (guint32 xid)
1204+{
1205+ Window win = (Window)xid;
1206+ CompWindow *window;
1207+
1208+ window = m_Screen->findWindow (win);
1209+ if (window)
1210+ window->close (CurrentTime);
1211+}
1212
1213=== modified file 'src/PluginAdapter.h'
1214--- src/PluginAdapter.h 2010-12-17 10:03:18 +0000
1215+++ src/PluginAdapter.h 2010-12-17 10:43:24 +0000
1216@@ -24,7 +24,9 @@
1217
1218 #include <sigc++/sigc++.h>
1219
1220-class PluginAdapter : public sigc::trackable
1221+#include "WindowManager.h"
1222+
1223+class PluginAdapter : public sigc::trackable, public WindowManager
1224 {
1225 public:
1226 static PluginAdapter * Default ();
1227@@ -52,6 +54,13 @@
1228 void NotifyResized (CompWindow *window, int x, int y, int w, int h);
1229 void NotifyStateChange (CompWindow *window, unsigned int state, unsigned int last_state);
1230
1231+ // WindowManager implementation
1232+ bool IsWindowMaximized (guint xid);
1233+ bool IsWindowDecorated (guint xid);
1234+ void Restore (guint32 xid);
1235+ void Minimize (guint32 xid);
1236+ void Close (guint32 xid);
1237+
1238 sigc::signal<void, CompWindow *> window_maximized;
1239 sigc::signal<void, CompWindow *> window_restored;
1240 sigc::signal<void, CompWindow *> window_minimized;
1241
1242=== added file 'src/WindowButtons.cpp'
1243--- src/WindowButtons.cpp 1970-01-01 00:00:00 +0000
1244+++ src/WindowButtons.cpp 2010-12-17 10:43:24 +0000
1245@@ -0,0 +1,254 @@
1246+/*
1247+ * Copyright (C) 2010 Canonical Ltd
1248+ *
1249+ * This program is free software: you can redistribute it and/or modify
1250+ * it under the terms of the GNU General Public License version 3 as
1251+ * published by the Free Software Foundation.
1252+ *
1253+ * This program is distributed in the hope that it will be useful,
1254+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1255+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1256+ * GNU General Public License for more details.
1257+ *
1258+ * You should have received a copy of the GNU General Public License
1259+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1260+ *
1261+ * Authored by: Neil Jagdish Patel <neil.patel@canonical.com>
1262+ */
1263+
1264+#include "Nux/Nux.h"
1265+#include "Nux/HLayout.h"
1266+#include "Nux/VLayout.h"
1267+#include "Nux/Button.h"
1268+
1269+#include "NuxGraphics/GLThread.h"
1270+#include "Nux/BaseWindow.h"
1271+#include "Nux/WindowCompositor.h"
1272+
1273+#include "WindowButtons.h"
1274+
1275+#include <glib.h>
1276+
1277+
1278+// FIXME: This will be all automatic in the future
1279+#define AMBIANCE "/usr/share/themes/Ambiance/metacity-1"
1280+
1281+enum
1282+{
1283+ BUTTON_CLOSE=0,
1284+ BUTTON_MINIMISE,
1285+ BUTTON_UNMAXIMISE
1286+};
1287+
1288+class WindowButton : public nux::Button
1289+{
1290+ // A single window button
1291+public:
1292+ WindowButton (int type)
1293+ : nux::Button ("X", NUX_TRACKER_LOCATION),
1294+ _normal_tex (NULL),
1295+ _prelight_tex (NULL),
1296+ _pressed_tex (NULL)
1297+ {
1298+ if (type == BUTTON_CLOSE)
1299+ LoadImages ("close");
1300+ else if (type == BUTTON_MINIMISE)
1301+ LoadImages ("minimize");
1302+ else
1303+ LoadImages ("unmaximize");
1304+ }
1305+
1306+ ~WindowButton ()
1307+ {
1308+ _normal_tex->UnReference ();
1309+ _prelight_tex->UnReference ();
1310+ _pressed_tex->UnReference ();
1311+ }
1312+
1313+ void Draw (nux::GraphicsEngine &GfxContext, bool force_draw)
1314+ {
1315+ nux::Geometry geo = GetGeometry ();
1316+ nux::BaseTexture *tex;
1317+ nux::TexCoordXForm texxform;
1318+
1319+ GfxContext.PushClippingRectangle (geo);
1320+
1321+ if (HasMouseFocus ())
1322+ {
1323+ tex = _pressed_tex;
1324+ }
1325+ else if (IsMouseInside ())
1326+ {
1327+ tex = _prelight_tex;
1328+ }
1329+ else
1330+ {
1331+ tex = _normal_tex;
1332+ }
1333+
1334+ GfxContext.GetRenderStates ().SetSeparateBlend (true,
1335+ GL_SRC_ALPHA,
1336+ GL_ONE_MINUS_SRC_ALPHA,
1337+ GL_ONE_MINUS_DST_ALPHA,
1338+ GL_ONE);
1339+ GfxContext.GetRenderStates ().SetColorMask (true, true, true, true);
1340+ if (tex)
1341+ GfxContext.QRP_GLSL_1Tex (geo.x,
1342+ geo.y,
1343+ (float)geo.width,
1344+ (float)geo.height,
1345+ tex->GetDeviceTexture (),
1346+ texxform,
1347+ nux::Color::White);
1348+ GfxContext.GetRenderStates ().SetSeparateBlend (false,
1349+ GL_SRC_ALPHA,
1350+ GL_ONE_MINUS_SRC_ALPHA,
1351+ GL_ONE_MINUS_DST_ALPHA,
1352+ GL_ONE);
1353+ GfxContext.PopClippingRectangle();
1354+ }
1355+
1356+ void LoadImages (const char *name)
1357+ {
1358+ //FIXME: We need to somehow be theme aware. Or, at least support the themes
1359+ // we know and have a good default fallback
1360+ gchar *filename;
1361+ GError *error = NULL;
1362+ GdkPixbuf *_normal;
1363+ GdkPixbuf *_prelight;
1364+ GdkPixbuf *_pressed;
1365+
1366+ filename = g_strdup_printf ("%s/%s.png", AMBIANCE, name);
1367+ _normal = gdk_pixbuf_new_from_file (filename, &error);
1368+ if (error)
1369+ {
1370+ g_warning ("Unable to load window button %s: %s", filename, error->message);
1371+ g_error_free (error);
1372+ error = NULL;
1373+ }
1374+ else
1375+ _normal_tex = nux::CreateTextureFromPixbuf (_normal);
1376+ g_free (filename);
1377+ g_object_unref (_normal);
1378+
1379+ filename = g_strdup_printf ("%s/%s_focused_prelight.png", AMBIANCE, name);
1380+ _prelight = gdk_pixbuf_new_from_file (filename, &error);
1381+ if (error)
1382+ {
1383+ g_warning ("Unable to load window button %s: %s", filename, error->message);
1384+ g_error_free (error);
1385+ error = NULL;
1386+ }
1387+ else
1388+ _prelight_tex = nux::CreateTextureFromPixbuf (_prelight);
1389+ g_free (filename);
1390+ g_object_unref (_prelight);
1391+
1392+ filename = g_strdup_printf ("%s/%s_focused_pressed.png", AMBIANCE, name);
1393+ _pressed = gdk_pixbuf_new_from_file (filename, &error);
1394+ if (error)
1395+ {
1396+ g_warning ("Unable to load window button %s: %s", name, error->message);
1397+ g_error_free (error);
1398+ error = NULL;
1399+ }
1400+ else
1401+ _pressed_tex = nux::CreateTextureFromPixbuf (_pressed);
1402+ g_free (filename);
1403+ g_object_unref (_pressed);
1404+
1405+ if (_normal_tex)
1406+ SetMinimumSize (_normal_tex->GetWidth (), _normal_tex->GetHeight ());
1407+ }
1408+
1409+private:
1410+ nux::BaseTexture *_normal_tex;
1411+ nux::BaseTexture *_prelight_tex;
1412+ nux::BaseTexture *_pressed_tex;
1413+};
1414+
1415+
1416+WindowButtons::WindowButtons ()
1417+: HLayout ("", NUX_TRACKER_LOCATION)
1418+{
1419+ WindowButton *but;
1420+
1421+ but = new WindowButton (BUTTON_CLOSE);
1422+ AddView (but, 0, nux::eCenter, nux::eFix);
1423+ but->sigClick.connect (sigc::mem_fun (this, &WindowButtons::OnCloseClicked));
1424+ but->OnMouseEnter.connect (sigc::mem_fun (this, &WindowButtons::RecvMouseEnter));
1425+ but->OnMouseLeave.connect (sigc::mem_fun (this, &WindowButtons::RecvMouseLeave));
1426+
1427+ but = new WindowButton (BUTTON_MINIMISE);
1428+ AddView (but, 0, nux::eCenter, nux::eFix);
1429+ but->sigClick.connect (sigc::mem_fun (this, &WindowButtons::OnMinimizeClicked));
1430+ but->OnMouseEnter.connect (sigc::mem_fun (this, &WindowButtons::RecvMouseEnter));
1431+ but->OnMouseLeave.connect (sigc::mem_fun (this, &WindowButtons::RecvMouseLeave));
1432+
1433+ but = new WindowButton (BUTTON_UNMAXIMISE);
1434+ AddView (but, 0, nux::eCenter, nux::eFix);
1435+ but->sigClick.connect (sigc::mem_fun (this, &WindowButtons::OnRestoreClicked));
1436+ but->OnMouseEnter.connect (sigc::mem_fun (this, &WindowButtons::RecvMouseEnter));
1437+ but->OnMouseLeave.connect (sigc::mem_fun (this, &WindowButtons::RecvMouseLeave));
1438+
1439+ SetContentDistribution (nux::eStackLeft);
1440+}
1441+
1442+
1443+WindowButtons::~WindowButtons ()
1444+{
1445+}
1446+
1447+void
1448+WindowButtons::OnCloseClicked ()
1449+{
1450+ close_clicked.emit ();
1451+}
1452+
1453+void
1454+WindowButtons::OnMinimizeClicked ()
1455+{
1456+ minimize_clicked.emit ();
1457+}
1458+
1459+void
1460+WindowButtons::OnRestoreClicked ()
1461+{
1462+ restore_clicked.emit ();
1463+}
1464+
1465+const gchar *
1466+WindowButtons::GetName ()
1467+{
1468+ return "window-buttons";
1469+}
1470+
1471+const gchar *
1472+WindowButtons::GetChildsName ()
1473+{
1474+ return "";
1475+}
1476+
1477+void
1478+WindowButtons::AddProperties (GVariantBuilder *builder)
1479+{
1480+ nux::Geometry geo = GetGeometry ();
1481+
1482+ /* Now some props from ourselves */
1483+ g_variant_builder_add (builder, "{sv}", "x", g_variant_new_int32 (geo.x));
1484+ g_variant_builder_add (builder, "{sv}", "y", g_variant_new_int32 (geo.y));
1485+ g_variant_builder_add (builder, "{sv}", "width", g_variant_new_int32 (geo.width));
1486+ g_variant_builder_add (builder, "{sv}", "height", g_variant_new_int32 (geo.height));
1487+}
1488+
1489+void WindowButtons::RecvMouseEnter (int x, int y, unsigned long button_flags, unsigned long key_flags)
1490+{
1491+ redraw_signal.emit ();
1492+}
1493+
1494+void WindowButtons::RecvMouseLeave (int x, int y, unsigned long button_flags, unsigned long key_flags)
1495+{
1496+ redraw_signal.emit ();
1497+}
1498+
1499+
1500
1501=== added file 'src/WindowButtons.h'
1502--- src/WindowButtons.h 1970-01-01 00:00:00 +0000
1503+++ src/WindowButtons.h 2010-12-17 10:43:24 +0000
1504@@ -0,0 +1,63 @@
1505+/*
1506+ * Copyright (C) 2010 Canonical Ltd
1507+ *
1508+ * This program is free software: you can redistribute it and/or modify
1509+ * it under the terms of the GNU General Public License version 3 as
1510+ * published by the Free Software Foundation.
1511+ *
1512+ * This program is distributed in the hope that it will be useful,
1513+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1514+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1515+ * GNU General Public License for more details.
1516+ *
1517+ * You should have received a copy of the GNU General Public License
1518+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1519+ *
1520+ * Authored by: Neil Jagdish Patel <neil.patel@canonical.com>
1521+ */
1522+
1523+#ifndef WINDOW_BUTTONS_H
1524+#define WINDOW_BUTTONS_H
1525+
1526+#include <Nux/View.h>
1527+
1528+#include "Introspectable.h"
1529+
1530+class WindowButtons : public nux::HLayout, public Introspectable
1531+{
1532+ // These are the [close][minimize][restore] buttons on the panel when there
1533+ // is a maximized window
1534+
1535+public:
1536+ WindowButtons ();
1537+ ~WindowButtons ();
1538+
1539+ sigc::signal<void> close_clicked;
1540+ sigc::signal<void> minimize_clicked;
1541+ sigc::signal<void> restore_clicked;
1542+ sigc::signal<void> redraw_signal;
1543+
1544+protected:
1545+ const gchar * GetName ();
1546+ const gchar * GetChildsName ();
1547+ void AddProperties (GVariantBuilder *builder);
1548+
1549+
1550+ // For testing the buttons
1551+ void RecvMouseDown (int x, int y, unsigned long button_flags, unsigned long key_flags);
1552+ void RecvMouseUp (int x, int y, unsigned long button_flags, unsigned long key_flags);
1553+ void RecvMouseEnter (int x, int y, unsigned long button_flags, unsigned long key_flags);
1554+ void RecvMouseLeave (int x, int y, unsigned long button_flags, unsigned long key_flags);
1555+ void RecvMouseClick (int x, int y, unsigned long button_flags, unsigned long key_flags);
1556+ void RecvMouseMove (int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags);
1557+
1558+private:
1559+ void OnCloseClicked ();
1560+ void OnMinimizeClicked ();
1561+ void OnRestoreClicked ();
1562+
1563+private:
1564+ nux::HLayout *_layout;
1565+};
1566+
1567+#endif
1568
1569=== added file 'src/WindowManager.cpp'
1570--- src/WindowManager.cpp 1970-01-01 00:00:00 +0000
1571+++ src/WindowManager.cpp 2010-12-17 10:43:24 +0000
1572@@ -0,0 +1,171 @@
1573+/*
1574+ * Copyright (C) 2010 Canonical Ltd
1575+ *
1576+ * This program is free software: you can redistribute it and/or modify
1577+ * it under the terms of the GNU General Public License version 3 as
1578+ * published by the Free Software Foundation.
1579+ *
1580+ * This program is distributed in the hope that it will be useful,
1581+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1582+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1583+ * GNU General Public License for more details.
1584+ *
1585+ * You should have received a copy of the GNU General Public License
1586+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1587+ *
1588+ * Authored by: Neil Jagdish Patel <neil.patel@canonical.com>
1589+ */
1590+
1591+#include "WindowManager.h"
1592+
1593+#include <gdk/gdkx.h>
1594+
1595+typedef struct {
1596+ unsigned long flags;
1597+ unsigned long functions;
1598+ unsigned long decorations;
1599+ long input_mode;
1600+ unsigned long status;
1601+} MotifWmHints, MwmHints;
1602+
1603+#define MWM_HINTS_FUNCTIONS (1L << 0)
1604+#define MWM_HINTS_DECORATIONS (1L << 1)
1605+#define _XA_MOTIF_WM_HINTS "_MOTIF_WM_HINTS"
1606+
1607+static void gdk_window_set_mwm_hints (Window xid,
1608+ MotifWmHints *new_hints);
1609+
1610+
1611+static WindowManager *window_manager = NULL;
1612+
1613+class WindowManagerDummy : public WindowManager
1614+{
1615+ bool IsWindowMaximized (guint32 xid)
1616+ {
1617+ return false;
1618+ }
1619+
1620+ bool IsWindowDecorated (guint32 xid)
1621+ {
1622+ return true;
1623+ }
1624+
1625+ void Restore (guint32 xid)
1626+ {
1627+ g_debug ("%s", G_STRFUNC);
1628+ }
1629+
1630+ void Minimize (guint32 xid)
1631+ {
1632+ g_debug ("%s", G_STRFUNC);
1633+ }
1634+
1635+ void Close (guint32 xid)
1636+ {
1637+ g_debug ("%s", G_STRFUNC);
1638+ }
1639+};
1640+
1641+WindowManager *
1642+WindowManager::Default ()
1643+{
1644+ if (!window_manager)
1645+ window_manager = new WindowManagerDummy ();
1646+
1647+ return window_manager;
1648+}
1649+
1650+void
1651+WindowManager::SetDefault (WindowManager *manager)
1652+{
1653+ window_manager = manager;
1654+}
1655+
1656+void
1657+WindowManager::Decorate (guint32 xid)
1658+{
1659+ MotifWmHints hints = { 0 };
1660+
1661+ hints.flags = MWM_HINTS_DECORATIONS;
1662+ hints.decorations = GDK_DECOR_ALL;
1663+
1664+ gdk_window_set_mwm_hints (xid, &hints);
1665+}
1666+
1667+void
1668+WindowManager::Undecorate (guint32 xid)
1669+{
1670+ MotifWmHints hints = { 0 };
1671+
1672+ hints.flags = MWM_HINTS_DECORATIONS;
1673+ hints.decorations = 0;
1674+
1675+ gdk_window_set_mwm_hints (xid, &hints);
1676+}
1677+
1678+/*
1679+ * Copied over C code
1680+ */
1681+static void
1682+gdk_window_set_mwm_hints (Window xid,
1683+ MotifWmHints *new_hints)
1684+{
1685+ GdkDisplay *display = gdk_display_get_default();
1686+ Atom hints_atom = None;
1687+ guchar *data = NULL;
1688+ MotifWmHints *hints = NULL;
1689+ Atom type = None;
1690+ gint format;
1691+ gulong nitems;
1692+ gulong bytes_after;
1693+
1694+ g_return_if_fail (GDK_IS_DISPLAY (display));
1695+
1696+ hints_atom = gdk_x11_get_xatom_by_name_for_display (display,
1697+ _XA_MOTIF_WM_HINTS);
1698+
1699+ gdk_error_trap_push ();
1700+ XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
1701+ xid,
1702+ hints_atom, 0, sizeof (MotifWmHints)/sizeof (long),
1703+ False, AnyPropertyType, &type, &format, &nitems,
1704+ &bytes_after, &data);
1705+ gdk_flush ();
1706+ if (gdk_error_trap_pop ())
1707+ {
1708+ g_debug ("ERROR: Cannot set decorations");
1709+ return;
1710+ }
1711+
1712+ if (type != hints_atom || !data)
1713+ hints = new_hints;
1714+ else
1715+ {
1716+ hints = (MotifWmHints *)data;
1717+
1718+ if (new_hints->flags & MWM_HINTS_FUNCTIONS)
1719+ {
1720+ hints->flags |= MWM_HINTS_FUNCTIONS;
1721+ hints->functions = new_hints->functions;
1722+ }
1723+ if (new_hints->flags & MWM_HINTS_DECORATIONS)
1724+ {
1725+ hints->flags |= MWM_HINTS_DECORATIONS;
1726+ hints->decorations = new_hints->decorations;
1727+ }
1728+ }
1729+
1730+ gdk_error_trap_push ();
1731+ XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
1732+ xid,
1733+ hints_atom, hints_atom, 32, PropModeReplace,
1734+ (guchar *)hints, sizeof (MotifWmHints)/sizeof (long));
1735+ gdk_flush ();
1736+ if (gdk_error_trap_pop ())
1737+ {
1738+ g_debug ("ERROR: Setting decorations");
1739+ }
1740+
1741+ if (data)
1742+ XFree (data);
1743+}
1744
1745=== added file 'src/WindowManager.h'
1746--- src/WindowManager.h 1970-01-01 00:00:00 +0000
1747+++ src/WindowManager.h 2010-12-17 10:43:24 +0000
1748@@ -0,0 +1,57 @@
1749+/*
1750+ * Copyright (C) 2010 Canonical Ltd
1751+ *
1752+ * This program is free software: you can redistribute it and/or modify
1753+ * it under the terms of the GNU General Public License version 3 as
1754+ * published by the Free Software Foundation.
1755+ *
1756+ * This program is distributed in the hope that it will be useful,
1757+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1758+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1759+ * GNU General Public License for more details.
1760+ *
1761+ * You should have received a copy of the GNU General Public License
1762+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1763+ *
1764+ * Authored by: Neil Jagdish Patel <neil.patel@canonical.com>
1765+ */
1766+
1767+#ifndef WINDOW_MANAGER_H
1768+#define WINDOW_MANAGER_H
1769+
1770+#include <glib.h>
1771+#include <sigc++/sigc++.h>
1772+
1773+class WindowManager
1774+{
1775+ // This is a glue interface that breaks the dependancy of Unity with Compiz
1776+ // Basically it has a default implementation that does nothing useful, but
1777+ // the idea is that unity.cpp uses SetDefault() early enough in it's
1778+ // initialization so the things that require it get a usable implementation
1779+ //
1780+ // Currently only the Panel uses it but hopefully we'll get more of
1781+ // PluginAdaptor features moved into here and also get the Launcher to use
1782+ // it.
1783+
1784+public:
1785+ static WindowManager * Default ();
1786+ static void SetDefault (WindowManager *manager);
1787+
1788+ virtual bool IsWindowMaximized (guint32 xid) = 0;
1789+ virtual bool IsWindowDecorated (guint32 xid) = 0;
1790+
1791+ virtual void Restore (guint32 xid) = 0;
1792+ virtual void Minimize (guint32 xid) = 0;
1793+ virtual void Close (guint32 xid) = 0;
1794+
1795+ virtual void Decorate (guint32 xid);
1796+ virtual void Undecorate (guint32 xid);
1797+
1798+ // Signals
1799+ sigc::signal<void, guint32> window_mapped;
1800+ sigc::signal<void, guint32> window_unmapped;
1801+ sigc::signal<void, guint32> window_maximized;
1802+ sigc::signal<void, guint32> window_restored;
1803+};
1804+
1805+#endif // WINDOW_MANAGER_H
1806
1807=== modified file 'src/unity.cpp'
1808--- src/unity.cpp 2010-12-16 21:07:28 +0000
1809+++ src/unity.cpp 2010-12-17 10:43:24 +0000
1810@@ -395,6 +395,8 @@
1811 GLScreenInterface::setHandler (gScreen);
1812
1813 PluginAdapter::Initialize (screen);
1814+ WindowManager::SetDefault (PluginAdapter::Default ());
1815+
1816 StartupNotifyService::Default ()->SetSnDisplay (screen->snDisplay (), screen->screenNum ());
1817
1818 nux::NuxInitialize (0);
1819@@ -410,7 +412,6 @@
1820
1821 debugger = new IntrospectionDBusInterface (this);
1822
1823-
1824 optionSetLauncherAutohideNotify (boost::bind (&UnityScreen::optionChanged, this, _1, _2));
1825 optionSetLauncherFloatNotify (boost::bind (&UnityScreen::optionChanged, this, _1, _2));
1826
1827
1828=== modified file 'tests/CMakeLists.txt'
1829--- tests/CMakeLists.txt 2010-12-13 09:54:54 +0000
1830+++ tests/CMakeLists.txt 2010-12-17 10:43:24 +0000
1831@@ -82,6 +82,14 @@
1832 ../src/Introspectable.h
1833 ../src/PanelHomeButton.cpp
1834 ../src/PanelHomeButton.h
1835+ ../src/PanelMenuView.cpp
1836+ ../src/PanelMenuView.h
1837+ ../src/StaticCairoText.cpp
1838+ ../src/StaticCairoText.h
1839+ ../src/WindowButtons.cpp
1840+ ../src/WindowButtons.h
1841+ ../src/WindowManager.cpp
1842+ ../src/WindowManager.h
1843 ../libunity/ubus-server.c
1844 ../libunity/ubus-server.h
1845 )