From 94c4606edd30dc8b1278580782f2809b69f04641 Mon Sep 17 00:00:00 2001
From: Sebastian Koslowski <koslowski@kit.edu>
Date: Fri, 3 Jun 2016 10:02:36 +0200
Subject: grc: py3k compat using python-modernize

---
 grc/gui/StateCache.py | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

(limited to 'grc/gui/StateCache.py')

diff --git a/grc/gui/StateCache.py b/grc/gui/StateCache.py
index 3cdb5f30ce..b109a1281b 100644
--- a/grc/gui/StateCache.py
+++ b/grc/gui/StateCache.py
@@ -17,8 +17,9 @@ along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 """
 
-import Actions
-from Constants import STATE_CACHE_SIZE
+from __future__ import absolute_import
+from . import Actions
+from .Constants import STATE_CACHE_SIZE
 
 class StateCache(object):
     """
-- 
cgit v1.2.3


From 486e0a9d06e43f3b8669471bef13a5eeedbda4c6 Mon Sep 17 00:00:00 2001
From: Seth Hitefield <sdhitefield@gmail.com>
Date: Wed, 3 May 2017 07:06:54 -0700
Subject: grc: gtk3: Converted actions to Gio.Action instead of Gtk.Action

---
 grc/core/Block.py            |   2 +-
 grc/core/ParseXML.py         |   2 +-
 grc/core/utils/expr_utils.py |   3 +-
 grc/gui/Actions.py           | 633 ++++++++++++++++++++++---------------------
 grc/gui/Application.py       | 281 ++++++++++++-------
 grc/gui/Bars.py              | 519 +++++++++++++++++------------------
 grc/gui/Config.py            |   2 +-
 grc/gui/Console.py           |   6 +
 grc/gui/DrawingArea.py       |  44 +++
 grc/gui/MainWindow.py        |  25 +-
 grc/gui/Notebook.py          |  44 ++-
 grc/gui/ParamWidgets.py      |   2 +-
 grc/gui/StateCache.py        |   4 +-
 grc/gui/Utils.py             |   6 +-
 grc/gui/VariableEditor.py    |   4 +-
 grc/gui/canvas/param.py      |   2 +-
 grc/main.py                  |  16 +-
 17 files changed, 889 insertions(+), 706 deletions(-)

(limited to 'grc/gui/StateCache.py')

diff --git a/grc/core/Block.py b/grc/core/Block.py
index 8350828092..087815b941 100644
--- a/grc/core/Block.py
+++ b/grc/core/Block.py
@@ -403,7 +403,7 @@ class Block(Element):
         return itertools.chain(self.active_sources, self.active_sinks)
 
     def get_children(self):
-        return self.get_ports() + self.params.values()
+        return self.get_ports() + list(self.params.values())
 
     def get_children_gui(self):
         return self.get_ports_gui() + self.params.values()
diff --git a/grc/core/ParseXML.py b/grc/core/ParseXML.py
index 163289ba06..430ba5b474 100644
--- a/grc/core/ParseXML.py
+++ b/grc/core/ParseXML.py
@@ -156,7 +156,7 @@ def to_file(nested_data, xml_file):
         ), xml_declaration=True, pretty_print=True, encoding='utf-8')
     xml_data += etree.tostring(_to_file(nested_data)[0],
                                pretty_print=True, encoding='utf-8')
-    with open(xml_file, 'w') as fp:
+    with open(xml_file, 'wb') as fp:
         fp.write(xml_data)
 
 
diff --git a/grc/core/utils/expr_utils.py b/grc/core/utils/expr_utils.py
index 555bd709b1..cc03e9cb1c 100644
--- a/grc/core/utils/expr_utils.py
+++ b/grc/core/utils/expr_utils.py
@@ -23,7 +23,7 @@ import string
 
 import six
 
-VAR_CHARS = string.letters + string.digits + '_'
+VAR_CHARS = string.ascii_letters + string.digits + '_'
 
 
 class graph(object):
@@ -194,4 +194,3 @@ def sort_objects(objects, get_id, get_expr):
     sorted_ids = sort_variables(id2expr)
     # Return list of sorted objects
     return [id2obj[id] for id in sorted_ids]
-
diff --git a/grc/gui/Actions.py b/grc/gui/Actions.py
index 97162065a6..d214f28049 100644
--- a/grc/gui/Actions.py
+++ b/grc/gui/Actions.py
@@ -20,286 +20,323 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 from __future__ import absolute_import
 
 import six
+import logging
 
-from gi.repository import Gtk, Gdk, GObject
+from gi.repository import Gtk, Gdk, Gio, GLib, GObject
 
-NO_MODS_MASK = 0
 
+log = logging.getLogger(__name__)
 
-########################################################################
-# Actions API
-########################################################################
-_actions_keypress_dict = dict()
-_keymap = Gdk.Keymap.get_default()
-_used_mods_mask = NO_MODS_MASK
-
-
-def handle_key_press(event):
-    """
-    Call the action associated with the key press event.
-    Both the key value and the mask must have a match.
-
-    Args:
-        event: a gtk key press event
-
-    Returns:
-        true if handled
-    """
-    # extract the key value and the consumed modifiers
-    _unused, keyval, egroup, level, consumed = _keymap.translate_keyboard_state(
-        event.hardware_keycode, event.get_state(), event.group)
-    # get the modifier mask and ignore irrelevant modifiers
-    mod_mask = event.get_state() & ~consumed & _used_mods_mask
-    # look up the keypress and call the action
-    try:
-        _actions_keypress_dict[(keyval, mod_mask)]()
-    except KeyError:
-        return False  # not handled
-    else:
-        return True  # handled here
-
-_all_actions_list = list()
-
-
-def get_all_actions():
-    return _all_actions_list
-
-_accel_group = Gtk.AccelGroup()
-
-
-def get_accel_group():
-    return _accel_group
-
-
-class _ActionBase(object):
-    """
-    Base class for Action and ToggleAction
-    Register actions and keypresses with this module.
-    """
-    def __init__(self, label, keypresses):
-        global _used_mods_mask
-
-        _all_actions_list.append(self)
-        for i in range(len(keypresses)/2):
-            keyval, mod_mask = keypresses[i*2:(i+1)*2]
-            # register this keypress
-            if (keyval, mod_mask) in _actions_keypress_dict:
-                raise KeyError('keyval/mod_mask pair already registered "%s"' % str((keyval, mod_mask)))
-            _actions_keypress_dict[(keyval, mod_mask)] = self
-            _used_mods_mask |= mod_mask
-            # set the accelerator group, and accelerator path
-            # register the key name and mod mask with the accelerator path
-            if label is None:
-                continue  # dont register accel
-            accel_path = '<main>/' + self.get_name()
-            self.set_accel_group(get_accel_group())
-            self.set_accel_path(accel_path)
-            Gtk.AccelMap.add_entry(accel_path, keyval, mod_mask)
-        self.args = None
+
+def filter_from_dict(vars):
+    return filter(lambda x: isinstance(x[1], Action), vars.items())
+
+
+class Namespace(object):
+
+    def __init__(self):
+        self._actions = {}
+
+    def add(self, action):
+        key = action.props.name
+        self._actions[key] = action
+
+    def connect(self, name, handler):
+        #log.debug("Connecting action <{}> to handler <{}>".format(name, handler.__name__))
+        self._actions[name].connect('activate', handler)
+
+    def register(self, name, parameter=None, handler=None, label=None, tooltip=None,
+                 icon_name=None, keypresses=None, preference_name=None, default=None):
+        # Check types
+        if not isinstance(name, str):
+            raise TypeError("Cannot register fuction: 'name' must be a str")
+        if parameter and not isinstance(parameter, str):
+            raise TypeError("Cannot register fuction: 'parameter' must be a str")
+        if handler and not callable(handler):
+            raise TypeError("Cannot register fuction: 'handler' must be callable")
+
+        # Check if the name has a prefix.
+        prefix = None
+        if name.startswith("app.") or name.startswith("win."):
+            # Set a prefix for later and remove it
+            prefix = name[0:3]
+            name = name[4:]
+
+        if handler:
+            log.debug("Register action [{}, prefix={}, param={}, handler={}]".format(
+                  name, prefix, parameter, handler.__name__))
+        else:
+            log.debug("Register action [{}, prefix={}, param={}, handler=None]".format(
+                  name, prefix, parameter))
+
+        action = Action(name, parameter, label=label, tooltip=tooltip,
+                        icon_name=icon_name, keypresses=keypresses, prefix=prefix,
+                        preference_name=preference_name, default=default)
+        if handler:
+            action.connect('activate', handler)
+
+        key = name
+        if prefix:
+            key = "{}.{}".format(prefix, name)
+            if prefix == "app":
+                pass
+                #self.app.add_action(action)
+            elif prefix == "win":
+                pass
+                #self.win.add_action(action)
+
+        #log.debug("Registering action as '{}'".format(key))
+        self._actions[key] = action
+        return action
+
+
+    # If the actions namespace is called, trigger an action
+    def __call__(self, name):
+        # Try to parse the action string.
+        valid, action_name, target_value = Action.parse_detailed_name(name)
+        if not valid:
+            raise Exception("Invalid action string: '{}'".format(name))
+        if action_name not in self._actions:
+            raise Exception("Action '{}' is not registered!".format(action_name))
+
+        if target_value:
+            self._actions[action_name].activate(target_value)
+        else:
+            self._actions[action_name].activate()
+
+    def __getitem__(self, key):
+        return self._actions[key]
+
+    def __iter__(self):
+        return self._actions.itervalues()
+
+    def __repr__(self):
+        return str(self)
+
+    def get_actions(self):
+        return self._actions
 
     def __str__(self):
-        """
-        The string representation should be the name of the action id.
-        Try to find the action id for this action by searching this module.
-        """
-        for name, value in six.iteritems(globals()):
-            if value == self:
-                return name
-        return self.get_name()
-
-    def __repr__(self): return str(self)
-
-    def __call__(self, *args):
-        """
-        Emit the activate signal when called with ().
-        """
-        self.args = args
-        self.emit('activate')
-
-
-class Action(Gtk.Action, _ActionBase):
-    """
-    A custom Action class based on Gtk.Action.
-    Pass additional arguments such as keypresses.
-    """
-
-    def __init__(self, keypresses=(), name=None, label=None, tooltip=None,
-                 stock_id=None):
-        """
-        Create a new Action instance.
-
-        Args:
-            key_presses: a tuple of (keyval1, mod_mask1, keyval2, mod_mask2, ...)
-            the: regular Gtk.Action parameters (defaults to None)
-        """
-        if name is None:
-            name = label
-        GObject.GObject.__init__(self, name=name, label=label, tooltip=tooltip,
-                            stock_id=stock_id)
-        _ActionBase.__init__(self, label, keypresses)
-
-
-class ToggleAction(Gtk.ToggleAction, _ActionBase):
-    """
-    A custom Action class based on Gtk.ToggleAction.
-    Pass additional arguments such as keypresses.
-    """
-
-    def __init__(self, keypresses=(), name=None, label=None, tooltip=None,
-                 stock_id=None, preference_name=None, default=True):
-        """
-        Create a new ToggleAction instance.
-
-        Args:
-            key_presses: a tuple of (keyval1, mod_mask1, keyval2, mod_mask2, ...)
-            the: regular Gtk.Action parameters (defaults to None)
-        """
-        if name is None:
-            name = label
-        GObject.GObject.__init__(self, name=name, label=label,
-                                  tooltip=tooltip, stock_id=stock_id)
-        _ActionBase.__init__(self, label, keypresses)
+        s = "{Actions:"
+        for key in self._actions:
+            s += " {},".format(key)
+        s = s.rstrip(",") + "}"
+        return s
+
+
+class Action(Gio.SimpleAction):
+
+    # Change these to normal python properties.
+    #prefs_name
+
+    def __init__(self, name, parameter=None, label=None, tooltip=None,
+                 icon_name=None, keypresses=None, prefix=None,
+                 preference_name=None, default=None):
+        self.name = name
+        self.label = label
+        self.tooltip = tooltip
+        self.icon_name = icon_name
+        self.keypresses = keypresses
+        self.prefix = prefix
         self.preference_name = preference_name
         self.default = default
 
-    def load_from_preferences(self):
+        # Don't worry about checking types here, since it's done in register()
+        # Save the parameter type to use for converting in __call__
+        self.type = None
+
+        variant = None
+        state = None
+        if parameter:
+            variant = GLib.VariantType.new(parameter)
+        if preference_name:
+            state = GLib.Variant.new_boolean(True)
+        Gio.SimpleAction.__init__(self, name=name, parameter_type=variant, state=state)
+
+    def enable(self):
+        self.props.enabled = True
+
+    def disable(self):
+        self.props.enabled = False
+
+    def set_enabled(self, state):
+        if not isinstance(state, bool):
+            raise TypeError("State must be True/False.")
+        self.props.enabled = state
+
+    def __str__(self):
+        return self.props.name
+
+    def __repr__(self):
+        return str(self)
+
+    def get_active(self):
+        if self.props.state:
+            return self.props.state.get_boolean()
+        return False
+
+    def set_active(self, state):
+        if not isinstance(state, bool):
+            raise TypeError("State must be True/False.")
+        self.change_state(GLib.Variant.new_boolean(state))
+
+    # Allows actions to be directly called.
+    def __call__(self, parameter=None):
+        if self.type and parameter:
+            # Try to convert it to the correct type.
+            try:
+                param = GLib.Variant(self.type, parameter)
+                self.activate(param)
+            except TypeError:
+                raise TypeError("Invalid parameter type for action '{}'. Expected: '{}'".format(self.get_name(), self.type))
+        else:
+            self.activate()
+
+    def load_from_preferences(self, *args):
+        log.debug("load_from_preferences({})".format(args))
         if self.preference_name is not None:
             config = Gtk.Application.get_default().config
-            self.set_active(config.entry(
-                self.preference_name, default=bool(self.default)))
+            self.set_active(config.entry(self.preference_name, default=bool(self.default)))
 
-    def save_to_preferences(self):
+    def save_to_preferences(self, *args):
+        log.debug("save_to_preferences({})".format(args))
         if self.preference_name is not None:
             config = Gtk.Application.get_default().config
             config.entry(self.preference_name, value=self.get_active())
 
+
+actions = Namespace()
+
+
+def get_actions():
+    return actions.get_actions()
+
+
+def connect(action, handler=None):
+    return actions.connect(action, handler=handler)
+
+
 ########################################################################
-# Actions
+# Old Actions
 ########################################################################
-PAGE_CHANGE = Action()
-EXTERNAL_UPDATE = Action()
-VARIABLE_EDITOR_UPDATE = Action()
-FLOW_GRAPH_NEW = Action(
+PAGE_CHANGE = actions.register("win.page_change")
+EXTERNAL_UPDATE = actions.register("app.external_update")
+VARIABLE_EDITOR_UPDATE = actions.register("app.variable_editor_update")
+FLOW_GRAPH_NEW = actions.register("app.flowgraph.new",
     label='_New',
     tooltip='Create a new flow graph',
-    stock_id=Gtk.STOCK_NEW,
-    keypresses=(Gdk.KEY_n, Gdk.ModifierType.CONTROL_MASK),
+    icon_name='document-new',
+    keypresses=["<Ctrl>n"],
+    parameter="s",
 )
-FLOW_GRAPH_OPEN = Action(
+FLOW_GRAPH_OPEN = actions.register("app.flowgraph.open",
     label='_Open',
     tooltip='Open an existing flow graph',
-    stock_id=Gtk.STOCK_OPEN,
-    keypresses=(Gdk.KEY_o, Gdk.ModifierType.CONTROL_MASK),
+    icon_name='document-open',
+    keypresses=["<Ctrl>o"],
 )
-FLOW_GRAPH_OPEN_RECENT = Action(
+FLOW_GRAPH_OPEN_RECENT = actions.register("app.flowgraph.open_recent",
     label='Open _Recent',
     tooltip='Open a recently used flow graph',
-    stock_id=Gtk.STOCK_OPEN,
+    icon_name='document-open-recent',
+    parameter="s",
 )
-FLOW_GRAPH_SAVE = Action(
+FLOW_GRAPH_CLEAR_RECENT = actions.register("app.flowgraph.clear_recent")
+FLOW_GRAPH_SAVE = actions.register("app.flowgraph.save",
     label='_Save',
     tooltip='Save the current flow graph',
-    stock_id=Gtk.STOCK_SAVE,
-    keypresses=(Gdk.KEY_s, Gdk.ModifierType.CONTROL_MASK),
+    icon_name='document-save',
+    keypresses=["<Ctrl>s"],
 )
-FLOW_GRAPH_SAVE_AS = Action(
+FLOW_GRAPH_SAVE_AS = actions.register("app.flowgraph.save_as",
     label='Save _As',
     tooltip='Save the current flow graph as...',
-    stock_id=Gtk.STOCK_SAVE_AS,
-    keypresses=(Gdk.KEY_s, Gdk.ModifierType.CONTROL_MASK | Gdk.ModifierType.SHIFT_MASK),
+    icon_name='document-save-as',
+    keypresses=["<Ctrl><Shift>s"],
 )
-FLOW_GRAPH_SAVE_A_COPY = Action(
-    label='Save A Copy',
-    tooltip='Save the copy of current flow graph',
+FLOW_GRAPH_SAVE_COPY = actions.register("app.flowgraph.save_copy",
+    label='Save Copy',
+    tooltip='Save a copy of current flow graph',
 )
-FLOW_GRAPH_DUPLICATE = Action(
+FLOW_GRAPH_DUPLICATE = actions.register("app.flowgraph.duplicate",
     label='_Duplicate',
     tooltip='Create a duplicate of current flow graph',
-    stock_id=Gtk.STOCK_COPY,
-    keypresses=(Gdk.KEY_d, Gdk.ModifierType.CONTROL_MASK | Gdk.ModifierType.SHIFT_MASK),
+    #stock_id=Gtk.STOCK_COPY,
+    keypresses=["<Ctrl><Shift>d"],
 )
-FLOW_GRAPH_CLOSE = Action(
+FLOW_GRAPH_CLOSE = actions.register("app.flowgraph.close",
     label='_Close',
     tooltip='Close the current flow graph',
-    stock_id=Gtk.STOCK_CLOSE,
-    keypresses=(Gdk.KEY_w, Gdk.ModifierType.CONTROL_MASK),
+    icon_name='window-close',
+    keypresses=["<Ctrl>w"],
 )
-APPLICATION_INITIALIZE = Action()
-APPLICATION_QUIT = Action(
+APPLICATION_INITIALIZE = actions.register("app.initialize")
+APPLICATION_QUIT = actions.register("app.quit",
     label='_Quit',
     tooltip='Quit program',
-    stock_id=Gtk.STOCK_QUIT,
-    keypresses=(Gdk.KEY_q, Gdk.ModifierType.CONTROL_MASK),
+    icon_name='application-exit',
+    keypresses=["<Ctrl>q"],
 )
-FLOW_GRAPH_UNDO = Action(
+FLOW_GRAPH_UNDO = actions.register("win.undo",
     label='_Undo',
     tooltip='Undo a change to the flow graph',
-    stock_id=Gtk.STOCK_UNDO,
-    keypresses=(Gdk.KEY_z, Gdk.ModifierType.CONTROL_MASK),
+    icon_name='edit-undo',
+    keypresses=["<Ctrl>z"],
 )
-FLOW_GRAPH_REDO = Action(
+FLOW_GRAPH_REDO = actions.register("win.redo",
     label='_Redo',
     tooltip='Redo a change to the flow graph',
-    stock_id=Gtk.STOCK_REDO,
-    keypresses=(Gdk.KEY_y, Gdk.ModifierType.CONTROL_MASK),
+    icon_name='edit-redo',
+    keypresses=["<Ctrl>y"],
 )
-NOTHING_SELECT = Action()
-SELECT_ALL = Action(
+NOTHING_SELECT = actions.register("win.unselect")
+SELECT_ALL = actions.register("win.select_all",
     label='Select _All',
     tooltip='Select all blocks and connections in the flow graph',
-    stock_id=Gtk.STOCK_SELECT_ALL,
-    keypresses=(Gdk.KEY_a, Gdk.ModifierType.CONTROL_MASK),
+    icon_name='edit-select-all',
+    keypresses=["<Ctrl>a"],
 )
-ELEMENT_SELECT = Action()
-ELEMENT_CREATE = Action()
-ELEMENT_DELETE = Action(
+ELEMENT_SELECT = actions.register("win.select")
+ELEMENT_CREATE = actions.register("win.add")
+ELEMENT_DELETE = actions.register("win.delete",
     label='_Delete',
     tooltip='Delete the selected blocks',
-    stock_id=Gtk.STOCK_DELETE,
-    keypresses=(Gdk.KEY_Delete, NO_MODS_MASK),
+    icon_name='edit-delete',
 )
-BLOCK_MOVE = Action()
-BLOCK_ROTATE_CCW = Action(
+BLOCK_MOVE = actions.register("win.block_move")
+BLOCK_ROTATE_CCW = actions.register("win.block_rotate_ccw",
     label='Rotate Counterclockwise',
     tooltip='Rotate the selected blocks 90 degrees to the left',
-    stock_id=Gtk.STOCK_GO_BACK,
-    keypresses=(Gdk.KEY_Left, NO_MODS_MASK),
+    icon_name='object-rotate-left',
 )
-BLOCK_ROTATE_CW = Action(
+BLOCK_ROTATE_CW = actions.register("win.block_rotate",
     label='Rotate Clockwise',
     tooltip='Rotate the selected blocks 90 degrees to the right',
-    stock_id=Gtk.STOCK_GO_FORWARD,
-    keypresses=(Gdk.KEY_Right, NO_MODS_MASK),
+    icon_name='object-rotate-right',
 )
-BLOCK_VALIGN_TOP = Action(
+BLOCK_VALIGN_TOP = actions.register("win.block_align_top",
     label='Vertical Align Top',
     tooltip='Align tops of selected blocks',
-    keypresses=(Gdk.KEY_t, Gdk.ModifierType.SHIFT_MASK),
 )
-BLOCK_VALIGN_MIDDLE = Action(
+BLOCK_VALIGN_MIDDLE = actions.register("win.block_align_middle",
     label='Vertical Align Middle',
     tooltip='Align centers of selected blocks vertically',
-    keypresses=(Gdk.KEY_m, Gdk.ModifierType.SHIFT_MASK),
 )
-BLOCK_VALIGN_BOTTOM = Action(
+BLOCK_VALIGN_BOTTOM = actions.register("win.block_align_bottom",
     label='Vertical Align Bottom',
     tooltip='Align bottoms of selected blocks',
-    keypresses=(Gdk.KEY_b, Gdk.ModifierType.SHIFT_MASK),
 )
-BLOCK_HALIGN_LEFT = Action(
+BLOCK_HALIGN_LEFT = actions.register("win.block_align_left",
     label='Horizontal Align Left',
     tooltip='Align left edges of blocks selected blocks',
-    keypresses=(Gdk.KEY_l, Gdk.ModifierType.SHIFT_MASK),
 )
-BLOCK_HALIGN_CENTER = Action(
+BLOCK_HALIGN_CENTER = actions.register("win.block_align_center",
     label='Horizontal Align Center',
     tooltip='Align centers of selected blocks horizontally',
-    keypresses=(Gdk.KEY_c, Gdk.ModifierType.SHIFT_MASK),
 )
-BLOCK_HALIGN_RIGHT = Action(
+BLOCK_HALIGN_RIGHT = actions.register("win.block_align_right",
     label='Horizontal Align Right',
     tooltip='Align right edges of selected blocks',
-    keypresses=(Gdk.KEY_r, Gdk.ModifierType.SHIFT_MASK),
 )
 BLOCK_ALIGNMENTS = [
     BLOCK_VALIGN_TOP,
@@ -310,234 +347,222 @@ BLOCK_ALIGNMENTS = [
     BLOCK_HALIGN_CENTER,
     BLOCK_HALIGN_RIGHT,
 ]
-BLOCK_PARAM_MODIFY = Action(
+BLOCK_PARAM_MODIFY = actions.register("win.block_modify",
     label='_Properties',
     tooltip='Modify params for the selected block',
-    stock_id=Gtk.STOCK_PROPERTIES,
-    keypresses=(Gdk.KEY_Return, NO_MODS_MASK),
+    icon_name='document-properties',
 )
-BLOCK_ENABLE = Action(
+BLOCK_ENABLE = actions.register("win.block_enable",
     label='E_nable',
     tooltip='Enable the selected blocks',
-    stock_id=Gtk.STOCK_CONNECT,
-    keypresses=(Gdk.KEY_e, NO_MODS_MASK),
+    icon_name='network-wired',
 )
-BLOCK_DISABLE = Action(
+BLOCK_DISABLE = actions.register("win.block_disable",
     label='D_isable',
     tooltip='Disable the selected blocks',
-    stock_id=Gtk.STOCK_DISCONNECT,
-    keypresses=(Gdk.KEY_d, NO_MODS_MASK),
+    icon_name='network-wired-disconnected',
 )
-BLOCK_BYPASS = Action(
+BLOCK_BYPASS = actions.register("win.block_bypass",
     label='_Bypass',
     tooltip='Bypass the selected block',
-    stock_id=Gtk.STOCK_MEDIA_FORWARD,
-    keypresses=(Gdk.KEY_b, NO_MODS_MASK),
+    icon_name='media-seek-forward',
 )
-TOGGLE_SNAP_TO_GRID = ToggleAction(
+TOGGLE_SNAP_TO_GRID = actions.register("win.snap_to_grid",
     label='_Snap to grid',
     tooltip='Snap blocks to a grid for an easier connection alignment',
-    preference_name='snap_to_grid'
+    preference_name='snap_to_grid',
 )
-TOGGLE_HIDE_DISABLED_BLOCKS = ToggleAction(
+TOGGLE_HIDE_DISABLED_BLOCKS = actions.register("win.hide_disabled",
     label='Hide _Disabled Blocks',
     tooltip='Toggle visibility of disabled blocks and connections',
-    stock_id=Gtk.STOCK_MISSING_IMAGE,
-    keypresses=(Gdk.KEY_d, Gdk.ModifierType.CONTROL_MASK),
+    icon_name='image-missing',
+    keypresses=["<Ctrl>d"],
+    preference_name='hide_disabled',
 )
-TOGGLE_HIDE_VARIABLES = ToggleAction(
+TOGGLE_HIDE_VARIABLES = actions.register("win.hide_variables",
     label='Hide Variables',
     tooltip='Hide all variable blocks',
     preference_name='hide_variables',
     default=False,
 )
-TOGGLE_FLOW_GRAPH_VAR_EDITOR = ToggleAction(
+TOGGLE_FLOW_GRAPH_VAR_EDITOR = actions.register("win.toggle_variable_editor",
     label='Show _Variable Editor',
     tooltip='Show the variable editor. Modify variables and imports in this flow graph',
-    stock_id=Gtk.STOCK_EDIT,
+    icon_name='accessories-text-editor',
     default=True,
-    keypresses=(Gdk.KEY_e, Gdk.ModifierType.CONTROL_MASK),
+    keypresses=["<Ctrl>e"],
     preference_name='variable_editor_visable',
 )
-TOGGLE_FLOW_GRAPH_VAR_EDITOR_SIDEBAR = ToggleAction(
+TOGGLE_FLOW_GRAPH_VAR_EDITOR_SIDEBAR = actions.register("win.toggle_variable_editor_sidebar",
     label='Move the Variable Editor to the Sidebar',
     tooltip='Move the variable editor to the sidebar',
     default=False,
     preference_name='variable_editor_sidebar',
 )
-TOGGLE_AUTO_HIDE_PORT_LABELS = ToggleAction(
+TOGGLE_AUTO_HIDE_PORT_LABELS = actions.register("win.auto_hide_port_labels",
     label='Auto-Hide _Port Labels',
     tooltip='Automatically hide port labels',
     preference_name='auto_hide_port_labels'
 )
-TOGGLE_SHOW_BLOCK_COMMENTS = ToggleAction(
+TOGGLE_SHOW_BLOCK_COMMENTS = actions.register("win.show_block_comments",
     label='Show Block Comments',
     tooltip="Show comment beneath each block",
     preference_name='show_block_comments'
 )
-TOGGLE_SHOW_CODE_PREVIEW_TAB = ToggleAction(
+TOGGLE_SHOW_CODE_PREVIEW_TAB = actions.register("win.toggle_code_preview",
     label='Generated Code Preview',
     tooltip="Show a preview of the code generated for each Block in its "
             "Properties Dialog",
     preference_name='show_generated_code_tab',
     default=False,
 )
-TOGGLE_SHOW_FLOWGRAPH_COMPLEXITY = ToggleAction(
+TOGGLE_SHOW_FLOWGRAPH_COMPLEXITY = actions.register("win.show_flowgraph_complexity",
     label='Show Flowgraph Complexity',
     tooltip="How many Balints is the flowgraph...",
     preference_name='show_flowgraph_complexity',
     default=False,
 )
-BLOCK_CREATE_HIER = Action(
+BLOCK_CREATE_HIER = actions.register("win.block_create_hier",
     label='C_reate Hier',
     tooltip='Create hier block from selected blocks',
-    stock_id=Gtk.STOCK_CONNECT,
-#   keypresses=(Gdk.KEY_c, NO_MODS_MASK),
+    icon_name='document-new',
 )
-BLOCK_CUT = Action(
+BLOCK_CUT = actions.register("win.block_cut",
     label='Cu_t',
     tooltip='Cut',
-    stock_id=Gtk.STOCK_CUT,
-    keypresses=(Gdk.KEY_x, Gdk.ModifierType.CONTROL_MASK),
+    icon_name='edit-cut',
+    keypresses=["<Ctrl>x"],
 )
-BLOCK_COPY = Action(
+BLOCK_COPY = actions.register("win.block_copy",
     label='_Copy',
     tooltip='Copy',
-    stock_id=Gtk.STOCK_COPY,
-    keypresses=(Gdk.KEY_c, Gdk.ModifierType.CONTROL_MASK),
+    icon_name='edit-copy',
+    keypresses=["<Ctrl>c"],
 )
-BLOCK_PASTE = Action(
+BLOCK_PASTE = actions.register("win.block_paste",
     label='_Paste',
     tooltip='Paste',
-    stock_id=Gtk.STOCK_PASTE,
-    keypresses=(Gdk.KEY_v, Gdk.ModifierType.CONTROL_MASK),
+    icon_name='edit-paste',
+    keypresses=["<Ctrl>v"],
 )
-ERRORS_WINDOW_DISPLAY = Action(
+ERRORS_WINDOW_DISPLAY = actions.register("app.errors",
     label='Flowgraph _Errors',
     tooltip='View flow graph errors',
-    stock_id=Gtk.STOCK_DIALOG_ERROR,
+    icon_name='dialog-error',
 )
-TOGGLE_CONSOLE_WINDOW = ToggleAction(
+TOGGLE_CONSOLE_WINDOW = actions.register("win.toggle_console_window",
     label='Show _Console Panel',
     tooltip='Toggle visibility of the console',
-    keypresses=(Gdk.KEY_r, Gdk.ModifierType.CONTROL_MASK),
+    keypresses=["<Ctrl>r"],
     preference_name='console_window_visible'
 )
-TOGGLE_BLOCKS_WINDOW = ToggleAction(
+# TODO: Might be able to convert this to a Gio.PropertyAction eventually.
+#       actions would need to be defined in the correct class and not globally
+TOGGLE_BLOCKS_WINDOW = actions.register("win.toggle_blocks_window",
     label='Show _Block Tree Panel',
     tooltip='Toggle visibility of the block tree widget',
-    keypresses=(Gdk.KEY_b, Gdk.ModifierType.CONTROL_MASK),
+    keypresses=["<Ctrl>b"],
     preference_name='blocks_window_visible'
 )
-TOGGLE_SCROLL_LOCK = ToggleAction(
+TOGGLE_SCROLL_LOCK = actions.register("win.console.scroll_lock",
     label='Console Scroll _Lock',
     tooltip='Toggle scroll lock for the console window',
     preference_name='scroll_lock'
 )
-ABOUT_WINDOW_DISPLAY = Action(
+ABOUT_WINDOW_DISPLAY = actions.register("app.about",
     label='_About',
     tooltip='About this program',
-    stock_id=Gtk.STOCK_ABOUT,
+    icon_name='help-about',
 )
-HELP_WINDOW_DISPLAY = Action(
+HELP_WINDOW_DISPLAY = actions.register("app.help",
     label='_Help',
     tooltip='Usage tips',
-    stock_id=Gtk.STOCK_HELP,
-    keypresses=(Gdk.KEY_F1, NO_MODS_MASK),
+    icon_name='help-contents',
+    keypresses=["F1"],
 )
-TYPES_WINDOW_DISPLAY = Action(
+TYPES_WINDOW_DISPLAY = actions.register("app.types",
     label='_Types',
     tooltip='Types color mapping',
-    stock_id=Gtk.STOCK_DIALOG_INFO,
+    icon_name='dialog-information',
 )
-FLOW_GRAPH_GEN = Action(
+FLOW_GRAPH_GEN = actions.register("app.flowgraph.generate",
     label='_Generate',
     tooltip='Generate the flow graph',
-    stock_id=Gtk.STOCK_CONVERT,
-    keypresses=(Gdk.KEY_F5, NO_MODS_MASK),
+    icon_name='insert-object',
+    keypresses=["F5"],
 )
-FLOW_GRAPH_EXEC = Action(
+FLOW_GRAPH_EXEC = actions.register("app.flowgraph.execute",
     label='_Execute',
     tooltip='Execute the flow graph',
-    stock_id=Gtk.STOCK_MEDIA_PLAY,
-    keypresses=(Gdk.KEY_F6, NO_MODS_MASK),
+    icon_name='media-playback-start',
+    keypresses=["F6"],
 )
-FLOW_GRAPH_KILL = Action(
+FLOW_GRAPH_KILL = actions.register("app.flowgraph.kill",
     label='_Kill',
     tooltip='Kill the flow graph',
-    stock_id=Gtk.STOCK_STOP,
-    keypresses=(Gdk.KEY_F7, NO_MODS_MASK),
+    icon_name='media-playback-stop',
+    keypresses=["F7"],
 )
-FLOW_GRAPH_SCREEN_CAPTURE = Action(
+FLOW_GRAPH_SCREEN_CAPTURE = actions.register("app.flowgraph.screen_capture",
     label='Screen Ca_pture',
     tooltip='Create a screen capture of the flow graph',
-    stock_id=Gtk.STOCK_PRINT,
-    keypresses=(Gdk.KEY_p, Gdk.ModifierType.CONTROL_MASK),
-)
-PORT_CONTROLLER_DEC = Action(
-    keypresses=(Gdk.KEY_minus, NO_MODS_MASK, Gdk.KEY_KP_Subtract, NO_MODS_MASK),
-)
-PORT_CONTROLLER_INC = Action(
-    keypresses=(Gdk.KEY_plus, NO_MODS_MASK, Gdk.KEY_KP_Add, NO_MODS_MASK),
-)
-BLOCK_INC_TYPE = Action(
-    keypresses=(Gdk.KEY_Down, NO_MODS_MASK),
-)
-BLOCK_DEC_TYPE = Action(
-    keypresses=(Gdk.KEY_Up, NO_MODS_MASK),
-)
-RELOAD_BLOCKS = Action(
+    icon_name='printer',
+    keypresses=["<Ctrl>p"],
+)
+PORT_CONTROLLER_DEC = actions.register("win.port_controller_dec")
+PORT_CONTROLLER_INC = actions.register("win.port_controller_inc")
+BLOCK_INC_TYPE = actions.register("win.block_inc_type")
+BLOCK_DEC_TYPE = actions.register("win.block_dec_type")
+RELOAD_BLOCKS = actions.register("app.reload_blocks",
     label='Reload _Blocks',
     tooltip='Reload Blocks',
-    stock_id=Gtk.STOCK_REFRESH
+    icon_name='view-refresh'
 )
-FIND_BLOCKS = Action(
+FIND_BLOCKS = actions.register("win.find_blocks",
     label='_Find Blocks',
     tooltip='Search for a block by name (and key)',
-    stock_id=Gtk.STOCK_FIND,
-    keypresses=(Gdk.KEY_f, Gdk.ModifierType.CONTROL_MASK,
-                Gdk.KEY_slash, NO_MODS_MASK),
+    icon_name='edit-find',
+    keypresses=["<Ctrl>f", "slash"],
 )
-CLEAR_CONSOLE = Action(
+CLEAR_CONSOLE = actions.register("win.console.clear",
     label='_Clear Console',
     tooltip='Clear Console',
-    stock_id=Gtk.STOCK_CLEAR,
+    icon_name='edit-clear',
 )
-SAVE_CONSOLE = Action(
+SAVE_CONSOLE = actions.register("win.console.save",
     label='_Save Console',
     tooltip='Save Console',
-    stock_id=Gtk.STOCK_SAVE,
+    icon_name='edit-save',
 )
-OPEN_HIER = Action(
+OPEN_HIER = actions.register("win.open_hier",
     label='Open H_ier',
     tooltip='Open the source of the selected hierarchical block',
-    stock_id=Gtk.STOCK_JUMP_TO,
+    icon_name='go-jump',
 )
-BUSSIFY_SOURCES = Action(
+BUSSIFY_SOURCES = actions.register("win.bussify_sources",
     label='Toggle So_urce Bus',
     tooltip='Gang source ports into a single bus port',
-    stock_id=Gtk.STOCK_JUMP_TO,
+    icon_name='go-jump',
 )
-BUSSIFY_SINKS = Action(
+BUSSIFY_SINKS = actions.register("win.bussify_sinks",
     label='Toggle S_ink Bus',
     tooltip='Gang sink ports into a single bus port',
-    stock_id=Gtk.STOCK_JUMP_TO,
+    icon_name='go-jump',
 )
-XML_PARSER_ERRORS_DISPLAY = Action(
+XML_PARSER_ERRORS_DISPLAY = actions.register("app.xml_errors",
     label='_Parser Errors',
     tooltip='View errors that occurred while parsing XML files',
-    stock_id=Gtk.STOCK_DIALOG_ERROR,
+    icon_name='dialog-error',
 )
-FLOW_GRAPH_OPEN_QSS_THEME = Action(
+FLOW_GRAPH_OPEN_QSS_THEME = actions.register("app.open_qss_theme",
     label='Set Default QT GUI _Theme',
     tooltip='Set a default QT Style Sheet file to use for QT GUI',
-    stock_id=Gtk.STOCK_OPEN,
+    icon_name='document-open',
 )
-TOOLS_RUN_FDESIGN = Action(
+TOOLS_RUN_FDESIGN = actions.register("app.filter_design",
     label='Filter Design Tool',
     tooltip='Execute gr_filter_design',
-    stock_id=Gtk.STOCK_EXECUTE,
-)
-TOOLS_MORE_TO_COME = Action(
-    label='More to come',
+    icon_name='media-playback-start',
 )
+POST_HANDLER = actions.register("app.post_handler")
+READY = actions.register("app.ready")
diff --git a/grc/gui/Application.py b/grc/gui/Application.py
index 9e89009dc9..c1456c3a8d 100644
--- a/grc/gui/Application.py
+++ b/grc/gui/Application.py
@@ -24,9 +24,9 @@ import os
 import subprocess
 import logging
 
-from gi.repository import Gtk, GObject
+from gi.repository import Gtk, Gio, GLib, GObject
 
-from . import Dialogs, Actions, Executor, FileDialogs, Utils
+from . import Dialogs, Actions, Executor, FileDialogs, Utils, Bars
 from .MainWindow import MainWindow
 from .ParserErrorsDialog import ParserErrorsDialog
 from .PropsDialog import PropsDialog
@@ -56,54 +56,58 @@ class Application(Gtk.Application):
         """
         self.clipboard = None
         self.dialog = None
-        for action in Actions.get_all_actions(): action.connect('activate', self._handle_action)
-        #setup the main window
+
+        # Setup the main window
         self.platform = platform
         self.config = platform.config
 
-        log.debug("__init__()")
-
-        #initialize
+        log.debug("Application()")
+        # Connect all actions to _handle_action
+        for x in Actions.get_actions():
+            Actions.connect(x, handler=self._handle_action)
+            Actions.actions[x].enable()
+            if x.startswith("app."):
+                self.add_action(Actions.actions[x])
+            # Setup the shortcut keys
+            # These are the globally defined shortcuts
+            keypress = Actions.actions[x].keypresses
+            if keypress:
+                self.set_accels_for_action(x, keypress)
+
+        # Initialize
         self.init_file_paths = [os.path.abspath(file_path) for file_path in file_paths]
         self.init = False
 
     def do_startup(self):
         Gtk.Application.do_startup(self)
-        log.debug("do_startup()")
+        log.debug("Application.do_startup()")
+
+        # Setup the menu
+        log.debug("Creating menu")
+        '''
+        self.menu = Bars.Menu()
+        self.set_menu()
+        if self.prefers_app_menu():
+            self.set_app_menu(self.menu)
+        else:
+            self.set_menubar(self.menu)
+        '''
 
     def do_activate(self):
         Gtk.Application.do_activate(self)
-        log.debug("do_activate()")
+        log.debug("Application.do_activate()")
 
-        self.main_window = MainWindow(self, self.platform, self._handle_action)
+        self.main_window = MainWindow(self, self.platform)
         self.main_window.connect('delete-event', self._quit)
-        self.main_window.connect('key-press-event', self._handle_key_press)
         self.get_focus_flag = self.main_window.get_focus_flag
+
         #setup the messages
         Messages.register_messenger(self.main_window.add_console_line)
         Messages.send_init(self.platform)
 
+        log.debug("Calling Actions.APPLICATION_INITIALIZE")
         Actions.APPLICATION_INITIALIZE()
 
-    def _handle_key_press(self, widget, event):
-        """
-        Handle key presses from the keyboard and translate key combinations into actions.
-        This key press handler is called prior to the gtk key press handler.
-        This handler bypasses built in accelerator key handling when in focus because
-        * some keys are ignored by the accelerators like the direction keys,
-        * some keys are not registered to any accelerators but are still used.
-        When not in focus, gtk and the accelerators handle the the key press.
-
-        Returns:
-            false to let gtk handle the key action
-        """
-        # prevent key event stealing while the search box is active
-        # .has_focus() only in newer versions 2.17+?
-        # .is_focus() seems to work, but exactly the same
-        if self.main_window.btwin.search_entry.has_focus():
-            return False
-        return Actions.handle_key_press(event)
-
     def _quit(self, window, event):
         """
         Handle the delete event from the main window.
@@ -117,7 +121,7 @@ class Application(Gtk.Application):
         return True
 
     def _handle_action(self, action, *args):
-        #print action
+        log.debug("_handle_action({0}, {1})".format(action, args))
         main = self.main_window
         page = main.current_page
         flow_graph = page.flow_graph if page else None
@@ -130,6 +134,7 @@ class Application(Gtk.Application):
         # Initialize/Quit
         ##################################################
         if action == Actions.APPLICATION_INITIALIZE:
+            log.debug("APPLICATION_INITIALIZE")
             file_path_to_show = self.config.file_open()
             for file_path in (self.init_file_paths or self.config.get_open_files()):
                 if os.path.exists(file_path):
@@ -139,35 +144,84 @@ class Application(Gtk.Application):
 
             main.btwin.search_entry.hide()
 
-            # Disable all actions, then re-enable a few
-            for action in Actions.get_all_actions():
-                action.set_sensitive(False)  # set all actions disabled
+            """
+            Only disable certain actions on startup. Each of these actions are
+            conditionally enabled in _handle_action, so disable them first.
+             - FLOW_GRAPH_UNDO/REDO are set in gui/StateCache.py
+             - XML_PARSER_ERRORS_DISPLAY is set in RELOAD_BLOCKS
+
+            TODO: These 4 should probably be included, but they are not currently
+            enabled anywhere else:
+             - PORT_CONTROLLER_DEC, PORT_CONTROLLER_INC
+             - BLOCK_INC_TYPE, BLOCK_DEC_TYPE
+
+            TODO: These should be handled better. They are set in
+            update_exec_stop(), but not anywhere else
+             - FLOW_GRAPH_GEN, FLOW_GRAPH_EXEC, FLOW_GRAPH_KILL
+            """
+            for action in (
+                Actions.ERRORS_WINDOW_DISPLAY,
+                Actions.ELEMENT_DELETE,
+                Actions.BLOCK_PARAM_MODIFY,
+                Actions.BLOCK_ROTATE_CCW,
+                Actions.BLOCK_ROTATE_CW,
+                Actions.BLOCK_VALIGN_TOP,
+                Actions.BLOCK_VALIGN_MIDDLE,
+                Actions.BLOCK_VALIGN_BOTTOM,
+                Actions.BLOCK_HALIGN_LEFT,
+                Actions.BLOCK_HALIGN_CENTER,
+                Actions.BLOCK_HALIGN_RIGHT,
+                Actions.BLOCK_CUT,
+                Actions.BLOCK_COPY,
+                Actions.BLOCK_PASTE,
+                Actions.BLOCK_ENABLE,
+                Actions.BLOCK_DISABLE,
+                Actions.BLOCK_BYPASS,
+                Actions.BLOCK_CREATE_HIER,
+                Actions.OPEN_HIER,
+                Actions.BUSSIFY_SOURCES,
+                Actions.BUSSIFY_SINKS,
+                Actions.FLOW_GRAPH_SAVE,
+                Actions.FLOW_GRAPH_UNDO,
+                Actions.FLOW_GRAPH_REDO,
+                Actions.XML_PARSER_ERRORS_DISPLAY
+            ):
+                action.disable()
+
+            # Load preferences
             for action in (
-                Actions.APPLICATION_QUIT, Actions.FLOW_GRAPH_NEW,
-                Actions.FLOW_GRAPH_OPEN, Actions.FLOW_GRAPH_SAVE_AS,
-                Actions.FLOW_GRAPH_DUPLICATE, Actions.FLOW_GRAPH_SAVE_A_COPY,
-                Actions.FLOW_GRAPH_CLOSE, Actions.ABOUT_WINDOW_DISPLAY,
-                Actions.FLOW_GRAPH_SCREEN_CAPTURE, Actions.HELP_WINDOW_DISPLAY,
-                Actions.TYPES_WINDOW_DISPLAY, Actions.TOGGLE_BLOCKS_WINDOW,
-                Actions.TOGGLE_CONSOLE_WINDOW, Actions.TOGGLE_HIDE_DISABLED_BLOCKS,
-                Actions.TOOLS_RUN_FDESIGN, Actions.TOGGLE_SCROLL_LOCK,
-                Actions.CLEAR_CONSOLE, Actions.SAVE_CONSOLE,
-                Actions.TOGGLE_AUTO_HIDE_PORT_LABELS, Actions.TOGGLE_SNAP_TO_GRID,
+                Actions.TOGGLE_BLOCKS_WINDOW,
+                Actions.TOGGLE_CONSOLE_WINDOW,
+                Actions.TOGGLE_HIDE_DISABLED_BLOCKS,
+                Actions.TOGGLE_SCROLL_LOCK,
+                Actions.TOGGLE_AUTO_HIDE_PORT_LABELS,
+                Actions.TOGGLE_SNAP_TO_GRID,
                 Actions.TOGGLE_SHOW_BLOCK_COMMENTS,
                 Actions.TOGGLE_SHOW_CODE_PREVIEW_TAB,
                 Actions.TOGGLE_SHOW_FLOWGRAPH_COMPLEXITY,
-                Actions.FLOW_GRAPH_OPEN_QSS_THEME,
                 Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR,
                 Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR_SIDEBAR,
                 Actions.TOGGLE_HIDE_VARIABLES,
-                Actions.SELECT_ALL,
             ):
-                action.set_sensitive(True)
+                action.set_enabled(True)
                 if hasattr(action, 'load_from_preferences'):
                     action.load_from_preferences()
+
+            # Hide the panels *IF* it's saved in preferences
+            main.update_panel_visibility(main.BLOCKS, Actions.TOGGLE_BLOCKS_WINDOW.get_active())
+            main.update_panel_visibility(main.CONSOLE, Actions.TOGGLE_CONSOLE_WINDOW.get_active())
+            main.update_panel_visibility(main.VARIABLES, Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR.get_active())
+
             if ParseXML.xml_failures:
                 Messages.send_xml_errors_if_any(ParseXML.xml_failures)
-                Actions.XML_PARSER_ERRORS_DISPLAY.set_sensitive(True)
+                Actions.XML_PARSER_ERRORS_DISPLAY.set_enabled(True)
+
+            # Force an update on the current page to match loaded preferences.
+            # In the future, change the __init__ order to load preferences first
+            page = main.current_page
+            if page:
+                page.flow_graph.update()
+
             self.init = True
         elif action == Actions.APPLICATION_QUIT:
             if main.close_pages():
@@ -400,12 +454,17 @@ class Application(Gtk.Application):
         elif action == Actions.ERRORS_WINDOW_DISPLAY:
             Dialogs.ErrorsDialog(main, flow_graph).run_and_destroy()
         elif action == Actions.TOGGLE_CONSOLE_WINDOW:
+            action.set_active(not action.get_active())
             main.update_panel_visibility(main.CONSOLE, action.get_active())
             action.save_to_preferences()
         elif action == Actions.TOGGLE_BLOCKS_WINDOW:
+            # This would be better matched to a Gio.PropertyAction, but to do
+            # this, actions would have to be defined in the window not globally
+            action.set_active(not action.get_active())
             main.update_panel_visibility(main.BLOCKS, action.get_active())
             action.save_to_preferences()
         elif action == Actions.TOGGLE_SCROLL_LOCK:
+            action.set_active(not action.get_active())
             active = action.get_active()
             main.console.text_display.scroll_lock = active
             if active:
@@ -418,41 +477,53 @@ class Application(Gtk.Application):
             if file_path is not None:
                 main.console.text_display.save(file_path)
         elif action == Actions.TOGGLE_HIDE_DISABLED_BLOCKS:
+            action.set_active(not action.get_active())
             Actions.NOTHING_SELECT()
         elif action == Actions.TOGGLE_AUTO_HIDE_PORT_LABELS:
+            action.set_active(not action.get_active())
             action.save_to_preferences()
             for page in main.get_pages():
                 page.flow_graph.create_shapes()
         elif action in (Actions.TOGGLE_SNAP_TO_GRID,
                         Actions.TOGGLE_SHOW_BLOCK_COMMENTS,
                         Actions.TOGGLE_SHOW_CODE_PREVIEW_TAB):
+            action.set_active(not action.get_active())
             action.save_to_preferences()
         elif action == Actions.TOGGLE_SHOW_FLOWGRAPH_COMPLEXITY:
+            action.set_active(not action.get_active())
             action.save_to_preferences()
             for page in main.get_pages():
                 flow_graph_update(page.flow_graph)
         elif action == Actions.TOGGLE_HIDE_VARIABLES:
-            # Call the variable editor TOGGLE in case it needs to be showing
-            Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR()
+            action.set_active(not action.get_active())
+            active = action.get_active()
+            # Either way, triggering this should simply trigger the variable editor
+            # to be visible.
+            varedit = Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR
+            if active:
+                log.debug("Variables are hidden. Forcing the variable panel to be visible.")
+                varedit.disable()
+            else:
+                varedit.enable()
+            # Just force it to show.
+            varedit.set_active(True)
+            main.update_panel_visibility(main.VARIABLES)
             Actions.NOTHING_SELECT()
             action.save_to_preferences()
+            varedit.save_to_preferences()
+            flow_graph_update()
         elif action == Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR:
-            # See if the variables are hidden
-            if Actions.TOGGLE_HIDE_VARIABLES.get_active():
-                # Force this to be shown
-                main.update_panel_visibility(main.VARIABLES, True)
-                action.set_active(True)
-                action.set_sensitive(False)
-            else:
-                if action.get_sensitive():
-                    main.update_panel_visibility(main.VARIABLES, action.get_active())
-                else:  # This is occurring after variables are un-hidden
-                    # Leave it enabled
-                    action.set_sensitive(True)
-                    action.set_active(True)
-            # Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR_SIDEBAR.set_sensitive(action.get_active())
+            # TODO: There may be issues at startup since these aren't triggered
+            # the same was as Gtk.Actions when loading preferences.
+            action.set_active(not action.get_active())
+            # Just assume this was triggered because it was enabled.
+            main.update_panel_visibility(main.VARIABLES, action.get_active())
+            action.save_to_preferences()
+
+            # Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR_SIDEBAR.set_enabled(action.get_active())
             action.save_to_preferences()
         elif action == Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR_SIDEBAR:
+            action.set_active(not action.get_active())
             if self.init:
                 Dialogs.MessageDialogWrapper(
                     main, Gtk.MessageType.INFO, Gtk.ButtonsType.CLOSE,
@@ -463,7 +534,7 @@ class Application(Gtk.Application):
         # Param Modifications
         ##################################################
         elif action == Actions.BLOCK_PARAM_MODIFY:
-            selected_block = action.args[0] if action.args else flow_graph.selected_block
+            selected_block = args[0] if args[0] else flow_graph.selected_block
             if selected_block:
                 self.dialog = PropsDialog(self.main_window, selected_block)
                 response = Gtk.ResponseType.APPLY
@@ -520,17 +591,17 @@ class Application(Gtk.Application):
         elif action == Actions.FLOW_GRAPH_NEW:
             main.new_page()
             if args:
-                flow_graph = main.get_flow_graph()
+                flow_graph = main.current_page.flow_graph
                 flow_graph._options_block.get_param('generate_options').set_value(args[0])
                 flow_graph_update(flow_graph)
         elif action == Actions.FLOW_GRAPH_OPEN:
-            file_paths = args if args else FileDialogs.OpenFlowGraph(main, page.file_path).run()
+            file_paths = args[0] if args[0] else FileDialogs.OpenFlowGraph(main, page.file_path).run()
             if file_paths: # Open a new page for each file, show only the first
                 for i,file_path in enumerate(file_paths):
                     main.new_page(file_path, show=(i==0))
                     self.config.add_recent_file(file_path)
                     main.tool_bar.refresh_submenus()
-                    main.menu_bar.refresh_submenus()
+                    #main.menu_bar.refresh_submenus()
         elif action == Actions.FLOW_GRAPH_OPEN_QSS_THEME:
             file_paths = FileDialogs.OpenQSS(main, self.platform.config.install_prefix +
                                              '/share/gnuradio/themes/').run()
@@ -558,33 +629,37 @@ class Application(Gtk.Application):
                 Actions.FLOW_GRAPH_SAVE()
                 self.config.add_recent_file(file_path)
                 main.tool_bar.refresh_submenus()
-                main.menu_bar.refresh_submenus()
-        elif action == Actions.FLOW_GRAPH_SAVE_A_COPY:
+                #TODO
+                #main.menu_bar.refresh_submenus()
+        elif action == Actions.FLOW_GRAPH_SAVE_COPY:
             try:
-                if not page.get_file_path():
+                if not page.file_path:
+                    # Make sure the current flowgraph has been saved
                     Actions.FLOW_GRAPH_SAVE_AS()
                 else:
-                    dup_file_path = page.get_file_path()
+                    dup_file_path = page.file_path
                     dup_file_name = '.'.join(dup_file_path.split('.')[:-1]) + "_copy" # Assuming .grc extension at the end of file_path
                     dup_file_path_temp = dup_file_name+'.grc'
                     count = 1
                     while os.path.exists(dup_file_path_temp):
                         dup_file_path_temp = dup_file_name+'('+str(count)+').grc'
                         count += 1
-                    dup_file_path_user = SaveFlowGraphFileDialog(dup_file_path_temp).run()
+                    dup_file_path_user = FileDialogs.SaveFlowGraph(main, dup_file_path_temp).run()
                     if dup_file_path_user is not None:
                         ParseXML.to_file(flow_graph.export_data(), dup_file_path_user)
                         Messages.send('Saved Copy to: "' + dup_file_path_user + '"\n')
             except IOError:
                 Messages.send_fail_save("Can not create a copy of the flowgraph\n")
         elif action == Actions.FLOW_GRAPH_DUPLICATE:
-            flow_graph = main.get_flow_graph()
+            previous = flow_graph
+            # Create a new page
             main.new_page()
-            curr_page = main.get_page()
-            new_flow_graph = main.get_flow_graph()
-            new_flow_graph.import_data(flow_graph.export_data())
+            page = main.current_page
+            new_flow_graph = page.flow_graph
+            # Import the old data and mark the current as not saved
+            new_flow_graph.import_data(previous.export_data())
             flow_graph_update(new_flow_graph)
-            curr_page.set_saved(False)
+            page.saved = False
         elif action == Actions.FLOW_GRAPH_SCREEN_CAPTURE:
             file_path, background_transparent = FileDialogs.SaveScreenShot(main, page.file_path).run()
             if file_path is not None:
@@ -634,7 +709,7 @@ class Application(Gtk.Application):
         elif action == Actions.RELOAD_BLOCKS:
             self.platform.build_block_library()
             main.btwin.repopulate()
-            Actions.XML_PARSER_ERRORS_DISPLAY.set_sensitive(bool(
+            Actions.XML_PARSER_ERRORS_DISPLAY.set_enabled(bool(
                 ParseXML.xml_failures))
             Messages.send_xml_errors_if_any(ParseXML.xml_failures)
             # Force a redraw of the graph, by getting the current state and re-importing it
@@ -667,7 +742,7 @@ class Application(Gtk.Application):
                              shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
 
         else:
-            print('!!! Action "%s" not handled !!!' % action)
+            log.warning('!!! Action "%s" not handled !!!' % action)
         ##################################################
         # Global Actions for all States
         ##################################################
@@ -678,19 +753,19 @@ class Application(Gtk.Application):
         selected_block = selected_blocks[0] if selected_blocks else None
 
         #update general buttons
-        Actions.ERRORS_WINDOW_DISPLAY.set_sensitive(not flow_graph.is_valid())
-        Actions.ELEMENT_DELETE.set_sensitive(bool(flow_graph.selected_elements))
-        Actions.BLOCK_PARAM_MODIFY.set_sensitive(bool(selected_block))
-        Actions.BLOCK_ROTATE_CCW.set_sensitive(bool(selected_blocks))
-        Actions.BLOCK_ROTATE_CW.set_sensitive(bool(selected_blocks))
+        Actions.ERRORS_WINDOW_DISPLAY.set_enabled(not flow_graph.is_valid())
+        Actions.ELEMENT_DELETE.set_enabled(bool(flow_graph.selected_elements))
+        Actions.BLOCK_PARAM_MODIFY.set_enabled(bool(selected_block))
+        Actions.BLOCK_ROTATE_CCW.set_enabled(bool(selected_blocks))
+        Actions.BLOCK_ROTATE_CW.set_enabled(bool(selected_blocks))
         #update alignment options
         for act in Actions.BLOCK_ALIGNMENTS:
             if act:
-                act.set_sensitive(len(selected_blocks) > 1)
+                act.set_enabled(len(selected_blocks) > 1)
         #update cut/copy/paste
-        Actions.BLOCK_CUT.set_sensitive(bool(selected_blocks))
-        Actions.BLOCK_COPY.set_sensitive(bool(selected_blocks))
-        Actions.BLOCK_PASTE.set_sensitive(bool(self.clipboard))
+        Actions.BLOCK_CUT.set_enabled(bool(selected_blocks))
+        Actions.BLOCK_COPY.set_enabled(bool(selected_blocks))
+        Actions.BLOCK_PASTE.set_enabled(bool(self.clipboard))
         #update enable/disable/bypass
         can_enable = any(block.state != 'enabled'
                          for block in selected_blocks)
@@ -700,26 +775,26 @@ class Application(Gtk.Application):
             all(block.can_bypass() for block in selected_blocks) and
             any(not block.get_bypassed() for block in selected_blocks)
         )
-        Actions.BLOCK_ENABLE.set_sensitive(can_enable)
-        Actions.BLOCK_DISABLE.set_sensitive(can_disable)
-        Actions.BLOCK_BYPASS.set_sensitive(can_bypass_all)
+        Actions.BLOCK_ENABLE.set_enabled(can_enable)
+        Actions.BLOCK_DISABLE.set_enabled(can_disable)
+        Actions.BLOCK_BYPASS.set_enabled(can_bypass_all)
 
-        Actions.BLOCK_CREATE_HIER.set_sensitive(bool(selected_blocks))
-        Actions.OPEN_HIER.set_sensitive(bool(selected_blocks))
-        Actions.BUSSIFY_SOURCES.set_sensitive(bool(selected_blocks))
-        Actions.BUSSIFY_SINKS.set_sensitive(bool(selected_blocks))
-        Actions.RELOAD_BLOCKS.set_sensitive(True)
-        Actions.FIND_BLOCKS.set_sensitive(True)
+        Actions.BLOCK_CREATE_HIER.set_enabled(bool(selected_blocks))
+        Actions.OPEN_HIER.set_enabled(bool(selected_blocks))
+        Actions.BUSSIFY_SOURCES.set_enabled(bool(selected_blocks))
+        Actions.BUSSIFY_SINKS.set_enabled(bool(selected_blocks))
+        Actions.RELOAD_BLOCKS.enable()
+        Actions.FIND_BLOCKS.enable()
 
         self.update_exec_stop()
 
-        Actions.FLOW_GRAPH_SAVE.set_sensitive(not page.saved)
+        Actions.FLOW_GRAPH_SAVE.set_enabled(not page.saved)
         main.update()
 
         flow_graph.update_selected()
         page.drawing_area.queue_draw()
 
-        return True  # action was handled
+        return True  # Action was handled
 
     def update_exec_stop(self):
         """
@@ -728,6 +803,6 @@ class Application(Gtk.Application):
         """
         page = self.main_window.current_page
         sensitive = page.flow_graph.is_valid() and not page.process
-        Actions.FLOW_GRAPH_GEN.set_sensitive(sensitive)
-        Actions.FLOW_GRAPH_EXEC.set_sensitive(sensitive)
-        Actions.FLOW_GRAPH_KILL.set_sensitive(page.process is not None)
+        Actions.FLOW_GRAPH_GEN.set_enabled(sensitive)
+        Actions.FLOW_GRAPH_EXEC.set_enabled(sensitive)
+        Actions.FLOW_GRAPH_KILL.set_enabled(page.process is not None)
diff --git a/grc/gui/Bars.py b/grc/gui/Bars.py
index 1510e109d2..2a8040f5d5 100644
--- a/grc/gui/Bars.py
+++ b/grc/gui/Bars.py
@@ -1,5 +1,5 @@
 """
-Copyright 2007, 2008, 2009, 2015 Free Software Foundation, Inc.
+Copyright 2007, 2008, 2009, 2015, 2016 Free Software Foundation, Inc.
 This file is part of GNU Radio
 
 GNU Radio Companion is free software; you can redistribute it and/or
@@ -19,306 +19,299 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 
 from __future__ import absolute_import
 
-from gi.repository import Gtk, GObject
+import logging
+
+from gi.repository import Gtk, GObject, Gio, GLib
 
 from . import Actions
 
 
+log = logging.getLogger(__name__)
+
+
+'''
+# Menu/Toolbar Lists:
+#
+# Sub items can be 1 of 3 types
+#  - List    Creates a section within the current menu
+#  - Tuple   Creates a submenu using a string or action as the parent. The child
+#            can be another menu list or an identifier used to call a helper function.
+#  - Action  Appends a new menu item to the current menu
+#
+
+LIST_NAME = [
+    [Action1, Action2], # New section
+    (Action3, [Action4, Action5]), # Submenu with action as parent
+    ("Label", [Action6, Action7]), # Submenu with string as parent
+    ("Label2", "helper") # Submenu with helper function. Calls 'create_helper()'
+]
+'''
+
+
 # The list of actions for the toolbar.
-TOOLBAR_LIST = (
-    (Actions.FLOW_GRAPH_NEW, 'flow_graph_new'),
-    (Actions.FLOW_GRAPH_OPEN, 'flow_graph_recent'),
-    Actions.FLOW_GRAPH_SAVE,
-    Actions.FLOW_GRAPH_CLOSE,
-    None,
-    Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR,
-    Actions.FLOW_GRAPH_SCREEN_CAPTURE,
-    None,
-    Actions.BLOCK_CUT,
-    Actions.BLOCK_COPY,
-    Actions.BLOCK_PASTE,
-    Actions.ELEMENT_DELETE,
-    None,
-    Actions.FLOW_GRAPH_UNDO,
-    Actions.FLOW_GRAPH_REDO,
-    None,
-    Actions.ERRORS_WINDOW_DISPLAY,
-    Actions.FLOW_GRAPH_GEN,
-    Actions.FLOW_GRAPH_EXEC,
-    Actions.FLOW_GRAPH_KILL,
-    None,
-    Actions.BLOCK_ROTATE_CCW,
-    Actions.BLOCK_ROTATE_CW,
-    None,
-    Actions.BLOCK_ENABLE,
-    Actions.BLOCK_DISABLE,
-    Actions.BLOCK_BYPASS,
-    Actions.TOGGLE_HIDE_DISABLED_BLOCKS,
-    None,
-    Actions.FIND_BLOCKS,
-    Actions.RELOAD_BLOCKS,
-    Actions.OPEN_HIER,
-)
+TOOLBAR_LIST = [
+    [(Actions.FLOW_GRAPH_NEW, 'flow_graph_new'), Actions.FLOW_GRAPH_OPEN,
+    (Actions.FLOW_GRAPH_OPEN_RECENT, 'flow_graph_recent'), Actions.FLOW_GRAPH_SAVE, Actions.FLOW_GRAPH_CLOSE],
+    [Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR, Actions.FLOW_GRAPH_SCREEN_CAPTURE],
+    [Actions.BLOCK_CUT, Actions.BLOCK_COPY, Actions.BLOCK_PASTE, Actions.ELEMENT_DELETE],
+    [Actions.FLOW_GRAPH_UNDO, Actions.FLOW_GRAPH_REDO],
+    [Actions.ERRORS_WINDOW_DISPLAY, Actions.FLOW_GRAPH_GEN, Actions.FLOW_GRAPH_EXEC, Actions.FLOW_GRAPH_KILL],
+    [Actions.BLOCK_ROTATE_CCW, Actions.BLOCK_ROTATE_CW],
+    [Actions.BLOCK_ENABLE, Actions.BLOCK_DISABLE, Actions.BLOCK_BYPASS, Actions.TOGGLE_HIDE_DISABLED_BLOCKS],
+    [Actions.FIND_BLOCKS, Actions.RELOAD_BLOCKS, Actions.OPEN_HIER]
+]
 
 
 # The list of actions and categories for the menu bar.
-MENU_BAR_LIST = (
-    (Gtk.Action(name='File', label='_File'), [
-        'flow_graph_new',
-        Actions.FLOW_GRAPH_DUPLICATE,
-        Actions.FLOW_GRAPH_OPEN,
-        'flow_graph_recent',
-        None,
-        Actions.FLOW_GRAPH_SAVE,
-        Actions.FLOW_GRAPH_SAVE_AS,
-        Actions.FLOW_GRAPH_SAVE_A_COPY,
-        None,
-        Actions.FLOW_GRAPH_SCREEN_CAPTURE,
-        None,
-        Actions.FLOW_GRAPH_CLOSE,
-        Actions.APPLICATION_QUIT,
-    ]),
-    (Gtk.Action(name='Edit', label='_Edit'), [
-        Actions.FLOW_GRAPH_UNDO,
-        Actions.FLOW_GRAPH_REDO,
-        None,
-        Actions.BLOCK_CUT,
-        Actions.BLOCK_COPY,
-        Actions.BLOCK_PASTE,
-        Actions.ELEMENT_DELETE,
-        Actions.SELECT_ALL,
-        None,
-        Actions.BLOCK_ROTATE_CCW,
-        Actions.BLOCK_ROTATE_CW,
-        (Gtk.Action(name='Align', label='_Align', tooltip=None, stock_id=None), Actions.BLOCK_ALIGNMENTS),
-        None,
-        Actions.BLOCK_ENABLE,
-        Actions.BLOCK_DISABLE,
-        Actions.BLOCK_BYPASS,
-        None,
-        Actions.BLOCK_PARAM_MODIFY,
-    ]),
-    (Gtk.Action(name='View', label='_View'), [
-        Actions.TOGGLE_BLOCKS_WINDOW,
-        None,
-        Actions.TOGGLE_CONSOLE_WINDOW,
-        Actions.TOGGLE_SCROLL_LOCK,
-        Actions.SAVE_CONSOLE,
-        Actions.CLEAR_CONSOLE,
-        None,
-        Actions.TOGGLE_HIDE_VARIABLES,
-        Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR,
-        Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR_SIDEBAR,
-        None,
-        Actions.TOGGLE_HIDE_DISABLED_BLOCKS,
-        Actions.TOGGLE_AUTO_HIDE_PORT_LABELS,
-        Actions.TOGGLE_SNAP_TO_GRID,
-        Actions.TOGGLE_SHOW_BLOCK_COMMENTS,
-        None,
-        Actions.TOGGLE_SHOW_CODE_PREVIEW_TAB,
-        None,
-        Actions.ERRORS_WINDOW_DISPLAY,
-        Actions.FIND_BLOCKS,
-    ]),
-    (Gtk.Action(name='Run', label='_Run'), [
-        Actions.FLOW_GRAPH_GEN,
-        Actions.FLOW_GRAPH_EXEC,
-        Actions.FLOW_GRAPH_KILL,
-    ]),
-    (Gtk.Action(name='Tools', label='_Tools'), [
-        Actions.TOOLS_RUN_FDESIGN,
-        Actions.FLOW_GRAPH_OPEN_QSS_THEME,
-        None,
-        Actions.TOGGLE_SHOW_FLOWGRAPH_COMPLEXITY,
-        None,
-        Actions.TOOLS_MORE_TO_COME,
-    ]),
-    (Gtk.Action(name='Help', label='_Help'), [
-        Actions.HELP_WINDOW_DISPLAY,
-        Actions.TYPES_WINDOW_DISPLAY,
-        Actions.XML_PARSER_ERRORS_DISPLAY,
-        None,
-        Actions.ABOUT_WINDOW_DISPLAY,
-    ]),
-)
+MENU_BAR_LIST = [
+  ('_File', [
+    [(Actions.FLOW_GRAPH_NEW, 'flow_graph_new'), Actions.FLOW_GRAPH_DUPLICATE,
+     Actions.FLOW_GRAPH_OPEN, (Actions.FLOW_GRAPH_OPEN_RECENT, 'flow_graph_recent')],
+    [Actions.FLOW_GRAPH_SAVE, Actions.FLOW_GRAPH_SAVE_AS, Actions.FLOW_GRAPH_SAVE_COPY],
+    [Actions.FLOW_GRAPH_SCREEN_CAPTURE],
+    [Actions.FLOW_GRAPH_CLOSE, Actions.APPLICATION_QUIT]
+  ]),
+  ('_Edit', [
+    [Actions.FLOW_GRAPH_UNDO, Actions.FLOW_GRAPH_REDO],
+    [Actions.BLOCK_CUT, Actions.BLOCK_COPY, Actions.BLOCK_PASTE, Actions.ELEMENT_DELETE, Actions.SELECT_ALL],
+    [Actions.BLOCK_ROTATE_CCW, Actions.BLOCK_ROTATE_CW, ('_Align', Actions.BLOCK_ALIGNMENTS)],
+    [Actions.BLOCK_ENABLE, Actions.BLOCK_DISABLE, Actions.BLOCK_BYPASS],
+    [Actions.BLOCK_PARAM_MODIFY]
+  ]),
+  ('_View', [
+    [Actions.TOGGLE_BLOCKS_WINDOW],
+    [Actions.TOGGLE_CONSOLE_WINDOW, Actions.TOGGLE_SCROLL_LOCK, Actions.SAVE_CONSOLE, Actions.CLEAR_CONSOLE],
+    [Actions.TOGGLE_HIDE_VARIABLES, Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR, Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR_SIDEBAR],
+    [Actions.TOGGLE_HIDE_DISABLED_BLOCKS, Actions.TOGGLE_AUTO_HIDE_PORT_LABELS, Actions.TOGGLE_SNAP_TO_GRID, Actions.TOGGLE_SHOW_BLOCK_COMMENTS],
+    [Actions.TOGGLE_SHOW_CODE_PREVIEW_TAB],
+    [Actions.ERRORS_WINDOW_DISPLAY, Actions.FIND_BLOCKS],
+  ]),
+  ('_Run', [
+    Actions.FLOW_GRAPH_GEN, Actions.FLOW_GRAPH_EXEC, Actions.FLOW_GRAPH_KILL
+  ]),
+  ('_Tools', [
+    [Actions.TOOLS_RUN_FDESIGN, Actions.FLOW_GRAPH_OPEN_QSS_THEME],
+    [Actions.TOGGLE_SHOW_FLOWGRAPH_COMPLEXITY]
+  ]),
+  ('_Help', [
+      [Actions.HELP_WINDOW_DISPLAY, Actions.TYPES_WINDOW_DISPLAY, Actions.XML_PARSER_ERRORS_DISPLAY],
+      [Actions.ABOUT_WINDOW_DISPLAY]
+  ])]
 
 
 # The list of actions for the context menu.
 CONTEXT_MENU_LIST = [
-    Actions.BLOCK_CUT,
-    Actions.BLOCK_COPY,
-    Actions.BLOCK_PASTE,
-    Actions.ELEMENT_DELETE,
-    None,
-    Actions.BLOCK_ROTATE_CCW,
-    Actions.BLOCK_ROTATE_CW,
-    Actions.BLOCK_ENABLE,
-    Actions.BLOCK_DISABLE,
-    Actions.BLOCK_BYPASS,
-    None,
-    (Gtk.Action(name='More', label='_More'), [
-        Actions.BLOCK_CREATE_HIER,
-        Actions.OPEN_HIER,
-        None,
-        Actions.BUSSIFY_SOURCES,
-        Actions.BUSSIFY_SINKS,
-    ]),
-    Actions.BLOCK_PARAM_MODIFY
+    [Actions.BLOCK_CUT, Actions.BLOCK_COPY, Actions.BLOCK_PASTE, Actions.ELEMENT_DELETE],
+    [Actions.BLOCK_ROTATE_CCW, Actions.BLOCK_ROTATE_CW, Actions.BLOCK_ENABLE, Actions.BLOCK_DISABLE, Actions.BLOCK_BYPASS],
+    [("_More", [
+        [Actions.BLOCK_CREATE_HIER, Actions.OPEN_HIER],
+        [Actions.BUSSIFY_SOURCES, Actions.BUSSIFY_SINKS]]
+    )],
+    [Actions.BLOCK_PARAM_MODIFY],
 ]
 
 
-class SubMenuCreator(object):
+class SubMenuHelper(object):
+    ''' Generates custom submenus for the main menu or toolbar. '''
 
-    def __init__(self, generate_modes, action_handler_callback):
-        self.generate_modes = generate_modes
-        self.action_handler_callback = action_handler_callback
-        self.submenus = []
+    def __init__(self):
+        self.submenus = {}
 
-    def create_submenu(self, action_tuple, item):
-        func = getattr(self, '_fill_' + action_tuple[1] + "_submenu")
-        self.submenus.append((action_tuple[0], func, item))
-        self.refresh_submenus()
+    def build_submenu(self, name, obj, set_func):
+        # Get the correct helper function
+        create_func = getattr(self, "create_{}".format(name))
+        # Save the helper functions for rebuilding the menu later
+        self.submenus[name] = (create_func, obj, set_func)
+        # Actually build the menu
+        set_func(obj, create_func())
 
     def refresh_submenus(self):
-        for action, func, item in self.submenus:
-            try:
-                item.set_property("menu", func(action))
-            except TypeError:
-                item.set_property("submenu", func(action))
-            item.set_property('sensitive', True)
-
-    def callback_adaptor(self, item, action_key):
-        action, key = action_key
-        self.action_handler_callback(action, key)
-
-    def _fill_flow_graph_new_submenu(self, action):
-        """Sub menu to create flow-graph with pre-set generate mode"""
-        menu = Gtk.Menu()
-        for key, name, default in self.generate_modes:
-            if default:
-                item = Actions.FLOW_GRAPH_NEW.create_menu_item()
-                item.set_label(name)
-            else:
-                item = Gtk.MenuItem(name=name, use_underline=False)
-                item.connect('activate', self.callback_adaptor, (action, key))
-            menu.append(item)
-        menu.show_all()
+        for name in self.submenus:
+            create_func, obj, set_func = self.submenus[name]
+            print ("refresh", create_func, obj, set_func)
+            set_func(obj, create_func())
+
+    def create_flow_graph_new(self):
+        """ Different flowgraph types """
+        menu = Gio.Menu()
+        platform = Gtk.Application.get_default().platform
+        generate_modes = platform.get_generate_options()
+        for key, name, default in generate_modes:
+            target = "app.flowgraph.new::{}".format(key)
+            menu.append(name, target)
         return menu
 
-    def _fill_flow_graph_recent_submenu(self, action):
-        """menu showing recent flow-graphs"""
-        menu = Gtk.Menu()
+    def create_flow_graph_recent(self):
+        """ Recent flow graphs """
+
         config = Gtk.Application.get_default().config
         recent_files = config.get_recent_files()
+        menu = Gio.Menu()
         if len(recent_files) > 0:
+            files = Gio.Menu()
             for i, file_name in enumerate(recent_files):
-                item = Gtk.MenuItem(name="%d. %s" % (i+1, file_name), use_underline=False)
-                item.connect('activate', self.callback_adaptor,
-                             (action, file_name))
-                menu.append(item)
-            menu.show_all()
-            return menu
-        return None
+                target = "app.flowgraph.open_recent::{}".format(file_name)
+                files.append(file_name, target)
+            menu.append_section(None, files)
+            #clear = Gio.Menu()
+            #clear.append("Clear recent files", "app.flowgraph.clear_recent")
+            #menu.append_section(None, clear)
+        else:
+            # Show an empty menu
+            menuitem = Gio.MenuItem.new("No items found", "app.none")
+            menu.append_item(menuitem)
+        return menu
 
 
-class Toolbar(Gtk.Toolbar, SubMenuCreator):
-    """The gtk toolbar with actions added from the toolbar list."""
+class MenuHelper(SubMenuHelper):
+    """
+    Recursively builds a menu from a given list of actions.
 
-    def __init__(self, generate_modes, action_handler_callback):
-        """
-        Parse the list of action names in the toolbar list.
-        Look up the action for each name in the action list and add it to the
-        toolbar.
-        """
-        GObject.GObject.__init__(self)
-        self.set_style(Gtk.ToolbarStyle.ICONS)
-        SubMenuCreator.__init__(self, generate_modes, action_handler_callback)
-
-        for action in TOOLBAR_LIST:
-            if isinstance(action, tuple) and isinstance(action[1], str):
-                # create a button with a sub-menu
-                # TODO: Fix later
-                #action[0].set_tool_item_type(Gtk.MenuToolButton)
-                item = action[0].create_tool_item()
-                #self.create_submenu(action, item)
-                #self.refresh_submenus()
-
-            elif action is None:
-                item = Gtk.SeparatorToolItem()
-
-            else:
-                #TODO: Fix later
-                #action.set_tool_item_type(Gtk.ToolButton)
-                item = action.create_tool_item()
-                # this reset of the tooltip property is required
-                # (after creating the tool item) for the tooltip to show
-                action.set_property('tooltip', action.get_property('tooltip'))
-            self.add(item)
-
-
-class MenuHelperMixin(object):
-    """Mixin class to help build menus from the above action lists"""
-
-    def _fill_menu(self, actions, menu=None):
-        """Create a menu from list of actions"""
-        menu = menu or Gtk.Menu()
+    Args:
+     - actions:  List of actions to build the menu
+     - menu:     Current menu being built
+
+    Notes:
+     - Tuple:  Create a new submenu from the parent (1st) and child (2nd) elements
+     - Action: Append to current menu
+     - List:   Start a new section
+    """
+
+    def __init__(self):
+        SubMenuHelper.__init__(self)
+
+    def build_menu(self, actions, menu):
         for item in actions:
             if isinstance(item, tuple):
-                menu_item = self._make_sub_menu(*item)
-            elif isinstance(item, str):
-                menu_item = getattr(self, 'create_' + item)()
-            elif item is None:
-                menu_item = Gtk.SeparatorMenuItem()
-            else:
-                menu_item = item.create_menu_item()
-            menu.append(menu_item)
-        menu.show_all()
-        return menu
-
-    def _make_sub_menu(self, main, actions):
-        """Create a submenu from a main action and a list of actions"""
-        main = main.create_menu_item()
-        main.set_submenu(self._fill_menu(actions))
-        return main
+                # Create a new submenu
+                parent, child = (item[0], item[1])
+
+                # Create the parent
+                label, target = (parent, None)
+                if isinstance(parent, Actions.Action):
+                    label = parent.label
+                    target = "{}.{}".format(parent.prefix, parent.name)
+                menuitem = Gio.MenuItem.new(label, None)
+                if hasattr(parent, "icon_name"):
+                    menuitem.set_icon(Gio.Icon.new_for_string(parent.icon_name))
+
+                # Create the new submenu
+                if isinstance(child, list):
+                    submenu = Gio.Menu()
+                    self.build_menu(child, submenu)
+                    menuitem.set_submenu(submenu)
+                elif isinstance(child, str):
+                    # Child is the name of the submenu to create
+                    def set_func(obj, menu):
+                        obj.set_submenu(menu)
+                    self.build_submenu(child, menuitem, set_func)
+                menu.append_item(menuitem)
+
+            elif isinstance(item, list):
+                # Create a new section
+                section = Gio.Menu()
+                self.build_menu(item, section)
+                menu.append_section(None, section)
+
+            elif isinstance(item, Actions.Action):
+                # Append a new menuitem
+                target = "{}.{}".format(item.prefix, item.name)
+                menuitem = Gio.MenuItem.new(item.label, target)
+                if item.icon_name:
+                    menuitem.set_icon(Gio.Icon.new_for_string(item.icon_name))
+                menu.append_item(menuitem)
+
+
+class ToolbarHelper(SubMenuHelper):
+    """
+     Builds a toolbar from a given list of actions.
+
+    Args:
+     - actions:  List of actions to build the menu
+     - item:     Current menu being built
+
+    Notes:
+     - Tuple:  Create a new submenu from the parent (1st) and child (2nd) elements
+     - Action: Append to current menu
+     - List:   Start a new section
+    """
 
+    def __init__(self):
+        SubMenuHelper.__init__(self)
 
-class MenuBar(Gtk.MenuBar, MenuHelperMixin, SubMenuCreator):
-    """The gtk menu bar with actions added from the menu bar list."""
+    def build_toolbar(self, actions, current):
+        for item in actions:
+            if isinstance(item, list):
+                # Toolbar's don't have sections like menus, so call this function
+                #  recursively with the "section" and just append a separator.
+                self.build_toolbar(item, self)
+                current.insert(Gtk.SeparatorToolItem.new(), -1)
+
+            elif isinstance(item, tuple):
+                parent, child = (item[0], item[1])
+                # Create an item with a submenu
+                # Generate the submenu and add to the item.
+                # Add the item to the toolbar
+                button = Gtk.MenuToolButton.new()
+                # The tuple should be made up of an Action and something.
+                button.set_label(parent.label)
+                button.set_tooltip_text(parent.tooltip)
+                button.set_icon_name(parent.icon_name)
+
+                target = "{}.{}".format(parent.prefix, parent.name)
+                button.set_action_name(target)
+
+                def set_func(obj, menu):
+                    obj.set_menu(Gtk.Menu.new_from_model(menu))
+
+                self.build_submenu(child, button, set_func)
+                current.insert(button, -1)
+
+            elif isinstance(item, Actions.Action):
+                button = Gtk.ToolButton.new()
+                button.set_label(item.label)
+                button.set_tooltip_text(item.tooltip)
+                button.set_icon_name(item.icon_name)
+                target = "{}.{}".format(item.prefix, item.name)
+                button.set_action_name(target)
+                current.insert(button, -1)
+
+
+class Menu(Gio.Menu, MenuHelper):
+    """ Main Menu """
 
-    def __init__(self, generate_modes, action_handler_callback):
-        """
-        Parse the list of submenus from the menubar list.
-        For each submenu, get a list of action names.
-        Look up the action for each name in the action list and add it to the
-        submenu. Add the submenu to the menu bar.
-        """
+    def __init__(self):
         GObject.GObject.__init__(self)
-        SubMenuCreator.__init__(self, generate_modes, action_handler_callback)
-        for main_action, actions in MENU_BAR_LIST:
-            self.append(self._make_sub_menu(main_action, actions))
+        MenuHelper.__init__(self)
 
-    def create_flow_graph_new(self):
-        main = Gtk.ImageMenuItem(label=Gtk.STOCK_NEW)
-        main.set_label(Actions.FLOW_GRAPH_NEW.get_label())
-        func = self._fill_flow_graph_new_submenu
-        self.submenus.append((Actions.FLOW_GRAPH_NEW, func, main))
-        self.refresh_submenus()
-        return main
+        log.debug("Building the main menu")
+        self.build_menu(MENU_BAR_LIST, self)
 
-    def create_flow_graph_recent(self):
-        main = Gtk.ImageMenuItem(label=Gtk.STOCK_OPEN)
-        main.set_label(Actions.FLOW_GRAPH_OPEN_RECENT.get_label())
-        func = self._fill_flow_graph_recent_submenu
-        self.submenus.append((Actions.FLOW_GRAPH_OPEN, func, main))
-        self.refresh_submenus()
-        if main.get_submenu() is None:
-            main.set_property('sensitive', False)
-        return main
 
+class ContextMenu(Gio.Menu, MenuHelper):
+    """ Context menu for the drawing area """
+
+    def __init__(self):
+        GObject.GObject.__init__(self)
+
+        log.debug("Building the context menu")
+        self.build_menu(CONTEXT_MENU_LIST, self)
 
-class ContextMenu(Gtk.Menu, MenuHelperMixin):
-    """The gtk menu with actions added from the context menu list."""
+
+class Toolbar(Gtk.Toolbar, ToolbarHelper):
+    """ The gtk toolbar with actions added from the toolbar list. """
 
     def __init__(self):
+        """
+        Parse the list of action names in the toolbar list.
+        Look up the action for each name in the action list and add it to the
+        toolbar.
+        """
         GObject.GObject.__init__(self)
-        self._fill_menu(CONTEXT_MENU_LIST, self)
+        ToolbarHelper.__init__(self)
+
+        self.set_style(Gtk.ToolbarStyle.ICONS)
+        #self.get_style_context().add_class(Gtk.STYLE_CLASS_PRIMARY_TOOLBAR)
+
+        #SubMenuCreator.__init__(self)
+        self.build_toolbar(TOOLBAR_LIST, self)
diff --git a/grc/gui/Config.py b/grc/gui/Config.py
index c4d395c0b3..6135296660 100644
--- a/grc/gui/Config.py
+++ b/grc/gui/Config.py
@@ -48,7 +48,7 @@ class Config(CoreConfig):
         self.install_prefix = install_prefix
         Constants.update_font_size(self.font_size)
 
-        self.parser = configparser.SafeConfigParser()
+        self.parser = configparser.ConfigParser()
         for section in ['main', 'files_open', 'files_recent']:
             try:
                 self.parser.add_section(section)
diff --git a/grc/gui/Console.py b/grc/gui/Console.py
index d40f300a8a..0ae862493d 100644
--- a/grc/gui/Console.py
+++ b/grc/gui/Console.py
@@ -20,6 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 from __future__ import absolute_import
 
 import os
+import logging
 
 import gi
 gi.require_version('Gtk', '3.0')
@@ -31,9 +32,14 @@ from .Dialogs import TextDisplay, MessageDialogWrapper
 from ..core import Messages
 
 
+log = logging.getLogger(__name__)
+
+
 class Console(Gtk.ScrolledWindow):
     def __init__(self):
         Gtk.ScrolledWindow.__init__(self)
+        log.debug("console()")
+        self.app = Gtk.Application.get_default()
 
         self.text_display = TextDisplay()
 
diff --git a/grc/gui/DrawingArea.py b/grc/gui/DrawingArea.py
index 94dfcf1370..2403fa2844 100644
--- a/grc/gui/DrawingArea.py
+++ b/grc/gui/DrawingArea.py
@@ -23,6 +23,7 @@ from gi.repository import Gtk, Gdk
 
 from .canvas.colors import FLOWGRAPH_BACKGROUND_COLOR
 from . import Constants
+from . import Actions
 
 
 class DrawingArea(Gtk.DrawingArea):
@@ -42,6 +43,7 @@ class DrawingArea(Gtk.DrawingArea):
         Gtk.DrawingArea.__init__(self)
 
         self._flow_graph = flow_graph
+        self.set_property('can_focus', True)
 
         self.zoom_factor = 1.0
         self._update_after_zoom = False
@@ -66,6 +68,11 @@ class DrawingArea(Gtk.DrawingArea):
             # Gdk.EventMask.FOCUS_CHANGE_MASK
         )
 
+        # This may not be the correct place to be handling the user events
+        # Should this be in the page instead?
+        # Or should more of the page functionality move here?
+        self.connect('key_press_event', self._handle_key_press)
+
         # setup drag and drop
         self.drag_dest_set(Gtk.DestDefaults.ALL, [], Gdk.DragAction.COPY)
         self.connect('drag-data-received', self._handle_drag_data_received)
@@ -78,12 +85,14 @@ class DrawingArea(Gtk.DrawingArea):
 
         def _handle_notify_event(widget, event, focus_flag):
             self._focus_flag = focus_flag
+
         self.connect('leave-notify-event', _handle_notify_event, False)
         self.connect('enter-notify-event', _handle_notify_event, True)
         # todo: fix
 #        self.set_flags(Gtk.CAN_FOCUS)  # self.set_can_focus(True)
 #        self.connect('focus-out-event', self._handle_focus_lost_event)
 
+
     ##########################################################################
     # Handlers
     ##########################################################################
@@ -155,6 +164,41 @@ class DrawingArea(Gtk.DrawingArea):
             coordinate=self._translate_event_coords(event),
         )
 
+    def _handle_key_press(self, widget, event):
+        """
+        Handle specific keypresses when the drawing area has focus that
+        triggers actions by the user.
+        """
+        key = event.keyval
+        mod = event.state
+
+        # Setup a map of the accelerator keys to the action to trigger
+        accels = {
+            Gtk.accelerator_parse('d'): Actions.BLOCK_DISABLE,
+            Gtk.accelerator_parse('e'): Actions.BLOCK_ENABLE,
+            Gtk.accelerator_parse('b'): Actions.BLOCK_BYPASS,
+            Gtk.accelerator_parse('c'): Actions.BLOCK_CREATE_HIER,
+            Gtk.accelerator_parse('Up'): Actions.BLOCK_DEC_TYPE,
+            Gtk.accelerator_parse('Down'): Actions.BLOCK_INC_TYPE,
+            Gtk.accelerator_parse('Left'): Actions.BLOCK_ROTATE_CCW,
+            Gtk.accelerator_parse('Right'): Actions.BLOCK_ROTATE_CW,
+            Gtk.accelerator_parse('minus'): Actions.PORT_CONTROLLER_DEC,
+            Gtk.accelerator_parse('plus'): Actions.PORT_CONTROLLER_INC,
+            Gtk.accelerator_parse('Add'): Actions.PORT_CONTROLLER_INC,
+            Gtk.accelerator_parse('Subtract'): Actions.PORT_CONTROLLER_DEC,
+            Gtk.accelerator_parse('Return'): Actions.BLOCK_PARAM_MODIFY,
+            Gtk.accelerator_parse('<Shift>t'): Actions.BLOCK_VALIGN_TOP,
+            Gtk.accelerator_parse('<Shift>m'): Actions.BLOCK_VALIGN_MIDDLE,
+            Gtk.accelerator_parse('<Shift>b'): Actions.BLOCK_VALIGN_BOTTOM,
+            Gtk.accelerator_parse('<Shift>l'): Actions.BLOCK_HALIGN_LEFT,
+            Gtk.accelerator_parse('<Shift>c'): Actions.BLOCK_HALIGN_CENTER,
+            Gtk.accelerator_parse('<Shift>r'): Actions.BLOCK_HALIGN_RIGHT,
+        }
+        # Not sold on this.
+        if (key, mod) in accels:
+            accels[(key, mod)]()
+            return True
+
     def _update_size(self):
         w, h = self._flow_graph.get_extents()[2:]
         self.set_size_request(w * self.zoom_factor + 100, h * self.zoom_factor + 100)
diff --git a/grc/gui/MainWindow.py b/grc/gui/MainWindow.py
index 5bb4c52a07..c13a59a16d 100644
--- a/grc/gui/MainWindow.py
+++ b/grc/gui/MainWindow.py
@@ -35,6 +35,7 @@ from .Notebook import Notebook, Page
 
 from ..core import Messages
 
+
 log = logging.getLogger(__name__)
 
 
@@ -49,7 +50,7 @@ class MainWindow(Gtk.ApplicationWindow):
     CONSOLE = 1
     VARIABLES = 2
 
-    def __init__(self, app, platform, action_handler_callback):
+    def __init__(self, app, platform):
         """
         MainWindow constructor
         Setup the menu, toolbar, flow graph editor notebook, block selection window...
@@ -58,18 +59,29 @@ class MainWindow(Gtk.ApplicationWindow):
         log.debug("__init__()")
 
         self._platform = platform
+        self.app = app
         self.config = platform.config
 
+        # Add all "win" actions to the local
+        win_actions = filter(lambda x: x.startswith("win."), Actions.get_actions())
+        map(lambda x: self.add_action(Actions.actions[x]), win_actions)
+
         # Setup window
         vbox = Gtk.VBox()
         self.add(vbox)
 
         # Create the menu bar and toolbar
         generate_modes = platform.get_generate_options()
-        self.add_accel_group(Actions.get_accel_group())
-        self.menu_bar = Bars.MenuBar(generate_modes, action_handler_callback)
+
+        # This needs to be replaced
+        # Have an option for either the application menu or this menu
+        self.menu_bar = Gtk.MenuBar.new_from_model(Bars.Menu())
         vbox.pack_start(self.menu_bar, False, False, 0)
-        self.tool_bar = Bars.Toolbar(generate_modes, action_handler_callback)
+
+        self.tool_bar = Bars.Toolbar()
+        self.tool_bar.set_hexpand(True)
+        # Show the toolbar
+        self.tool_bar.show()
         vbox.pack_start(self.tool_bar, False, False, 0)
 
         # Main parent container for the different panels
@@ -126,9 +138,7 @@ class MainWindow(Gtk.ApplicationWindow):
             self.left_subpanel.set_position(self.config.variable_editor_position())
 
         self.show_all()
-        self.console.hide()
-        self.vars.hide()
-        self.btwin.hide()
+        log.debug("Main window ready")
 
     ############################################################
     # Event Handlers
@@ -206,7 +216,6 @@ class MainWindow(Gtk.ApplicationWindow):
     def current_page(self, page):
         self.notebook.current_page = page
 
-
     def add_console_line(self, line):
         """
         Place line at the end of the text buffer, then scroll its window all the way down.
diff --git a/grc/gui/Notebook.py b/grc/gui/Notebook.py
index e78b748326..ef08961036 100644
--- a/grc/gui/Notebook.py
+++ b/grc/gui/Notebook.py
@@ -19,6 +19,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 
 from __future__ import absolute_import
 import os
+import logging
 
 from gi.repository import Gtk, Gdk, GObject
 
@@ -28,15 +29,24 @@ from .Constants import MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT
 from .DrawingArea import DrawingArea
 
 
+log = logging.getLogger(__name__)
+
+
 class Notebook(Gtk.Notebook):
     def __init__(self):
         Gtk.Notebook.__init__(self)
-
+        log.debug("notebook()")
+        self.app = Gtk.Application.get_default()
         self.current_page = None
+
         self.set_show_border(False)
         self.set_scrollable(True)
         self.connect('switch-page', self._handle_page_change)
 
+        self.add_events(Gdk.EventMask.SCROLL_MASK)
+        self.connect('scroll-event', self._handle_scroll)
+        self._ignore_consecutive_scrolls = 0
+
     def _handle_page_change(self, notebook, page, page_num):
         """
         Handle a page change. When the user clicks on a new tab,
@@ -51,6 +61,26 @@ class Notebook(Gtk.Notebook):
         self.current_page = self.get_nth_page(page_num)
         Actions.PAGE_CHANGE()
 
+    def _handle_scroll(self, widget, event):
+        # Not sure how to handle this at the moment.
+        natural = True
+        # Slow it down
+        if self._ignore_consecutive_scrolls == 0:
+            if event.direction in (Gdk.ScrollDirection.UP, Gdk.ScrollDirection.LEFT):
+                if natural:
+                    self.prev_page()
+                else:
+                    self.next_page()
+            elif event.direction in (Gdk.ScrollDirection.DOWN, Gdk.ScrollDirection.RIGHT):
+                if natural:
+                    self.next_page()
+                else:
+                    self.prev_page()
+            self._ignore_consecutive_scrolls = 3
+        else:
+            self._ignore_consecutive_scrolls -= 1
+        return False
+
 
 class Page(Gtk.HBox):
     """A page in the notebook."""
@@ -99,20 +129,12 @@ class Page(Gtk.HBox):
         self.scrolled_window = Gtk.ScrolledWindow()
         self.scrolled_window.set_size_request(MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT)
         self.scrolled_window.set_policy(Gtk.PolicyType.ALWAYS, Gtk.PolicyType.ALWAYS)
-        self.scrolled_window.connect('key-press-event', self._handle_scroll_window_key_press)
+
         self.scrolled_window.add(self.drawing_area)
         self.pack_start(self.scrolled_window, True, True, 0)
-
         self.show_all()
 
-    def _handle_scroll_window_key_press(self, widget, event):
-        """forward Ctrl-PgUp/Down to NotebookPage (switch fg instead of horiz. scroll"""
-        is_ctrl_pg = (
-            event.state & Gdk.ModifierType.CONTROL_MASK and
-            event.keyval in (Gdk.KEY_Page_Up, Gdk.KEY_Page_Down)
-        )
-        if is_ctrl_pg:
-            return self.get_parent().event(event)
+
 
     def get_generator(self):
         """
diff --git a/grc/gui/ParamWidgets.py b/grc/gui/ParamWidgets.py
index b56eace402..71cb1b7a7d 100644
--- a/grc/gui/ParamWidgets.py
+++ b/grc/gui/ParamWidgets.py
@@ -25,7 +25,7 @@ from . import Utils
 
 style_provider = Gtk.CssProvider()
 
-style_provider.load_from_data("""
+style_provider.load_from_data(b"""
     #dtype_complex         { background-color: #3399FF; }
     #dtype_real            { background-color: #FF8C69; }
     #dtype_float           { background-color: #FF8C69; }
diff --git a/grc/gui/StateCache.py b/grc/gui/StateCache.py
index b109a1281b..ef260d6091 100644
--- a/grc/gui/StateCache.py
+++ b/grc/gui/StateCache.py
@@ -99,5 +99,5 @@ class StateCache(object):
         """
         Update the undo and redo actions based on the number of next and prev states.
         """
-        Actions.FLOW_GRAPH_REDO.set_sensitive(self.num_next_states != 0)
-        Actions.FLOW_GRAPH_UNDO.set_sensitive(self.num_prev_states != 0)
+        Actions.FLOW_GRAPH_REDO.set_enabled(self.num_next_states != 0)
+        Actions.FLOW_GRAPH_UNDO.set_enabled(self.num_prev_states != 0)
diff --git a/grc/gui/Utils.py b/grc/gui/Utils.py
index 3fffe6dd20..969f3759f2 100644
--- a/grc/gui/Utils.py
+++ b/grc/gui/Utils.py
@@ -21,6 +21,7 @@ from __future__ import absolute_import
 
 from gi.repository import GLib
 import cairo
+import six
 
 from .canvas.colors import FLOWGRAPH_BACKGROUND_COLOR
 from . import Constants
@@ -107,7 +108,10 @@ def encode(value):
     Older versions of glib seg fault if the last byte starts a multi-byte
     character.
     """
-    valid_utf8 = value.decode('utf-8', errors='replace').encode('utf-8')
+    if six.PY2:
+        valid_utf8 = value.decode('utf-8', errors='replace').encode('utf-8')
+    else:
+        valid_utf8 = value
     return GLib.markup_escape_text(valid_utf8)
 
 
diff --git a/grc/gui/VariableEditor.py b/grc/gui/VariableEditor.py
index 484395be8c..e310676420 100644
--- a/grc/gui/VariableEditor.py
+++ b/grc/gui/VariableEditor.py
@@ -254,7 +254,9 @@ class VariableEditor(Gtk.VBox):
         elif key == self.ADD_VARIABLE:
             self.emit('create_new_block', 'variable')
         elif key == self.OPEN_PROPERTIES:
-            Actions.BLOCK_PARAM_MODIFY(self._block)
+            # TODO: This probably isn't working because the action doesn't expect a parameter
+            #Actions.BLOCK_PARAM_MODIFY()
+            pass
         elif key == self.DELETE_BLOCK:
             self.emit('remove_block', self._block.get_id())
         elif key == self.DELETE_CONFIRM:
diff --git a/grc/gui/canvas/param.py b/grc/gui/canvas/param.py
index 2ec99e70d8..b027b7653a 100644
--- a/grc/gui/canvas/param.py
+++ b/grc/gui/canvas/param.py
@@ -105,7 +105,7 @@ class Param(CoreParam):
                 if style < 0:  # Front truncate
                     string = '...' + string[3-max_len:]
                 elif style == 0:  # Center truncate
-                    string = string[:max_len/2 - 3] + '...' + string[-max_len/2:]
+                    string = string[:max_len//2 - 3] + '...' + string[-max_len//2:]
                 elif style > 0:  # Rear truncate
                     string = string[:max_len-3] + '...'
             return string
diff --git a/grc/main.py b/grc/main.py
index 305e8b8f78..224a9b11e8 100755
--- a/grc/main.py
+++ b/grc/main.py
@@ -22,10 +22,6 @@ gi.require_version('Gtk', '3.0')
 gi.require_version('PangoCairo', '1.0')
 from gi.repository import Gtk
 
-from gnuradio import gr
-from .gui.Platform import Platform
-from .gui.Application import Application
-
 
 VERSION_AND_DISCLAIMER_TEMPLATE = """\
 GNU Radio Companion %s
@@ -45,6 +41,7 @@ LOG_LEVELS = {
 
 
 def main():
+    from gnuradio import gr
     parser = argparse.ArgumentParser(
         description=VERSION_AND_DISCLAIMER_TEMPLATE % gr.version())
     parser.add_argument('flow_graphs', nargs='*')
@@ -65,7 +62,8 @@ def main():
     console = logging.StreamHandler()
     console.setLevel(LOG_LEVELS[args.log])
 
-    msg_format = '[%(asctime)s - %(levelname)8s] --- %(message)s (%(filename)s:%(lineno)s)'
+    #msg_format = '[%(asctime)s - %(levelname)8s] --- %(message)s (%(filename)s:%(lineno)s)'
+    msg_format = '[%(levelname)s] %(message)s (%(filename)s:%(lineno)s)'
     date_format = '%I:%M'
     formatter = logging.Formatter(msg_format, datefmt=date_format)
 
@@ -73,8 +71,14 @@ def main():
     console.setFormatter(formatter)
     log.addHandler(console)
 
-    log.debug("Loading platform")
+    log.debug("Running main")
 
+    # Delay importing until the logging is setup
+    # Otherwise, the decorators could not use logging.
+    from .gui.Platform import Platform
+    from .gui.Application import Application
+
+    log.debug("Loading platform")
     platform = Platform(
         version=gr.version(),
         version_parts=(gr.major_version(), gr.api_version(), gr.minor_version()),
-- 
cgit v1.2.3