Source code for eg.Core

# -*- coding: utf-8 -*-
#
# This file is part of EventGhost.
# Copyright © 2005-2016 EventGhost Project <http://www.eventghost.org/>
#
# EventGhost is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 2 of the License, or (at your option)
# any later version.
#
# EventGhost is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with EventGhost. If not, see <http://www.gnu.org/licenses/>.

"""
.. attribute:: globals

    :class:`eg.Bunch` instance, that holds all global variables used by
    PythonCommand actions. PythonScripts (and all other code) can access
    these globals through :obj:`eg.globals`.


.. attribute:: event

    Instance of the :class:`eg.EventGhostEvent` instance, that is currently
    been processed.

.. autofunction:: eg.DummyFunc
"""

import asyncore
import locale
import os
import socket
import sys
import threading
import time
import wx
from os.path import exists, join

# Local imports
import eg
import Init

eg.useTreeItemGUID = False

Init.InitPathsAndBuiltins()

eg.CORE_PLUGIN_GUIDS = (
    "{9D499A2C-72B6-40B0-8C8C-995831B10BB4}",  # "EventGhost"
    "{A21F443B-221D-44E4-8596-E1ED7100E0A4}",  # "System"
    "{E974D074-B0A3-4D0C-BBD1-992475DDD69D}",  # "Window"
    "{6B1751BF-F94E-4260-AB7E-64C0693FD959}",  # "Mouse"
)

eg.ID_TEST = wx.NewId()
eg.mainDir = eg.Cli.mainDir

eg.revision = 2000  # Deprecated
eg.startupArguments = eg.Cli.args
eg.debugLevel = eg.startupArguments.debugLevel
eg.systemEncoding = locale.getdefaultlocale()[1]
eg.document = None
eg.mainFrame = None
eg.result = None
eg.plugins = eg.Bunch()
eg.globals = eg.Bunch()
eg.globals.eg = eg
eg.event = None
eg.eventTable = {}
eg.eventString = ""
eg.notificationHandlers = {}
eg.programCounter = None
eg.programReturnStack = []
eg.indent = 0
eg.pluginList = []
eg.mainThread = threading.currentThread()
eg.stopExecutionFlag = False
eg.lastFoundWindows = []
eg.currentItem = None
eg.actionGroup = eg.Bunch()
eg.actionGroup.items = []
eg.GUID = eg.GUID()

def _CommandEvent():
    """Generate new (CmdEvent, Binder) tuple
        e.g. MooCmdEvent, EVT_MOO = EgCommandEvent()
    """
    evttype = wx.NewEventType()

    class _Event(wx.PyCommandEvent):
        def __init__(self, id, **kw):
            wx.PyCommandEvent.__init__(self, evttype, id)
            self.__dict__.update(kw)
            if not hasattr(self, "value"):
                self.value = None

        def GetValue(self):
            return self.value

        def SetValue(self, value):
            self.value = value

    return _Event, wx.PyEventBinder(evttype, 1)

eg.CommandEvent = _CommandEvent
eg.ValueChangedEvent, eg.EVT_VALUE_CHANGED = eg.CommandEvent()

eg.pyCrustFrame = None
eg.dummyAsyncoreDispatcher = None

from eg.WinApi.Dynamic import GetCurrentProcessId  # NOQA
eg.processId = GetCurrentProcessId()
Init.InitPil()

class Exception(Exception):
    def __unicode__(self):
        try:
            return "\n".join([unicode(arg) for arg in self.args])
        except UnicodeDecodeError:
            return "\n".join([str(arg).decode('mbcs') for arg in self.args])


class StopException(Exception):
    pass


class HiddenAction:
    pass


def Bind(notification, listener):
    if notification not in eg.notificationHandlers:
        notificationHandler = eg.NotificationHandler()
        eg.notificationHandlers[notification] = notificationHandler
    else:
        notificationHandler = eg.notificationHandlers[notification]
    notificationHandler.listeners.append(listener)

def CallWait(func, *args, **kwargs):
    result = [None]
    event = threading.Event()

    def CallWaitWrapper():
        try:
            result[0] = func(*args, **kwargs)
        finally:
            event.set()

    wx.CallAfter(CallWaitWrapper)
    event.wait()
    return result[0]

def DummyFunc(*dummyArgs, **dummyKwargs):
    """
    Just a do-nothing-function, that accepts arbitrary arguments.
    """
    pass

[docs]def Exit(): """ Sometimes you want to quickly exit a PythonScript, because you don't want to build deeply nested if-structures for example. eg.Exit() will exit your PythonScript immediately. (Note: This is actually a sys.exit() but will not exit EventGhost, because the SystemExit exception is catched for a PythonScript.) """ sys.exit()
def HasActiveHandler(eventstring): for eventHandler in eg.eventTable.get(eventstring, []): obj = eventHandler while obj: if not obj.isEnabled: break obj = obj.parent else: return True return False def MessageBox(message, caption=eg.APP_NAME, style=wx.OK, parent=None): if parent is None: style |= wx.STAY_ON_TOP dialog = eg.MessageDialog(parent, message, caption, style) result = dialog.ShowModal() dialog.Destroy() return result def Notify(notification, value=None): if notification in eg.notificationHandlers: for listener in eg.notificationHandlers[notification].listeners: listener(value) # pylint: disable-msg=W0613
[docs]def RegisterPlugin( name = None, description = None, kind = "other", author = "[unknown author]", version = "[unknown version]", icon = None, canMultiLoad = False, createMacrosOnAdd = False, url = None, help = None, guid = None, **kwargs ): """ Registers information about a plugin to EventGhost. :param name: should be a short descriptive string with the name of the plugin. :param description: a short description of the plugin. :param kind: gives a hint about the category the plugin belongs to. It should be a string with a value out of ``"remote"`` (for remote receiver plugins), ``"program"`` (for program control plugins), ``"external"`` (for plugins that control external hardware) or ``"other"`` (if none of the other categories match). :param author: can be set to the name or a list of names of the developer(s) of the plugin. :param version: can be set to a version string. :param icon: can be a base64 encoded image for the plugin. If ``icon == None``, an "icon.png" will be used if it exists in the plugin folder. :param canMultiLoad: set this to ``True``, if a configuration can have more than one instance of this plugin. :param createMacrosOnAdd: if set to ``True``, when adding the plugin, EventGhost will ask the user, if he/she wants to add a folder with all actions of this plugin to his/her configuration. :param url: displays a clickable link in the plugin info dialog. :param help: a longer description and/or additional information for the plugin. Will be added to 'description'. :param guid: will help EG to identify your plugin, so there are no name clashes with other plugins that accidentally might have the same name and will later ease the update of plugins. :param \*\*kwargs: just to consume unknown parameters, to make the call backward compatible. """ pass
# pylint: enable-msg=W0613 def RestartAsyncore(): """ Informs the asyncore loop of a new socket to handle. """ oldDispatcher = eg.dummyAsyncoreDispatcher dispatcher = asyncore.dispatcher() dispatcher.create_socket(socket.AF_INET, socket.SOCK_STREAM) eg.dummyAsyncoreDispatcher = dispatcher if oldDispatcher: oldDispatcher.close() if oldDispatcher is None: # create a global asyncore loop thread threading.Thread(target=asyncore.loop, name="AsyncoreThread").start() def RunProgram(): eg.stopExecutionFlag = False del eg.programReturnStack[:] while eg.programCounter is not None: programCounter = eg.programCounter item, idx = programCounter item.Execute() if eg.programCounter == programCounter: # program counter has not changed. Ask the parent for the next # item. if isinstance(item.parent, eg.MacroItem): eg.programCounter = item.parent.GetNextChild(idx) else: eg.programCounter = None while eg.programCounter is None and eg.programReturnStack: # we have no next item in this level. So look in the return # stack if any return has to be executed eg.indent -= 2 item, idx = eg.programReturnStack.pop() eg.programCounter = item.parent.GetNextChild(idx) eg.indent = 0
[docs]def StopMacro(ignoreReturn=False): """ Instructs EventGhost to stop executing the current macro after the current action (thus the PythonScript or PythonCommand) has finished. """ eg.programCounter = None if ignoreReturn: del eg.programReturnStack[:]
def Unbind(notification, listener): eg.notificationHandlers[notification].listeners.remove(listener) def Wait(secs, raiseException=True): while secs > 0.0: if eg.stopExecutionFlag: if raiseException: raise eg.StopException("Execution interrupted by the user.") else: return False if secs > 0.1: time.sleep(0.1) else: time.sleep(secs) secs -= 0.1 return True # now assign all the functions above to `eg` eg.Bind = Bind eg.CallWait = CallWait eg.DummyFunc = DummyFunc eg.Exception = Exception eg.Exit = Exit eg.HasActiveHandler = HasActiveHandler eg.HiddenAction = HiddenAction eg.MessageBox = MessageBox eg.Notify = Notify eg.RegisterPlugin = RegisterPlugin eg.RestartAsyncore = RestartAsyncore eg.RunProgram = RunProgram eg.StopException = StopException eg.StopMacro = StopMacro eg.Unbind = Unbind eg.Wait = Wait eg.messageReceiver = eg.MainMessageReceiver() eg.app = eg.App() # we can't import the Icons module earlier, because wx.App must exist import Icons # NOQA eg.Icons = Icons eg.log = eg.Log() eg.Print = eg.log.Print eg.PrintError = eg.log.PrintError eg.PrintNotice = eg.log.PrintNotice eg.PrintTraceback = eg.log.PrintTraceback eg.PrintDebugNotice = eg.log.PrintDebugNotice eg.PrintWarningNotice = eg.log.PrintWarningNotice eg.PrintStack = eg.log.PrintStack eg.config = eg.Config() eg.debugLevel = int(eg.config.logDebug) or eg.debugLevel def TracebackHook(tType, tValue, traceback): eg.log.PrintTraceback(excInfo=(tType, tValue, traceback)) sys.excepthook = TracebackHook eg.colour = eg.Colour() if eg.startupArguments.isMain and not eg.startupArguments.translate: eg.text = eg.Text(eg.config.language) else: eg.text = eg.Text('en_EN') eg.actionThread = eg.ActionThread() eg.eventThread = eg.EventThread() eg.pluginManager = eg.PluginManager() eg.scheduler = eg.Scheduler() eg.TriggerEvent = eg.eventThread.TriggerEvent eg.TriggerEnduringEvent = eg.eventThread.TriggerEnduringEvent from eg.WinApi.SendKeys import SendKeysParser # NOQA eg.SendKeys = SendKeysParser() setattr(eg, "PluginClass", eg.PluginBase) setattr(eg, "ActionClass", eg.ActionBase) eg.taskBarIcon = eg.TaskBarIcon( eg.startupArguments.isMain and eg.config.showTrayIcon and not eg.startupArguments.translate and not eg.startupArguments.install and not eg.startupArguments.pluginFile ) eg.SetProcessingState = eg.taskBarIcon.SetProcessingState eg.wit = None eg.socketSever = None eg.Init = Init eg.Init.Init()