2008-12-01 19:51:43 +00:00
|
|
|
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
2008-10-31 18:09:20 +00:00
|
|
|
|
2008-10-31 04:22:44 +00:00
|
|
|
const Clutter = imports.gi.Clutter;
|
2009-05-01 18:13:51 +00:00
|
|
|
const Gdk = imports.gi.Gdk;
|
2009-01-22 21:28:19 +00:00
|
|
|
const Gio = imports.gi.Gio;
|
2008-12-05 21:50:09 +00:00
|
|
|
const Mainloop = imports.mainloop;
|
2009-04-29 18:01:09 +00:00
|
|
|
const Meta = imports.gi.Meta;
|
2009-02-02 23:02:16 +00:00
|
|
|
const Shell = imports.gi.Shell;
|
|
|
|
const Signals = imports.signals;
|
2008-10-31 04:22:44 +00:00
|
|
|
|
2008-10-31 23:09:46 +00:00
|
|
|
const Overlay = imports.ui.overlay;
|
2009-02-02 23:02:16 +00:00
|
|
|
const Panel = imports.ui.panel;
|
2008-12-09 22:10:43 +00:00
|
|
|
const RunDialog = imports.ui.runDialog;
|
2009-02-10 16:12:58 +00:00
|
|
|
const Tweener = imports.ui.tweener;
|
2008-12-09 22:10:43 +00:00
|
|
|
const WindowManager = imports.ui.windowManager;
|
2008-10-31 18:09:20 +00:00
|
|
|
|
2008-10-31 18:29:42 +00:00
|
|
|
const DEFAULT_BACKGROUND_COLOR = new Clutter.Color();
|
|
|
|
DEFAULT_BACKGROUND_COLOR.from_pixel(0x2266bbff);
|
|
|
|
|
2008-10-31 18:09:20 +00:00
|
|
|
let panel = null;
|
2008-10-31 23:09:46 +00:00
|
|
|
let overlay = null;
|
2008-12-04 15:16:16 +00:00
|
|
|
let overlayActive = false;
|
2008-12-09 22:10:43 +00:00
|
|
|
let runDialog = null;
|
2008-11-21 14:02:09 +00:00
|
|
|
let wm = null;
|
2009-03-13 21:14:31 +00:00
|
|
|
let recorder = null;
|
2009-03-26 22:01:07 +00:00
|
|
|
let inModal = false;
|
2008-10-31 18:09:20 +00:00
|
|
|
|
2008-10-31 04:22:44 +00:00
|
|
|
function start() {
|
2008-11-26 19:14:18 +00:00
|
|
|
let global = Shell.Global.get();
|
2009-01-22 21:28:19 +00:00
|
|
|
|
|
|
|
Gio.DesktopAppInfo.set_desktop_env("GNOME");
|
|
|
|
|
2009-01-19 23:21:57 +00:00
|
|
|
global.grab_dbus_service();
|
|
|
|
global.start_task_panel();
|
2008-10-31 18:29:42 +00:00
|
|
|
|
2009-02-10 16:12:58 +00:00
|
|
|
Tweener.init();
|
2008-11-23 04:12:34 +00:00
|
|
|
|
2008-10-31 18:29:42 +00:00
|
|
|
// The background color really only matters if there is no desktop
|
|
|
|
// window (say, nautilus) running. We set it mostly so things look good
|
|
|
|
// when we are running inside Xephyr.
|
|
|
|
global.stage.color = DEFAULT_BACKGROUND_COLOR;
|
|
|
|
|
|
|
|
// Mutter currently hardcodes putting "Yessir. The compositor is running""
|
|
|
|
// in the overlay. Clear that out.
|
2008-10-31 23:09:46 +00:00
|
|
|
let children = global.overlay_group.get_children();
|
2008-10-31 18:29:42 +00:00
|
|
|
for (let i = 0; i < children.length; i++)
|
2008-11-28 20:12:20 +00:00
|
|
|
children[i].destroy();
|
2008-10-31 18:29:42 +00:00
|
|
|
|
2008-11-19 23:21:42 +00:00
|
|
|
global.connect('panel-run-dialog', function(panel) {
|
|
|
|
// Make sure not more than one run dialog is shown.
|
2008-12-09 22:10:43 +00:00
|
|
|
if (!runDialog) {
|
|
|
|
runDialog = new RunDialog.RunDialog();
|
2009-05-02 22:33:13 +00:00
|
|
|
let endHandler = function() {
|
2008-12-09 22:10:43 +00:00
|
|
|
runDialog.destroy();
|
|
|
|
runDialog = null;
|
2008-11-19 23:21:42 +00:00
|
|
|
};
|
2009-05-02 22:33:13 +00:00
|
|
|
runDialog.connect('run', endHandler);
|
|
|
|
runDialog.connect('cancel', endHandler);
|
2008-12-09 22:10:43 +00:00
|
|
|
if (!runDialog.show())
|
2009-05-02 22:33:13 +00:00
|
|
|
endHandler();
|
2008-11-19 23:21:42 +00:00
|
|
|
}
|
2008-11-07 18:42:23 +00:00
|
|
|
});
|
|
|
|
|
2008-10-31 18:09:20 +00:00
|
|
|
panel = new Panel.Panel();
|
2008-11-21 14:02:09 +00:00
|
|
|
|
|
|
|
overlay = new Overlay.Overlay();
|
|
|
|
wm = new WindowManager.WindowManager();
|
2008-12-05 21:12:43 +00:00
|
|
|
|
|
|
|
let display = global.screen.get_display();
|
2009-02-13 17:11:10 +00:00
|
|
|
let toggleOverlay = function(display) {
|
2009-01-07 22:19:46 +00:00
|
|
|
if (overlay.visible) {
|
2009-05-02 22:33:13 +00:00
|
|
|
hideOverlay();
|
2009-01-07 22:19:46 +00:00
|
|
|
} else {
|
2009-05-02 22:33:13 +00:00
|
|
|
showOverlay();
|
2009-01-07 22:19:46 +00:00
|
|
|
}
|
2009-02-17 20:15:01 +00:00
|
|
|
};
|
2009-03-13 21:14:31 +00:00
|
|
|
|
|
|
|
global.screen.connect('toggle-recording', function() {
|
|
|
|
if (recorder == null) {
|
|
|
|
// We have to initialize GStreamer first. This isn't done
|
|
|
|
// inside ShellRecorder to make it usable inside projects
|
|
|
|
// with other usage of GStreamer.
|
|
|
|
let Gst = imports.gi.Gst;
|
|
|
|
Gst.init(null, null);
|
|
|
|
recorder = new Shell.Recorder({ stage: global.stage });
|
|
|
|
}
|
|
|
|
|
|
|
|
if (recorder.is_recording()) {
|
|
|
|
recorder.pause();
|
|
|
|
} else {
|
|
|
|
recorder.record();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2009-02-13 17:11:10 +00:00
|
|
|
display.connect('overlay-key', toggleOverlay);
|
|
|
|
global.connect('panel-main-menu', toggleOverlay);
|
|
|
|
|
2009-04-29 18:01:09 +00:00
|
|
|
// Need to update struts on new workspaces when they are added
|
|
|
|
global.screen.connect('notify::n-workspaces', _setStageArea);
|
|
|
|
|
2009-02-16 19:32:04 +00:00
|
|
|
Mainloop.idle_add(_removeUnusedWorkspaces);
|
|
|
|
}
|
|
|
|
|
|
|
|
// metacity-clutter currently uses the same prefs as plain metacity,
|
|
|
|
// which probably means we'll be starting out with multiple workspaces;
|
|
|
|
// remove any unused ones. (We do this from an idle handler, because
|
|
|
|
// global.get_windows() still returns NULL at the point when start()
|
|
|
|
// is called.)
|
|
|
|
function _removeUnusedWorkspaces() {
|
|
|
|
|
|
|
|
let global = Shell.Global.get();
|
|
|
|
|
|
|
|
let windows = global.get_windows();
|
|
|
|
let maxWorkspace = 0;
|
|
|
|
for (let i = 0; i < windows.length; i++) {
|
|
|
|
let win = windows[i];
|
|
|
|
|
|
|
|
if (!win.get_meta_window().is_on_all_workspaces() &&
|
|
|
|
win.get_workspace() > maxWorkspace) {
|
|
|
|
maxWorkspace = win.get_workspace();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let screen = global.screen;
|
|
|
|
if (screen.n_workspaces > maxWorkspace) {
|
|
|
|
for (let w = screen.n_workspaces - 1; w > maxWorkspace; w--) {
|
|
|
|
let workspace = screen.get_workspace_by_index(w);
|
|
|
|
screen.remove_workspace(workspace, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2008-10-31 23:09:46 +00:00
|
|
|
}
|
|
|
|
|
2008-12-01 19:51:43 +00:00
|
|
|
// Used to go into a mode where all keyboard and mouse input goes to
|
|
|
|
// the stage. Returns true if we successfully grabbed the keyboard and
|
|
|
|
// went modal, false otherwise
|
2008-11-24 19:07:18 +00:00
|
|
|
function startModal() {
|
2008-11-26 19:14:18 +00:00
|
|
|
let global = Shell.Global.get();
|
2008-10-31 23:09:46 +00:00
|
|
|
|
2008-11-24 19:07:18 +00:00
|
|
|
if (!global.grab_keyboard())
|
2008-11-28 20:12:20 +00:00
|
|
|
return false;
|
2009-04-29 18:01:09 +00:00
|
|
|
global.set_stage_input_mode(Shell.StageInputMode.FULLSCREEN);
|
2008-11-24 19:07:18 +00:00
|
|
|
|
2009-03-26 22:01:07 +00:00
|
|
|
inModal = true;
|
2008-11-24 19:07:18 +00:00
|
|
|
|
|
|
|
return true;
|
2008-10-31 23:09:46 +00:00
|
|
|
}
|
|
|
|
|
2008-11-24 19:07:18 +00:00
|
|
|
function endModal() {
|
2008-11-26 19:14:18 +00:00
|
|
|
let global = Shell.Global.get();
|
2008-10-31 23:09:46 +00:00
|
|
|
|
2008-11-24 19:07:18 +00:00
|
|
|
global.ungrab_keyboard();
|
2009-04-29 18:01:09 +00:00
|
|
|
global.set_stage_input_mode(Shell.StageInputMode.NORMAL);
|
2009-03-26 22:01:07 +00:00
|
|
|
inModal = false;
|
2008-10-31 04:22:44 +00:00
|
|
|
}
|
2008-11-24 19:07:18 +00:00
|
|
|
|
2009-05-02 22:33:13 +00:00
|
|
|
function showOverlay() {
|
2008-12-04 15:16:16 +00:00
|
|
|
if (startModal()) {
|
|
|
|
overlayActive = true;
|
2008-11-28 20:12:20 +00:00
|
|
|
overlay.show();
|
2008-12-04 15:16:16 +00:00
|
|
|
}
|
2008-11-24 19:07:18 +00:00
|
|
|
}
|
|
|
|
|
2009-05-02 22:33:13 +00:00
|
|
|
function hideOverlay() {
|
2008-11-24 19:07:18 +00:00
|
|
|
overlay.hide();
|
2008-12-04 15:16:16 +00:00
|
|
|
overlayActive = false;
|
2008-11-24 19:07:18 +00:00
|
|
|
endModal();
|
|
|
|
}
|
2009-04-29 18:01:09 +00:00
|
|
|
|
2009-05-02 22:33:13 +00:00
|
|
|
function createAppLaunchContext() {
|
2009-05-01 18:13:51 +00:00
|
|
|
let global = Shell.Global.get();
|
|
|
|
let screen = global.screen;
|
|
|
|
let display = screen.get_display();
|
|
|
|
|
|
|
|
let context = new Gdk.AppLaunchContext();
|
|
|
|
context.set_timestamp(display.get_current_time());
|
|
|
|
|
|
|
|
// Make sure that the app is opened on the current workspace even if
|
2009-05-01 20:21:00 +00:00
|
|
|
// the user switches before it starts
|
2009-05-01 18:13:51 +00:00
|
|
|
context.set_desktop(screen.get_active_workspace_index());
|
|
|
|
|
|
|
|
return context;
|
|
|
|
}
|
|
|
|
|
2009-04-29 18:01:09 +00:00
|
|
|
let _shellActors = [];
|
|
|
|
|
|
|
|
// For adding an actor that is part of the shell in the normal desktop view
|
|
|
|
function addShellActor(actor) {
|
|
|
|
let global = Shell.Global.get();
|
|
|
|
|
|
|
|
_shellActors.push(actor);
|
|
|
|
|
|
|
|
actor.connect('notify::visible', _setStageArea);
|
|
|
|
actor.connect('destroy', function(actor) {
|
|
|
|
let i = _shellActors.indexOf(actor);
|
|
|
|
if (i != -1)
|
|
|
|
_shellActors.splice(i, 1);
|
|
|
|
_setStageArea();
|
|
|
|
});
|
|
|
|
|
|
|
|
while (actor != global.stage) {
|
|
|
|
actor.connect('notify::allocation', _setStageArea);
|
|
|
|
actor = actor.get_parent();
|
|
|
|
}
|
|
|
|
|
|
|
|
_setStageArea();
|
|
|
|
}
|
|
|
|
|
|
|
|
function _setStageArea() {
|
|
|
|
let global = Shell.Global.get();
|
|
|
|
let rects = [], struts = [];
|
|
|
|
|
|
|
|
for (let i = 0; i < _shellActors.length; i++) {
|
|
|
|
if (!_shellActors[i].visible)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
let [x, y] = _shellActors[i].get_transformed_position();
|
|
|
|
let [w, h] = _shellActors[i].get_transformed_size();
|
|
|
|
|
|
|
|
let rect = new Meta.Rectangle({ x: x, y: y, width: w, height: h});
|
|
|
|
rects.push(rect);
|
|
|
|
|
|
|
|
// Metacity wants to know what side of the screen the strut is
|
|
|
|
// considered to be attached to. If the actor is only touching
|
|
|
|
// one edge, or is touching the entire width/height of one
|
|
|
|
// edge, then it's obvious which side to call it. If it's in a
|
|
|
|
// corner, we pick a side arbitrarily. If it doesn't touch any
|
|
|
|
// edges, or it spans the width/height across the middle of
|
|
|
|
// the screen, then we don't create a strut for it at all.
|
|
|
|
let side;
|
|
|
|
if (w >= global.screen_width) {
|
|
|
|
if (y <= 0)
|
|
|
|
side = Meta.Side.TOP;
|
|
|
|
else if (y + h >= global.screen_height)
|
|
|
|
side = Meta.Side.BOTTOM;
|
|
|
|
else
|
|
|
|
continue;
|
|
|
|
} else if (h >= global.screen_height) {
|
|
|
|
if (x <= 0)
|
|
|
|
side = Meta.Side.LEFT;
|
|
|
|
else if (x + w >= global.screen_width)
|
|
|
|
side = Meta.Side.RIGHT;
|
|
|
|
else
|
|
|
|
continue;
|
|
|
|
} else if (x <= 0)
|
|
|
|
side = Meta.Side.LEFT;
|
|
|
|
else if (y <= 0)
|
|
|
|
side = Meta.Side.TOP;
|
|
|
|
else if (x + w >= global.screen_width)
|
|
|
|
side = Meta.Side.RIGHT;
|
|
|
|
else if (y + h >= global.screen_height)
|
|
|
|
side = Meta.Side.BOTTOM;
|
|
|
|
else
|
|
|
|
continue;
|
|
|
|
|
|
|
|
let strut = new Meta.Strut({ rect: rect, side: side });
|
|
|
|
struts.push(strut);
|
|
|
|
}
|
|
|
|
|
|
|
|
let screen = global.screen;
|
|
|
|
for (let w = 0; w < screen.n_workspaces; w++) {
|
|
|
|
let workspace = screen.get_workspace_by_index(w);
|
|
|
|
workspace.set_builtin_struts(struts);
|
|
|
|
}
|
|
|
|
|
|
|
|
global.set_stage_input_region(rects);
|
|
|
|
}
|