diff --git a/Pipfile b/Pipfile
index 579d61263..98e9e2f75 100644
--- a/Pipfile
+++ b/Pipfile
@@ -26,7 +26,6 @@ wheel = "*"
[packages]
pycairo = "1.20.0"
PyGObject = "3.38.0"
-events = "0.4"
argparse = "1.4.0"
rx = "~=3.2"
more-itertools = "~=7.2"
diff --git a/Pipfile.lock b/Pipfile.lock
index 444c87375..05f7cc528 100644
--- a/Pipfile.lock
+++ b/Pipfile.lock
@@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
- "sha256": "bf6b40e37ac055327ede1ff942a50f66fb6f50ea2f875e56e5f6366c73b77a47"
+ "sha256": "9b36de1fcafb41ae1bc1fd84c2f55e12349f11e42a72267f7f310add0623ee9c"
},
"pipfile-spec": 6,
"requires": {
@@ -40,13 +40,6 @@
"index": "pypi",
"version": "==0.6"
},
- "events": {
- "hashes": [
- "sha256:a7286af378ba3e46640ac9825156c93bdba7502174dd696090fdfcd4d80a1abd"
- ],
- "index": "pypi",
- "version": "==0.5"
- },
"importlib-metadata": {
"hashes": [
"sha256:aa18d7378b00b40847790e7c27e11673d7fed219354109d0e7b9e5b25dc3ad26",
diff --git a/fapolicy-analyzer.spec b/fapolicy-analyzer.spec
index 0e15ba81c..01cbd4a61 100644
--- a/fapolicy-analyzer.spec
+++ b/fapolicy-analyzer.spec
@@ -61,7 +61,6 @@ Summary: File Access Policy Analyzer GUI
Requires: python3
Requires: python3-gobject
-Requires: python3-events
Requires: python3-configargparse
Requires: python3-more-itertools
Requires: python3-rx
diff --git a/fapolicy_analyzer/events/__init__.py b/fapolicy_analyzer/events/__init__.py
new file mode 100644
index 000000000..07a62a48c
--- /dev/null
+++ b/fapolicy_analyzer/events/__init__.py
@@ -0,0 +1,25 @@
+# Copyright (c) 2017 by Nicola Iarocci and contributors.
+# Copyright Concurrent Technologies Corporation 2024
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+# -*- coding: utf-8 -*-
+from .events import Events, EventsException
+
+__version__ = '0.4'
+
+__all__ = [
+ Events.__name__,
+ EventsException.__name__,
+]
diff --git a/fapolicy_analyzer/events/events.py b/fapolicy_analyzer/events/events.py
new file mode 100644
index 000000000..49969987f
--- /dev/null
+++ b/fapolicy_analyzer/events/events.py
@@ -0,0 +1,133 @@
+# Copyright (c) 2017 by Nicola Iarocci and contributors.
+# Copyright Concurrent Technologies Corporation 2024
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+# -*- coding: utf-8 -*-
+
+"""
+ Events
+ ~~~~~~
+
+ Implements C#-Style Events.
+
+ Derived from the original work by Zoran Isailovski:
+ http://code.activestate.com/recipes/410686/ - Copyright (c) 2005
+
+ :copyright: (c) 2014-2017 by Nicola Iarocci.
+ :license: BSD, see LICENSE for more details.
+"""
+
+
+class _EventSlot:
+ def __init__(self, name):
+ self.targets = []
+ self.__name__ = name
+
+ def __repr__(self):
+ return "event '%s'" % self.__name__
+
+ def __call__(self, *a, **kw):
+ for f in tuple(self.targets):
+ f(*a, **kw)
+
+ def __iadd__(self, f):
+ self.targets.append(f)
+ return self
+
+ def __isub__(self, f):
+ while f in self.targets:
+ self.targets.remove(f)
+ return self
+
+ def __len__(self):
+ return len(self.targets)
+
+ def __iter__(self):
+ def gen():
+ for target in self.targets:
+ yield target
+ return gen()
+
+ def __getitem__(self, key):
+ return self.targets[key]
+
+
+class EventsException(Exception):
+ pass
+
+
+class Events:
+ """
+ Encapsulates the core to event subscription and event firing, and feels
+ like a "natural" part of the language.
+
+ The class Events is there mainly for 3 reasons:
+
+ - Events (Slots) are added automatically, so there is no need to
+ declare/create them separately. This is great for prototyping. (Note
+ that `__events__` is optional and should primarilly help detect
+ misspelled event names.)
+ - To provide (and encapsulate) some level of introspection.
+ - To "steel the name" and hereby remove unneeded redundancy in a call
+ like:
+
+ xxx.OnChange = event('OnChange')
+ """
+ def __init__(self, events=None, event_slot_cls=_EventSlot):
+ self.__event_slot_cls__ = event_slot_cls
+
+ if events is not None:
+
+ try:
+ for _ in events:
+ break
+ except:
+ raise AttributeError("type object %s is not iterable" %
+ (type(events)))
+ else:
+ self.__events__ = events
+
+ def __getattr__(self, name):
+ if name.startswith('__'):
+ raise AttributeError("type object '%s' has no attribute '%s'" %
+ (self.__class__.__name__, name))
+
+ if hasattr(self, '__events__'):
+ if name not in self.__events__:
+ raise EventsException("Event '%s' is not declared" % name)
+
+ elif hasattr(self.__class__, '__events__'):
+ if name not in self.__class__.__events__:
+ raise EventsException("Event '%s' is not declared" % name)
+
+ self.__dict__[name] = ev = self.__event_slot_cls__(name)
+ return ev
+
+ def __repr__(self):
+ return '<%s.%s object at %s>' % (self.__class__.__module__,
+ self.__class__.__name__,
+ hex(id(self)))
+
+ __str__ = __repr__
+
+ def __len__(self):
+ return len(list(self.__iter__()))
+
+ def __iter__(self):
+ def gen(dictitems=self.__dict__.items()):
+ for attr, val in dictitems:
+ if isinstance(val, self.__event_slot_cls__):
+ yield val
+ return gen()
diff --git a/fapolicy_analyzer/ui/add_file_button.py b/fapolicy_analyzer/ui/add_file_button.py
index 0d6a0f777..cb11e6283 100644
--- a/fapolicy_analyzer/ui/add_file_button.py
+++ b/fapolicy_analyzer/ui/add_file_button.py
@@ -18,7 +18,7 @@
from os import path
import gi
-from events import Events
+from fapolicy_analyzer.events import Events
from fapolicy_analyzer.ui import strings
from fapolicy_analyzer.ui.file_chooser_dialog import FileChooserDialog
diff --git a/fapolicy_analyzer/ui/editable_text_view.py b/fapolicy_analyzer/ui/editable_text_view.py
index d8c3b2a65..42633e504 100644
--- a/fapolicy_analyzer/ui/editable_text_view.py
+++ b/fapolicy_analyzer/ui/editable_text_view.py
@@ -26,7 +26,7 @@
except ImportError:
import importlib_resources as resources
-from events import Events
+from fapolicy_analyzer.events import Events
from fapolicy_analyzer.ui.ui_widget import UIBuilderWidget
gi.require_version("GtkSource", "3.0")
diff --git a/fapolicy_analyzer/ui/object_list.py b/fapolicy_analyzer/ui/object_list.py
index e9f05bafe..ba53af898 100644
--- a/fapolicy_analyzer/ui/object_list.py
+++ b/fapolicy_analyzer/ui/object_list.py
@@ -14,7 +14,7 @@
# along with this program. If not, see .
import gi
-from events import Events
+from fapolicy_analyzer.events import Events
from fapolicy_analyzer.ui.strings import (
FILE_LIST_RULE_ID_HEADER,
diff --git a/fapolicy_analyzer/ui/policy_rules_admin_page.py b/fapolicy_analyzer/ui/policy_rules_admin_page.py
index 6fc42ef64..22fbf55ae 100644
--- a/fapolicy_analyzer/ui/policy_rules_admin_page.py
+++ b/fapolicy_analyzer/ui/policy_rules_admin_page.py
@@ -18,7 +18,7 @@
from typing import Optional, Sequence
import gi
-from events import Events
+from fapolicy_analyzer.events import Events
from fapolicy_analyzer import EventLog, Group, Trust, User
from fapolicy_analyzer.ui.acl_list import ACLList
diff --git a/fapolicy_analyzer/ui/profiler_page.py b/fapolicy_analyzer/ui/profiler_page.py
index 9c9c88d6e..8fad34094 100644
--- a/fapolicy_analyzer/ui/profiler_page.py
+++ b/fapolicy_analyzer/ui/profiler_page.py
@@ -27,7 +27,7 @@
import fapolicy_analyzer.ui.strings as s
import gi
-from events import Events
+from fapolicy_analyzer.events import Events
from fapolicy_analyzer.ui.actions import (
clear_profiler_state,
start_profiling,
diff --git a/fapolicy_analyzer/ui/rules/rules_admin_page.py b/fapolicy_analyzer/ui/rules/rules_admin_page.py
index 47b81d8fb..3d48180e4 100644
--- a/fapolicy_analyzer/ui/rules/rules_admin_page.py
+++ b/fapolicy_analyzer/ui/rules/rules_admin_page.py
@@ -17,7 +17,7 @@
import logging
from typing import Any, Optional, Sequence, Tuple
-from events import Events
+from fapolicy_analyzer.events import Events
from fapolicy_analyzer import Rule, System, reload_profiler_rules
from fapolicy_analyzer.ui.actions import (
diff --git a/fapolicy_analyzer/ui/searchable_list.py b/fapolicy_analyzer/ui/searchable_list.py
index c0750712a..9f64cb2e4 100644
--- a/fapolicy_analyzer/ui/searchable_list.py
+++ b/fapolicy_analyzer/ui/searchable_list.py
@@ -20,7 +20,7 @@
from fapolicy_analyzer.ui.strings import FILTERING_DISABLED_DURING_LOADING_MESSAGE
gi.require_version("Gtk", "3.0")
-from events import Events
+from fapolicy_analyzer.events import Events
from gi.repository import Gtk
from fapolicy_analyzer.ui.loader import Loader
diff --git a/fapolicy_analyzer/ui/stats/stats_view_page.py b/fapolicy_analyzer/ui/stats/stats_view_page.py
index 6fbeca905..87dcf7bc5 100644
--- a/fapolicy_analyzer/ui/stats/stats_view_page.py
+++ b/fapolicy_analyzer/ui/stats/stats_view_page.py
@@ -15,7 +15,7 @@
import gi
-from events import Events
+from fapolicy_analyzer.events import Events
from fapolicy_analyzer.ui.reducers.stats_reducer import StatsStreamState
from fapolicy_analyzer.ui.actions import (
diff --git a/fapolicy_analyzer/ui/system_trust_database_admin.py b/fapolicy_analyzer/ui/system_trust_database_admin.py
index 548952ceb..7854bdabb 100644
--- a/fapolicy_analyzer/ui/system_trust_database_admin.py
+++ b/fapolicy_analyzer/ui/system_trust_database_admin.py
@@ -16,7 +16,7 @@
import logging
from locale import gettext as _
-from events import Events
+from fapolicy_analyzer.events import Events
import fapolicy_analyzer.ui.strings as strings
from fapolicy_analyzer.ui.actions import (
diff --git a/scripts/srpm/fapolicy-analyzer.el9.spec b/scripts/srpm/fapolicy-analyzer.el9.spec
index 74baf6651..448aad0f1 100644
--- a/scripts/srpm/fapolicy-analyzer.el9.spec
+++ b/scripts/srpm/fapolicy-analyzer.el9.spec
@@ -134,7 +134,6 @@ Summary: File Access Policy Analyzer GUI
Requires: python3
Requires: python3-gobject
-Requires: python3-events
Requires: python3-configargparse
Requires: python3-more-itertools
Requires: python3-rx
diff --git a/setup.py b/setup.py
index e44ad867c..388edb60e 100644
--- a/setup.py
+++ b/setup.py
@@ -60,6 +60,7 @@ def get_features():
include=[
"fapolicy_analyzer",
"fapolicy_analyzer.css",
+ "fapolicy_analyzer.events*",
"fapolicy_analyzer.glade",
"fapolicy_analayzer.locale*",
"fapolicy_analyzer.redux*",