webview2 0.0.1__tar.gz

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.
@@ -0,0 +1,52 @@
1
+ Metadata-Version: 2.4
2
+ Name: webview2
3
+ Version: 0.0.1
4
+ Summary: Build immersive applications supported by WebView2 on Windows Operation Systems
5
+ Home-page: https://github.com/aiyojun/pypi-repo
6
+ Author: aiyojun
7
+ Author-email: aiyojun@gmail.com
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Operating System :: Microsoft :: Windows
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Topic :: Software Development :: Libraries
13
+ Description-Content-Type: text/markdown
14
+ Requires-Dist: pywin32
15
+ Requires-Dist: voxe==0.0.4
16
+ Dynamic: author
17
+ Dynamic: author-email
18
+ Dynamic: classifier
19
+ Dynamic: description
20
+ Dynamic: description-content-type
21
+ Dynamic: home-page
22
+ Dynamic: requires-dist
23
+ Dynamic: summary
24
+
25
+ # Project description
26
+
27
+ Build immersive applications supported by WebView2 on Windows Operation Systems
28
+
29
+ ## Usage
30
+
31
+ ```python
32
+ import asyncio
33
+
34
+ from webview2 import Window, webview2_api
35
+
36
+ class MainWindow(Window):
37
+ @webview2_api
38
+ def greeting(self):
39
+ return "hello webview2"
40
+
41
+
42
+ win = MainWindow(
43
+ title="My App", size="1480x960",# icon="logo.ico",
44
+ url="https://www.bing.com",# cache="PATH_OF_WEBVIEW2_CACHE"
45
+ )
46
+ asyncio.run(win.run())
47
+
48
+ ```
49
+
50
+ ## Titlebar
51
+
52
+ Mark the css `app-region:drag;` of the title bar element to achieve the effect of dragging the title bar.
@@ -0,0 +1,28 @@
1
+ # Project description
2
+
3
+ Build immersive applications supported by WebView2 on Windows Operation Systems
4
+
5
+ ## Usage
6
+
7
+ ```python
8
+ import asyncio
9
+
10
+ from webview2 import Window, webview2_api
11
+
12
+ class MainWindow(Window):
13
+ @webview2_api
14
+ def greeting(self):
15
+ return "hello webview2"
16
+
17
+
18
+ win = MainWindow(
19
+ title="My App", size="1480x960",# icon="logo.ico",
20
+ url="https://www.bing.com",# cache="PATH_OF_WEBVIEW2_CACHE"
21
+ )
22
+ asyncio.run(win.run())
23
+
24
+ ```
25
+
26
+ ## Titlebar
27
+
28
+ Mark the css `app-region:drag;` of the title bar element to achieve the effect of dragging the title bar.
@@ -0,0 +1,3 @@
1
+ [build-system]
2
+ requires = ["setuptools>=42", "wheel"]
3
+ build-backend = "setuptools.build_meta"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,32 @@
1
+ import sys
2
+
3
+ import setuptools
4
+
5
+ if sys.platform != "win32":
6
+ raise RuntimeError("This package only supports Windows 10 or later")
7
+
8
+ with open("README.md", 'r', encoding='utf-8') as fp:
9
+ readme = fp.read()
10
+
11
+ setuptools.setup(
12
+ name="webview2",
13
+ version="0.0.1",
14
+ author="aiyojun",
15
+ author_email="aiyojun@gmail.com",
16
+ description="Build immersive applications supported by WebView2 on Windows Operation Systems",
17
+ long_description=readme,
18
+ long_description_content_type="text/markdown",
19
+ url="https://github.com/aiyojun/pypi-repo",
20
+ packages=setuptools.find_packages(),
21
+ install_requires=[
22
+ "pywin32",
23
+ "voxe==0.0.4",
24
+ ],
25
+ classifiers=[
26
+ "Development Status :: 3 - Alpha",
27
+ "Operating System :: Microsoft :: Windows",
28
+ "Programming Language :: Python :: 3",
29
+ "Intended Audience :: Developers",
30
+ "Topic :: Software Development :: Libraries",
31
+ ],
32
+ )
@@ -0,0 +1,20 @@
1
+ from .bridge import Window, webview2_api
2
+
3
+ __version__ = "0.0.1"
4
+
5
+ __all__ = ["Window", "webview2_api"]
6
+
7
+ def main(args: list[str] | None = None) -> int:
8
+ import sys
9
+ import argparse
10
+ parser = argparse.ArgumentParser(description='Run an application by webview.')
11
+ parser.add_argument('--url', type=str, help='Entry of the application')
12
+ parser.add_argument('--icon', type=str, required=False, default=None, help='Path of app icon')
13
+ parser.add_argument('--title', type=str, required=False, default=None, help='Application title')
14
+ parser.add_argument('--cache', type=str, required=False, default=None, help='Path of webview cache')
15
+ parser.add_argument('--size', type=str, required=False, default=None, help='Window size')
16
+ args = parser.parse_args(sys.argv[1:] if args is None else args)
17
+ win = Window(args.title, args.icon, args.url, args.size, args.cache)
18
+ import asyncio
19
+ asyncio.run(win.run())
20
+ return 0
@@ -0,0 +1,6 @@
1
+ import sys
2
+
3
+ if __name__ == "__main__":
4
+ from . import main
5
+
6
+ sys.exit(main())
@@ -0,0 +1,225 @@
1
+ import asyncio
2
+ import ctypes
3
+ import functools
4
+ import json
5
+ import os
6
+ import pathlib
7
+ import re
8
+ import traceback
9
+ import typing
10
+ import uuid
11
+
12
+ import pythoncom
13
+ import voxe
14
+ import win32con
15
+ import win32gui
16
+
17
+ from .core import dll, listener
18
+
19
+ _dir_ = os.path.dirname(__file__)
20
+
21
+
22
+ class Transport:
23
+ chunk: int = 1024 * 1024 * 10
24
+ reqid: typing.Optional[str] = None
25
+ pkgid: typing.Optional[str] = None
26
+ total: int = 0
27
+ cache: typing.Optional[bytearray] = None
28
+ offset: int = 0
29
+ futures: typing.Dict[str, asyncio.Future[bytearray]] = {}
30
+ acks: typing.Dict[str, asyncio.Future[int]] = {}
31
+ on_service = None
32
+ scopes = {}
33
+ cb = None
34
+ cb2 = None
35
+
36
+ def __init__(self):
37
+ self.cb = lambda x: self.on_listen(x)
38
+ self.cb2 = listener(self.cb)
39
+ dll.set_listener(self.cb2)
40
+
41
+ def _read(self, size):
42
+ buf = (ctypes.c_uint8 * size)()
43
+ dll.read(buf, size)
44
+ return bytes(buf[:size])
45
+
46
+ def _write(self, data: bytes):
47
+ data = data if type(data) is bytearray else bytearray(data)
48
+ size = len(data)
49
+ buf = (ctypes.c_uint8 * size).from_buffer(data)
50
+ return dll.write(buf, size)
51
+
52
+ def on_listen(self, buf: bytes):
53
+ try:
54
+ data = json.loads(buf)
55
+ if "type" not in data:
56
+ return
57
+ if data["type"] == "ack":
58
+ pkgid = data["pkgid"]
59
+ if pkgid in self.acks:
60
+ self.acks[pkgid].set_result(1)
61
+ return
62
+ if data["type"] != "req":
63
+ return
64
+ self.pkgid = data["pkgid"]
65
+ if self.reqid is None or self.reqid != data["reqid"]:
66
+ self.reqid = data["reqid"]
67
+ self.total = data["total"]
68
+ self.cache = bytearray(self.total)
69
+ self.offset = 0
70
+ size = data["size"]
71
+ self.cache[self.offset:self.offset + size] = self._read(size)
72
+ dll.post(json.dumps(dict(type="ack", pkgid=self.pkgid, reqid=self.reqid)).encode(encoding='utf-8'))
73
+ self.offset += size
74
+ if self.offset >= self.total:
75
+ try:
76
+ ctx = voxe.loads(bytes(self.cache))
77
+ method_name, args = ctx[0], ctx[1:]
78
+ if type(self.scopes) is dict:
79
+ if method_name in self.scopes:
80
+ r = self.scopes[method_name](*args)
81
+ asyncio.create_task(self.post_packet(voxe.dumps(0, r), self.reqid))
82
+ else:
83
+ asyncio.create_task(self.post_packet(voxe.dumps(1, "no such method"), self.reqid))
84
+ else:
85
+ if method_name in dir(self.scopes):
86
+ method = getattr(self.scopes, method_name)
87
+ r = method(*args)
88
+ asyncio.create_task(self.post_packet(voxe.dumps(0, r), self.reqid))
89
+ else:
90
+ asyncio.create_task(self.post_packet(voxe.dumps(1, "no such method"), self.reqid))
91
+ except Exception as e:
92
+ traceback.print_exc()
93
+ asyncio.create_task(self.post_packet(voxe.dumps(1, str(e)), self.reqid))
94
+ pass
95
+ if self.on_service:
96
+ self.on_service(self.cache)
97
+ if self.offset >= self.total and self.reqid in self.futures:
98
+ self.futures[self.reqid].set_result(self.cache)
99
+ self.reqid = None
100
+ self.cache = None
101
+ except json.decoder.JSONDecodeError:
102
+ pass
103
+ except Exception as e:
104
+ traceback.print_exc()
105
+
106
+ async def post_packet(self, data: bytes, reqid=None):
107
+ if reqid is None:
108
+ reqid = str(uuid.uuid4()).replace("-", "")
109
+ size = len(data)
110
+ chunk = self.chunk
111
+ pb, pe = 0, 0
112
+ while pb < size:
113
+ pe = pb + chunk
114
+ if pe > size:
115
+ pe = size
116
+ pkgid = str(uuid.uuid4()).replace("-", "")
117
+ ack = asyncio.Future()
118
+ self.acks[pkgid] = ack
119
+ self._write(data[pb:pe])
120
+ try:
121
+ dll.post(json.dumps(dict(type="req", reqid=reqid, pkgid=pkgid, total=size, size=pe-pb)).encode('utf-8'))
122
+ await asyncio.wait_for(ack, None)
123
+ except Exception:
124
+ traceback.print_exc()
125
+ finally:
126
+ del self.acks[pkgid]
127
+ pb = pe
128
+
129
+ async def request(self, data: bytes, timeout=None):
130
+ reqid = str(uuid.uuid4()).replace("-", "")
131
+ future = asyncio.Future()
132
+ self.futures[reqid] = future
133
+ await self.post_packet(data, reqid)
134
+ r = await asyncio.wait_for(future, timeout=timeout)
135
+ del self.futures[reqid]
136
+ return r
137
+
138
+
139
+ def webview2_api(func):
140
+ @functools.wraps(func)
141
+ def wrapper(*args, **kwargs):
142
+ return func(*args, **kwargs)
143
+
144
+ wrapper.__webview2_api__ = True
145
+ return wrapper
146
+
147
+
148
+ class Window:
149
+ def __init__(self, title=None, icon=None, url=None, size=None, cache=None, memory_size=1024*1024*10):
150
+ if cache is not None:
151
+ os.environ["WEBVIEW2_USER_DATA_FOLDER"] = cache
152
+ if size is not None and 'x' in size.lower():
153
+ size = [int(item) for item in size.lower().split('x')]
154
+ width, height = size[0], size[1]
155
+ dll.set_size(width, height)
156
+ if title is not None:
157
+ dll.set_title(title.encode(encoding='utf-8'))
158
+ if icon is not None:
159
+ dll.set_icon(icon.encode(encoding='utf-8'))
160
+ if url is not None:
161
+ dll.set_navigation(url.encode(encoding='utf-8'))
162
+ if memory_size is not None:
163
+ dll.set_memory(memory_size)
164
+ transport = Transport()
165
+ transport.scopes = self
166
+
167
+ async def run(self):
168
+ pythoncom.OleInitialize()
169
+ dll.preload(self._build_context(os.path.join(_dir_, "webview2.js")).encode(encoding='utf-8'))
170
+ dll.build()
171
+ while True:
172
+ r = win32gui.PeekMessage(None, 0, 0, win32con.PM_REMOVE)
173
+ code, msg = r
174
+ if code == 0:
175
+ await asyncio.sleep(0.005)
176
+ continue
177
+ if msg[1] == win32con.WM_QUIT:
178
+ break
179
+ win32gui.TranslateMessage(msg)
180
+ win32gui.DispatchMessage(msg)
181
+ self.close()
182
+ pythoncom.CoUninitialize()
183
+ return 0
184
+
185
+ def _build_context(self, script_path):
186
+ script = pathlib.Path(script_path).read_text()
187
+ methods = []
188
+ for name in dir(self):
189
+ if not re.match(r"^[a-zA-Z][a-zA-Z0-9_]*$", name):
190
+ continue
191
+ member = getattr(self, name)
192
+ if not callable(member):
193
+ continue
194
+ func = member.__func__ if hasattr(member, "__func__") else member
195
+ if not getattr(func, "__webview2_api__", False):
196
+ continue
197
+ methods.append(
198
+ f"{name}:async(...args)=>await invoke(window.webview2.transport,window.webview2.voxe,'{name}', ...args)")
199
+ ptr = script.rfind("}")
200
+ script = (script[0:ptr]
201
+ + ";Object.defineProperty(window,'webview2',Object.freeze({value:{api:{"
202
+ + ",".join(methods)
203
+ + "},voxe:new Voxe(),transport:new Transport()},writable:false,configurable:false,enumerable:false}))"
204
+ + script[ptr:])
205
+ return script
206
+
207
+ @webview2_api
208
+ def close(self):
209
+ hwnd = dll.get_window()
210
+ win32gui.SendMessage(hwnd, win32con.WM_CLOSE, 0, 0)
211
+
212
+ @webview2_api
213
+ def maximize(self):
214
+ hwnd = dll.get_window()
215
+ win32gui.ShowWindow(hwnd, win32con.SW_MAXIMIZE)
216
+
217
+ @webview2_api
218
+ def minimize(self):
219
+ hwnd = dll.get_window()
220
+ win32gui.ShowWindow(hwnd, win32con.SW_MINIMIZE)
221
+
222
+ @webview2_api
223
+ def restore(self):
224
+ hwnd = dll.get_window()
225
+ win32gui.ShowWindow(hwnd, win32con.SW_RESTORE)
@@ -0,0 +1,56 @@
1
+ import ctypes
2
+ import os
3
+
4
+ os.add_dll_directory(os.path.dirname(__file__))
5
+ dll = ctypes.CDLL("WebView2Window.dll")
6
+
7
+ listener = ctypes.CFUNCTYPE(None, ctypes.c_char_p)
8
+ set_title = dll.set_title
9
+ set_position = dll.set_position
10
+ set_size = dll.set_size
11
+ set_client = dll.set_client
12
+ set_navigation = dll.set_navigation
13
+ set_icon = dll.set_icon
14
+ set_listener = dll.set_listener
15
+ set_memory = dll.set_memory
16
+ get_window = dll.get_window
17
+ read = dll.read
18
+ write = dll.write
19
+ post = dll.post
20
+ build = dll.build
21
+ destroy = dll.destroy
22
+ preload = dll.preload
23
+ evaluate = dll.evaluate
24
+
25
+ set_title.argtypes = [ctypes.c_char_p]
26
+ set_title.restype = None
27
+ set_position.argtypes = [ctypes.c_int, ctypes.c_int]
28
+ set_position.restype = None
29
+ set_size.argtypes = [ctypes.c_int, ctypes.c_int]
30
+ set_size.restype = None
31
+ set_client.argtypes = [ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int]
32
+ set_client.restype = None
33
+ set_navigation.argtypes = [ctypes.c_char_p]
34
+ set_navigation.restype = None
35
+ set_icon.argtypes = [ctypes.c_char_p]
36
+ set_icon.restype = None
37
+ set_listener.argtypes = [listener]
38
+ set_listener.restype = None
39
+ set_memory.argtypes = [ctypes.c_int]
40
+ set_memory.restype = None
41
+ get_window.argtypes = []
42
+ get_window.restype = ctypes.c_void_p
43
+ read.argtypes = [ctypes.POINTER(ctypes.c_uint8), ctypes.c_int]
44
+ read.restype = ctypes.c_int
45
+ write.argtypes = [ctypes.POINTER(ctypes.c_uint8), ctypes.c_int]
46
+ write.restype = ctypes.c_int
47
+ post.argtypes = [ctypes.c_char_p]
48
+ post.restype = None
49
+ build.argtypes = []
50
+ build.restype = None
51
+ destroy.argtypes = []
52
+ destroy.restype = None
53
+ preload.argtypes = [ctypes.c_char_p]
54
+ preload.restype = None
55
+ evaluate.argtypes = [ctypes.c_char_p, listener]
56
+ evaluate.restype = None
@@ -0,0 +1,52 @@
1
+ Metadata-Version: 2.4
2
+ Name: webview2
3
+ Version: 0.0.1
4
+ Summary: Build immersive applications supported by WebView2 on Windows Operation Systems
5
+ Home-page: https://github.com/aiyojun/pypi-repo
6
+ Author: aiyojun
7
+ Author-email: aiyojun@gmail.com
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Operating System :: Microsoft :: Windows
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Topic :: Software Development :: Libraries
13
+ Description-Content-Type: text/markdown
14
+ Requires-Dist: pywin32
15
+ Requires-Dist: voxe==0.0.4
16
+ Dynamic: author
17
+ Dynamic: author-email
18
+ Dynamic: classifier
19
+ Dynamic: description
20
+ Dynamic: description-content-type
21
+ Dynamic: home-page
22
+ Dynamic: requires-dist
23
+ Dynamic: summary
24
+
25
+ # Project description
26
+
27
+ Build immersive applications supported by WebView2 on Windows Operation Systems
28
+
29
+ ## Usage
30
+
31
+ ```python
32
+ import asyncio
33
+
34
+ from webview2 import Window, webview2_api
35
+
36
+ class MainWindow(Window):
37
+ @webview2_api
38
+ def greeting(self):
39
+ return "hello webview2"
40
+
41
+
42
+ win = MainWindow(
43
+ title="My App", size="1480x960",# icon="logo.ico",
44
+ url="https://www.bing.com",# cache="PATH_OF_WEBVIEW2_CACHE"
45
+ )
46
+ asyncio.run(win.run())
47
+
48
+ ```
49
+
50
+ ## Titlebar
51
+
52
+ Mark the css `app-region:drag;` of the title bar element to achieve the effect of dragging the title bar.
@@ -0,0 +1,12 @@
1
+ README.md
2
+ pyproject.toml
3
+ setup.py
4
+ webview2/__init__.py
5
+ webview2/__main__.py
6
+ webview2/bridge.py
7
+ webview2/core.py
8
+ webview2.egg-info/PKG-INFO
9
+ webview2.egg-info/SOURCES.txt
10
+ webview2.egg-info/dependency_links.txt
11
+ webview2.egg-info/requires.txt
12
+ webview2.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ pywin32
2
+ voxe==0.0.4
@@ -0,0 +1 @@
1
+ webview2