diff --git a/js/ui/windowManager.js b/js/ui/windowManager.js index 4694ea380..2c4b0ef23 100644 --- a/js/ui/windowManager.js +++ b/js/ui/windowManager.js @@ -8,6 +8,7 @@ const Tweener = imports.tweener.tweener; const Main = imports.ui.main; +const WINDOW_ANIMATION_TIME = 0.25; const SWITCH_ANIMATION_TIME = 0.5; function WindowManager() { @@ -20,20 +21,219 @@ WindowManager.prototype = { this._global = Shell.Global.get(); this._shellwm = this._global.window_manager; + this._minimizing = []; + this._maximizing = []; + this._unmaximizing = []; + this._mapping = []; + this._destroying = []; this._switchData = null; this._shellwm.connect('switch-workspace', function(o, from, to, direction) { let actors = me._shellwm.get_switch_workspace_actors(); - me.switchWorkspace(actors, from, to, direction); + me._switchWorkspace(actors, from, to, direction); }); this._shellwm.connect('kill-switch-workspace', function(o) { - me.switchWorkspaceDone(); + me._switchWorkspaceDone(); + }); + this._shellwm.connect('minimize', + function(o, actor) { + me._minimizeWindow(actor); + }); + this._shellwm.connect('kill-minimize', + function(o, actor) { + me._minimizeWindowDone(actor); + }); + this._shellwm.connect('maximize', + function(o, actor, tx, ty, tw, th) { + me._maximizeWindow(actor, tx, ty, tw, th); + }); + this._shellwm.connect('kill-maximize', + function(o, actor) { + me._maximizeWindowDone(actor); + }); + this._shellwm.connect('unmaximize', + function(o, actor, tx, ty, tw, th) { + me._unmaximizeWindow(actor, tx, ty, tw, th); + }); + this._shellwm.connect('kill-unmaximize', + function(o, actor) { + me._unmaximizeWindowDone(actor); + }); + this._shellwm.connect('map', + function(o, actor) { + me._mapWindow(actor); + }); + this._shellwm.connect('kill-map', + function(o, actor) { + me._mapWindowDone(actor); + }); + this._shellwm.connect('destroy', + function(o, actor) { + me._destroyWindow(actor); + }); + this._shellwm.connect('kill-destroy', + function(o, actor) { + me._destroyWindowDone(actor); }); }, - switchWorkspace : function(windows, from, to, direction) { + + _minimizeWindow : function(actor) { + if (actor.get_window_type() != Meta.CompWindowType.NORMAL) { + this._shellwm.completed_minimize(actor); + return; + } + + actor.set_scale(1.0, 1.0); + actor.move_anchor_point_from_gravity(Clutter.Gravity.CENTER); + + /* scale window down to 0x0. + * maybe TODO: get icon geometry passed through and move the window towards it? + */ + this._minimizing.push(actor); + Tweener.addTween(actor, + { scale_x: 0.0, + scale_y: 0.0, + time: WINDOW_ANIMATION_TIME, + transition: "easeOutQuad", + onComplete: this._minimizeWindowDone, + onCompleteScope: this, + onCompleteParams: [actor] + }); + }, + + _minimizeWindowDone : function(actor) { + let idx = this._minimizing.indexOf(actor); + if (idx != -1) { + Tweener.removeTweens(actor); + actor.set_scale(1.0, 1.0); + actor.move_anchor_point_from_gravity(Clutter.Gravity.NORTH_WEST); + this._shellwm.completed_minimize(actor); + + this._minimizing.splice(idx, 1); + } + }, + + _maximizeWindow : function(actor, target_x, target_y, target_width, target_height) { + if (actor.get_window_type() != Meta.CompWindowType.NORMAL) { + this._shellwm.completed_maximize(actor); + return; + } + + /* this doesn't work very well, as simply scaling up the existing + * window contents doesn't produce anything like the same results as + * actually maximizing the window. + */ + let scale_x = target_width / actor.width; + let scale_y = target_height / actor.height; + let anchor_x = (actor.x - target_x) * actor.width/(target_width - actor.width); + let anchor_y = (actor.y - target_y) * actor.height/(target_height - actor.height); + + actor.move_anchor_point(anchor_x, anchor_y); + + this._maximizing.push(actor); + Tweener.addTween(actor, + { scale_x: scale_x, + scale_y: scale_y, + time: WINDOW_ANIMATION_TIME, + transition: "easeOutQuad", + onComplete: this._maximizeWindowDone, + onCompleteScope: this, + onCompleteParams: [actor] + }); + }, + + _maximizeWindowDone : function(actor) { + let idx = this._maximizing.indexOf(actor); + if (idx != -1) { + Tweener.removeTweens(actor); + actor.set_scale(1.0, 1.0); + actor.move_anchor_point_from_gravity(Clutter.Gravity.NORTH_WEST); + this._shellwm.completed_maximize(actor); + + this._maximizing.splice(idx, 1); + } + }, + + _unmaximizeWindow : function(actor, target_x, target_y, target_width, target_height) { + this._shellwm.completed_unmaximize(actor); + }, + + _unmaximizeWindowDone : function(actor) { + }, + + + _mapWindow : function(actor) { + if (actor.get_window_type() != Meta.CompWindowType.NORMAL) { + this._shellwm.completed_map(actor); + return; + } + + actor.move_anchor_point_from_gravity(Clutter.Gravity.CENTER); + actor.set_scale(0.0, 0.0); + actor.show(); + + /* scale window up from 0x0 to normal size */ + this._mapping.push(actor); + Tweener.addTween(actor, + { scale_x: 1.0, + scale_y: 1.0, + time: WINDOW_ANIMATION_TIME, + transition: "easeOutQuad", + onComplete: this._mapWindowDone, + onCompleteScope: this, + onCompleteParams: [actor] + }); + }, + + _mapWindowDone : function(actor) { + let idx = this._mapping.indexOf(actor); + if (idx != -1) { + Tweener.removeTweens(actor); + actor.set_scale(1.0, 1.0); + actor.move_anchor_point_from_gravity(Clutter.Gravity.NORTH_WEST); + this._shellwm.completed_map(actor); + + this._mapping.splice(idx, 1); + } + }, + + _destroyWindow : function(actor) { + if (actor.get_window_type() != Meta.CompWindowType.NORMAL) { + this._shellwm.completed_destroy(actor); + return; + } + + actor.move_anchor_point_from_gravity(Clutter.Gravity.CENTER); + + /* anachronistic 'tv-like' effect - squash on y axis, leave x alone */ + this._destroying.push(actor); + Tweener.addTween(actor, + { scale_x: 1.0, + scale_y: 0.0, + time: WINDOW_ANIMATION_TIME, + transition: "easeOutQuad", + onComplete: this._destroyWindowDone, + onCompleteScope: this, + onCompleteParams: [actor] + }); + }, + + _destroyWindowDone : function(actor) { + let idx = this._destroying.indexOf(actor); + if (idx != -1) { + this._shellwm.completed_destroy(actor); + Tweener.removeTweens(actor); + actor.set_scale(1.0, 1.0); + + this._mapping.splice(idx, 1); + } + }, + + + _switchWorkspace : function(windows, from, to, direction) { // If the overlay is active, it will do the transition itself if (Main.overlayActive) { this._shellwm.completed_switch_workspace(); @@ -96,7 +296,7 @@ WindowManager.prototype = { y: yDest, time: SWITCH_ANIMATION_TIME, transition: "easeOutBack", - onComplete: this.switchWorkspaceDone + onComplete: this._switchWorkspaceDone }); Tweener.addTween(switchData.inGroup, { x: 0, @@ -106,7 +306,7 @@ WindowManager.prototype = { }); }, - switchWorkspaceDone : function() { + _switchWorkspaceDone : function() { let switchData = this._switchData; if (!switchData) return; diff --git a/src/gnome-shell-plugin.c b/src/gnome-shell-plugin.c index 1f2983186..43d2db03e 100644 --- a/src/gnome-shell-plugin.c +++ b/src/gnome-shell-plugin.c @@ -46,7 +46,6 @@ static void gnome_shell_plugin_constructed (GObject *object); static void gnome_shell_plugin_dispose (GObject *object); static void gnome_shell_plugin_finalize (GObject *object); -#ifdef NOT_YET static void gnome_shell_plugin_minimize (MutterPlugin *plugin, MutterWindow *actor); static void gnome_shell_plugin_maximize (MutterPlugin *plugin, @@ -65,7 +64,6 @@ static void gnome_shell_plugin_map (MutterPlugin *plugi MutterWindow *actor); static void gnome_shell_plugin_destroy (MutterPlugin *plugin, MutterWindow *actor); -#endif static void gnome_shell_plugin_switch_workspace (MutterPlugin *plugin, const GList **actors, @@ -121,13 +119,11 @@ gnome_shell_plugin_class_init (GnomeShellPluginClass *klass) gobject_class->dispose = gnome_shell_plugin_dispose; gobject_class->finalize = gnome_shell_plugin_finalize; -#ifdef NOT_YET plugin_class->map = gnome_shell_plugin_map; plugin_class->minimize = gnome_shell_plugin_minimize; plugin_class->maximize = gnome_shell_plugin_maximize; plugin_class->unmaximize = gnome_shell_plugin_unmaximize; plugin_class->destroy = gnome_shell_plugin_destroy; -#endif plugin_class->switch_workspace = gnome_shell_plugin_switch_workspace; plugin_class->kill_effect = gnome_shell_plugin_kill_effect; @@ -212,6 +208,55 @@ get_shell_wm (void) return wm; } +static void +gnome_shell_plugin_minimize (MutterPlugin *plugin, + MutterWindow *actor) +{ + _shell_wm_minimize (get_shell_wm (), + actor); + +} + +static void +gnome_shell_plugin_maximize (MutterPlugin *plugin, + MutterWindow *actor, + gint x, + gint y, + gint width, + gint height) +{ + _shell_wm_maximize (get_shell_wm (), + actor, x, y, width, height); +} + +static void +gnome_shell_plugin_unmaximize (MutterPlugin *plugin, + MutterWindow *actor, + gint x, + gint y, + gint width, + gint height) +{ + _shell_wm_unmaximize (get_shell_wm (), + actor, x, y, width, height); +} + +static void +gnome_shell_plugin_map (MutterPlugin *plugin, + MutterWindow *actor) +{ + _shell_wm_map (get_shell_wm (), + actor); +} + +static void +gnome_shell_plugin_destroy (MutterPlugin *plugin, + MutterWindow *actor) +{ + _shell_wm_destroy (get_shell_wm (), + actor); +} + static void gnome_shell_plugin_switch_workspace (MutterPlugin *plugin, const GList **actors, diff --git a/src/shell-marshal.list b/src/shell-marshal.list index 11ef833a0..a86d7fd82 100644 --- a/src/shell-marshal.list +++ b/src/shell-marshal.list @@ -1 +1,2 @@ VOID:INT,INT,INT +VOID:OBJECT,INT,INT,INT,INT diff --git a/src/shell-wm.c b/src/shell-wm.c index 5fed2c322..7b77a0415 100644 --- a/src/shell-wm.c +++ b/src/shell-wm.c @@ -14,7 +14,6 @@ struct _ShellWM { /* Signals */ enum { -#ifdef NOT_YET MINIMIZE, KILL_MINIMIZE, MAXIMIZE, @@ -25,7 +24,6 @@ enum KILL_MAP, DESTROY, KILL_DESTROY, -#endif SWITCH_WORKSPACE, KILL_SWITCH_WORKSPACE, @@ -61,6 +59,96 @@ shell_wm_class_init (ShellWMClass *klass) gobject_class->finalize = shell_wm_finalize; + shell_wm_signals[MINIMIZE] = + g_signal_new ("minimize", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + MUTTER_TYPE_COMP_WINDOW); + shell_wm_signals[KILL_MINIMIZE] = + g_signal_new ("kill-minimize", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + MUTTER_TYPE_COMP_WINDOW); + shell_wm_signals[MAXIMIZE] = + g_signal_new ("maximize", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + _shell_marshal_VOID__OBJECT_INT_INT_INT_INT, + G_TYPE_NONE, 5, + MUTTER_TYPE_COMP_WINDOW, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT); + shell_wm_signals[KILL_MAXIMIZE] = + g_signal_new ("kill-maximize", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + MUTTER_TYPE_COMP_WINDOW); + shell_wm_signals[UNMAXIMIZE] = + g_signal_new ("unmaximize", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + _shell_marshal_VOID__OBJECT_INT_INT_INT_INT, + G_TYPE_NONE, 1, + MUTTER_TYPE_COMP_WINDOW, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT); + shell_wm_signals[KILL_UNMAXIMIZE] = + g_signal_new ("kill-unmaximize", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + MUTTER_TYPE_COMP_WINDOW); + shell_wm_signals[MAP] = + g_signal_new ("map", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + MUTTER_TYPE_COMP_WINDOW); + shell_wm_signals[KILL_MAP] = + g_signal_new ("kill-map", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + MUTTER_TYPE_COMP_WINDOW); + shell_wm_signals[DESTROY] = + g_signal_new ("destroy", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + MUTTER_TYPE_COMP_WINDOW); + shell_wm_signals[KILL_DESTROY] = + g_signal_new ("kill-destroy", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + MUTTER_TYPE_COMP_WINDOW); shell_wm_signals[SWITCH_WORKSPACE] = g_signal_new ("switch-workspace", G_TYPE_FROM_CLASS (klass), @@ -148,29 +236,149 @@ shell_wm_completed_switch_workspace (ShellWM *wm) shell_wm_set_switch_workspace_actors (wm, NULL); } +/** + * shell_wm_completed_minimize + * @wm: the ShellWM + * @actor: the MutterWindow actor + * + * The plugin must call this when it has completed a window minimize effect. + **/ +void +shell_wm_completed_minimize (ShellWM *wm, + MutterWindow *actor) +{ + mutter_plugin_effect_completed (wm->plugin, + actor, + MUTTER_PLUGIN_MINIMIZE); +} + +/** + * shell_wm_completed_maximize + * @wm: the ShellWM + * @actor: the MutterWindow actor + * + * The plugin must call this when it has completed a window maximize effect. + **/ +void +shell_wm_completed_maximize (ShellWM *wm, + MutterWindow *actor) +{ + mutter_plugin_effect_completed (wm->plugin, + actor, + MUTTER_PLUGIN_MAXIMIZE); +} + +/** + * shell_wm_completed_unmaximize + * @wm: the ShellWM + * @actor: the MutterWindow actor + * + * The plugin must call this when it has completed a window unmaximize effect. + **/ +void +shell_wm_completed_unmaximize (ShellWM *wm, + MutterWindow *actor) +{ + mutter_plugin_effect_completed (wm->plugin, + actor, + MUTTER_PLUGIN_UNMAXIMIZE); +} + +/** + * shell_wm_completed_map + * @wm: the ShellWM + * @actor: the MutterWindow actor + * + * The plugin must call this when it has completed a window map effect. + **/ +void +shell_wm_completed_map (ShellWM *wm, + MutterWindow *actor) +{ + mutter_plugin_effect_completed (wm->plugin, + actor, + MUTTER_PLUGIN_MAP); +} + +/** + * shell_wm_completed_destroy + * @wm: the ShellWM + * @actor: the MutterWindow actor + * + * The plugin must call this when it has completed a window destroy effect. + **/ +void +shell_wm_completed_destroy (ShellWM *wm, + MutterWindow *actor) +{ + mutter_plugin_effect_completed (wm->plugin, + actor, + MUTTER_PLUGIN_DESTROY); +} void _shell_wm_kill_effect (ShellWM *wm, MutterWindow *actor, gulong events) { -#ifdef NOT_YET if (events & MUTTER_PLUGIN_MINIMIZE) - g_signal_emit (wm, shell_wm_signals[KILL_MINIMIZE], 0); + g_signal_emit (wm, shell_wm_signals[KILL_MINIMIZE], 0, actor); if (events & MUTTER_PLUGIN_MAXIMIZE) - g_signal_emit (wm, shell_wm_signals[KILL_MAXIMIZE], 0); + g_signal_emit (wm, shell_wm_signals[KILL_MAXIMIZE], 0, actor); if (events & MUTTER_PLUGIN_UNMAXIMIZE) - g_signal_emit (wm, shell_wm_signals[KILL_UNMAXIMIZE], 0); + g_signal_emit (wm, shell_wm_signals[KILL_UNMAXIMIZE], 0, actor); if (events & MUTTER_PLUGIN_MAP) - g_signal_emit (wm, shell_wm_signals[KILL_MAP], 0); + g_signal_emit (wm, shell_wm_signals[KILL_MAP], 0, actor); if (events & MUTTER_PLUGIN_DESTROY) - g_signal_emit (wm, shell_wm_signals[KILL_DESTROY], 0); -#endif + g_signal_emit (wm, shell_wm_signals[KILL_DESTROY], 0, actor); if (events & MUTTER_PLUGIN_SWITCH_WORKSPACE) g_signal_emit (wm, shell_wm_signals[KILL_SWITCH_WORKSPACE], 0); } +void +_shell_wm_minimize (ShellWM *wm, + MutterWindow *actor) +{ + g_signal_emit (wm, shell_wm_signals[MINIMIZE], 0, actor); +} + +void +_shell_wm_maximize (ShellWM *wm, + MutterWindow *actor, + int target_x, + int target_y, + int target_width, + int target_height) +{ + g_signal_emit (wm, shell_wm_signals[MAXIMIZE], 0, actor, target_x, target_y, target_width, target_height); +} + +void +_shell_wm_unmaximize (ShellWM *wm, + MutterWindow *actor, + int target_x, + int target_y, + int target_width, + int target_height) +{ + g_signal_emit (wm, shell_wm_signals[UNMAXIMIZE], 0, actor, target_x, target_y, target_width, target_height); +} + +void +_shell_wm_map (ShellWM *wm, + MutterWindow *actor) +{ + g_signal_emit (wm, shell_wm_signals[MAP], 0, actor); +} + +void +_shell_wm_destroy (ShellWM *wm, + MutterWindow *actor) +{ + g_signal_emit (wm, shell_wm_signals[DESTROY], 0, actor); +} + /** * shell_wm_new: * @plugin: the #MutterPlugin diff --git a/src/shell-wm.h b/src/shell-wm.h index 7d15a7aa3..f5b349f68 100644 --- a/src/shell-wm.h +++ b/src/shell-wm.h @@ -27,12 +27,22 @@ GType shell_wm_get_type (void) G_GNUC_CONST; ShellWM *shell_wm_new (MutterPlugin *plugin); GList *shell_wm_get_switch_workspace_actors (ShellWM *wm); + +void shell_wm_completed_minimize (ShellWM *wm, + MutterWindow *actor); +void shell_wm_completed_maximize (ShellWM *wm, + MutterWindow *actor); +void shell_wm_completed_unmaximize (ShellWM *wm, + MutterWindow *actor); +void shell_wm_completed_map (ShellWM *wm, + MutterWindow *actor); +void shell_wm_completed_destroy (ShellWM *wm, + MutterWindow *actor); void shell_wm_completed_switch_workspace (ShellWM *wm); /* These forward along the different effects from GnomeShellPlugin */ -#ifdef NOT_YET void _shell_wm_minimize (ShellWM *wm, MutterWindow *actor); void _shell_wm_maximize (ShellWM *wm, @@ -51,7 +61,6 @@ void _shell_wm_map (ShellWM *wm, MutterWindow *actor); void _shell_wm_destroy (ShellWM *wm, MutterWindow *actor); -#endif void _shell_wm_switch_workspace (ShellWM *wm, const GList **actors,