#!python # -*- mode: python; Encoding: utf-8; coding: utf-8 -*- # Last updated: <2022/08/14 02:04:06 +0900> """ Screensaver sample by using pygame Windows10 x64 21H2 + Python 3.8.10 64bit. require library * pygame 1.9.6 (pygame 2.x.x is not work) * pywin32 304 * pyinstaller 5.3 """ import ctypes import datetime import math import os import sys import time import win32api import win32event import win32gui import win32security import winerror DBG = False IMG_NAME = "resources/ball_64x64.png" PREVIEW_BG_IMG = "resources/preview_bg.png" PREVIEW_LOGO_IMG = "resources/preview_logo.png" APPLI_NAME = "screensaver sample by using pygame" VER_NUM = "0.0.1" MUTEX_NAME_FILLSCR = "screensaver_pygame_fullscr" MUTEX_NAME_CONFIG = "screensaver_pygame_config" MUTEX_NAME_PREVIEW = "screensaver_pygame_preview" def resource_path(filename): """Get resource file path.""" if hasattr(sys, "_MEIPASS"): # use PyInstaller base_dir = sys._MEIPASS else: base_dir = os.path.abspath(".") return os.path.join(base_dir, filename) def full_screen(screen): """drawing pygame window.""" # invisivle mouse cursor pygame.mouse.set_visible(False) # load image img = pygame.image.load(resource_path(IMG_NAME)).convert() img.set_colorkey(img.get_at((0, 0)), pygame.RLEACCEL) # initialize work scrw, scrh = screen.get_width(), screen.get_height() x, y = scrw / 2, scrh / 2 dx = float(scrw) / (60 * 2) dy = float(scrh) / (60 * 3) clock = pygame.time.Clock() counter = 0 looping = True # main loop while looping: # check key, mouse for event in pygame.event.get(): if event.type == pygame.QUIT: looping = False if event.type == pygame.KEYUP: # any key up looping = False if event.type == pygame.MOUSEMOTION: # move mouse if counter >= 120: looping = False if not looping: break # update sprite position w, h = img.get_width(), img.get_height() x += dx y += dy if x <= (w / 2) or x >= scrw - (w / 2): dx *= -1 if y <= (h / 2) or y >= scrh - (h / 2): dy *= -1 # clear bg screen.fill((16, 16, 16)) # draw sprite px, py = int(x - (w / 2)), int(y - (h / 2)) screen.blit(img, (px, py)) counter += 1 pygame.display.flip() clock.tick(60) # visible mouse cursor pygame.mouse.set_visible(True) def preview(screen): frames = 360 * 2 bgimg = pygame.image.load(resource_path(PREVIEW_BG_IMG)).convert() logoimg = pygame.image.load(resource_path(PREVIEW_LOGO_IMG)).convert() logoimg.set_colorkey(logoimg.get_at((0, 0)), pygame.RLEACCEL) clock = pygame.time.Clock() ang = 0 looping = True for i in range(frames): for event in pygame.event.get(): if event.type == pygame.QUIT: looping = False if event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE: looping = False if not looping: break scrw, scrh = screen.get_width(), screen.get_height() screen.fill((100, 150, 200)) iw, ih = bgimg.get_width(), bgimg.get_height() px = int((scrw - iw) / 2) py = int((scrh - ih) / 2) screen.blit(bgimg, (px, py)) iw, ih = logoimg.get_width(), logoimg.get_height() px = int((scrw - iw) / 2) py = int((scrh * 0.15) * math.sin(math.radians(ang)) + (scrh / 2) - (ih / 2)) screen.blit(logoimg, (px, py)) ang += 3 pygame.display.flip() clock.tick(60) def get_window_size(hwnd): """Get window size.""" rect = win32gui.GetWindowRect(hwnd) x0, y0, x1, y1 = rect[0], rect[1], rect[2], rect[3] return ((x1 - x0), (y1 - y0)) def msg_box(msg, title): """Display MessageBox by Windows API.""" user32 = ctypes.WinDLL("user32") # user32.MessageBoxW.restype = ctypes.c_int32 # user32.MessageBoxW.argtypes = (ctypes.c_void_p, ctypes.c_wchar_p, # ctypes.c_wchar_p, ctypes.c_uint32) user32.MessageBoxW(0, msg, title, 0x00000040) def write_log(s): global DBG if DBG: desktop_dir = os.path.expanduser('~/Desktop') log_file = os.path.join(desktop_dir, "temp.log.txt") dt_now = datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S") with open(log_file, 'a') as f: f.write("[%s] %s\n" % (dt_now, s)) def get_mutex(name): sa = win32security.SECURITY_ATTRIBUTES() sa.SECURITY_DESCRIPTOR.SetSecurityDescriptorDacl(True, None, False) mtx = win32event.CreateMutex(sa, False, name) err = win32api.GetLastError() if not mtx or err == winerror.ERROR_ALREADY_EXISTS: return (mtx, False) return (mtx, True) def close_mutex(mtx): global cmdopt if mtx: # win32event.ReleaseMutex(mtx) # win32api.CloseHandle(mtx) mtx.Close() write_log("%s : Close mutex. Exit." % cmdopt) # ---------------------------------------- # parse commandline option kind = "None" hwnd = 0 if len(sys.argv) >= 2: s = sys.argv[1][0:2].lower() if s == "/p": kind = "preview" hwnd = int(sys.argv[2]) elif s == "/c": kind = "config" elif s == "/s": kind = "fullscreen" cmdopt = " ".join(sys.argv) if kind == "config": # ---------------------------------------- # config / setting mtx, success = get_mutex(MUTEX_NAME_CONFIG) if not success: # Process exists write_log("%s : %s already exists. Exit." % (cmdopt, MUTEX_NAME_CONFIG)) sys.exit(0) # new process write_log("%s : New process." % cmdopt) msg_box("%s\nver.%s" % (APPLI_NAME, VER_NUM), "Information") close_mutex(mtx) sys.exit() if kind == "preview": # ---------------------------------------- # preview mtx, success = get_mutex(MUTEX_NAME_PREVIEW) if not success: write_log("%s : %s already exists. Exit." % (cmdopt, MUTEX_NAME_PREVIEW)) sys.exit(0) os.environ['SDL_VIDEODRIVER'] = 'windib' if hwnd != 0: # set SDL_WINDOWID os.environ['SDL_WINDOWID'] = str(hwnd) wdw_size = get_window_size(hwnd) write_log("Windows size: %d x %d" % (wdw_size)) else: wdw_size = (152, 112) write_log("%s : New process. hwnd = %d , Wdw size = %d x %d" % (cmdopt, hwnd, wdw_size[0], wdw_size[1])) import pygame # nopep8 pygame.init() screen = pygame.display.set_mode(wdw_size) preview(screen) pygame.quit() close_mutex(mtx) sys.exit() # ---------------------------------------- # full screen mtx, success = get_mutex(MUTEX_NAME_FILLSCR) if not success: # Process exists write_log("%s : %s already exists. Exit." % (cmdopt, MUTEX_NAME_FILLSCR)) sys.exit(0) # New process write_log("%s : New process." % cmdopt) import pygame # nopep8 pygame.init() screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN) full_screen(screen) pygame.quit() close_mutex(mtx) sys.exit()