Merge branch 'workspace-salon'

Conflicts:
	src/shell-global.c

svn path=/trunk/; revision=152
This commit is contained in:
Colin Walters 2009-01-19 23:06:59 +00:00
parent b6ec5080c8
commit 5afcf07782
10 changed files with 514 additions and 41 deletions

View File

@ -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.

View File

@ -98,6 +98,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());
// The background color really only matters if there is no desktop

View File

@ -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;
},
@ -423,46 +434,67 @@ Workspace.prototype = {
return [xCenter, yCenter, fraction];
},
_addCloneTitle : function (clone) {
let transformed = clone.get_transformed_size();
_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);
}
},
_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});
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();
// 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) {
_adjustCloneTitle : function (clone) {
let transformed = clone.get_transformed_size();
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"
});
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) {

17
src/Makefile-taskpanel.am Normal file
View File

@ -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

View File

@ -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) \

View File

@ -0,0 +1,70 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
#include "shell-panel-window.h"
#include <libwnck/libwnck.h>
#include <stdlib.h>
#include <string.h>
#include <dbus/dbus-glib.h>
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);
}

View File

@ -7,8 +7,11 @@
#include <clutter/x11/clutter-x11.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <libgnomeui-2.0/libgnomeui/gnome-thumbnail.h>
#include <dbus/dbus-glib.h>
#include <libgnomeui/gnome-thumbnail.h>
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);
}

View File

@ -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,

260
src/shell-panel-window.c Normal file
View File

@ -0,0 +1,260 @@
#include "shell-panel-window.h"
#include <gdk/gdkx.h>
#include <X11/Xlib.h>
#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;
}

35
src/shell-panel-window.h Normal file
View File

@ -0,0 +1,35 @@
#ifndef __SHELL_PANEL_WINDOW_H__
#define __SHELL_PANEL_WINDOW_H__
#include <gtk/gtk.h>
#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__ */