Beispiel #1
0
/* The plug window should completely occupy the area of the child, so we won't
 * get an expose event. But in case we do (the plug unmaps itself, say), this
 * expose handler draws with real or fake transparency.
 */
static gboolean
na_tray_child_expose_event (GtkWidget      *widget,
                            GdkEventExpose *event)
{
  NaTrayChild *child = NA_TRAY_CHILD (widget);
  GdkWindow *window = gtk_widget_get_window (widget);

  if (na_tray_child_has_alpha (child))
    {
      /* Clear to transparent */
      cairo_t *cr = gdk_cairo_create (window);
      cairo_set_source_rgba (cr, 0, 0, 0, 0);
      cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
      gdk_cairo_region (cr, event->region);
      cairo_fill (cr);
      cairo_destroy (cr);
    }
  else if (child->parent_relative_bg)
    {
      /* Clear to parent-relative pixmap */
      gdk_window_clear_area (window,
                             event->area.x, event->area.y,
                             event->area.width, event->area.height);
    }

  return FALSE;
}
Beispiel #2
0
static void
cinnamon_tray_manager_child_on_realize (GtkWidget             *widget,
                                     CinnamonTrayManagerChild *child)
{
  /* If the tray child is using an RGBA colormap (and so we have real
   * transparency), we don't need to worry about the background. If
   * not, we obey the bg-color property by creating a cairo pattern of
   * that color and setting it as our background. Then "parent-relative"
   * background on the socket and the plug within that will cause
   * the icons contents to appear on top of our background color.
   */
  if (!na_tray_child_has_alpha (NA_TRAY_CHILD (child->socket)))
    {
      ClutterColor color = child->manager->priv->bg_color;
      cairo_pattern_t *bg_pattern;

      bg_pattern = cairo_pattern_create_rgb (color.red / 255.,
                                             color.green / 255.,
                                             color.blue / 255.);
      gdk_window_set_background_pattern (gtk_widget_get_window (widget),
                                         bg_pattern);

      cairo_pattern_destroy (bg_pattern);
    }
}
Beispiel #3
0
na_tray_child_expose_event (GtkWidget      *widget,
                            GdkEventExpose *event)
#endif
{
  NaTrayChild *child = NA_TRAY_CHILD (widget);
  GdkWindow *window = gtk_widget_get_window (widget);

  if (na_tray_child_has_alpha (child))
    {
      /* Clear to transparent */
#if !GTK_CHECK_VERSION (3, 0, 0)
      cairo_t *cr = gdk_cairo_create (window);
#endif
      cairo_set_source_rgba (cr, 0, 0, 0, 0);
      cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
#if GTK_CHECK_VERSION (3, 0, 0)
      cairo_paint (cr);
#else
      gdk_cairo_region (cr, event->region);
      cairo_fill (cr);
      cairo_destroy (cr);
#endif
    }
  else if (child->parent_relative_bg)
    {
      /* Clear to parent-relative pixmap */
#if GTK_CHECK_VERSION (3, 0, 0)
      GdkWindow *window;
      cairo_surface_t *target;
      GdkRectangle clip_rect;

      window = gtk_widget_get_window (widget);
      target = cairo_get_group_target (cr);

      gdk_cairo_get_clip_rectangle (cr, &clip_rect);

      /* Clear to parent-relative pixmap
       * We need to use direct X access here because GDK doesn't know about
       * the parent relative pixmap. */
      cairo_surface_flush (target);

      XClearArea (GDK_WINDOW_XDISPLAY (window),
                  GDK_WINDOW_XID (window),
                  clip_rect.x, clip_rect.y,
                  clip_rect.width, clip_rect.height,
                  False);
      cairo_surface_mark_dirty_rectangle (target,
                                          clip_rect.x, clip_rect.y,
                                          clip_rect.width, clip_rect.height);
#else
      gdk_window_clear_area (window,
                             event->area.x, event->area.y,
                             event->area.width, event->area.height);
#endif
    }

  return FALSE;
}
Beispiel #4
0
static void
na_tray_child_size_allocate (GtkWidget      *widget,
                             GtkAllocation  *allocation)
{
  NaTrayChild *child = NA_TRAY_CHILD (widget);
  GtkAllocation widget_allocation;
  gboolean moved, resized;

  gtk_widget_get_allocation (widget, &widget_allocation);

  moved = (allocation->x != widget_allocation.x ||
	   allocation->y != widget_allocation.y);
  resized = (allocation->width != widget_allocation.width ||
	     allocation->height != widget_allocation.height);

  /* When we are allocating the widget while mapped we need special handling
   * for both real and fake transparency.
   *
   * Real transparency: we need to invalidate and trigger a redraw of the old
   *   and new areas. (GDK really should handle this for us, but doesn't as of
   *   GTK+-2.14)
   *
   * Fake transparency: if the widget moved, we need to force the contents to
   *   be redrawn with the new offset for the parent-relative background.
   */
  if ((moved || resized) && gtk_widget_get_mapped (widget))
    {
      if (na_tray_child_has_alpha (child))
        gdk_window_invalidate_rect (gdk_window_get_parent (gtk_widget_get_window (widget)),
                                    &widget_allocation, FALSE);
    }

  GTK_WIDGET_CLASS (na_tray_child_parent_class)->size_allocate (widget,
                                                                allocation);

  if ((moved || resized) && gtk_widget_get_mapped (widget))
    {
      if (na_tray_child_has_alpha (NA_TRAY_CHILD (widget)))
        gdk_window_invalidate_rect (gdk_window_get_parent (gtk_widget_get_window (widget)),
                                    &widget_allocation, FALSE);
      else if (moved && child->parent_relative_bg)
        na_tray_child_force_redraw (child);
    }
}
Beispiel #5
0
static void
na_tray_child_realize (GtkWidget *widget)
{
  NaTrayChild *child = NA_TRAY_CHILD (widget);
  GdkVisual *visual = gtk_widget_get_visual (widget);
  GdkWindow *window;

  GTK_WIDGET_CLASS (na_tray_child_parent_class)->realize (widget);

  window = gtk_widget_get_window (widget);

  if (child->has_alpha)
    {
      /* We have real transparency with an ARGB visual and the Composite
       * extension. */

      /* Set a transparent background */
      GdkColor transparent = { 0, 0, 0, 0 }; /* only pixel=0 matters */
      gdk_window_set_background (window, &transparent);
      gdk_window_set_composited (window, TRUE);

      child->parent_relative_bg = FALSE;
	}
	#if GTK_CHECK_VERSION(3, 0, 0)
		else if (visual == gdk_window_get_visual(gdk_window_get_parent(window)))
	#else
		else if (visual == gdk_drawable_get_visual(GDK_DRAWABLE(gdk_window_get_parent(window))))
	#endif
	{
      /* Otherwise, if the visual matches the visual of the parent window, we
       * can use a parent-relative background and fake transparency. */
      gdk_window_set_back_pixmap (window, NULL, TRUE);

      child->parent_relative_bg = TRUE;
    }
  else
    {
      /* Nothing to do; the icon will sit on top of an ugly gray box */
      child->parent_relative_bg = FALSE;
    }

  gdk_window_set_composited (window, child->composited);

  gtk_widget_set_app_paintable (GTK_WIDGET (child),
                                child->parent_relative_bg || child->has_alpha);

  /* Double-buffering will interfere with the parent-relative-background fake
   * transparency, since the double-buffer code doesn't know how to fill in the
   * background of the double-buffer correctly.
   */
  gtk_widget_set_double_buffered (GTK_WIDGET (child),
                                  child->parent_relative_bg);
}
static gboolean
na_tray_manager_plug_removed (GtkSocket       *socket,
			      NaTrayManager   *manager)
{
  NaTrayChild *child = NA_TRAY_CHILD (socket);

  g_hash_table_remove (manager->socket_table,
                       GINT_TO_POINTER (child->icon_window));
  g_signal_emit (manager, manager_signals[TRAY_ICON_REMOVED], 0, child);

  /* This destroys the socket. */
  return FALSE;
}
Beispiel #7
0
static void
na_tray_child_realize (GtkWidget *widget)
{
  NaTrayChild *child = NA_TRAY_CHILD (widget);
  GdkVisual *visual = gtk_widget_get_visual (widget);
  GdkWindow *window;

  GTK_WIDGET_CLASS (na_tray_child_parent_class)->realize (widget);

  window = gtk_widget_get_window (widget);

  if (child->has_alpha)
    {
      /* We have real transparency with an ARGB visual and the Composite
       * extension. */

      /* Set a transparent background */
      cairo_pattern_t *transparent = cairo_pattern_create_rgba (0, 0, 0, 0);
      gdk_window_set_background_pattern (window, transparent);
      gdk_window_set_composited (window, TRUE);
      cairo_pattern_destroy (transparent);

      child->parent_relative_bg = FALSE;
    }
  else if (visual == gdk_window_get_visual (gdk_window_get_parent (window)))
    {
      /* Otherwise, if the visual matches the visual of the parent window, we
       * can use a parent-relative background and fake transparency. */
      gdk_window_set_background_pattern (window, NULL);

      child->parent_relative_bg = TRUE;
    }
  else
    {
      /* Nothing to do; the icon will sit on top of an ugly gray box */
      child->parent_relative_bg = FALSE;
    }

  gdk_window_set_composited (window, child->composited);

  gtk_widget_set_app_paintable (GTK_WIDGET (child),
                                child->parent_relative_bg || child->has_alpha);

  /* Double-buffering will interfere with the parent-relative-background fake
   * transparency, since the double-buffer code doesn't know how to fill in the
   * background of the double-buffer correctly.
   */
  gtk_widget_set_double_buffered (GTK_WIDGET (child),
                                  child->parent_relative_bg);
}
Beispiel #8
0
static void
cinnamon_tray_icon_constructed (GObject *object)
{
  GdkWindow *icon_app_window;
  CinnamonTrayIcon *icon = CINNAMON_TRAY_ICON (object);
  CinnamonEmbeddedWindow *window;
  GdkDisplay *display;
  Window plug_xid;
  Atom _NET_WM_PID, type;
  int result, format;
  gulong nitems, bytes_after, *val = NULL;

  /* We do all this now rather than computing it on the fly later,
   * because Cinnamon may want to see their values from a
   * tray-icon-removed signal handler, at which point the plug has
   * already been removed from the socket.
   */

  g_object_get (object, "window", &window, NULL);
  g_return_if_fail (window != NULL);
  icon->priv->socket = NA_TRAY_CHILD (gtk_bin_get_child (GTK_BIN (window)));
  g_object_unref (window);

  icon->priv->title = na_tray_child_get_title (icon->priv->socket);
  na_tray_child_get_wm_class (icon->priv->socket, NULL, &icon->priv->wm_class);

  icon_app_window = gtk_socket_get_plug_window (GTK_SOCKET (icon->priv->socket));
  if (icon_app_window == NULL)
    {
      g_warning ("cinnamon tray: icon app window is gone");
      return;
    }
  plug_xid = GDK_WINDOW_XID (icon_app_window);

  display = gtk_widget_get_display (GTK_WIDGET (icon->priv->socket));
  gdk_error_trap_push ();
  _NET_WM_PID = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_PID");
  result = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), plug_xid,
                               _NET_WM_PID, 0, G_MAXLONG, False, XA_CARDINAL,
                               &type, &format, &nitems,
                               &bytes_after, (guchar **)&val);
  if (!gdk_error_trap_pop () &&
      result == Success &&
      type == XA_CARDINAL &&
      nitems == 1)
    icon->priv->pid = *val;

  if (val)
    XFree (val);
}
Beispiel #9
0
/* The plug window should completely occupy the area of the child, so we won't
 * get a draw event. But in case we do (the plug unmaps itself, say), this
 * draw handler draws with real or fake transparency.
 */
static gboolean
na_tray_child_draw (GtkWidget *widget,
                    cairo_t   *cr)
{
  NaTrayChild *child = NA_TRAY_CHILD (widget);

  if (na_tray_child_has_alpha (child))
    {
      /* Clear to transparent */
      cairo_set_source_rgba (cr, 0, 0, 0, 0);
      cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
      cairo_paint (cr);
    }
  else if (child->parent_relative_bg)
    {
      GdkWindow *window;
      cairo_surface_t *target;
      GdkRectangle clip_rect;

      window = gtk_widget_get_window (widget);
      target = cairo_get_group_target (cr);

      gdk_cairo_get_clip_rectangle (cr, &clip_rect);

      /* Clear to parent-relative pixmap
       * We need to use direct X access here because GDK doesn't know about
       * the parent relative pixmap. */
      cairo_surface_flush (target);

      XClearArea (GDK_WINDOW_XDISPLAY (window),
                  GDK_WINDOW_XID (window),
                  clip_rect.x, clip_rect.y,
                  clip_rect.width, clip_rect.height,
                  False);
      cairo_surface_mark_dirty_rectangle (target,
                                          clip_rect.x, clip_rect.y,
                                          clip_rect.width, clip_rect.height);
    }

  return FALSE;
}
Beispiel #10
0
static void
na_tray_icon_added (NaTrayManager *na_manager, GtkWidget *socket,
                    gpointer user_data)
{
  CinnamonTrayManager *manager = user_data;
  GtkWidget *win;
  CinnamonTrayManagerChild *child;

  /* We don't need the NaTrayIcon to be composited on the window we
   * put it in: the window is the same size as the tray icon
   * and transparent. We can just use the default X handling of
   * subwindows as mode of SOURCE (replace the parent with the
   * child) and then composite the parent onto the stage.
   */
  na_tray_child_set_composited (NA_TRAY_CHILD (socket), FALSE);

  win = cinnamon_embedded_window_new (manager->priv->stage);
  gtk_container_add (GTK_CONTAINER (win), socket);

  /* The visual of the socket matches that of its contents; make
   * the window we put it in match that as well */
  gtk_widget_set_visual (win, gtk_widget_get_visual (socket));

  child = g_slice_new0 (CinnamonTrayManagerChild);
  child->manager = manager;
  child->window = win;
  child->socket = socket;

  g_signal_connect (win, "realize",
                    G_CALLBACK (cinnamon_tray_manager_child_on_realize), child);

  gtk_widget_show_all (win);

  g_hash_table_insert (manager->priv->icons, socket, child);

  g_signal_connect (socket, "plug-added", G_CALLBACK (on_plug_added), manager);
}