From 2fdec80fe173e0f91e72e02bb731f6a7c1be528c Mon Sep 17 00:00:00 2001 From: Jens Thiede Date: Mon, 10 Oct 2011 16:51:51 +0200 Subject: [PATCH] Some major refactoring. Key events fully implemented. --- glop.asd | 5 +- src/glop.lisp | 14 ++ src/osx/appkit.lisp | 133 +++++++++--------- src/osx/bridge/GlopGLView.h | 4 - src/osx/bridge/GlopGLView.m | 37 ----- .../{GlopWindowResponder.h => GlopView.h} | 4 +- .../{GlopWindowResponder.m => GlopView.m} | 54 +++---- src/osx/bridge/Makefile | 2 +- src/osx/bridge/appkit.m | 16 +++ src/osx/bridge/glop-bridge.dylib | Bin 26124 -> 25876 bytes src/osx/foundation.lisp | 51 ++++--- src/osx/glop-gl-view.lisp | 22 --- src/osx/glop-osx.lisp | 61 ++++---- src/osx/glop-view.lisp | 4 + src/osx/glop-window-responder.lisp | 4 - src/osx/package.lisp | 14 +- src/osx/quartz.lisp | 4 +- src/utils.lisp | 6 +- 18 files changed, 195 insertions(+), 240 deletions(-) delete mode 100644 src/osx/bridge/GlopGLView.h delete mode 100644 src/osx/bridge/GlopGLView.m rename src/osx/bridge/{GlopWindowResponder.h => GlopView.h} (62%) rename src/osx/bridge/{GlopWindowResponder.m => GlopView.m} (58%) delete mode 100644 src/osx/glop-gl-view.lisp create mode 100644 src/osx/glop-view.lisp delete mode 100644 src/osx/glop-window-responder.lisp diff --git a/glop.asd b/glop.asd index d8dfb71..084acb8 100644 --- a/glop.asd +++ b/glop.asd @@ -27,13 +27,12 @@ :serial t :components ((:file "package") (:file "carbon") - (:file "quartz") (:file "bridge") (:file "foundation") (:file "appkit") + (:file "quartz") (:file "glop-app") - (:file "glop-window-responder") - (:file "glop-gl-view") + (:file "glop-view") (:file "glop-osx"))) #+(or win32 windows) (:module "win32" diff --git a/src/glop.lisp b/src/glop.lisp index f31f6a1..fd1d323 100644 --- a/src/glop.lisp +++ b/src/glop.lisp @@ -199,6 +199,13 @@ set window fullscreen state." "Swaps GL buffers.")) ;;; Events handling +(defmacro define-simple-print-object (type &rest attribs) + `(defmethod print-object ((event ,type) stream) + (with-slots ,attribs event + (format stream + ,(format nil "#<~~s~{ ~s ~~s~}>" attribs) + (type-of event) ,@attribs)))) + (defclass event () () (:documentation "Common ancestor for all events.")) @@ -208,6 +215,7 @@ set window fullscreen state." (text :initarg :text :reader text) (pressed :initarg :pressed :reader pressed)) (:documentation "Keyboard key press or release.")) +(define-simple-print-object key-event keycode keysym text pressed) (defclass key-press-event (key-event) () @@ -223,6 +231,7 @@ set window fullscreen state." ((button :initarg :button :reader button) (pressed :initarg :pressed :reader pressed)) (:documentation "Mouse button press or release.")) +(define-simple-print-object button-event button pressed) (defclass button-press-event (button-event) () @@ -240,16 +249,19 @@ set window fullscreen state." (dx :initarg :dx :reader dx) (dy :initarg :dy :reader dy)) (:documentation "Mouse motion.")) +(define-simple-print-object mouse-motion-event x y dx dy) (defclass expose-event (event) ((width :initarg :width :reader width) (height :initarg :height :reader height)) (:documentation "Window expose.")) +(define-simple-print-object expose-event width height) (defclass resize-event (event) ((width :initarg :width :reader width) (height :initarg :height :reader height)) (:documentation "Window resized.")) +(define-simple-print-object resize-event width height) (defclass close-event (event) () (:documentation "Window closed.")) @@ -257,6 +269,7 @@ set window fullscreen state." (defclass visibility-event (event) ((visible :initarg :visible :reader visible)) (:documentation "Window visibility changed.")) +(define-simple-print-object visibility-event visible) (defclass visibility-obscured-event (visibility-event) () @@ -271,6 +284,7 @@ set window fullscreen state." (defclass focus-event (event) ((focused :initarg :focused :reader focused)) (:documentation "Window focus state changed.")) +(define-simple-print-object focus-event focused) (defclass focus-in-event (focus-event) () diff --git a/src/osx/appkit.lisp b/src/osx/appkit.lisp index b39f93f..ae2e58b 100644 --- a/src/osx/appkit.lisp +++ b/src/osx/appkit.lisp @@ -65,23 +65,23 @@ (foreign-enum-keyword 'ns-event-type (%ns-event-type event))) (defcenum ns-key-code - :A - :S - :D - :F - :H - :G - :Z - :X - :C - :V - (:B 11) - :Q - :W - :E - :R - :Y - :T + :a + :s + :d + :f + :h + :g + :z + :x + :c + :v + (:b 11) + :q + :w + :e + :r + :y + :t :1 :2 :3 @@ -95,38 +95,39 @@ :8 :0 :|]| - :O - :U + :o + :u :|[| - :I - :P - :enter - :L - :J + :i + :p + :return + :l + :j :|'| - :K + :k (:|;| 41) :|\\| :|,| :|/| - :N - :M + :n + :m :|.| :tab :space :|`| (:backspace 51) - :esc - (:rsuper 54) - :lsuper - :lshift + (:escape 53) + :super-r + :super-l + :shift-l :caps-lock - :lalt - :lctrl - :rshift - :ralt - :rctrl - (:f17 64) + :alt-l + :ctrl-l + :shift-r + :alt-r + :ctrl-r + (:function 63) + :f17 :kp-decimal (:kp-multiply 67) (:kp-add 69) @@ -162,24 +163,23 @@ (:f15 113) :insert :home - :pageup - :del + :page-up + :delete :f4 :end :f2 - :pagedown + :page-down :f1 :left :right :down :up) -(defcfun ("NSEventKeyCode" %ns-event-key-code) :uint16 +(defcfun ("NSEventKeyCode" ns-event-key-code) :uint16 (event :pointer)) -(defun ns-event-key-code (event) - (let* ((code (%ns-event-key-code event)) - (key (foreign-enum-keyword 'ns-key-code code :errorp nil))) +(defun keysym (code) + (let* ((key (foreign-enum-keyword 'ns-key-code code :errorp nil))) (if key key :unknown))) (defbitfield ns-modifier-flags @@ -219,6 +219,8 @@ (defcfun ("NSEventDeltaY" ns-event-delta-y) cg-float (event :pointer)) +(defcfun ("NSEventCharacters" ns-event-characters) ns-string + (event :pointer)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; NSApplication ;;; @@ -240,12 +242,9 @@ (width :int) (height :int)) -(defcfun ("NSWindowSetTitle" %ns-window-set-title) :pointer +(defcfun ("NSWindowSetTitle" ns-window-set-title) :void (window :pointer) - (title :pointer)) -(defun ns-window-set-title (window title) - (with-ns-strings ((ns-title title)) - (%ns-window-set-title window ns-title))) + (title ns-string)) (defcfun ("NSWindowSetBackgroundColor" ns-window-set-background-color) :void (window :pointer) @@ -298,34 +297,23 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(defcfun ("NSMenuAllocInit" %ns-menu-alloc-init) :pointer - (title :pointer)) -(defun ns-menu-alloc-init (title) - (with-ns-strings ((ns-str-title title)) - (%ns-menu-alloc-init ns-str-title))) +(defcfun ("NSMenuAllocInit" ns-menu-alloc-init) :pointer + (title ns-string)) (defcfun ("NSMenuAddItem" ns-menu-add-item) :void (menu :pointer) (item :pointer)) -(defcfun ("NSMenuAddItemWithTitle" %ns-menu-add-item-with-title) :void +(defcfun ("NSMenuAddItemWithTitle" ns-menu-add-item-with-title) :void (menu :pointer) - (title :pointer) + (title ns-string) (selector :pointer) - (key-equiv :pointer)) -(defun ns-menu-add-item-with-title (menu title selector key-equiv) - (with-ns-strings ((ns-str-title title) - (ns-str-key-equiv key-equiv)) - (%ns-menu-add-item-with-title menu ns-str-title selector ns-str-key-equiv))) - -(defcfun ("NSMenuItemAllocInit" %ns-menu-item-alloc-init) :void - (title :pointer) + (key-equiv ns-string)) + +(defcfun ("NSMenuItemAllocInit" ns-menu-item-alloc-init) :void + (title ns-string) (selector :pointer) - (key-equiv :pointer)) -(defun ns-menu-item-alloc-init (title selector key-equiv) - (with-ns-strings ((ns-str-title title) - (ns-str-key-equiv key-equiv)) - (%ns-menu-item-alloc-init ns-str-title selector ns-str-key-equiv))) + (key-equiv ns-string)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -408,6 +396,13 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(defcfun ("NSOpenGLContextInit" ns-opengl-context-init) :pointer + (format :pointer)) + +(defcfun ("NSOpenGLContextSetView" ns-opengl-context-set-view) :void + (context :pointer) + (view :pointer)) + (defcfun ("NSOpenGLContextClearDrawable" ns-opengl-context-clear-drawable) :void (context :pointer)) diff --git a/src/osx/bridge/GlopGLView.h b/src/osx/bridge/GlopGLView.h deleted file mode 100644 index cb26d58..0000000 --- a/src/osx/bridge/GlopGLView.h +++ /dev/null @@ -1,4 +0,0 @@ -#import - -@interface GlopGLView : NSOpenGLView -@end diff --git a/src/osx/bridge/GlopGLView.m b/src/osx/bridge/GlopGLView.m deleted file mode 100644 index 48b7e02..0000000 --- a/src/osx/bridge/GlopGLView.m +++ /dev/null @@ -1,37 +0,0 @@ -#import "GlopGLView.h" - -@implementation GlopGLView - -- (void)drawRect:(NSRect)dirtyRect -{ -} - -@end - - -GlopGLView *GlopGLViewInit (int x, int y, int width, int height, - NSOpenGLPixelFormat *pixelFormat) -{ - NSRect frame = NSMakeRect(x, y, width, height); - return [[GlopGLView alloc] initWithFrame:frame pixelFormat:pixelFormat]; -} - -NSOpenGLContext *GlopGLViewOpenGLContext (GlopGLView *view) -{ - return [view openGLContext]; -} - -void GlopGLViewSetOpenGLContext (GlopGLView *view, NSOpenGLContext *context) -{ - [view setOpenGLContext:context]; -} - -void GlopGLViewClearGLContext (GlopGLView *view) -{ - [view clearGLContext]; -} - -void GlopGLViewSetNextResponder (GlopGLView *view, NSResponder *responder) -{ - [view setNextResponder:responder]; -} diff --git a/src/osx/bridge/GlopWindowResponder.h b/src/osx/bridge/GlopView.h similarity index 62% rename from src/osx/bridge/GlopWindowResponder.h rename to src/osx/bridge/GlopView.h index 8fb94c8..3de803d 100644 --- a/src/osx/bridge/GlopWindowResponder.h +++ b/src/osx/bridge/GlopView.h @@ -1,9 +1,9 @@ -#import +#import typedef void(*GlopEventCallback)(NSEvent*); -@interface GlopWindowResponder : NSResponder +@interface GlopView : NSView { GlopEventCallback eventCallback; } diff --git a/src/osx/bridge/GlopWindowResponder.m b/src/osx/bridge/GlopView.m similarity index 58% rename from src/osx/bridge/GlopWindowResponder.m rename to src/osx/bridge/GlopView.m index be3b610..02ed7e1 100644 --- a/src/osx/bridge/GlopWindowResponder.m +++ b/src/osx/bridge/GlopView.m @@ -1,13 +1,28 @@ -#import "GlopWindowResponder.h" +#import "GlopView.h" -@implementation GlopWindowResponder +@implementation GlopView -- (id)initWithEventCallback:(GlopEventCallback)callback +- (id)initWithEventCallback:(GlopEventCallback)callback; { eventCallback = callback; return [self init]; } +- (BOOL)acceptsFirstResponder +{ + return YES; +} + +- (BOOL)canBecomeKeyView +{ + return YES; +} + +- (BOOL)isOpaque +{ + return YES; +} + - (void)keyUp:(NSEvent *)event { eventCallback(event); @@ -63,40 +78,15 @@ - (void)flagsChanged:(NSEvent *)event eventCallback(event); } -/* -- (void)mouseDragged:(NSEvent *)event -{ - eventCallback(event); -} - -- (void)rightMouseDragged:(NSEvent *)event -{ - eventCallback(event); -} - -- (void)otherMouseDragged:(NSEvent *)event -{ - eventCallback(event); -} - -- (void)mouseEntered:(NSEvent *)event -{ - eventCallback(event); -} - -- (void)mouseExited:(NSEvent *)event -{ - eventCallback(event); -} -*/ - - (void)windowWillClose:(NSNotification *)notification { } @end -GlopWindowResponder *GlopWindowResponderInit (GlopEventCallback callback) + +GlopView *GlopViewInit (GlopEventCallback callback) { - return [[GlopWindowResponder alloc] initWithEventCallback:callback]; + return [[GlopView alloc] initWithEventCallback:callback]; } + diff --git a/src/osx/bridge/Makefile b/src/osx/bridge/Makefile index 68f65b6..df28fbf 100644 --- a/src/osx/bridge/Makefile +++ b/src/osx/bridge/Makefile @@ -1,5 +1,5 @@ CFLAGS=-Wall -OBJ=foundation.o appkit.o GlopApp.o GlopWindowResponder.o GlopGLView.o +OBJ=foundation.o appkit.o GlopApp.o GlopView.o all: glop-bridge.dylib diff --git a/src/osx/bridge/appkit.m b/src/osx/bridge/appkit.m index c1aa125..f10a4c8 100644 --- a/src/osx/bridge/appkit.m +++ b/src/osx/bridge/appkit.m @@ -67,6 +67,11 @@ CGFloat NSEventDeltaY (NSEvent *event) return [event deltaY]; } +NSString *NSEventCharacters (NSEvent *event) +{ + return [event characters]; +} + /******************************************************************************/ /*** NSApplication ***/ @@ -210,6 +215,17 @@ void NSMenuAddItemWithTitle (NSMenu *menu, NSString *title, SEL selector, /******************************************************************************/ +NSOpenGLContext *NSOpenGLContextInit (NSOpenGLPixelFormat *format) +{ + return [[NSOpenGLContext alloc] initWithFormat:format + shareContext:nil]; +} + +void NSOpenGLContextSetView (NSOpenGLContext *context, NSView *view) +{ + [context setView:view]; +} + void NSOpenGLContextClearDrawable (NSOpenGLContext *context) { [context clearDrawable]; diff --git a/src/osx/bridge/glop-bridge.dylib b/src/osx/bridge/glop-bridge.dylib index ab825034c3afd475523855e538cb45ddb687e414..440142d58b4efaab2e4d848596b3efcb5d8ae452 100755 GIT binary patch literal 25876 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 literal 26124 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