Repository: beeware/toga

Issue:
Tutorial 4 does not draw anything except from text
## Expected Behavior
Tutorial 4 should draw Tiberius along with text and a box around it


## Current Behavior
Tutorial 4 only draws text - no error is output, only the following message:
`[Cocoa] Not implemented: Canvas.on_resize`

## Steps to reproduce
<!--- Provide a set of steps describing how to reproduce this bug. If you have a live example, provide the link below -->
1. Create a new Conda environment using Python 3.7.6

2. Install toga as outlined in https://toga.readthedocs.io/en/latest/how-to/contribute.html

3. Paste the code found in https://toga.readthedocs.io/en/latest/tutorial/tutorial-4.html into tutorial4.py

4. `python tutorial4.py`


## Your Environment
<!--- Provide details on your current environment you found the bug in -->

* Python Version 
Python 3.7.6

* Operating System and Version (select from the following and list the specific version number; if your OS is not listed, list that as well)

  - [X] macOS - version: 10.15.2 (19C57)
  - [ ] Linux - distro:   - version:
  - [ ] Windows - version:
  - [ ] Other - name:  - version:

* Toga Version 
b40f067db6af099cf486166bfc74fc8c9e56decf

* Toga Target (the type of app you are trying to generate)

  - [ ] android
  - [X] cocoa
  - [ ] django
  - [ ] gtk
  - [ ] iOS
  - [ ] tvOS
  - [ ] watchOS
  - [ ] winforms
  - [ ] win32
  - [ ] Other (please specify)



Discussion:
Thanks for the report!

The "on_resize" message is to be expected; that's not an error, just a warning that resize features aren't fully implemented on Cocoa.

However, it's odd that you're seeing the text, but not the rest of the image. That's not a behavior that I've seen before, and I haven't been able to reproduce it in my own testing. The only notable difference between your system and mine is the version of macOS - I'm still on 10.14 - but I wouldn't have thought that would be the cause...

Is there anything else that might be considered notable about your setup?
It's a clean Conda environment with just toga, pyserial and msgpack installed. Nothing else noteworthy really.. Has Toga been tested on the latest MacOS?
*I* haven't tested it on 10.15, but I believe others have. 

Any assistance you can provide would be gratefully accepted. Are you able to confirm (dropping print statements into the codebase would be enough) that the Toga canvas drawing commands are actually being executed? Knowing whether the commands are executing, but not doing anything vs failing silently would be a good starting point.

Resolving patch:
diff --git a/src/cocoa/toga_cocoa/libs/appkit.py b/src/cocoa/toga_cocoa/libs/appkit.py
--- a/src/cocoa/toga_cocoa/libs/appkit.py
+++ b/src/cocoa/toga_cocoa/libs/appkit.py
@@ -91,6 +91,7 @@ class NSAlertStyle(Enum):
 NSGlyphInfoAttributeName = objc_const(appkit, "NSGlyphInfoAttributeName")
 
 NSViewBoundsDidChangeNotification = objc_const(appkit, 'NSViewBoundsDidChangeNotification')
+NSViewFrameDidChangeNotification = objc_const(appkit, 'NSViewFrameDidChangeNotification')
 
 ######################################################################
 # NSBezierPath.h
diff --git a/src/cocoa/toga_cocoa/libs/foundation.py b/src/cocoa/toga_cocoa/libs/foundation.py
--- a/src/cocoa/toga_cocoa/libs/foundation.py
+++ b/src/cocoa/toga_cocoa/libs/foundation.py
@@ -1,10 +1,9 @@
 ##########################################################################
 # System/Library/Frameworks/Foundation.framework
 ##########################################################################
-from ctypes import *
-from ctypes import util
+from ctypes import cdll, c_bool, util
 
-from rubicon.objc import *
+from rubicon.objc import NSPoint, NSRect, ObjCClass
 
 ######################################################################
 foundation = cdll.LoadLibrary(util.find_library('Foundation'))
diff --git a/src/cocoa/toga_cocoa/widgets/canvas.py b/src/cocoa/toga_cocoa/widgets/canvas.py
--- a/src/cocoa/toga_cocoa/widgets/canvas.py
+++ b/src/cocoa/toga_cocoa/widgets/canvas.py
@@ -1,4 +1,4 @@
-from rubicon.objc import CGFloat
+from rubicon.objc import CGFloat, SEL
 
 from toga_cocoa.libs import (
     core_graphics,
@@ -12,11 +12,13 @@
     NSForegroundColorAttributeName,
     NSGraphicsContext,
     NSMutableDictionary,
+    NSNotificationCenter,
     NSPoint,
     NSStrokeColorAttributeName,
     NSStrokeWidthAttributeName,
     NSRect,
     NSView,
+    NSViewFrameDidChangeNotification,
     objc_method,
 )
 from toga_cocoa.colors import native_color
@@ -27,7 +29,7 @@
 class TogaCanvas(NSView):
     @objc_method
     def drawRect_(self, rect: NSRect) -> None:
-        context = NSGraphicsContext.currentContext.graphicsPort()
+        context = NSGraphicsContext.currentContext.CGContext
 
         if self.interface.redraw:
             self.interface._draw(self._impl, draw_context=context)
@@ -37,6 +39,11 @@ def isFlipped(self) -> bool:
         # Default Cocoa coordinate frame is around the wrong way.
         return True
 
+    @objc_method
+    def frameChanged_(self, notification) -> None:
+        if self.interface.on_resize:
+            self.interface.on_resize(self.interface)
+
 
 class Canvas(Widget):
     def create(self):
@@ -44,6 +51,13 @@ def create(self):
         self.native.interface = self.interface
         self.native._impl = self
 
+        NSNotificationCenter.defaultCenter.addObserver(
+            self.native,
+            selector=SEL("frameChanged:"),
+            name=NSViewFrameDidChangeNotification,
+            object=self.native
+        )
+
         # Add the layout constraints
         self.add_constraints()
 
@@ -225,4 +239,4 @@ def rehint(self):
         self.interface.intrinsic.width = fitting_size.width
 
     def set_on_resize(self, handler):
-        self.interface.factory.not_implemented('Canvas.on_resize')
+        pass


Test patch: