示例#1
0
def start_app(engine):
    """ Run the QApplication for the given tk-desktop engine """
    if engine.has_ui:
        from tank.platform.qt import QtGui

        app = QtGui.QApplication([])
        app.setQuitOnLastWindowClosed(False)
        app.setApplicationName("%s Python" % engine.context.project["name"])

        # set default icon
        python_icon = os.path.realpath(
            os.path.join(os.path.dirname(__file__), "..", "..", "resources",
                         "python_icon.png"))
        app.setWindowIcon(QtGui.QIcon(python_icon))

        # Let the engine know we've created the app
        engine.register_qapplication(app)

        # use the toolkit look and feel
        engine._initialize_dark_look_and_feel()

        result = 0
        while True:
            # loop until we are signaled to close, in case an app accidentally quits the app
            result = app.exec_()
            if not engine.connected:
                # we have been signaled to quit rather than waiting for more commands
                break
        return result

    else:  # not engine.has_ui
        # wait for the engine communication channel to shut down
        engine.msg_server.join()
        return 0
示例#2
0
    def __setup_ui(self, callback):
        """
        Starts a QApplication and initializes the UI.
        """
        from tank.platform.qt import QtCore, QtGui

        # we got QT capabilities. Start a QT app and fire the command into the app
        tk_shotgun = self.import_module("tk_shotgun")

        t = tk_shotgun.Task(self, callback)

        # start up our QApp now
        qt_application = QtGui.QApplication([])
        qt_application.setWindowIcon(QtGui.QIcon(self.icon_256))
        self._initialize_dark_look_and_feel()

        # when the QApp starts, initialize our task code
        QtCore.QTimer.singleShot(0, t.run_command)

        # and ask the main app to exit when the task emits its finished signal
        t.finished.connect(qt_application.quit)

        # start the application loop. This will block the process until the task
        # has completed - this is either triggered by a main window closing or
        # byt the finished signal being called from the task class above.
        qt_application.exec_()
示例#3
0
def start_qt_app_and_show_modal(title, engine, widget_class, *args, **kwargs):
    """
    Wrapper around the engine.show_modal() call that first starts a 
    QApplication, then shows the window, then quits the QApplication.
    
    :param title: Window title
    :param engine: Engine object to associate with
    :param widget_class: UI class to create
    :param args/kwargs: parameters to pass to the UI
    
    :returns: The modal dialog return value
    """

    t = QtTask(title, engine, widget_class, args, kwargs)

    # start up our QApp now
    qt_application = QtGui.QApplication([])
    qt_application.setWindowIcon(QtGui.QIcon(engine.icon_256))
    engine._initialize_dark_look_and_feel()

    # when the QApp starts, initialize our task code
    QtCore.QTimer.singleShot(0, t.run_command)

    # and ask the main app to exit when the task emits its finished signal
    t.finished.connect(qt_application.quit)

    # start the application loop. This will block the process until the task
    # has completed - this is either triggered by a main window closing or
    # by the finished signal being called from the task class above.
    qt_application.exec_()

    return t.get_return_data()
示例#4
0
    def execute_command(self, cmd_key, args):
        """
        Executes a given command.
        """
        cb = self.commands[cmd_key]["callback"]

        # make sure the number of parameters to the command are correct
        cb_arg_spec = inspect.getargspec(cb)
        cb_arg_list = cb_arg_spec[0]
        cb_var_args = cb_arg_spec[1]

        if hasattr(cb, "__self__"):
            # first argument to cb will be class instance:
            cb_arg_list = cb_arg_list[1:]

        # ensure the correct/minimum number of arguments have been passed:
        have_expected_args = False
        if cb_var_args:
            have_expected_args = (len(args) >= len(cb_arg_list))
        else:
            have_expected_args = (len(args) == len(cb_arg_list))

        if not have_expected_args:
            expected_args = list(cb_arg_list)
            if cb_var_args:
                expected_args.append("*%s" % cb_var_args)
            raise TankError(
                "Cannot run command! Expected command arguments (%s)" %
                ", ".join(expected_args))

        if not self._has_qt:
            # QT not available - just run the command straight
            return cb(*args)
        else:
            from tank.platform.qt import QtCore, QtGui

            # we got QT capabilities. Start a QT app and fire the command into the app
            tk_shell = self.import_module("tk_shell")
            t = tk_shell.Task(self, cb, args)

            # start up our QApp now
            qt_application = QtGui.QApplication([])
            qt_application.setWindowIcon(QtGui.QIcon(self.icon_256))
            self._initialize_dark_look_and_feel()

            # now we have a working UI!
            self._has_ui = True

            # when the QApp starts, initialize our task code
            QtCore.QTimer.singleShot(0, t.run_command)

            # and ask the main app to exit when the task emits its finished signal
            t.finished.connect(qt_application.quit)

            # start the application loop. This will block the process until the task
            # has completed - this is either triggered by a main window closing or
            # byt the finished signal being called from the task class above.
            qt_application.exec_()
    def run(self, splash=None, version=None):
        """
        Run the engine.

        This method is called from the GUI bootstrap to setup the application
        and to run the Qt event loop.
        """
        self.app_version = version

        # Initialize Qt app
        from tank.platform.qt import QtGui

        app = QtGui.QApplication.instance()
        if app is None:
            app = QtGui.QApplication(sys.argv)

        # update the app icon
        icon = QtGui.QIcon(":tk-desktop/default_systray_icon")
        app.setWindowIcon(icon)

        splash.set_message("Building UI")

        # setup the global look and feel
        self._engine._initialize_dark_look_and_feel()

        # load custom font
        QtGui.QFontDatabase.addApplicationFont(
            ":/tk-desktop/fonts/OpenSans-Bold.ttf")
        QtGui.QFontDatabase.addApplicationFont(
            ":/tk-desktop/fonts/OpenSans-Regular.ttf")
        QtGui.QFontDatabase.addApplicationFont(
            ":/tk-desktop/fonts/OpenSans-CondLight.ttf")
        QtGui.QFontDatabase.addApplicationFont(
            ":/tk-desktop/fonts/OpenSans-Light.ttf")

        # merge in app specific look and feel
        css_file = os.path.join(self._engine.disk_location, "resources",
                                "desktop_dark.css")
        f = open(css_file)
        css = app.styleSheet() + "\n\n" + f.read()
        f.close()
        app.setStyleSheet(css)

        # initialize System Tray
        self.desktop_window = desktop_window.DesktopWindow()

        # make sure we close down our rpc threads
        app.aboutToQuit.connect(self._engine.destroy_engine)

        # hide the splash if it exists
        if splash is not None:
            splash.hide()

        # and run the app
        result = app.exec_()
        return result
示例#6
0
    def post_app_init(self):
        """
        Init that runs after all apps have been loaded.
        """

        tk_houdini = self.import_module("tk_houdini")
        bootstrap = tk_houdini.bootstrap

        if bootstrap.g_temp_env in os.environ:
            if self.has_ui:
                # setup houdini menus
                menu_file = os.path.join(os.environ[bootstrap.g_temp_env],
                                         'MainMenuCommon')

                # as of houdini 12.5 add .xml
                if hou.applicationVersion() > (12, 5, 0):
                    menu_file = menu_file + ".xml"

                menu = tk_houdini.MenuGenerator(self)
                if not os.path.exists(menu_file):
                    # just create the xml for the menus
                    menu.create_menu(menu_file)

                # get map of id to callback
                self._callback_map = menu.callback_map()

            # Figure out the tmp OP Library path for this session
            oplibrary_path = os.environ[bootstrap.g_temp_env].replace(
                "\\", "/")

            # Setup the OTLs that need to be loaded for the Toolkit apps
            self._load_otls(oplibrary_path)

        if self.has_ui:
            # startup Qt
            from tank.platform.qt import QtGui
            from tank.platform.qt import QtCore

            app = QtGui.QApplication.instance()
            if app is None:
                # create the QApplication
                sys.argv[0] = 'Shotgun'
                app = QtGui.QApplication(sys.argv)
                app.setQuitOnLastWindowClosed(False)
                app.setApplicationName(sys.argv[0])

                # tell QT to interpret C strings as utf-8
                utf8 = QtCore.QTextCodec.codecForName("utf-8")
                QtCore.QTextCodec.setCodecForCStrings(utf8)

                # set the stylesheet
                self._initialize_dark_look_and_feel()

            tk_houdini.python_qt_houdini.exec_(app)
def start_app(engine):
    """
    Run the QApplication for the given tk-desktop engine.
    """

    # If we're running the new engine that knows how to start the app, delegate the
    # task to it
    if hasattr(engine, "start_app"):
        return engine.start_app()

    # Otherwise run the legacy code.
    if engine.has_ui:

        # NOTE
        # The following code is meant to run for very old verions of tk-desktop. It
        # should not be edited to support newer features.
        from tank.platform.qt import QtGui

        app = QtGui.QApplication([])
        app.setQuitOnLastWindowClosed(False)
        app.setApplicationName("%s Python" % engine.context.project["name"])

        # set default icon
        python_icon = os.path.realpath(
            os.path.join(
                os.path.dirname(__file__), "..", "..", "resources", "python_icon.png"
            )
        )
        app.setWindowIcon(QtGui.QIcon(python_icon))

        # Let the engine know we've created the app
        engine.register_qapplication(app)

        # use the toolkit look and feel
        engine._initialize_dark_look_and_feel()

        result = 0
        while True:
            # loop until we are signaled to close, in case an app accidentally quits the app
            result = app.exec_()
            if not engine.connected:
                # we have been signaled to quit rather than waiting for more commands
                break
        return result

    else:  # not engine.has_ui
        # wait for the engine communication channel to shut down
        engine.msg_server.join()
        return 0
示例#8
0
    def _initialize_application(self):
        from tank.platform.qt import QtGui

        app = QtGui.QApplication([])

        # We may launch multiple UI apps, do not quit as soon as the last one closes.
        app.setQuitOnLastWindowClosed(False)

        # Make the name pretty for the tray and the task manager.
        app.setApplicationName("%s Python" %
                               self._engine.context.project["name"])
        # set default icon
        python_icon = os.path.join(self._engine.disk_location,
                                   "icon_bg_python.png")
        app.setWindowIcon(QtGui.QIcon(python_icon))

        self.register_qapplication(app)
        # use the toolkit look and feel
        self._engine._initialize_dark_look_and_feel()

        return app
示例#9
0
    def __setup_ui(self, callback):
        """
        Starts a QApplication and initializes the UI.
        """
        from tank.platform.qt import QtCore, QtGui

        # we got QT capabilities. Start a QT app and fire the command into the app
        tk_shotgun = self.import_module("tk_shotgun")

        t = tk_shotgun.Task(self, callback)

        # We need to clear Qt library paths on Linux if KDE is the active environment.
        # This resolves issues with mismatched Qt libraries between the OS and the
        # application being launched if it is a DCC that comes with a bundled Qt.
        if sys.platform == "linux2" and os.environ.get(
                "KDE_FULL_SESSION") is not None:
            QtGui.QApplication.setLibraryPaths([])

        # start up our QApp now
        qt_application = QtGui.QApplication([])
        qt_application.setWindowIcon(QtGui.QIcon(self.icon_256))

        # make sure we have a dark theme
        self._initialize_dark_look_and_feel()

        # now we have a working UI!
        self._has_ui = True

        # when the QApp starts, initialize our task code
        QtCore.QTimer.singleShot(0, t.run_command)

        # and ask the main app to exit when the task emits its finished signal
        t.finished.connect(qt_application.quit)

        # start the application loop. This will block the process until the task
        # has completed - this is either triggered by a main window closing or
        # byt the finished signal being called from the task class above.
        qt_application.exec_()
    def _initialize_application(self):
        from tank.platform.qt import QtGui

        if sgtk.util.is_macos():
            # If we are on Mac with PySide2, then starting a QApplication even with no Windows
            # will steal focus from any currently focused application.
            # So we need to use AppKit if available to stop it from stealing focus.
            try:
                import AppKit

                info = AppKit.NSBundle.mainBundle().infoDictionary()
                info["LSUIElement"] = "1"
            except ImportError:
                # Since AppKit is bundled with the Desktop installer, it's possible we are using
                # an older version of the installer that doesn't contain this package. In which
                # case just move on silently.
                pass

        app = QtGui.QApplication([])

        # We may launch multiple UI apps, do not quit as soon as the last one closes.
        app.setQuitOnLastWindowClosed(False)

        # Make the name pretty for the tray and the task manager.
        app.setApplicationName("%s Python" %
                               self._engine.context.project["name"])
        # set default icon
        python_icon = os.path.join(self._engine.disk_location,
                                   "icon_bg_python.png")
        app.setWindowIcon(QtGui.QIcon(python_icon))

        self.register_qapplication(app)
        # use the toolkit look and feel
        self._engine._initialize_dark_look_and_feel()

        return app
示例#11
0
    def execute_command(self, cmd_key, args):
        """
        Executes a given command.
        """
        cb = self.commands[cmd_key]["callback"]

        # make sure the number of parameters to the command are correct
        cb_arg_spec = inspect.getargspec(cb)
        cb_arg_list = cb_arg_spec[0]
        cb_var_args = cb_arg_spec[1]

        if hasattr(cb, "__self__"):
            # first argument to cb will be class instance:
            cb_arg_list = cb_arg_list[1:]

        # ensure the correct/minimum number of arguments have been passed:
        have_expected_args = False
        if cb_var_args:
            have_expected_args = (len(args) >= len(cb_arg_list))
        else:
            have_expected_args = (len(args) == len(cb_arg_list))

        if not have_expected_args:
            expected_args = list(cb_arg_list)
            if cb_var_args:
                expected_args.append("*%s" % cb_var_args)
            raise TankError(
                "Cannot run command! Expected command arguments (%s)" %
                ", ".join(expected_args))

        if not self._has_qt:
            # QT not available - just run the command straight
            return cb(*args)
        else:
            from tank.platform.qt import QtCore, QtGui

            # we got QT capabilities. Start a QT app and fire the command into the app
            tk_shell = self.import_module("tk_shell")
            t = tk_shell.Task(self, cb, args)

            # start up our QApp now, if none is already running
            qt_application = None
            if not QtGui.qApp:
                # We need to clear Qt library paths on Linux if KDE is the active environment.
                # This resolves issues with mismatched Qt libraries between the OS and the
                # application being launched if it is a DCC that comes with a bundled Qt.
                if sys.platform == "linux2" and os.environ.get(
                        "KDE_FULL_SESSION") is not None:
                    QtGui.QApplication.setLibraryPaths([])

                qt_application = QtGui.QApplication([])
                qt_application.setWindowIcon(QtGui.QIcon(self.icon_256))
                self._initialize_dark_look_and_feel()

            # if we didn't start the QApplication here, let the responsability
            # to run the exec loop and quit to the initial creator of the QApplication
            if qt_application:
                # when the QApp starts, initialize our task code
                QtCore.QTimer.singleShot(0, t.run_command)
                # and ask the main app to exit when the task emits its finished signal
                t.finished.connect(qt_application.quit)

                # start the application loop. This will block the process until the task
                # has completed - this is either triggered by a main window closing or
                # byt the finished signal being called from the task class above.
                qt_application.exec_()
            else:
                # we can run the command now, as the QApp is already started
                t.run_command()
示例#12
0
    def run(self, splash, version, **kwargs):
        """
        Run the engine.

        This method is called from the GUI bootstrap to setup the application
        and to run the Qt event loop.

        :param splash: Splash screen widget we can display messages on. Can be ``None``
        :param version: Version of the Shotgun Desktop installer code.
        :param startup_version: Version of the Desktop Startup code. Can be omitted.
        :param startup_descriptor: Descriptor of the Desktop Startup code. Can be omitted.
        """
        self.app_version = version

        # Startup version will not be set if we have an old installer invoking
        # this engine.
        self.startup_version = kwargs.get("startup_version")
        self.startup_descriptor = kwargs.get("startup_descriptor")
        server = kwargs.get("server")

        # Log usage statistics about the Shotgun Desktop executable and the desktop startup.
        sgtk.util.log_user_attribute_metric("tk-framework-desktopstartup",
                                            self.startup_version)
        sgtk.util.log_user_attribute_metric("Shotgun Desktop version",
                                            self.app_version)
        # If a server is passed down from the desktop startup, it means we won't be using the engine-based
        # websocket server.
        sgtk.util.log_user_attribute_metric("Engine-Websockets",
                                            "no" if server else "yes")

        if self.uses_legacy_authentication():
            self._migrate_credentials()

        # We need to initialize current login
        # We know for sure there is a default user, since either the migration was done
        # or we logged in as an actual user with the new installer.
        human_user = ShotgunAuthenticator(
            # We don't want to get the script user, but the human user, so tell the
            # CoreDefaultsManager manager that we are not interested in the script user. Do not use
            # the regular shotgun_authentication.DefaultsManager to get this user because it will
            # not know about proxy information.
            sgtk.util.CoreDefaultsManager(mask_script_user=True
                                          )).get_default_user()
        # Cache the user so we can refresh the credentials before launching a background process
        self._user = human_user
        # Retrieve the current logged in user information. This will be used when creating
        # event log entries.
        self._current_login = self._engine.sgtk.shotgun.find_one(
            "HumanUser", [["login", "is", human_user.login]], ["id", "login"])

        # Initialize Qt app
        from tank.platform.qt import QtGui

        app = QtGui.QApplication.instance()
        if app is None:
            app = QtGui.QApplication(sys.argv)

        # update the app icon
        icon = QtGui.QIcon(":tk-desktop/default_systray_icon")
        app.setWindowIcon(icon)

        if splash:
            splash.set_message("Building UI")

        # setup the global look and feel
        self._engine._initialize_dark_look_and_feel()

        # load custom font
        QtGui.QFontDatabase.addApplicationFont(
            ":/tk-desktop/fonts/OpenSans-Bold.ttf")
        QtGui.QFontDatabase.addApplicationFont(
            ":/tk-desktop/fonts/OpenSans-Regular.ttf")
        QtGui.QFontDatabase.addApplicationFont(
            ":/tk-desktop/fonts/OpenSans-CondLight.ttf")
        QtGui.QFontDatabase.addApplicationFont(
            ":/tk-desktop/fonts/OpenSans-Light.ttf")

        # merge in app specific look and feel
        css_file = os.path.join(self._engine.disk_location, "resources",
                                "desktop_dark.css")
        f = open(css_file)
        css = app.styleSheet() + "\n\n" + f.read()
        f.close()
        app.setStyleSheet(css)

        # If server is passed down to this method, it means we are running an older version of the
        # desktop startup code, which runs its own browser integration.
        #
        # Sadly, we can't tear down the previous server and restart it. Attempting to tear_down() and
        # instantiate a new server will raise an error.ReactorNotRestartable exception. So we'll start
        # our websocket integration only if there is no server running from the desktop startup.
        # Note that the server argument is set regardless of whether the server launched or crashed,
        # so we have to actually get its value instead of merely checking for existence.
        if server is None:
            # Initialize all of this after the style-sheet has been applied so any prompt are also
            # styled after the Shotgun Desktop's visual-style.
            if splash:
                splash.set_message("Initializing browser integration.")
            try:
                desktop_server_framework = sgtk.platform.get_framework(
                    "tk-framework-desktopserver")
                desktop_server_framework.launch_desktop_server(
                    self._user.host, self._current_login["id"], parent=splash)
            except Exception:
                logger.exception(
                    "Unexpected error while trying to launch the browser integration:"
                )
            else:
                logger.debug("Browser integration was launched successfully.")

        # hide the splash if it exists
        if splash is not None:
            splash.hide()

        # desktop_window needs to import shotgun_authentication globally. However, doing so
        # can cause a crash when running Shotgun Desktop installer 1.02 code. We used to
        # not restart Desktop when upgrading the core, which caused the older version of core
        # to be kept in memory and the newer core to not be used until the app was reloaded.
        #
        # Since pre 0.16 cores didn't have a shotgun_authentication module, we
        # would have crashed if this had been imported at init time. Note that earlier
        # in this method we forcefully restarted the application if we noticed
        # that the core was upgraded without restarting. Which means that if we
        # end up here, it's now because we're in a good state.
        from . import desktop_window

        # initialize System Tray
        self.desktop_window = desktop_window.DesktopWindow()

        # We need for the dialog to exist for messages to get to the UI console.
        if kwargs.get("server") is not None:
            logger.warning(
                "You are running an older version of the Shotgun Desktop which is not fully compatible "
                "with the Shotgun Integrations. Please install the latest version."
            )

        # run the commands that are configured to be executed at startup
        self._run_startup_commands()

        # make sure we close down our rpc threads
        app.aboutToQuit.connect(self._engine.destroy_engine)

        # and run the app
        result = app.exec_()
        return result
示例#13
0
    def post_app_init(self):
        """
        Init that runs after all apps have been loaded.
        """

        if not self.has_ui:
            # no UI. everything after this requires the UI!
            return

        tk_houdini = self.import_module("tk_houdini")
        bootstrap = tk_houdini.bootstrap

        if bootstrap.g_temp_env in os.environ:

            commands = None
            enable_sg_menu = self.get_setting("enable_sg_menu", True)
            enable_sg_shelf = self.get_setting("enable_sg_shelf", True)

            # menu and/or shelf definitions will be written here
            xml_tmp_dir = os.environ[bootstrap.g_temp_env]

            if enable_sg_menu or enable_sg_shelf:

                # get the list of registered commands to supply to the menu
                # and/or shelf. The commands returned are AppCommand objects
                # defined in tk_houdini.ui_generation
                commands = tk_houdini.get_registered_commands(self)

                # populate a callback map. this is a map of command ids to a
                # corresponding callback. these are used by the menu and shelf
                # for executing installed app commands.
                self._callback_map = \
                    dict((cmd.get_id(), cmd.callback) for cmd in commands)

            if commands and enable_sg_menu:

                # setup houdini menus
                menu_file = os.path.join(xml_tmp_dir, "MainMenuCommon")

                # as of houdini 12.5 add .xml
                if hou.applicationVersion() > (12, 5, 0):
                    menu_file = menu_file + ".xml"

                # keep the reference to the menu handler for convenience so
                # that we can access it from the menu scripts when they get
                # ahold of the current engine.
                self._menu = tk_houdini.AppCommandsMenu(self, commands)
                if not os.path.exists(menu_file):
                    # just create the xml for the menus
                    self._menu.create_menu(menu_file)

            if commands and enable_sg_shelf:

                # setup houdini shelf
                self._shelf = tk_houdini.AppCommandsShelf(self, commands)

                # cleans up any old tools on an existing shelf -- just in case.
                # we currently can't programmatically add a shelf to an
                # existing shelf set, so for now we just leave the shelf and
                # add/remove tools.
                self._shelf.destroy_tools()

                shelf_file = os.path.join(xml_tmp_dir, "sg_shelf.xml")
                self._shelf.create_shelf(shelf_file)

            if commands and self._panels_supported():

                # Get the list of registered commands to build panels for. The
                # commands returned are AppCommand objects defined in
                # tk_houdini.ui_generation
                panel_commands = tk_houdini.get_registered_panels(self)

                # expose the wrapped panel method on the engine so that the
                # panels can call it directly
                self.get_wrapped_panel_widget = \
                    tk_houdini.get_wrapped_panel_widget

                if panel_commands:
                    self._panels_file = os.path.join(xml_tmp_dir,
                                                     "sg_panels.pypanel")
                    panels = tk_houdini.AppCommandsPanelHandler(
                        self, commands, panel_commands)
                    panels.create_panels(self._panels_file)

            # Figure out the tmp OP Library path for this session
            oplibrary_path = os.environ[bootstrap.g_temp_env].replace(
                "\\", "/")

            # Setup the OTLs that need to be loaded for the Toolkit apps
            self._load_otls(oplibrary_path)

        # no integrated pyside support. need to run custom event loop. see
        # python/tk_houdini/python_qt_houdini.py
        if not self._integrated_pyside:

            # startup Qt
            from tank.platform.qt import QtGui

            app = QtGui.QApplication.instance()
            if app is None:

                # create the QApplication
                sys.argv[0] = "Shotgun"
                app = QtGui.QApplication(sys.argv)
                app.setQuitOnLastWindowClosed(False)
                app.setApplicationName(sys.argv[0])

            self.log_debug(
                "No integrated PySide. Starting integrated event loop.")
            tk_houdini.python_qt_houdini.exec_(app)

        # tell QT to interpret C strings as utf-8
        from tank.platform.qt import QtCore
        utf8 = QtCore.QTextCodec.codecForName("utf-8")
        QtCore.QTextCodec.setCodecForCStrings(utf8)
        self.log_debug("set utf-8 codec for widget text")

        # Typically we only call this method for engines which don't have a
        # well defined styling. Houdini appears to use stylesheets to handle
        # its styling which it conflicts with the toolkit strategy of using a
        # dark QStyle underneath with additional stylesheets on top, allowing
        # the qss to be minimized. Calling this method applies a global style,
        # palette, and default stylesheet which, in addition to some
        # workarounds when parenting toolkit widgets, allows for the
        # consistent, intended look and feel of the toolkit widgets.
        # Surprisingly, calling this does not seem to have any affect on
        # houdini itself, despite the global nature of the method.
        self._initialize_dark_look_and_feel()