Skip to content

Commit

Permalink
Merge pull request #741 from freakboy3742/async-windows
Browse files Browse the repository at this point in the history
Add Winforms-compatible asyncio Proactor.
  • Loading branch information
freakboy3742 authored Oct 12, 2019
2 parents 49ffdce + a674288 commit a9e27f5
Show file tree
Hide file tree
Showing 23 changed files with 285 additions and 65 deletions.
1 change: 1 addition & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ exclude=\
src/*/build,\
src/gtk/toga_gtk/libs/gtk.py
src/gtk/toga_gtk/libs/__init__.py
src/winforms/toga_winforms/libs/__init__.py
examples/.template,\
examples/*/android,\
examples/*/linux,\
Expand Down
3 changes: 3 additions & 0 deletions src/android/toga_android/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ def main_loop(self):
# main Android event loop.
pass

def set_main_window(self, window):
pass

def exit(self):
pass

Expand Down
3 changes: 3 additions & 0 deletions src/cocoa/toga_cocoa/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,9 @@ def main_loop(self):

self.loop.run_forever(lifecycle=CocoaLifecycle(self.native))

def set_main_window(self, window):
pass

def exit(self):
self.native.terminate(None)

Expand Down
1 change: 1 addition & 0 deletions src/core/toga/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ def main_window(self):
def main_window(self, window):
self._main_window = window
window.app = self
self._impl.set_main_window(window)

@property
def current_window(self):
Expand Down
3 changes: 3 additions & 0 deletions src/django/toga_django/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ def open_document(self, fileURL):
def create_menus(self):
self.interface.factory.not_implemented('App.create_menus()')

def set_main_window(self, window):
pass

def exit(self):
pass

Expand Down
3 changes: 3 additions & 0 deletions src/dummy/toga_dummy/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ def create_menus(self):
def main_loop(self):
self._action('main loop')

def set_main_window(self, window):
self._set_value('main_window', window)

def exit(self):
self._action('exit')

Expand Down
3 changes: 3 additions & 0 deletions src/gtk/toga_gtk/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,9 @@ def main_loop(self):

self.loop.run_forever(application=self.native)

def set_main_window(self, window):
pass

def exit(self):
self.native.quit()

Expand Down
3 changes: 3 additions & 0 deletions src/iOS/toga_iOS/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ def main_loop(self):

self.loop.run_forever(lifecycle=iOSLifecycle())

def set_main_window(self, window):
pass

def exit(self):
pass

Expand Down
2 changes: 1 addition & 1 deletion src/winforms/setup.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#/usr/bin/env python
#!/usr/bin/env python
import io
import re

Expand Down
26 changes: 21 additions & 5 deletions src/winforms/toga_winforms/app.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import asyncio
import sys
import traceback

import toga
from toga.handlers import wrapped_handler

from .libs import Threading, WinForms, add_handler, user32, win_version, shcore
from .libs import Threading, WinForms, user32, win_version, shcore
from .libs.proactor import WinformsProactorEventLoop
from .window import Window


Expand All @@ -18,8 +22,12 @@ def __init__(self, interface):
self.interface = interface
self.interface._impl = self

self.loop = WinformsProactorEventLoop()
asyncio.set_event_loop(self.loop)

def create(self):
self.native = WinForms.Application
self.app_context = WinForms.ApplicationContext()

# Check the version of windows and make sure we are setting the DPI mode
# with the most up to date API
Expand Down Expand Up @@ -76,7 +84,7 @@ def create_menus(self):
submenu = WinForms.ToolStripMenuItem(cmd.group.label)
item = WinForms.ToolStripMenuItem(cmd.label)
if cmd.action:
item.Click += add_handler(cmd)
item.Click += cmd._impl.as_handler()
else:
item.Enabled = False
cmd._impl.native.append(item)
Expand Down Expand Up @@ -118,10 +126,12 @@ def app_exception_handler(self, sender, winforms_exc):
def run_app(self):
try:
self.create()

self.native.ThreadException += self.app_exception_handler
self.native.Run(self.interface.main_window._impl.native)
self.native.ApplicationExit += self.app_exit_handler

self.loop.run_forever(self.app_context)
except: # NOQA
import traceback
traceback.print_exc()

def main_loop(self):
Expand All @@ -130,9 +140,15 @@ def main_loop(self):
thread.Start()
thread.Join()

def app_exit_handler(self, sender, *args, **kwargs):
pass

def exit(self):
self.native.Exit()

def set_main_window(self, window):
self.app_context.MainForm = window._impl.native

def set_on_exit(self, value):
pass

Expand All @@ -155,7 +171,7 @@ def hide_cursor(self):
self.interface.factory.not_implemented('App.hide_cursor()')

def add_background_task(self, handler):
self.interface.factory.not_implemented('App.add_background_task()')
self.loop.call_soon(wrapped_handler(self, handler), self)


class DocumentApp(App):
Expand Down
6 changes: 6 additions & 0 deletions src/winforms/toga_winforms/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,9 @@ def set_enabled(self, value):
if self.native:
for widget in self.native:
widget.Enabled = self.interface.enabled

def as_handler(self):
def handler(sender, event):
return self.interface.action(None)

return handler
9 changes: 6 additions & 3 deletions src/winforms/toga_winforms/icons.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,12 @@ def create_icon_from_file(filename):
self.native = create_icon_from_file(file_path + '.bmp')

else:
print("[Winforms] No valid icon format available for {}; "
"fall back on Tiberius instead".format(
self.interface.filename))
print(
"[Winforms] No valid icon format available for {}; "
"fall back on Tiberius instead".format(
self.interface.filename
)
)
tiberius_file = toga_Icon.TIBERIUS_ICON.filename + '.ico'
self.interface.icon = toga_Icon.TIBERIUS_ICON
self.native = WinIcon(tiberius_file)
1 change: 1 addition & 0 deletions src/winforms/toga_winforms/images.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from toga_winforms.libs import WinImage
import os


class Image(object):
def __init__(self, interface):
self.interface = interface
Expand Down
25 changes: 25 additions & 0 deletions src/winforms/toga_winforms/libs/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from .winforms import ( # noqa: F401
Bitmap,
Color,
Convert,
FontFamily,
FontStyle,
Point,
Single,
Size,
Threading,
Uri,
WinDateTime,
WinFont,
WinForms,
WinIcon,
WinImage,
shcore,
user32,
win_version
)
from .fonts import (
HorizontalTextAlignment,
TextAlignment,
win_font_family
)
Original file line number Diff line number Diff line change
@@ -1,25 +1,6 @@
import ctypes
from .winforms import ContentAlignment, FontFamily, WinForms, SystemFonts, Text

import clr

clr.AddReference("System.Windows.Forms")

import System.Windows.Forms as WinForms # noqa: E402
from System import Decimal as ClrDecimal # noqa: E402, F401
from System import Single # noqa: E402, F401
from System import Convert # noqa: E402, F401
from System import DateTime as WinDateTime # noqa: E402, F401
from System import Threading # noqa: E402, F401
from System import Uri # noqa: E402, F401
from System import Environment # noqa: E402, F401

from System.Drawing import Icon as WinIcon # noqa: E402, F401
from System.Drawing import Image as WinImage # noqa: E402, F401
from System.Drawing import Font as WinFont # noqa: E402, F401
from System.Drawing import ContentAlignment, Size, Point # noqa: E402, F401
from System.Drawing import FontFamily, FontStyle, SystemFonts # noqa: E402, F401
from System.Drawing import Text, Color, Bitmap # noqa: E402, F401
from toga.constants import LEFT, RIGHT, CENTER, JUSTIFY # noqa: E402
from toga.constants import LEFT, RIGHT, CENTER, JUSTIFY
from toga.fonts import (
MESSAGE,
SYSTEM,
Expand All @@ -28,16 +9,7 @@
CURSIVE,
FANTASY,
MONOSPACE,
) # noqa: E402

user32 = ctypes.windll.user32
# shcore dll not exist on some Windows versions
# win_version should be checked to ensure proper usage
try:
shcore = ctypes.windll.shcore
except OSError:
shcore = None
win_version = Environment.OSVersion.Version
)


def TextAlignment(value):
Expand All @@ -59,15 +31,6 @@ def HorizontalTextAlignment(value):
}[value]


def add_handler(cmd):
action = cmd.action

def handler(sender, event):
return action(None)

return handler


def win_font_family(value):
win_families = {
SYSTEM: SystemFonts.DefaultFont.FontFamily,
Expand Down
Loading

0 comments on commit a9e27f5

Please sign in to comment.