diff --git a/L10n/en.template b/L10n/en.template
index f5acb377..bf8d022e 100644
--- a/L10n/en.template
+++ b/L10n/en.template
@@ -802,4 +802,7 @@
 "Ships" = "Ships";
 
 /* update.py: Update Available Text; In files: update.py:229; */
-"{NEWVER} is available" = "{NEWVER} is available";
\ No newline at end of file
+"{NEWVER} is available" = "{NEWVER} is available";
+
+/* myNotebook.py: Can't Paste Images or Files in Text; */
+"Cannot paste non-text content." = "Cannot paste non-text content.";
diff --git a/build.py b/build.py
index 1bc96765..2d4ef790 100644
--- a/build.py
+++ b/build.py
@@ -133,7 +133,6 @@ def build() -> None:
                 "distutils",
                 "_markerlib",
                 "optparse",
-                "PIL",
                 "simplejson",
                 "unittest",
                 "doctest",
diff --git a/config/linux.py b/config/linux.py
index 73100800..51a40626 100644
--- a/config/linux.py
+++ b/config/linux.py
@@ -5,6 +5,8 @@ Copyright (c) EDCD, All Rights Reserved
 Licensed under the GNU General Public License.
 See LICENSE file.
 """
+from __future__ import annotations
+
 import os
 import pathlib
 import sys
diff --git a/monitor.py b/monitor.py
index 8364f95b..e7f99543 100644
--- a/monitor.py
+++ b/monitor.py
@@ -63,6 +63,8 @@ elif sys.platform == 'win32':
     GetWindowText = ctypes.windll.user32.GetWindowTextW
     GetWindowText.argtypes = [HWND, LPWSTR, ctypes.c_int]
     GetWindowTextLength = ctypes.windll.user32.GetWindowTextLengthW
+    GetWindowTextLength.argtypes = [ctypes.wintypes.HWND]
+    GetWindowTextLength.restype = ctypes.c_int
 
     GetProcessHandleFromHwnd = ctypes.windll.oleacc.GetProcessHandleFromHwnd
 
diff --git a/myNotebook.py b/myNotebook.py
index 6fa35774..398b2136 100644
--- a/myNotebook.py
+++ b/myNotebook.py
@@ -14,7 +14,12 @@ from __future__ import annotations
 
 import sys
 import tkinter as tk
-from tkinter import ttk
+from tkinter import ttk, messagebox
+from typing import TYPE_CHECKING
+from PIL import ImageGrab
+
+if TYPE_CHECKING:
+    def _(x: str) -> str: return x
 
 # Can't do this with styles on OSX - http://www.tkdocs.com/tutorial/styles.html#whydifficult
 if sys.platform == 'darwin':
@@ -77,7 +82,7 @@ class Label(tk.Label):
     """Custom tk.Label class to fix some display issues."""
 
     def __init__(self, master: ttk.Frame | None = None, **kw):
-        # This format chosen over `sys.platform in (...)` as mypy and friends dont understand that
+        # This format chosen over `sys.platform in (...)` as mypy and friends don't understand that
         if sys.platform in ('darwin', 'win32'):
             kw['foreground'] = kw.pop('foreground', PAGEFG)
             kw['background'] = kw.pop('background', PAGEBG)
@@ -87,7 +92,64 @@ class Label(tk.Label):
         tk.Label.__init__(self, master, **kw)  # Just use tk.Label on all platforms
 
 
-class Entry(sys.platform == 'darwin' and tk.Entry or ttk.Entry):  # type: ignore
+class EntryMenu(ttk.Entry):
+    """Extended entry widget that includes a context menu with Copy, Cut-and-Paste commands."""
+
+    def __init__(self, *args, **kwargs) -> None:
+        super().__init__(*args, **kwargs)
+
+        self.menu = tk.Menu(self, tearoff=False)
+        self.menu.add_command(label="Copy", command=self.copy)
+        self.menu.add_command(label="Cut", command=self.cut)
+        self.menu.add_separator()
+        self.menu.add_command(label="Paste", command=self.paste)
+        self.menu.add_separator()
+        self.menu.add_command(label="Select All", command=self.select_all)
+
+        self.bind("<Button-3>", self.display_popup)
+
+    def display_popup(self, event: tk.Event) -> None:
+        """Display the menu popup."""
+        self.menu.post(event.x_root, event.y_root)
+
+    def select_all(self) -> None:
+        """Select all the text within the Entry."""
+        self.selection_range(0, tk.END)
+        self.focus_set()
+
+    def copy(self) -> None:
+        """Copy the selected Entry text."""
+        if self.selection_present():
+            self.clipboard_clear()
+            self.clipboard_append(self.selection_get())
+
+    def cut(self) -> None:
+        """Cut the selected Entry text."""
+        if self.selection_present():
+            self.copy()
+            self.delete(tk.SEL_FIRST, tk.SEL_LAST)
+
+    def paste(self) -> None:
+        """Paste the selected Entry text."""
+        try:
+            # Attempt to grab an image from the clipboard (apprently also works for files)
+            img = ImageGrab.grabclipboard()
+            if img:
+                # Hijack existing translation, yes it doesn't exactly match here.
+                # LANG: Generic error prefix - following text is from Frontier auth service;
+                messagebox.showwarning(_('Error'),
+                                       _('Cannot paste non-text content.'))  # LANG: Can't Paste Images or Files in Text
+                return
+            text = self.clipboard_get()
+            if self.selection_present() and text:
+                self.delete(tk.SEL_FIRST, tk.SEL_LAST)
+            self.insert(tk.INSERT, text)
+        except tk.TclError:
+            # No text in clipboard or clipboard is not text
+            pass
+
+
+class Entry(sys.platform == 'darwin' and tk.Entry or EntryMenu or ttk.Entry):  # type: ignore
     """Custom t(t)k.Entry class to fix some display issues."""
 
     def __init__(self, master: ttk.Frame | None = None, **kw):
@@ -95,7 +157,7 @@ class Entry(sys.platform == 'darwin' and tk.Entry or ttk.Entry):  # type: ignore
             kw['highlightbackground'] = kw.pop('highlightbackground', PAGEBG)
             tk.Entry.__init__(self, master, **kw)
         else:
-            ttk.Entry.__init__(self, master, **kw)
+            EntryMenu.__init__(self, master, **kw)
 
 
 class Button(sys.platform == 'darwin' and tk.Button or ttk.Button):  # type: ignore
diff --git a/requirements-dev.txt b/requirements-dev.txt
index c6d90c8a..41c3a928 100644
--- a/requirements-dev.txt
+++ b/requirements-dev.txt
@@ -5,7 +5,7 @@ wheel
 # We can't rely on just picking this up from either the base (not venv),
 # or venv-init-time version.  Specify here so that dependabot will prod us
 # about new versions.
-setuptools==69.1.1
+setuptools==69.2.0
 
 # Static analysis tools
 flake8==7.0.0
@@ -20,8 +20,8 @@ flake8-use-fstring==1.4
 
 mypy==1.9.0
 pep8-naming==0.13.3
-safety==2.3.5
-types-requests==2.31.0.20240125
+safety==3.0.1
+types-requests==2.31.0.20240311
 types-pkg-resources==0.1.3
 
 # Code formatting tools
@@ -38,9 +38,9 @@ grip==4.6.2
 py2exe==0.13.0.1; sys_platform == 'win32'
 
 # Testing
-pytest==8.0.2
+pytest==8.1.1
 pytest-cov==4.1.0  # Pytest code coverage support
-coverage[toml]==7.4.1 # pytest-cov dep. This is here to ensure that it includes TOML support for pyproject.toml configs
+coverage[toml]==7.4.4 # pytest-cov dep. This is here to ensure that it includes TOML support for pyproject.toml configs
 coverage-conditional-plugin==0.9.0
 # For manipulating folder permissions and the like.
 pywin32==306; sys_platform == 'win32'
diff --git a/requirements.txt b/requirements.txt
index 75b7fc01..e9d4f58d 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,5 +1,6 @@
 certifi==2024.2.2
 requests==2.31.0
+pillow==10.2.0
 # requests depends on this now ?
 charset-normalizer==2.1.1