mirror of
https://github.com/elementary/gala.git
synced 2024-12-25 02:02:11 +03:00
Some major code-style changes and clean up
* add copyright headers * don't use "this." * use tabs to indent * some varible renames * factor out some callbacks There is probably more to come
This commit is contained in:
parent
43cb1fa553
commit
50399b4ad5
@ -41,10 +41,9 @@ ensure_vala_version("0.16.0" MINIMUM)
|
||||
|
||||
include(ValaPrecompile)
|
||||
vala_precompile(VALA_C
|
||||
src/gala.vala
|
||||
src/gala-settings.vala
|
||||
src/gala-plugin.vala
|
||||
src/main.vala
|
||||
src/Main.vala
|
||||
src/Settings.vala
|
||||
src/TextShadowEffect.vala
|
||||
src/Widgets/WorkspaceSwitcher.vala
|
||||
src/Widgets/WindowSwitcher.vala
|
||||
src/Widgets/CornerMenu.vala
|
||||
@ -69,4 +68,4 @@ add_schema ("data/org.pantheon.desktop.gala.gschema.xml")
|
||||
add_executable(gala ${VALA_C})#src/main.c)
|
||||
|
||||
install(TARGETS gala RUNTIME DESTINATION bin)
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/data/gala.desktop DESTINATION share/applications)
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/data/gala.desktop DESTINATION share/applications)
|
||||
|
497
src/Main.vala
Normal file
497
src/Main.vala
Normal file
@ -0,0 +1,497 @@
|
||||
//
|
||||
// Copyright (C) 2012 Tom Beckmann, Rico Tzschichholz
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
using Meta;
|
||||
|
||||
namespace Gala
|
||||
{
|
||||
public enum InputArea {
|
||||
NONE,
|
||||
FULLSCREEN,
|
||||
HOT_CORNER
|
||||
}
|
||||
|
||||
public class Plugin : Meta.Plugin
|
||||
{
|
||||
WorkspaceSwitcher wswitcher;
|
||||
WindowSwitcher winswitcher;
|
||||
CornerMenu corner_menu;
|
||||
Clutter.Actor elements;
|
||||
|
||||
public Plugin ()
|
||||
{
|
||||
if (Settings.get_default().use_gnome_defaults)
|
||||
return;
|
||||
|
||||
Prefs.override_preference_schema ("attach-modal-dialogs", SCHEMA);
|
||||
Prefs.override_preference_schema ("button-layout", SCHEMA);
|
||||
Prefs.override_preference_schema ("edge-tiling", SCHEMA);
|
||||
Prefs.override_preference_schema ("enable-animations", SCHEMA);
|
||||
Prefs.override_preference_schema ("theme", SCHEMA);
|
||||
}
|
||||
|
||||
public override void start ()
|
||||
{
|
||||
elements = Compositor.get_stage_for_screen (screen);
|
||||
Compositor.get_window_group_for_screen (screen).reparent (elements);
|
||||
Compositor.get_overlay_group_for_screen (screen).reparent (elements);
|
||||
Compositor.get_stage_for_screen (screen).add_child (elements);
|
||||
|
||||
screen.override_workspace_layout (ScreenCorner.TOPLEFT, false, -1, 4);
|
||||
|
||||
int width, height;
|
||||
screen.get_size (out width, out height);
|
||||
|
||||
corner_menu = new CornerMenu (this);
|
||||
elements.add_child (corner_menu);
|
||||
corner_menu.visible = false;
|
||||
|
||||
wswitcher = new WorkspaceSwitcher (this, width, height);
|
||||
wswitcher.workspaces = 4;
|
||||
elements.add_child (wswitcher);
|
||||
|
||||
winswitcher = new WindowSwitcher (this);
|
||||
elements.add_child (winswitcher);
|
||||
|
||||
KeyBinding.set_custom_handler ("panel-main-menu", () => {
|
||||
try {
|
||||
Process.spawn_command_line_async (
|
||||
Settings.get_default().panel_main_menu_action);
|
||||
} catch (Error e) { warning (e.message); }
|
||||
});
|
||||
|
||||
KeyBinding.set_custom_handler ("switch-windows",
|
||||
(display, screen, window, ev, binding) => {
|
||||
window_switcher (display, screen, binding, false);
|
||||
});
|
||||
KeyBinding.set_custom_handler ("switch-windows-backward",
|
||||
(display, screen, window, ev, binding) => {
|
||||
window_switcher (display, screen, binding, true);
|
||||
});
|
||||
|
||||
KeyBinding.set_custom_handler ("switch-to-workspace-left", () => {});
|
||||
KeyBinding.set_custom_handler ("switch-to-workspace-right", () => {});
|
||||
KeyBinding.set_custom_handler ("switch-to-workspace-up", (d, s) => workspace_switcher (s, true));
|
||||
KeyBinding.set_custom_handler ("switch-to-workspace-down", (d, s) => workspace_switcher (s, false));
|
||||
|
||||
KeyBinding.set_custom_handler ("move-to-workspace-left", () => {});
|
||||
KeyBinding.set_custom_handler ("move-to-workspace-right", () => {});
|
||||
KeyBinding.set_custom_handler ("move-to-workspace-up", (d, s, w) => move_window (w, true) );
|
||||
KeyBinding.set_custom_handler ("move-to-workspace-down", (d, s, w) => move_window (w, false) );
|
||||
|
||||
/*shadows*/
|
||||
ShadowFactory.get_default ().set_params ("normal", true, {30, -1, 0, 35, 120});
|
||||
|
||||
/*hot corner*/
|
||||
var hot_corner = new Clutter.Rectangle ();
|
||||
hot_corner.x = width - 2;
|
||||
hot_corner.y = height - 2;
|
||||
hot_corner.width = 2;
|
||||
hot_corner.height = 2;
|
||||
hot_corner.reactive = true;
|
||||
|
||||
hot_corner.enter_event.connect (() => {
|
||||
corner_menu.show ();
|
||||
return false;
|
||||
});
|
||||
|
||||
Compositor.get_overlay_group_for_screen (screen).add_child (hot_corner);
|
||||
|
||||
if (Settings.get_default ().enable_manager_corner)
|
||||
set_input_area (InputArea.HOT_CORNER);
|
||||
else
|
||||
set_input_area (InputArea.NONE);
|
||||
|
||||
Settings.get_default ().notify["enable-manager-corner"].connect (() => {
|
||||
if (Settings.get_default ().enable_manager_corner)
|
||||
set_input_area (InputArea.HOT_CORNER);
|
||||
else
|
||||
set_input_area (InputArea.NONE);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* set the area where clutter can receive events
|
||||
**/
|
||||
public void set_input_area (InputArea area)
|
||||
{
|
||||
X.Rectangle rect;
|
||||
int width, height;
|
||||
screen.get_size (out width, out height);
|
||||
|
||||
switch (area) {
|
||||
case InputArea.FULLSCREEN:
|
||||
rect = {0, 0, (short)width, (short)height};
|
||||
break;
|
||||
case InputArea.HOT_CORNER: //leave one pix in the bottom left
|
||||
rect = {(short)(width - 1), (short)(height - 1), 1, 1};
|
||||
break;
|
||||
default:
|
||||
Util.empty_stage_input_region (screen);
|
||||
return;
|
||||
}
|
||||
|
||||
var xregion = X.Fixes.create_region (screen.get_display ().get_xdisplay (), {rect});
|
||||
Util.set_stage_input_region (screen, xregion);
|
||||
}
|
||||
|
||||
public void move_window (Window? window, bool up)
|
||||
{
|
||||
if (window == null || window.is_on_all_workspaces ())
|
||||
return;
|
||||
|
||||
var idx = screen.get_active_workspace ().index () + ((up)?-1:1);
|
||||
window.change_workspace_by_index (idx, false,
|
||||
screen.get_display ().get_current_time ());
|
||||
|
||||
screen.get_workspace_by_index (idx).activate_with_focus (window,
|
||||
screen.get_display ().get_current_time ());
|
||||
}
|
||||
|
||||
public new void begin_modal ()
|
||||
{
|
||||
base.begin_modal (x_get_stage_window (Compositor.get_stage_for_screen (screen)), {}, 0, screen.get_display ().get_current_time ());
|
||||
}
|
||||
public new void end_modal ()
|
||||
{
|
||||
base.end_modal (get_screen ().get_display ().get_current_time ());
|
||||
}
|
||||
|
||||
public void window_switcher (Display display, Screen screen, KeyBinding binding, bool backward)
|
||||
{
|
||||
if (screen.get_display ().get_tab_list (TabList.NORMAL, screen, screen.get_active_workspace ()).length () == 0)
|
||||
return;
|
||||
|
||||
begin_modal ();
|
||||
|
||||
int width, height;
|
||||
screen.get_size (out width, out height);
|
||||
|
||||
winswitcher.list_windows (display, screen, binding, backward);
|
||||
|
||||
winswitcher.x = width / 2 - winswitcher.width / 2;
|
||||
winswitcher.y = height / 2 - winswitcher.height / 2;
|
||||
winswitcher.grab_key_focus ();
|
||||
winswitcher.animate (Clutter.AnimationMode.EASE_OUT_QUAD, 250, opacity : 255);
|
||||
}
|
||||
|
||||
public void workspace_switcher (Screen screen, bool up)
|
||||
{
|
||||
int width, height;
|
||||
screen.get_size (out width, out height);
|
||||
|
||||
wswitcher.x = width / 2 - wswitcher.width / 2;
|
||||
wswitcher.y = height / 2 - wswitcher.height / 2;
|
||||
wswitcher.animate (Clutter.AnimationMode.EASE_OUT_QUAD, 100, opacity:255);
|
||||
wswitcher.workspace = move_workspaces (up);;
|
||||
|
||||
begin_modal ();
|
||||
wswitcher.grab_key_focus ();
|
||||
}
|
||||
|
||||
public int move_workspaces (bool up)
|
||||
{
|
||||
var i = screen.get_active_workspace_index ();
|
||||
|
||||
if (up && i - 1 >= 0) //move up
|
||||
i --;
|
||||
else if (!up && i + 1 < screen.n_workspaces) //move down
|
||||
i ++;
|
||||
|
||||
if (i != screen.get_active_workspace_index ()) {
|
||||
screen.get_workspace_by_index (i).
|
||||
activate (screen.get_display ().get_current_time ());
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
public override void minimize (WindowActor actor)
|
||||
{
|
||||
minimize_completed (actor);
|
||||
}
|
||||
|
||||
//stolen from original mutter plugin
|
||||
public override void maximize (WindowActor actor, int ex, int ey, int ew, int eh)
|
||||
{
|
||||
if (actor.meta_window.window_type == WindowType.NORMAL) {
|
||||
float x, y, width, height;
|
||||
actor.get_size (out width, out height);
|
||||
actor.get_position (out x, out y);
|
||||
|
||||
float scale_x = (float)ew / width;
|
||||
float scale_y = (float)eh / height;
|
||||
float anchor_x = (float)(x - ex) * width / (ew - width);
|
||||
float anchor_y = (float)(y - ey) * height / (eh - height);
|
||||
|
||||
actor.move_anchor_point (anchor_x, anchor_y);
|
||||
actor.animate (Clutter.AnimationMode.EASE_IN_SINE, 150, scale_x:scale_x,
|
||||
scale_y:scale_y).completed.connect ( () => {
|
||||
actor.move_anchor_point_from_gravity (Clutter.Gravity.NORTH_WEST);
|
||||
actor.animate (Clutter.AnimationMode.LINEAR, 1, scale_x:1.0f,
|
||||
scale_y:1.0f);//just scaling didnt want to work..
|
||||
maximize_completed (actor);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
maximize_completed (actor);
|
||||
}
|
||||
|
||||
public override void map (WindowActor actor)
|
||||
{
|
||||
actor.show ();
|
||||
|
||||
switch (actor.meta_window.window_type) {
|
||||
case WindowType.NORMAL:
|
||||
actor.scale_gravity = Clutter.Gravity.CENTER;
|
||||
actor.rotation_center_x = {0, actor.height, 10};
|
||||
actor.scale_x = 0.55f;
|
||||
actor.scale_y = 0.55f;
|
||||
actor.opacity = 0;
|
||||
actor.rotation_angle_x = 40.0f;
|
||||
actor.animate (Clutter.AnimationMode.EASE_OUT_QUAD, 350,
|
||||
scale_x:1.0f, scale_y:1.0f, rotation_angle_x:0.0f, opacity:255)
|
||||
.completed.connect ( () => {
|
||||
map_completed (actor);
|
||||
});
|
||||
break;
|
||||
case WindowType.MENU:
|
||||
case WindowType.DROPDOWN_MENU:
|
||||
case WindowType.POPUP_MENU:
|
||||
case WindowType.MODAL_DIALOG:
|
||||
case WindowType.DIALOG:
|
||||
actor.scale_gravity = Clutter.Gravity.NORTH;
|
||||
actor.scale_x = 1.0f;
|
||||
actor.scale_y = 0.0f;
|
||||
actor.opacity = 0;
|
||||
actor.animate (Clutter.AnimationMode.EASE_OUT_QUAD, 150,
|
||||
scale_y:1.0f, opacity:255).completed.connect ( () => {
|
||||
map_completed (actor);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
map_completed (actor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void destroy (WindowActor actor)
|
||||
{
|
||||
switch (actor.meta_window.window_type) {
|
||||
case WindowType.NORMAL:
|
||||
actor.scale_gravity = Clutter.Gravity.CENTER;
|
||||
actor.rotation_center_x = {0, actor.height, 10};
|
||||
actor.show ();
|
||||
actor.animate (Clutter.AnimationMode.EASE_IN_QUAD, 250,
|
||||
scale_x:0.95f, scale_y:0.95f, opacity:0, rotation_angle_x:15.0f)
|
||||
.completed.connect ( () => {
|
||||
destroy_completed (actor);
|
||||
});
|
||||
break;
|
||||
case WindowType.MENU:
|
||||
case WindowType.DROPDOWN_MENU:
|
||||
case WindowType.POPUP_MENU:
|
||||
case WindowType.MODAL_DIALOG:
|
||||
case WindowType.DIALOG:
|
||||
actor.scale_gravity = Clutter.Gravity.NORTH;
|
||||
actor.animate (Clutter.AnimationMode.EASE_OUT_QUAD, 200,
|
||||
scale_y:0.0f, opacity:0).completed.connect ( () => {
|
||||
destroy_completed (actor);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
destroy_completed (actor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
GLib.List<Clutter.Actor>? win;
|
||||
GLib.List<Clutter.Actor>? par; //class space for kill func
|
||||
Clutter.Group in_group;
|
||||
Clutter.Group out_group;
|
||||
|
||||
public override void switch_workspace (int from, int to, MotionDirection direction)
|
||||
{
|
||||
unowned List<Clutter.Actor> windows = Compositor.get_window_actors (get_screen ());
|
||||
//FIXME js/ui/windowManager.js line 430
|
||||
int w, h;
|
||||
get_screen ().get_size (out w, out h);
|
||||
|
||||
var x2 = 0.0f; var y2 = 0.0f;
|
||||
if (direction == MotionDirection.UP ||
|
||||
direction == MotionDirection.UP_LEFT ||
|
||||
direction == MotionDirection.UP_RIGHT)
|
||||
y2 = h;
|
||||
else if (direction == MotionDirection.DOWN ||
|
||||
direction == MotionDirection.DOWN_LEFT ||
|
||||
direction == MotionDirection.DOWN_RIGHT)
|
||||
y2 = -h;
|
||||
|
||||
if (direction == MotionDirection.LEFT ||
|
||||
direction == MotionDirection.UP_LEFT ||
|
||||
direction == MotionDirection.DOWN_LEFT)
|
||||
y2 = h;
|
||||
else if (direction == MotionDirection.RIGHT ||
|
||||
direction == MotionDirection.UP_RIGHT ||
|
||||
direction == MotionDirection.DOWN_RIGHT)
|
||||
y2 = -h;
|
||||
|
||||
var in_group = new Clutter.Group ();
|
||||
var out_group = new Clutter.Group ();
|
||||
var group = Compositor.get_window_group_for_screen (get_screen ());
|
||||
group.add_actor (in_group);
|
||||
group.add_actor (out_group);
|
||||
|
||||
win = new List<Clutter.Actor> ();
|
||||
par = new List<Clutter.Actor> ();
|
||||
|
||||
for (var i=0;i<windows.length ();i++) {
|
||||
var window = windows.nth_data (i);
|
||||
if (!(window as WindowActor).meta_window.showing_on_its_workspace ())
|
||||
continue;
|
||||
|
||||
win.append (window);
|
||||
par.append (window.get_parent ());
|
||||
if ((window as WindowActor).get_workspace () == from) {
|
||||
window.reparent (out_group);
|
||||
} else if ((window as WindowActor).get_workspace () == to) {
|
||||
window.reparent (in_group);
|
||||
window.show_all ();
|
||||
}
|
||||
}
|
||||
in_group.set_position (-x2, -y2);
|
||||
in_group.raise_top ();
|
||||
|
||||
out_group.animate (Clutter.AnimationMode.EASE_OUT_QUAD, 300,
|
||||
x:x2, y:y2);
|
||||
in_group.animate (Clutter.AnimationMode.EASE_OUT_QUAD, 300,
|
||||
x:0.0f, y:0.0f).completed.connect ( () => {
|
||||
end_switch_workspace ();
|
||||
});
|
||||
}
|
||||
|
||||
public override void kill_window_effects (WindowActor actor)
|
||||
{
|
||||
/*FIXME should call the things in anim.completed
|
||||
minimize_completed (actor);
|
||||
maximize_completed (actor);
|
||||
unmaximize_completed (actor);
|
||||
map_completed (actor);
|
||||
destroy_completed (actor);
|
||||
*/
|
||||
}
|
||||
|
||||
private void end_switch_workspace ()
|
||||
{
|
||||
if (win == null || par == null)
|
||||
return;
|
||||
|
||||
for (var i=0;i<win.length ();i++) {
|
||||
var window = win.nth_data (i);
|
||||
if ((window as WindowActor).is_destroyed ())
|
||||
continue;
|
||||
if (window.get_parent () == out_group) {
|
||||
window.reparent (par.nth_data (i));
|
||||
window.hide ();
|
||||
} else
|
||||
window.reparent (par.nth_data (i));
|
||||
}
|
||||
|
||||
win = null;
|
||||
par = null;
|
||||
|
||||
if (in_group != null) {
|
||||
in_group.detach_animation ();
|
||||
in_group.destroy ();
|
||||
}
|
||||
|
||||
if (out_group != null) {
|
||||
out_group.detach_animation ();
|
||||
out_group.destroy ();
|
||||
}
|
||||
|
||||
switch_workspace_completed ();
|
||||
}
|
||||
|
||||
public override void unmaximize (Meta.WindowActor actor, int x, int y, int w, int h)
|
||||
{
|
||||
unmaximize_completed (actor);
|
||||
}
|
||||
|
||||
public override void kill_switch_workspace ()
|
||||
{
|
||||
end_switch_workspace ();
|
||||
}
|
||||
|
||||
public override bool xevent_filter (X.Event event)
|
||||
{
|
||||
return x_handle_event (event) != 0;
|
||||
}
|
||||
|
||||
public override PluginInfo plugin_info ()
|
||||
{
|
||||
return {"Gala", Gala.VERSION, "Tom Beckmann", "GPLv3", "A nice window manager"};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const string VERSION = "0.1";
|
||||
const string SCHEMA = "org.pantheon.desktop.gala";
|
||||
|
||||
const OptionEntry[] OPTIONS = {
|
||||
{ "version", 0, OptionFlags.NO_ARG, OptionArg.CALLBACK, (void*) print_version, "Print version", null },
|
||||
{ null }
|
||||
};
|
||||
|
||||
void print_version () {
|
||||
stdout.printf ("Gala %s\n", Gala.VERSION);
|
||||
Meta.exit (Meta.ExitCode.SUCCESS);
|
||||
}
|
||||
|
||||
[CCode (cname="clutter_x11_handle_event")]
|
||||
public extern int x_handle_event (X.Event xevent);
|
||||
[CCode (cname="clutter_x11_get_stage_window")]
|
||||
public extern X.Window x_get_stage_window (Clutter.Actor stage);
|
||||
|
||||
int main (string [] args) {
|
||||
|
||||
unowned OptionContext ctx = Meta.get_option_context ();
|
||||
ctx.add_main_entries (Gala.OPTIONS, null);
|
||||
try {
|
||||
ctx.parse (ref args);
|
||||
} catch (Error e) {
|
||||
stderr.printf ("Error initializing: %s\n", e.message);
|
||||
Meta.exit (Meta.ExitCode.ERROR);
|
||||
}
|
||||
|
||||
Meta.Plugin.type_register (new Gala.Plugin ().get_type ());
|
||||
|
||||
/**
|
||||
* Prevent Meta.init () from causing gtk to load gail and at-bridge
|
||||
* Taken from Gnome-Shell main.c
|
||||
*/
|
||||
GLib.Environment.set_variable ("NO_GAIL", "1", true);
|
||||
GLib.Environment.set_variable ("NO_AT_BRIDGE", "1", true);
|
||||
Meta.init ();
|
||||
GLib.Environment.unset_variable ("NO_GAIL");
|
||||
GLib.Environment.unset_variable ("NO_AT_BRIDGE");
|
||||
|
||||
return Meta.run ();
|
||||
}
|
||||
}
|
46
src/Settings.vala
Normal file
46
src/Settings.vala
Normal file
@ -0,0 +1,46 @@
|
||||
//
|
||||
// Copyright (C) 2012 GardenGnome, Rico Tzschichholz
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
namespace Gala
|
||||
{
|
||||
public class Settings : Granite.Services.Settings
|
||||
{
|
||||
public bool attach_modal_dialogs { get; set; }
|
||||
public string[] button_layout { get; set; }
|
||||
public bool edge_tiling { get; set; }
|
||||
public bool enable_animations { get; set; }
|
||||
public string panel_main_menu_action { get; set; }
|
||||
public string theme { get; set; }
|
||||
public bool use_gnome_defaults { get; set; }
|
||||
public bool enable_manager_corner { get; set; }
|
||||
|
||||
static Settings? instance = null;
|
||||
|
||||
private Settings ()
|
||||
{
|
||||
base (SCHEMA);
|
||||
}
|
||||
|
||||
public static Settings get_default ()
|
||||
{
|
||||
if (instance == null)
|
||||
instance = new Settings ();
|
||||
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
}
|
62
src/TextShadowEffect.vala
Normal file
62
src/TextShadowEffect.vala
Normal file
@ -0,0 +1,62 @@
|
||||
//
|
||||
// Copyright (C) 2012 Tom Beckmann, Rico Tzschichholz
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
namespace Gala
|
||||
{
|
||||
public class TextShadowEffect : Clutter.Effect
|
||||
{
|
||||
int _offset_y;
|
||||
public int offset_y {
|
||||
get { return _offset_y; }
|
||||
set { _offset_y = value; update (); }
|
||||
}
|
||||
|
||||
int _offset_x;
|
||||
public int offset_x {
|
||||
get { return _offset_x; }
|
||||
set { _offset_x = value; update (); }
|
||||
}
|
||||
|
||||
uint8 _opacity;
|
||||
public uint8 opacity {
|
||||
get { return _opacity; }
|
||||
set { _opacity = value; update (); }
|
||||
}
|
||||
|
||||
public TextShadowEffect (int offset_x, int offset_y, uint8 opacity)
|
||||
{
|
||||
_offset_x = offset_x;
|
||||
_offset_y = offset_y;
|
||||
_opacity = opacity;
|
||||
}
|
||||
|
||||
public override bool pre_paint ()
|
||||
{
|
||||
var layout = ((Clutter.Text)get_actor ()).get_layout ();
|
||||
Cogl.pango_render_layout (layout, offset_x, offset_y, Cogl.Color.from_4ub (0, 0, 0, opacity), 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void update ()
|
||||
{
|
||||
if (get_actor () != null)
|
||||
get_actor ().queue_redraw ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,165 +1,174 @@
|
||||
//
|
||||
// Copyright (C) 2012 Tom Beckmann, Rico Tzschichholz
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
public class CornerMenu : Clutter.Group {
|
||||
|
||||
Clutter.Box workspaces;
|
||||
|
||||
unowned Gala.Plugin plugin;
|
||||
|
||||
bool animating; //prevent closing of the popup too fast
|
||||
|
||||
public CornerMenu (Gala.Plugin plugin) {
|
||||
|
||||
this.plugin = plugin;
|
||||
|
||||
this.width = 100;
|
||||
this.height = 100;
|
||||
|
||||
this.scale_gravity = Clutter.Gravity.SOUTH_EAST;
|
||||
this.opacity = 0;
|
||||
this.scale_x = this.scale_y = 0.0f;
|
||||
|
||||
this.workspaces = new Clutter.Box (new Clutter.BoxLayout ());
|
||||
(this.workspaces.layout_manager as Clutter.BoxLayout).spacing = 15;
|
||||
(this.workspaces.layout_manager as Clutter.BoxLayout).vertical = true;
|
||||
|
||||
this.reactive = true;
|
||||
this.leave_event.connect ( (e) => {
|
||||
if (this.get_children ().index (e.related) == -1)
|
||||
this.hide ();
|
||||
return false;
|
||||
});
|
||||
|
||||
var tile = new GtkClutter.Texture ();
|
||||
try {
|
||||
tile.set_from_pixbuf (Gtk.IconTheme.get_default ().load_icon ("preferences-desktop-display", 64, 0));
|
||||
} catch (Error e) { warning (e.message); }
|
||||
tile.x = 5;
|
||||
tile.y = 5;
|
||||
tile.reactive = true;
|
||||
tile.button_release_event.connect ( () => {
|
||||
|
||||
var windows = new GLib.List<Meta.Window> ();
|
||||
plugin.screen.get_active_workspace ().list_windows ().foreach ( (w) => {
|
||||
if (w.window_type != Meta.WindowType.NORMAL || w.minimized)
|
||||
return;
|
||||
windows.append (w);
|
||||
});
|
||||
|
||||
//make sure active window is biggest
|
||||
var active_idx = windows.index (plugin.screen.get_display ().get_focus_window ());
|
||||
if (active_idx != -1 && active_idx != 0) {
|
||||
windows.delete_link (windows.nth (active_idx));
|
||||
windows.prepend (plugin.screen.get_display ().get_focus_window ());
|
||||
}
|
||||
|
||||
unowned Meta.Rectangle area;
|
||||
plugin.screen.get_active_workspace ().get_work_area_all_monitors (out area);
|
||||
|
||||
var n_wins = windows.length ();
|
||||
var index = 0;
|
||||
|
||||
windows.foreach ( (w) => {
|
||||
if (w.maximized_horizontally || w.maximized_vertically)
|
||||
w.unmaximize (Meta.MaximizeFlags.VERTICAL | Meta.MaximizeFlags.HORIZONTAL);
|
||||
switch (n_wins) {
|
||||
case 1:
|
||||
w.move_resize_frame (true, area.x, area.y, area.width, area.height);
|
||||
break;
|
||||
case 2:
|
||||
w.move_resize_frame (true, area.x+area.width/2*index, area.y, area.width/2,
|
||||
area.height);
|
||||
break;
|
||||
case 3:
|
||||
if (index == 0)
|
||||
w.move_resize_frame (true, area.x, area.y, area.width/2, area.height);
|
||||
else {
|
||||
w.move_resize_frame (true, area.x+area.width/2,
|
||||
area.y+(area.height/2*(index-1)), area.width/2, area.height/2);
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
if (index < 2)
|
||||
w.move_resize_frame (true, area.x+area.width/2*index, area.y,
|
||||
area.width/2, area.height/2);
|
||||
else
|
||||
w.move_resize_frame (true, (index==3)?area.x+area.width/2:area.x,
|
||||
area.y+area.height/2, area.width/2, area.height/2);
|
||||
break;
|
||||
case 5:
|
||||
if (index < 2)
|
||||
w.move_resize_frame (true, area.x, area.y+(area.height/2*index),
|
||||
area.width/2, area.height/2);
|
||||
else
|
||||
w.move_resize_frame (true, area.x+area.width/2,
|
||||
area.y+(area.height/3*(index-2)), area.width/2, area.height/3);
|
||||
break;
|
||||
case 6:
|
||||
if (index < 3)
|
||||
w.move_resize_frame (true, area.x, area.y+(area.height/3*index),
|
||||
area.width/2, area.height/3);
|
||||
else
|
||||
w.move_resize_frame (true, area.x+area.width/2,
|
||||
area.y+(area.height/3*(index-3)), area.width/2, area.height/3);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
index ++;
|
||||
});
|
||||
return true;
|
||||
});
|
||||
|
||||
this.add_child (tile);
|
||||
//this.add_child (this.workspaces);
|
||||
}
|
||||
|
||||
public new void show () {
|
||||
if (this.visible)
|
||||
return;
|
||||
plugin.set_input_area (Gala.InputArea.FULLSCREEN);
|
||||
plugin.begin_modal ();
|
||||
|
||||
animating = true;
|
||||
|
||||
int width, height;
|
||||
plugin.get_screen ().get_size (out width, out height);
|
||||
this.x = width - this.width;
|
||||
this.y = height - this.height;
|
||||
|
||||
this.visible = true;
|
||||
this.grab_key_focus ();
|
||||
this.animate (Clutter.AnimationMode.EASE_OUT_BOUNCE, 400, scale_x:1.0f, scale_y:1.0f, opacity:255).completed.connect ( () => {
|
||||
animating = false;
|
||||
});
|
||||
|
||||
/*for (var i=0;i<plugin.get_screen ().n_workspaces;i++) {
|
||||
plugin.get_screen ().get_workspace_by_index (i);
|
||||
|
||||
var g = new Clutter.Group ();
|
||||
|
||||
var s = new Clutter.Rectangle.with_color ({0, 0, 0, 255});
|
||||
var b = new Clutter.Clone (background);
|
||||
|
||||
b.width = s.width = WIDTH;
|
||||
b.height = s.height = HEIGHT;
|
||||
|
||||
g.add_child (s);
|
||||
g.add_child (b);
|
||||
|
||||
this.workspaces.add_child (g);
|
||||
}*/
|
||||
}
|
||||
|
||||
public new void hide () {
|
||||
if (!this.visible || animating)
|
||||
return;
|
||||
|
||||
plugin.end_modal ();
|
||||
plugin.set_input_area (Gala.InputArea.HOT_CORNER);
|
||||
|
||||
this.animate (Clutter.AnimationMode.EASE_OUT_QUAD, 400, scale_x:0.0f, scale_y:0.0f, opacity:0)
|
||||
.completed.connect ( () => {
|
||||
this.visible = false;
|
||||
});
|
||||
}
|
||||
namespace Gala
|
||||
{
|
||||
public class CornerMenu : Clutter.Group
|
||||
{
|
||||
Gala.Plugin plugin;
|
||||
|
||||
Clutter.Box workspaces;
|
||||
|
||||
bool animating; // delay closing the popup
|
||||
|
||||
public CornerMenu (Gala.Plugin _plugin)
|
||||
{
|
||||
plugin = _plugin;
|
||||
|
||||
width = 100;
|
||||
height = 100;
|
||||
opacity = 0;
|
||||
scale_gravity = Clutter.Gravity.SOUTH_EAST;
|
||||
scale_x = scale_y = 0.0f;
|
||||
reactive = true;
|
||||
|
||||
workspaces = new Clutter.Box (new Clutter.BoxLayout ());
|
||||
(workspaces.layout_manager as Clutter.BoxLayout).spacing = 15;
|
||||
(workspaces.layout_manager as Clutter.BoxLayout).vertical = true;
|
||||
|
||||
leave_event.connect ((e) => {
|
||||
if (get_children ().index (e.related) == -1)
|
||||
hide ();
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
var tile = new GtkClutter.Texture ();
|
||||
try {
|
||||
tile.set_from_pixbuf (Gtk.IconTheme.get_default ().load_icon ("preferences-desktop-display", 64, 0));
|
||||
} catch (Error e) {
|
||||
warning (e.message);
|
||||
}
|
||||
|
||||
tile.x = 5;
|
||||
tile.y = 5;
|
||||
tile.reactive = true;
|
||||
tile.button_release_event.connect (() => {
|
||||
var windows = new GLib.List<Meta.Window> ();
|
||||
plugin.screen.get_active_workspace ().list_windows ().foreach ( (w) => {
|
||||
if (w.window_type != Meta.WindowType.NORMAL || w.minimized)
|
||||
return;
|
||||
|
||||
windows.append (w);
|
||||
});
|
||||
|
||||
//make sure active window is biggest
|
||||
var active_idx = windows.index (plugin.screen.get_display ().get_focus_window ());
|
||||
if (active_idx != -1 && active_idx != 0) {
|
||||
windows.delete_link (windows.nth (active_idx));
|
||||
windows.prepend (plugin.screen.get_display ().get_focus_window ());
|
||||
}
|
||||
|
||||
unowned Meta.Rectangle area;
|
||||
plugin.screen.get_active_workspace ().get_work_area_all_monitors (out area);
|
||||
|
||||
var n_wins = windows.length ();
|
||||
var index = 0;
|
||||
|
||||
windows.foreach ( (w) => {
|
||||
if (w.maximized_horizontally || w.maximized_vertically)
|
||||
w.unmaximize (Meta.MaximizeFlags.VERTICAL | Meta.MaximizeFlags.HORIZONTAL);
|
||||
|
||||
switch (n_wins) {
|
||||
case 1:
|
||||
w.move_resize_frame (true, area.x, area.y, area.width, area.height);
|
||||
break;
|
||||
case 2:
|
||||
w.move_resize_frame (true, area.x+area.width/2*index, area.y, area.width/2,
|
||||
area.height);
|
||||
break;
|
||||
case 3:
|
||||
if (index == 0)
|
||||
w.move_resize_frame (true, area.x, area.y, area.width/2, area.height);
|
||||
else {
|
||||
w.move_resize_frame (true, area.x+area.width/2,
|
||||
area.y+(area.height/2*(index-1)), area.width/2, area.height/2);
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
if (index < 2)
|
||||
w.move_resize_frame (true, area.x+area.width/2*index, area.y,
|
||||
area.width/2, area.height/2);
|
||||
else
|
||||
w.move_resize_frame (true, (index==3)?area.x+area.width/2:area.x,
|
||||
area.y+area.height/2, area.width/2, area.height/2);
|
||||
break;
|
||||
case 5:
|
||||
if (index < 2)
|
||||
w.move_resize_frame (true, area.x, area.y+(area.height/2*index),
|
||||
area.width/2, area.height/2);
|
||||
else
|
||||
w.move_resize_frame (true, area.x+area.width/2,
|
||||
area.y+(area.height/3*(index-2)), area.width/2, area.height/3);
|
||||
break;
|
||||
case 6:
|
||||
if (index < 3)
|
||||
w.move_resize_frame (true, area.x, area.y+(area.height/3*index),
|
||||
area.width/2, area.height/3);
|
||||
else
|
||||
w.move_resize_frame (true, area.x+area.width/2,
|
||||
area.y+(area.height/3*(index-3)), area.width/2, area.height/3);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
index ++;
|
||||
});
|
||||
return true;
|
||||
});
|
||||
|
||||
add_child (tile);
|
||||
//add_child (workspaces);
|
||||
}
|
||||
|
||||
public new void show ()
|
||||
{
|
||||
if (visible)
|
||||
return;
|
||||
|
||||
plugin.set_input_area (Gala.InputArea.FULLSCREEN);
|
||||
plugin.begin_modal ();
|
||||
|
||||
animating = true;
|
||||
|
||||
int width, height;
|
||||
plugin.get_screen ().get_size (out width, out height);
|
||||
x = width - width;
|
||||
y = height - height;
|
||||
|
||||
visible = true;
|
||||
grab_key_focus ();
|
||||
animate (Clutter.AnimationMode.EASE_OUT_BOUNCE, 400, scale_x:1.0f, scale_y:1.0f, opacity:255).completed.connect (() => {
|
||||
animating = false;
|
||||
});
|
||||
}
|
||||
|
||||
public new void hide ()
|
||||
{
|
||||
if (!visible || animating)
|
||||
return;
|
||||
|
||||
plugin.end_modal ();
|
||||
plugin.set_input_area (Gala.InputArea.HOT_CORNER);
|
||||
|
||||
animate (Clutter.AnimationMode.EASE_OUT_QUAD, 400, scale_x : 0.0f, scale_y : 0.0f, opacity : 0)
|
||||
.completed.connect ( () => {
|
||||
visible = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,204 +1,237 @@
|
||||
//
|
||||
// Copyright (C) 2012 Tom Beckmann, Rico Tzschichholz
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
using Clutter;
|
||||
using Granite.Drawing;
|
||||
|
||||
public class WindowSwitcher : Clutter.Group {
|
||||
|
||||
int ICON_SIZE = 128;
|
||||
int spacing = 12;
|
||||
|
||||
public float len;
|
||||
|
||||
Clutter.CairoTexture bg;
|
||||
Clutter.CairoTexture cur;
|
||||
Clutter.Text title;
|
||||
|
||||
int _windows = 1;
|
||||
public int windows {
|
||||
get { return _windows; }
|
||||
set {
|
||||
_windows = value;
|
||||
this.width = spacing+_windows*(ICON_SIZE+spacing);
|
||||
}
|
||||
}
|
||||
|
||||
GLib.List<weak Meta.Window> window_list;
|
||||
|
||||
Meta.Window? _current_window;
|
||||
Meta.Window? current_window {
|
||||
get { return _current_window; }
|
||||
set {
|
||||
_current_window = value;
|
||||
|
||||
this.title.text = this.current_window.title;
|
||||
this.title.x = (int)(this.width/2-this.title.width/2);
|
||||
}
|
||||
}
|
||||
|
||||
Gala.Plugin plugin;
|
||||
|
||||
public WindowSwitcher (Gala.Plugin plugin) {
|
||||
this.plugin = plugin;
|
||||
|
||||
this.height = ICON_SIZE+spacing*2;
|
||||
this.opacity = 0;
|
||||
this.scale_gravity = Clutter.Gravity.CENTER;
|
||||
|
||||
this.bg = new Clutter.CairoTexture (100, 100);
|
||||
this.bg.auto_resize = true;
|
||||
|
||||
this.bg.draw.connect ( (ctx) => {
|
||||
Granite.Drawing.Utilities.cairo_rounded_rectangle (ctx, 0.5, 0.5, width-1,
|
||||
height-1, 10);
|
||||
ctx.set_line_width (1);
|
||||
ctx.set_source_rgba (0, 0, 0, 0.5);
|
||||
ctx.stroke_preserve ();
|
||||
ctx.set_source_rgba (1, 1, 1, 0.4);
|
||||
ctx.fill ();
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
this.cur = new Clutter.CairoTexture (ICON_SIZE, ICON_SIZE);
|
||||
this.cur.width = ICON_SIZE;
|
||||
this.cur.height = ICON_SIZE;
|
||||
this.cur.y = spacing+1;
|
||||
this.cur.x = spacing+1;
|
||||
this.cur.auto_resize = true;
|
||||
this.cur.draw.connect ( (ctx) => {
|
||||
Granite.Drawing.Utilities.cairo_rounded_rectangle (ctx, 0.5, 0.5, cur.width-2,
|
||||
cur.height-1, 10);
|
||||
ctx.set_line_width (1);
|
||||
ctx.set_source_rgba (0, 0, 0, 0.9);
|
||||
ctx.stroke_preserve ();
|
||||
ctx.set_source_rgba (1, 1, 1, 0.9);
|
||||
ctx.fill ();
|
||||
|
||||
return true;
|
||||
});
|
||||
this.windows = 1;
|
||||
|
||||
this.title = new Clutter.Text.with_text ("bold 16px", "");
|
||||
this.title.y = ICON_SIZE + spacing*2 + 6;
|
||||
this.title.color = {255, 255, 255, 255};
|
||||
this.title.add_effect (new TextShadowEffect (1, 1, 220));
|
||||
|
||||
this.add_child (bg);
|
||||
this.add_child (cur);
|
||||
this.add_child (title);
|
||||
bg.add_constraint (new Clutter.BindConstraint (this, Clutter.BindCoordinate.WIDTH, 0));
|
||||
bg.add_constraint (new Clutter.BindConstraint (this, Clutter.BindCoordinate.HEIGHT, 0));
|
||||
|
||||
this.key_release_event.connect_after ( (e) => {
|
||||
if (((e.modifier_state & Clutter.ModifierType.MOD1_MASK) == 0) ||
|
||||
e.keyval == Clutter.Key.Alt_L) {
|
||||
plugin.end_modal ();
|
||||
current_window.activate (e.time);
|
||||
|
||||
this.animate (Clutter.AnimationMode.EASE_OUT_QUAD, 200, opacity:0);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
this.captured_event.connect ( (e) => {
|
||||
if (!(e.get_type () == Clutter.EventType.KEY_PRESS))
|
||||
return false;
|
||||
|
||||
bool backward = (((Clutter.Event)e).get_state () & X.KeyMask.ShiftMask) == 1;
|
||||
var action = plugin.get_screen ().get_display ().get_keybinding_action (
|
||||
((Clutter.Event)e).get_key_code (), ((Clutter.Event)e).get_state ());
|
||||
|
||||
switch (action) {
|
||||
case Meta.KeyBindingAction.SWITCH_GROUP:
|
||||
case Meta.KeyBindingAction.SWITCH_WINDOWS:
|
||||
this.current_window = plugin.get_screen ().get_display ().
|
||||
get_tab_next (Meta.TabList.NORMAL, plugin.get_screen (),
|
||||
plugin.get_screen ().get_active_workspace (), this.current_window, backward);
|
||||
break;
|
||||
case Meta.KeyBindingAction.SWITCH_GROUP_BACKWARD:
|
||||
case Meta.KeyBindingAction.SWITCH_WINDOWS_BACKWARD:
|
||||
this.current_window = plugin.get_screen ().get_display ().
|
||||
get_tab_next (Meta.TabList.NORMAL, plugin.get_screen (),
|
||||
plugin.get_screen ().get_active_workspace (), this.current_window, true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
cur.animate (Clutter.AnimationMode.EASE_OUT_QUAD, 200,
|
||||
x:0.0f+spacing+this.window_list.index (this.current_window)*(spacing+ICON_SIZE));
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public void list_windows (Meta.Display display, Meta.Screen screen,
|
||||
Meta.KeyBinding binding, bool backward) {
|
||||
this.get_children ().foreach ( (c) => { //clear
|
||||
if (c != cur && c != bg && c != title)
|
||||
this.remove_child (c);
|
||||
});
|
||||
|
||||
this.current_window = display.get_tab_next (Meta.TabList.NORMAL, screen,
|
||||
screen.get_active_workspace (), null, backward);
|
||||
if (this.current_window == null)
|
||||
this.current_window = display.get_tab_current (Meta.TabList.NORMAL, screen,
|
||||
screen.get_active_workspace ());
|
||||
if (this.current_window == null)
|
||||
return;
|
||||
|
||||
if (binding.get_mask () == 0) {
|
||||
this.current_window.activate (display.get_current_time ());
|
||||
return;
|
||||
}
|
||||
|
||||
var matcher = Bamf.Matcher.get_default ();
|
||||
|
||||
var i = 0;
|
||||
this.window_list = screen.get_display ().get_tab_list (Meta.TabList.NORMAL, screen,
|
||||
screen.get_active_workspace ()).copy ();
|
||||
this.window_list.foreach ( (w) => {
|
||||
if (w == null)
|
||||
return;
|
||||
|
||||
Bamf.Window bamfwin = null;
|
||||
matcher.get_windows ().foreach ( (bamfw) => {
|
||||
if ((bamfw as Bamf.Window).get_pid () == (uint32)w.get_pid ()) {
|
||||
bamfwin = bamfw as Bamf.Window;
|
||||
}
|
||||
});
|
||||
|
||||
Gdk.Pixbuf image = null;
|
||||
if (bamfwin != null) {
|
||||
var app = matcher.get_application_for_window (bamfwin);
|
||||
if (app != null) {
|
||||
var desktop = new GLib.DesktopAppInfo.from_filename (app.get_desktop_file ());
|
||||
try {
|
||||
image = Gtk.IconTheme.get_default ().lookup_by_gicon (desktop.get_icon (),
|
||||
ICON_SIZE, 0).load_icon ();
|
||||
} catch (Error e) { warning (e.message); }
|
||||
}
|
||||
}
|
||||
|
||||
if (image == null) {
|
||||
try {
|
||||
image = Gtk.IconTheme.get_default ().load_icon ("application-default-icon",
|
||||
ICON_SIZE, 0);
|
||||
} catch (Error e) { warning (e.message); }
|
||||
}
|
||||
|
||||
var icon = new GtkClutter.Texture ();
|
||||
try {
|
||||
icon.set_from_pixbuf (image);
|
||||
} catch (Error e) { warning (e.message); }
|
||||
|
||||
icon.width = ICON_SIZE-10;
|
||||
icon.height = ICON_SIZE-10;
|
||||
icon.x = spacing+i*(spacing+ICON_SIZE)+5;
|
||||
icon.y = spacing+5;
|
||||
this.add_child (icon);
|
||||
|
||||
i ++;
|
||||
});
|
||||
this.windows = i;
|
||||
|
||||
var idx = this.window_list.index (this.current_window);
|
||||
cur.x = spacing+idx*(spacing+ICON_SIZE);
|
||||
}
|
||||
namespace Gala
|
||||
{
|
||||
public class WindowSwitcher : Clutter.Group
|
||||
{
|
||||
const int ICON_SIZE = 128;
|
||||
const int spacing = 12;
|
||||
|
||||
Gala.Plugin plugin;
|
||||
|
||||
GLib.List<unowned Meta.Window> window_list;
|
||||
|
||||
CairoTexture background;
|
||||
CairoTexture current;
|
||||
Text title;
|
||||
|
||||
int _windows = 1;
|
||||
int windows {
|
||||
get { return _windows; }
|
||||
set {
|
||||
_windows = value;
|
||||
width = spacing + _windows * (ICON_SIZE + spacing);
|
||||
}
|
||||
}
|
||||
|
||||
Meta.Window? _current_window;
|
||||
Meta.Window? current_window {
|
||||
get { return _current_window; }
|
||||
set {
|
||||
_current_window = value;
|
||||
title.text = current_window.title;
|
||||
title.x = (int)(width / 2 - title.width / 2);
|
||||
}
|
||||
}
|
||||
|
||||
public WindowSwitcher (Gala.Plugin _plugin)
|
||||
{
|
||||
plugin = _plugin;
|
||||
|
||||
height = ICON_SIZE + spacing * 2;
|
||||
opacity = 0;
|
||||
scale_gravity = Gravity.CENTER;
|
||||
|
||||
background = new CairoTexture (100, 100);
|
||||
background.auto_resize = true;
|
||||
background.draw.connect (draw_background);
|
||||
|
||||
current = new CairoTexture (ICON_SIZE, ICON_SIZE);
|
||||
current.y = spacing + 1;
|
||||
current.x = spacing + 1;
|
||||
current.width = ICON_SIZE;
|
||||
current.height = ICON_SIZE;
|
||||
current.auto_resize = true;
|
||||
current.draw.connect (draw_current);
|
||||
|
||||
windows = 1;
|
||||
|
||||
title = new Text.with_text ("bold 16px", "");
|
||||
title.y = ICON_SIZE + spacing * 2 + 6;
|
||||
title.color = {255, 255, 255, 255};
|
||||
title.add_effect (new TextShadowEffect (1, 1, 220));
|
||||
|
||||
add_child (background);
|
||||
add_child (current);
|
||||
add_child (title);
|
||||
|
||||
background.add_constraint (new BindConstraint (this, BindCoordinate.WIDTH, 0));
|
||||
background.add_constraint (new BindConstraint (this, BindCoordinate.HEIGHT, 0));
|
||||
}
|
||||
|
||||
public override bool key_release_event (Clutter.KeyEvent event)
|
||||
{
|
||||
if (((event.modifier_state & ModifierType.MOD1_MASK) == 0) ||
|
||||
event.keyval == Key.Alt_L) {
|
||||
plugin.end_modal ();
|
||||
current_window.activate (event.time);
|
||||
|
||||
animate (AnimationMode.EASE_OUT_QUAD, 200, opacity:0);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool captured_event (Clutter.Event event)
|
||||
{
|
||||
if (!(event.get_type () == EventType.KEY_PRESS))
|
||||
return false;
|
||||
|
||||
bool backward = (event.get_state () & X.KeyMask.ShiftMask) != 0;
|
||||
var action = plugin.get_screen ().get_display ().get_keybinding_action (
|
||||
event.get_key_code (), event.get_state ());
|
||||
|
||||
switch (action) {
|
||||
case Meta.KeyBindingAction.SWITCH_GROUP:
|
||||
case Meta.KeyBindingAction.SWITCH_WINDOWS:
|
||||
current_window = plugin.get_screen ().get_display ().
|
||||
get_tab_next (Meta.TabList.NORMAL, plugin.get_screen (),
|
||||
plugin.get_screen ().get_active_workspace (), current_window, backward);
|
||||
break;
|
||||
case Meta.KeyBindingAction.SWITCH_GROUP_BACKWARD:
|
||||
case Meta.KeyBindingAction.SWITCH_WINDOWS_BACKWARD:
|
||||
current_window = plugin.get_screen ().get_display ().
|
||||
get_tab_next (Meta.TabList.NORMAL, plugin.get_screen (),
|
||||
plugin.get_screen ().get_active_workspace (), current_window, true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
current.animate (AnimationMode.EASE_OUT_QUAD, 200,
|
||||
x : 0.0f + spacing + window_list.index (current_window) * (spacing + ICON_SIZE));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool draw_background (Cairo.Context cr)
|
||||
{
|
||||
Utilities.cairo_rounded_rectangle (cr, 0.5, 0.5, width - 1, height - 1, 10);
|
||||
cr.set_line_width (1);
|
||||
cr.set_source_rgba (0, 0, 0, 0.5);
|
||||
cr.stroke_preserve ();
|
||||
cr.set_source_rgba (1, 1, 1, 0.4);
|
||||
cr.fill ();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool draw_current (Cairo.Context cr)
|
||||
{
|
||||
Utilities.cairo_rounded_rectangle (cr, 0.5, 0.5, current.width - 2, current.height - 1, 10);
|
||||
cr.set_line_width (1);
|
||||
cr.set_source_rgba (0, 0, 0, 0.9);
|
||||
cr.stroke_preserve ();
|
||||
cr.set_source_rgba (1, 1, 1, 0.9);
|
||||
cr.fill ();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void list_windows (Meta.Display display, Meta.Screen screen, Meta.KeyBinding binding, bool backward)
|
||||
{
|
||||
get_children ().foreach ((c) => { //clear
|
||||
if (c != current && c != background && c != title)
|
||||
remove_child (c);
|
||||
});
|
||||
|
||||
current_window = display.get_tab_next (Meta.TabList.NORMAL, screen,
|
||||
screen.get_active_workspace (), null, backward);
|
||||
|
||||
if (current_window == null)
|
||||
current_window = display.get_tab_current (Meta.TabList.NORMAL, screen, screen.get_active_workspace ());
|
||||
|
||||
if (current_window == null)
|
||||
return;
|
||||
|
||||
if (binding.get_mask () == 0) {
|
||||
current_window.activate (display.get_current_time ());
|
||||
return;
|
||||
}
|
||||
|
||||
var matcher = Bamf.Matcher.get_default ();
|
||||
|
||||
var i = 0;
|
||||
window_list = display.get_tab_list (Meta.TabList.NORMAL, screen, screen.get_active_workspace ()).copy ();
|
||||
|
||||
window_list.foreach ((w) => {
|
||||
if (w == null)
|
||||
return;
|
||||
|
||||
Bamf.Window bamfwin = null;
|
||||
matcher.get_windows ().foreach ( (bamfw) => {
|
||||
if ((bamfw as Bamf.Window).get_pid () == (uint32)w.get_pid ()) {
|
||||
bamfwin = bamfw as Bamf.Window;
|
||||
}
|
||||
});
|
||||
|
||||
Gdk.Pixbuf image = null;
|
||||
if (bamfwin != null) {
|
||||
var app = matcher.get_application_for_window (bamfwin);
|
||||
if (app != null) {
|
||||
var desktop = new GLib.DesktopAppInfo.from_filename (app.get_desktop_file ());
|
||||
try {
|
||||
image = Gtk.IconTheme.get_default ().lookup_by_gicon (desktop.get_icon (), ICON_SIZE, 0).load_icon ();
|
||||
} catch (Error e) { warning (e.message); }
|
||||
}
|
||||
}
|
||||
|
||||
if (image == null) {
|
||||
try {
|
||||
image = Gtk.IconTheme.get_default ().load_icon ("application-default-icon", ICON_SIZE, 0);
|
||||
} catch (Error e) {
|
||||
warning (e.message);
|
||||
}
|
||||
}
|
||||
|
||||
var icon = new GtkClutter.Texture ();
|
||||
try {
|
||||
icon.set_from_pixbuf (image);
|
||||
} catch (Error e) {
|
||||
warning (e.message);
|
||||
}
|
||||
|
||||
icon.x = spacing + 5 + i * (spacing + ICON_SIZE);
|
||||
icon.y = spacing + 5;
|
||||
icon.width = ICON_SIZE - 10;
|
||||
icon.height = ICON_SIZE - 10;
|
||||
add_child (icon);
|
||||
|
||||
i++;
|
||||
});
|
||||
|
||||
windows = i;
|
||||
|
||||
var idx = window_list.index (current_window);
|
||||
current.x = spacing + idx * (spacing + ICON_SIZE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,108 +1,147 @@
|
||||
//
|
||||
// Copyright (C) 2012 Tom Beckmann, Rico Tzschichholz
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
public class WorkspaceSwitcher : Clutter.Group {
|
||||
|
||||
public float len;
|
||||
|
||||
Clutter.CairoTexture bg;
|
||||
Clutter.CairoTexture cur;
|
||||
|
||||
int _workspaces = 1;
|
||||
public int workspaces {
|
||||
get {return _workspaces;}
|
||||
set {_workspaces = value; this.height = len*_workspaces+spacing;}
|
||||
}
|
||||
int _workspace = 0;
|
||||
public int workspace {
|
||||
get {return _workspace;}
|
||||
set {
|
||||
_workspace = value;
|
||||
cur.animate (Clutter.AnimationMode.EASE_OUT_QUAD, 300, y:_workspace*len+1+spacing);
|
||||
}
|
||||
}
|
||||
|
||||
int spacing = 10;
|
||||
float WIDTH = 200;
|
||||
|
||||
Gala.Plugin plugin;
|
||||
|
||||
public WorkspaceSwitcher (Gala.Plugin plugin, int w, int h) {
|
||||
|
||||
this.plugin = plugin;
|
||||
|
||||
this.height = 100+spacing*2;
|
||||
this.width = WIDTH+spacing*2;
|
||||
this.opacity = 0;
|
||||
|
||||
this.bg = new Clutter.CairoTexture (100, (int)WIDTH);
|
||||
this.bg.auto_resize = true;
|
||||
|
||||
len = (float)(h)/w*WIDTH;
|
||||
this.bg.draw.connect ( (ctx) => {
|
||||
Granite.Drawing.Utilities.cairo_rounded_rectangle (ctx, 0.5, 0.5, width-1,
|
||||
height-1, 10);
|
||||
ctx.set_line_width (1);
|
||||
ctx.set_source_rgba (0, 0, 0, 0.5);
|
||||
ctx.stroke_preserve ();
|
||||
ctx.set_source_rgba (1, 1, 1, 0.4);
|
||||
ctx.fill ();
|
||||
|
||||
for (var i=0;i<workspaces;i++) {
|
||||
Granite.Drawing.Utilities.cairo_rounded_rectangle (ctx, 0.5+spacing,
|
||||
i*len+0.5+spacing, width-1-spacing*2, len-1-spacing, 10);
|
||||
ctx.set_line_width (1);
|
||||
ctx.set_source_rgba (0, 0, 0, 0.8);
|
||||
ctx.stroke_preserve ();
|
||||
ctx.set_source_rgba (0, 0, 0, 0.4);
|
||||
ctx.fill ();
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
this.cur = new Clutter.CairoTexture (100, 100);
|
||||
this.cur.width = width-1-spacing*2;
|
||||
this.cur.height = len-1-spacing;
|
||||
this.cur.x = spacing+1;
|
||||
this.cur.auto_resize = true;
|
||||
this.cur.draw.connect ( (ctx) => {
|
||||
Granite.Drawing.Utilities.cairo_rounded_rectangle (ctx, 0.5, 0.5, cur.width-2,
|
||||
cur.height-1, 10);
|
||||
ctx.set_line_width (1);
|
||||
ctx.set_source_rgba (0, 0, 0, 0.9);
|
||||
ctx.stroke_preserve ();
|
||||
ctx.set_source_rgba (1, 1, 1, 0.9);
|
||||
ctx.fill ();
|
||||
|
||||
return true;
|
||||
});
|
||||
this.workspace = 0;
|
||||
|
||||
this.add_child (bg);
|
||||
this.add_child (cur);
|
||||
bg.add_constraint (new Clutter.BindConstraint (this, Clutter.BindCoordinate.WIDTH, 0));
|
||||
bg.add_constraint (new Clutter.BindConstraint (this, Clutter.BindCoordinate.HEIGHT, 0));
|
||||
|
||||
this.key_release_event.connect ( (e) => {
|
||||
if (((e.modifier_state & Clutter.ModifierType.MOD1_MASK) == 0) ||
|
||||
e.keyval == Clutter.Key.Alt_L) {
|
||||
|
||||
plugin.end_modal ();
|
||||
this.animate (Clutter.AnimationMode.EASE_OUT_QUAD, 200, opacity:0);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
this.key_press_event.connect ( (e) => {
|
||||
switch (e.keyval) {
|
||||
case Clutter.Key.Up:
|
||||
this.workspace = plugin.move_workspaces (true);
|
||||
return false;
|
||||
case Clutter.Key.Down:
|
||||
this.workspace = plugin.move_workspaces (false);
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
using Clutter;
|
||||
using Granite.Drawing;
|
||||
|
||||
namespace Gala
|
||||
{
|
||||
public class WorkspaceSwitcher : Group
|
||||
{
|
||||
const float WIDTH = 200;
|
||||
const int spacing = 10;
|
||||
|
||||
float len;
|
||||
|
||||
Gala.Plugin plugin;
|
||||
|
||||
CairoTexture background;
|
||||
CairoTexture current;
|
||||
|
||||
int _workspaces = 1;
|
||||
public int workspaces {
|
||||
get { return _workspaces; }
|
||||
set {
|
||||
_workspaces = value;
|
||||
height = len * _workspaces + spacing;
|
||||
}
|
||||
}
|
||||
|
||||
int _workspace = 0;
|
||||
public int workspace {
|
||||
get { return _workspace; }
|
||||
set {
|
||||
_workspace = value;
|
||||
current.animate (AnimationMode.EASE_OUT_QUAD, 300, y : _workspace * len + 1 + spacing);
|
||||
}
|
||||
}
|
||||
|
||||
public WorkspaceSwitcher (Gala.Plugin _plugin, int w, int h)
|
||||
{
|
||||
plugin = _plugin;
|
||||
|
||||
len = (float)h / w * WIDTH;
|
||||
|
||||
height = 100 + spacing * 2;
|
||||
width = WIDTH + spacing * 2;
|
||||
opacity = 0;
|
||||
|
||||
background = new CairoTexture (100, (int)WIDTH);
|
||||
background.auto_resize = true;
|
||||
background.draw.connect (draw_background);
|
||||
|
||||
current = new CairoTexture (100, 100);
|
||||
current.x = spacing + 1;
|
||||
current.width = width - 1 - spacing * 2;
|
||||
current.height = len - 1 - spacing;
|
||||
current.auto_resize = true;
|
||||
current.draw.connect (draw_current);
|
||||
|
||||
workspace = 0;
|
||||
|
||||
add_child (background);
|
||||
add_child (current);
|
||||
|
||||
background.add_constraint (new BindConstraint (this, BindCoordinate.WIDTH, 0));
|
||||
background.add_constraint (new BindConstraint (this, BindCoordinate.HEIGHT, 0));
|
||||
}
|
||||
|
||||
public override bool key_release_event (KeyEvent event)
|
||||
{
|
||||
if (((event.modifier_state & ModifierType.MOD1_MASK) == 0) ||
|
||||
event.keyval == Key.Alt_L) {
|
||||
plugin.end_modal ();
|
||||
animate (AnimationMode.EASE_OUT_QUAD, 200, opacity : 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool key_press_event (KeyEvent event)
|
||||
{
|
||||
switch (event.keyval) {
|
||||
case Key.Up:
|
||||
workspace = plugin.move_workspaces (true);
|
||||
return false;
|
||||
case Key.Down:
|
||||
workspace = plugin.move_workspaces (false);
|
||||
return false;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool draw_background (Cairo.Context cr)
|
||||
{
|
||||
Utilities.cairo_rounded_rectangle (cr, 0.5, 0.5, width - 1, height - 1, 10);
|
||||
cr.set_line_width (1);
|
||||
cr.set_source_rgba (0, 0, 0, 0.5);
|
||||
cr.stroke_preserve ();
|
||||
cr.set_source_rgba (1, 1, 1, 0.4);
|
||||
cr.fill ();
|
||||
|
||||
for (var i = 0; i < workspaces; i++) {
|
||||
Utilities.cairo_rounded_rectangle (cr, 0.5 + spacing, i * len + 0.5 + spacing,
|
||||
width - 1 - spacing * 2, len - 1 - spacing, 10);
|
||||
cr.set_line_width (1);
|
||||
cr.set_source_rgba (0, 0, 0, 0.8);
|
||||
cr.stroke_preserve ();
|
||||
cr.set_source_rgba (0, 0, 0, 0.4);
|
||||
cr.fill ();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool draw_current (Cairo.Context cr)
|
||||
{
|
||||
Utilities.cairo_rounded_rectangle (cr, 0.5, 0.5, current.width - 2, current.height - 1, 10);
|
||||
cr.set_line_width (1);
|
||||
cr.set_source_rgba (0, 0, 0, 0.9);
|
||||
cr.stroke_preserve ();
|
||||
cr.set_source_rgba (1, 1, 1, 0.9);
|
||||
cr.fill ();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,409 +0,0 @@
|
||||
|
||||
namespace Gala {
|
||||
|
||||
public enum InputArea {
|
||||
FULLSCREEN,
|
||||
HOT_CORNER,
|
||||
NONE
|
||||
}
|
||||
|
||||
public class Plugin : Meta.Plugin {
|
||||
|
||||
public WorkspaceSwitcher wswitcher;
|
||||
public WindowSwitcher winswitcher;
|
||||
public CornerMenu corner_menu;
|
||||
public Clutter.Actor elements;
|
||||
|
||||
public Plugin () {
|
||||
if (Settings.get_default().use_gnome_defaults)
|
||||
return;
|
||||
Meta.Prefs.override_preference_schema ("attach-modal-dialogs", SCHEMA);
|
||||
Meta.Prefs.override_preference_schema ("button-layout", SCHEMA);
|
||||
Meta.Prefs.override_preference_schema ("edge-tiling", SCHEMA);
|
||||
Meta.Prefs.override_preference_schema ("enable-animations", SCHEMA);
|
||||
Meta.Prefs.override_preference_schema ("theme", SCHEMA);
|
||||
}
|
||||
|
||||
public override void start () {
|
||||
|
||||
this.elements = Meta.Compositor.get_stage_for_screen (screen);
|
||||
Meta.Compositor.get_window_group_for_screen (screen).reparent (elements);
|
||||
Meta.Compositor.get_overlay_group_for_screen (screen).reparent (elements);
|
||||
Meta.Compositor.get_stage_for_screen (screen).add_child (elements);
|
||||
|
||||
screen.override_workspace_layout (Meta.ScreenCorner.TOPLEFT, false, -1, 4);
|
||||
|
||||
int w, h;
|
||||
screen.get_size (out w, out h);
|
||||
|
||||
this.corner_menu = new CornerMenu (this);
|
||||
this.elements.add_child (this.corner_menu);
|
||||
this.corner_menu.visible = false;
|
||||
|
||||
this.wswitcher = new WorkspaceSwitcher (this, w, h);
|
||||
this.wswitcher.workspaces = 4;
|
||||
this.elements.add_child (this.wswitcher);
|
||||
|
||||
this.winswitcher = new WindowSwitcher (this);
|
||||
this.elements.add_child (this.winswitcher);
|
||||
|
||||
Meta.KeyBinding.set_custom_handler ("panel-main-menu", () => {
|
||||
try {
|
||||
Process.spawn_command_line_async (
|
||||
Settings.get_default().panel_main_menu_action);
|
||||
} catch (Error e) { warning (e.message); }
|
||||
});
|
||||
Meta.KeyBinding.set_custom_handler ("switch-windows",
|
||||
(display, screen, window, ev, binding) => {
|
||||
window_switcher (display, screen, binding, false);
|
||||
});
|
||||
Meta.KeyBinding.set_custom_handler ("switch-windows-backward",
|
||||
(display, screen, window, ev, binding) => {
|
||||
window_switcher (display, screen, binding, true);
|
||||
});
|
||||
Meta.KeyBinding.set_custom_handler ("switch-to-workspace-left", ()=>{});
|
||||
Meta.KeyBinding.set_custom_handler ("switch-to-workspace-right", ()=>{});
|
||||
Meta.KeyBinding.set_custom_handler ("switch-to-workspace-up", (d,s) =>
|
||||
workspace_switcher (s, true) );
|
||||
Meta.KeyBinding.set_custom_handler ("switch-to-workspace-down", (d,s) =>
|
||||
workspace_switcher (s, false) );
|
||||
|
||||
Meta.KeyBinding.set_custom_handler ("move-to-workspace-left", ()=>{});
|
||||
Meta.KeyBinding.set_custom_handler ("move-to-workspace-right", ()=>{});
|
||||
Meta.KeyBinding.set_custom_handler ("move-to-workspace-up", (d,s,w) =>
|
||||
move_window (w, true) );
|
||||
Meta.KeyBinding.set_custom_handler ("move-to-workspace-down", (d,s,w) =>
|
||||
move_window (w, false) );
|
||||
|
||||
/*shadows*/
|
||||
Meta.ShadowFactory.get_default ().set_params ("normal", true, {30, -1, 0, 35, 120});
|
||||
|
||||
/*hot corner*/
|
||||
var hot_corner = new Clutter.Rectangle ();
|
||||
hot_corner.x = w - 2;
|
||||
hot_corner.y = h - 2;
|
||||
hot_corner.width = 2;
|
||||
hot_corner.height = 2;
|
||||
hot_corner.reactive = true;
|
||||
|
||||
hot_corner.enter_event.connect ( () => {
|
||||
corner_menu.show ();
|
||||
return false;
|
||||
});
|
||||
|
||||
Meta.Compositor.get_overlay_group_for_screen (screen).add_child (hot_corner);
|
||||
|
||||
if (Settings.get_default ().enable_manager_corner)
|
||||
set_input_area (InputArea.HOT_CORNER);
|
||||
else
|
||||
set_input_area (InputArea.NONE);
|
||||
|
||||
Settings.get_default ().notify["enable-manager-corner"].connect ( () => {
|
||||
if (Settings.get_default ().enable_manager_corner)
|
||||
set_input_area (InputArea.HOT_CORNER);
|
||||
else
|
||||
set_input_area (InputArea.NONE);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* set the area where clutter can receive events
|
||||
**/
|
||||
public void set_input_area (InputArea area) {
|
||||
X.Rectangle rect;
|
||||
int width, height;
|
||||
|
||||
screen.get_size (out width, out height);
|
||||
|
||||
switch (area) {
|
||||
case InputArea.FULLSCREEN:
|
||||
rect = {0, 0, (short)width, (short)height};
|
||||
break;
|
||||
case InputArea.HOT_CORNER: //leave one pix in the bottom left
|
||||
rect = {(short)(width - 1), (short)(height - 1), 1, 1};
|
||||
break;
|
||||
default:
|
||||
Meta.Util.empty_stage_input_region (screen);
|
||||
return;
|
||||
}
|
||||
var xregion = X.Fixes.create_region (screen.get_display ().get_xdisplay (), {rect});
|
||||
Meta.Util.set_stage_input_region (screen, xregion);
|
||||
}
|
||||
|
||||
public void move_window (Meta.Window? window, bool up) {
|
||||
if (window == null)
|
||||
return;
|
||||
|
||||
if (window.is_on_all_workspaces ())
|
||||
return;
|
||||
var idx = screen.get_active_workspace ().index () + ((up)?-1:1);
|
||||
window.change_workspace_by_index (idx, false,
|
||||
screen.get_display ().get_current_time ());
|
||||
|
||||
screen.get_workspace_by_index (idx).activate_with_focus (window,
|
||||
screen.get_display ().get_current_time ());
|
||||
}
|
||||
|
||||
public new void begin_modal () {
|
||||
base.begin_modal (x_get_stage_window (Meta.Compositor.get_stage_for_screen (
|
||||
this.get_screen ())), {}, 0, this.get_screen ().get_display ().get_current_time ());
|
||||
}
|
||||
public new void end_modal () {
|
||||
base.end_modal (this.get_screen ().get_display ().get_current_time ());
|
||||
}
|
||||
|
||||
public void window_switcher (Meta.Display display, Meta.Screen screen,
|
||||
Meta.KeyBinding binding, bool backward) {
|
||||
if (screen.get_display ().get_tab_list (Meta.TabList.NORMAL, screen,
|
||||
screen.get_active_workspace ()).length () == 0)
|
||||
return;
|
||||
|
||||
this.begin_modal ();
|
||||
|
||||
int w, h;
|
||||
this.get_screen ().get_size (out w, out h);
|
||||
this.winswitcher.list_windows (display, screen, binding, backward);
|
||||
|
||||
this.winswitcher.x = w/2-winswitcher.width/2;
|
||||
this.winswitcher.y = h/2-winswitcher.height/2;
|
||||
this.winswitcher.grab_key_focus ();
|
||||
this.winswitcher.animate (Clutter.AnimationMode.EASE_OUT_QUAD, 250, opacity:255);
|
||||
}
|
||||
|
||||
public void workspace_switcher (Meta.Screen screen, bool up) {
|
||||
int w, h;
|
||||
this.get_screen ().get_size (out w, out h);
|
||||
|
||||
wswitcher.x = w/2-wswitcher.width/2;
|
||||
wswitcher.y = h/2-wswitcher.height/2;
|
||||
wswitcher.animate (Clutter.AnimationMode.EASE_OUT_QUAD, 100, opacity:255);
|
||||
wswitcher.workspace = move_workspaces (up);;
|
||||
|
||||
this.begin_modal ();
|
||||
wswitcher.grab_key_focus ();
|
||||
}
|
||||
|
||||
public int move_workspaces (bool up) {
|
||||
var i = screen.get_active_workspace_index ();
|
||||
if (up && i-1 >= 0) //move up
|
||||
i --;
|
||||
else if (!up && i+1 < screen.n_workspaces) //move down
|
||||
i ++;
|
||||
if (i != screen.get_active_workspace_index ()) {
|
||||
screen.get_workspace_by_index (i).
|
||||
activate (screen.get_display ().get_current_time ());
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
public override void minimize (Meta.WindowActor actor) {
|
||||
this.minimize_completed (actor);
|
||||
}
|
||||
|
||||
//stolen from original mutter plugin
|
||||
public override void maximize (Meta.WindowActor actor, int ex, int ey, int ew, int eh) {
|
||||
if (actor.meta_window.window_type == Meta.WindowType.NORMAL) {
|
||||
float x, y, width, height;
|
||||
actor.get_size (out width, out height);
|
||||
actor.get_position (out x, out y);
|
||||
|
||||
float scale_x = (float)ew / width;
|
||||
float scale_y = (float)eh / height;
|
||||
float anchor_x = (float)(x - ex) * width / (ew - width);
|
||||
float anchor_y = (float)(y - ey) * height / (eh - height);
|
||||
|
||||
actor.move_anchor_point (anchor_x, anchor_y);
|
||||
actor.animate (Clutter.AnimationMode.EASE_IN_SINE, 150, scale_x:scale_x,
|
||||
scale_y:scale_y).completed.connect ( () => {
|
||||
actor.move_anchor_point_from_gravity (Clutter.Gravity.NORTH_WEST);
|
||||
actor.animate (Clutter.AnimationMode.LINEAR, 1, scale_x:1.0f,
|
||||
scale_y:1.0f);//just scaling didnt want to work..
|
||||
this.maximize_completed (actor);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
this.maximize_completed (actor);
|
||||
}
|
||||
|
||||
public override void map (Meta.WindowActor actor) {
|
||||
actor.show ();
|
||||
switch (actor.meta_window.window_type) {
|
||||
case Meta.WindowType.NORMAL:
|
||||
actor.scale_gravity = Clutter.Gravity.CENTER;
|
||||
actor.rotation_center_x = {0, actor.height, 10};
|
||||
actor.scale_x = 0.55f;
|
||||
actor.scale_y = 0.55f;
|
||||
actor.opacity = 0;
|
||||
actor.rotation_angle_x = 40.0f;
|
||||
actor.animate (Clutter.AnimationMode.EASE_OUT_QUAD, 350,
|
||||
scale_x:1.0f, scale_y:1.0f, rotation_angle_x:0.0f, opacity:255)
|
||||
.completed.connect ( () => {
|
||||
this.map_completed (actor);
|
||||
});
|
||||
break;
|
||||
case Meta.WindowType.MENU:
|
||||
case Meta.WindowType.DROPDOWN_MENU:
|
||||
case Meta.WindowType.POPUP_MENU:
|
||||
case Meta.WindowType.MODAL_DIALOG:
|
||||
case Meta.WindowType.DIALOG:
|
||||
actor.scale_gravity = Clutter.Gravity.NORTH;
|
||||
actor.scale_x = 1.0f;
|
||||
actor.scale_y = 0.0f;
|
||||
actor.opacity = 0;
|
||||
actor.animate (Clutter.AnimationMode.EASE_OUT_QUAD, 150,
|
||||
scale_y:1.0f, opacity:255).completed.connect ( () => {
|
||||
this.map_completed (actor);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
this.map_completed (actor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
public override void destroy (Meta.WindowActor actor) {
|
||||
switch (actor.meta_window.window_type) {
|
||||
case Meta.WindowType.NORMAL:
|
||||
actor.scale_gravity = Clutter.Gravity.CENTER;
|
||||
actor.rotation_center_x = {0, actor.height, 10};
|
||||
actor.show ();
|
||||
actor.animate (Clutter.AnimationMode.EASE_IN_QUAD, 250,
|
||||
scale_x:0.95f, scale_y:0.95f, opacity:0, rotation_angle_x:15.0f)
|
||||
.completed.connect ( () => {
|
||||
this.destroy_completed (actor);
|
||||
});
|
||||
break;
|
||||
case Meta.WindowType.MENU:
|
||||
case Meta.WindowType.DROPDOWN_MENU:
|
||||
case Meta.WindowType.POPUP_MENU:
|
||||
case Meta.WindowType.MODAL_DIALOG:
|
||||
case Meta.WindowType.DIALOG:
|
||||
actor.scale_gravity = Clutter.Gravity.NORTH;
|
||||
actor.animate (Clutter.AnimationMode.EASE_OUT_QUAD, 200,
|
||||
scale_y:0.0f, opacity:0).completed.connect ( () => {
|
||||
this.destroy_completed (actor);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
this.destroy_completed (actor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private GLib.List<Clutter.Actor> win;
|
||||
private GLib.List<Clutter.Actor> par; //class space for kill func
|
||||
private Clutter.Group in_group;
|
||||
private Clutter.Group out_group;
|
||||
|
||||
public override void switch_workspace (int from, int to, Meta.MotionDirection direction) {
|
||||
unowned List<Clutter.Actor> windows =
|
||||
Meta.Compositor.get_window_actors (this.get_screen ());
|
||||
//FIXME js/ui/windowManager.js line 430
|
||||
int w, h;
|
||||
this.get_screen ().get_size (out w, out h);
|
||||
|
||||
var x2 = 0.0f; var y2 = 0.0f;
|
||||
if (direction == Meta.MotionDirection.UP ||
|
||||
direction == Meta.MotionDirection.UP_LEFT ||
|
||||
direction == Meta.MotionDirection.UP_RIGHT)
|
||||
y2 = h;
|
||||
else if (direction == Meta.MotionDirection.DOWN ||
|
||||
direction == Meta.MotionDirection.DOWN_LEFT ||
|
||||
direction == Meta.MotionDirection.DOWN_RIGHT)
|
||||
y2 = -h;
|
||||
|
||||
if (direction == Meta.MotionDirection.LEFT ||
|
||||
direction == Meta.MotionDirection.UP_LEFT ||
|
||||
direction == Meta.MotionDirection.DOWN_LEFT)
|
||||
y2 = h;
|
||||
else if (direction == Meta.MotionDirection.RIGHT ||
|
||||
direction == Meta.MotionDirection.UP_RIGHT ||
|
||||
direction == Meta.MotionDirection.DOWN_RIGHT)
|
||||
y2 = -h;
|
||||
|
||||
var in_group = new Clutter.Group ();
|
||||
var out_group = new Clutter.Group ();
|
||||
var group = Meta.Compositor.get_window_group_for_screen (this.get_screen ());
|
||||
group.add_actor (in_group);
|
||||
group.add_actor (out_group);
|
||||
|
||||
win = new List<Clutter.Actor> ();
|
||||
par = new List<Clutter.Actor> ();
|
||||
|
||||
for (var i=0;i<windows.length ();i++) {
|
||||
var window = windows.nth_data (i);
|
||||
if (!(window as Meta.WindowActor).meta_window.showing_on_its_workspace ())
|
||||
continue;
|
||||
|
||||
win.append (window);
|
||||
par.append (window.get_parent ());
|
||||
if ((window as Meta.WindowActor).get_workspace () == from) {
|
||||
window.reparent (out_group);
|
||||
} else if ((window as Meta.WindowActor).get_workspace () == to) {
|
||||
window.reparent (in_group);
|
||||
window.show_all ();
|
||||
}
|
||||
}
|
||||
in_group.set_position (-x2, -y2);
|
||||
in_group.raise_top ();
|
||||
|
||||
out_group.animate (Clutter.AnimationMode.EASE_OUT_QUAD, 300,
|
||||
x:x2, y:y2);
|
||||
in_group.animate (Clutter.AnimationMode.EASE_OUT_QUAD, 300,
|
||||
x:0.0f, y:0.0f).completed.connect ( () => {
|
||||
end_switch_workspace ();
|
||||
});
|
||||
}
|
||||
public override void kill_window_effects (Meta.WindowActor actor){
|
||||
/*this.minimize_completed (actor);FIXME should call the things in anim.completed
|
||||
this.maximize_completed (actor);
|
||||
this.unmaximize_completed (actor);
|
||||
this.map_completed (actor);
|
||||
this.destroy_completed (actor);*/
|
||||
}
|
||||
private void end_switch_workspace () {
|
||||
if (win == null || par == null)
|
||||
return;
|
||||
|
||||
for (var i=0;i<win.length ();i++) {
|
||||
var window = win.nth_data (i);
|
||||
if ((window as Meta.WindowActor).is_destroyed ())
|
||||
continue;
|
||||
if (window.get_parent () == out_group) {
|
||||
window.reparent (par.nth_data (i));
|
||||
window.hide ();
|
||||
} else
|
||||
window.reparent (par.nth_data (i));
|
||||
}
|
||||
win = null;
|
||||
par = null;
|
||||
|
||||
if (in_group != null) {
|
||||
in_group.detach_animation ();
|
||||
in_group.destroy ();
|
||||
}
|
||||
if (out_group != null) {
|
||||
out_group.detach_animation ();
|
||||
out_group.destroy ();
|
||||
}
|
||||
|
||||
this.switch_workspace_completed ();
|
||||
}
|
||||
public override void unmaximize (Meta.WindowActor actor, int x, int y, int w, int h) {
|
||||
this.unmaximize_completed (actor);
|
||||
}
|
||||
|
||||
public override void kill_switch_workspace () {
|
||||
end_switch_workspace ();
|
||||
}
|
||||
public override bool xevent_filter (X.Event event) {
|
||||
return x_handle_event (event) != 0;
|
||||
}
|
||||
|
||||
public override Meta.PluginInfo plugin_info () {
|
||||
return {"Gala", Gala.VERSION, "Tom Beckmann", "GPLv3", "A nice window manager"};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
namespace Gala
|
||||
{
|
||||
public class Settings : Granite.Services.Settings
|
||||
{
|
||||
public bool attach_modal_dialogs { get; set; }
|
||||
public string[] button_layout { get; set; }
|
||||
public bool edge_tiling { get; set; }
|
||||
public bool enable_animations { get; set; }
|
||||
public string panel_main_menu_action { get; set; }
|
||||
public string theme { get; set; }
|
||||
public bool use_gnome_defaults { get; set; }
|
||||
public bool enable_manager_corner { get; set; }
|
||||
|
||||
static Settings? instance = null;
|
||||
|
||||
private Settings ()
|
||||
{
|
||||
base (SCHEMA);
|
||||
}
|
||||
|
||||
public static Settings get_default()
|
||||
{
|
||||
if (instance == null)
|
||||
instance = new Settings ();
|
||||
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
|
||||
public class TextShadowEffect : Clutter.Effect {
|
||||
int _offset_y;
|
||||
public int offset_y {
|
||||
get { return _offset_y; }
|
||||
set { _offset_y = value; this.update (); }
|
||||
}
|
||||
int _offset_x;
|
||||
public int offset_x {
|
||||
get { return _offset_x; }
|
||||
set { _offset_x = value; this.update (); }
|
||||
}
|
||||
uint8 _opacity;
|
||||
public uint8 opacity {
|
||||
get { return _opacity; }
|
||||
set { _opacity = value; this.update (); }
|
||||
}
|
||||
|
||||
public TextShadowEffect (int offset_x, int offset_y, uint8 opacity) {
|
||||
this._offset_x = offset_x;
|
||||
this._offset_y = offset_y;
|
||||
this._opacity = opacity;
|
||||
}
|
||||
|
||||
public override bool pre_paint () {
|
||||
var layout = ((Clutter.Text)this.get_actor ()).get_layout ();
|
||||
Cogl.pango_render_layout (layout, this.offset_x, this.offset_y,
|
||||
Cogl.Color.from_4ub (0, 0, 0, opacity), 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void update () {
|
||||
if (this.get_actor () != null)
|
||||
this.get_actor ().queue_redraw ();
|
||||
}
|
||||
}
|
||||
|
||||
namespace Gala {
|
||||
|
||||
const string VERSION = "0.1";
|
||||
|
||||
const string SCHEMA = "org.pantheon.desktop.gala";
|
||||
|
||||
const OptionEntry[] OPTIONS = {
|
||||
{ "version", 0, OptionFlags.NO_ARG, OptionArg.CALLBACK, (void*) print_version, "Print version", null },
|
||||
{ null }
|
||||
};
|
||||
|
||||
void print_version () {
|
||||
stdout.printf ("Gala %s\n", Gala.VERSION);
|
||||
Meta.exit (Meta.ExitCode.SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
|
||||
[CCode (cname="clutter_x11_handle_event")]
|
||||
public extern int x_handle_event (X.Event xevent);
|
||||
[CCode (cname="clutter_x11_get_stage_window")]
|
||||
public extern X.Window x_get_stage_window (Clutter.Actor stage);
|
||||
|
||||
int main (string [] args) {
|
||||
|
||||
unowned OptionContext ctx = Meta.get_option_context ();
|
||||
ctx.add_main_entries (Gala.OPTIONS, null);
|
||||
try {
|
||||
ctx.parse (ref args);
|
||||
} catch (Error e) {
|
||||
stderr.printf ("Error initializing: %s\n", e.message);
|
||||
Meta.exit (Meta.ExitCode.ERROR);
|
||||
}
|
||||
|
||||
Meta.Plugin.type_register (new Gala.Plugin ().get_type ());
|
||||
|
||||
/**
|
||||
* Prevent Meta.init () from causing gtk to load gail and at-bridge
|
||||
* Taken from Gnome-Shell main.c
|
||||
*/
|
||||
GLib.Environment.set_variable ("NO_GAIL", "1", true);
|
||||
GLib.Environment.set_variable ("NO_AT_BRIDGE", "1", true);
|
||||
Meta.init ();
|
||||
GLib.Environment.unset_variable ("NO_GAIL");
|
||||
GLib.Environment.unset_variable ("NO_AT_BRIDGE");
|
||||
|
||||
return Meta.run ();
|
||||
}
|
Loading…
Reference in New Issue
Block a user