tray: Add NaXembed object

This GObject subclass is a minimal wrapper similar to GtkSocket,
meant to replace the GTK widgetry involved in the tray manager.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2590>
This commit is contained in:
Carlos Garnacho 2022-12-07 20:50:53 +01:00 committed by Marge Bot
parent aef1db9585
commit f9519f4a55
3 changed files with 949 additions and 2 deletions

View File

@ -2,11 +2,13 @@ tray_sources = [
'na-tray-child.c',
'na-tray-child.h',
'na-tray-manager.c',
'na-tray-manager.h'
'na-tray-manager.h',
'na-xembed.c',
'na-xembed.h'
]
libtray = static_library('tray', tray_sources,
c_args: ['-DG_LOG_DOMAIN="notification_area"'],
dependencies: [clutter_dep, gtk_dep],
dependencies: [mutter_dep, gtk_dep],
include_directories: conf_inc
)

882
src/tray/na-xembed.c Normal file
View File

@ -0,0 +1,882 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/* Copyright (C) 2022 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
* Author: Carlos Garnacho <carlosg@gnome.org>
*
* Based on GTK+ code by Owen Taylor <otaylor@gtk.org>
*/
#include "config.h"
#include "na-xembed.h"
#include <meta/meta-x11-errors.h>
#include <X11/extensions/Xfixes.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
typedef struct _NaXembedPrivate NaXembedPrivate;
struct _NaXembedPrivate
{
MetaX11Display *x11_display;
Window socket_window;
Window plug_window;
int root_x;
int root_y;
int request_width;
int request_height;
int current_width;
int current_height;
int resize_count;
int xembed_version;
unsigned int event_func_id;
guint resize_id;
XVisualInfo *xvisual_info;
Atom atom__XEMBED;
Atom atom__XEMBED_INFO;
Atom atom_WM_NORMAL_HINTS;
gboolean have_size;
gboolean need_map;
gboolean is_mapped;
gboolean has_alpha;
};
/* XEMBED messages */
typedef enum _XembedMessageType XembedMessageType;
enum _XembedMessageType {
XEMBED_EMBEDDED_NOTIFY,
XEMBED_WINDOW_ACTIVATE,
XEMBED_WINDOW_DEACTIVATE,
XEMBED_REQUEST_FOCUS,
XEMBED_FOCUS_IN,
XEMBED_FOCUS_OUT,
XEMBED_FOCUS_NEXT,
XEMBED_FOCUS_PREV,
XEMBED_GRAB_KEY,
XEMBED_UNGRAB_KEY,
XEMBED_MODALITY_ON,
XEMBED_MODALITY_OFF,
};
/* Flags for _XEMBED_INFO */
#define XEMBED_MAPPED (1 << 0)
#define XEMBED_PROTOCOL_VERSION 1
G_DEFINE_TYPE_WITH_PRIVATE (NaXembed, na_xembed, G_TYPE_OBJECT)
enum {
PLUG_ADDED,
PLUG_REMOVED,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0, };
enum {
PROP_0,
PROP_X11_DISPLAY,
N_PROPS
};
static GParamSpec *props[N_PROPS] = { 0, };
static void
xembed_send_message (NaXembed *xembed,
Window recipient,
XembedMessageType message,
glong detail,
glong data1,
glong data2)
{
NaXembedPrivate *priv = na_xembed_get_instance_private (xembed);
XClientMessageEvent xclient;
memset (&xclient, 0, sizeof (xclient));
xclient.window = recipient;
xclient.type = ClientMessage;
xclient.message_type = priv->atom__XEMBED;
xclient.format = 32;
xclient.data.l[0] = 0; /* Time */
xclient.data.l[1] = message;
xclient.data.l[2] = detail;
xclient.data.l[3] = data1;
xclient.data.l[4] = data2;
meta_x11_error_trap_push (priv->x11_display);
XSendEvent (meta_x11_display_get_xdisplay (priv->x11_display),
recipient,
False, NoEventMask, (XEvent*) &xclient);
meta_x11_error_trap_pop (priv->x11_display);
}
static void
na_xembed_end_embedding (NaXembed *xembed)
{
NaXembedPrivate *priv = na_xembed_get_instance_private (xembed);
priv->plug_window = None;
priv->current_width = 0;
priv->current_height = 0;
priv->resize_count = 0;
g_clear_handle_id (&priv->resize_id, g_source_remove);
}
static void
na_xembed_send_configure_event (NaXembed *xembed)
{
NaXembedPrivate *priv = na_xembed_get_instance_private (xembed);
XConfigureEvent xconfigure;
memset (&xconfigure, 0, sizeof (xconfigure));
xconfigure.type = ConfigureNotify;
xconfigure.event = priv->plug_window;
xconfigure.window = priv->plug_window;
xconfigure.x = priv->root_x;
xconfigure.y = priv->root_y;
xconfigure.width = priv->current_width;
xconfigure.height = priv->current_height;
xconfigure.border_width = 0;
xconfigure.above = None;
xconfigure.override_redirect = False;
meta_x11_error_trap_push (priv->x11_display);
XSendEvent (meta_x11_display_get_xdisplay (priv->x11_display),
priv->plug_window,
False, NoEventMask,
(XEvent*) &xconfigure);
meta_x11_error_trap_pop (priv->x11_display);
}
static void
na_xembed_synchronize_size (NaXembed *xembed)
{
NaXembedPrivate *priv = na_xembed_get_instance_private (xembed);
Display *xdisplay = meta_x11_display_get_xdisplay (priv->x11_display);
int x, y, width, height;
x = priv->root_x;
y = priv->root_y;
width = priv->request_width;
height = priv->request_height;
XMoveResizeWindow (xdisplay,
priv->socket_window,
x, y,
width, height);
if (priv->plug_window)
{
meta_x11_error_trap_push (priv->x11_display);
if (width != priv->current_width ||
height != priv->current_height)
{
XMoveResizeWindow (xdisplay,
priv->plug_window,
0, 0,
width, height);
if (priv->resize_count)
priv->resize_count--;
priv->current_width = width;
priv->current_height = height;
}
if (priv->need_map)
{
XMapWindow (xdisplay, priv->plug_window);
priv->need_map = FALSE;
}
while (priv->resize_count)
{
na_xembed_send_configure_event (xembed);
priv->resize_count--;
}
meta_x11_error_trap_pop (priv->x11_display);
}
}
static gboolean
synchronize_size_cb (gpointer user_data)
{
NaXembed *xembed = user_data;
NaXembedPrivate *priv = na_xembed_get_instance_private (xembed);
na_xembed_synchronize_size (xembed);
priv->resize_id = 0;
return G_SOURCE_REMOVE;
}
static void
na_xembed_resize (NaXembed *xembed)
{
NaXembedPrivate *priv = na_xembed_get_instance_private (xembed);
XSizeHints hints;
long supplied;
g_clear_handle_id (&priv->resize_id, g_source_remove);
meta_x11_error_trap_push (priv->x11_display);
priv->request_width = 1;
priv->request_height = 1;
if (XGetWMNormalHints (meta_x11_display_get_xdisplay (priv->x11_display),
priv->plug_window,
&hints, &supplied))
{
if (hints.flags & PMinSize)
{
priv->request_width = MAX (hints.min_width, 1);
priv->request_height = MAX (hints.min_height, 1);
}
else if (hints.flags & PBaseSize)
{
priv->request_width = MAX (hints.base_width, 1);
priv->request_height = MAX (hints.base_height, 1);
}
}
priv->have_size = TRUE;
meta_x11_error_trap_pop (priv->x11_display);
priv->resize_id = g_idle_add (synchronize_size_cb, xembed);
}
static gboolean
na_xembed_get_info (NaXembed *xembed,
Window xwindow,
unsigned long *version,
unsigned long *flags)
{
NaXembedPrivate *priv = na_xembed_get_instance_private (xembed);
MetaX11Display *x11_display = priv->x11_display;
Display *xdisplay = meta_x11_display_get_xdisplay (x11_display);
Atom type;
int format;
unsigned long nitems, bytes_after;
unsigned char *data;
unsigned long *data_long;
int status;
meta_x11_error_trap_push (x11_display);
status = XGetWindowProperty (xdisplay,
xwindow,
priv->atom__XEMBED_INFO,
0, 2, False,
priv->atom__XEMBED_INFO,
&type, &format,
&nitems, &bytes_after, &data);
meta_x11_error_trap_pop (x11_display);
if (status != Success)
return FALSE;
if (type == None)
return FALSE;
if (type != priv->atom__XEMBED_INFO)
{
g_warning ("_XEMBED_INFO property has wrong type");
XFree (data);
return FALSE;
}
if (nitems < 2)
{
g_warning ("_XEMBED_INFO too short");
XFree (data);
return FALSE;
}
data_long = (unsigned long *)data;
if (version)
*version = data_long[0];
if (flags)
*flags = data_long[1] & XEMBED_MAPPED;
XFree (data);
return TRUE;
}
static void
na_xembed_add_window (NaXembed *xembed,
Window xid,
gboolean need_reparent)
{
NaXembedPrivate *priv = na_xembed_get_instance_private (xembed);
Display *xdisplay = meta_x11_display_get_xdisplay (priv->x11_display);
XVisualInfo template = { 0, };
int n_xvisuals;
unsigned long version;
unsigned long flags;
priv->plug_window = xid;
meta_x11_error_trap_push (priv->x11_display);
XSelectInput (xdisplay,
priv->plug_window,
StructureNotifyMask | PropertyChangeMask);
if (meta_x11_error_trap_pop_with_return (priv->x11_display))
{
priv->plug_window = None;
return;
}
/* OK, we now will reliably get destroy notification on socket->plug_window */
meta_x11_error_trap_push (priv->x11_display);
if (need_reparent)
{
XSetWindowAttributes socket_attrs;
XWindowAttributes plug_attrs;
int result;
result = XGetWindowAttributes (xdisplay, priv->plug_window, &plug_attrs);
if (result == 0)
{
meta_x11_error_trap_pop (priv->x11_display);
priv->plug_window = None;
return;
}
template.visualid = plug_attrs.visual->visualid;
priv->xvisual_info =
XGetVisualInfo (meta_x11_display_get_xdisplay (priv->x11_display),
VisualIDMask,
&template,
&n_xvisuals);
if (!priv->xvisual_info)
{
meta_x11_error_trap_pop (priv->x11_display);
priv->plug_window = None;
return;
}
priv->has_alpha = (priv->xvisual_info->depth >
__builtin_popcount (priv->xvisual_info->red_mask |
priv->xvisual_info->green_mask |
priv->xvisual_info->blue_mask));
socket_attrs.override_redirect = True;
priv->socket_window =
XCreateWindow (xdisplay,
meta_x11_display_get_xroot (priv->x11_display),
-100, -100, 1, 1, 0,
priv->xvisual_info->depth,
InputOutput,
plug_attrs.visual,
CWOverrideRedirect,
&socket_attrs);
XUnmapWindow (xdisplay, priv->plug_window); /* Shouldn't actually be necessary for XEMBED, but just in case */
XReparentWindow (xdisplay,
priv->plug_window,
priv->socket_window,
0, 0);
}
priv->have_size = FALSE;
priv->xembed_version = -1;
if (na_xembed_get_info (xembed, priv->plug_window, &version, &flags))
{
priv->xembed_version = MIN (XEMBED_PROTOCOL_VERSION, version);
priv->is_mapped = (flags & XEMBED_MAPPED) != 0;
}
else
{
/* FIXME, we should probably actually check the state before we started */
priv->is_mapped = TRUE;
}
priv->need_map = priv->is_mapped;
meta_x11_error_trap_pop (priv->x11_display);
meta_x11_error_trap_push (priv->x11_display);
XFixesChangeSaveSet (xdisplay, priv->plug_window,
SetModeInsert, SaveSetRoot, SaveSetUnmap);
meta_x11_error_trap_pop (priv->x11_display);
xembed_send_message (xembed,
priv->plug_window,
XEMBED_EMBEDDED_NOTIFY, 0,
priv->socket_window,
priv->xembed_version);
na_xembed_resize (xembed);
g_signal_emit (xembed, signals[PLUG_ADDED], 0);
XMapWindow (xdisplay, priv->socket_window);
}
static void
na_xembed_handle_map_request (NaXembed *xembed)
{
NaXembedPrivate *priv = na_xembed_get_instance_private (xembed);
if (!priv->is_mapped)
{
priv->is_mapped = TRUE;
priv->need_map = TRUE;
na_xembed_resize (xembed);
}
}
static void
na_xembed_handle_unmap_notify (NaXembed *xembed)
{
NaXembedPrivate *priv = na_xembed_get_instance_private (xembed);
if (priv->is_mapped)
{
priv->is_mapped = FALSE;
na_xembed_resize (xembed);
}
}
static void
xembed_filter_func (MetaX11Display *x11_display,
XEvent *xevent,
gpointer user_data)
{
NaXembed *xembed = user_data;
NaXembedPrivate *priv = na_xembed_get_instance_private (xembed);
Display *xdisplay = meta_x11_display_get_xdisplay (priv->x11_display);
if (priv->socket_window == None)
return;
if (xevent->xany.window != priv->socket_window &&
xevent->xany.window != priv->plug_window)
return;
switch (xevent->type)
{
case ClientMessage:
/* We choose to ignore all _XEMBED ClientEvent messages
* addressed to the socket.
*/
break;
case CreateNotify:
{
XCreateWindowEvent *xcwe = &xevent->xcreatewindow;
if (!priv->plug_window)
na_xembed_add_window (xembed, xcwe->window, FALSE);
break;
}
case ConfigureRequest:
{
XConfigureRequestEvent *xcre = &xevent->xconfigurerequest;
if (!priv->plug_window)
na_xembed_add_window (xembed, xcre->window, FALSE);
if (priv->plug_window)
{
if (xcre->value_mask & (CWWidth | CWHeight))
{
priv->resize_count++;
na_xembed_resize (xembed);
}
else if (xcre->value_mask & (CWX | CWY))
{
na_xembed_send_configure_event (xembed);
}
/* Ignore stacking requests. */
}
break;
}
case DestroyNotify:
{
XDestroyWindowEvent *xdwe = &xevent->xdestroywindow;
/* Note that we get destroy notifies both from SubstructureNotify on
* our window and StructureNotify on socket->plug_window
*/
if (priv->plug_window && (xdwe->window == priv->plug_window))
{
g_object_ref (xembed);
g_signal_emit (xembed, signals[PLUG_REMOVED], 0);
na_xembed_end_embedding (xembed);
g_object_unref (xembed);
}
break;
}
case MapRequest:
if (!priv->plug_window)
na_xembed_add_window (xembed, xevent->xmaprequest.window, FALSE);
if (priv->plug_window == xevent->xmaprequest.window)
na_xembed_handle_map_request (xembed);
break;
case PropertyNotify:
if (priv->plug_window &&
xevent->xproperty.window == priv->plug_window)
{
if (xevent->xproperty.atom == priv->atom_WM_NORMAL_HINTS)
{
priv->have_size = FALSE;
na_xembed_resize (xembed);
}
else if (xevent->xproperty.atom == priv->atom__XEMBED_INFO)
{
unsigned long flags;
if (na_xembed_get_info (xembed, priv->plug_window, NULL, &flags))
{
gboolean was_mapped = priv->is_mapped;
gboolean is_mapped = (flags & XEMBED_MAPPED) != 0;
if (was_mapped != is_mapped)
{
if (is_mapped)
{
na_xembed_handle_map_request (xembed);
}
else
{
meta_x11_error_trap_push (priv->x11_display);
XMapWindow (xdisplay, priv->plug_window);
meta_x11_error_trap_pop (priv->x11_display);
na_xembed_handle_unmap_notify (xembed);
}
}
}
}
}
break;
case ReparentNotify:
{
XReparentEvent *xre = &xevent->xreparent;
if (priv->plug_window == None &&
xre->parent == priv->socket_window)
{
na_xembed_add_window (xembed, xre->window, FALSE);
}
else if (priv->plug_window != None &&
xre->window == priv->plug_window &&
xre->parent != priv->socket_window)
{
g_object_ref (xembed);
g_signal_emit (xembed, signals[PLUG_REMOVED], 0);
na_xembed_end_embedding (xembed);
g_object_unref (xembed);
}
break;
}
case UnmapNotify:
if (priv->plug_window != None &&
xevent->xunmap.window == priv->plug_window)
na_xembed_handle_unmap_notify (xembed);
break;
}
}
static void
na_xembed_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
NaXembed *xembed = NA_XEMBED (object);
NaXembedPrivate *priv = na_xembed_get_instance_private (xembed);
switch (prop_id)
{
case PROP_X11_DISPLAY:
priv->x11_display = g_value_get_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
na_xembed_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
NaXembed *xembed = NA_XEMBED (object);
NaXembedPrivate *priv = na_xembed_get_instance_private (xembed);
switch (prop_id)
{
case PROP_X11_DISPLAY:
g_value_set_object (value, priv->x11_display);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
na_xembed_finalize (GObject *object)
{
NaXembed *xembed = NA_XEMBED (object);
NaXembedPrivate *priv = na_xembed_get_instance_private (xembed);
g_clear_pointer (&priv->xvisual_info, XFree);
if (priv->x11_display && priv->event_func_id)
meta_x11_display_remove_event_func (priv->x11_display, priv->event_func_id);
if (priv->plug_window)
na_xembed_end_embedding (xembed);
G_OBJECT_CLASS (na_xembed_parent_class)->finalize (object);
}
static void
na_xembed_constructed (GObject *object)
{
NaXembed *xembed = NA_XEMBED (object);
NaXembedPrivate *priv = na_xembed_get_instance_private (xembed);
Display *xdisplay;
G_OBJECT_CLASS (na_xembed_parent_class)->constructed (object);
xdisplay = meta_x11_display_get_xdisplay (priv->x11_display);
priv->event_func_id =
meta_x11_display_add_event_func (priv->x11_display,
xembed_filter_func,
object,
NULL);
priv->atom__XEMBED = XInternAtom (xdisplay, "_XEMBED", False);
priv->atom__XEMBED_INFO = XInternAtom (xdisplay, "_XEMBED_INFO", False);
priv->atom_WM_NORMAL_HINTS = XInternAtom (xdisplay, "WM_NORMAL_HINTS", False);
}
static void
na_xembed_class_init (NaXembedClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->set_property = na_xembed_set_property;
object_class->get_property = na_xembed_get_property;
object_class->finalize = na_xembed_finalize;
object_class->constructed = na_xembed_constructed;
signals[PLUG_ADDED] =
g_signal_new ("plug-added",
G_OBJECT_CLASS_TYPE (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (NaXembedClass, plug_added),
NULL, NULL, NULL,
G_TYPE_NONE, 0);
signals[PLUG_REMOVED] =
g_signal_new ("plug-removed",
G_OBJECT_CLASS_TYPE (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (NaXembedClass, plug_removed),
NULL, NULL, NULL,
G_TYPE_NONE, 0);
props[PROP_X11_DISPLAY] =
g_param_spec_object ("x11-display",
"x11-display",
"x11-display",
META_TYPE_X11_DISPLAY,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_properties (object_class, N_PROPS, props);
}
static void
na_xembed_init (NaXembed *xembed)
{
}
void
na_xembed_add_id (NaXembed *xembed,
Window window)
{
na_xembed_add_window (xembed, window, TRUE);
}
Window
na_xembed_get_plug_window (NaXembed *xembed)
{
NaXembedPrivate *priv = na_xembed_get_instance_private (xembed);
return priv->plug_window;
}
Window
na_xembed_get_socket_window (NaXembed *xembed)
{
NaXembedPrivate *priv = na_xembed_get_instance_private (xembed);
return priv->socket_window;
}
void
na_xembed_set_root_position (NaXembed *xembed,
int x,
int y)
{
NaXembedPrivate *priv = na_xembed_get_instance_private (xembed);
if (priv->root_x == x &&
priv->root_y == y)
return;
priv->root_x = x;
priv->root_y = y;
if (priv->resize_id == 0)
priv->resize_id = g_idle_add (synchronize_size_cb, xembed);
}
MetaX11Display *
na_xembed_get_x11_display (NaXembed *xembed)
{
NaXembedPrivate *priv = na_xembed_get_instance_private (xembed);
return priv->x11_display;
}
void
na_xembed_get_size (NaXembed *xembed,
int *width,
int *height)
{
NaXembedPrivate *priv = na_xembed_get_instance_private (xembed);
if (width)
*width = priv->request_width;
if (height)
*height = priv->request_height;
}
static void
get_pixel_details (unsigned long pixel_mask,
int *shift,
int *precision)
{
unsigned long m = 0;
int s = 0;
int p = 0;
if (pixel_mask != 0)
{
m = pixel_mask;
while (!(m & 0x1))
{
s++;
m >>= 1;
}
while (m & 0x1)
{
p++;
m >>= 1;
}
}
if (shift)
*shift = s;
if (precision)
*precision = p;
}
void
na_xembed_set_background_color (NaXembed *xembed,
const ClutterColor *color)
{
NaXembedPrivate *priv = na_xembed_get_instance_private (xembed);
XVisualInfo *xvisual_info;
Display *xdisplay;
unsigned long pixel;
if (!priv->socket_window)
return;
if (!priv->xvisual_info)
return;
xvisual_info = priv->xvisual_info;
if (priv->has_alpha)
{
pixel = 0;
}
else
{
double red, green, blue;
int red_shift, red_prec, green_shift, green_prec, blue_shift, blue_prec;
unsigned int padding;
/* Shifting by >= width-of-type isn't defined in C */
if (xvisual_info->depth >= 32)
padding = 0;
else
padding = ((~(uint32_t)0)) << xvisual_info->depth;
red = (double) color->red / 255.0;
green = (double) color->green / 255.0;
blue = (double) color->blue / 255.0;
get_pixel_details (xvisual_info->red_mask, &red_shift, &red_prec);
get_pixel_details (xvisual_info->green_mask, &green_shift, &green_prec);
get_pixel_details (xvisual_info->blue_mask, &blue_shift, &blue_prec);
pixel = ~(xvisual_info->red_mask |
xvisual_info->green_mask |
xvisual_info->blue_mask |
padding);
pixel += (((int) (red * ((1 << red_prec) - 1))) << red_shift) +
(((int) (green * ((1 << green_prec) - 1))) << green_shift) +
(((int) (blue * ((1 << blue_prec) - 1))) << blue_shift);
}
xdisplay = meta_x11_display_get_xdisplay (priv->x11_display);
XSetWindowBackground (xdisplay, priv->socket_window, pixel);
XClearWindow (xdisplay, priv->socket_window);
}

63
src/tray/na-xembed.h Normal file
View File

@ -0,0 +1,63 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/* na-xembed.h
* Copyright (C) 2022 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
* Author: Carlos Garnacho <carlosg@gnome.org>
*/
#ifndef NA_XEMBED_H
#define NA_XEMBED_H
#include <meta/meta-x11-display.h>
#include <glib-object.h>
#include <X11/Xlib.h>
G_BEGIN_DECLS
#define NA_TYPE_XEMBED (na_xembed_get_type ())
G_DECLARE_DERIVABLE_TYPE (NaXembed, na_xembed, NA, XEMBED, GObject)
struct _NaXembedClass
{
GObjectClass parent_class;
void (* plug_added) (NaXembed *xembed);
void (* plug_removed) (NaXembed *xembed);
};
MetaX11Display * na_xembed_get_x11_display (NaXembed *xembed);
void na_xembed_add_id (NaXembed *xembed,
Window window);
Window na_xembed_get_plug_window (NaXembed *xembed);
Window na_xembed_get_socket_window (NaXembed *xembed);
void na_xembed_set_root_position (NaXembed *xembed,
int x,
int y);
void na_xembed_get_size (NaXembed *xembed,
int *width,
int *height);
void na_xembed_set_background_color (NaXembed *xembed,
const ClutterColor *color);
G_END_DECLS
#endif /* NA_XEMBED_H */