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