From 57ca69fe09285ed7572d86f94e257484caa015a2 Mon Sep 17 00:00:00 2001 From: Mike Gabriel Date: Fri, 1 Mar 2019 13:47:39 +0100 Subject: nxdialog: Turn into autotools project, add man page. --- nxdialog/Makefile.am | 21 +++ nxdialog/README.md | 23 +++ nxdialog/VERSION | 1 + nxdialog/bin/Makefile.am | 3 + nxdialog/bin/nxdialog | 394 +++++++++++++++++++++++++++++++++++++++++++++++ nxdialog/configure.ac | 22 +++ nxdialog/man/Makefile.am | 5 + nxdialog/man/nxdialog.1 | 72 +++++++++ nxdialog/nxdialog | 394 ----------------------------------------------- 9 files changed, 541 insertions(+), 394 deletions(-) create mode 100644 nxdialog/Makefile.am create mode 100644 nxdialog/README.md create mode 120000 nxdialog/VERSION create mode 100644 nxdialog/bin/Makefile.am create mode 100755 nxdialog/bin/nxdialog create mode 100644 nxdialog/configure.ac create mode 100644 nxdialog/man/Makefile.am create mode 100644 nxdialog/man/nxdialog.1 delete mode 100755 nxdialog/nxdialog (limited to 'nxdialog') diff --git a/nxdialog/Makefile.am b/nxdialog/Makefile.am new file mode 100644 index 000000000..e444af1fa --- /dev/null +++ b/nxdialog/Makefile.am @@ -0,0 +1,21 @@ +NULL = + +SUBDIRS = bin man + +ACLOCAL_AMFLAGS = -I m4 + +MAINTAINERCLEANFILES = \ + $(srcdir)/autom4te.cache/* \ + $(srcdir)/build-aux/* \ + $(srcdir)/Makefile.in \ + $(srcdir)/man/Makefile.in \ + $(srcdir)/src/Makefile.in \ + $(srcdir)/aclocal.m4 \ + $(srcdir)/config.h.in \ + $(srcdir)/config.h.in~ \ + $(srcdir)/config.guess \ + $(srcdir)/config.sub \ + $(srcdir)/configure \ + $(NULL) + +DISTCLEANFILES=$(MAINTAINERCLEANFILES) diff --git a/nxdialog/README.md b/nxdialog/README.md new file mode 100644 index 000000000..68422b1f6 --- /dev/null +++ b/nxdialog/README.md @@ -0,0 +1,23 @@ +# NX Dialog Helper Tool + +The ``nxdialog`` script can be executed with Python 2.6.x (or higher) and +Python 3.4.x (or higher) alike. + +## Runtime Dependencies + +Required Python modules: + + * argparse + * gi + +Required GIR namespaces: + + * Gtk + * Gdk + * GdkX11 + +See the man page for more details. + +## License + +The ``nxdialog`` script and related files have been licensed under GPLv2+. diff --git a/nxdialog/VERSION b/nxdialog/VERSION new file mode 120000 index 000000000..6ff19de4b --- /dev/null +++ b/nxdialog/VERSION @@ -0,0 +1 @@ +../VERSION \ No newline at end of file diff --git a/nxdialog/bin/Makefile.am b/nxdialog/bin/Makefile.am new file mode 100644 index 000000000..fa1942a19 --- /dev/null +++ b/nxdialog/bin/Makefile.am @@ -0,0 +1,3 @@ +NULL = + +dist_bin_SCRIPTS = nxdialog diff --git a/nxdialog/bin/nxdialog b/nxdialog/bin/nxdialog new file mode 100755 index 000000000..e7ca10aad --- /dev/null +++ b/nxdialog/bin/nxdialog @@ -0,0 +1,394 @@ +#!/usr/bin/env python +# +# ^^^ This is working with python2 and python3 so we choose a shebang +# that will find either version. +# Citing PEP394: "One exception to this is scripts that are +# deliberately written to be source compatible with both Python +# 2.x and 3.x. Such scripts may continue to use python on their +# shebang line. + +# Copyright (C) 2008 Google Inc. +# Copyright (C) 2019 Ulrich Sibiller +# +# 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, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +# This version is based on the nxdialog.py of the long abandoned +# Google project "neatx" (https://code.google.com/archive/p/neatx/). +# List of changes: +# - pulled in the few parts of the neatx python modules that are actually +# to make it a standlone script +# - added usage output +# - dropped logging code, print errors to stderr +# - can handle the "yesno" dialog type +# - added missing docstrings +# - pylint improvements +# - removed neatx entry from the pulldoww menu +# - use PyGObject instead of PyGtk and thus Gtk3 +# - replace optparse by argparse +# - make code compatible to python2 and python3. + +"""nxdialog program for handling dialog display.""" + +# If an "NX_CLIENT" environment variable is not provided to nxagent +# nxcomp library assumes this script is located in /usr/NX/bin/nxclient +# +# Example: +# nxdialog --dialog yesno --message "message text" --caption "message title" --parent 0 + +from __future__ import print_function + +import argparse +import os +import signal +import sys + +import gi +gi.require_version('Gtk', '3.0') +# pylint: disable=wrong-import-position +from gi.repository import Gtk, Gdk, GdkX11 + +PROGRAM = "nxdialog" + +DISCONNECT = 1 +TERMINATE = 2 + +EXIT_SUCCESS = 0 +EXIT_FAILURE = 1 + +CANCEL_TEXT = "Cancel" +DISCONNECT_TEXT = "Disconnect" +TERMINATE_TEXT = "Terminate" +YES_TEXT = "Yes" +NO_TEXT = "No" + +DLG_TYPE_ERROR = "error" +DLG_TYPE_OK = "ok" +DLG_TYPE_PANIC = "panic" +DLG_TYPE_PULLDOWN = "pulldown" +DLG_TYPE_QUIT = "quit" +DLG_TYPE_YESNO = "yesno" +DLG_TYPE_YESNOSUSPEND = "yesnosuspend" + +VALID_DLG_TYPES = frozenset([ + DLG_TYPE_ERROR, + DLG_TYPE_OK, + DLG_TYPE_PANIC, + DLG_TYPE_PULLDOWN, + DLG_TYPE_QUIT, + DLG_TYPE_YESNO, + DLG_TYPE_YESNOSUSPEND, +]) + + +class PullDownMenu(object): + """ Shows a popup menu to disconnect/terminate session. """ + + def __init__(self, window_id): + """ Initializes this class. + + @type window_id: int + @param window_id: X11 window id of target window + + """ + self.window_id = window_id + self.result = None + + def show(self): + """ Shows popup and returns result. """ + + display = Gdk.Display.get_default() + win = GdkX11.X11Window.foreign_new_for_display(display, self.window_id) + + menu = Gtk.Menu() + menu.connect("deactivate", self.menu_deactivate) + + # TODO: Show title item in bold font + title = Gtk.MenuItem(label="Session control") + title.set_sensitive(False) + menu.append(title) + + disconnect = Gtk.MenuItem(label=DISCONNECT_TEXT) + disconnect.connect("activate", self.item_activate, DISCONNECT) + menu.append(disconnect) + + terminate = Gtk.MenuItem(label=TERMINATE_TEXT) + terminate.connect("activate", self.item_activate, TERMINATE) + menu.append(terminate) + + menu.append(Gtk.SeparatorMenuItem()) + + cancel = Gtk.MenuItem(label=CANCEL_TEXT) + menu.append(cancel) + + menu.show_all() + + menu.popup(parent_menu_shell=None, parent_menu_item=None, + func=self.pos_menu, data=win, + button=0, activate_time=Gtk.get_current_event_time()) + + Gtk.main() + + return self.result + + def item_activate(self, _, result): + """ called when a menu item is selected """ + self.result = result + Gtk.main_quit() + + @staticmethod + def menu_deactivate(_): + """ called when menu is deactivated """ + Gtk.main_quit() + + @staticmethod + def pos_menu(menu, _xpos, _ypos, *data): + """ Positions menu at the top center of the parent window. """ + parent = data[0] + + # Get parent geometry and origin + _, _, win_width, _ = parent.get_geometry() + _, win_x, win_y = parent.get_origin() + + # Calculate width of menu + #menu_width = menu.get_preferred_width().natural_width + menu_width = menu.get_allocated_width() + + # Calculate center + center_x = int(win_x + ((win_width - menu_width) / 2)) + + return (center_x, win_y, True) + + +def show_yes_no_suspend_box(title, text): + """ Shows a message box to disconnect/terminate session. + + @type title: str + @param title: Message box title + @type text: str + @param text: Message box text + @return: Choosen action + + """ + dlg = Gtk.MessageDialog(type=Gtk.MessageType.QUESTION, + flags=Gtk.DialogFlags.MODAL) + dlg.set_title(title) + dlg.set_markup(text) + dlg.add_button(DISCONNECT_TEXT, DISCONNECT) + dlg.add_button(TERMINATE_TEXT, TERMINATE) + dlg.add_button(CANCEL_TEXT, Gtk.ResponseType.CANCEL) + + res = dlg.run() + + if res in (DISCONNECT, TERMINATE): + return res + + # Everything else is cancel + return None + + +def show_yes_no_box(title, text): + """ Shows a message box with answers yes and no. + + @type title: str + @param title: Message box title + @type text: str + @param text: Message box text + @return: Choosen action + + """ + dlg = Gtk.MessageDialog(type=Gtk.MessageType.QUESTION, + flags=Gtk.DialogFlags.MODAL) + dlg.set_title(title) + dlg.set_markup(text) + dlg.add_button(YES_TEXT, TERMINATE) + dlg.add_button(NO_TEXT, Gtk.ResponseType.CANCEL) + + res = dlg.run() + + if res == TERMINATE: + return res + + # Everything else is cancel + return None + + +def handle_session_action(agentpid, action): + """ Execute session action choosen by user. + + @type agentpid: int + @param agentpid: Nxagent process id as passed by command line + @type action: int or None + @param action: Choosen action + + """ + + if action == DISCONNECT: + print("Disconnecting from session, sending SIGHUP to %s" % (agentpid)) + if agentpid != 0: + os.kill(agentpid, signal.SIGHUP) + + elif action == TERMINATE: + print("Terminating session, sending SIGTERM to process %s" % (agentpid)) + if agentpid != 0: + os.kill(agentpid, signal.SIGTERM) + + elif action is None: + pass + + else: + raise NotImplementedError() + + +def show_simple_message_box(icon, title, text): + """ Shows a simple message box. + + @type icon: QMessageBox.Icon + @param icon: Icon for message box + @type title: str + @param title: Message box title + @type text: str + @param text: Message box text + + """ + dlg = Gtk.MessageDialog(type=icon, flags=Gtk.DialogFlags.MODAL, + buttons=Gtk.ButtonsType.OK) + dlg.set_title(title) + dlg.set_markup(text) + dlg.run() + + +class NxDialogProgram(object): + """ the main program """ + + def __init__(self): + self.args = None + self.options = None + + def main(self): + """ let's do something """ + try: + self.options = self.parse_args() + + self.run() + + except (SystemExit, KeyboardInterrupt): + raise + + except Exception as expt: + sys.stderr.write("Caught exception: %s\n" % (expt)) + sys.exit(EXIT_FAILURE) + + @staticmethod + def parse_args(): + """ init parser """ + + parser = argparse.ArgumentParser(description="Helper for nxagent to display dialogs") + + # nxagent 3.5.99.18 only uses yesno, ok, pulldown and yesnosuspend + # yesno dialogs will always kill the session if "yes" is selected + parser.add_argument("--dialog", dest="dialog_type", + help='type of dialog to show, one of "yesno", \ + "ok", "error", "panic", "quit", "pulldown", \ + "yesnosuspend"') + parser.add_argument("--message", dest="text", + help="message text to display in the dialog") + parser.add_argument("--caption", dest="caption", + help="window title of the dialog") + parser.add_argument("--display", dest="display", + help="X11 display where the dialog should be \ + shown") + parser.add_argument("--parent", type=int, dest="agentpid", + help="pid of the nxagent") + parser.add_argument("--window", type=int, dest="window", + help="id of window where to embed the \ + pulldown dialog type") + # -class, -local, -allowmultiple are unused in nxlibs 3.5.99.18 + parser.add_argument("--class", dest="dlgclass", default="info", + help="class of the message (info, warning, error) \ + default: info) [currently unimplemented]") + parser.add_argument("--local", action="store_true", dest="local", + help="specify that proxy mode is used \ + [currently unimplemented]") + parser.add_argument("--allowmultiple", action="store_true", + dest="allowmultiple", + help="allow launching more than one dialog with \ + the same message [currently unimplemented]") + + return parser.parse_args() + + def run(self): + """ Disconnect/terminate NX session upon user's request. """ + + if not self.options.dialog_type: + sys.stderr.write("Dialog type not supplied via --type\n") + sys.exit(EXIT_FAILURE) + + dlgtype = self.options.dialog_type + + if dlgtype not in VALID_DLG_TYPES: + sys.stderr.write("Invalid dialog type '%s'\n" % (dlgtype)) + sys.exit(EXIT_FAILURE) + + if dlgtype in (DLG_TYPE_PULLDOWN, + DLG_TYPE_YESNOSUSPEND, + DLG_TYPE_YESNO) and self.options.agentpid is None: + sys.stderr.write("Agent pid not supplied via --parent\n") + sys.exit(EXIT_FAILURE) + + if dlgtype == DLG_TYPE_PULLDOWN and not self.options.window: + sys.stderr.write("Window id not supplied via --window\n") + sys.exit(EXIT_FAILURE) + + if self.options.caption: + message_caption = self.options.caption + else: + message_caption = sys.argv[0] + + if self.options.text: + message_text = self.options.text + else: + message_text = "" + + if self.options.display: + os.environ["DISPLAY"] = self.options.display + + if dlgtype == DLG_TYPE_OK: + show_simple_message_box( + Gtk.MessageType.INFO, message_caption, message_text) + + elif dlgtype in (DLG_TYPE_ERROR, DLG_TYPE_PANIC): + show_simple_message_box( + Gtk.MessageType.ERROR, message_caption, message_text) + + elif dlgtype == DLG_TYPE_PULLDOWN: + handle_session_action(self.options.agentpid, + PullDownMenu(self.options.window).show()) + + elif dlgtype == DLG_TYPE_YESNOSUSPEND: + handle_session_action(self.options.agentpid, + show_yes_no_suspend_box(message_caption, message_text)) + + elif dlgtype == DLG_TYPE_YESNO: + handle_session_action(self.options.agentpid, + show_yes_no_box(message_caption, message_text)) + + else: + # TODO: Implement all dialog types + sys.stderr.write("Dialog type '%s' not implemented" % (dlgtype)) + sys.exit(EXIT_FAILURE) + + +NxDialogProgram().main() diff --git a/nxdialog/configure.ac b/nxdialog/configure.ac new file mode 100644 index 000000000..bc8e81b84 --- /dev/null +++ b/nxdialog/configure.ac @@ -0,0 +1,22 @@ +dnl *************************************************************************** +dnl *** configure.ac for nxdialog *** +dnl *************************************************************************** + +m4_define([nxdialog_version], m4_esyscmd([tr -d '\n' < VERSION])) + +# Initialize Autoconf +AC_PREREQ(2.60) + +AC_INIT([NX Dialog], [nxdialog_version], [https://github.com/ArcticaProject/nx-libs/issues]) +AC_CONFIG_AUX_DIR([build-aux]) +AC_PREFIX_DEFAULT([/usr/local]) + +AM_INIT_AUTOMAKE([foreign no-dist-gzip dist-bzip2]) + +AC_CONFIG_FILES([ +Makefile +bin/Makefile +man/Makefile +]) + +AC_OUTPUT diff --git a/nxdialog/man/Makefile.am b/nxdialog/man/Makefile.am new file mode 100644 index 000000000..a862b1e7a --- /dev/null +++ b/nxdialog/man/Makefile.am @@ -0,0 +1,5 @@ +NULL = + +dist_man_MANS = \ + nxdialog.1 \ + $(NULL) diff --git a/nxdialog/man/nxdialog.1 b/nxdialog/man/nxdialog.1 new file mode 100644 index 000000000..636d59f8d --- /dev/null +++ b/nxdialog/man/nxdialog.1 @@ -0,0 +1,72 @@ +'\" -*- coding: utf-8 -*- +.if \n(.g .ds T< \\FC +.if \n(.g .ds T> \\F[\n[.fam]] +.de URL +\\$2 \(la\\$1\(ra\\$3 +.. +.if \n(.g .mso www.tmac +.TH nxdialog 1 "Jan 2019" "Version 3.5.99.18" "NX Dialog" +.SH NAME +nxdialog \- NX Dialog Helper +.SH SYNOPSIS +'nh +.fi +.ad l +\fBnxdialog\fR \fI[-h] [--dialog DIALOG_TYPE] [--message TEXT] + [--caption CAPTION] [--display DISPLAY] [--parent AGENTPID] + [--window WINDOW] [--class DLGCLASS] [--local] + [--allowmultiple]\fR + +.SH DESCRIPTION +\fBnxdialog\fR is a GUI helper that can be used with nxagent to provide +user interaction on certain events inside nxagent. It adds graphical +widgets (menus, dialog boxes, etc.) to nxagent that allow a smarter user +interaction with the agent. +.PP +\fBnxagent\fR is not using \fBnxdialog\fR by default, set the +\fI$NX_CLIENT\fR environment variable to make the \fBnxdialog\fR path known to +\fBnxagent\fR. +.PP +If you want to disable \fBnxdialog\fR usage in \fBnxagent\fR, then make +sure that the \fI$NX_CLIENT\fR environment variable is unset. +.PP +.SH COMMAND LINE OPTIONS +.TP 8 +.B \-h, \-\-help +Show this help message and exit. +.TP 8 +.B --dialog DIALOG_TYPE +Type of dialog to show, one of "yesno", "ok", "error", "panic", "quit", "pulldown", "yesnosuspend". +.TP 8 +.B --message \fITEXT\fR +Message text to display in the dialog. +.TP 8 +.B --caption CAPTION +Window title of the dialog. +.TP 8 +.B --display DISPLAY +X11 display where the dialog should be shown (default: \fI$DISPLAY\fR). +.TP 8 +.B --parent AGENTPID +PID of the nxagent. The agent PID can be 0 for testing \fBnxdialog\fR. +.TP 8 +.B --window WINDOW +X11 id of window where to embed the pulldown dialog type. +.TP 8 +.B --class DLGCLASS +Class of the message (info, warning, error) default: info) [currently unimplemented]. +.TP 8 +.B --local +Specify that proxy mode is used [currently unimplemented]. +.TP 8 +.B --allowmultiple +Allow launching more than one dialog with the same message [currently unimplemented]. + +.SH AUTHOR +The \fBnxdialog\fR application has been derived from Google's +NeatX client application by Ulrich Sibiller . +.PP +This manual has been written by Mike Gabriel + for the X2Go Project +(https://wiki.x2go.org) and the Arctica Project +(https://arctica-project.org). diff --git a/nxdialog/nxdialog b/nxdialog/nxdialog deleted file mode 100755 index e7ca10aad..000000000 --- a/nxdialog/nxdialog +++ /dev/null @@ -1,394 +0,0 @@ -#!/usr/bin/env python -# -# ^^^ This is working with python2 and python3 so we choose a shebang -# that will find either version. -# Citing PEP394: "One exception to this is scripts that are -# deliberately written to be source compatible with both Python -# 2.x and 3.x. Such scripts may continue to use python on their -# shebang line. - -# Copyright (C) 2008 Google Inc. -# Copyright (C) 2019 Ulrich Sibiller -# -# 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, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -# 02110-1301, USA. - -# This version is based on the nxdialog.py of the long abandoned -# Google project "neatx" (https://code.google.com/archive/p/neatx/). -# List of changes: -# - pulled in the few parts of the neatx python modules that are actually -# to make it a standlone script -# - added usage output -# - dropped logging code, print errors to stderr -# - can handle the "yesno" dialog type -# - added missing docstrings -# - pylint improvements -# - removed neatx entry from the pulldoww menu -# - use PyGObject instead of PyGtk and thus Gtk3 -# - replace optparse by argparse -# - make code compatible to python2 and python3. - -"""nxdialog program for handling dialog display.""" - -# If an "NX_CLIENT" environment variable is not provided to nxagent -# nxcomp library assumes this script is located in /usr/NX/bin/nxclient -# -# Example: -# nxdialog --dialog yesno --message "message text" --caption "message title" --parent 0 - -from __future__ import print_function - -import argparse -import os -import signal -import sys - -import gi -gi.require_version('Gtk', '3.0') -# pylint: disable=wrong-import-position -from gi.repository import Gtk, Gdk, GdkX11 - -PROGRAM = "nxdialog" - -DISCONNECT = 1 -TERMINATE = 2 - -EXIT_SUCCESS = 0 -EXIT_FAILURE = 1 - -CANCEL_TEXT = "Cancel" -DISCONNECT_TEXT = "Disconnect" -TERMINATE_TEXT = "Terminate" -YES_TEXT = "Yes" -NO_TEXT = "No" - -DLG_TYPE_ERROR = "error" -DLG_TYPE_OK = "ok" -DLG_TYPE_PANIC = "panic" -DLG_TYPE_PULLDOWN = "pulldown" -DLG_TYPE_QUIT = "quit" -DLG_TYPE_YESNO = "yesno" -DLG_TYPE_YESNOSUSPEND = "yesnosuspend" - -VALID_DLG_TYPES = frozenset([ - DLG_TYPE_ERROR, - DLG_TYPE_OK, - DLG_TYPE_PANIC, - DLG_TYPE_PULLDOWN, - DLG_TYPE_QUIT, - DLG_TYPE_YESNO, - DLG_TYPE_YESNOSUSPEND, -]) - - -class PullDownMenu(object): - """ Shows a popup menu to disconnect/terminate session. """ - - def __init__(self, window_id): - """ Initializes this class. - - @type window_id: int - @param window_id: X11 window id of target window - - """ - self.window_id = window_id - self.result = None - - def show(self): - """ Shows popup and returns result. """ - - display = Gdk.Display.get_default() - win = GdkX11.X11Window.foreign_new_for_display(display, self.window_id) - - menu = Gtk.Menu() - menu.connect("deactivate", self.menu_deactivate) - - # TODO: Show title item in bold font - title = Gtk.MenuItem(label="Session control") - title.set_sensitive(False) - menu.append(title) - - disconnect = Gtk.MenuItem(label=DISCONNECT_TEXT) - disconnect.connect("activate", self.item_activate, DISCONNECT) - menu.append(disconnect) - - terminate = Gtk.MenuItem(label=TERMINATE_TEXT) - terminate.connect("activate", self.item_activate, TERMINATE) - menu.append(terminate) - - menu.append(Gtk.SeparatorMenuItem()) - - cancel = Gtk.MenuItem(label=CANCEL_TEXT) - menu.append(cancel) - - menu.show_all() - - menu.popup(parent_menu_shell=None, parent_menu_item=None, - func=self.pos_menu, data=win, - button=0, activate_time=Gtk.get_current_event_time()) - - Gtk.main() - - return self.result - - def item_activate(self, _, result): - """ called when a menu item is selected """ - self.result = result - Gtk.main_quit() - - @staticmethod - def menu_deactivate(_): - """ called when menu is deactivated """ - Gtk.main_quit() - - @staticmethod - def pos_menu(menu, _xpos, _ypos, *data): - """ Positions menu at the top center of the parent window. """ - parent = data[0] - - # Get parent geometry and origin - _, _, win_width, _ = parent.get_geometry() - _, win_x, win_y = parent.get_origin() - - # Calculate width of menu - #menu_width = menu.get_preferred_width().natural_width - menu_width = menu.get_allocated_width() - - # Calculate center - center_x = int(win_x + ((win_width - menu_width) / 2)) - - return (center_x, win_y, True) - - -def show_yes_no_suspend_box(title, text): - """ Shows a message box to disconnect/terminate session. - - @type title: str - @param title: Message box title - @type text: str - @param text: Message box text - @return: Choosen action - - """ - dlg = Gtk.MessageDialog(type=Gtk.MessageType.QUESTION, - flags=Gtk.DialogFlags.MODAL) - dlg.set_title(title) - dlg.set_markup(text) - dlg.add_button(DISCONNECT_TEXT, DISCONNECT) - dlg.add_button(TERMINATE_TEXT, TERMINATE) - dlg.add_button(CANCEL_TEXT, Gtk.ResponseType.CANCEL) - - res = dlg.run() - - if res in (DISCONNECT, TERMINATE): - return res - - # Everything else is cancel - return None - - -def show_yes_no_box(title, text): - """ Shows a message box with answers yes and no. - - @type title: str - @param title: Message box title - @type text: str - @param text: Message box text - @return: Choosen action - - """ - dlg = Gtk.MessageDialog(type=Gtk.MessageType.QUESTION, - flags=Gtk.DialogFlags.MODAL) - dlg.set_title(title) - dlg.set_markup(text) - dlg.add_button(YES_TEXT, TERMINATE) - dlg.add_button(NO_TEXT, Gtk.ResponseType.CANCEL) - - res = dlg.run() - - if res == TERMINATE: - return res - - # Everything else is cancel - return None - - -def handle_session_action(agentpid, action): - """ Execute session action choosen by user. - - @type agentpid: int - @param agentpid: Nxagent process id as passed by command line - @type action: int or None - @param action: Choosen action - - """ - - if action == DISCONNECT: - print("Disconnecting from session, sending SIGHUP to %s" % (agentpid)) - if agentpid != 0: - os.kill(agentpid, signal.SIGHUP) - - elif action == TERMINATE: - print("Terminating session, sending SIGTERM to process %s" % (agentpid)) - if agentpid != 0: - os.kill(agentpid, signal.SIGTERM) - - elif action is None: - pass - - else: - raise NotImplementedError() - - -def show_simple_message_box(icon, title, text): - """ Shows a simple message box. - - @type icon: QMessageBox.Icon - @param icon: Icon for message box - @type title: str - @param title: Message box title - @type text: str - @param text: Message box text - - """ - dlg = Gtk.MessageDialog(type=icon, flags=Gtk.DialogFlags.MODAL, - buttons=Gtk.ButtonsType.OK) - dlg.set_title(title) - dlg.set_markup(text) - dlg.run() - - -class NxDialogProgram(object): - """ the main program """ - - def __init__(self): - self.args = None - self.options = None - - def main(self): - """ let's do something """ - try: - self.options = self.parse_args() - - self.run() - - except (SystemExit, KeyboardInterrupt): - raise - - except Exception as expt: - sys.stderr.write("Caught exception: %s\n" % (expt)) - sys.exit(EXIT_FAILURE) - - @staticmethod - def parse_args(): - """ init parser """ - - parser = argparse.ArgumentParser(description="Helper for nxagent to display dialogs") - - # nxagent 3.5.99.18 only uses yesno, ok, pulldown and yesnosuspend - # yesno dialogs will always kill the session if "yes" is selected - parser.add_argument("--dialog", dest="dialog_type", - help='type of dialog to show, one of "yesno", \ - "ok", "error", "panic", "quit", "pulldown", \ - "yesnosuspend"') - parser.add_argument("--message", dest="text", - help="message text to display in the dialog") - parser.add_argument("--caption", dest="caption", - help="window title of the dialog") - parser.add_argument("--display", dest="display", - help="X11 display where the dialog should be \ - shown") - parser.add_argument("--parent", type=int, dest="agentpid", - help="pid of the nxagent") - parser.add_argument("--window", type=int, dest="window", - help="id of window where to embed the \ - pulldown dialog type") - # -class, -local, -allowmultiple are unused in nxlibs 3.5.99.18 - parser.add_argument("--class", dest="dlgclass", default="info", - help="class of the message (info, warning, error) \ - default: info) [currently unimplemented]") - parser.add_argument("--local", action="store_true", dest="local", - help="specify that proxy mode is used \ - [currently unimplemented]") - parser.add_argument("--allowmultiple", action="store_true", - dest="allowmultiple", - help="allow launching more than one dialog with \ - the same message [currently unimplemented]") - - return parser.parse_args() - - def run(self): - """ Disconnect/terminate NX session upon user's request. """ - - if not self.options.dialog_type: - sys.stderr.write("Dialog type not supplied via --type\n") - sys.exit(EXIT_FAILURE) - - dlgtype = self.options.dialog_type - - if dlgtype not in VALID_DLG_TYPES: - sys.stderr.write("Invalid dialog type '%s'\n" % (dlgtype)) - sys.exit(EXIT_FAILURE) - - if dlgtype in (DLG_TYPE_PULLDOWN, - DLG_TYPE_YESNOSUSPEND, - DLG_TYPE_YESNO) and self.options.agentpid is None: - sys.stderr.write("Agent pid not supplied via --parent\n") - sys.exit(EXIT_FAILURE) - - if dlgtype == DLG_TYPE_PULLDOWN and not self.options.window: - sys.stderr.write("Window id not supplied via --window\n") - sys.exit(EXIT_FAILURE) - - if self.options.caption: - message_caption = self.options.caption - else: - message_caption = sys.argv[0] - - if self.options.text: - message_text = self.options.text - else: - message_text = "" - - if self.options.display: - os.environ["DISPLAY"] = self.options.display - - if dlgtype == DLG_TYPE_OK: - show_simple_message_box( - Gtk.MessageType.INFO, message_caption, message_text) - - elif dlgtype in (DLG_TYPE_ERROR, DLG_TYPE_PANIC): - show_simple_message_box( - Gtk.MessageType.ERROR, message_caption, message_text) - - elif dlgtype == DLG_TYPE_PULLDOWN: - handle_session_action(self.options.agentpid, - PullDownMenu(self.options.window).show()) - - elif dlgtype == DLG_TYPE_YESNOSUSPEND: - handle_session_action(self.options.agentpid, - show_yes_no_suspend_box(message_caption, message_text)) - - elif dlgtype == DLG_TYPE_YESNO: - handle_session_action(self.options.agentpid, - show_yes_no_box(message_caption, message_text)) - - else: - # TODO: Implement all dialog types - sys.stderr.write("Dialog type '%s' not implemented" % (dlgtype)) - sys.exit(EXIT_FAILURE) - - -NxDialogProgram().main() -- cgit v1.2.3