קודם הקוד נו הנחש ההוא פייתון (צריך לכתוב?)
import tkinter as tk
from tkinter import messagebox, ttk
import sys, os, json, threading, time
# הגדרות לפי משתמש
USER_NAME = os.getlogin()
TEMP_DIR = os.environ.get('TEMP', os.getcwd())
CONFIG_FILE = os.path.join(TEMP_DIR, f"win_helper_{USER_NAME}.json")
# תמיכת נתיב נכנס לקבצי משאבים כשהבנייה ב-PyInstaller
def resource_path(relative_path):
try:
base_path = sys._MEIPASS
except Exception:
base_path = os.path.abspath(".")
return os.path.join(base_path, relative_path)
ICON_PATH = resource_path("app_icon.ico")
try:
import win32gui, win32con, win32api, win32process, winreg
import psutil
from PIL import Image, ImageDraw
import pystray
from pystray import MenuItem as item
except ImportError:
pass
# מילון שפות
LANGS = {
"he": {
"title": "ניהול חלונות (עברית)",
"p_label": "תוכנות במעקב:",
"add_btn": "הוסף",
"rem_btn": "הסר נבחר",
"help_btn": "הוראות",
"startup_on": "הפעל אוטומטית עם המחשב",
"startup_off": "בטל הפעלה אוטומטית",
"lang_btn": "Switch to English",
"help_text": "1. גרור את הפס האפור כדי להזיז את הכפתורים.\n2. כפתור ⛶ הופך למסך מלא.\n3. הסמל יעלם כשתהיה במסך מלא ויחזור כשתצא.\n4. ניתן לעבור חופשי בין תוכנות (Alt+Tab).",
"help_title": "הוראות שימוש",
"added": "נוסף בהצלחה",
"process_name": "שם תהליך (EXE)"
},
"en": {
"title": "Window Manager (English)",
"p_label": "Tracked Applications:",
"add_btn": "Add",
"rem_btn": "Remove Selected",
"help_btn": "Instructions",
"startup_on": "Run at Startup",
"startup_off": "Disable Startup",
"lang_btn": "החלףלעברית",
"help_text": "1. Drag the gray bar to move buttons.\n2. Use ⛶ for Fullscreen.\n3. Icons hide in Fullscreen and return when window is normal.\n4. Free switching between apps (Alt+Tab).",
"help_title": "Instructions",
"added": "Added successfully",
"process_name": "Process Name (EXE)"
}
}
def load_config():
if os.path.exists(CONFIG_FILE):
with open(CONFIG_FILE, "r", encoding="utf-8") as f:
try: return json.load(f)
except: pass
return {"apps": ["responsa.exe"], "lang": "he"}
def save_config(config):
with open(CONFIG_FILE, "w", encoding="utf-8") as f:
json.dump(config, f)
class FloatingButtons:
def __init__(self, target_hwnd, manager):
self.target_hwnd = target_hwnd
self.manager = manager
self.root = tk.Toplevel()
self.root.overrideredirect(True)
self.root.attributes("-topmost", True)
self.root.attributes("-alpha", 0.75)
# מסגרת
self.main_frame = tk.Frame(self.root, bg="#1a1a1a", bd=1)
self.main_frame.pack()
# ידית גרירה
self.drag_handle = tk.Frame(self.main_frame, bg="#505050", width=12, cursor="fleur")
self.drag_handle.pack(side="left", fill="y")
self.drag_handle.bind("<Button-1>", self.start_move)
self.drag_handle.bind("<B1-Motion>", self.do_move)
self.btn_frame = tk.Frame(self.main_frame, bg="#1a1a1a")
self.btn_frame.pack(side="left", padx=2, pady=2)
btn_style = {"bg": "#1a1a1a", "fg": "white", "relief": "flat", "font": ("Segoe UI Symbol", 9), "width": 4}
# כפתור מסך מלא
self.btn_full = tk.Button(self.btn_frame, text="⛶", command=self.toggle_fullscreen, **btn_style)
self.btn_full.pack(side="left", padx=1)
# כפתור סגירה
self.btn_close = tk.Button(self.btn_frame, text="✕", command=self.kill_target, **btn_style)
self.btn_close.configure(fg="#ff5555")
self.btn_close.pack(side="left", padx=1)
self.fullscreen_data = None
self.offset_x = 240
self.offset_y = 10
self.update_position()
def start_move(self, event):
self._start_x = event.x
self._start_y = event.y
def do_move(self, event):
x = self.root.winfo_pointerx() - self._start_x
y = self.root.winfo_pointery() - self._start_y
self.root.geometry(f"+{x}+{y}")
rect = win32gui.GetWindowRect(self.target_hwnd)
self.offset_x = rect[2] - x
self.offset_y = y - rect[1]
def is_target_fullscreen(self):
try:
rect = win32gui.GetWindowRect(self.target_hwnd)
screen_w = win32api.GetSystemMetrics(win32con.SM_CXSCREEN)
screen_h = win32api.GetSystemMetrics(win32con.SM_CYSCREEN)
# אם החלון בגודל המסך בדיוק וחסר לו מסגרת (WS_POPUP)
style = win32gui.GetWindowLong(self.target_hwnd, win32con.GWL_STYLE)
return (rect[2]-rect[0] >= screen_w and rect[3]-rect[1] >= screen_h and not (style & win32con.WS_CAPTION))
except: return False
def update_position(self):
if not win32gui.IsWindow(self.target_hwnd):
self.root.destroy()
return
try:
fg = win32gui.GetForegroundWindow()
active = (fg == self.target_hwnd or fg == self.root.winfo_id())
# הסתרה אם התוכנה במסך מלא (שלה או שלנו)
if self.is_target_fullscreen() or not active:
self.root.withdraw()
else:
self.root.deiconify()
rect = win32gui.GetWindowRect(self.target_hwnd)
x = rect[2] - self.offset_x
y = rect[1] + self.offset_y
self.root.geometry(f"+{x}+{y}")
except: pass
self.root.after(50, self.update_position)
def toggle_fullscreen(self):
hwnd = self.target_hwnd
if not self.fullscreen_data:
style = win32gui.GetWindowLong(hwnd, win32con.GWL_STYLE)
rect = win32gui.GetWindowRect(hwnd)
self.fullscreen_data = (style, rect)
win32gui.SetWindowLong(hwnd, win32con.GWL_STYLE, win32con.WS_POPUP | win32con.WS_VISIBLE)
mon = win32api.GetMonitorInfo(win32api.MonitorFromWindow(hwnd))['Monitor']
win32gui.SetWindowPos(hwnd, win32con.HWND_TOP, mon[0], mon[1],
mon[2]-mon[0], mon[3]-mon[1], win32con.SWP_FRAMECHANGED)
# לצאת ממסך מלא בלחיצת ESC דרך חוט חיצוני
threading.Thread(target=self.esc_monitor, daemon=True).start()
else: self.exit_fullscreen()
def esc_monitor(self):
while self.fullscreen_data:
if win32api.GetAsyncKeyState(win32con.VK_ESCAPE):
self.root.after(0, self.exit_fullscreen)
break
time.sleep(0.1)
def exit_fullscreen(self):
if self.fullscreen_data:
style, rect = self.fullscreen_data
win32gui.SetWindowLong(self.target_hwnd, win32con.GWL_STYLE, style)
win32gui.SetWindowPos(self.target_hwnd, win32con.HWND_NOTOPMOST, rect[0], rect[1],
rect[2]-rect[0], rect[3]-rect[1], win32con.SWP_FRAMECHANGED)
win32gui.ShowWindow(self.target_hwnd, win32con.SW_MAXIMIZE)
self.fullscreen_data = None
def kill_target(self):
try:
_, pid = win32process.GetWindowThreadProcessId(self.target_hwnd)
handle = win32api.OpenProcess(win32con.PROCESS_TERMINATE, False, pid)
win32api.TerminateProcess(handle, -1)
win32api.CloseHandle(handle)
except: pass
class ManagerApp:
def __init__(self, root):
self.root = root
self.config = load_config()
self.active_overlays = {}
self.setup_ui()
self.running = True
threading.Thread(target=self.scan_loop, daemon=True).start()
threading.Thread(target=self.run_tray, daemon=True).start()
def setup_ui(self):
l = LANGS[self.config["lang"]]
is_rtl = (self.config["lang"] == "he")
self.root.title(l["title"])
self.root.geometry("450x500")
self.root.protocol('WM_DELETE_WINDOW', self.hide)
# איקון חלון התוכנה (taskbar) - ניסיון ראשון
try:
self.root.iconbitmap(ICON_PATH)
except Exception:
try:
icon = tk.PhotoImage(file=ICON_PATH)
self.root.iconphoto(False, icon)
except Exception:
pass
for widget in self.root.winfo_children(): widget.destroy()
main = ttk.Frame(self.root, padding=20)
main.pack(fill="both", expand=True)
# כותרת ושפה
top_f = ttk.Frame(main)
top_f.pack(fill="x")
ttk.Button(top_f, text=l["lang_btn"], command=self.toggle_lang).pack(side="left")
tk.Label(main, text=l["p_label"], font=("Segoe UI", 12, "bold")).pack(pady=10)
# רשימה
self.tree = ttk.Treeview(main, columns=("n"), show="headings", height=8)
self.tree.heading("n", text=l["process_name"])
self.tree.pack(fill="both", expand=True)
self.refresh_tree()
# הוספה
add_f = ttk.Frame(main)
add_f.pack(fill="x", pady=10)
self.new_entry = ttk.Entry(add_f, justify="center")
self.new_entry.pack(side="right" if is_rtl else "left", fill="x", expand=True, padx=5)
self.new_entry.insert(0, "responsa.exe")
ttk.Button(add_f, text=l["add_btn"], command=self.add_item).pack(side="left" if is_rtl else "right")
# כפתורים
btn_f = ttk.Frame(main)
btn_f.pack(fill="x")
ttk.Button(btn_f, text=l["rem_btn"], command=self.remove_item).pack(side="right" if is_rtl else "left", fill="x", expand=True, padx=2)
ttk.Button(btn_f, text=l["help_btn"], command=self.show_help).pack(side="left" if is_rtl else "right", fill="x", expand=True, padx=2)
self.start_btn = ttk.Button(main, text="...", command=self.toggle_startup)
self.start_btn.pack(fill="x", pady=10)
self.update_startup_ui()
def toggle_lang(self):
self.config["lang"] = "en" if self.config["lang"] == "he" else "he"
save_config(self.config)
self.setup_ui()
def show_help(self):
l = LANGS[self.config["lang"]]
messagebox.showinfo(l["help_title"], l["help_text"])
def refresh_tree(self):
for i in self.tree.get_children(): self.tree.delete(i)
for a in self.config.get("apps", []): self.tree.insert("", "end", values=(a,))
def add_item(self):
n = self.new_entry.get().lower().strip()
if n and n not in self.config["apps"]:
self.config["apps"].append(n)
save_config(self.config)
self.refresh_tree()
def remove_item(self):
sel = self.tree.selection()
if sel:
name = self.tree.item(sel[0])['values'][0]
self.config["apps"].remove(name)
save_config(self.config)
self.refresh_tree()
def update_startup_ui(self):
l = LANGS[self.config["lang"]]
try:
key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, r"Software\Microsoft\Windows\CurrentVersion\Run", 0, winreg.KEY_READ)
winreg.QueryValueEx(key, "WindowHelper")
winreg.CloseKey(key)
self.start_btn.configure(text=l["startup_off"])
self.startup_active = True
except:
self.start_btn.configure(text=l["startup_on"])
self.startup_active = False
def toggle_startup(self):
path = r"Software\Microsoft\Windows\CurrentVersion\Run"
if not self.startup_active:
key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, path, 0, winreg.KEY_SET_VALUE)
winreg.SetValueEx(key, "WindowHelper", 0, winreg.REG_SZ, sys.executable)
winreg.CloseKey(key)
else:
key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, path, 0, winreg.KEY_SET_VALUE)
try: winreg.DeleteValue(key, "WindowHelper")
except: pass
winreg.CloseKey(key)
self.update_startup_ui()
def scan_loop(self):
while self.running:
def callback(hwnd, _):
if win32gui.IsWindowVisible(hwnd):
try:
_, pid = win32process.GetWindowThreadProcessId(hwnd)
name = psutil.Process(pid).name().lower()
if name in self.config["apps"] and hwnd not in self.active_overlays and pid != os.getpid():
self.root.after(0, lambda: self.active_overlays.update({hwnd: FloatingButtons(hwnd, self)}))
except: pass
win32gui.EnumWindows(callback, None)
time.sleep(1.0)
def hide(self): self.root.withdraw()
def show(self): self.root.after(0, self.root.deiconify)
def run_tray(self):
img = Image.open(ICON_PATH) if os.path.exists(ICON_PATH) else Image.new('RGB', (64, 64), (0, 120, 215))
icon = pystray.Icon("winhelper", img, "Window Helper", (item('Settings / הגדרות', self.show), item('Exit / יציאה', lambda i: self.stop(i))))
icon.run()
def stop(self, i):
self.running = False
i.stop()
self.root.after(0, self.root.destroy)
if __name__ == "__main__":
root = tk.Tk()
app = ManagerApp(root)
root.mainloop()
הקובץ apps_config.json להגדרות התוכנה נמצא בתקיית %temp% בכדי לא ללכלך..
===