54d8f3b27d
svn path=/trunk/; revision=136
405 lines
13 KiB
C
405 lines
13 KiB
C
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
|
|
|
#include "shell-global.h"
|
|
#include "shell-wm.h"
|
|
|
|
#include "display.h"
|
|
#include <clutter/x11/clutter-x11.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
|
|
struct _ShellGlobal {
|
|
GObject parent;
|
|
|
|
MutterPlugin *plugin;
|
|
ShellWM *wm;
|
|
gboolean keyboard_grabbed;
|
|
const char *imagedir;
|
|
};
|
|
|
|
enum {
|
|
PROP_0,
|
|
|
|
PROP_OVERLAY_GROUP,
|
|
PROP_SCREEN,
|
|
PROP_SCREEN_WIDTH,
|
|
PROP_SCREEN_HEIGHT,
|
|
PROP_STAGE,
|
|
PROP_WINDOW_GROUP,
|
|
PROP_WINDOW_MANAGER,
|
|
PROP_IMAGEDIR
|
|
};
|
|
|
|
/* Signals */
|
|
enum
|
|
{
|
|
PANEL_RUN_DIALOG,
|
|
PANEL_MAIN_MENU,
|
|
LAST_SIGNAL
|
|
};
|
|
|
|
G_DEFINE_TYPE(ShellGlobal, shell_global, G_TYPE_OBJECT);
|
|
|
|
static guint shell_global_signals [LAST_SIGNAL] = { 0 };
|
|
|
|
static void
|
|
shell_global_set_property(GObject *object,
|
|
guint prop_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
switch (prop_id)
|
|
{
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
shell_global_get_property(GObject *object,
|
|
guint prop_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
ShellGlobal *global = SHELL_GLOBAL (object);
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_OVERLAY_GROUP:
|
|
g_value_set_object (value, mutter_plugin_get_overlay_group (global->plugin));
|
|
break;
|
|
case PROP_SCREEN:
|
|
g_value_set_object (value, mutter_plugin_get_screen (global->plugin));
|
|
break;
|
|
case PROP_SCREEN_WIDTH:
|
|
{
|
|
int width, height;
|
|
|
|
mutter_plugin_query_screen_size (global->plugin, &width, &height);
|
|
g_value_set_int (value, width);
|
|
}
|
|
break;
|
|
case PROP_SCREEN_HEIGHT:
|
|
{
|
|
int width, height;
|
|
|
|
mutter_plugin_query_screen_size (global->plugin, &width, &height);
|
|
g_value_set_int (value, height);
|
|
}
|
|
break;
|
|
case PROP_STAGE:
|
|
g_value_set_object (value, mutter_plugin_get_stage (global->plugin));
|
|
break;
|
|
case PROP_WINDOW_GROUP:
|
|
g_value_set_object (value, mutter_plugin_get_window_group (global->plugin));
|
|
break;
|
|
case PROP_WINDOW_MANAGER:
|
|
g_value_set_object (value, global->wm);
|
|
break;
|
|
case PROP_IMAGEDIR:
|
|
g_value_set_string (value, global->imagedir);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
shell_global_init (ShellGlobal *global)
|
|
{
|
|
const char *datadir = g_getenv ("GNOME_SHELL_DATADIR");
|
|
char *imagedir;
|
|
|
|
if (!datadir)
|
|
datadir = GNOME_SHELL_DATADIR;
|
|
|
|
/* We make sure imagedir ends with a '/', since the JS won't have
|
|
* access to g_build_filename() and so will end up just
|
|
* concatenating global.imagedir to a filename.
|
|
*/
|
|
imagedir = g_build_filename (datadir, "images/", NULL);
|
|
if (g_file_test (imagedir, G_FILE_TEST_IS_DIR))
|
|
global->imagedir = imagedir;
|
|
else
|
|
{
|
|
g_free (imagedir);
|
|
global->imagedir = g_strdup_printf ("%s/", datadir);
|
|
}
|
|
}
|
|
|
|
static void
|
|
shell_global_class_init (ShellGlobalClass *klass)
|
|
{
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
|
|
gobject_class->get_property = shell_global_get_property;
|
|
gobject_class->set_property = shell_global_set_property;
|
|
|
|
shell_global_signals[PANEL_RUN_DIALOG] =
|
|
g_signal_new ("panel-run-dialog",
|
|
G_TYPE_FROM_CLASS (klass),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (ShellGlobalClass, panel_run_dialog),
|
|
NULL, NULL,
|
|
g_cclosure_marshal_VOID__INT,
|
|
G_TYPE_NONE, 1, G_TYPE_INT);
|
|
|
|
shell_global_signals[PANEL_MAIN_MENU] =
|
|
g_signal_new ("panel-main-menu",
|
|
G_TYPE_FROM_CLASS (klass),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (ShellGlobalClass, panel_main_menu),
|
|
NULL, NULL,
|
|
g_cclosure_marshal_VOID__INT,
|
|
G_TYPE_NONE, 1, G_TYPE_INT);
|
|
|
|
g_object_class_install_property (gobject_class,
|
|
PROP_OVERLAY_GROUP,
|
|
g_param_spec_object ("overlay-group",
|
|
"Overlay Group",
|
|
"Actor holding objects that appear above the desktop contents",
|
|
CLUTTER_TYPE_ACTOR,
|
|
G_PARAM_READABLE));
|
|
g_object_class_install_property (gobject_class,
|
|
PROP_SCREEN,
|
|
g_param_spec_object ("screen",
|
|
"Screen",
|
|
"Metacity screen object for the shell",
|
|
META_TYPE_SCREEN,
|
|
G_PARAM_READABLE));
|
|
g_object_class_install_property (gobject_class,
|
|
PROP_SCREEN_WIDTH,
|
|
g_param_spec_int ("screen-width",
|
|
"Screen Width",
|
|
"Screen width, in pixels",
|
|
0, G_MAXINT, 1,
|
|
G_PARAM_READABLE));
|
|
|
|
g_object_class_install_property (gobject_class,
|
|
PROP_SCREEN_HEIGHT,
|
|
g_param_spec_int ("screen-height",
|
|
"Screen Height",
|
|
"Screen height, in pixels",
|
|
0, G_MAXINT, 1,
|
|
G_PARAM_READABLE));
|
|
g_object_class_install_property (gobject_class,
|
|
PROP_STAGE,
|
|
g_param_spec_object ("stage",
|
|
"Stage",
|
|
"Stage holding the desktop scene graph",
|
|
CLUTTER_TYPE_ACTOR,
|
|
G_PARAM_READABLE));
|
|
g_object_class_install_property (gobject_class,
|
|
PROP_WINDOW_GROUP,
|
|
g_param_spec_object ("window-group",
|
|
"Window Group",
|
|
"Actor holding window actors",
|
|
CLUTTER_TYPE_ACTOR,
|
|
G_PARAM_READABLE));
|
|
g_object_class_install_property (gobject_class,
|
|
PROP_WINDOW_MANAGER,
|
|
g_param_spec_object ("window-manager",
|
|
"Window Manager",
|
|
"Window management interface",
|
|
SHELL_TYPE_WM,
|
|
G_PARAM_READABLE));
|
|
g_object_class_install_property (gobject_class,
|
|
PROP_IMAGEDIR,
|
|
g_param_spec_string ("imagedir",
|
|
"Image directory",
|
|
"Directory containing gnome-shell image files",
|
|
NULL,
|
|
G_PARAM_READABLE));
|
|
}
|
|
|
|
/**
|
|
* shell_clutter_texture_set_from_pixbuf:
|
|
* texture: #ClutterTexture to be modified
|
|
* pixbuf: #GdkPixbuf to set as an image for #ClutterTexture
|
|
*
|
|
* Convenience function for setting an image for #ClutterTexture based on #GdkPixbuf.
|
|
* Copied from an example posted by hp in this thread http://mail.gnome.org/archives/gtk-devel-list/2008-September/msg00218.html
|
|
*
|
|
* Return value: %TRUE on success, %FALSE on failure
|
|
*/
|
|
gboolean
|
|
shell_clutter_texture_set_from_pixbuf (ClutterTexture *texture,
|
|
GdkPixbuf *pixbuf)
|
|
{
|
|
return clutter_texture_set_from_rgb_data (texture,
|
|
gdk_pixbuf_get_pixels (pixbuf),
|
|
gdk_pixbuf_get_has_alpha (pixbuf),
|
|
gdk_pixbuf_get_width (pixbuf),
|
|
gdk_pixbuf_get_height (pixbuf),
|
|
gdk_pixbuf_get_rowstride (pixbuf),
|
|
gdk_pixbuf_get_has_alpha (pixbuf)
|
|
? 4 : 3,
|
|
0, NULL);
|
|
}
|
|
|
|
/**
|
|
* shell_global_get:
|
|
*
|
|
* Gets the singleton global object that represents the desktop.
|
|
*
|
|
* Return value: (transfer none): the singleton global object
|
|
*/
|
|
ShellGlobal *
|
|
shell_global_get (void)
|
|
{
|
|
static ShellGlobal *the_object = NULL;
|
|
|
|
if (!the_object)
|
|
the_object = g_object_new (SHELL_TYPE_GLOBAL, 0);
|
|
|
|
return the_object;
|
|
}
|
|
|
|
/**
|
|
* shell_global_set_stage_input_area:
|
|
* x: X coordinate of rectangle
|
|
* y: Y coordinate of rectangle
|
|
* width: width of rectangle
|
|
* height: height of rectangle
|
|
*
|
|
* Sets the area of the stage that is responsive to mouse clicks as
|
|
* a rectangle.
|
|
*/
|
|
void
|
|
shell_global_set_stage_input_area (ShellGlobal *global,
|
|
int x,
|
|
int y,
|
|
int width,
|
|
int height)
|
|
{
|
|
g_return_if_fail (SHELL_IS_GLOBAL (global));
|
|
|
|
mutter_plugin_set_stage_input_area (global->plugin, x, y, width, height);
|
|
}
|
|
|
|
/**
|
|
* shell_global_get_windows:
|
|
*
|
|
* Gets the list of MutterWindows for the plugin's screen
|
|
*
|
|
* Return value: (element-type MutterWindow) (transfer none): the list of windows
|
|
*/
|
|
GList *
|
|
shell_global_get_windows (ShellGlobal *global)
|
|
{
|
|
g_return_val_if_fail (SHELL_IS_GLOBAL (global), NULL);
|
|
|
|
return mutter_plugin_get_windows (global->plugin);
|
|
}
|
|
|
|
void
|
|
_shell_global_set_plugin (ShellGlobal *global,
|
|
MutterPlugin *plugin)
|
|
{
|
|
g_return_if_fail (SHELL_IS_GLOBAL (global));
|
|
g_return_if_fail (global->plugin == NULL);
|
|
|
|
global->plugin = plugin;
|
|
global->wm = shell_wm_new (plugin);
|
|
}
|
|
|
|
/**
|
|
* shell_global_grab_keyboard:
|
|
* @global: a #ShellGlobal
|
|
*
|
|
* Grab the keyboard to the stage window. The stage will receive
|
|
* all keyboard events until shell_global_ungrab_keyboard() is called.
|
|
* This is appropriate to do when the desktop goes into a special
|
|
* mode where no normal global key shortcuts or application keyboard
|
|
* processing should happen.
|
|
*/
|
|
gboolean
|
|
shell_global_grab_keyboard (ShellGlobal *global)
|
|
{
|
|
MetaScreen *screen = mutter_plugin_get_screen (global->plugin);
|
|
MetaDisplay *display = meta_screen_get_display (screen);
|
|
Display *xdisplay = meta_display_get_xdisplay (display);
|
|
ClutterStage *stage = CLUTTER_STAGE (mutter_plugin_get_stage (global->plugin));
|
|
Window stagewin = clutter_x11_get_stage_window (stage);
|
|
|
|
/* FIXME: we need to coordinate with the rest of Metacity or we
|
|
* may grab the keyboard away from other portions of Metacity
|
|
* and leave Metacity in a confused state. An X client is allowed
|
|
* to overgrab itself, though not allowed to grab they keyboard
|
|
* away from another applications.
|
|
*/
|
|
if (global->keyboard_grabbed)
|
|
return FALSE;
|
|
|
|
if (XGrabKeyboard (xdisplay, stagewin,
|
|
False, /* owner_events - steal events from the rest of metacity */
|
|
GrabModeAsync, GrabModeAsync,
|
|
CurrentTime) != Success)
|
|
return FALSE; /* probably AlreadyGrabbed, some other app has a keyboard grab */
|
|
|
|
global->keyboard_grabbed = TRUE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* shell_global_ungrab_keyboard:
|
|
* @global: a #ShellGlobal
|
|
*
|
|
* Undoes the effect of shell_global_grab_keyboard
|
|
*/
|
|
void
|
|
shell_global_ungrab_keyboard (ShellGlobal *global)
|
|
{
|
|
MetaScreen *screen;
|
|
MetaDisplay *display;
|
|
Display *xdisplay;
|
|
|
|
g_return_if_fail (global->keyboard_grabbed);
|
|
|
|
screen = mutter_plugin_get_screen (global->plugin);
|
|
display = meta_screen_get_display (screen);
|
|
xdisplay = meta_display_get_xdisplay (display);
|
|
|
|
XUngrabKeyboard (xdisplay, CurrentTime);
|
|
|
|
global->keyboard_grabbed = FALSE;
|
|
}
|
|
|
|
/**
|
|
* shell_global_reexec_self:
|
|
* @global: A #ShellGlobal
|
|
*
|
|
* Restart the current process. Only intended for development purposes.
|
|
*/
|
|
void
|
|
shell_global_reexec_self (ShellGlobal *global)
|
|
{
|
|
GPtrArray *arr;
|
|
gsize len;
|
|
char *buf;
|
|
char *buf_p;
|
|
char *buf_end;
|
|
GError *error = NULL;
|
|
|
|
/* Linux specific (I think, anyways). */
|
|
if (!g_file_get_contents ("/proc/self/cmdline", &buf, &len, &error))
|
|
{
|
|
g_warning ("failed to get /proc/self/cmdline: %s", error->message);
|
|
return;
|
|
}
|
|
|
|
buf_end = buf+len;
|
|
arr = g_ptr_array_new ();
|
|
/* The cmdline file is NUL-separated */
|
|
for (buf_p = buf; buf_p < buf_end; buf_p = buf_p + strlen (buf_p) + 1)
|
|
g_ptr_array_add (arr, buf_p);
|
|
|
|
g_ptr_array_add (arr, NULL);
|
|
execvp (arr->pdata[0], (char**)arr->pdata);
|
|
g_warning ("failed to reexec: %s", g_strerror (errno));
|
|
g_ptr_array_free (arr, TRUE);
|
|
} |