דילוג לתוכן
  • חוקי הפורום
  • פופולרי
  • לא נפתר
  • משתמשים
  • חיפוש גוגל בפורום
  • צור קשר
עיצובים
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • ברירת מחדל (ללא עיצוב (ברירת מחדל))
  • ללא עיצוב (ברירת מחדל)
כיווץ
מתמחים טופ
  1. דף הבית
  2. מחשבים וטכנולוגיה
  3. עזרה הדדית - מחשבים וטכנולוגיה
  4. להורדה | תוכנה קטנה לשליטה בתוכנות מסך מלא וסגירה בכח

להורדה | תוכנה קטנה לשליטה בתוכנות מסך מלא וסגירה בכח

מתוזמן נעוץ נעול הועבר עזרה הדדית - מחשבים וטכנולוגיה
6 פוסטים 3 כותבים 104 צפיות 3 עוקבים
  • מהישן לחדש
  • מהחדש לישן
  • הכי הרבה הצבעות
תגובה
  • תגובה כנושא
התחברו כדי לפרסם תגובה
נושא זה נמחק. רק משתמשים עם הרשאות מתאימות יוכלו לצפות בו.
  • A מנותק
    A מנותק
    AVIVI
    כתב נערך לאחרונה על ידי AVIVI
    #1

    טוב.. מי שלא אוהב תוכנות שנוצרו עם AI נא לדלג לשרשור אחר שכוייח מראש!

    ועכשיו לתוכנה
    דאע"פ דהוי AI הושקעו המון שעות לשפר ולשכלל ולמנוע קריסות ושאר ירקות

    קודם כל כרגיל אין אחריות על כלום!!!

    ועכשיו לאחר שהזהרנו אומר לכם שניסיתי כמה פעמים ולא היתה שום בעייה נתקדם

    אז מאחר שאני מתעסק עם בר אילן ב"ה הרבה ולאחר שהסגירה שלו בעייתית כמו שצויין בשרשור הזה לדוגמא
    וגם הפריע לי בהרבה תוכנות שאי אפשר לעשות אותם במסך מלא (כמו F11)

    בקשתי מהגבינה מלאכותית🧀 שתגבן לי איזו תוכנה קטנה ומועילה לסדר לי קצת את החיים

    ואני חושב שלמי שצריך את זה זה יהיה לעזר רב! ומשום כך אני משתף אתכם בע"ה

    טוב לאחר הברברת נתקדם לתוכנה
    אז אספר לכם שזו תוכנה קלה פשוטה ומהירה (לא אמרתי יציבה... אבל אותי כעת זה ממש מספק)
    יכול להיות שיש עוד תוכנות כאלו ויכול להיות שאין פחות מעניין אותי כי זו תוכנה בול למה שאני צריך

    להורדה - ניהול חלונות.exe כ- 20MB

    צילום מסך והדרכה חביבה שלא נ"ל שכ"כ צריך בספויילר


    נכתב בשביל משתמשי בר אילן שב"ה קצת פחות טכנולוגים
    טוב כשלב ראשון כמובן לוחצים על התוכנה שיורדת
    נפתח המסך הבא
    dfbd9477-41a5-46bc-8ee0-d01ce329cdff-{7DB596BD-442C-409F-92C0-9A820541E0D9}.png
    טוב יש כאן כמה אופציות
    Of course, if you speak English, click the button on the top left.

    1. להוסיף ולהסיר תוכנות
      כרגע בברירת מחדל יש את responsa.exe שזה קובץ ההפעלה של בר אילן אם זה רק מה שאתם צריכים אין לכם מה לעשות עוד והתקדמו לשלב הבא
      במידה שלא ואת רוצים תוכנה אחרת חפשו את קובץ ההפעלה שלה
      לא כ"כ מסובך אתם צריכים לרדת לשורש ולראות מה קובץ ההפעלה
      לחפש נניח את תוכנת וורד בחיפוש>ללחוץ על פתח מיקום קובץ ועל כל דבר שנפתח ללחוץ שוב מקש ימני>פתח מיקום עד שמגיעים לקובץ עם סיומת exe
      לדוגמא קובץ ההפעלה של וורד הוא WINWORD.EXE וכן הלאה
      להכניס לשורה למטה וללחוץ על 'הוסף'

    ועכשיו בפתיחת התוכנה יופיעו הסמלים הבאים

    83fa01cd-3491-4808-9d23-9b35eb8cfd3e-{48BA88C6-0641-430B-B6D4-247BF9721753}.png

    1. וזה דבר חשוב באם אתם לא רוצים שבכל הפעלה של המחשב תאלצו להדליק את התוכנה פשוט לחצו על הכפתור למטה שמדליק את זה באופן אוטומטי בכל הפעלה
      תמיד תוכלו לבטל את זה בלחיצה חוזרת!

    2. באם תרצו לכבות כליל את התוכנה סתאם כי לא בא לכם על התוכנה או כל סיבה אחרת
      היא מסתתרת בצד שמאל למטה
      לחצו כאן
      c814ee4a-9bf1-4ba1-85c8-2107f331069e-image.png
      ואז מקש ימני כאן ויציאה
      c2d05ddf-deeb-4472-a837-01e623d8d87c-{D535266D-2D9F-4D2F-A29D-8B3CC8E94E4B}.png

    שימו לב! שאם אם לוחצים על התוכנה שהיא כבר דלוקה היא נפתחת פעמיים וזה סתם גוזל משאבים תמיד תבדקו בשורת המשימות אם היא פתוחה

    וכמובן כמובן הכל בקוד פתוח למי שרוצה בספויילר ממש כאן
    ומעט פרטים יותר טכניים


    קודם הקוד נו הנחש ההוא פייתון (צריך לכתוב?)

    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% בכדי לא ללכלך..

    ===

    מאד אשמח שמי שימצא עניין וישתמש בתוכנה נישתית זו יודיעני זה ממש משמח והיה זה שכרי!

    מי שמוצא באג טעות או כל דבר אחר בתוכנה זו מוזמן לתקן בשמחה ואין עיני צרה


    נ.ב. אם יש שיפור שאני רוצה להוסיף זה מצב קיוסק שהוספתי ועבד מצויין אולם לאחר שזה סיבך קצת את הפיתוח ונגס מזמני היקר נגיסות גדולות השמטתי את זה
    אני חושב שתוכנה זו היא בסיס מצוין לקיוסק קליל
    אולי אוסיף את זה בהמשך או שמישהו יתנדב בשמחה

    טוב אני חושב שכתבתי המון על תוכנה כה קטנה😊
    אז שיהיה בהצלחה והרבה סייעתא דשמייא אמן.

    עדכונים ובאגים

    כ"ח אדר - כרגע יש באגי אנטיוירוס בהורדה ובעליה לאחר איתחול לעת עתה יש להחריג באנטיוירוס

    בעזרת השם נעשה ונצליח....

    יוסי מחשביםי מטען ניידמ 2 תגובות תגובה אחרונה
    4
    • A AVIVI

      טוב.. מי שלא אוהב תוכנות שנוצרו עם AI נא לדלג לשרשור אחר שכוייח מראש!

      ועכשיו לתוכנה
      דאע"פ דהוי AI הושקעו המון שעות לשפר ולשכלל ולמנוע קריסות ושאר ירקות

      קודם כל כרגיל אין אחריות על כלום!!!

      ועכשיו לאחר שהזהרנו אומר לכם שניסיתי כמה פעמים ולא היתה שום בעייה נתקדם

      אז מאחר שאני מתעסק עם בר אילן ב"ה הרבה ולאחר שהסגירה שלו בעייתית כמו שצויין בשרשור הזה לדוגמא
      וגם הפריע לי בהרבה תוכנות שאי אפשר לעשות אותם במסך מלא (כמו F11)

      בקשתי מהגבינה מלאכותית🧀 שתגבן לי איזו תוכנה קטנה ומועילה לסדר לי קצת את החיים

      ואני חושב שלמי שצריך את זה זה יהיה לעזר רב! ומשום כך אני משתף אתכם בע"ה

      טוב לאחר הברברת נתקדם לתוכנה
      אז אספר לכם שזו תוכנה קלה פשוטה ומהירה (לא אמרתי יציבה... אבל אותי כעת זה ממש מספק)
      יכול להיות שיש עוד תוכנות כאלו ויכול להיות שאין פחות מעניין אותי כי זו תוכנה בול למה שאני צריך

      להורדה - ניהול חלונות.exe כ- 20MB

      צילום מסך והדרכה חביבה שלא נ"ל שכ"כ צריך בספויילר


      נכתב בשביל משתמשי בר אילן שב"ה קצת פחות טכנולוגים
      טוב כשלב ראשון כמובן לוחצים על התוכנה שיורדת
      נפתח המסך הבא
      dfbd9477-41a5-46bc-8ee0-d01ce329cdff-{7DB596BD-442C-409F-92C0-9A820541E0D9}.png
      טוב יש כאן כמה אופציות
      Of course, if you speak English, click the button on the top left.

      1. להוסיף ולהסיר תוכנות
        כרגע בברירת מחדל יש את responsa.exe שזה קובץ ההפעלה של בר אילן אם זה רק מה שאתם צריכים אין לכם מה לעשות עוד והתקדמו לשלב הבא
        במידה שלא ואת רוצים תוכנה אחרת חפשו את קובץ ההפעלה שלה
        לא כ"כ מסובך אתם צריכים לרדת לשורש ולראות מה קובץ ההפעלה
        לחפש נניח את תוכנת וורד בחיפוש>ללחוץ על פתח מיקום קובץ ועל כל דבר שנפתח ללחוץ שוב מקש ימני>פתח מיקום עד שמגיעים לקובץ עם סיומת exe
        לדוגמא קובץ ההפעלה של וורד הוא WINWORD.EXE וכן הלאה
        להכניס לשורה למטה וללחוץ על 'הוסף'

      ועכשיו בפתיחת התוכנה יופיעו הסמלים הבאים

      83fa01cd-3491-4808-9d23-9b35eb8cfd3e-{48BA88C6-0641-430B-B6D4-247BF9721753}.png

      1. וזה דבר חשוב באם אתם לא רוצים שבכל הפעלה של המחשב תאלצו להדליק את התוכנה פשוט לחצו על הכפתור למטה שמדליק את זה באופן אוטומטי בכל הפעלה
        תמיד תוכלו לבטל את זה בלחיצה חוזרת!

      2. באם תרצו לכבות כליל את התוכנה סתאם כי לא בא לכם על התוכנה או כל סיבה אחרת
        היא מסתתרת בצד שמאל למטה
        לחצו כאן
        c814ee4a-9bf1-4ba1-85c8-2107f331069e-image.png
        ואז מקש ימני כאן ויציאה
        c2d05ddf-deeb-4472-a837-01e623d8d87c-{D535266D-2D9F-4D2F-A29D-8B3CC8E94E4B}.png

      שימו לב! שאם אם לוחצים על התוכנה שהיא כבר דלוקה היא נפתחת פעמיים וזה סתם גוזל משאבים תמיד תבדקו בשורת המשימות אם היא פתוחה

      וכמובן כמובן הכל בקוד פתוח למי שרוצה בספויילר ממש כאן
      ומעט פרטים יותר טכניים


      קודם הקוד נו הנחש ההוא פייתון (צריך לכתוב?)

      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% בכדי לא ללכלך..

      ===

      מאד אשמח שמי שימצא עניין וישתמש בתוכנה נישתית זו יודיעני זה ממש משמח והיה זה שכרי!

      מי שמוצא באג טעות או כל דבר אחר בתוכנה זו מוזמן לתקן בשמחה ואין עיני צרה


      נ.ב. אם יש שיפור שאני רוצה להוסיף זה מצב קיוסק שהוספתי ועבד מצויין אולם לאחר שזה סיבך קצת את הפיתוח ונגס מזמני היקר נגיסות גדולות השמטתי את זה
      אני חושב שתוכנה זו היא בסיס מצוין לקיוסק קליל
      אולי אוסיף את זה בהמשך או שמישהו יתנדב בשמחה

      טוב אני חושב שכתבתי המון על תוכנה כה קטנה😊
      אז שיהיה בהצלחה והרבה סייעתא דשמייא אמן.

      עדכונים ובאגים

      כ"ח אדר - כרגע יש באגי אנטיוירוס בהורדה ובעליה לאחר איתחול לעת עתה יש להחריג באנטיוירוס

      יוסי מחשביםי מנותק
      יוסי מחשביםי מנותק
      יוסי מחשבים
      צוות פיקוח
      כתב נערך לאחרונה על ידי
      #2

      @AVIVI
      א. נחמד מאד
      ב. לי זה לא נדלק בכלל, הלכתי למנהל המשימות ראיתי שבכל הדלקה נוצרים 2 תהליכים, מחקתי אחד ואז התוכנה נפתחה.

      A תגובה 1 תגובה אחרונה
      1
      • יוסי מחשביםי יוסי מחשבים

        @AVIVI
        א. נחמד מאד
        ב. לי זה לא נדלק בכלל, הלכתי למנהל המשימות ראיתי שבכל הדלקה נוצרים 2 תהליכים, מחקתי אחד ואז התוכנה נפתחה.

        A מנותק
        A מנותק
        AVIVI
        כתב נערך לאחרונה על ידי AVIVI
        #3

        @יוסי-מחשבים
        תודה!
        מוזר מה שקרה לך
        ניסתי בשני מחשבים ועל הפעם הראשונה עבד
        אולי לחצת פעמיים?

        בעזרת השם נעשה ונצליח....

        יוסי מחשביםי תגובה 1 תגובה אחרונה
        0
        • A AVIVI

          @יוסי-מחשבים
          תודה!
          מוזר מה שקרה לך
          ניסתי בשני מחשבים ועל הפעם הראשונה עבד
          אולי לחצת פעמיים?

          יוסי מחשביםי מנותק
          יוסי מחשביםי מנותק
          יוסי מחשבים
          צוות פיקוח
          כתב נערך לאחרונה על ידי
          #4

          @AVIVI כתב בלהורדה | תוכנה קטנה לשליטה בתוכנות מסך מלא וסגירה בכח:

          ניסתי בשני מחשבים ועל הפעם הראשונה עבד
          אולי לחצת פעמיים?

          לא לחצתי פעמיים, ניסיתי בשני מחשבים ובשניהם כנ"ל.

          A תגובה 1 תגובה אחרונה
          0
          • יוסי מחשביםי יוסי מחשבים

            @AVIVI כתב בלהורדה | תוכנה קטנה לשליטה בתוכנות מסך מלא וסגירה בכח:

            ניסתי בשני מחשבים ועל הפעם הראשונה עבד
            אולי לחצת פעמיים?

            לא לחצתי פעמיים, ניסיתי בשני מחשבים ובשניהם כנ"ל.

            A מנותק
            A מנותק
            AVIVI
            כתב נערך לאחרונה על ידי
            #5

            @יוסי-מחשבים ח"ו שחשדתי בך ללחוץ פעמיים סתם
            הרי ביודעי ומכירי קאמינא על הידע הרב שיש לך ועל העזרה שלך לי אישית ולהרבה אנשים כאן הרבה פעמים בחפץ לב ובנדיבות ושמחה ועל כך אני מודה לך

            וכשכתבתי התכוונתי לשאר האנשים שמשום שהתוכנה נפתחת מעט לאט הם לוחצים פעם שנייה ובאמת היא נפתחת פעמיים כמו שכתבתי בסוף המדריך

            האם כוונתך למה שמופיע בתמונה הזו?
            c214c243-6066-4d4e-bf87-36487fb755eb-image.png
            כי אם כן לא ראיתי בזה שום בעיה זה עבד לי עם שני התהליכים הללו מצויין ולא הוזקקתי לכבות אחד מהם

            ובא נאמר אם יש באג כלשהו אתה תדע לסדר אותו יותר טוב ממני...😉

            בעזרת השם נעשה ונצליח....

            תגובה 1 תגובה אחרונה
            0
            • A AVIVI

              טוב.. מי שלא אוהב תוכנות שנוצרו עם AI נא לדלג לשרשור אחר שכוייח מראש!

              ועכשיו לתוכנה
              דאע"פ דהוי AI הושקעו המון שעות לשפר ולשכלל ולמנוע קריסות ושאר ירקות

              קודם כל כרגיל אין אחריות על כלום!!!

              ועכשיו לאחר שהזהרנו אומר לכם שניסיתי כמה פעמים ולא היתה שום בעייה נתקדם

              אז מאחר שאני מתעסק עם בר אילן ב"ה הרבה ולאחר שהסגירה שלו בעייתית כמו שצויין בשרשור הזה לדוגמא
              וגם הפריע לי בהרבה תוכנות שאי אפשר לעשות אותם במסך מלא (כמו F11)

              בקשתי מהגבינה מלאכותית🧀 שתגבן לי איזו תוכנה קטנה ומועילה לסדר לי קצת את החיים

              ואני חושב שלמי שצריך את זה זה יהיה לעזר רב! ומשום כך אני משתף אתכם בע"ה

              טוב לאחר הברברת נתקדם לתוכנה
              אז אספר לכם שזו תוכנה קלה פשוטה ומהירה (לא אמרתי יציבה... אבל אותי כעת זה ממש מספק)
              יכול להיות שיש עוד תוכנות כאלו ויכול להיות שאין פחות מעניין אותי כי זו תוכנה בול למה שאני צריך

              להורדה - ניהול חלונות.exe כ- 20MB

              צילום מסך והדרכה חביבה שלא נ"ל שכ"כ צריך בספויילר


              נכתב בשביל משתמשי בר אילן שב"ה קצת פחות טכנולוגים
              טוב כשלב ראשון כמובן לוחצים על התוכנה שיורדת
              נפתח המסך הבא
              dfbd9477-41a5-46bc-8ee0-d01ce329cdff-{7DB596BD-442C-409F-92C0-9A820541E0D9}.png
              טוב יש כאן כמה אופציות
              Of course, if you speak English, click the button on the top left.

              1. להוסיף ולהסיר תוכנות
                כרגע בברירת מחדל יש את responsa.exe שזה קובץ ההפעלה של בר אילן אם זה רק מה שאתם צריכים אין לכם מה לעשות עוד והתקדמו לשלב הבא
                במידה שלא ואת רוצים תוכנה אחרת חפשו את קובץ ההפעלה שלה
                לא כ"כ מסובך אתם צריכים לרדת לשורש ולראות מה קובץ ההפעלה
                לחפש נניח את תוכנת וורד בחיפוש>ללחוץ על פתח מיקום קובץ ועל כל דבר שנפתח ללחוץ שוב מקש ימני>פתח מיקום עד שמגיעים לקובץ עם סיומת exe
                לדוגמא קובץ ההפעלה של וורד הוא WINWORD.EXE וכן הלאה
                להכניס לשורה למטה וללחוץ על 'הוסף'

              ועכשיו בפתיחת התוכנה יופיעו הסמלים הבאים

              83fa01cd-3491-4808-9d23-9b35eb8cfd3e-{48BA88C6-0641-430B-B6D4-247BF9721753}.png

              1. וזה דבר חשוב באם אתם לא רוצים שבכל הפעלה של המחשב תאלצו להדליק את התוכנה פשוט לחצו על הכפתור למטה שמדליק את זה באופן אוטומטי בכל הפעלה
                תמיד תוכלו לבטל את זה בלחיצה חוזרת!

              2. באם תרצו לכבות כליל את התוכנה סתאם כי לא בא לכם על התוכנה או כל סיבה אחרת
                היא מסתתרת בצד שמאל למטה
                לחצו כאן
                c814ee4a-9bf1-4ba1-85c8-2107f331069e-image.png
                ואז מקש ימני כאן ויציאה
                c2d05ddf-deeb-4472-a837-01e623d8d87c-{D535266D-2D9F-4D2F-A29D-8B3CC8E94E4B}.png

              שימו לב! שאם אם לוחצים על התוכנה שהיא כבר דלוקה היא נפתחת פעמיים וזה סתם גוזל משאבים תמיד תבדקו בשורת המשימות אם היא פתוחה

              וכמובן כמובן הכל בקוד פתוח למי שרוצה בספויילר ממש כאן
              ומעט פרטים יותר טכניים


              קודם הקוד נו הנחש ההוא פייתון (צריך לכתוב?)

              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% בכדי לא ללכלך..

              ===

              מאד אשמח שמי שימצא עניין וישתמש בתוכנה נישתית זו יודיעני זה ממש משמח והיה זה שכרי!

              מי שמוצא באג טעות או כל דבר אחר בתוכנה זו מוזמן לתקן בשמחה ואין עיני צרה


              נ.ב. אם יש שיפור שאני רוצה להוסיף זה מצב קיוסק שהוספתי ועבד מצויין אולם לאחר שזה סיבך קצת את הפיתוח ונגס מזמני היקר נגיסות גדולות השמטתי את זה
              אני חושב שתוכנה זו היא בסיס מצוין לקיוסק קליל
              אולי אוסיף את זה בהמשך או שמישהו יתנדב בשמחה

              טוב אני חושב שכתבתי המון על תוכנה כה קטנה😊
              אז שיהיה בהצלחה והרבה סייעתא דשמייא אמן.

              עדכונים ובאגים

              כ"ח אדר - כרגע יש באגי אנטיוירוס בהורדה ובעליה לאחר איתחול לעת עתה יש להחריג באנטיוירוס

              מטען ניידמ מנותק
              מטען ניידמ מנותק
              מטען נייד
              כתב נערך לאחרונה על ידי
              #6

              @AVIVI 👏 👏 👏 👏 👏 👏 👏

              תגובה 1 תגובה אחרונה
              1

              • התחברות

              • אין לך חשבון עדיין? הרשמה

              • התחברו או הירשמו כדי לחפש.
              • פוסט ראשון
                פוסט אחרון
              0
              • חוקי הפורום
              • פופולרי
              • לא נפתר
              • משתמשים
              • חיפוש גוגל בפורום
              • צור קשר