Back to index

unity  6.0.0
PanelTray.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2010-2012 Canonical Ltd
00003  *
00004  * This program is free software: you can redistribute it and/or modify
00005  * it under the terms of the GNU General Public License version 3 as
00006  * published by the Free Software Foundation.
00007  *
00008  * This program is distributed in the hope that it will be useful,
00009  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00010  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011  * GNU General Public License for more details.
00012  *
00013  * You should have received a copy of the GNU General Public License
00014  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00015  *
00016  * Authored by: Neil Jagdish Patel <neil.patel@canonical.com>
00017  *              Marco Trevisan (TreviƱo) <3v1n0@ubuntu.com>
00018  */
00019 
00020 #include "PanelTray.h"
00021 #include "unity-shared/PanelStyle.h"
00022 
00023 #include <NuxCore/Logger.h>
00024 #include <UnityCore/Variant.h>
00025 
00026 namespace
00027 {
00028 nux::logging::Logger logger("unity.panel");
00029 const std::string SETTINGS_NAME = "com.canonical.Unity.Panel";
00030 const int PADDING = 3;
00031 }
00032 
00033 namespace unity
00034 {
00035 
00036 PanelTray::PanelTray()
00037   : View(NUX_TRACKER_LOCATION)
00038   , settings_(g_settings_new(SETTINGS_NAME.c_str()))
00039   , window_(gtk_window_new(GTK_WINDOW_TOPLEVEL))
00040   , whitelist_(g_settings_get_strv(settings_, "systray-whitelist"))
00041 {
00042   int panel_height = panel::Style::Instance().panel_height;
00043 
00044   whitelist_changed_.Connect(settings_, "changed::systray-whitelist", [&] (GSettings*, gchar*) {
00045     g_strfreev(whitelist_);
00046     whitelist_ = g_settings_get_strv(settings_, "systray-whitelist");
00047   });
00048 
00049   auto gtkwindow = glib::object_cast<GtkWindow>(window_);
00050   gtk_window_set_type_hint(gtkwindow, GDK_WINDOW_TYPE_HINT_DOCK);
00051   gtk_window_set_has_resize_grip(gtkwindow, FALSE);
00052   gtk_window_set_keep_above(gtkwindow, TRUE);
00053   gtk_window_set_skip_pager_hint(gtkwindow, TRUE);
00054   gtk_window_set_skip_taskbar_hint(gtkwindow, TRUE);
00055   gtk_window_resize(gtkwindow, 1, panel_height);
00056   gtk_window_move(gtkwindow, -panel_height,-panel_height);
00057   gtk_widget_set_name(window_, "UnityPanelApplet");
00058 
00059   gtk_widget_set_visual(window_, gdk_screen_get_rgba_visual(gdk_screen_get_default()));
00060   gtk_widget_realize(window_);
00061   gtk_widget_set_app_paintable(window_, TRUE);
00062   draw_signal_.Connect(window_, "draw", sigc::mem_fun(this, &PanelTray::OnTrayDraw));
00063 
00064   if (!g_getenv("UNITY_PANEL_TRAY_DISABLE"))
00065   {
00066     tray_ = na_tray_new_for_screen(gdk_screen_get_default(),
00067                                    GTK_ORIENTATION_HORIZONTAL,
00068                                    (NaTrayFilterCallback)FilterTrayCallback,
00069                                    this);
00070     na_tray_set_icon_size(tray_, panel_height);
00071 
00072     icon_removed_signal_.Connect(na_tray_get_manager(tray_), "tray_icon_removed",
00073                                  sigc::mem_fun(this, &PanelTray::OnTrayIconRemoved));
00074 
00075     gtk_container_add(GTK_CONTAINER(window_.RawPtr()), GTK_WIDGET(tray_.RawPtr()));
00076     gtk_widget_show(GTK_WIDGET(tray_.RawPtr()));
00077   }
00078 
00079   SetMinMaxSize(1, panel_height);
00080 }
00081 
00082 PanelTray::~PanelTray()
00083 {
00084   g_strfreev(whitelist_);
00085 
00086   if (gtk_widget_get_realized(window_))
00087   {
00088     // We call Release since we're deleting the window here manually,
00089     // and we don't want the smart pointer to try and delete it as well.
00090     gtk_widget_destroy(window_.Release());
00091   }
00092 }
00093 
00094 Window PanelTray::xid()
00095 {
00096   if (!window_)
00097     return 0;
00098 
00099   return gdk_x11_window_get_xid(gtk_widget_get_window(window_));
00100 }
00101 
00102 void PanelTray::Draw(nux::GraphicsEngine& gfx_context, bool force_draw)
00103 {
00104   nux::Geometry const& geo = GetAbsoluteGeometry();
00105 
00106   gfx_context.PushClippingRectangle(geo);
00107   nux::GetPainter().PaintBackground(gfx_context, geo);
00108   gfx_context.PopClippingRectangle();
00109 
00110   if (geo != last_geo_)
00111   {
00112     last_geo_ = geo;
00113     gtk_window_move(GTK_WINDOW(window_.RawPtr()), geo.x + PADDING, geo.y);
00114   }
00115 }
00116 
00117 void PanelTray::Sync()
00118 {
00119   if (tray_)
00120   {
00121     SetMinMaxSize(WidthOfTray() + (PADDING * 2), panel::Style::Instance().panel_height);
00122     QueueRelayout();
00123     QueueDraw();
00124 
00125     if (!children_.empty())
00126       gtk_widget_show(window_);
00127     else
00128       gtk_widget_hide(window_);
00129   }
00130 }
00131 
00132 gboolean PanelTray::FilterTrayCallback(NaTray* tray, NaTrayChild* icon, PanelTray* self)
00133 {
00134   int i = 0;
00135   bool accept = false;
00136   const char *name = nullptr;
00137 
00138   glib::String title(na_tray_child_get_title(icon));
00139 
00140   glib::String res_class;
00141   glib::String res_name;
00142   na_tray_child_get_wm_class(icon, &res_name, &res_class);
00143 
00144   while ((name = self->whitelist_[i]))
00145   {
00146     if (g_strcmp0(name, "all") == 0)
00147     {
00148       accept = true;
00149       break;
00150     }
00151     else if (!name || name[0] == '\0')
00152     {
00153       accept = false;
00154       break;
00155     }
00156     else if ((title && g_str_has_prefix(title, name))
00157              || (res_name && g_str_has_prefix(res_name, name))
00158              || (res_class && g_str_has_prefix(res_class, name)))
00159     {
00160       accept = true;
00161       break;
00162     }
00163 
00164     i++;
00165   }
00166 
00167   if (accept)
00168   {
00169     if (na_tray_child_has_alpha(icon))
00170       na_tray_child_set_composited(icon, TRUE);
00171 
00172     self->children_.push_back(icon);
00173     self->sync_idle_.reset(new glib::Idle(sigc::mem_fun(self, &PanelTray::IdleSync)));
00174   }
00175 
00176   LOG_DEBUG(logger) << "TrayChild "
00177                     << (accept ? "Accepted: " : "Rejected: ")
00178                     << na_tray_child_get_title(icon) << " "
00179                     << res_name << " " << res_class;
00180 
00181   return accept ? TRUE : FALSE;
00182 }
00183 
00184 void PanelTray::OnTrayIconRemoved(NaTrayManager* manager, NaTrayChild* removed)
00185 {
00186   for (auto child : children_)
00187   {
00188     if (child == removed)
00189     {
00190       sync_idle_.reset(new glib::Idle(sigc::mem_fun(this, &PanelTray::IdleSync)));
00191       children_.remove(child);
00192       break;
00193     }
00194   }
00195 }
00196 
00197 bool PanelTray::IdleSync()
00198 {
00199   int width = WidthOfTray();
00200   gtk_window_resize(GTK_WINDOW(window_.RawPtr()), width, panel::Style::Instance().panel_height);
00201   Sync();
00202 
00203   return false;
00204 }
00205 
00206 int PanelTray::WidthOfTray()
00207 {
00208   int width = 0;
00209   for (auto child: children_)
00210   {
00211     int w = gtk_widget_get_allocated_width(GTK_WIDGET(child));
00212     width += w > 24 ? w : 24;
00213   }
00214   return width;
00215 }
00216 
00217 gboolean PanelTray::OnTrayDraw(GtkWidget* widget, cairo_t* cr)
00218 {
00219   GtkAllocation alloc;
00220 
00221   gtk_widget_get_allocation(widget, &alloc);
00222 
00223   cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
00224   cairo_paint(cr);
00225 
00226   cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
00227   cairo_set_source_rgba(cr, 0.0f, 0.0f, 0.0f, 0.0f);
00228   cairo_rectangle(cr, 0, 0, alloc.width, alloc.height);
00229   cairo_fill(cr);
00230 
00231   gtk_container_propagate_draw(GTK_CONTAINER(widget),
00232                                gtk_bin_get_child(GTK_BIN(widget)),
00233                                cr);
00234 
00235   return FALSE;
00236 }
00237 
00238 std::string PanelTray::GetName() const
00239 {
00240   return "Tray";
00241 }
00242 
00243 void PanelTray::AddProperties(GVariantBuilder* builder)
00244 {
00245   variant::BuilderWrapper(builder)
00246   .add(GetAbsoluteGeometry())
00247   .add("children_count", children_.size());
00248 }
00249 
00250 } // namespace unity