-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathLinux_Minecraft_clock.py
More file actions
130 lines (107 loc) · 4.45 KB
/
Copy pathLinux_Minecraft_clock.py
File metadata and controls
130 lines (107 loc) · 4.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
import tkinter as tk
from PIL import Image, ImageTk
import datetime
import os
import sys
IS_WINDOWS = sys.platform.startswith("win")
if IS_WINDOWS:
import ctypes
import win32gui
import win32con
TOTAL_IMAGES = 63
IMAGES_PATH = "frames"
ICON_FILENAME = "icon.png" # Use a PNG icon for cross-platform support
def resource_path(relative_path):
"""Get absolute path to resource, works for dev and PyInstaller"""
base_path = getattr(sys, '_MEIPASS', os.path.abspath("."))
return os.path.join(base_path, relative_path)
def set_win_taskbar_icon(window, icon_path):
"""Force taskbar + Alt+Tab icon (replaces feather) using WinAPI"""
hwnd = ctypes.windll.user32.GetParent(window.winfo_id())
if os.path.exists(icon_path):
hicon = ctypes.windll.user32.LoadImageW(
0, icon_path, 1, 0, 0, 0x00000010 # IMAGE_ICON, LR_LOADFROMFILE
)
if hicon:
ctypes.windll.user32.SendMessageW(hwnd, 0x80, 1, hicon) # small icon
ctypes.windll.user32.SendMessageW(hwnd, 0x80, 0, hicon) # big icon
def minutes_since_noon(hour, minute):
if hour < 12:
hour += 24
return (hour - 12) * 60 + minute
def get_image_index(hour, minute):
minutes = minutes_since_noon(hour, minute)
index = int(minutes // (720 / (TOTAL_IMAGES / 2))) % TOTAL_IMAGES
return index
class MinecraftClockApp(tk.Tk):
def __init__(self):
super().__init__()
# Configure window
self.geometry("300x300+100+100")
self.title("Minecraft Clock")
self.configure(bg="white")
self.wm_attributes("-topmost", True)
if IS_WINDOWS:
# Windows-specific settings
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(u"minecraft.clock.app")
icon_path = resource_path(ICON_FILENAME)
set_win_taskbar_icon(self, icon_path)
self.wm_attributes("-transparentcolor", "white")
self.after(100, self.set_taskbar_window)
else:
# Linux/Mac icon setting
icon_path = resource_path(ICON_FILENAME)
if os.path.exists(icon_path):
try:
icon_img = tk.PhotoImage(file=icon_path)
self.iconphoto(False, icon_img)
except Exception as e:
print(f"Failed to load icon: {e}")
# Label to show image
self.label = tk.Label(self, bg="white")
self.label.pack(fill="both", expand=True)
# Enable dragging
self.bind("<ButtonPress-1>", self.start_move)
self.bind("<B1-Motion>", self.do_move)
# Right-click to exit
self.bind("<Button-3>", lambda e: self.destroy())
# Load image and update regularly
self.update_image()
self.after(10000, self.periodic_update)
def set_taskbar_window(self):
if not IS_WINDOWS:
return
hwnd = ctypes.windll.user32.GetParent(self.winfo_id())
style = win32gui.GetWindowLong(hwnd, win32con.GWL_STYLE)
style &= ~win32con.WS_OVERLAPPEDWINDOW
style |= win32con.WS_POPUP | win32con.WS_VISIBLE
win32gui.SetWindowLong(hwnd, win32con.GWL_STYLE, style)
exStyle = win32gui.GetWindowLong(hwnd, win32con.GWL_EXSTYLE)
exStyle |= win32con.WS_EX_APPWINDOW
exStyle &= ~win32con.WS_EX_TOOLWINDOW
win32gui.SetWindowLong(hwnd, win32con.GWL_EXSTYLE, exStyle)
win32gui.SetWindowPos(hwnd, win32con.HWND_TOPMOST, 100, 100, 300, 300,
win32con.SWP_FRAMECHANGED | win32con.SWP_SHOWWINDOW)
def update_image(self):
now = datetime.datetime.now()
idx = get_image_index(now.hour, now.minute)
frame_path = resource_path(os.path.join(IMAGES_PATH, f"frame_{idx}.png"))
if os.path.exists(frame_path):
img = Image.open(frame_path).resize((300, 300), Image.LANCZOS)
self.tk_img = ImageTk.PhotoImage(img)
self.label.configure(image=self.tk_img)
else:
self.label.configure(text=f"Missing frame_{idx}.png", image='', bg='white')
def periodic_update(self):
self.update_image()
self.after(10000, self.periodic_update)
def start_move(self, event):
self._x = event.x
self._y = event.y
def do_move(self, event):
x = self.winfo_pointerx() - self._x
y = self.winfo_pointery() - self._y
self.geometry(f"+{x}+{y}")
if __name__ == "__main__":
app = MinecraftClockApp()
app.mainloop()