[ShellTrayIcon] add ShellTrayIcon, make ShellTrayManager use it
The actor emitted by ShellTrayManager is now ShellTrayIcon, a subclass of ShellGtkEmbed which has several properties on it which are (or will soon be) useful to the shell. Part of the rearranging to use ShellTrayIcon means that we now show the ShellEmbeddedWindow before creating its ShellGtkEmbed, which requires a few modifications to ShellEmbeddedWindow (notably, telling it at construct time what stage it will be drawn on, since it needs to know that before it has a ShellGtkEmbed now). https://bugzilla.gnome.org/show_bug.cgi?id=608869
This commit is contained in:
parent
63f2066135
commit
ae9360659d
@ -885,7 +885,9 @@ Panel.prototype = {
|
||||
});
|
||||
},
|
||||
|
||||
_onTrayIconAdded: function(o, icon, wmClass) {
|
||||
_onTrayIconAdded: function(o, icon) {
|
||||
let wmClass = icon.wm_class.toLowerCase();
|
||||
|
||||
icon.height = PANEL_ICON_SIZE;
|
||||
|
||||
let role = STANDARD_TRAY_ICON_IMPLEMENTATIONS[wmClass];
|
||||
|
@ -74,6 +74,7 @@ shell_public_headers_h = \
|
||||
shell-perf-log.h \
|
||||
shell-slicer.h \
|
||||
shell-stack.h \
|
||||
shell-tray-icon.h \
|
||||
shell-tray-manager.h \
|
||||
shell-uri-util.h \
|
||||
shell-window-tracker.h \
|
||||
@ -104,6 +105,7 @@ libgnome_shell_la_SOURCES = \
|
||||
shell-perf-log.c \
|
||||
shell-slicer.c \
|
||||
shell-stack.c \
|
||||
shell-tray-icon.c \
|
||||
shell-tray-manager.c \
|
||||
shell-uri-util.c \
|
||||
shell-window-tracker.c \
|
||||
|
@ -38,10 +38,17 @@
|
||||
|
||||
G_DEFINE_TYPE (ShellEmbeddedWindow, shell_embedded_window, GTK_TYPE_WINDOW);
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
|
||||
PROP_STAGE
|
||||
};
|
||||
|
||||
struct _ShellEmbeddedWindowPrivate {
|
||||
ShellGtkEmbed *actor;
|
||||
|
||||
GdkRectangle position;
|
||||
Window stage_xwindow;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -87,22 +94,9 @@ static void
|
||||
shell_embedded_window_realize (GtkWidget *widget)
|
||||
{
|
||||
ShellEmbeddedWindow *window = SHELL_EMBEDDED_WINDOW (widget);
|
||||
ClutterActor *stage;
|
||||
Window stage_xwindow;
|
||||
|
||||
GTK_WIDGET_CLASS (shell_embedded_window_parent_class)->realize (widget);
|
||||
|
||||
stage = clutter_actor_get_stage (CLUTTER_ACTOR (window->priv->actor));
|
||||
|
||||
/* Clutter is buggy and will realize an actor when it has a parent
|
||||
* but no grandparent; this is a workaround until
|
||||
* http://bugzilla.openedhand.com/show_bug.cgi?id=1138 is fixed - we
|
||||
* only have one stage in the shell in any case.
|
||||
*/
|
||||
if (!stage)
|
||||
stage = clutter_stage_get_default ();
|
||||
|
||||
stage_xwindow = clutter_x11_get_stage_window (CLUTTER_STAGE (stage));
|
||||
|
||||
/* Using XReparentWindow() is simpler than using gdk_window_reparent(),
|
||||
* since it avoids maybe having to create a new foreign GDK window for
|
||||
@ -113,7 +107,7 @@ shell_embedded_window_realize (GtkWidget *widget)
|
||||
*/
|
||||
XReparentWindow (GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (widget)),
|
||||
GDK_WINDOW_XWINDOW (gtk_widget_get_window (widget)),
|
||||
stage_xwindow,
|
||||
window->priv->stage_xwindow,
|
||||
window->priv->position.x, window->priv->position.y);
|
||||
}
|
||||
|
||||
@ -143,6 +137,27 @@ shell_embedded_window_check_resize (GtkContainer *container)
|
||||
clutter_actor_queue_relayout (CLUTTER_ACTOR (window->priv->actor));
|
||||
}
|
||||
|
||||
static void
|
||||
shell_embedded_window_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
ShellEmbeddedWindow *window = SHELL_EMBEDDED_WINDOW (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_STAGE:
|
||||
window->priv->stage_xwindow =
|
||||
clutter_x11_get_stage_window (g_value_get_object (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static GObject *
|
||||
shell_embedded_window_constructor (GType gtype,
|
||||
guint n_properties,
|
||||
@ -177,6 +192,7 @@ shell_embedded_window_class_init (ShellEmbeddedWindowClass *klass)
|
||||
|
||||
g_type_class_add_private (klass, sizeof (ShellEmbeddedWindowPrivate));
|
||||
|
||||
object_class->set_property = shell_embedded_window_set_property;
|
||||
object_class->constructor = shell_embedded_window_constructor;
|
||||
|
||||
widget_class->show = shell_embedded_window_show;
|
||||
@ -185,6 +201,14 @@ shell_embedded_window_class_init (ShellEmbeddedWindowClass *klass)
|
||||
widget_class->configure_event = shell_embedded_window_configure_event;
|
||||
|
||||
container_class->check_resize = shell_embedded_window_check_resize;
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_STAGE,
|
||||
g_param_spec_object ("stage",
|
||||
"Stage",
|
||||
"ClutterStage to embed on",
|
||||
CLUTTER_TYPE_STAGE,
|
||||
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
|
||||
}
|
||||
|
||||
static void
|
||||
@ -207,8 +231,9 @@ _shell_embedded_window_set_actor (ShellEmbeddedWindow *window,
|
||||
|
||||
window->priv->actor = actor;
|
||||
|
||||
if (gtk_widget_get_visible (GTK_WIDGET (window))
|
||||
&& CLUTTER_ACTOR_IS_REALIZED (actor))
|
||||
if (actor &&
|
||||
CLUTTER_ACTOR_IS_REALIZED (actor) &&
|
||||
gtk_widget_get_visible (GTK_WIDGET (window)))
|
||||
gtk_widget_map (GTK_WIDGET (window));
|
||||
}
|
||||
|
||||
@ -267,8 +292,9 @@ _shell_embedded_window_unrealize (ShellEmbeddedWindow *window)
|
||||
* Public API
|
||||
*/
|
||||
GtkWidget *
|
||||
shell_embedded_window_new (void)
|
||||
shell_embedded_window_new (ClutterStage *stage)
|
||||
{
|
||||
return g_object_new (SHELL_TYPE_EMBEDDED_WINDOW,
|
||||
"stage", stage,
|
||||
NULL);
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
#define __SHELL_EMBEDDED_WINDOW_H__
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
#define SHELL_TYPE_EMBEDDED_WINDOW (shell_embedded_window_get_type ())
|
||||
#define SHELL_EMBEDDED_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHELL_TYPE_EMBEDDED_WINDOW, ShellEmbeddedWindow))
|
||||
@ -29,6 +30,6 @@ struct _ShellEmbeddedWindowClass
|
||||
};
|
||||
|
||||
GType shell_embedded_window_get_type (void) G_GNUC_CONST;
|
||||
GtkWidget *shell_embedded_window_new (void);
|
||||
GtkWidget *shell_embedded_window_new (ClutterStage *stage);
|
||||
|
||||
#endif /* __SHELL_EMBEDDED_WINDOW_H__ */
|
||||
|
168
src/shell-tray-icon.c
Normal file
168
src/shell-tray-icon.c
Normal file
@ -0,0 +1,168 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "shell-tray-icon.h"
|
||||
#include "shell-gtk-embed.h"
|
||||
#include "shell-window-tracker.h"
|
||||
#include "gtk-compat.h"
|
||||
#include "tray/na-tray-child.h"
|
||||
#include <gdk/gdkx.h>
|
||||
#include "st.h"
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
|
||||
PROP_PID,
|
||||
PROP_TITLE,
|
||||
PROP_WM_CLASS
|
||||
};
|
||||
|
||||
struct _ShellTrayIconPrivate
|
||||
{
|
||||
NaTrayChild *socket;
|
||||
|
||||
pid_t pid;
|
||||
char *title, *wm_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (ShellTrayIcon, shell_tray_icon, SHELL_TYPE_GTK_EMBED);
|
||||
|
||||
static void
|
||||
shell_tray_icon_finalize (GObject *object)
|
||||
{
|
||||
ShellTrayIcon *icon = SHELL_TRAY_ICON (object);
|
||||
|
||||
g_free (icon->priv->title);
|
||||
g_free (icon->priv->wm_class);
|
||||
|
||||
G_OBJECT_CLASS (shell_tray_icon_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_tray_icon_constructed (GObject *object)
|
||||
{
|
||||
GdkWindow *icon_app_window;
|
||||
ShellTrayIcon *icon = SHELL_TRAY_ICON (object);
|
||||
ShellEmbeddedWindow *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 the shell 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));
|
||||
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);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_tray_icon_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
ShellTrayIcon *icon = SHELL_TRAY_ICON (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_PID:
|
||||
g_value_set_uint (value, icon->priv->pid);
|
||||
break;
|
||||
|
||||
case PROP_TITLE:
|
||||
g_value_set_string (value, icon->priv->title);
|
||||
break;
|
||||
|
||||
case PROP_WM_CLASS:
|
||||
g_value_set_string (value, icon->priv->wm_class);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
shell_tray_icon_class_init (ShellTrayIconClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
g_type_class_add_private (klass, sizeof (ShellTrayIconPrivate));
|
||||
|
||||
object_class->get_property = shell_tray_icon_get_property;
|
||||
object_class->constructed = shell_tray_icon_constructed;
|
||||
object_class->finalize = shell_tray_icon_finalize;
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_PID,
|
||||
g_param_spec_uint ("pid",
|
||||
"PID",
|
||||
"The PID of the icon's application",
|
||||
0, G_MAXUINT, 0,
|
||||
G_PARAM_READABLE));
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_TITLE,
|
||||
g_param_spec_string ("title",
|
||||
"Title",
|
||||
"The icon's window title",
|
||||
NULL,
|
||||
G_PARAM_READABLE));
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_WM_CLASS,
|
||||
g_param_spec_string ("wm-class",
|
||||
"WM Class",
|
||||
"The icon's window WM_CLASS",
|
||||
NULL,
|
||||
G_PARAM_READABLE));
|
||||
}
|
||||
|
||||
static void
|
||||
shell_tray_icon_init (ShellTrayIcon *icon)
|
||||
{
|
||||
icon->priv = G_TYPE_INSTANCE_GET_PRIVATE (icon, SHELL_TYPE_TRAY_ICON,
|
||||
ShellTrayIconPrivate);
|
||||
}
|
||||
|
||||
/*
|
||||
* Public API
|
||||
*/
|
||||
ClutterActor *
|
||||
shell_tray_icon_new (ShellEmbeddedWindow *window)
|
||||
{
|
||||
g_return_val_if_fail (SHELL_IS_EMBEDDED_WINDOW (window), NULL);
|
||||
|
||||
return g_object_new (SHELL_TYPE_TRAY_ICON,
|
||||
"window", window,
|
||||
NULL);
|
||||
}
|
34
src/shell-tray-icon.h
Normal file
34
src/shell-tray-icon.h
Normal file
@ -0,0 +1,34 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
#ifndef __SHELL_TRAY_ICON_H__
|
||||
#define __SHELL_TRAY_ICON_H__
|
||||
|
||||
#include "shell-gtk-embed.h"
|
||||
|
||||
#define SHELL_TYPE_TRAY_ICON (shell_tray_icon_get_type ())
|
||||
#define SHELL_TRAY_ICON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHELL_TYPE_TRAY_ICON, ShellTrayIcon))
|
||||
#define SHELL_TRAY_ICON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SHELL_TYPE_TRAY_ICON, ShellTrayIconClass))
|
||||
#define SHELL_IS_TRAY_ICON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SHELL_TYPE_TRAY_ICON))
|
||||
#define SHELL_IS_TRAY_ICON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SHELL_TYPE_TRAY_ICON))
|
||||
#define SHELL_TRAY_ICON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SHELL_TYPE_TRAY_ICON, ShellTrayIconClass))
|
||||
|
||||
typedef struct _ShellTrayIcon ShellTrayIcon;
|
||||
typedef struct _ShellTrayIconClass ShellTrayIconClass;
|
||||
typedef struct _ShellTrayIconPrivate ShellTrayIconPrivate;
|
||||
|
||||
struct _ShellTrayIcon
|
||||
{
|
||||
ShellGtkEmbed parent;
|
||||
|
||||
ShellTrayIconPrivate *priv;
|
||||
};
|
||||
|
||||
struct _ShellTrayIconClass
|
||||
{
|
||||
ShellGtkEmbedClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType shell_tray_icon_get_type (void) G_GNUC_CONST;
|
||||
ClutterActor *shell_tray_icon_new (ShellEmbeddedWindow *window);
|
||||
|
||||
#endif /* __SHELL_TRAY_ICON_H__ */
|
@ -13,7 +13,7 @@
|
||||
#include "shell-tray-manager.h"
|
||||
#include "na-tray-manager.h"
|
||||
|
||||
#include "shell-gtk-embed.h"
|
||||
#include "shell-tray-icon.h"
|
||||
#include "shell-embedded-window.h"
|
||||
#include "shell-global.h"
|
||||
|
||||
@ -30,7 +30,6 @@ typedef struct {
|
||||
GtkWidget *socket;
|
||||
GtkWidget *window;
|
||||
ClutterActor *actor;
|
||||
gboolean emitted_plugged;
|
||||
} ShellTrayManagerChild;
|
||||
|
||||
enum {
|
||||
@ -159,11 +158,9 @@ shell_tray_manager_class_init (ShellTrayManagerClass *klass)
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (ShellTrayManagerClass, tray_icon_added),
|
||||
NULL, NULL,
|
||||
gi_cclosure_marshal_generic,
|
||||
G_TYPE_NONE, 3,
|
||||
CLUTTER_TYPE_ACTOR,
|
||||
G_TYPE_STRING,
|
||||
G_TYPE_STRING);
|
||||
g_cclosure_marshal_VOID__OBJECT,
|
||||
G_TYPE_NONE, 1,
|
||||
CLUTTER_TYPE_ACTOR);
|
||||
shell_tray_manager_signals[TRAY_ICON_REMOVED] =
|
||||
g_signal_new ("tray-icon-removed",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
@ -280,31 +277,14 @@ on_plug_added (GtkSocket *socket,
|
||||
ShellTrayManager *manager)
|
||||
{
|
||||
ShellTrayManagerChild *child;
|
||||
char *wm_class, *lower_wm_class;
|
||||
char *title;
|
||||
|
||||
g_signal_handlers_disconnect_by_func (socket, on_plug_added, manager);
|
||||
|
||||
child = g_hash_table_lookup (manager->priv->icons, socket);
|
||||
/* Only emit this signal once; the point of waiting until we
|
||||
* get the first plugged notification is to be able to get the WM_CLASS
|
||||
* from the child window. But we don't want to emit this signal twice
|
||||
* if for some reason the socket gets replugged.
|
||||
*/
|
||||
if (child->emitted_plugged)
|
||||
return;
|
||||
child->emitted_plugged = TRUE;
|
||||
|
||||
na_tray_child_get_wm_class (NA_TRAY_CHILD (socket), NULL, &wm_class);
|
||||
if (!wm_class)
|
||||
return;
|
||||
|
||||
title = na_tray_child_get_title (NA_TRAY_CHILD (socket));
|
||||
|
||||
lower_wm_class = g_ascii_strdown (wm_class, -1);
|
||||
child->actor = shell_tray_icon_new (SHELL_EMBEDDED_WINDOW (child->window));
|
||||
g_signal_emit (manager, shell_tray_manager_signals[TRAY_ICON_ADDED], 0,
|
||||
child->actor, lower_wm_class, title);
|
||||
g_free (lower_wm_class);
|
||||
g_free (wm_class);
|
||||
g_free (title);
|
||||
child->actor);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -313,7 +293,6 @@ na_tray_icon_added (NaTrayManager *na_manager, GtkWidget *socket,
|
||||
{
|
||||
ShellTrayManager *manager = user_data;
|
||||
GtkWidget *win;
|
||||
ClutterActor *icon;
|
||||
ShellTrayManagerChild *child;
|
||||
|
||||
/* We don't need the NaTrayIcon to be composited on the window we
|
||||
@ -324,7 +303,7 @@ na_tray_icon_added (NaTrayManager *na_manager, GtkWidget *socket,
|
||||
*/
|
||||
na_tray_child_set_composited (NA_TRAY_CHILD (socket), FALSE);
|
||||
|
||||
win = shell_embedded_window_new ();
|
||||
win = shell_embedded_window_new (manager->priv->stage);
|
||||
gtk_container_add (GTK_CONTAINER (win), socket);
|
||||
|
||||
/* The colormap of the socket matches that of its contents; make
|
||||
@ -341,9 +320,6 @@ na_tray_icon_added (NaTrayManager *na_manager, GtkWidget *socket,
|
||||
|
||||
gtk_widget_show_all (win);
|
||||
|
||||
icon = shell_gtk_embed_new (SHELL_EMBEDDED_WINDOW (win));
|
||||
|
||||
child->actor = g_object_ref (icon);
|
||||
g_hash_table_insert (manager->priv->icons, socket, child);
|
||||
|
||||
g_signal_connect (socket, "plug-added", G_CALLBACK (on_plug_added), manager);
|
||||
|
Loading…
Reference in New Issue
Block a user