pyloid 0.20.2.dev2__py3-none-any.whl → 0.22.0.dev1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
pyloid/pyloid.py CHANGED
@@ -26,9 +26,11 @@ import logging
26
26
  from .browser_window import BrowserWindow
27
27
  from .tray import TrayEvent
28
28
  from PySide6.QtCore import QCoreApplication
29
- from PySide6.QtCore import QRunnable, QThreadPool, Signal, QObject
30
- import time
31
- from .thread_pool import PyloidThreadPool
29
+ from PySide6.QtCore import Signal, QObject, Slot
30
+ import uuid
31
+ from PySide6.QtCore import QEventLoop
32
+ import socket
33
+ from typing import Any
32
34
 
33
35
  # for linux debug
34
36
  os.environ["QTWEBENGINE_DICTIONARIES_PATH"] = "/"
@@ -73,11 +75,14 @@ class _WindowController(QObject):
73
75
  )
74
76
 
75
77
 
76
- class Pyloid(QApplication):
78
+
79
+ # Only Work in Main Thread
80
+ class _Pyloid(QApplication):
77
81
  def __init__(
78
82
  self,
79
83
  app_name,
80
84
  single_instance=True,
85
+ data=None,
81
86
  ):
82
87
  """
83
88
  Initializes the Pyloid application.
@@ -88,6 +93,8 @@ class Pyloid(QApplication):
88
93
  The name of the application
89
94
  single_instance : bool, optional
90
95
  Whether to run the application as a single instance (default is True)
96
+ data : dict, optional
97
+ Data to be transmitted to the frontend web engine via IPC
91
98
 
92
99
  Examples
93
100
  --------
@@ -101,8 +108,10 @@ class Pyloid(QApplication):
101
108
  ```
102
109
  """
103
110
  super().__init__(sys.argv)
111
+
112
+ self.data = data
104
113
 
105
- self.windows = []
114
+ self.windows_dict = {} # 윈도우 ID를 키로 사용하는 딕셔너리
106
115
  self.server = None
107
116
 
108
117
  self.app_name = app_name
@@ -199,8 +208,8 @@ class Pyloid(QApplication):
199
208
  self.icon = QIcon(icon_path)
200
209
 
201
210
  # Immediately update the icon for all open windows.
202
- for window in self.windows:
203
- window._window.setWindowIcon(self.icon)
211
+ for window in self.windows_dict.values():
212
+ window.set_icon(self.icon)
204
213
 
205
214
  def create_window(
206
215
  self,
@@ -261,7 +270,8 @@ class Pyloid(QApplication):
261
270
  dev_tools,
262
271
  js_apis,
263
272
  )
264
- return self.windows[-1]
273
+ latest_window_id = list(self.windows_dict.keys())[-1]
274
+ return self.windows_dict[latest_window_id]
265
275
 
266
276
  def _create_window_signal_function(
267
277
  self,
@@ -289,7 +299,7 @@ class Pyloid(QApplication):
289
299
  dev_tools,
290
300
  js_apis,
291
301
  )
292
- self.windows.append(window)
302
+ self.windows_dict[window.window.id] = window
293
303
  return window
294
304
 
295
305
  def run(self):
@@ -333,7 +343,7 @@ class Pyloid(QApplication):
333
343
  ###########################################################################################
334
344
  # App window
335
345
  ###########################################################################################
336
- def get_windows(self) -> List[BrowserWindow]:
346
+ def get_windows(self) -> Dict[str, BrowserWindow]:
337
347
  """
338
348
  Returns a list of all browser windows.
339
349
 
@@ -351,7 +361,7 @@ class Pyloid(QApplication):
351
361
  print(window.get_id())
352
362
  ```
353
363
  """
354
- return self.windows
364
+ return self.windows_dict
355
365
 
356
366
  def show_main_window(self):
357
367
  """
@@ -364,8 +374,9 @@ class Pyloid(QApplication):
364
374
  app.show_main_window()
365
375
  ```
366
376
  """
367
- if self.windows:
368
- main_window = self.windows[0]
377
+ if self.windows_dict:
378
+ # 번째 윈도우 가져오기
379
+ main_window = next(iter(self.windows_dict.values()))
369
380
  main_window._window.show()
370
381
 
371
382
  def focus_main_window(self):
@@ -379,8 +390,9 @@ class Pyloid(QApplication):
379
390
  app.focus_main_window()
380
391
  ```
381
392
  """
382
- if self.windows:
383
- main_window = self.windows[0]
393
+ if self.windows_dict:
394
+ # 번째 윈도우 가져오기
395
+ main_window = next(iter(self.windows_dict.values()))
384
396
  main_window._window.activateWindow()
385
397
  main_window._window.raise_()
386
398
  main_window._window.setWindowState(
@@ -399,8 +411,8 @@ class Pyloid(QApplication):
399
411
  app.show_and_focus_main_window()
400
412
  ```
401
413
  """
402
- if self.windows:
403
- main_window = self.windows[0]
414
+ if self.windows_dict:
415
+ main_window = next(iter(self.windows_dict.values()))
404
416
  main_window._window.show()
405
417
  main_window._window.activateWindow()
406
418
  main_window._window.raise_()
@@ -420,7 +432,7 @@ class Pyloid(QApplication):
420
432
  app.close_all_windows()
421
433
  ```
422
434
  """
423
- for window in self.windows:
435
+ for window in self.windows_dict.values():
424
436
  window._window.close()
425
437
 
426
438
  def quit(self):
@@ -435,12 +447,12 @@ class Pyloid(QApplication):
435
447
  ```
436
448
  """
437
449
 
438
- # 윈도우 정리
439
- for window in self.windows:
450
+ for window in self.windows_dict.values():
440
451
  window._window.close()
441
452
  window.web_page.deleteLater()
442
453
  window.web_view.deleteLater()
443
454
 
455
+ self.windows_dict.clear()
444
456
  QApplication.quit()
445
457
 
446
458
  ###########################################################################################
@@ -449,7 +461,7 @@ class Pyloid(QApplication):
449
461
  def get_window_by_id(self, window_id: str) -> Optional[BrowserWindow]:
450
462
  """
451
463
  Returns the window with the given ID.
452
-
464
+
453
465
  Parameters
454
466
  ----------
455
467
  window_id : str
@@ -459,22 +471,19 @@ class Pyloid(QApplication):
459
471
  -------
460
472
  Optional[BrowserWindow]
461
473
  The window object with the given ID. Returns None if the window is not found.
462
-
474
+
463
475
  Examples
464
476
  --------
465
477
  ```python
466
478
  app = Pyloid(app_name="Pyloid-App")
467
-
479
+
468
480
  window = app.get_window_by_id("123e4567-e89b-12d3-a456-426614174000")
469
-
481
+
470
482
  if window:
471
483
  print("Window found:", window)
472
484
  ```
473
485
  """
474
- for window in self.windows:
475
- if window.id == window_id:
476
- return window
477
- return None
486
+ return self.windows_dict.get(window_id)
478
487
 
479
488
  def hide_window_by_id(self, window_id: str):
480
489
  """
@@ -520,12 +529,7 @@ class Pyloid(QApplication):
520
529
  """
521
530
  window = self.get_window_by_id(window_id)
522
531
  if window:
523
- window._window.show()
524
- window._window.activateWindow()
525
- window._window.raise_()
526
- window._window.setWindowState(
527
- window._window.windowState() & ~Qt.WindowMinimized | Qt.WindowActive
528
- )
532
+ window.show()
529
533
 
530
534
  def close_window_by_id(self, window_id: str):
531
535
  """
@@ -1397,8 +1401,1026 @@ class Pyloid(QApplication):
1397
1401
  """
1398
1402
 
1399
1403
  # 모든 윈도우에 변경사항 적용
1400
- for window in self.windows:
1404
+ for window in self.windows_dict.values():
1401
1405
  window.web_view.page().runJavaScript(js_code)
1402
1406
  window.web_view.page().setBackgroundColor(
1403
1407
  Qt.GlobalColor.black if self.theme == "dark" else Qt.GlobalColor.white
1404
1408
  )
1409
+
1410
+
1411
+ class Pyloid(QObject):
1412
+ command_signal = Signal(str, str, object)
1413
+ result_signal = Signal(str, object)
1414
+
1415
+ def __init__(self, app_name: str, single_instance: bool = True, data: Optional[Dict[str, Any]] = None):
1416
+ """
1417
+ Initialize the Pyloid application.
1418
+
1419
+ This application is designed to work in a multi-threaded environment.
1420
+ All Qt GUI related operations are executed in the main thread's event queue regardless of the calling thread,
1421
+ ensuring thread safety for GUI operations.
1422
+
1423
+ Parameters
1424
+ ----------
1425
+ app_name : str, required
1426
+ The name of the application.
1427
+ single_instance : bool, optional
1428
+ Determines whether to run as a single instance. (Default is True)
1429
+ data : dict, optional
1430
+ Data to be transmitted to the frontend web engine via IPC
1431
+
1432
+ Notes
1433
+ -----
1434
+ The generated or passed `id` is transmitted to the frontend via IPC,
1435
+ and is used as an API key to connect to the integrated backend FastAPI server.
1436
+ """
1437
+ super().__init__()
1438
+
1439
+ self.data = data
1440
+
1441
+ self.app = _Pyloid(app_name, single_instance, self.data)
1442
+
1443
+ self.command_signal.connect(self._handle_command)
1444
+
1445
+ @Slot(str, str, object)
1446
+ def _handle_command(self, command_id, command_type, params):
1447
+ result = None
1448
+
1449
+ if command_type == "set_icon":
1450
+ result = self.app.set_icon(params["icon_path"])
1451
+
1452
+ elif command_type == "create_window":
1453
+ window = self.app.create_window(
1454
+ title=params.get("title", ""),
1455
+ width=params.get("width", 800),
1456
+ height=params.get("height", 600),
1457
+ x=params.get("x", 200),
1458
+ y=params.get("y", 200),
1459
+ frame=params.get("frame", True),
1460
+ context_menu=params.get("context_menu", False),
1461
+ dev_tools=params.get("dev_tools", False)
1462
+ )
1463
+ result = window
1464
+
1465
+ elif command_type == "run":
1466
+ result = self.app.run()
1467
+
1468
+ elif command_type == "get_windows":
1469
+ result = self.app.get_windows()
1470
+
1471
+ elif command_type == "show_main_window":
1472
+ result = self.app.show_main_window()
1473
+
1474
+ elif command_type == "focus_main_window":
1475
+ result = self.app.focus_main_window()
1476
+
1477
+ elif command_type == "show_and_focus_main_window":
1478
+ result = self.app.show_and_focus_main_window()
1479
+
1480
+ elif command_type == "close_all_windows":
1481
+ result = self.app.close_all_windows()
1482
+
1483
+ elif command_type == "quit":
1484
+ result = self.app.quit()
1485
+
1486
+ elif command_type == "get_window_by_id":
1487
+ result = self.app.get_window_by_id(params["window_id"])
1488
+
1489
+ elif command_type == "hide_window_by_id":
1490
+ result = self.app.hide_window_by_id(params["window_id"])
1491
+
1492
+ elif command_type == "show_window_by_id":
1493
+ result = self.app.show_window_by_id(params["window_id"])
1494
+
1495
+ elif command_type == "close_window_by_id":
1496
+ result = self.app.close_window_by_id(params["window_id"])
1497
+
1498
+ elif command_type == "toggle_fullscreen_by_id":
1499
+ result = self.app.toggle_fullscreen_by_id(params["window_id"])
1500
+
1501
+ elif command_type == "minimize_window_by_id":
1502
+ result = self.app.minimize_window_by_id(params["window_id"])
1503
+
1504
+ elif command_type == "maximize_window_by_id":
1505
+ result = self.app.maximize_window_by_id(params["window_id"])
1506
+
1507
+ elif command_type == "unmaximize_window_by_id":
1508
+ result = self.app.unmaximize_window_by_id(params["window_id"])
1509
+
1510
+ elif command_type == "capture_window_by_id":
1511
+ result = self.app.capture_window_by_id(params["window_id"], params["save_path"])
1512
+
1513
+ elif command_type == "set_tray_icon":
1514
+ result = self.app.set_tray_icon(params["tray_icon_path"])
1515
+
1516
+ elif command_type == "set_tray_menu_items":
1517
+ result = self.app.set_tray_menu_items(params["tray_menu_items"])
1518
+
1519
+ elif command_type == "set_tray_actions":
1520
+ result = self.app.set_tray_actions(params["actions"])
1521
+
1522
+ elif command_type == "show_notification":
1523
+ result = self.app.show_notification(params["title"], params["message"])
1524
+
1525
+ elif command_type == "set_tray_icon_animation":
1526
+ result = self.app.set_tray_icon_animation(params["icon_frames"], params.get("interval", 200))
1527
+
1528
+ elif command_type == "set_tray_tooltip":
1529
+ result = self.app.set_tray_tooltip(params["message"])
1530
+
1531
+ elif command_type == "set_notification_callback":
1532
+ result = self.app.set_notification_callback(params["callback"])
1533
+
1534
+ elif command_type == "get_all_monitors":
1535
+ result = self.app.get_all_monitors()
1536
+
1537
+ elif command_type == "get_primary_monitor":
1538
+ result = self.app.get_primary_monitor()
1539
+
1540
+ elif command_type == "set_clipboard_text":
1541
+ result = self.app.set_clipboard_text(params["text"])
1542
+
1543
+ elif command_type == "get_clipboard_text":
1544
+ result = self.app.get_clipboard_text()
1545
+
1546
+ elif command_type == "set_clipboard_image":
1547
+ result = self.app.set_clipboard_image(params["image"])
1548
+
1549
+ elif command_type == "get_clipboard_image":
1550
+ result = self.app.get_clipboard_image()
1551
+
1552
+ elif command_type == "set_auto_start":
1553
+ result = self.app.set_auto_start(params["enable"])
1554
+
1555
+ elif command_type == "is_auto_start":
1556
+ result = self.app.is_auto_start()
1557
+
1558
+ elif command_type == "watch_file":
1559
+ result = self.app.watch_file(params["file_path"])
1560
+
1561
+ elif command_type == "watch_directory":
1562
+ result = self.app.watch_directory(params["dir_path"])
1563
+
1564
+ elif command_type == "stop_watching":
1565
+ result = self.app.stop_watching(params["path"])
1566
+
1567
+ elif command_type == "get_watched_paths":
1568
+ result = self.app.get_watched_paths()
1569
+
1570
+ elif command_type == "get_watched_files":
1571
+ result = self.app.get_watched_files()
1572
+
1573
+ elif command_type == "get_watched_directories":
1574
+ result = self.app.get_watched_directories()
1575
+
1576
+ elif command_type == "remove_all_watched_paths":
1577
+ result = self.app.remove_all_watched_paths()
1578
+
1579
+ elif command_type == "set_file_change_callback":
1580
+ result = self.app.set_file_change_callback(params["callback"])
1581
+
1582
+ elif command_type == "set_directory_change_callback":
1583
+ result = self.app.set_directory_change_callback(params["callback"])
1584
+
1585
+ elif command_type == "open_file_dialog":
1586
+ result = self.app.open_file_dialog(params.get("dir"), params.get("filter"))
1587
+
1588
+ elif command_type == "save_file_dialog":
1589
+ result = self.app.save_file_dialog(params.get("dir"), params.get("filter"))
1590
+
1591
+ elif command_type == "select_directory_dialog":
1592
+ result = self.app.select_directory_dialog(params.get("dir"))
1593
+
1594
+ else:
1595
+ return None
1596
+
1597
+ self.result_signal.emit(command_id, result)
1598
+
1599
+ def execute_command(self, command_type: str, params: object, timeout: Optional[int] = None):
1600
+ command_id = str(uuid.uuid4())
1601
+
1602
+ result_data = [None]
1603
+ loop = QEventLoop()
1604
+
1605
+ if timeout:
1606
+ timer = QTimer()
1607
+ timer.setSingleShot(True)
1608
+ timer.timeout.connect(loop.quit)
1609
+ timer.start(timeout)
1610
+
1611
+ def on_result(received_id, result):
1612
+ if received_id == command_id:
1613
+ result_data[0] = result
1614
+ loop.quit()
1615
+
1616
+
1617
+ self.result_signal.connect(on_result, Qt.QueuedConnection)
1618
+
1619
+ self.command_signal.emit(command_id, command_type, params)
1620
+
1621
+ loop.exec()
1622
+
1623
+ self.result_signal.disconnect(on_result)
1624
+
1625
+ return result_data[0]
1626
+
1627
+ # -------------------------------------------------------------------
1628
+ # Execute_command 래퍼 (wrapper) 함수들
1629
+ # -------------------------------------------------------------------
1630
+
1631
+ def set_icon(self, icon_path: str) -> bool:
1632
+ """
1633
+ Dynamically sets the application's icon.
1634
+
1635
+ Parameters
1636
+ ----------
1637
+ icon_path : str
1638
+ Path to the new icon file
1639
+
1640
+ Examples
1641
+ --------
1642
+ >>> app = Pyloid(app_name="Pyloid-App")
1643
+ >>> app.set_icon("icons/icon.png")
1644
+ """
1645
+ return self.execute_command("set_icon", {"icon_path": icon_path})
1646
+
1647
+ def create_window(
1648
+ self,
1649
+ title: str,
1650
+ width: int = 800,
1651
+ height: int = 600,
1652
+ x: int = 200,
1653
+ y: int = 200,
1654
+ frame: bool = True,
1655
+ context_menu: bool = False,
1656
+ dev_tools: bool = False,
1657
+ ) -> BrowserWindow:
1658
+ """
1659
+ Creates a new browser window.
1660
+
1661
+ Parameters
1662
+ ----------
1663
+ title : str, required
1664
+ Title of the window
1665
+ width : int, optional
1666
+ Width of the window (default is 800)
1667
+ height : int, optional
1668
+ Height of the window (default is 600)
1669
+ x : int, optional
1670
+ X coordinate of the window (default is 200)
1671
+ y : int, optional
1672
+ Y coordinate of the window (default is 200)
1673
+ frame : bool, optional
1674
+ Whether the window has a frame (default is True)
1675
+ context_menu : bool, optional
1676
+ Whether to use the context menu (default is False)
1677
+ dev_tools : bool, optional
1678
+ Whether to use developer tools (default is False)
1679
+
1680
+ Returns
1681
+ -------
1682
+ BrowserWindow
1683
+ The created browser window object
1684
+
1685
+ Examples
1686
+ --------
1687
+ >>> app = Pyloid(app_name="Pyloid-App")
1688
+ >>> window_id = app.create_window(title="New Window", width=1024, height=768)
1689
+ """
1690
+ params = {
1691
+ "title": title,
1692
+ "width": width,
1693
+ "height": height,
1694
+ "x": x,
1695
+ "y": y,
1696
+ "frame": frame,
1697
+ "context_menu": context_menu,
1698
+ "dev_tools": dev_tools,
1699
+ }
1700
+ return self.execute_command("create_window", params)
1701
+
1702
+ def run(self) -> None:
1703
+ """
1704
+ Runs the application event loop.
1705
+
1706
+ Examples
1707
+ --------
1708
+ >>> app = Pyloid(app_name="Pyloid-App")
1709
+ >>> app.run()
1710
+ """
1711
+ return self.app.run()
1712
+
1713
+ def get_windows(self) -> Dict[str, BrowserWindow]:
1714
+ """
1715
+ Returns a list of all browser windows.
1716
+
1717
+ Returns
1718
+ -------
1719
+ Dict[str, BrowserWindow]
1720
+ Dictionary of all browser windows
1721
+
1722
+ Examples
1723
+ --------
1724
+ >>> app = Pyloid(app_name="Pyloid-App")
1725
+ >>> windows = app.get_windows()
1726
+ """
1727
+ return self.execute_command("get_windows", {})
1728
+
1729
+ def show_main_window(self) -> None:
1730
+ """
1731
+ Shows and focuses the first window.
1732
+
1733
+ Examples
1734
+ --------
1735
+ >>> app = Pyloid(app_name="Pyloid-App")
1736
+ >>> app.show_main_window()
1737
+ """
1738
+ return self.execute_command("show_main_window", {})
1739
+
1740
+ def focus_main_window(self) -> None:
1741
+ """
1742
+ Focuses the first window.
1743
+
1744
+ Examples
1745
+ --------
1746
+ >>> app = Pyloid(app_name="Pyloid-App")
1747
+ >>> app.focus_main_window()
1748
+ """
1749
+ return self.execute_command("focus_main_window", {})
1750
+
1751
+ def show_and_focus_main_window(self) -> None:
1752
+ """
1753
+ Shows and focuses the first window.
1754
+
1755
+ Examples
1756
+ --------
1757
+ >>> app = Pyloid(app_name="Pyloid-App")
1758
+ >>> app.show_and_focus_main_window()
1759
+ """
1760
+ return self.execute_command("show_and_focus_main_window", {})
1761
+
1762
+ def close_all_windows(self) -> None:
1763
+ """
1764
+ Closes all windows.
1765
+
1766
+ Examples
1767
+ --------
1768
+ >>> app = Pyloid(app_name="Pyloid-App")
1769
+ >>> app.close_all_windows()
1770
+ """
1771
+ return self.execute_command("close_all_windows", {})
1772
+
1773
+ def quit(self) -> None:
1774
+ """
1775
+ Quits the application.
1776
+
1777
+ Examples
1778
+ --------
1779
+ >>> app = Pyloid(app_name="Pyloid-App")
1780
+ >>> app.quit()
1781
+ """
1782
+ return self.execute_command("quit", {})
1783
+
1784
+ def get_window_by_id(self, window_id: str) -> Optional[BrowserWindow]:
1785
+ """
1786
+ Returns the window with the given ID.
1787
+
1788
+ Parameters
1789
+ ----------
1790
+ window_id : str
1791
+ The ID of the window to find
1792
+
1793
+ Returns
1794
+ -------
1795
+ Optional[BrowserWindow]
1796
+ The window object with the given ID. Returns None if the window is not found.
1797
+
1798
+ Examples
1799
+ --------
1800
+ >>> app = Pyloid(app_name="Pyloid-App")
1801
+ >>> window = app.get_window_by_id("some-window-id")
1802
+ """
1803
+ return self.execute_command("get_window_by_id", {"window_id": window_id})
1804
+
1805
+ def hide_window_by_id(self, window_id: str) -> None:
1806
+ """
1807
+ Hides the window with the given ID.
1808
+
1809
+ Parameters
1810
+ ----------
1811
+ window_id : str
1812
+ The ID of the window to hide
1813
+
1814
+ Examples
1815
+ --------
1816
+ >>> app = Pyloid(app_name="Pyloid-App")
1817
+ >>> app.hide_window_by_id("some-window-id")
1818
+ """
1819
+ return self.execute_command("hide_window_by_id", {"window_id": window_id})
1820
+
1821
+ def show_window_by_id(self, window_id: str) -> None:
1822
+ """
1823
+ Shows and focuses the window with the given ID.
1824
+
1825
+ Parameters
1826
+ ----------
1827
+ window_id : str
1828
+ The ID of the window to show
1829
+
1830
+ Examples
1831
+ --------
1832
+ >>> app = Pyloid(app_name="Pyloid-App")
1833
+ >>> app.show_window_by_id("some-window-id")
1834
+ """
1835
+ return self.execute_command("show_window_by_id", {"window_id": window_id})
1836
+
1837
+ def close_window_by_id(self, window_id: str) -> None:
1838
+ """
1839
+ Closes the window with the given ID.
1840
+
1841
+ Parameters
1842
+ ----------
1843
+ window_id : str
1844
+ The ID of the window to close
1845
+
1846
+ Examples
1847
+ --------
1848
+ >>> app = Pyloid(app_name="Pyloid-App")
1849
+ >>> app.close_window_by_id("some-window-id")
1850
+ """
1851
+ return self.execute_command("close_window_by_id", {"window_id": window_id})
1852
+
1853
+ def toggle_fullscreen_by_id(self, window_id: str) -> None:
1854
+ """
1855
+ Toggles fullscreen mode for the window with the given ID.
1856
+
1857
+ Parameters
1858
+ ----------
1859
+ window_id : str
1860
+ The ID of the window to toggle fullscreen mode
1861
+
1862
+ Examples
1863
+ --------
1864
+ >>> app = Pyloid(app_name="Pyloid-App")
1865
+ >>> app.toggle_fullscreen_by_id("some-window-id")
1866
+ """
1867
+ return self.execute_command("toggle_fullscreen_by_id", {"window_id": window_id})
1868
+
1869
+ def minimize_window_by_id(self, window_id: str) -> None:
1870
+ """
1871
+ Minimizes the window with the given ID.
1872
+
1873
+ Parameters
1874
+ ----------
1875
+ window_id : str
1876
+ The ID of the window to minimize
1877
+
1878
+ Examples
1879
+ --------
1880
+ >>> app = Pyloid(app_name="Pyloid-App")
1881
+ >>> app.minimize_window_by_id("some-window-id")
1882
+ """
1883
+ return self.execute_command("minimize_window_by_id", {"window_id": window_id})
1884
+
1885
+ def maximize_window_by_id(self, window_id: str) -> None:
1886
+ """
1887
+ Maximizes the window with the given ID.
1888
+
1889
+ Parameters
1890
+ ----------
1891
+ window_id : str
1892
+ The ID of the window to maximize
1893
+
1894
+ Examples
1895
+ --------
1896
+ >>> app = Pyloid(app_name="Pyloid-App")
1897
+ >>> app.maximize_window_by_id("some-window-id")
1898
+ """
1899
+ return self.execute_command("maximize_window_by_id", {"window_id": window_id})
1900
+
1901
+ def unmaximize_window_by_id(self, window_id: str) -> None:
1902
+ """
1903
+ Unmaximizes the window with the given ID.
1904
+
1905
+ Parameters
1906
+ ----------
1907
+ window_id : str
1908
+ The ID of the window to unmaximize
1909
+
1910
+ Examples
1911
+ --------
1912
+ >>> app = Pyloid(app_name="Pyloid-App")
1913
+ >>> app.unmaximize_window_by_id("some-window-id")
1914
+ """
1915
+ return self.execute_command("unmaximize_window_by_id", {"window_id": window_id})
1916
+
1917
+ def capture_window_by_id(self, window_id: str, save_path: str) -> Optional[str]:
1918
+ """
1919
+ Captures the specified window.
1920
+
1921
+ Parameters
1922
+ ----------
1923
+ window_id : str
1924
+ The ID of the window to capture
1925
+ save_path : str
1926
+ The path to save the captured image
1927
+
1928
+ Returns
1929
+ -------
1930
+ Optional[str]
1931
+ The path of the saved image. Returns None if the window is not found or an error occurs.
1932
+
1933
+ Examples
1934
+ --------
1935
+ >>> app = Pyloid(app_name="Pyloid-App")
1936
+ >>> image_path = app.capture_window_by_id("some-window-id", "save/image.png")
1937
+ """
1938
+ return self.execute_command("capture_window_by_id", {"window_id": window_id, "save_path": save_path})
1939
+
1940
+ def set_tray_icon(self, tray_icon_path: str) -> bool:
1941
+ """
1942
+ Dynamically sets the tray icon.
1943
+
1944
+ Parameters
1945
+ ----------
1946
+ tray_icon_path : str
1947
+ The path of the new tray icon file
1948
+
1949
+ Examples
1950
+ --------
1951
+ >>> app = Pyloid(app_name="Pyloid-App")
1952
+ >>> app.set_tray_icon("icons/icon.png")
1953
+ """
1954
+ return self.execute_command("set_tray_icon", {"tray_icon_path": tray_icon_path})
1955
+
1956
+ def set_tray_menu_items(self, tray_menu_items: List[Dict[str, Union[str, Callable]]]) -> bool:
1957
+ """
1958
+ Dynamically sets the tray menu items.
1959
+
1960
+ Parameters
1961
+ ----------
1962
+ tray_menu_items : List[Dict[str, Union[str, Callable]]]
1963
+ The list of new tray menu items
1964
+
1965
+ Examples
1966
+ --------
1967
+ >>> app = Pyloid(app_name="Pyloid-App")
1968
+ >>> menu_items = [{"label": "Open", "callback": lambda: print("Open clicked")},
1969
+ >>> {"label": "Exit", "callback": app.quit}]
1970
+ >>> app.set_tray_menu_items(menu_items)
1971
+ """
1972
+ return self.execute_command("set_tray_menu_items", {"tray_menu_items": tray_menu_items})
1973
+
1974
+ def set_tray_actions(self, actions: Dict[TrayEvent, Callable]) -> bool:
1975
+ """
1976
+ Dynamically sets the actions for tray icon activation.
1977
+
1978
+ Parameters
1979
+ ----------
1980
+ actions : Dict[TrayEvent, Callable]
1981
+ Dictionary with TrayEvent enum values as keys and corresponding callback functions as values
1982
+
1983
+ Examples
1984
+ --------
1985
+ >>> app = Pyloid(app_name="Pyloid-App")
1986
+ >>> app.set_tray_actions({TrayEvent.DoubleClick: lambda: print("Double-clicked")})
1987
+ """
1988
+ return self.execute_command("set_tray_actions", {"actions": actions})
1989
+
1990
+ def show_notification(self, title: str, message: str) -> bool:
1991
+ """
1992
+ Displays a notification in the system tray.
1993
+
1994
+ Parameters
1995
+ ----------
1996
+ title : str
1997
+ Notification title
1998
+ message : str
1999
+ Notification message
2000
+
2001
+ Examples
2002
+ --------
2003
+ >>> app = Pyloid(app_name="Pyloid-App")
2004
+ >>> app.show_notification("Update Available", "A new update is available for download.")
2005
+ """
2006
+ return self.execute_command("show_notification", {"title": title, "message": message})
2007
+
2008
+ def set_tray_icon_animation(self, icon_frames: List[str], interval: int = 200) -> bool:
2009
+ """
2010
+ Dynamically sets and starts the animation for the tray icon.
2011
+
2012
+ Parameters
2013
+ ----------
2014
+ icon_frames : list of str
2015
+ List of animation frame image paths
2016
+ interval : int, optional
2017
+ Frame interval in milliseconds, default is 200
2018
+
2019
+ Examples
2020
+ --------
2021
+ >>> app = Pyloid(app_name="Pyloid-App")
2022
+ >>> app.set_tray_icon_animation(["frame1.png", "frame2.png", "frame3.png"], 100)
2023
+ """
2024
+ return self.execute_command("set_tray_icon_animation", {"icon_frames": icon_frames, "interval": interval})
2025
+
2026
+ def set_tray_tooltip(self, message: str) -> bool:
2027
+ """
2028
+ Dynamically sets the tooltip for the tray icon.
2029
+
2030
+ Parameters
2031
+ ----------
2032
+ message : str
2033
+ New tooltip message
2034
+
2035
+ Examples
2036
+ --------
2037
+ >>> app = Pyloid(app_name="Pyloid-App")
2038
+ >>> app.set_tray_tooltip("Pyloid is running")
2039
+ """
2040
+ return self.execute_command("set_tray_tooltip", {"message": message})
2041
+
2042
+ def set_notification_callback(self, callback: Callable[[str], None]) -> bool:
2043
+ """
2044
+ Sets the callback function to be called when a notification is clicked.
2045
+
2046
+ Parameters
2047
+ ----------
2048
+ callback : function
2049
+ Callback function to be called when a notification is clicked
2050
+
2051
+ Examples
2052
+ --------
2053
+ >>> app = Pyloid(app_name="Pyloid-App")
2054
+ >>> def on_notification_click():
2055
+ >>> print("Notification clicked")
2056
+ >>> app.set_notification_callback(on_notification_click)
2057
+ """
2058
+ return self.execute_command("set_notification_callback", {"callback": callback})
2059
+
2060
+ def get_all_monitors(self) -> List[Monitor]:
2061
+ """
2062
+ Returns information about all connected monitors.
2063
+
2064
+ Returns
2065
+ -------
2066
+ List[Monitor]
2067
+ List containing monitor information
2068
+
2069
+ Examples
2070
+ --------
2071
+ >>> app = Pyloid(app_name="Pyloid-App")
2072
+ >>> monitors = app.get_all_monitors()
2073
+ >>> for monitor in monitors:
2074
+ >>> print(monitor.info())
2075
+ """
2076
+ return self.execute_command("get_all_monitors", {})
2077
+
2078
+ def get_primary_monitor(self) -> Monitor:
2079
+ """
2080
+ Returns information about the primary monitor.
2081
+
2082
+ Returns
2083
+ -------
2084
+ Monitor
2085
+ Primary monitor information
2086
+
2087
+ Examples
2088
+ --------
2089
+ >>> app = Pyloid(app_name="Pyloid-App")
2090
+ >>> primary_monitor = app.get_primary_monitor()
2091
+ >>> print(primary_monitor.info())
2092
+ """
2093
+ return self.execute_command("get_primary_monitor", {})
2094
+
2095
+ def set_clipboard_text(self, text: str) -> None:
2096
+ """
2097
+ Copies text to the clipboard.
2098
+
2099
+ Parameters
2100
+ ----------
2101
+ text : str
2102
+ Text to copy to the clipboard
2103
+
2104
+ Examples
2105
+ --------
2106
+ >>> app = Pyloid(app_name="Pyloid-App")
2107
+ >>> app.set_clipboard_text("Hello, World!")
2108
+ """
2109
+ return self.execute_command("set_clipboard_text", {"text": text})
2110
+
2111
+ def get_clipboard_text(self) -> str:
2112
+ """
2113
+ Retrieves text from the clipboard.
2114
+
2115
+ Returns
2116
+ -------
2117
+ str
2118
+ Text stored in the clipboard
2119
+
2120
+ Examples
2121
+ --------
2122
+ >>> app = Pyloid(app_name="Pyloid-App")
2123
+ >>> text = app.get_clipboard_text()
2124
+ >>> print(text)
2125
+ """
2126
+ return self.execute_command("get_clipboard_text", {})
2127
+
2128
+ def set_clipboard_image(self, image: Union[str, bytes, os.PathLike]) -> None:
2129
+ """
2130
+ Copies an image to the clipboard.
2131
+
2132
+ Parameters
2133
+ ----------
2134
+ image : Union[str, bytes, os.PathLike]
2135
+ Path to the image file to copy to the clipboard
2136
+
2137
+ Examples
2138
+ --------
2139
+ >>> app = Pyloid(app_name="Pyloid-App")
2140
+ >>> app.set_clipboard_image("/path/to/image.png")
2141
+ """
2142
+ return self.execute_command("set_clipboard_image", {"image": image})
2143
+
2144
+ def get_clipboard_image(self) -> QImage:
2145
+ """
2146
+ Retrieves an image from the clipboard.
2147
+
2148
+ Returns
2149
+ -------
2150
+ QImage
2151
+ QImage object stored in the clipboard (None if no image)
2152
+
2153
+ Examples
2154
+ --------
2155
+ >>> app = Pyloid(app_name="Pyloid-App")
2156
+ >>> image = app.get_clipboard_image()
2157
+ >>> if image is not None:
2158
+ >>> image.save("/path/to/save/image.png")
2159
+ """
2160
+ return self.execute_command("get_clipboard_image", {})
2161
+
2162
+ def set_auto_start(self, enable: bool) -> Union[bool, None]:
2163
+ """
2164
+ Sets the application to start automatically at system startup.
2165
+
2166
+ Parameters
2167
+ ----------
2168
+ enable : bool
2169
+ True to enable auto start, False to disable
2170
+
2171
+ Returns
2172
+ -------
2173
+ bool or None
2174
+ True if auto start is successfully set, False if disabled, None if not supported in non-production environment
2175
+
2176
+ Examples
2177
+ --------
2178
+ >>> app = Pyloid(app_name="Pyloid-App")
2179
+ >>> app.set_auto_start(True)
2180
+ """
2181
+ return self.execute_command("set_auto_start", {"enable": enable})
2182
+
2183
+ def is_auto_start(self) -> bool:
2184
+ """
2185
+ Checks if the application is set to start automatically at system startup.
2186
+
2187
+ Returns
2188
+ -------
2189
+ bool
2190
+ True if auto start is enabled, False otherwise
2191
+
2192
+ Examples
2193
+ --------
2194
+ >>> app = Pyloid(app_name="Pyloid-App")
2195
+ >>> auto_start_enabled = app.is_auto_start()
2196
+ >>> print(auto_start_enabled)
2197
+ """
2198
+ return self.execute_command("is_auto_start", {})
2199
+
2200
+ def watch_file(self, file_path: str) -> bool:
2201
+ """
2202
+ Adds a file to the watch list.
2203
+
2204
+ Parameters
2205
+ ----------
2206
+ file_path : str
2207
+ Path to the file to watch
2208
+
2209
+ Returns
2210
+ -------
2211
+ bool
2212
+ True if the file is successfully added to the watch list, False otherwise
2213
+
2214
+ Examples
2215
+ --------
2216
+ >>> app = Pyloid(app_name="Pyloid-App")
2217
+ >>> app.watch_file("/path/to/file.txt")
2218
+ """
2219
+ return self.execute_command("watch_file", {"file_path": file_path})
2220
+
2221
+ def watch_directory(self, dir_path: str) -> bool:
2222
+ """
2223
+ Adds a directory to the watch list.
2224
+
2225
+ Parameters
2226
+ ----------
2227
+ dir_path : str
2228
+ Path to the directory to watch
2229
+
2230
+ Returns
2231
+ -------
2232
+ bool
2233
+ True if the directory is successfully added to the watch list, False otherwise
2234
+
2235
+ Examples
2236
+ --------
2237
+ >>> app = Pyloid(app_name="Pyloid-App")
2238
+ >>> app.watch_directory("/path/to/directory")
2239
+ """
2240
+ return self.execute_command("watch_directory", {"dir_path": dir_path})
2241
+
2242
+ def stop_watching(self, path: str) -> bool:
2243
+ """
2244
+ Removes a file or directory from the watch list.
2245
+
2246
+ Parameters
2247
+ ----------
2248
+ path : str
2249
+ Path to the file or directory to stop watching
2250
+
2251
+ Returns
2252
+ -------
2253
+ bool
2254
+ True if the path is successfully removed from the watch list, False otherwise
2255
+
2256
+ Examples
2257
+ --------
2258
+ >>> app = Pyloid(app_name="Pyloid-App")
2259
+ >>> app.stop_watching("/path/to/file_or_directory")
2260
+ """
2261
+ return self.execute_command("stop_watching", {"path": path})
2262
+
2263
+ def get_watched_paths(self) -> List[str]:
2264
+ """
2265
+ Returns all currently watched paths.
2266
+
2267
+ Returns
2268
+ -------
2269
+ List[str]
2270
+ List of all watched paths
2271
+
2272
+ Examples
2273
+ --------
2274
+ >>> app = Pyloid(app_name="Pyloid-App")
2275
+ >>> app.get_watched_paths()
2276
+ ['/path/to/file1.txt', '/path/to/directory']
2277
+ """
2278
+ return self.execute_command("get_watched_paths", {})
2279
+
2280
+ def get_watched_files(self) -> List[str]:
2281
+ """
2282
+ Returns all currently watched files.
2283
+
2284
+ Returns
2285
+ -------
2286
+ List[str]
2287
+ List of all watched files
2288
+
2289
+ Examples
2290
+ --------
2291
+ >>> app = Pyloid(app_name="Pyloid-App")
2292
+ >>> app.get_watched_files()
2293
+ ['/path/to/file1.txt', '/path/to/file2.txt']
2294
+ """
2295
+ return self.execute_command("get_watched_files", {})
2296
+
2297
+ def get_watched_directories(self) -> List[str]:
2298
+ """
2299
+ Returns all currently watched directories.
2300
+
2301
+ Returns
2302
+ -------
2303
+ List[str]
2304
+ List of all watched directories
2305
+
2306
+ Examples
2307
+ --------
2308
+ >>> app = Pyloid(app_name="Pyloid-App")
2309
+ >>> app.get_watched_directories()
2310
+ ['/path/to/directory1', '/path/to/directory2']
2311
+ """
2312
+ return self.execute_command("get_watched_directories", {})
2313
+
2314
+ def remove_all_watched_paths(self) -> None:
2315
+ """
2316
+ Removes all paths from the watch list.
2317
+
2318
+ Examples
2319
+ --------
2320
+ >>> app = Pyloid(app_name="Pyloid-App")
2321
+ >>> app.remove_all_watched_paths()
2322
+ """
2323
+ return self.execute_command("remove_all_watched_paths", {})
2324
+
2325
+ def set_file_change_callback(self, callback: Callable[[str], None]) -> None:
2326
+ """
2327
+ Sets the callback function to be called when a file is changed.
2328
+
2329
+ Parameters
2330
+ ----------
2331
+ callback : Callable[[str], None]
2332
+ Function to be called when a file is changed
2333
+
2334
+ Examples
2335
+ --------
2336
+ >>> def on_file_change(file_path):
2337
+ >>> print(f"File changed: {file_path}")
2338
+ >>> app = Pyloid(app_name="Pyloid-App")
2339
+ >>> app.set_file_change_callback(on_file_change)
2340
+ """
2341
+ return self.execute_command("set_file_change_callback", {"callback": callback})
2342
+
2343
+ def set_directory_change_callback(self, callback: Callable[[str], None]) -> None:
2344
+ """
2345
+ Sets the callback function to be called when a directory is changed.
2346
+
2347
+ Parameters
2348
+ ----------
2349
+ callback : Callable[[str], None]
2350
+ Function to be called when a directory is changed
2351
+
2352
+ Examples
2353
+ --------
2354
+ >>> def on_directory_change(dir_path):
2355
+ >>> print(f"Directory changed: {dir_path}")
2356
+ >>> app = Pyloid(app_name="Pyloid-App")
2357
+ >>> app.set_directory_change_callback(on_directory_change)
2358
+ """
2359
+ return self.execute_command("set_directory_change_callback", {"callback": callback})
2360
+
2361
+ def open_file_dialog(self, dir: Optional[str] = None, filter: Optional[str] = None) -> Optional[str]:
2362
+ """
2363
+ Opens a file dialog to select a file to open.
2364
+
2365
+ Parameters
2366
+ ----------
2367
+ dir : str, optional
2368
+ The initial directory that the dialog will open in.
2369
+ filter : str, optional
2370
+ A string that specifies the file types that can be selected.
2371
+
2372
+ Returns
2373
+ -------
2374
+ Optional[str]
2375
+ The path of the selected file or None if no file is selected.
2376
+
2377
+ Examples
2378
+ --------
2379
+ >>> app = Pyloid(app_name="Pyloid-App")
2380
+ >>> file_path = app.open_file_dialog(dir="/home/user", filter="Text Files (*.txt)")
2381
+ """
2382
+ return self.execute_command("open_file_dialog", {"dir": dir, "filter": filter})
2383
+
2384
+ def save_file_dialog(self, dir: Optional[str] = None, filter: Optional[str] = None) -> Optional[str]:
2385
+ """
2386
+ Opens a file dialog to select a file to save.
2387
+
2388
+ Parameters
2389
+ ----------
2390
+ dir : str, optional
2391
+ The initial directory that the dialog will open in.
2392
+ filter : str, optional
2393
+ A string that specifies the file types that can be saved.
2394
+
2395
+ Returns
2396
+ -------
2397
+ Optional[str]
2398
+ The path of the selected file or None if no file is selected.
2399
+
2400
+ Examples
2401
+ --------
2402
+ >>> app = Pyloid(app_name="Pyloid-App")
2403
+ >>> file_path = app.save_file_dialog(dir="/home/user", filter="Text Files (*.txt)")
2404
+ """
2405
+ return self.execute_command("save_file_dialog", {"dir": dir, "filter": filter})
2406
+
2407
+ def select_directory_dialog(self, dir: Optional[str] = None) -> Optional[str]:
2408
+ """
2409
+ Opens a dialog to select a directory.
2410
+
2411
+ Parameters
2412
+ ----------
2413
+ dir : str, optional
2414
+ The initial directory that the dialog will open in.
2415
+
2416
+ Returns
2417
+ -------
2418
+ Optional[str]
2419
+ The path of the selected directory or None if no directory is selected.
2420
+
2421
+ Examples
2422
+ --------
2423
+ >>> app = Pyloid(app_name="Pyloid-App")
2424
+ >>> directory_path = app.select_directory_dialog(dir="/home/user")
2425
+ """
2426
+ return self.execute_command("select_directory_dialog", {"dir": dir})