2019-03-05 08:36:59 -03:00
|
|
|
/* jslint esversion: 6 */
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Copyright 2019 Abakkk
|
|
|
|
|
*
|
|
|
|
|
* This file is part of DrowOnYourScreen, a drawing extension for GNOME Shell.
|
|
|
|
|
* https://framagit.org/abakkk/DrawOnYourScreen
|
|
|
|
|
*
|
|
|
|
|
* 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 2 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/>.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
const Gio = imports.gi.Gio;
|
|
|
|
|
const Lang = imports.lang;
|
|
|
|
|
const Meta = imports.gi.Meta;
|
|
|
|
|
const Shell = imports.gi.Shell;
|
|
|
|
|
const St = imports.gi.St;
|
|
|
|
|
const Main = imports.ui.main;
|
|
|
|
|
const OsdWindow = imports.ui.osdWindow;
|
|
|
|
|
const Extension = imports.misc.extensionUtils.getCurrentExtension();
|
|
|
|
|
const Convenience = Extension.imports.convenience;
|
|
|
|
|
const Draw = Extension.imports.draw;
|
|
|
|
|
const _ = imports.gettext.domain(Extension.metadata["gettext-domain"]).gettext;
|
|
|
|
|
|
|
|
|
|
let manager;
|
|
|
|
|
|
|
|
|
|
function init() {
|
|
|
|
|
Convenience.initTranslations();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function enable() {
|
|
|
|
|
manager = new AreaManager();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function disable() {
|
|
|
|
|
manager.disable();
|
|
|
|
|
manager = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// AreaManager assigns one DrawingArea per monitor (updateAreas()),
|
|
|
|
|
// distributes keybinding callbacks to the active area
|
|
|
|
|
// and handles stylesheet and monitor changes.
|
|
|
|
|
var AreaManager = new Lang.Class({
|
2019-03-08 07:37:59 -03:00
|
|
|
Name: 'DrawOnYourScreenAreaManager',
|
2019-03-05 08:36:59 -03:00
|
|
|
|
|
|
|
|
_init: function() {
|
2019-03-10 18:16:11 -03:00
|
|
|
this.settings = Convenience.getSettings();
|
2019-03-05 08:36:59 -03:00
|
|
|
this.areas = [];
|
|
|
|
|
this.activeArea = null;
|
|
|
|
|
this.enterGicon = new Gio.ThemedIcon({ name: 'applications-graphics-symbolic' });
|
|
|
|
|
this.leaveGicon = new Gio.ThemedIcon({ name: 'application-exit-symbolic' });
|
|
|
|
|
|
|
|
|
|
Main.wm.addKeybinding('toggle-drawing',
|
2019-03-10 18:16:11 -03:00
|
|
|
this.settings,
|
2019-03-05 08:36:59 -03:00
|
|
|
Meta.KeyBindingFlags.NONE,
|
|
|
|
|
Shell.ActionMode.ALL,
|
|
|
|
|
this.toggleDrawing.bind(this));
|
|
|
|
|
|
|
|
|
|
Main.wm.addKeybinding('erase-drawing',
|
2019-03-10 18:16:11 -03:00
|
|
|
this.settings,
|
2019-03-05 08:36:59 -03:00
|
|
|
Meta.KeyBindingFlags.NONE,
|
|
|
|
|
Shell.ActionMode.ALL,
|
|
|
|
|
this.eraseDrawing.bind(this));
|
|
|
|
|
|
|
|
|
|
this.updateAreas();
|
|
|
|
|
this.monitorChangedHandler = Main.layoutManager.connect('monitors-changed', this.updateAreas.bind(this));
|
|
|
|
|
|
|
|
|
|
if (Extension.stylesheet) {
|
|
|
|
|
this.stylesheetMonitor = Extension.stylesheet.monitor(Gio.FileMonitorFlags.NONE, null);
|
|
|
|
|
this.stylesheetChangedHandler = this.stylesheetMonitor.connect('changed', (monitor, file, otherFile, eventType) => {
|
|
|
|
|
if ((eventType != 0 && eventType != 3) || !Extension.stylesheet.query_exists(null))
|
|
|
|
|
return;
|
|
|
|
|
let theme = St.ThemeContext.get_for_stage(global.stage).get_theme();
|
|
|
|
|
theme.unload_stylesheet(Extension.stylesheet);
|
|
|
|
|
theme.load_stylesheet(Extension.stylesheet);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
updateAreas: function() {
|
|
|
|
|
if (this.activeArea)
|
|
|
|
|
this.toggleDrawing();
|
|
|
|
|
this.removeAreas();
|
|
|
|
|
|
|
|
|
|
this.monitors = Main.layoutManager.monitors;
|
|
|
|
|
|
|
|
|
|
for (let i = 0; i < this.monitors.length; i++) {
|
|
|
|
|
let monitor = this.monitors[i];
|
2019-03-10 09:05:38 -03:00
|
|
|
let container = new St.Widget({ name: 'drawOnYourSreenContainer' + i });
|
2019-03-05 08:36:59 -03:00
|
|
|
let helper = new Draw.DrawingHelper({ name: 'drawOnYourSreenHelper' + i }, monitor);
|
2019-03-11 13:53:35 -03:00
|
|
|
let load = i == Main.layoutManager.primaryIndex && this.settings.get_boolean('persistent-drawing');
|
|
|
|
|
let area = new Draw.DrawingArea({ name: 'drawOnYourSreenArea' + i }, monitor, helper, load);
|
2019-03-10 09:05:38 -03:00
|
|
|
container.add_child(area);
|
|
|
|
|
container.add_child(helper);
|
2019-03-10 18:16:11 -03:00
|
|
|
|
|
|
|
|
if (this.settings.get_boolean("move-drawing-on-desktop"))
|
|
|
|
|
Main.layoutManager._backgroundGroup.insert_child_above(container, Main.layoutManager._bgManagers[i].backgroundActor);
|
|
|
|
|
else
|
|
|
|
|
Main.uiGroup.insert_child_above(container, global.window_group);
|
|
|
|
|
|
2019-03-10 09:05:38 -03:00
|
|
|
container.set_position(monitor.x, monitor.y);
|
|
|
|
|
container.set_size(monitor.width, monitor.height);
|
2019-03-05 08:36:59 -03:00
|
|
|
area.set_size(monitor.width, monitor.height);
|
2019-03-11 15:07:01 -03:00
|
|
|
if (area.isEmpty)
|
|
|
|
|
container.hide();
|
2019-03-08 08:28:03 -03:00
|
|
|
area.emitter.stopDrawingHandler = area.emitter.connect('stop-drawing', this.toggleDrawing.bind(this));
|
|
|
|
|
area.emitter.showOsdHandler = area.emitter.connect('show-osd', this.showOsd.bind(this));
|
2019-03-05 08:36:59 -03:00
|
|
|
this.areas.push(area);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
addInternalKeybindings: function() {
|
|
|
|
|
this.internalKeybindings = {
|
|
|
|
|
'undo': this.activeArea.undo.bind(this.activeArea),
|
|
|
|
|
'redo': this.activeArea.redo.bind(this.activeArea),
|
|
|
|
|
'delete-last-element': this.activeArea.deleteLastElement.bind(this.activeArea),
|
2019-03-05 17:08:43 -03:00
|
|
|
'smooth-last-element': this.activeArea.smoothLastElement.bind(this.activeArea),
|
2019-03-11 13:53:35 -03:00
|
|
|
'save-as-svg': this.activeArea.saveAsSvg.bind(this.activeArea),
|
2019-03-05 08:36:59 -03:00
|
|
|
'toggle-background': this.activeArea.toggleBackground.bind(this.activeArea),
|
2019-03-07 12:32:06 -03:00
|
|
|
'toggle-square-area': this.activeArea.toggleSquareArea.bind(this.activeArea),
|
2019-03-05 08:36:59 -03:00
|
|
|
'increment-line-width': () => this.activeArea.incrementLineWidth(1),
|
|
|
|
|
'decrement-line-width': () => this.activeArea.incrementLineWidth(-1),
|
|
|
|
|
'increment-line-width-more': () => this.activeArea.incrementLineWidth(5),
|
|
|
|
|
'decrement-line-width-more': () => this.activeArea.incrementLineWidth(-5),
|
|
|
|
|
'toggle-linejoin': this.activeArea.toggleLineJoin.bind(this.activeArea),
|
|
|
|
|
'toggle-linecap': this.activeArea.toggleLineCap.bind(this.activeArea),
|
|
|
|
|
'toggle-dash' : this.activeArea.toggleDash.bind(this.activeArea),
|
|
|
|
|
'select-none-shape': () => this.activeArea.selectShape(Draw.Shapes.NONE),
|
|
|
|
|
'select-line-shape': () => this.activeArea.selectShape(Draw.Shapes.LINE),
|
|
|
|
|
'select-ellipse-shape': () => this.activeArea.selectShape(Draw.Shapes.ELLIPSE),
|
|
|
|
|
'select-rectangle-shape': () => this.activeArea.selectShape(Draw.Shapes.RECTANGLE),
|
|
|
|
|
'select-text-shape': () => this.activeArea.selectShape(Draw.Shapes.TEXT),
|
|
|
|
|
'toggle-font-family': this.activeArea.toggleFontFamily.bind(this.activeArea),
|
|
|
|
|
'toggle-font-weight': this.activeArea.toggleFontWeight.bind(this.activeArea),
|
|
|
|
|
'toggle-font-style': this.activeArea.toggleFontStyle.bind(this.activeArea),
|
|
|
|
|
'toggle-panel-and-dock-visibility': this.togglePanelAndDockOpacity.bind(this),
|
|
|
|
|
'toggle-help': this.activeArea.toggleHelp.bind(this.activeArea),
|
|
|
|
|
'open-stylesheet': this.openStylesheetFile.bind(this)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
for (let key in this.internalKeybindings) {
|
|
|
|
|
Main.wm.addKeybinding(key,
|
2019-03-10 18:16:11 -03:00
|
|
|
this.settings,
|
2019-03-05 08:36:59 -03:00
|
|
|
Meta.KeyBindingFlags.NONE,
|
|
|
|
|
256,
|
|
|
|
|
this.internalKeybindings[key]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (let i = 1; i < 10; i++) {
|
|
|
|
|
Main.wm.addKeybinding('select-color' + i,
|
2019-03-10 18:16:11 -03:00
|
|
|
this.settings,
|
2019-03-05 08:36:59 -03:00
|
|
|
Meta.KeyBindingFlags.NONE,
|
|
|
|
|
256,
|
|
|
|
|
() => this.activeArea.selectColor(i));
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
removeInternalKeybindings: function() {
|
|
|
|
|
for (let key in this.internalKeybindings) {
|
|
|
|
|
Main.wm.removeKeybinding(key);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (let i = 1; i < 10; i++) {
|
|
|
|
|
Main.wm.removeKeybinding('select-color' + i);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
openStylesheetFile: function() {
|
|
|
|
|
if (Extension.stylesheet && Extension.stylesheet.query_exists(null))
|
|
|
|
|
Gio.AppInfo.launch_default_for_uri(Extension.stylesheet.get_uri(), global.create_app_launch_context(0, -1));
|
|
|
|
|
if (this.activeArea)
|
|
|
|
|
this.toggleDrawing();
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
eraseDrawing: function() {
|
|
|
|
|
for (let i = 0; i < this.areas.length; i++) {
|
|
|
|
|
this.areas[i].erase();
|
2019-03-11 15:07:01 -03:00
|
|
|
this.areas[i].get_parent().hide();
|
2019-03-05 08:36:59 -03:00
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
togglePanelAndDockOpacity: function() {
|
|
|
|
|
if (this.hiddenList) {
|
|
|
|
|
for (let i = 0; i < this.hiddenList.length; i++) {
|
|
|
|
|
this.hiddenList[i].actor.set_opacity(this.hiddenList[i].oldOpacity);
|
|
|
|
|
}
|
|
|
|
|
this.hiddenList = null;
|
|
|
|
|
} else {
|
|
|
|
|
let activeIndex = this.areas.indexOf(this.activeArea);
|
|
|
|
|
|
|
|
|
|
// dash-to-dock
|
|
|
|
|
let dtdContainers = Main.uiGroup.get_children().filter((actor) => {
|
|
|
|
|
return actor.name && actor.name == 'dashtodockContainer' &&
|
|
|
|
|
actor._delegate &&
|
|
|
|
|
actor._delegate._monitorIndex !== undefined &&
|
|
|
|
|
actor._delegate._monitorIndex == activeIndex;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// for simplicity, we assume that main dash-to-panel panel is displayed on primary monitor
|
|
|
|
|
// and we hide all secondary panels together if the active area is not on the primary
|
|
|
|
|
let name = activeIndex == Main.layoutManager.primaryIndex ? 'panelBox' : 'dashtopanelSecondaryPanelBox';
|
|
|
|
|
let panelBoxes = Main.uiGroup.get_children().filter((actor) => {
|
|
|
|
|
return actor.name && actor.name == name;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let actorToHide = dtdContainers.concat(panelBoxes);
|
|
|
|
|
this.hiddenList = [];
|
|
|
|
|
for (let i = 0; i < actorToHide.length; i++) {
|
|
|
|
|
this.hiddenList.push({ actor: actorToHide[i], oldOpacity: actorToHide[i].get_opacity() });
|
|
|
|
|
actorToHide[i].set_opacity(0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
2019-03-11 15:07:01 -03:00
|
|
|
toggleDrawing: function(emitter, hide) {
|
2019-03-05 08:36:59 -03:00
|
|
|
if (this.activeArea) {
|
2019-03-10 09:05:38 -03:00
|
|
|
let activeIndex = this.areas.indexOf(this.activeArea);
|
|
|
|
|
let activeContainer = this.activeArea.get_parent();
|
2019-03-11 13:53:35 -03:00
|
|
|
let save = activeIndex == Main.layoutManager.primaryIndex && this.settings.get_boolean('persistent-drawing');
|
2019-03-11 15:07:01 -03:00
|
|
|
hide = hide || this.activeArea.isEmpty;
|
2019-03-10 09:05:38 -03:00
|
|
|
|
2019-03-05 08:36:59 -03:00
|
|
|
if (this.hiddenList)
|
|
|
|
|
this.togglePanelAndDockOpacity();
|
2019-03-10 09:05:38 -03:00
|
|
|
|
2019-03-05 08:36:59 -03:00
|
|
|
Main.popModal(this.activeArea);
|
|
|
|
|
this.removeInternalKeybindings();
|
|
|
|
|
this.activeArea.reactive = false;
|
2019-03-11 13:53:35 -03:00
|
|
|
this.activeArea.leaveDrawingMode(save);
|
2019-03-05 08:36:59 -03:00
|
|
|
this.activeArea = null;
|
2019-03-10 09:05:38 -03:00
|
|
|
|
2019-03-10 18:16:11 -03:00
|
|
|
activeContainer.get_parent().remove_actor(activeContainer);
|
|
|
|
|
if (this.settings.get_boolean("move-drawing-on-desktop"))
|
|
|
|
|
Main.layoutManager._backgroundGroup.insert_child_above(activeContainer, Main.layoutManager._bgManagers[activeIndex].backgroundActor);
|
|
|
|
|
else
|
|
|
|
|
Main.uiGroup.insert_child_above(activeContainer, global.window_group);
|
2019-03-10 09:05:38 -03:00
|
|
|
|
2019-03-11 15:07:01 -03:00
|
|
|
if (hide)
|
|
|
|
|
activeContainer.hide();
|
|
|
|
|
|
2019-03-05 21:19:37 -03:00
|
|
|
// check display or screen (API changes)
|
|
|
|
|
if (global.display.set_cursor)
|
|
|
|
|
global.display.set_cursor(Meta.Cursor.DEFAULT);
|
|
|
|
|
else if (global.screen && global.screen.set_cursor)
|
|
|
|
|
global.screen.set_cursor(Meta.Cursor.DEFAULT);
|
2019-03-10 09:05:38 -03:00
|
|
|
|
2019-03-05 08:36:59 -03:00
|
|
|
Main.osdWindowManager.show(activeIndex, this.leaveGicon, _("Leaving drawing mode"), null);
|
|
|
|
|
} else {
|
|
|
|
|
// avoid to deal with Meta changes (global.display/global.screen)
|
|
|
|
|
let currentIndex = Main.layoutManager.monitors.indexOf(Main.layoutManager.currentMonitor);
|
2019-03-10 09:05:38 -03:00
|
|
|
let activeContainer = this.areas[currentIndex].get_parent();
|
|
|
|
|
|
2019-03-10 18:16:11 -03:00
|
|
|
activeContainer.get_parent().remove_actor(activeContainer);
|
|
|
|
|
Main.uiGroup.add_child(activeContainer);
|
2019-03-10 09:05:38 -03:00
|
|
|
|
2019-03-05 08:36:59 -03:00
|
|
|
// 256 is a custom Shell.ActionMode
|
|
|
|
|
if (!Main.pushModal(this.areas[currentIndex], { actionMode: 256 | 1 }))
|
|
|
|
|
return;
|
|
|
|
|
this.activeArea = this.areas[currentIndex];
|
|
|
|
|
this.addInternalKeybindings();
|
|
|
|
|
this.activeArea.reactive = true;
|
|
|
|
|
this.activeArea.enterDrawingMode();
|
2019-03-10 09:05:38 -03:00
|
|
|
|
2019-03-05 21:19:37 -03:00
|
|
|
// check display or screen (API changes)
|
|
|
|
|
if (global.display.set_cursor)
|
|
|
|
|
global.display.set_cursor(Meta.Cursor.POINTING_HAND);
|
|
|
|
|
else if (global.screen && global.screen.set_cursor)
|
|
|
|
|
global.screen.set_cursor(Meta.Cursor.POINTING_HAND);
|
2019-03-10 09:05:38 -03:00
|
|
|
|
2019-03-05 08:36:59 -03:00
|
|
|
// increase OSD display time
|
|
|
|
|
let hideTimeoutSave = OsdWindow.HIDE_TIMEOUT;
|
|
|
|
|
OsdWindow.HIDE_TIMEOUT = 2000;
|
|
|
|
|
Main.osdWindowManager.show(currentIndex, this.enterGicon, _("Press Ctrl + F1 for help") + "\n\n" + _("Entering drawing mode"), null);
|
|
|
|
|
OsdWindow.HIDE_TIMEOUT = hideTimeoutSave;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
showOsd: function(emitter, label, level, maxLevel) {
|
|
|
|
|
let activeIndex = this.areas.indexOf(this.activeArea);
|
|
|
|
|
if (activeIndex != -1)
|
|
|
|
|
Main.osdWindowManager.show(activeIndex, this.enterGicon, label, level, maxLevel);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
removeAreas: function() {
|
|
|
|
|
for (let i = 0; i < this.areas.length; i++) {
|
|
|
|
|
let area = this.areas[i];
|
2019-03-10 11:33:38 -03:00
|
|
|
let container = area.get_parent();
|
|
|
|
|
container.get_parent().remove_actor(container);
|
2019-03-08 08:28:03 -03:00
|
|
|
area.emitter.disconnect(area.emitter.stopDrawingHandler);
|
|
|
|
|
area.emitter.disconnect(area.emitter.showOsdHandler);
|
2019-03-05 08:36:59 -03:00
|
|
|
area.disable();
|
2019-03-10 11:33:38 -03:00
|
|
|
container.destroy();
|
2019-03-05 08:36:59 -03:00
|
|
|
}
|
|
|
|
|
this.areas = [];
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
disable: function() {
|
|
|
|
|
if (this.stylesheetChangedHandler) {
|
|
|
|
|
this.stylesheetMonitor.disconnect(this.stylesheetChangedHandler);
|
|
|
|
|
this.stylesheetChangedHandler = null;
|
|
|
|
|
}
|
2019-03-08 08:28:03 -03:00
|
|
|
if (this.monitorChangedHandler) {
|
|
|
|
|
Main.layoutManager.disconnect(this.monitorChangedHandler);
|
|
|
|
|
this.monitorChangedHandler = null;
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-05 08:36:59 -03:00
|
|
|
if (this.activeArea)
|
|
|
|
|
this.toggleDrawing();
|
|
|
|
|
Main.wm.removeKeybinding('toggle-drawing');
|
|
|
|
|
Main.wm.removeKeybinding('erase-drawing');
|
|
|
|
|
this.removeAreas();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|