From 5afcf07782b58a70568f750cdee20b67688ab487 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Mon, 19 Jan 2009 23:06:59 +0000 Subject: [PATCH] Merge branch 'workspace-salon' Conflicts: src/shell-global.c svn path=/trunk/; revision=152 --- configure.ac | 5 +- js/ui/main.js | 3 + js/ui/workspaces.js | 112 ++++++++++------ src/Makefile-taskpanel.am | 17 +++ src/Makefile.am | 2 + src/gnomeshell-taskpanel.c | 70 ++++++++++ src/shell-global.c | 49 +++++++ src/shell-global.h | 2 + src/shell-panel-window.c | 260 +++++++++++++++++++++++++++++++++++++ src/shell-panel-window.h | 35 +++++ 10 files changed, 514 insertions(+), 41 deletions(-) create mode 100644 src/Makefile-taskpanel.am create mode 100644 src/gnomeshell-taskpanel.c create mode 100644 src/shell-panel-window.c create mode 100644 src/shell-panel-window.h diff --git a/configure.ac b/configure.ac index 17a6a4d23..ee8f0bfd1 100644 --- a/configure.ac +++ b/configure.ac @@ -9,6 +9,8 @@ AC_CONFIG_HEADERS(config.h) AC_DISABLE_STATIC AC_PROG_CC +# Needed for per-target cflags, like in gnomeshell-taskpanel +AM_PROG_CC_C_O AM_PROG_LIBTOOL GETTEXT_PACKAGE=gnome-shell @@ -16,10 +18,11 @@ AC_SUBST(GETTEXT_PACKAGE) AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE", [The prefix for our gettext translation domains.]) -PKG_CHECK_MODULES(MUTTER_PLUGIN, gtk+-2.0 metacity-plugins gjs-gi-1.0) +PKG_CHECK_MODULES(MUTTER_PLUGIN, gtk+-2.0 dbus-glib-1 metacity-plugins gjs-gi-1.0) PKG_CHECK_MODULES(TIDY, clutter-0.8) PKG_CHECK_MODULES(BIG, clutter-cairo-0.8 gtk+-2.0 librsvg-2.0) PKG_CHECK_MODULES(TRAY, gtk+-2.0) +PKG_CHECK_MODULES(TASKPANEL, libwnck-1.0 dbus-glib-1) # We require libgnomeui for generating thumbnails for recent files with GnomeThumbnailFactory. # We'll switch to using GnomeDesktopThumbnailFactory once the branch of gnome-desktop that contains # it becomes stable. diff --git a/js/ui/main.js b/js/ui/main.js index b4e1fab62..9f132c645 100644 --- a/js/ui/main.js +++ b/js/ui/main.js @@ -97,6 +97,9 @@ Signals.addSignalMethods(ClutterFrameTicker.prototype); function start() { let global = Shell.Global.get(); + + // Here we grab our DBus name, etc. + global.late_init(); Tweener.setFrameTicker(new ClutterFrameTicker()); diff --git a/js/ui/workspaces.js b/js/ui/workspaces.js index d58a92f8f..8a4066440 100644 --- a/js/ui/workspaces.js +++ b/js/ui/workspaces.js @@ -15,6 +15,7 @@ const GdkPixbuf = imports.gi.GdkPixbuf; // Windows are slightly translucent in the overlay mode const WINDOW_OPACITY = 0.9 * 255; +const FOCUS_ANIMATION_TIME = 0.15; const WINDOWCLONE_BG_COLOR = new Clutter.Color(); WINDOWCLONE_BG_COLOR.from_pixel(0x000000f0); @@ -78,17 +79,24 @@ Workspace.prototype = { this._windows = [this._desktop]; for (let i = 0; i < windows.length; i++) { if (this._isOverlayWindow(windows[i])) { - let clone = this._makeClone(windows[i]); + let clone = this._makeClone(windows[i], i); clone.connect("button-press-event", function(clone, event) { clone.raise_top(); me._activateWindow(clone.realWindow, event.get_time()); }); + clone.connect('enter-event', function (a, e) { + me._cloneEnter(clone, e); + }); + clone.connect('leave-event', function (a, e) { + me._cloneLeave(clone, e); + }); this.actor.add_actor(clone); this._windows.push(clone); } } + this._overlappedMode = !((this._windows.length-1) in POSITIONS); this._removeButton = null; this._visible = false; }, @@ -191,11 +199,7 @@ Workspace.prototype = { scale_y: scale, time: Overlay.ANIMATION_TIME, opacity: WINDOW_OPACITY, - transition: "easeOutQuad", - onComplete: function () { - this._addCloneTitle(window); - }, - onCompleteScope: this + transition: "easeOutQuad" }); } @@ -222,7 +226,7 @@ Workspace.prototype = { for (let i = 0; i < this._windows.length; i++) { let window = this._windows[i]; if (window.cloneTitle) - window.cloneTitle.destroy(); + window.cloneTitle.hide(); Tweener.addTween(window, { x: this.fullSizeX + window.origX, y: this.fullSizeY + window.origY, @@ -250,6 +254,7 @@ Workspace.prototype = { // Animates grid shrinking/expanding when a row or column // of workspaces is added or removed resizeToGrid : function (oldScale) { + let me = this; let rescale = this.scale / oldScale; for (let i = 0; i < this._windows.length; i++) { @@ -263,10 +268,12 @@ Workspace.prototype = { scale_x: newWindowScale, scale_y: newWindowScale, time: Overlay.ANIMATION_TIME, - transition: "easeOutQuad" + transition: "easeOutQuad", + onComplete: function () { + me._adjustCloneTitle(me._windows[i]); + } }); - this._adjustCloneTitle(this._windows[i], newX, newY, - newWindowScale); + } if (this._removeButton) { @@ -364,12 +371,15 @@ Workspace.prototype = { // Tests if @win should be shown in the overlay _isOverlayWindow : function (win) { - return win.get_window_type() != Meta.WindowType.DESKTOP && - !win.is_override_redirect(); + let wintype = win.get_window_type(); + if (wintype == Meta.WindowType.DESKTOP || + wintype == Meta.WindowType.DOCK) + return false; + return !win.is_override_redirect(); }, // Create a clone of a window to use in the overlay. - _makeClone : function(window) { + _makeClone : function(window, index) { let clone = new Clutter.CloneTexture({ parent_texture: window.get_texture(), reactive: true, x: window.x, @@ -377,6 +387,7 @@ Workspace.prototype = { clone.realWindow = window; clone.origX = window.x; clone.origY = window.y; + clone.index = index; return clone; }, @@ -422,47 +433,68 @@ Workspace.prototype = { return [xCenter, yCenter, fraction]; }, + + _cloneEnter: function (clone, event) { + if (!clone.cloneTitle) + this._createCloneTitle(clone); + clone.cloneTitle.show(); + this._adjustCloneTitle(clone) + if (!this._overlappedMode) + return; + if (clone.index != this._windows.length-1) { + clone.raise_top(); + clone.cloneTitle.raise(clone); + } + }, + + _cloneLeave: function (clone, event) { + clone.cloneTitle.hide(); + if (!this._overlappedMode) + return; + if (clone.index != this._windows.length-1) { + clone.lower(this._windows[clone.index+1]); + clone.cloneTitle.raise(clone); + } + }, - _addCloneTitle : function (clone) { - let transformed = clone.get_transformed_size(); + _createCloneTitle : function (clone) { + let me = this; let window = clone.realWindow; - let icon = window.meta_window.mini_icon; - let iconTexture = new Clutter.Texture({ width: 16, height: 16, keep_aspect_ratio: true}); - Shell.clutter_texture_set_from_pixbuf(iconTexture, icon); + let box = new Big.Box({background_color : WINDOWCLONE_BG_COLOR, y_align: Big.BoxAlignment.CENTER, corner_radius: 5, padding: 4, spacing: 4, - orientation: Big.BoxOrientation.HORIZONTAL}); + orientation: Big.BoxOrientation.HORIZONTAL}); + + let icon = window.meta_window.mini_icon; + let iconTexture = new Clutter.Texture({ x: clone.x, + y: clone.y + clone.height - 16, + width: 16, height: 16, keep_aspect_ratio: true}); + Shell.clutter_texture_set_from_pixbuf(iconTexture, icon); box.append(iconTexture, Big.BoxPackFlags.NONE); + let title = new Clutter.Label({color: WINDOWCLONE_TITLE_COLOR, - font_name: "Sans 14", + font_name: "Sans 12", text: window.meta_window.title, ellipsize: Pango.EllipsizeMode.END}); - // Get current width (just the icon), with spacing, plus title - box.fullWidth = box.width + box.spacing + title.width; - box.width = Math.min(box.fullWidth, transformed[0]); - box.append(title, Big.BoxPackFlags.EXPAND); - box.set_position(clone.x, clone.y); - let parent = clone.get_parent(); - clone.cloneTitle = box; + box.append(title, Big.BoxPackFlags.EXPAND); + // Get and cache the expected width (just the icon), with spacing, plus title + box.fullWidth = box.width; + box.hide(); // Hidden by default, show on mouseover + clone.cloneTitle = box; + + let parent = clone.get_parent(); parent.add_actor(box); }, - _adjustCloneTitle : function (clone, newX, newY, newScale) { - let title = clone.cloneTitle; - if (!title) - return; - - let newWidth = Math.min(title.fullWidth, clone.width * newScale); - Tweener.addTween(title, - { x: newX, - y: newY, - width: newWidth, - time: Overlay.ANIMATION_TIME, - transition: "easeOutQuad" - }); + _adjustCloneTitle : function (clone) { + let transformed = clone.get_transformed_size(); + let title = clone.cloneTitle; + title.width = Math.min(title.fullWidth, transformed[0]); + let xoff = (transformed[0] - title.width)/2; + title.set_position(clone.x+xoff, clone.y); }, _activateWindow : function(w, time) { diff --git a/src/Makefile-taskpanel.am b/src/Makefile-taskpanel.am new file mode 100644 index 000000000..be1575853 --- /dev/null +++ b/src/Makefile-taskpanel.am @@ -0,0 +1,17 @@ +gnomeshell_taskpanel_CPPFLAGS = \ + -I$(top_srcdir)/src \ + -DG_DISABLE_DEPRECATED \ + -DWNCK_I_KNOW_THIS_IS_UNSTABLE \ + -DG_LOG_DOMAIN=\"gnomeshell-taskpanel\" \ + $(TASKPANEL_CFLAGS) \ + $(NULL) + +gnomeshell_taskpanel_SOURCES = \ + gnomeshell-taskpanel.c \ + shell-panel-window.c \ + shell-panel-window.h \ + $(NULL) + +gnomeshell_taskpanel_LDADD = $(TASKPANEL_LIBS) + +bin_PROGRAMS += gnomeshell-taskpanel diff --git a/src/Makefile.am b/src/Makefile.am index 60e4784f6..8422f7373 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2,11 +2,13 @@ NULL = BUILT_SOURCES = CLEANFILES = EXTRA_DIST = +bin_PROGRAMS = noinst_LTLIBRARIES = include Makefile-tidy.am include Makefile-big.am include Makefile-tray.am +include Makefile-taskpanel.am gnome_shell_cflags = \ $(MUTTER_PLUGIN_CFLAGS) \ diff --git a/src/gnomeshell-taskpanel.c b/src/gnomeshell-taskpanel.c new file mode 100644 index 000000000..1dca7808d --- /dev/null +++ b/src/gnomeshell-taskpanel.c @@ -0,0 +1,70 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +#include "shell-panel-window.h" +#include +#include +#include +#include + +static void +on_name_owner_changed (DBusGProxy *proxy, + const char *name, + const char *prev_owner, + const char *new_owner, + gpointer user_data) +{ + if (strcmp (name, "org.gnome.Shell") == 0 && new_owner[0] == '\0') + exit (0); +} + +static void +monitor_main_shell () +{ + DBusGConnection *session; + DBusGProxy *driver; + + session = dbus_g_bus_get (DBUS_BUS_SESSION, NULL); + + driver = dbus_g_proxy_new_for_name (session, + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS); + + dbus_g_proxy_add_signal (driver, + "NameOwnerChanged", + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_INVALID); + + dbus_g_proxy_connect_signal (driver, + "NameOwnerChanged", + G_CALLBACK (on_name_owner_changed), + NULL, + NULL); +} + +int +main (int argc, char **argv) +{ + ShellPanelWindow *panel; + WnckScreen *screen; + WnckTasklist *tasks; + + gtk_init (&argc, &argv); + + monitor_main_shell (); + + panel = shell_panel_window_new (); + + screen = wnck_screen_get_default(); + tasks = WNCK_TASKLIST (wnck_tasklist_new (screen)); + + gtk_container_add (GTK_CONTAINER (panel), GTK_WIDGET (tasks)); + + gtk_widget_show_all (GTK_WIDGET (panel)); + + gtk_main (); + + exit (0); +} \ No newline at end of file diff --git a/src/shell-global.c b/src/shell-global.c index ce5d80705..22ccd3a43 100644 --- a/src/shell-global.c +++ b/src/shell-global.c @@ -7,8 +7,11 @@ #include #include #include +#include #include #include +#include +#include #include struct _ShellGlobal { @@ -456,3 +459,49 @@ shell_global_reexec_self (ShellGlobal *global) g_warning ("failed to reexec: %s", g_strerror (errno)); g_ptr_array_free (arr, TRUE); } + +/** + * shell_global_late_init + * + * Perform once-only global initialization; currently this executes + * the external tasklist process and grabs the org.gnome.Shell DBus name. + */ +void +shell_global_late_init (ShellGlobal *global) +{ + static gboolean initialized = FALSE; + GError *error = NULL; + DBusGConnection *session; + DBusGProxy *bus; + guint32 request_name_result; + const char* panel_args[] = {"gnomeshell-taskpanel", NULL}; + + if (initialized) + return; + initialized = TRUE; + + session = dbus_g_bus_get (DBUS_BUS_SESSION, NULL); + + bus = dbus_g_proxy_new_for_name (session, + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS); + + if (!dbus_g_proxy_call (bus, "RequestName", &error, + G_TYPE_STRING, "org.gnome.Shell", + G_TYPE_UINT, 0, + G_TYPE_INVALID, + G_TYPE_UINT, &request_name_result, + G_TYPE_INVALID)) { + g_print ("failed to acquire org.gnome.Shell: %s\n", error->message); + exit (0); + } + + if (!g_spawn_async (NULL, &panel_args, NULL, G_SPAWN_SEARCH_PATH, NULL, + NULL, NULL, &error)) { + g_critical ("failed to execute %s: %s", panel_args[0], error->message); + g_clear_error (&error); + } + + g_object_unref (bus); +} \ No newline at end of file diff --git a/src/shell-global.h b/src/shell-global.h index 06afd79fe..a9119c13b 100644 --- a/src/shell-global.h +++ b/src/shell-global.h @@ -38,6 +38,8 @@ GdkPixbuf *shell_get_thumbnail_for_recent_info(GtkRecentInfo *recent_info); ShellGlobal *shell_global_get (void); +void shell_global_late_init (ShellGlobal *global); + void shell_global_set_stage_input_area (ShellGlobal *global, int x, int y, diff --git a/src/shell-panel-window.c b/src/shell-panel-window.c new file mode 100644 index 000000000..04e9fbd91 --- /dev/null +++ b/src/shell-panel-window.c @@ -0,0 +1,260 @@ +#include "shell-panel-window.h" + +#include +#include + +#define PANEL_HEIGHT 25 + +enum { + PROP_0, + +}; + +static void shell_panel_window_dispose (GObject *object); +static void shell_panel_window_finalize (GObject *object); +static void shell_panel_window_set_property ( GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec ); +static void shell_panel_window_get_property( GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec ); +static void shell_panel_window_size_request (GtkWidget *self, GtkRequisition *req); +static void shell_panel_window_size_allocate (GtkWidget *self, GtkAllocation *allocation); +static void shell_panel_window_realize (GtkWidget *self); +static void shell_panel_window_show (GtkWidget *self); +static void set_strut (ShellPanelWindow *self); +static void on_workarea_changed (ShellPanelWindow *self); +static void handle_new_workarea (ShellPanelWindow *self); +static GdkFilterReturn filter_func (GdkXEvent *xevent, + GdkEvent *event, + gpointer data); + +G_DEFINE_TYPE(ShellPanelWindow, shell_panel_window, GTK_TYPE_WINDOW); + +struct ShellPanelWindowPrivate { + GtkAllocation workarea; + guint width; +}; + +static void +shell_panel_window_class_init(ShellPanelWindowClass *klass) +{ + GObjectClass *gobject_class = (GObjectClass *)klass; + GtkWidgetClass *widget_class = (GtkWidgetClass *)klass; + + gobject_class->dispose = shell_panel_window_dispose; + gobject_class->finalize = shell_panel_window_finalize; + gobject_class->set_property = shell_panel_window_set_property; + gobject_class->get_property = shell_panel_window_get_property; + + widget_class->realize = shell_panel_window_realize; + widget_class->size_request = shell_panel_window_size_request; + widget_class->size_allocate = shell_panel_window_size_allocate; + widget_class->show = shell_panel_window_show; +} + +static void shell_panel_window_init (ShellPanelWindow *self) +{ + self->priv = g_new0 (ShellPanelWindowPrivate, 1); + + gtk_window_set_type_hint (GTK_WINDOW (self), GDK_WINDOW_TYPE_HINT_DOCK); + gtk_window_set_focus_on_map (GTK_WINDOW (self), FALSE); + gdk_window_add_filter (NULL, filter_func, self); +} + +static void shell_panel_window_dispose (GObject *object) +{ + ShellPanelWindow *self = (ShellPanelWindow*)object; + + G_OBJECT_CLASS (shell_panel_window_parent_class)->dispose(object); +} + +static void shell_panel_window_finalize (GObject *object) +{ + ShellPanelWindow *self = (ShellPanelWindow*)object; + + g_free (self->priv); + g_signal_handlers_destroy(object); + G_OBJECT_CLASS (shell_panel_window_parent_class)->finalize(object); +} + +static void shell_panel_window_set_property ( GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec ) +{ + ShellPanelWindow* self = SHELL_PANEL_WINDOW(object); + switch (property_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +static void shell_panel_window_get_property ( GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec ) +{ + ShellPanelWindow* self = SHELL_PANEL_WINDOW(object); + switch (property_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +ShellPanelWindow* shell_panel_window_new(void) +{ + return (ShellPanelWindow*) g_object_new(SHELL_TYPE_PANEL_WINDOW, + "type", GTK_WINDOW_TOPLEVEL, NULL); +} + + +static void +set_strut (ShellPanelWindow *self) +{ + long *buf; + int x, y; + int strut_size; + + strut_size = GTK_WIDGET (self)->allocation.height; + + gtk_window_get_position (GTK_WINDOW (self), &x, &y); + + buf = g_new0(long, 4); + buf[3] = strut_size; + gdk_property_change (GTK_WIDGET (self)->window, gdk_atom_intern_static_string ("_NET_WM_STRUT"), + gdk_atom_intern_static_string ("CARDINAL"), 32, + GDK_PROP_MODE_REPLACE, + (guchar*) buf, 4); + g_free (buf); +} + +static void +shell_panel_window_size_request (GtkWidget *widget, GtkRequisition *requisition) +{ + ShellPanelWindow *self = SHELL_PANEL_WINDOW (widget); + GTK_WIDGET_CLASS (shell_panel_window_parent_class)->size_request(widget, requisition); + requisition->width = self->priv->width; + requisition->height = PANEL_HEIGHT; +} + +static void +shell_panel_window_size_allocate (GtkWidget *widget, GtkAllocation *allocation) +{ + ShellPanelWindow *self = SHELL_PANEL_WINDOW (widget); + GTK_WIDGET_CLASS (shell_panel_window_parent_class)->size_allocate(widget, allocation); + if (GTK_WIDGET_REALIZED (self)) + set_strut (self); +} + +static void +shell_panel_window_realize (GtkWidget *widget) +{ + ShellPanelWindow *self = SHELL_PANEL_WINDOW (widget); + GTK_WIDGET_CLASS (shell_panel_window_parent_class)->realize(widget); + set_strut (self); +} + +static void +shell_panel_window_show (GtkWidget *widget) +{ + ShellPanelWindow *self = SHELL_PANEL_WINDOW (widget); + on_workarea_changed (self); + GTK_WIDGET_CLASS (shell_panel_window_parent_class)->show(widget); +} + +static void +handle_new_workarea (ShellPanelWindow *self) +{ + int monitor; + GtkRequisition requisition; + GdkRectangle monitor_geometry; + int x, y; + int width; + + monitor = gdk_screen_get_monitor_at_point (gdk_screen_get_default (), + self->priv->workarea.x, + self->priv->workarea.y); + gdk_screen_get_monitor_geometry (gdk_screen_get_default (), + monitor, &monitor_geometry); + gtk_widget_size_request (GTK_WIDGET (self), &requisition); + + x = self->priv->workarea.x; + y = monitor_geometry.y + monitor_geometry.height - requisition.height; + width = monitor_geometry.width - x; + + self->priv->width = width; + gtk_widget_set_size_request (GTK_WIDGET (self), width, PANEL_HEIGHT); + gtk_window_move (GTK_WINDOW (self), x, y); +} + +static void +on_workarea_changed (ShellPanelWindow *self) +{ + gulong bytes_after, nitems; + Atom type; + gint format; + guchar *data; + long *data32; + Atom workarea = gdk_x11_get_xatom_by_name_for_display (gdk_display_get_default (), "_NET_WORKAREA"); + + XGetWindowProperty (GDK_DISPLAY(), GDK_ROOT_WINDOW(), + workarea, + 0, 4, FALSE, workarea, + &type, &format, &nitems, &bytes_after, &data); + if ((format == 32) && (nitems == 4) && (bytes_after == 0)) { + int x, y, width, height; + data32 = (long*)data; + x = data32[0]; y = data32[1]; + width = data32[2]; height = data32[3]; + if (x == self->priv->workarea.x && + y == self->priv->workarea.y && + width == self->priv->workarea.width && + height == self->priv->workarea.height) + return; + + self->priv->workarea.x = x; + self->priv->workarea.y = y; + self->priv->workarea.width = width; + self->priv->workarea.height = height; + + handle_new_workarea (self); + } else if (nitems == 0) { + self->priv->workarea.x = self->priv->workarea.y = 0; + self->priv->workarea.width = self->priv->workarea.height = -1; + handle_new_workarea (self); + } else { + g_printerr ("unexpected return from XGetWindowProperty: %d %ld %ld\n", + format, nitems, bytes_after); + } +} + +static GdkFilterReturn +filter_func (GdkXEvent *gdk_xevent, + GdkEvent *event, + gpointer data) +{ + ShellPanelWindow *self = SHELL_PANEL_WINDOW (data); + GdkFilterReturn ret = GDK_FILTER_CONTINUE; + XEvent *xevent = (XEvent *) event; + Atom workarea = gdk_x11_get_xatom_by_name_for_display (gdk_display_get_default (), "_NET_WORKAREA"); + + switch (xevent->type) { + case PropertyNotify: + { + if (xevent->xproperty.atom != workarea) + break; + + on_workarea_changed (self); + } + break; + default: + break; + } + return ret; +} diff --git a/src/shell-panel-window.h b/src/shell-panel-window.h new file mode 100644 index 000000000..9f1bbc5bd --- /dev/null +++ b/src/shell-panel-window.h @@ -0,0 +1,35 @@ +#ifndef __SHELL_PANEL_WINDOW_H__ +#define __SHELL_PANEL_WINDOW_H__ + +#include + +#define SHELL_TYPE_PANEL_WINDOW (shell_panel_window_get_type ()) +#define SHELL_PANEL_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHELL_TYPE_PANEL_WINDOW, ShellPanelWindow)) +#define SHELL_PANEL_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SHELL_TYPE_PANEL_WINDOW, ShellPanelWindowClass)) +#define SHELL_IS_PANEL_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SHELL_TYPE_PANEL_WINDOW)) +#define SHELL_IS_PANEL_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SHELL_TYPE_PANEL_WINDOW)) +#define SHELL_PANEL_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SHELL_TYPE_PANEL_WINDOW, ShellPanelWindowClass)) + +typedef struct _ShellPanelWindow ShellPanelWindow; +typedef struct _ShellPanelWindowClass ShellPanelWindowClass; + +typedef struct ShellPanelWindowPrivate ShellPanelWindowPrivate; + +struct _ShellPanelWindow +{ + GtkWindow parent; + + ShellPanelWindowPrivate *priv; +}; + +struct _ShellPanelWindowClass +{ + GtkWindowClass parent_class; + +}; + +GType shell_panel_window_get_type (void) G_GNUC_CONST; +ShellPanelWindow* shell_panel_window_new(void); + + +#endif /* __SHELL_PANEL_WINDOW_H__ */