├── screenshot.gif
├── schemas
├── gschemas.compiled
└── org.gnome.shell.extensions.turnoffdisplay.gschema.xml
├── locale
├── cs
│ └── LC_MESSAGES
│ │ └── turnoffdisplay.mo
├── de
│ └── LC_MESSAGES
│ │ └── turnoffdisplay.mo
└── en
│ └── LC_MESSAGES
│ └── turnoffdisplay.mo
├── metadata.json
├── turnoffdisplay.pot
├── utils.js
├── en_EN.po
├── css_adjust.js
├── de_DE.po
├── icons
└── disable-display-symbolic.svg
├── xinput_mouse.js
├── extension.js
└── prefs.js
/screenshot.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonthechipmunk/turnoffdisplay/HEAD/screenshot.gif
--------------------------------------------------------------------------------
/schemas/gschemas.compiled:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonthechipmunk/turnoffdisplay/HEAD/schemas/gschemas.compiled
--------------------------------------------------------------------------------
/locale/cs/LC_MESSAGES/turnoffdisplay.mo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonthechipmunk/turnoffdisplay/HEAD/locale/cs/LC_MESSAGES/turnoffdisplay.mo
--------------------------------------------------------------------------------
/locale/de/LC_MESSAGES/turnoffdisplay.mo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonthechipmunk/turnoffdisplay/HEAD/locale/de/LC_MESSAGES/turnoffdisplay.mo
--------------------------------------------------------------------------------
/locale/en/LC_MESSAGES/turnoffdisplay.mo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonthechipmunk/turnoffdisplay/HEAD/locale/en/LC_MESSAGES/turnoffdisplay.mo
--------------------------------------------------------------------------------
/metadata.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "Adds a button to the status menu to turn off the screen.\n\n(requires 'xset' and 'xinput' (xorg). On wayland it instead activates the screen saver. So make sure it is configured appropriately.)",
3 | "name": "Turn off Display",
4 | "settings-schema": "org.gnome.shell.extensions.turnoffdisplay",
5 | "shell-version": [
6 | "3.10",
7 | "3.12",
8 | "3.14",
9 | "3.16",
10 | "3.18",
11 | "3.20",
12 | "3.22",
13 | "3.24",
14 | "3.26",
15 | "3.28",
16 | "3.30"
17 | ],
18 | "url": "https://github.com/simonthechipmunk/turnoffdisplay",
19 | "uuid": "turnoffdisplay@simonthechipmunk.noreply.com",
20 | "gettext-domain": "turnoffdisplay",
21 | "version": 15
22 | }
23 |
--------------------------------------------------------------------------------
/schemas/org.gnome.shell.extensions.turnoffdisplay.gschema.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | true
5 | Round Button
6 | Sets the button to either be a separate item or add it to the shutdown/lock controls
7 |
8 |
9 | false
10 | Handle Mouse
11 | Turns off external mouse pointers when screen is disabled
12 |
13 |
14 | 'auto'
15 | Menu Handling Mode
16 | The mode for handling the main menu width
17 |
18 |
19 | 450
20 | Fixed Menu Width
21 | Fixed width of the aggregated menu
22 |
23 |
24 |
25 | Keyboard Shortcut
26 | Keybinding to turn off the Display
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/turnoffdisplay.pot:
--------------------------------------------------------------------------------
1 | # Translation template for "Turn off Display".
2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
3 | # This file is distributed under the same license as the extension package.
4 | # Simon Junga , 2015.
5 | #
6 | #, fuzzy
7 | msgid ""
8 | msgstr ""
9 | "Project-Id-Version: PACKAGE VERSION\n"
10 | "Report-Msgid-Bugs-To: \n"
11 | "POT-Creation-Date: 2015-10-04 15:08+0200\n"
12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13 | "Last-Translator: FULL NAME \n"
14 | "Language-Team: LANGUAGE \n"
15 | "Language: \n"
16 | "MIME-Version: 1.0\n"
17 | "Content-Type: text/plain; charset=UTF-8\n"
18 | "Content-Transfer-Encoding: 8bit\n"
19 |
20 | #: extension.js:181 extension.js:195
21 | msgid "Display Off"
22 | msgstr ""
23 |
24 | #: prefs.js:84
25 | msgid "Integrate into System Controls (Round Buttons)"
26 | msgstr ""
27 |
28 | #: prefs.js:85
29 | msgid "Adds a round button instead of a separate entry in the Systemmenu"
30 | msgstr ""
31 |
32 | #: prefs.js:88 prefs.js:95 prefs.js:100
33 | msgid "Disable Mouse when Screen is turned Off"
34 | msgstr ""
35 |
36 | #: prefs.js:89
37 | msgid ""
38 | "Automatically disable all external mouse pointers to prevent the screen from "
39 | "turning on accidentally."
40 | msgstr ""
41 |
42 | #: prefs.js:96
43 | msgid "Disabling mouse input automatically is not yet supported with Wayland."
44 | msgstr ""
45 |
46 | #: prefs.js:101
47 | msgid ""
48 | "Disabling mouse input automatically requires Xinput. Please install it and "
49 | "restart Gnome-Shell."
50 | msgstr ""
51 |
52 | #: prefs.js:109
53 | msgid "Menu Width adjustment Mode"
54 | msgstr ""
55 |
56 | #: prefs.js:109
57 | msgid "Select the mode for handling the width of the Main Menu."
58 | msgstr ""
59 |
60 | #: prefs.js:110
61 | msgid "Off"
62 | msgstr ""
63 |
64 | #: prefs.js:110
65 | msgid "Automatic"
66 | msgstr ""
67 |
68 | #: prefs.js:110
69 | msgid "Fixed"
70 | msgstr ""
71 |
72 | #: prefs.js:112
73 | msgid "Fixed menu size in px."
74 | msgstr ""
75 |
76 | #: prefs.js:116
77 | msgid "Custom Keybinding"
78 | msgstr ""
79 |
80 | #: prefs.js:117
81 | msgid ""
82 | "Set a Keybinding to turn off the Display (Examples: F12, space, "
83 | "w)"
84 | msgstr ""
85 |
86 | #: prefs.js:118
87 | msgid "Keybinding is enabled"
88 | msgstr ""
89 |
90 | #: prefs.js:119
91 | msgid "Keybinding is disabled. Set a valid Shortcut to enable it"
92 | msgstr ""
93 |
--------------------------------------------------------------------------------
/utils.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Gnome3 extension utilities
3 | *
4 | * Basic helper functions
5 | *
6 | *
7 | * This program is free software; you can redistribute it and/or modify it
8 | * under the terms of the GNU General Public License as published by the Free
9 | * Software Foundation; either version 2 of the License, or (at your option)
10 | * any later version.
11 | *
12 | */
13 |
14 |
15 | //***// imports:
16 |
17 | // utilities for external programs and command line
18 | const Gio = imports.gi.Gio;
19 |
20 | // translations
21 | const Config = imports.misc.config;
22 | const Gettext = imports.gettext;
23 |
24 | // own imports
25 | const Me = imports.misc.extensionUtils.getCurrentExtension();
26 |
27 |
28 |
29 |
30 | //***// basic helper functions
31 |
32 | /*
33 | * _getSettingsSchema:
34 | * @schema: (optional): the gsettings schema to use
35 | *
36 | * Get the settings Schema for gsettings
37 | * If @schema is not provided, it will be taken from metadata['gsettings-schema']
38 | */
39 | function _getSettingsSchema(setschema) {
40 |
41 | const GioSSS = Gio.SettingsSchemaSource;
42 |
43 | // get the gsettings schema and path
44 | let schema = setschema || Me.metadata['settings-schema'];
45 | let source = GioSSS.new_from_directory(Me.dir.get_child('schemas').get_path(),
46 | GioSSS.get_default(),
47 | false);
48 |
49 |
50 | return new Gio.Settings({
51 | settings_schema : source.lookup(schema, true)
52 | });
53 |
54 | }
55 |
56 |
57 |
58 | /*
59 | * _initTranslations:
60 | * @domain: (optional): the gettext domain to use
61 | *
62 | * Initialize Gettext to load translations from extensionsdir/locale.
63 | * If @domain is not provided, it will be taken from metadata['gettext-domain']
64 | */
65 | function _initTranslations(setdomain) {
66 |
67 | let domain = setdomain || Me.metadata['gettext-domain'];
68 |
69 | // check if this extension was built with "make zip-file", and thus
70 | // has the locale files in a subfolder
71 | // otherwise assume that extension has been installed in the
72 | // same prefix as gnome-shell
73 | let localeDir = Me.dir.get_child('locale');
74 | if (localeDir.query_exists(null)) {
75 | Gettext.bindtextdomain(domain, localeDir.get_path());
76 | }
77 |
78 | else {
79 | Gettext.bindtextdomain(domain, Config.LOCALEDIR);
80 | }
81 |
82 | }
83 |
84 |
85 |
86 |
--------------------------------------------------------------------------------
/en_EN.po:
--------------------------------------------------------------------------------
1 | # Translation template for "Turn off Display".
2 | # Copyright (C) 2015 THE PACKAGE'S COPYRIGHT HOLDER
3 | # This file is distributed under the same license as the extension package.
4 | # Simon Junga , 2015.
5 | #
6 | #, fuzzy
7 | msgid ""
8 | msgstr ""
9 | "Project-Id-Version: PACKAGE VERSION\n"
10 | "Report-Msgid-Bugs-To: \n"
11 | "POT-Creation-Date: 2015-10-04 15:08+0200\n"
12 | "PO-Revision-Date: 2015-03-28 17:48+0100\n"
13 | "Last-Translator: Simon \n"
14 | "Language-Team: English\n"
15 | "Language: en_EN\n"
16 | "MIME-Version: 1.0\n"
17 | "Content-Type: text/plain; charset=UTF-8\n"
18 | "Content-Transfer-Encoding: 8bit\n"
19 | "Plural-Forms: nplurals=2; plural=(n != 1);\n"
20 |
21 | #: extension.js:181 extension.js:195
22 | msgid "Display Off"
23 | msgstr "Display Off"
24 |
25 | #: prefs.js:84
26 | msgid "Integrate into System Controls (Round Buttons)"
27 | msgstr "Integrate into System Controls (Round Buttons)"
28 |
29 | #: prefs.js:85
30 | msgid "Adds a round button instead of a separate entry in the Systemmenu"
31 | msgstr "Adds a round button instead of a separate entry in the Systemmenu"
32 |
33 | #: prefs.js:88 prefs.js:95 prefs.js:100
34 | msgid "Disable Mouse when Screen is turned Off"
35 | msgstr "Disable Mouse when Screen is turned Off"
36 |
37 | #: prefs.js:89
38 | msgid ""
39 | "Automatically disable all external mouse pointers to prevent the screen from "
40 | "turning on accidentally."
41 | msgstr ""
42 | "Automatically disable all external mouse pointers to prevent the screen from "
43 | "turning on accidentally."
44 |
45 | #: prefs.js:96
46 | msgid "Disabling mouse input automatically is not yet supported with Wayland."
47 | msgstr ""
48 |
49 | #: prefs.js:101
50 | msgid ""
51 | "Disabling mouse input automatically requires Xinput. Please install it and "
52 | "restart Gnome-Shell."
53 | msgstr ""
54 |
55 | #: prefs.js:109
56 | msgid "Menu Width adjustment Mode"
57 | msgstr "Menu Width adjustment Mode"
58 |
59 | #: prefs.js:109
60 | msgid "Select the mode for handling the width of the Main Menu."
61 | msgstr "Select the mode for handling the width of the Main Menu."
62 |
63 | #: prefs.js:110
64 | msgid "Off"
65 | msgstr "Off"
66 |
67 | #: prefs.js:110
68 | msgid "Automatic"
69 | msgstr "Automatic"
70 |
71 | #: prefs.js:110
72 | msgid "Fixed"
73 | msgstr "Fixed"
74 |
75 | #: prefs.js:112
76 | msgid "Fixed menu size in px."
77 | msgstr "Fixed menu size in px."
78 |
79 | #: prefs.js:116
80 | msgid "Custom Keybinding"
81 | msgstr "Custom Keybinding"
82 |
83 | #: prefs.js:117
84 | msgid ""
85 | "Set a Keybinding to turn off the Display (Examples: F12, space, "
86 | "w)"
87 | msgstr ""
88 | "Set a Keybinding to turn off the Display (Examples: F12, space, "
89 | "w)"
90 |
91 | #: prefs.js:118
92 | msgid "Keybinding is enabled"
93 | msgstr "Keybinding is enabled"
94 |
95 | #: prefs.js:119
96 | msgid "Keybinding is disabled. Set a valid Shortcut to enable it"
97 | msgstr "Keybinding is disabled. Set a valid Shortcut to enable it"
98 |
--------------------------------------------------------------------------------
/css_adjust.js:
--------------------------------------------------------------------------------
1 | /*
2 | * css_adjust.js
3 | * Gnome3 Turn off Display Extension
4 | *
5 | * Helper for handling automatic or manual adjustment of the aggregate menu to fit all added items in the system area.
6 | *
7 | *
8 | * Author: Simon Junga (simonthechipmunk at gmx.de)
9 | *
10 | * This program is free software; you can redistribute it and/or modify it
11 | * under the terms of the GNU General Public License as published by the Free
12 | * Software Foundation; either version 2 of the License, or (at your option)
13 | * any later version.
14 | *
15 | */
16 |
17 |
18 | //***// imports:
19 |
20 | // main functionality
21 | const Main = imports.ui.main;
22 |
23 |
24 |
25 |
26 | // define global variables
27 | let menuChangedAdd, menuChangedRem;
28 |
29 | let aggregateMenu = Main.panel.statusArea['aggregateMenu'];
30 | let aggregateMenuWidth = aggregateMenu.menu.actor.get_width();
31 |
32 |
33 |
34 | //***// basic functions
35 |
36 | function handle_aggregate_menu(mode, width) {
37 | // set mode
38 |
39 | if(mode == "auto" && !menuChangedAdd && !menuChangedRem) {
40 |
41 |
42 | // monitor changes in the system area
43 | menuChangedAdd = aggregateMenu._system._actionsItem.actor.connect('actor_added', function() {
44 |
45 | checkAggregatemenuwidth();
46 | });
47 |
48 | menuChangedRem = aggregateMenu._system._actionsItem.actor.connect('actor_removed', function() {
49 |
50 | checkAggregatemenuwidth();
51 | });
52 |
53 | // initial menu adjustment
54 | checkAggregatemenuwidth();
55 |
56 | }
57 |
58 |
59 | else if(mode == "fixed" && width >= aggregateMenuWidth) {
60 | // set menu to fixed size
61 | disconnect_all();
62 | aggregateMenu.menu.actor.set_width(width);
63 | }
64 |
65 |
66 | else if(mode == "off") {
67 | // reset menu to original size
68 | disconnect_all();
69 | aggregateMenu.menu.actor.set_width(aggregateMenuWidth);
70 | }
71 |
72 |
73 | }
74 |
75 |
76 |
77 |
78 |
79 | function checkAggregatemenuwidth() {
80 | // run menu width adjustment if necessary
81 |
82 |
83 | let actionChildren = aggregateMenu._system._actionsItem.actor.get_children();
84 | let allButtonWidth = actionChildren[1].get_width()*2;
85 |
86 | //calculate new width
87 | for (let button of actionChildren) {
88 | allButtonWidth += button.get_width();
89 | }
90 |
91 | // change the menu width
92 | if(aggregateMenuWidth < allButtonWidth){
93 | aggregateMenu.menu.actor.set_width(allButtonWidth);
94 | }
95 | else if (aggregateMenu.menu.actor.get_width() != aggregateMenuWidth){
96 | aggregateMenu.menu.actor.set_width(aggregateMenuWidth);
97 | }
98 |
99 | }
100 |
101 |
102 |
103 |
104 |
105 | function disconnect_all() {
106 | // disconnect from active signals
107 |
108 | if(menuChangedAdd) {
109 | aggregateMenu.menu.actor.disconnect(menuChangedAdd);
110 | menuChangedAdd = null;
111 | }
112 |
113 | if(menuChangedRem) {
114 | aggregateMenu.menu.actor.disconnect(menuChangedRem);
115 | menuChangedRem = null;
116 | }
117 | }
118 |
119 |
--------------------------------------------------------------------------------
/de_DE.po:
--------------------------------------------------------------------------------
1 | # Translation template for "Turn off Display".
2 | # Copyright (C) 2015 THE PACKAGE'S COPYRIGHT HOLDER
3 | # This file is distributed under the same license as the extension package.
4 | # Simon Junga , 2015.
5 | #
6 | #, fuzzy
7 | msgid ""
8 | msgstr ""
9 | "Project-Id-Version: PACKAGE VERSION\n"
10 | "Report-Msgid-Bugs-To: \n"
11 | "POT-Creation-Date: 2015-10-04 15:08+0200\n"
12 | "PO-Revision-Date: 2015-03-28 17:48+0100\n"
13 | "Last-Translator: Simon \n"
14 | "Language-Team: German\n"
15 | "Language: de_DE\n"
16 | "MIME-Version: 1.0\n"
17 | "Content-Type: text/plain; charset=UTF-8\n"
18 | "Content-Transfer-Encoding: 8bit\n"
19 | "Plural-Forms: nplurals=2; plural=(n != 1);\n"
20 |
21 | #: extension.js:181 extension.js:195
22 | msgid "Display Off"
23 | msgstr "Bildschirm Aus"
24 |
25 | #: prefs.js:84
26 | msgid "Integrate into System Controls (Round Buttons)"
27 | msgstr "Im Systembereich anzeigen (Runde Schaltflächen)"
28 |
29 | #: prefs.js:85
30 | msgid "Adds a round button instead of a separate entry in the Systemmenu"
31 | msgstr "Erstellt eine runde Schaltfläche anstatt eines separaten Menüeintrags"
32 |
33 | #: prefs.js:88 prefs.js:95 prefs.js:100
34 | msgid "Disable Mouse when Screen is turned Off"
35 | msgstr "Maus deaktivieren wenn der Bildschirm aus ist"
36 |
37 | #: prefs.js:89
38 | msgid ""
39 | "Automatically disable all external mouse pointers to prevent the screen from "
40 | "turning on accidentally."
41 | msgstr ""
42 | "Automatisch alle angeschlossenen Zeigegeräte (Mäuse) deaktivieren um ein "
43 | "versehentliches Einschalten des Bildschirms zu verhindern."
44 |
45 | #: prefs.js:96
46 | msgid "Disabling mouse input automatically is not yet supported with Wayland."
47 | msgstr "Automatisches Abschalten angeschlossener Zeigegeräte (Mäuse) wird unter Wayland zur Zeit nicht unterstützt."
48 |
49 | #: prefs.js:101
50 | msgid ""
51 | "Disabling mouse input automatically requires Xinput. Please install it and "
52 | "restart Gnome-Shell."
53 | msgstr "Zum automatischen Abschalten angeschlossener Zeigegeräte (Mäuse) wird Xinput benötigt. Bitte installieren Sie es und starten Gnome-Shell neu."
54 |
55 | #: prefs.js:109
56 | msgid "Menu Width adjustment Mode"
57 | msgstr "Anpassung der Menübreite"
58 |
59 | #: prefs.js:109
60 | msgid "Select the mode for handling the width of the Main Menu."
61 | msgstr "Modusauswahl zur Breitenanpassung des Hauptmenüs."
62 |
63 | #: prefs.js:110
64 | msgid "Off"
65 | msgstr "Aus"
66 |
67 | #: prefs.js:110
68 | msgid "Automatic"
69 | msgstr "Automatisch"
70 |
71 | #: prefs.js:110
72 | msgid "Fixed"
73 | msgstr "Manuell"
74 |
75 | #: prefs.js:112
76 | msgid "Fixed menu size in px."
77 | msgstr "Feste Menübreite in px."
78 |
79 | #: prefs.js:116
80 | msgid "Custom Keybinding"
81 | msgstr "Eigene Tastenkombination"
82 |
83 | #: prefs.js:117
84 | msgid ""
85 | "Set a Keybinding to turn off the Display (Examples: F12, space, "
86 | "w)"
87 | msgstr ""
88 | "Tastenkürzel um den Bildschirm auszuschalten (Beispiele: F12, space, "
89 | "w)"
90 |
91 | #: prefs.js:118
92 | msgid "Keybinding is enabled"
93 | msgstr "Tastenkürzel ist aktiv"
94 |
95 | #: prefs.js:119
96 | msgid "Keybinding is disabled. Set a valid Shortcut to enable it"
97 | msgstr ""
98 | "Tastenkürzel ist inaktiv. Zum Aktivieren gültige Tastenkombination eingeben"
99 |
--------------------------------------------------------------------------------
/icons/disable-display-symbolic.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
78 |
--------------------------------------------------------------------------------
/xinput_mouse.js:
--------------------------------------------------------------------------------
1 | /*
2 | * xinput_mouse.js
3 | * Gnome3 Turn off Display Extension
4 | *
5 | * Helper for Xinput to detect and disable mouse input devices. Adapted from Touchpad Indicator by https://extensions.gnome.org/accounts/profile/orangeshirt
6 | *
7 | *
8 | * Author: Simon Junga (simonthechipmunk at gmx.de)
9 | * Original Author: Armin Köhler (orangeshirt at web.de>)
10 | *
11 | * This program is free software; you can redistribute it and/or modify it
12 | * under the terms of the GNU General Public License as published by the Free
13 | * Software Foundation; either version 2 of the License, or (at your option)
14 | * any later version.
15 | *
16 | */
17 |
18 |
19 | //***// imports:
20 |
21 | // utilities for external programs and command line
22 | const GLib = imports.gi.GLib;
23 |
24 |
25 |
26 |
27 | // define global variables
28 | let xinput_is_installed = xinput_installed();
29 |
30 | const exclude_devices = new Array('touchpad','glidepoint','fingersensingpad', 'bcm5974','trackpad','smartpad',
31 | 'trackpoint','accu point','trackstick', 'touchstyk','pointing stick','dualpoint stick',
32 | 'touchscreen', 'maxtouch', 'touch',
33 | 'pen stylus', 'pen eraser');
34 |
35 |
36 |
37 |
38 | //***// basic functions
39 |
40 | function get_pointer_ids() {
41 | // get all IDs for devices that match the property "pointing device"
42 | let pointerIDs = new Array();
43 | let lines = execute_sync('xinput --list');
44 | if (lines) {
45 | lines = lines[1].toString().split('\n');
46 | let y = 0;
47 | for (let line = 0; line < lines.length; line++) {
48 | if ((lines[line].indexOf('slave pointer') != -1) && (lines[line].indexOf('XTEST') == -1)) {
49 | pointerIDs[y] = lines[line].toString().split('=')[1].split('[')[0].split('\t')[0];
50 | y++;
51 | }
52 | }
53 | }
54 | return pointerIDs;
55 |
56 | }
57 |
58 |
59 |
60 |
61 |
62 | function get_mouse_ids() {
63 | // get all IDs for devices that match the property "pointing device" and are not listed in exclude_devices
64 | let mouseIDs = new Array();
65 | let lines = execute_sync('xinput --list');
66 | if (lines) {
67 | lines = lines[1].toString().split('\n');
68 | let y = 0;
69 | for (let line = 0; line < lines.length; line++) {
70 | if ((lines[line].indexOf('slave pointer') !=- 1) && (lines[line].indexOf('XTEST') == -1)) {
71 | // check for devices on exclude list
72 | let checkOK = 1;
73 | for (let check = 0; check < exclude_devices.length; check++) {
74 | if ((lines[line].toLowerCase().indexOf(exclude_devices[check].toString().toLowerCase()) ) != -1) {
75 | checkOK = 0;
76 | }
77 | }
78 |
79 | if(checkOK) {
80 | mouseIDs[y] = lines[line].toString().split('=')[1].split('[')[0].split('\t')[0];
81 | y++;
82 | }
83 | }
84 | }
85 | }
86 | return mouseIDs;
87 |
88 | }
89 |
90 |
91 |
92 |
93 |
94 | function switch_devices(mode, deviceIDs) {
95 | // enable/disable devices by ID
96 | for (let device of deviceIDs) {
97 | if(mode == "on") {
98 | execute_sync('xinput --enable ' + device);
99 | }
100 |
101 | else if(mode == "off") {
102 | execute_sync('xinput --disable ' + device);
103 | }
104 | }
105 |
106 | }
107 |
108 |
109 |
110 |
111 | function execute_sync(command) {
112 | //run a command on the command line
113 | try {
114 | return GLib.spawn_command_line_sync(command);
115 | }
116 | catch (err) {
117 | return false;
118 | }
119 | }
120 |
121 |
122 |
123 |
124 | function xinput_installed(){
125 | //check if xinput is present
126 | if(execute_sync('xinput --list')){
127 | return true;
128 | }
129 | return false;
130 | }
131 |
132 |
--------------------------------------------------------------------------------
/extension.js:
--------------------------------------------------------------------------------
1 | /*
2 | * extension.js
3 | * Gnome3 Turn off Display Extension
4 | *
5 | * Adds a button to the status menu to turn off the screen. This extension is here to continue "Blank Screen" by l300lvl which is updated to GS3.6
6 | * https://extensions.gnome.org/extension/242/blank-screen/ *** https://github.com/l300lvl/Blank-Screen-Extension
7 | *
8 | *
9 | * Author: Simon Junga (simonthechipmunk at gmx.de)
10 | * Original Author: l300lvl
11 | *
12 | * This program is free software; you can redistribute it and/or modify it
13 | * under the terms of the GNU General Public License as published by the Free
14 | * Software Foundation; either version 2 of the License, or (at your option)
15 | * any later version.
16 | *
17 | */
18 |
19 |
20 | //***// imports:
21 |
22 | // icons and labels
23 | const St = imports.gi.St;
24 |
25 | // main functionality
26 | const Main = imports.ui.main;
27 | const Meta = imports.gi.Meta;
28 | const Shell = imports.gi.Shell;
29 | const Mainloop = imports.mainloop;
30 |
31 | // menu items
32 | const PopupMenu = imports.ui.popupMenu;
33 |
34 | // utilities for external programs and command line
35 | const Config = imports.misc.config;
36 | const ShellVersion = Config.PACKAGE_VERSION.split('.');
37 | const Util = imports.misc.util;
38 | const GLib = imports.gi.GLib;
39 |
40 | // clutter and Gtk
41 | const Gtk = imports.gi.Gtk;
42 |
43 | // translations
44 | const Gettext = imports.gettext.domain('turnoffdisplay');
45 | const _ = Gettext.gettext;
46 |
47 | // own imports
48 | const Me = imports.misc.extensionUtils.getCurrentExtension();
49 | const Prefs = Me.imports.prefs;
50 | const Utils = Me.imports.utils;
51 | const CSSadjust = Me.imports.css_adjust;
52 | const Xinput = Me.imports.xinput_mouse;
53 | const Settings = Utils._getSettingsSchema();
54 |
55 |
56 |
57 |
58 | // define global variables
59 | let menuitem, button, systemMenu, menuSettings, keybindSettings, handlemenumodeSettings, fixmenuwidthSettings;
60 | let eventKeybind=null;
61 | let eventXsetwatch=null;
62 | let eventStartup=null;
63 |
64 |
65 |
66 | //***// basic extension functions
67 |
68 | function init() {
69 | // initialize preferences
70 | Prefs.init();
71 |
72 | // get extension icons
73 | Gtk.IconTheme.get_default().append_search_path(Me.dir.get_child('icons').get_path());
74 | }
75 |
76 |
77 |
78 |
79 | function enable() {
80 |
81 | // create the menu entry
82 | _MenuEntry(true);
83 |
84 | // set keybinding
85 | _SetKeybinding(true);
86 |
87 | // start menu width adjustment
88 | CSSadjust.handle_aggregate_menu(Prefs._getHandleMenuMode(), Prefs._getFixMenuWidth() );
89 |
90 |
91 |
92 | // TODO:BUG something is really screwed up here... the get_width() method of any system-area button will return wrong values until
93 | // the shell is running for at least a few seconds. For now calling the adjustment method 5 seconds into operation is the only thing
94 | // that actually helps. Since I'm already 2 weeks late for the 3.20 release because of that this shit is now going upstream...*sigh*
95 | //eventStartup = GLib.idle_add(GLib.PRIORITY_LOW, function() {
96 | eventStartup = GLib.timeout_add(0, 5000, function() {
97 |
98 | if(Prefs._getHandleMenuMode() == "auto" && ShellVersion[1] <= 16) CSSadjust.checkAggregatemenuwidth();
99 | return false;
100 | });
101 |
102 |
103 | // connect to signals "preference changed"
104 | menuSettings = Settings.connect('changed::integrate', function() {
105 | _MenuEntry(false);
106 | _MenuEntry(true);
107 | });
108 |
109 | keybindSettings = Settings.connect('changed::turnoffdisplay-keybinding', function() {
110 | _SetKeybinding(false);
111 | _SetKeybinding(true);
112 | });
113 |
114 | handlemenumodeSettings = Settings.connect('changed::handlemenumode', function() {
115 | CSSadjust.handle_aggregate_menu(Prefs._getHandleMenuMode(), Prefs._getFixMenuWidth() );
116 | });
117 |
118 | fixmenuwidthSettings = Settings.connect('changed::fixmenuwidth', function() {
119 | if(Prefs._getHandleMenuMode() == "fixed") {
120 | CSSadjust.handle_aggregate_menu("fixed", Prefs._getFixMenuWidth() );
121 | }
122 | });
123 |
124 | }
125 |
126 |
127 |
128 |
129 | function disable() {
130 | // disable the menu entry
131 | _MenuEntry(false);
132 |
133 | // remove keybinding
134 | _SetKeybinding(false);
135 |
136 | // disconnect from signals "preference changed"
137 | Settings.disconnect(menuSettings);
138 | Settings.disconnect(keybindSettings);
139 | Settings.disconnect(handlemenumodeSettings);
140 | Settings.disconnect(fixmenuwidthSettings);
141 |
142 | // remove timer event
143 | if(eventKeybind) {
144 | Mainloop.source_remove(eventKeybind);
145 | }
146 |
147 | if(eventXsetwatch) {
148 | Mainloop.source_remove(eventXsetwatch);
149 | }
150 |
151 | if(eventStartup) {
152 | Mainloop.source_remove(eventStartup);
153 | }
154 |
155 | // disable menu width adjustment
156 | CSSadjust.handle_aggregate_menu("off");
157 |
158 | }
159 |
160 |
161 |
162 |
163 |
164 |
165 | //***// extension functions
166 |
167 | function _MenuEntry(set) {
168 | // create/destroy the menu entry
169 |
170 | // enable the entry
171 | if(set) {
172 |
173 | // create the menu entry according to preference settings
174 | if(!Prefs._getIntegrate()) {
175 |
176 | systemMenu = Main.panel.statusArea['aggregateMenu'];
177 |
178 | // create separate menu button
179 | menuitem = new PopupMenu.PopupBaseMenuItem({ activate: true });
180 | let icon = new St.Icon({ icon_name: 'disable-display-symbolic', style_class: 'popup-menu-icon' });
181 | let text = new St.Label({ text: _("Display Off"), style_class: "sm-label" });
182 | menuitem.actor.add(icon);
183 | menuitem.actor.add(text);
184 | menuitem.connect('activate', _DisplayOff);
185 | // add the menuentry to the menu
186 | systemMenu.menu.addMenuItem(menuitem, 0);
187 |
188 | }
189 |
190 | else {
191 |
192 | systemMenu = Main.panel.statusArea['aggregateMenu']._system;
193 |
194 | // create round button in system control area
195 | button = systemMenu._createActionButton('disable-display-symbolic', _("Display Off"));
196 | button.connect('clicked', _DisplayOff);
197 | // add the menuentry to the menu
198 | //systemMenu._actionsItem.actor.insert_child_at_index(button, 4);
199 | systemMenu._actionsItem.actor.add(button, { expand: true, x_fill: false });
200 | }
201 |
202 | }
203 |
204 |
205 | // disable the entry
206 | else {
207 |
208 | if(menuitem) {
209 | // remove the menuitem
210 | menuitem.destroy();
211 | }
212 |
213 | else {
214 |
215 | // remove the button
216 | systemMenu._actionsItem.actor.remove_child(button);
217 | }
218 |
219 | // reset menuitem/button variable
220 | menuitem = null;
221 | button = null;
222 |
223 | }
224 |
225 | }
226 |
227 |
228 |
229 |
230 |
231 |
232 | function _DisplayOff() {
233 | // turn off the display
234 |
235 | //close the menu
236 | systemMenu.menu.itemActivated();
237 | if (GLib.getenv('XDG_SESSION_TYPE') == 'wayland') {
238 | _DisplayOffWayland();
239 | } else {
240 | _DisplayOffXWindows();
241 |
242 | // disable external mice if set in the preferences
243 | if(Prefs._getHandleMouse() && Xinput.xinput_is_installed) {
244 | disable_mouse();
245 | }
246 | }
247 |
248 | }
249 |
250 | function _DisplayOffXWindows() {
251 | //use xset to disable the screen
252 | Util.spawn(['xset','dpms','force','off']);
253 | }
254 |
255 | function _DisplayOffWayland() {
256 | Util.spawn(['dbus-send', '--session', '--dest=org.gnome.ScreenSaver',
257 | '--type=method_call', '/org/gnome/ScreenSaver',
258 | 'org.gnome.ScreenSaver.SetActive', 'boolean:true']);
259 | }
260 |
261 |
262 |
263 |
264 |
265 |
266 | function _SetKeybinding(set) {
267 | // enable keybinding to turn off the display
268 |
269 | if (Prefs._getKeybinding() != "" && set) {
270 |
271 | // Shell version management
272 | let mode;
273 |
274 | if (ShellVersion[1] <= 14 ) {
275 | mode = Shell.KeyBindingMode.NORMAL;
276 | }
277 | else{
278 | mode = Shell.ActionMode.NORMAL;
279 | }
280 |
281 |
282 | Main.wm.addKeybinding('turnoffdisplay-keybinding', Settings, Meta.KeyBindingFlags.NONE, mode, function() {
283 | // turn off display after 500ms (workaround! - needs something like 'key-release-event')
284 | eventKeybind = GLib.timeout_add(0, 500, _DisplayOff);
285 | }, null, null);
286 |
287 | }
288 |
289 | else {
290 | Main.wm.removeKeybinding('turnoffdisplay-keybinding');
291 | }
292 |
293 | }
294 |
295 |
296 |
297 |
298 |
299 | function disable_mouse() {
300 | // disable mouse pointers and watch for display revoke
301 |
302 | let mousepointerIDs = Xinput.get_mouse_ids();
303 | Xinput.switch_devices("off", mousepointerIDs);
304 |
305 | // check monitor status periodically
306 | eventXsetwatch = GLib.timeout_add(0, 500, function() {
307 |
308 | let lines = GLib.spawn_command_line_sync('xset -q');
309 | if (lines) {
310 |
311 | // check for "Monitor is On"
312 | lines = lines.toString();
313 | if (lines.indexOf('Monitor is On') != -1) {
314 | Xinput.switch_devices("on", mousepointerIDs);
315 | return false;
316 | }
317 | }
318 |
319 | return true;
320 |
321 | });
322 |
323 | }
324 |
325 |
--------------------------------------------------------------------------------
/prefs.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Preferences for the extension which will be available in the
3 | * "gnome-shell-extension-prefs" tool.
4 | *
5 | *
6 | * see: https://live.gnome.org/GnomeShell/Extensions#Extension_Preferences
7 | *
8 | */
9 |
10 | //***// imports:
11 |
12 | // main
13 | const Gio = imports.gi.Gio;
14 | const Gtk = imports.gi.Gtk;
15 | const Lang = imports.lang;
16 |
17 | // utilities for external programs and command line
18 | const GLib = imports.gi.GLib;
19 |
20 | // translations
21 | const Gettext = imports.gettext.domain('turnoffdisplay');
22 | const _ = Gettext.gettext;
23 |
24 | // own imports
25 | const Me = imports.misc.extensionUtils.getCurrentExtension();
26 | const Utils = Me.imports.utils;
27 | const Xinput = Me.imports.xinput_mouse;
28 |
29 |
30 |
31 |
32 | // define global variables
33 | let settings = {};
34 |
35 |
36 |
37 |
38 |
39 | //***// basic preferences functions
40 |
41 | function init() {
42 |
43 | // init translations
44 | Utils._initTranslations();
45 |
46 | // load the settings schema
47 | settings = Utils._getSettingsSchema();
48 |
49 | // create custom command bindings for gsettings "bool", "string", "stringarray" and "int"
50 | let set_boolean = Lang.bind(settings, settings.set_boolean);
51 | let set_string = Lang.bind(settings, settings.set_string);
52 | let set_strv = Lang.bind(settings, settings.set_strv);
53 | let set_int = Lang.bind(settings, settings.set_int);
54 |
55 | settings.set_boolean = function(key, value) {
56 | set_boolean(key, value);
57 | Gio.Settings.sync();
58 | };
59 |
60 | settings.set_string = function(key, value) {
61 | set_string(key, value);
62 | Gio.Settings.sync();
63 | };
64 |
65 | settings.set_strv = function(key, value) {
66 | set_strv(key, value);
67 | Gio.Settings.sync();
68 | };
69 |
70 | settings.set_int = function(key, value) {
71 | set_int(key, value);
72 | Gio.Settings.sync();
73 | };
74 |
75 | }
76 |
77 |
78 |
79 | function buildPrefsWidget() {
80 | // build the Gtk preferences widget
81 | let frame = new Gtk.Box({orientation: Gtk.Orientation.VERTICAL, border_width: 10, margin: 20});
82 |
83 | // add items to the widget frame
84 | frame.add( _createSwitchbox( _("Integrate into System Controls (Round Buttons)"),
85 | _("Adds a round button instead of a separate entry in the Systemmenu"), _getIntegrate, _setIntegrate ));
86 |
87 | let box;
88 | let text = _("Disable Mouse when Screen is turned Off");
89 | let tooltip = _("Automatically disable all external mouse pointers to prevent the screen from turning on accidentally.");
90 | let sensitive = true;
91 |
92 |
93 |
94 | if(GLib.getenv('XDG_SESSION_TYPE') == 'wayland'){
95 | text = _("Disable Mouse when Screen is turned Off");
96 | tooltip = _("Disabling mouse input automatically is not yet supported with Wayland.");
97 | sensitive = false;
98 | }
99 | else if(!Xinput.xinput_is_installed){
100 | text = _("Disable Mouse when Screen is turned Off");
101 | tooltip = _("Disabling mouse input automatically requires Xinput. Please install it and restart Gnome-Shell.");
102 | sensitive = false;
103 | }
104 |
105 | box = _createSwitchbox( text, tooltip, _getHandleMouse, _setHandleMouse );
106 | box.set_sensitive(sensitive);
107 | frame.add(box);
108 |
109 | frame.add( _createComboBox( _("Menu Width adjustment Mode"), _("Select the mode for handling the width of the Main Menu."),
110 | {'off': _("Off"), 'auto' : _("Automatic"), 'fixed' : _("Fixed")}, _getHandleMenuMode, _setHandleMenuMode ));
111 |
112 | frame.add( _createAdjustBox( "", _("Fixed menu size in px."),
113 | 360.0, 1200.0, 1.0, _getFixMenuWidth, _setFixMenuWidth ));
114 |
115 |
116 | frame.add( _createKeybindbox( _("Custom Keybinding"),
117 | _("Set a Keybinding to turn off the Display (Examples: F12, space, w)"),
118 | "emblem-ok-symbolic", _("Keybinding is enabled"),
119 | "window-close-symbolic", _("Keybinding is disabled. Set a valid Shortcut to enable it"), _getKeybinding, _setKeybinding ));
120 | frame.show_all();
121 | return frame;
122 | }
123 |
124 |
125 |
126 |
127 |
128 |
129 | //***// preferences functions
130 |
131 | function _createSwitchbox(text, tooltip, getFunction, setFunction) {
132 | // create box with toggle switch
133 | let box = new Gtk.Box({ orientation: Gtk.Orientation.HORIZONTAL, margin: 5});
134 | let label = new Gtk.Label({ label: text, xalign: 0, tooltip_text: tooltip });
135 | let toggleswitch = new Gtk.Switch({ active: getFunction(), tooltip_text: tooltip });
136 |
137 | // connect to "toggled" emit signal
138 | toggleswitch.connect('notify::active', setFunction);
139 |
140 | //fill the box with content
141 | box.pack_start(label, true, true, 0);
142 | box.add(toggleswitch);
143 |
144 | return box;
145 | }
146 |
147 |
148 |
149 |
150 | function _createComboBox(text, tooltip, values, getFunction, setFunction) {
151 | // create box with combo selection field
152 | let box = new Gtk.Box({ orientation: Gtk.Orientation.HORIZONTAL, margin: 5});
153 | let label = new Gtk.Label({ label: text, xalign: 0, tooltip_text: tooltip });
154 | let widget = new Gtk.ComboBoxText({ tooltip_text: tooltip });
155 | for (id in values) {
156 | widget.append(id, values[id]);
157 | }
158 | widget.set_active_id(getFunction());
159 |
160 | // connect to "changed" emit signal
161 | widget.connect('changed', function(combo_widget) {
162 | setFunction(combo_widget.get_active_id());
163 | });
164 | //fill the box with content
165 | box.pack_start(label, true, true, 0);
166 | box.add(widget);
167 | return box;
168 | }
169 |
170 |
171 |
172 |
173 | function _createAdjustBox(text, tooltip, LOWER, UPPER, INCREM, getFunction, setFunction) {
174 | // create box with adjust selection field
175 | let box = new Gtk.Box({ orientation: Gtk.Orientation.HORIZONTAL, margin: 5});
176 | let label = new Gtk.Label({ label: text, xalign: 0, tooltip_text: tooltip });
177 | let adjustbox = new Gtk.Adjustment({ lower: LOWER, step_increment: INCREM, upper: UPPER, value: 1.0 });
178 | let spinbutton = new Gtk.SpinButton({ adjustment: adjustbox, digits: 0, tooltip_text: tooltip});
179 | spinbutton.set_value(getFunction() );
180 |
181 | // toggle sensitive property
182 | if(_getHandleMenuMode() != "fixed") { box.sensitive = false; }
183 | let sensitive = settings.connect('changed::handlemenumode', function() {
184 | if(_getHandleMenuMode() == "fixed") {
185 | box.sensitive = true;
186 | }
187 | else {
188 | box.sensitive = false;
189 | }
190 | });
191 |
192 | // connect to "value-changed" emit signal
193 | spinbutton.connect('value_changed', function() {
194 | setFunction(spinbutton.value);
195 | });
196 | //fill the box with content
197 | box.pack_start(label, true, true, 0);
198 | box.add(spinbutton, true, true, 5);
199 |
200 | return box;
201 | }
202 |
203 |
204 |
205 |
206 | function _createKeybindbox(text, tooltip, secIconOK, secIcontooltipOK, secIconNOK, secIcontooltipNOK, getFunction, setFunction) {
207 | // create box with keybinding entry
208 | let box = new Gtk.Box({ orientation: Gtk.Orientation.HORIZONTAL, margin: 5});
209 | let label = new Gtk.Label({ label: text, xalign: 0, tooltip_text: tooltip });
210 | let textbox = new Gtk.Entry({ text : getFunction(), tooltip_text: tooltip });
211 | updateTextbox();
212 | // connect to "text-changed" emit signal and check for valid keybinding
213 | textbox.connect('changed', function() { updateTextbox(); });
214 |
215 | function updateTextbox(){
216 | let [key, mods] = Gtk.accelerator_parse(textbox.get_text());
217 |
218 | if(Gtk.accelerator_valid(key, mods)) {
219 | textbox["secondary-icon-name"] = secIconOK;
220 | textbox["secondary-icon-tooltip-text"] = secIcontooltipOK;
221 | let shortcut = Gtk.accelerator_name(key, mods);
222 | _setKeybinding(shortcut);
223 | }
224 |
225 | else {
226 | textbox["secondary-icon-name"] = secIconNOK;
227 | textbox["secondary-icon-tooltip-text"] = secIcontooltipNOK;
228 | setFunction("");
229 | }
230 | }
231 |
232 |
233 | //fill the box with content
234 | box.pack_start(label, true, true, 0);
235 | box.add(textbox, true, true, 5);
236 |
237 | return box;
238 | }
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 | // functions to get/set gsettings entries
247 | function _getIntegrate() {
248 | return settings.get_boolean('integrate');
249 | }
250 |
251 | function _setIntegrate() {
252 | settings.set_boolean('integrate', !_getIntegrate());
253 | }
254 |
255 |
256 | function _getHandleMouse() {
257 | return settings.get_boolean('handlemouse');
258 | }
259 |
260 | function _setHandleMouse() {
261 | settings.set_boolean('handlemouse', !_getHandleMouse());
262 | }
263 |
264 |
265 | function _getHandleMenuMode() {
266 | return settings.get_string('handlemenumode');
267 | }
268 |
269 | function _setHandleMenuMode(command) {
270 | settings.set_string('handlemenumode', command);
271 | }
272 |
273 |
274 | function _getFixMenuWidth() {
275 | return settings.get_int('fixmenuwidth');
276 | }
277 |
278 | function _setFixMenuWidth(command) {
279 | settings.set_int('fixmenuwidth', command);
280 | }
281 |
282 |
283 | function _getKeybinding() {
284 | return settings.get_strv('turnoffdisplay-keybinding')[0];
285 | }
286 |
287 | function _setKeybinding(command) {
288 | settings.set_strv('turnoffdisplay-keybinding', [command]);
289 | }
290 |
291 |
--------------------------------------------------------------------------------