diff --git a/heart/example/main.c b/heart/example/main.c index e503d0b..cb8f361 100644 --- a/heart/example/main.c +++ b/heart/example/main.c @@ -5,17 +5,26 @@ #include #include #include +#include -void cursor_callback(struct hrt_seat *seat) { +static void cursor_callback(struct hrt_seat *seat) { puts("Cursor callback called"); } -void output_callback(struct hrt_output *output) { +static void output_callback(struct hrt_output *output) { puts("Output callback called"); } +static void new_view_callback(struct hrt_view *view) { + puts("New view callback called!"); +} + +static void view_destroy_callback(struct hrt_view *view) { + puts("View destroy callback called"); +} + static bool showNormalCursor = true; -bool keyboard_callback(struct hrt_seat *seat, struct hrt_keypress_info *info) { +static bool keyboard_callback(struct hrt_seat *seat, struct hrt_keypress_info *info) { puts("Keyboard callback called"); printf("Modifiers: %d\n", info->modifiers); printf("Keys pressed:"); @@ -42,9 +51,14 @@ static const struct hrt_output_callbacks output_callbacks = { }; static const struct hrt_seat_callbacks seat_callbacks = { - .button_event = &cursor_callback, - .wheel_event = &cursor_callback, - .keyboard_keypress_event = &keyboard_callback, + .button_event = &cursor_callback, + .wheel_event = &cursor_callback, + .keyboard_keypress_event = &keyboard_callback, +}; + +static const struct hrt_view_callbacks view_callbacks = { + .new_view = &new_view_callback, + .view_destroyed = &view_destroy_callback, }; int main(int argc, char *argv[]) { @@ -52,7 +66,7 @@ int main(int argc, char *argv[]) { struct hrt_server server; - if(!hrt_server_init(&server, &output_callbacks, &seat_callbacks, WLR_DEBUG)) { + if(!hrt_server_init(&server, &output_callbacks, &seat_callbacks, &view_callbacks, WLR_DEBUG)) { return 1; } diff --git a/heart/include/hrt/hrt_server.h b/heart/include/hrt/hrt_server.h index 31dc61a..ae6e32e 100644 --- a/heart/include/hrt/hrt_server.h +++ b/heart/include/hrt/hrt_server.h @@ -35,10 +35,14 @@ struct hrt_server { struct wl_listener new_xdg_surface; const struct hrt_output_callbacks *output_callback; + const struct hrt_view_callbacks *view_callbacks; }; -bool hrt_server_init(struct hrt_server *server, const struct hrt_output_callbacks *output_callbacks, - const struct hrt_seat_callbacks *seat_callbacks, enum wlr_log_importance log_level); +bool hrt_server_init(struct hrt_server *server, + const struct hrt_output_callbacks *output_callbacks, + const struct hrt_seat_callbacks *seat_callbacks, + const struct hrt_view_callbacks *view_callbacks, + enum wlr_log_importance log_level); bool hrt_server_start(struct hrt_server *server); @@ -46,4 +50,6 @@ void hrt_server_stop(struct hrt_server *server); void hrt_server_finish(struct hrt_server *server); +struct wlr_scene_tree *hrt_server_scene_tree(struct hrt_server *server); + #endif diff --git a/heart/include/hrt/hrt_view.h b/heart/include/hrt/hrt_view.h index c4aafe6..29b0a95 100644 --- a/heart/include/hrt/hrt_view.h +++ b/heart/include/hrt/hrt_view.h @@ -1,10 +1,47 @@ +#include #include #include "hrt/hrt_server.h" +struct hrt_view; + +typedef void (*view_destroy_handler)(struct hrt_view *view); + struct hrt_view { + struct wlr_xdg_surface *xdg_surface; struct wlr_xdg_toplevel *xdg_toplevel; + /* + Contains the tree with the xdg surface tree + plus decorations and that sort of thing. + */ struct wlr_scene_tree *scene_tree; + + // internal state: struct wl_listener map; struct wl_listener unmap; struct wl_listener destroy; + view_destroy_handler destroy_handler; +}; + +struct hrt_view_callbacks { + /** + * A new view has been created. Must call `hrt_view_init` for the + * view to be displayed. + **/ + void (*new_view)(struct hrt_view *view); + view_destroy_handler view_destroyed; }; + +/** + * Fully initialize the view and place it in the given scene tree. + **/ +void hrt_view_init(struct hrt_view *view, struct wlr_scene_tree *tree); + +/** + * Request that this view be the given size. Returns the associated configure serial. + **/ +uint32_t hrt_view_set_size(struct hrt_view *view, int width, int height); + +/** + * Sets the view to the given coordinates relative to its parent. + **/ +void hrt_view_set_relative(struct hrt_view *view, int x, int y); diff --git a/heart/src/meson.build b/heart/src/meson.build index eca78b3..2db0f04 100644 --- a/heart/src/meson.build +++ b/heart/src/meson.build @@ -1,9 +1,10 @@ hrt_source_files += files( - 'server.c', - 'output.c', + 'cursor.c', 'input.c', - 'seat.c', 'keyboard.c', - 'cursor.c', + 'output.c', + 'seat.c', + 'server.c', + 'view.c', 'xdg_shell.c', ) diff --git a/heart/src/server.c b/heart/src/server.c index 458a81e..1e75329 100644 --- a/heart/src/server.c +++ b/heart/src/server.c @@ -15,8 +15,11 @@ #include #include -bool hrt_server_init(struct hrt_server *server, const struct hrt_output_callbacks *output_callbacks, - const struct hrt_seat_callbacks *seat_callbacks, enum wlr_log_importance log_level) { +bool hrt_server_init(struct hrt_server *server, + const struct hrt_output_callbacks *output_callbacks, + const struct hrt_seat_callbacks *seat_callbacks, + const struct hrt_view_callbacks *view_callbacks, + enum wlr_log_importance log_level) { wlr_log_init(log_level, NULL); server->wl_display = wl_display_create(); server->backend = wlr_backend_autocreate(server->wl_display); @@ -47,6 +50,8 @@ bool hrt_server_init(struct hrt_server *server, const struct hrt_output_callback server->output_layout = wlr_output_layout_create(); + server->view_callbacks = view_callbacks; + server->xdg_shell = wlr_xdg_shell_create(server->wl_display, 3); server->new_xdg_surface.notify = handle_new_xdg_surface; wl_signal_add(&server->xdg_shell->events.new_surface, &server->new_xdg_surface); @@ -101,3 +106,7 @@ void hrt_server_finish(struct hrt_server *server) { wl_display_destroy_clients(server->wl_display); wl_display_destroy(server->wl_display); } + +struct wlr_scene_tree *hrt_server_scene_tree(struct hrt_server *server) { + return &server->scene->tree; +} diff --git a/heart/src/view.c b/heart/src/view.c new file mode 100644 index 0000000..46df7bc --- /dev/null +++ b/heart/src/view.c @@ -0,0 +1,22 @@ +#include +#include +#include + +#include "hrt/hrt_view.h" + +void hrt_view_init(struct hrt_view *view, struct wlr_scene_tree *tree) { + view->scene_tree = wlr_scene_tree_create(tree); + + struct wlr_scene_tree *xdg_tree = + wlr_scene_xdg_surface_create(view->scene_tree, view->xdg_toplevel->base); + xdg_tree->node.data = view; + view->xdg_surface->data = xdg_tree; +} + +uint32_t hrt_view_set_size(struct hrt_view *view, int width, int height) { + return wlr_xdg_toplevel_set_size(view->xdg_toplevel, width, height); +} + +void hrt_view_set_relative(struct hrt_view *view, int x, int y) { + wlr_scene_node_set_position(&view->scene_tree->node, x, y); +} diff --git a/heart/src/xdg_shell.c b/heart/src/xdg_shell.c index d9bbf97..91df4c3 100644 --- a/heart/src/xdg_shell.c +++ b/heart/src/xdg_shell.c @@ -25,6 +25,8 @@ static void handle_xdg_toplevel_destroy(struct wl_listener *listener, wlr_log(WLR_DEBUG, "XDG Toplevel Destroyed!"); struct hrt_view *view = wl_container_of(listener, view, destroy); + view->destroy_handler(view); + wl_list_remove(&view->map.link); wl_list_remove(&view->unmap.link); wl_list_remove(&view->destroy.link); @@ -32,18 +34,14 @@ static void handle_xdg_toplevel_destroy(struct wl_listener *listener, free(view); } -struct hrt_view *initialize_view(struct wlr_xdg_surface *xdg_surface, struct wlr_scene_tree *tree) { +static struct hrt_view *create_view_from_xdg_surface(struct wlr_xdg_surface *xdg_surface, view_destroy_handler destroy_handler) { // This method can only deal with toplevel xdg_surfaces: assert(xdg_surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); struct hrt_view *view = calloc(1, sizeof(struct hrt_view)); view->xdg_toplevel = xdg_surface->toplevel; + view->xdg_surface = xdg_surface; + view->destroy_handler = destroy_handler; - // Add the view to the scene tree (we should probab - view->scene_tree = wlr_scene_xdg_surface_create(tree, view->xdg_toplevel->base); - view->scene_tree->node.data = view; - xdg_surface->data = view->scene_tree; - - // Listen to events: view->map.notify = handle_xdg_toplevel_map; wl_signal_add(&xdg_surface->events.map, &view->map); view->unmap.notify = handle_xdg_toplevel_unmap; @@ -54,23 +52,34 @@ struct hrt_view *initialize_view(struct wlr_xdg_surface *xdg_surface, struct wlr return view; } - void handle_new_xdg_surface(struct wl_listener *listener, void *data) { wlr_log(WLR_DEBUG, "New XDG Surface recieved"); struct hrt_server *server = wl_container_of(listener, server, new_xdg_surface); struct wlr_xdg_surface *xdg_surface = data; if(xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { - // We the front end doesn't need to know about popups; wlroots handles it for us. + // The front end doesn't need to know about popups; wlroots handles it for us. // we do need to set some internal data so that they can be rendered though. struct wlr_xdg_surface *parent = wlr_xdg_surface_from_wlr_surface(xdg_surface->popup->parent); struct wlr_scene_tree *parent_tree = parent->data; - xdg_surface->data = wlr_scene_xdg_surface_create( - parent_tree, xdg_surface); + // The parent view might not have been initizlized properly. In that case, it + // isn't being displayed, so we just ignore it: + if (parent_tree) { + xdg_surface->data = wlr_scene_xdg_surface_create(parent_tree, xdg_surface); + } else { + wlr_log(WLR_ERROR, "Encountered XDG Popup without properly configured parent"); + } return; } + // Initialization occurs in two steps so the consumer can place the view where it needs to go; + // in order to create a scene tree node, it must have a parent. + // We don't have it until the callback. + struct hrt_view *view = create_view_from_xdg_surface(xdg_surface, + server->view_callbacks->view_destroyed); // At some point, we will want the front end to call this, as it should decide what node // of the scene graph the view gets added to: - initialize_view(xdg_surface, &server->scene->tree); + // hrt_view_init(view, &server->scene->tree); + + server->view_callbacks->new_view(view); } diff --git a/lisp/bindings/hrt-bindings.lisp b/lisp/bindings/hrt-bindings.lisp index 58fce85..97b5fb9 100644 --- a/lisp/bindings/hrt-bindings.lisp +++ b/lisp/bindings/hrt-bindings.lisp @@ -1,5 +1,41 @@ (cl:in-package #:hrt) +;; next section imported from file build/include/hrt/hrt_view.h + +(cffi:defcstruct hrt-view) + +(cffi:defctype view-destroy-handler :pointer #| function ptr void (struct hrt_view *) |#) + +(cffi:defcstruct hrt-view + (xdg-surface :pointer #| (:struct wlr-xdg-surface) |# ) + (xdg-toplevel :pointer #| (:struct wlr-xdg-toplevel) |# ) + (scene-tree :pointer #| (:struct wlr-scene-tree) |# ) + (map (:struct wl-listener)) + (unmap (:struct wl-listener)) + (destroy (:struct wl-listener)) + (destroy-handler view-destroy-handler)) + +(cffi:defcstruct hrt-view-callbacks + (new-view :pointer #| function ptr void (struct hrt_view *) |#) + (view-destroyed view-destroy-handler)) + +(cffi:defcfun ("hrt_view_init" hrt-view-init) :void + "Fully initialize the view and place it in the given scene tree." + (view (:pointer (:struct hrt-view))) + (tree :pointer #| (:struct wlr-scene-tree) |# )) + +(cffi:defcfun ("hrt_view_set_size" hrt-view-set-size) :uint32 + "Request that this view be the given size. Returns the associated configure serial." + (view (:pointer (:struct hrt-view))) + (width :int) + (height :int)) + +(cffi:defcfun ("hrt_view_set_relative" hrt-view-set-relative) :void + "Sets the view to the given coordinates relative to its parent." + (view (:pointer (:struct hrt-view))) + (x :int) + (y :int)) + ;; next section imported from file build/include/hrt/hrt_input.h (cffi:defcstruct hrt-server) @@ -100,12 +136,14 @@ See themes section of man xcursor(3) to find where to find valid cursor names." (seat (:struct hrt-seat)) (xdg-shell :pointer #| (:struct wlr-xdg-shell) |# ) (new-xdg-surface (:struct wl-listener)) - (output-callback (:pointer (:struct hrt-output-callbacks)))) + (output-callback (:pointer (:struct hrt-output-callbacks))) + (view-callbacks (:pointer (:struct hrt-view-callbacks)))) (cffi:defcfun ("hrt_server_init" hrt-server-init) :bool (server (:pointer (:struct hrt-server))) (output-callbacks (:pointer (:struct hrt-output-callbacks))) (seat-callbacks (:pointer (:struct hrt-seat-callbacks))) + (view-callbacks (:pointer (:struct hrt-view-callbacks))) (log-level :int #| enum wlr-log-importance |#)) (cffi:defcfun ("hrt_server_start" hrt-server-start) :bool @@ -117,11 +155,5 @@ See themes section of man xcursor(3) to find where to find valid cursor names." (cffi:defcfun ("hrt_server_finish" hrt-server-finish) :void (server (:pointer (:struct hrt-server)))) -;; next section imported from file build/include/hrt/hrt_view.h - -(cffi:defcstruct hrt-view - (xdg-toplevel :pointer #| (:struct wlr-xdg-toplevel) |# ) - (scene-tree :pointer #| (:struct wlr-scene-tree) |# ) - (map (:struct wl-listener)) - (unmap (:struct wl-listener)) - (destroy (:struct wl-listener))) +(cffi:defcfun ("hrt_server_scene_tree" hrt-server-scene-tree) :pointer #| (:struct wlr-scene-tree) |# + (server (:pointer (:struct hrt-server)))) diff --git a/lisp/bindings/hrt-bindings.yml b/lisp/bindings/hrt-bindings.yml index 39c47e4..13b6076 100644 --- a/lisp/bindings/hrt-bindings.yml +++ b/lisp/bindings/hrt-bindings.yml @@ -6,10 +6,10 @@ arguments: - "-DWLR_USE_UNSTABLE" - "-Iheart/include" files: + - build/include/hrt/hrt_view.h - build/include/hrt/hrt_input.h - build/include/hrt/hrt_output.h - build/include/hrt/hrt_server.h - - build/include/hrt/hrt_view.h pointer-expansion: include: match: "hrt.*" diff --git a/lisp/bindings/package.lisp b/lisp/bindings/package.lisp index 883dca5..285f8e7 100644 --- a/lisp/bindings/package.lisp +++ b/lisp/bindings/package.lisp @@ -3,6 +3,11 @@ (:nicknames #:hrt) (:export #:hrt-output-callbacks #:hrt-seat-callbacks + #:hrt-view-callbacks + #:new-view + #:hrt-view + #:hrt-view-init + #:view-destroyed #:hrt-seat #:hrt-output #:hrt-keypress-info @@ -10,6 +15,7 @@ #:output-removed #:button-event #:wheel-event #:keyboard-keypress-event #:hrt-server + #:hrt-server-scene-tree #:hrt-server-init #:hrt-server-start #:hrt-server-stop diff --git a/lisp/main.lisp b/lisp/main.lisp index 6233305..e393cce 100644 --- a/lisp/main.lisp +++ b/lisp/main.lisp @@ -32,12 +32,18 @@ (setf ,@(loop for pair in sets append (list (car pair) `(cffi:callback ,(cadr pair)))))))) +(defun init-view-callbacks (view-callbacks) + (init-callback-struct view-callbacks (:struct hrt-view-callbacks) + (new-view handle-new-view-event) + (view-destroyed handle-view-destroyed-event))) + (defun run-server () (disable-fpu-exceptions) (hrt:load-foreign-libraries) (log-init :level :trace) (cffi:with-foreign-objects ((output-callbacks '(:struct hrt-output-callbacks)) (seat-callbacks '(:struct hrt-seat-callbacks)) + (view-callbacks '(:struct hrt-view-callbacks)) (server '(:struct hrt-server))) (init-callback-struct output-callbacks (:struct hrt-output-callbacks) (output-added output-callback) @@ -46,9 +52,11 @@ (button-event cursor-callback) (wheel-event cursor-callback) (keyboard-keypress-event keyboard-callback)) + (init-view-callbacks view-callbacks) + (setf (mahogany-state-server *compositor-state*) server) (log-string :debug "Initialized mahogany state") - (hrt-server-init server output-callbacks seat-callbacks 3) + (hrt-server-init server output-callbacks seat-callbacks view-callbacks 3) (log-string :debug "Initialized heart state") (unwind-protect (hrt-server-start server) diff --git a/lisp/state.lisp b/lisp/state.lisp index 8ccf3cf..bb954ea 100644 --- a/lisp/state.lisp +++ b/lisp/state.lisp @@ -9,7 +9,10 @@ :accessor mahogany-state-key-state) (keybindings :type list :initform nil - :reader mahogany-state-keybindings))) + :reader mahogany-state-keybindings) + (views :type list + :initform nil + :reader mahogany-state-views))) ;; (defmethod initialize-instance :after ((object mahogany-state) &key &allow-other-keys)) @@ -31,3 +34,14 @@ (setf (slot-value state 'keybindings) kmaps) (unless (key-state-active-p (mahogany-state-key-state state)) (server-keystate-reset state))) + +(defun mahogany-state-view-add (state view) + (declare (type mahogany-state state)) + (push view (slot-value state 'views)) + (log-string :trace "Views: ~S" (slot-value state 'views))) + +(defun mahogany-state-view-remove (state view) + (declare (type mahogany-state state)) + (with-slots (views) state + (setf views (remove view views :test #'cffi:pointer-eq)) + (log-string :trace "Views: ~S" views))) diff --git a/lisp/view.lisp b/lisp/view.lisp new file mode 100644 index 0000000..4ba6d7f --- /dev/null +++ b/lisp/view.lisp @@ -0,0 +1,12 @@ +(in-package #:mahogany) + +(cffi:defcallback handle-new-view-event :void + ((view (:pointer (:struct hrt-view)))) + (log-string :trace "New view callback called!") + (hrt-view-init view (hrt-server-scene-tree (mahogany-state-server *compositor-state*))) + (mahogany-state-view-add *compositor-state* view)) + +(cffi:defcallback handle-view-destroyed-event :void + ((view (:pointer (:struct hrt-view)))) + (log-string :trace "View destroyed callback called!") + (mahogany-state-view-remove *compositor-state* view)) diff --git a/mahogany.asd b/mahogany.asd index 6672269..896889f 100644 --- a/mahogany.asd +++ b/mahogany.asd @@ -40,6 +40,7 @@ (:file "frame" :depends-on ("tree-interface")) (:file "view" :depends-on ("tree-interface")))) (:file "state" :depends-on ("package")) + (:file "view" :depends-on ("package" "bindings")) (:file "input" :depends-on ("state" "keyboard")) (:file "globals" :depends-on ("state" "system")) (:file "main" :depends-on ("bindings" "keyboard" "input" "package"))))