Skip to content
This repository was archived by the owner on Dec 26, 2023. It is now read-only.

Commit

Permalink
[T] gtk3 gui based on gobject --> removed yad/zenity dependency
Browse files Browse the repository at this point in the history
  • Loading branch information
Nico Rittstieg committed Jan 3, 2019
1 parent ffa2d18 commit 8121976
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 96 deletions.
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ Dependencies:
- wmctrl (https://sites.google.com/site/tstyblo/wmctrl/)
- xwininfo (for getting window geometry and extents)
- xdotool (for hiding windows)
- Python 3
- Python 3.7
- python-setuptools
- zenity, yad (for gtk dialogs)
- python-gobject
- gtk3

Compatibility:
--------------------------
Expand Down Expand Up @@ -131,6 +132,7 @@ Profile files are stored in '~/.config/savedesktop'
"y": 219,
"width": 1094,
"height": 599,
"timeout": 5,
"cmd": [
"nemo"
],
Expand All @@ -144,7 +146,7 @@ The following state properties are supported:
- maximized_horz
- shaded
- hidden
- fullscreen.
- fullscreen

Project Web site:
--------------------
Expand Down
26 changes: 0 additions & 26 deletions savedesktop/check.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,6 @@ def check_dependencies(args: argparse.Namespace):
if args.gui:
gui.show_error("xdotool is not installed")
exit(-1)
if args.gui and not check_yad_installation():
print("yad is not installed", file=sys.stderr)
if args.gui:
gui.show_error("yad is not installed")
exit(-1)
if args.gui and not check_zenity_installation():
print("zenity is not installed", file=sys.stderr)
if args.gui:
gui.show_error("zenity is not installed")
exit(-1)


def check_wmctrl_installation():
Expand All @@ -78,22 +68,6 @@ def check_xdotool_installation():
return False


def check_zenity_installation():
try:
subprocess.call(["zenity", "--version"], stdout=subprocess.DEVNULL)
return True
except FileNotFoundError as e:
return False


def check_yad_installation():
try:
subprocess.call(["yad", "--version"], stdout=subprocess.DEVNULL)
return True
except FileNotFoundError as e:
return False


def check_desktop(args: argparse.Namespace, desktop_count: int):
if args.desktop is not None:
if args.desktop < 0 or args.desktop >= desktop_count:
Expand Down
193 changes: 133 additions & 60 deletions savedesktop/gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,82 +18,155 @@
# You should have received a copy of the GNU General Public License along with this program.
# If not, see <http://www.gnu.org/licenses/>.

import gi

gi.require_version('Gtk', '3.0')
import argparse
import subprocess
import time
from typing import List
from gi.repository import Gtk


def show_error(msg: str):
subprocess.check_output(["zenity",
"--error",
"--title=Save Virtual Desktop",
"--width=600",
"--text={}".format(msg)])
dialog = Gtk.MessageDialog(None,
0,
Gtk.MessageType.ERROR,
Gtk.ButtonsType.CLOSE,
"An error has occurred")
dialog.format_secondary_text(msg)
dialog.set_title("Save/Restore Virtual Desktop")
dialog.set_default_size(500, 160)
dialog.run()
dialog.destroy()


def show_save_desktop(args: argparse.Namespace, desktop_list: List[str], profile_list: List[str]):
if len(profile_list) == 0:
profile_list.append("default")
if args.profile not in profile_list:
profile_list.insert(0, args.profile)
else:
for i in range(len(profile_list)):
if profile_list[i] == args.profile:
profile_list[i] = "^{}".format(args.profile)
break
if args.desktop is not None:
desktop_list[args.desktop] = "^{}".format(desktop_list[args.desktop])
try:
output = subprocess.check_output(["yad",
"--width=300",
"--form",
"--title=Save Virtual Desktop",
"--field=Desktop:CB",
"!".join(desktop_list),
"--field=Profile:CBE",
"!".join(profile_list),
"--field=Open JSON file:CHK",
"TRUE" if args.open else "FALSE",
],
stderr=subprocess.STDOUT)
except subprocess.CalledProcessError:
# Return Code 1 -> The user has pressed Cancel button

dialog = SaveDialog(args.desktop, desktop_list, args.profile, profile_list)
response = dialog.run()

if response != Gtk.ResponseType.OK:
dialog.destroy()
exit(0)
# parse yad output : b'0 - Workspace 1|default|TRUE|\n'
values = str(output)[2:-4].split("|")
args.desktop = int(values[0][0])
args.profile = values[1].strip()

args.desktop = dialog.desktop_combo.get_active()
args.profile = dialog.profile_combo.get_active_text().strip()
if len(args.profile) == 0:
args.profile = "default"
args.open = "TRUE" == values[2]
# avoid wmctrl timing probs
time.sleep(.100)
args.open = dialog.open_checkbox.get_active()

dialog.destroy()


def show_restore_desktop(args: argparse.Namespace, desktop_list: List[str], profile_list: List[str]):
for i in range(len(profile_list)):
if profile_list[i] == args.profile:
profile_list[i] = "^{}".format(args.profile)
break
desktop_list[args.desktop] = "^{}".format(desktop_list[args.desktop])
try:
output = subprocess.check_output(["yad",
"--width=300",
"--form",
"--title=Restore Virtual Desktop",
"--field=Desktop:CB",
"!".join(desktop_list),
"--field=Profile:CB",
"!".join(profile_list),
],
stderr=subprocess.STDOUT)
except subprocess.CalledProcessError:
# Return Code 1 -> The user has pressed Cancel button
dialog = RestoreDialog(args.desktop, desktop_list, args.profile, profile_list)
response = dialog.run()

if response != Gtk.ResponseType.OK:
dialog.destroy()
exit(0)
# parse yad output : b'0 - Workspace 1|default|\n'
values = str(output)[2:-4].split("|")
args.desktop = int(values[0][0])
args.profile = values[1].strip()
# avoid wmctrl timing probs
time.sleep(.100)

args.desktop = dialog.desktop_combo.get_active()
args.profile = dialog.profile_combo.get_active_text()

dialog.destroy()


class SaveDialog(Gtk.Dialog):

def __init__(self, current_desktop: int, desktop_list: List[str], current_profile, profile_list: List[str]):
Gtk.Dialog.__init__(self,
"Save Virtual Desktop",
None, 0,
(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
Gtk.STOCK_OK, Gtk.ResponseType.OK))

self.set_border_width(5)

self.set_icon(self.render_icon(Gtk.STOCK_DIALOG_QUESTION, Gtk.IconSize.DIALOG))

vbox = self.get_content_area()
vbox.set_spacing(5)

hbox = Gtk.HBox(spacing=20)
vbox.pack_start(hbox, True, True, 0)
label = Gtk.Label("Desktop:")
label.set_size_request(70, 20)
label.set_xalign(0)
hbox.pack_start(label, False, False, 0)
self.desktop_combo = Gtk.ComboBoxText()
for desktop in desktop_list:
self.desktop_combo.append_text(desktop)
self.desktop_combo.set_active(current_desktop)
hbox.pack_start(self.desktop_combo, True, True, 0)

hbox = Gtk.HBox(spacing=20)
vbox.pack_start(hbox, True, True, 0)
label = Gtk.Label("Profile:")
label.set_size_request(70, 20)
label.set_xalign(0)
hbox.pack_start(label, False, False, 0)
self.profile_combo = Gtk.ComboBoxText()
for profile in profile_list:
self.profile_combo.append_text(profile)
self.profile_combo.set_active(profile_list.index(current_profile))
hbox.pack_start(self.profile_combo, True, True, 0)

hbox = Gtk.HBox(spacing=10)
vbox.pack_start(hbox, True, True, 10)
label = Gtk.Label()
label.set_size_request(70, 20)
hbox.pack_start(label, False, False, 0)
self.open_checkbox = Gtk.CheckButton("Open JSON file")
hbox.pack_start(self.open_checkbox, False, False, 0)

vbox.pack_start(Gtk.HSeparator(), True, True, 0)

self.show_all()


class RestoreDialog(Gtk.Dialog):

def __init__(self, current_desktop: int, desktop_list: List[str], current_profile, profile_list: List[str]):
Gtk.Dialog.__init__(self,
"Restore Virtual Desktop",
None, 0,
(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
Gtk.STOCK_OK, Gtk.ResponseType.OK))

self.set_border_width(5)
self.set_icon(self.render_icon(Gtk.STOCK_DIALOG_QUESTION, Gtk.IconSize.DIALOG))

vbox = self.get_content_area()
vbox.set_spacing(5)

hbox = Gtk.HBox(spacing=20)
vbox.pack_start(hbox, True, True, 0)
label = Gtk.Label("Desktop:")
label.set_size_request(70, 20)
label.set_xalign(0)
hbox.pack_start(label, False, False, 0)
self.desktop_combo = Gtk.ComboBoxText()
for desktop in desktop_list:
self.desktop_combo.append_text(desktop)
self.desktop_combo.set_active(current_desktop)
hbox.pack_start(self.desktop_combo, True, True, 0)

hbox = Gtk.HBox(spacing=20)
vbox.pack_start(hbox, True, True, 10)
label = Gtk.Label("Profile:")
label.set_size_request(70, 20)
label.set_xalign(0)
hbox.pack_start(label, False, False, 0)
self.profile_combo = Gtk.ComboBoxText.new_with_entry()
for profile in profile_list:
self.profile_combo.append_text(profile)
self.profile_combo.set_active(profile_list.index(current_profile))
hbox.pack_start(self.profile_combo, True, True, 0)

vbox.pack_start(Gtk.HSeparator(), True, True, 0)

self.show_all()
9 changes: 6 additions & 3 deletions savedesktop/rvd.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ def main():
parser = argparse.ArgumentParser(description='Restore virtual desktops (workspaces)')
parser.add_argument("-g", "--gui", action="store_true", help="gui mode")
parser.add_argument("-p", "--profile", default="default", help="profile name")
parser.add_argument("-d", "--desktop", type=int, default=0, help="target desktop number from 0 to n")
parser.add_argument("--version", action="version", version="0.1.0")
parser.add_argument("-d", "--desktop", type=int, default=None, help="target desktop number from 0 to n")
parser.add_argument("--version", action="version", version="0.1.1")
args = parser.parse_args()
c.check_dependencies(args)
try:
Expand All @@ -57,7 +57,10 @@ def restore(args: argparse.Namespace):
try:
window_list = p.read_profile(args.profile)
except FileNotFoundError as e:
print("profile '{0}' not found".format(e.filename), file=sys.stderr)
msg = "profile '{0}' not found".format(e.filename)
print(msg, file=sys.stderr)
if args.gui:
gui.show_error(msg)
exit(-1)
wmctrl.switch_desktop(args.desktop)
for props in window_list:
Expand Down
2 changes: 1 addition & 1 deletion savedesktop/svd.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def main():
parser.add_argument("-o", "--open", action="store_true", help="show saved profile")
parser.add_argument("-p", "--profile", default="default", help="profile name")
parser.add_argument("-d", "--desktop", type=int, default=None, help="desktop number from 0 to n")
parser.add_argument("--version", action="version", version="0.1.0")
parser.add_argument("--version", action="version", version="0.1.1")
args = parser.parse_args()
c.check_dependencies(args)
try:
Expand Down
2 changes: 2 additions & 0 deletions savedesktop/wmctrl.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ def list_window_details(desktop: int = None) -> List[dict]:
result = list()
out = run_wmctrl("-p", "-G", "-l")
for line in out.split('\n'):
if line.endswith("Save Virtual Desktop"):
continue
tokens = line.split(maxsplit=7)
if desktop is not None and desktop != int(tokens[1]):
continue
Expand Down
6 changes: 3 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@

setuptools.setup(
name='savedesktop',
version='0.1.0',
version='0.1.1',
data_files=data_files,
entry_points={
'console_scripts': ['svd=savedesktop.svd:main', 'rvd=savedesktop.rvd:main']
Expand All @@ -40,10 +40,10 @@
description='cli script to save and restore virtual desktops',
long_description=long_description,
long_description_content_type='text/markdown',
url='https://gitlab.com/nrittsti/sd',
url='https://github.com/nrittsti/savedesktop',
packages=setuptools.find_packages(),
license="GPL",
keywords=['window manager', 'wmctrl', 'desktop'],
keywords=['window manager', 'wmctrl', 'desktop', 'automation'],
classifiers=(
'Programming Language :: Python :: 3',
'License :: OSI Approved :: GPL License',
Expand Down

0 comments on commit 8121976

Please sign in to comment.