Skip to content

Commit

Permalink
Fix workspace-grid for Cinnamon 5.4 (#4405)
Browse files Browse the repository at this point in the history
  • Loading branch information
rcalixte authored Aug 2, 2022
1 parent ce540d2 commit 556d5f5
Show file tree
Hide file tree
Showing 10 changed files with 601 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
const Lang = imports.lang;
const St = imports.gi.St;
const Clutter = imports.gi.Clutter;

function BarIndicatorStyle(applet, cols, rows, height) {
this._init(applet, cols, rows, height);
}

BarIndicatorStyle.prototype = {

_init: function(applet, cols, rows, height) {
this.applet = applet;
this.button = [];
this.update_grid(cols, rows, height);
this.switch_id = global.window_manager.connect('switch-workspace', Lang.bind(this, this.update));
this.scroll_id = this.applet.actor.connect('scroll-event', Lang.bind(this,this.onMouseScroll));
},

update_grid: function(cols, rows, height) {
this.cols = cols;
this.rows = rows;
this.height = height;
this.rebuild();
},

cleanup: function() {
global.window_manager.disconnect(this.switch_id);
this.applet.actor.disconnect(this.scroll_id);
},

onMouseScroll: function(actor, event){
if (this.scrollby == 'row')
this.scrollByRow(event);
else
this.scrollByCol(event);
},

scrollByCol: function(event) {
var idx = global.screen.get_active_workspace_index();

if (event.get_scroll_direction() == 0) idx--;
else if (event.get_scroll_direction() == 1) idx++;

if(global.screen.get_workspace_by_index(idx) != null)
global.screen.get_workspace_by_index(idx).activate(global.get_current_time());
},

scrollByRow: function(event) {
var idx = global.screen.get_active_workspace_index();
var numworkspaces = this.rows * this.cols;

var row = Math.floor(idx/this.cols);
var col = idx % this.cols;

if (event.get_scroll_direction() == 0) {
row--;
if (row < 0) {
row=this.rows-1;
col--;
}
}
else if (event.get_scroll_direction() == 1) {
row++;
if (row >= this.rows) {
row=0;
col++;
}
}

if (col < 0 || col >= this.cols)
return;

idx = row*this.cols + col;

if(global.screen.get_workspace_by_index(idx) != null)
global.screen.get_workspace_by_index(idx).activate(global.get_current_time());
},

onRowIndicatorClicked: function(actor, event) {
if (event.get_button() != 1) return false;

let curws_idx = global.screen.get_active_workspace_index();
let curws_row = Math.floor(curws_idx/this.cols);
let [x, y] = event.get_coords();
let [wx, wy] = actor.get_transformed_position();
let [w, h] = actor.get_size();
y -= wy;

let clicked_row = Math.floor(this.rows*y/h);
clicked_idx = (clicked_row * this.cols) + (curws_idx % this.cols);

global.screen.get_workspace_by_index(clicked_idx).activate(global.get_current_time());
return true;
},

onWorkspaceButtonClicked: function(actor, event) {
if (event.get_button() != 1) return false;
global.screen.get_workspace_by_index(actor.index).activate(global.get_current_time());
},

setReactivity: function(reactive) {
for (let i=0; i < this.button.length; ++i)
this.button[i].set_reactive(reactive);
},

rebuild: function() {
this.applet.actor.destroy_all_children();

if (this.rows > 1) {
this.row_indicator = new St.DrawingArea({ reactive: true });
this.row_indicator.set_width(this.height/1.75);
this.row_indicator.connect('repaint', Lang.bind(this, this.draw_row_indicator));
this.row_indicator.connect('button-press-event', Lang.bind(this, this.onRowIndicatorClicked));
this.applet.actor.add(this.row_indicator);
}

this.button = [];
for ( let i=0; i<global.screen.n_workspaces; ++i ) {
this.button[i] = new St.Button({ name: 'workspaceButton', style_class: 'workspace-button', reactive: true });

let text = (i+1).toString();
let label = new St.Label({ text: text });
label.set_style("font-weight: bold");
this.button[i].set_child(label);
this.applet.actor.add(this.button[i]);
this.button[i].index = i;
this.button[i].set_height(this.height);
this.button[i].set_width(this.height*1.25);
this.button[i].connect('button-release-event', Lang.bind(this, this.onWorkspaceButtonClicked));
}
this.update();
},

update: function() {
let nworks = this.button.length;
let active_ws = global.screen.get_active_workspace_index();
let active_row = Math.floor(active_ws/this.cols);
let low = (active_row)*this.cols;
let high = low + this.cols;

// If the user added or removed workspaces external to this applet then
// we could end up with a selected workspaces that is out of bounds. Just
// revert to displaying the last row in that case.
if (active_ws >= nworks) {
high = nworks - 1;
low = high - this.cols;
}

for (let i=0; i < nworks; ++i) {
if (i >= low && i < high) this.button[i].show();
else this.button[i].hide();

if (i == active_ws) {
this.button[i].get_child().set_text((i+1).toString());
this.button[i].add_style_pseudo_class('outlined');
}
else {
this.button[i].get_child().set_text((i+1).toString());
this.button[i].remove_style_pseudo_class('outlined');
}
}

if ( this.row_indicator ) {
this.row_indicator.queue_repaint();
}
},

draw_row_indicator: function(area) {
let [width, height] = area.get_surface_size();
let themeNode = this.row_indicator.get_theme_node();
let cr = area.get_context();

let base_color = this.get_base_color();
let active_color = null;
let inactive_color = null;

if (this.is_theme_light_on_dark()) {
active_color = base_color.lighten();
inactive_color = base_color.darken();
}
else {
active_color = base_color.darken().darken();
inactive_color = base_color.lighten().lighten();
}

let active = global.screen.get_active_workspace_index();
let active_row = Math.floor(active/this.cols);

// Catch overflow due to externally added/removed workspaces
if (active >= this.button.length) active_row = (this.button.length-1) /this.cols;

for ( let i=0; i < this.rows; ++i ) {
let y = (i+1)*height/(this.rows+1);
let endx = (width / 10) * 9;
cr.moveTo(0, y);
cr.lineTo(endx, y);
let color = active_row == i ? active_color : inactive_color;
Clutter.cairo_set_source_color(cr, color);
cr.setLineWidth(2.0);
cr.stroke();
}
},

is_theme_light_on_dark: function() {
let selected_idx = global.screen.get_active_workspace_index();
let unselected_idx = 0;
if (unselected_idx == selected_idx) unselected_idx = 1;

let selected_txt_color = this.button[selected_idx].get_theme_node().get_color('color');
let unselected_txt_color = this.button[unselected_idx].get_theme_node().get_color('color');

let sel_avg = (selected_txt_color.red + selected_txt_color.green + selected_txt_color.blue)/3;
let unsel_avg = (unselected_txt_color.red + unselected_txt_color.green + unselected_txt_color.blue)/3;
return (sel_avg < unsel_avg);
},

// All colors we use in this applet are based on this theme defined color.
// We simply grab the color of a normal, non-outlined workspae button.
get_base_color: function() {
let unselected_idx = 0;
if (unselected_idx == global.screen.get_active_workspace_index()) unselected_idx = 1;
return this.button[unselected_idx].get_theme_node().get_color('color');
}
};

124 changes: 124 additions & 0 deletions workspace-grid@hernejj/files/workspace-grid@hernejj/5.4/GridStyle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
const Lang = imports.lang;
const St = imports.gi.St;
const Clutter = imports.gi.Clutter;

function GridStyle(applet, cols, rows, height) {
this._init(applet, cols, rows, height);
}

GridStyle.prototype = {

_init: function(applet, cols, rows, height) {
this.scrollby = 'col';
this.applet = applet;
this.button = [];
this.update_grid(cols, rows, height);
this.event_handlers = [];
this.switch_id = global.window_manager.connect('switch-workspace', Lang.bind(this, this.update));
this.scroll_id = this.applet.actor.connect('scroll-event', Lang.bind(this,this.onMouseScroll));
},

cleanup: function() {
global.window_manager.disconnect(this.switch_id);
this.applet.actor.disconnect(this.scroll_id);
},

update_grid: function(cols, rows, height) {
this.cols = cols;
this.rows = rows;
this.height = height;
this.rebuild();
},

onMouseScroll: function(actor, event){
if (this.scrollby == 'row')
this.scrollByRow(event);
else
this.scrollByCol(event);
},

scrollByCol: function(event) {
var idx = global.screen.get_active_workspace_index();

if (event.get_scroll_direction() == 0) idx--;
else if (event.get_scroll_direction() == 1) idx++;

if(global.screen.get_workspace_by_index(idx) != null)
global.screen.get_workspace_by_index(idx).activate(global.get_current_time());
},

scrollByRow: function(event) {
var idx = global.screen.get_active_workspace_index();
var numworkspaces = this.rows * this.cols;

var row = Math.floor(idx/this.cols);
var col = idx % this.cols ;

if (event.get_scroll_direction() == 0) {
row--;
if (row < 0) {
row=this.rows-1;
col--;
}
}
else if (event.get_scroll_direction() == 1) {
row++;
if (row >= this.rows) {
row=0;
col++;
}
}

if (col < 0 || col >= this.cols)
return;

idx = row*this.cols + col;

if(global.screen.get_workspace_by_index(idx) != null)
global.screen.get_workspace_by_index(idx).activate(global.get_current_time());
},

onWorkspaceButtonClicked: function(actor, event) {
if (event.get_button() != 1) return false;
global.screen.get_workspace_by_index(actor.index).activate(global.get_current_time());
},

setReactivity: function(reactive) {
for (let i=0; i < this.button.length; ++i)
this.button[i].reactive = reactive;
},

rebuild: function() {
this.applet.actor.destroy_all_children();
this.table = new St.Table({homogeneous: false, reactive: true });
this.applet.actor.add(this.table);

let btn_height = this.height/this.rows;
this.button = [];
for(let r=0; r < this.rows; r++) {
for(let c=0; c < this.cols; c++) {
let i = (r*this.cols)+c;

this.button[i] = new St.Button({ name: 'workspaceButton', style_class: 'workspace-button', reactive: true });
this.button[i].index = i;
this.button[i].set_height(btn_height);
this.button[i].set_width(btn_height*1.25);
this.button[i].connect('button-release-event', Lang.bind(this, this.onWorkspaceButtonClicked));
this.table.add(this.button[i], {row: r, col: c});
}
}
this.update();
},

update: function() {
let active_ws = global.screen.get_active_workspace_index();

for (let i=0; i < this.button.length; ++i) {
if (i == active_ws)
this.button[i].add_style_pseudo_class('outlined');
else
this.button[i].remove_style_pseudo_class('outlined');
}
}
};

Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
const TOPLEFT = imports.gi.Meta.DisplayCorner.TOPLEFT;

function WorkspaceController(cols, rows) {
this._init(cols, rows);
}

WorkspaceController.prototype = {

_init: function(cols, rows) {
this.set_workspace_grid(cols, rows);
},

// Create proper workspace layout geometry within Gnome
set_workspace_grid: function (cols, rows) {
this.cols = cols;
this.rows = rows;
this.__equalize_num_workspaces();
global.screen.override_workspace_layout(TOPLEFT, false, rows, cols);
},

// Update Gnome's view of workspaces to reflect our count based on row*col.
__equalize_num_workspaces: function() {
let new_ws_count = this.cols * this.rows;
let old_ws_count = global.screen.n_workspaces;

if (new_ws_count > old_ws_count) {
for (let i=old_ws_count; i<new_ws_count; i++)
global.screen.append_new_workspace(false, global.get_current_time());
}
else if (new_ws_count < old_ws_count) {
for (let i=old_ws_count; i>new_ws_count; i--) {
let ws = global.screen.get_workspace_by_index( global.screen.n_workspaces-1 );
global.screen.remove_workspace(ws, global.get_current_time());
}
}
},

// This applet is going away. Revert to allowing Cinnamon to control workspaces.
release_control: function() {
this.set_workspace_grid(-1, 1); // Set to no rows, and a single desktop
}
};

Loading

0 comments on commit 556d5f5

Please sign in to comment.