Move screenshooter to rust
diff --git a/build.rs b/build.rs
index 7d05e6b..33dcfb9 100644
--- a/build.rs
+++ b/build.rs
@@ -34,6 +34,7 @@
 fn main() {
     let protocols = [
         "wayland",
+        "weston-screenshooter",
         "linux-dmabuf-unstable-v1",
         "croscomp",
         "alpha-compositing-unstable-v1",
diff --git a/src/display.rs b/src/display.rs
index 8b97614..178efda 100644
--- a/src/display.rs
+++ b/src/display.rs
@@ -11,7 +11,10 @@
 use super::protocol::croscomp_output::CroscompOutput;
 use crate::server::Resource;
 
-fn handle_bind(resource: &mut Resource<CroscompDisplay>, compositor: &mut super::Compositor) {
+fn handle_bind(
+    resource: &mut Resource<CroscompDisplay>,
+    compositor: &mut super::Compositor,
+) -> bool {
     for head in compositor.head_iter().filter(|h| h.is_enabled()) {
         println!("head {:?}", head);
 
@@ -52,6 +55,8 @@
 
         output_resource.send(Done {});
     }
+
+    true
 }
 
 pub fn init(shell: &Rc<RefCell<crate::Shell>>) {
diff --git a/src/main.rs b/src/main.rs
index dc5d5ce..49b92bd 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -26,6 +26,7 @@
 mod protocol;
 mod remote_shell;
 mod rotate;
+mod screenshooter;
 mod server;
 mod shell;
 mod splash;
@@ -217,6 +218,8 @@
 
     aura_shell::init(&shell);
 
+    screenshooter::init(&shell);
+
     compositor.borrow_mut().wake();
 
     unsafe {
diff --git a/src/protocol.rs b/src/protocol.rs
index 02bcba9..7c2986c 100644
--- a/src/protocol.rs
+++ b/src/protocol.rs
@@ -16,6 +16,7 @@
 pub(crate) use wayland_server::AnonymousObject;
 
 include!(concat!(env!("OUT_DIR"), "/wayland.rs"));
+include!(concat!(env!("OUT_DIR"), "/weston-screenshooter.rs"));
 include!(concat!(env!("OUT_DIR"), "/croscomp.rs"));
 include!(concat!(env!("OUT_DIR"), "/aura-shell.rs"));
 include!(concat!(
diff --git a/src/remote_shell.rs b/src/remote_shell.rs
index 8155fee..4ba1413 100644
--- a/src/remote_shell.rs
+++ b/src/remote_shell.rs
@@ -56,6 +56,8 @@
             resource.send(Configure {
                 layout_mode: LayoutMode::Windowed.to_raw(),
             });
+
+            true
         })
         .on_request(|_resource, request| {
             use super::protocol::zcr_remote_shell_v1::Request::*;
diff --git a/src/screenshooter.rs b/src/screenshooter.rs
new file mode 100644
index 0000000..e910aed
--- /dev/null
+++ b/src/screenshooter.rs
@@ -0,0 +1,114 @@
+// Copyright 2021 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use crate::Shell;
+use std::cell::RefCell;
+use std::rc::Rc;
+
+use crate::ffi;
+use crate::protocol;
+
+use crate::server::Resource;
+use protocol::weston_screenshooter::{Request, WestonScreenshooter};
+
+struct ScreenShooter {
+    shell: Rc<RefCell<crate::Shell>>,
+    client: Option<*mut ffi::wl_client>,
+}
+
+impl ScreenShooter {
+    fn shoot(&mut self) {
+        let path = "/usr/bin/weston-screenshooter";
+        let shell = self.shell.borrow();
+        let mut compositor = shell.compositor.borrow_mut();
+
+        if self.client.is_none() {
+            self.client = compositor.launch_client(path).ok();
+        }
+    }
+
+    fn record(&mut self) {
+        println!("screenshooter record");
+    }
+}
+
+fn handle_request(resource: &mut Resource<WestonScreenshooter>, request: &Request) {
+    unsafe extern "C" fn done(
+        data: *mut ::std::ffi::c_void,
+        outcome: ffi::weston_screenshooter_outcome,
+    ) {
+        use protocol::weston_screenshooter::Event::Done;
+        let resource = Resource::<WestonScreenshooter>::from_c_ptr(data as *mut _);
+
+        match outcome {
+            ffi::weston_screenshooter_outcome::WESTON_SCREENSHOOTER_SUCCESS => resource.send(Done),
+            _ => resource.post_no_memory(),
+        }
+    }
+
+    match request {
+        Request::Shoot { output, buffer } => unsafe {
+            let output = (*ffi::weston_head_from_resource(output.as_ref().c_ptr())).output;
+            let buffer = ffi::weston_buffer_from_resource(buffer.as_ref().c_ptr());
+
+            ffi::weston_screenshooter_shoot(output, buffer, Some(done), resource.c_ptr() as *mut _);
+        },
+    }
+}
+
+pub fn init(shell: &Rc<RefCell<Shell>>) {
+    let shooter = Rc::new(RefCell::new(ScreenShooter {
+        shell: Rc::clone(shell),
+        client: None,
+    }));
+
+    let s = shell.borrow();
+    let mut compositor = s.compositor.borrow_mut();
+    let rc = Rc::clone(&shooter);
+    let destroy_rc = Rc::clone(&shooter);
+
+    let version = 1;
+    let global = compositor
+        .server
+        .create_global::<WestonScreenshooter>(version)
+        .on_bind(move |resource| {
+            match rc.borrow().client {
+                Some(native_client) if native_client == resource.client() => {
+                    // good case
+                    true
+                }
+                _ => {
+                    resource.post_error(
+                        ffi::wl_display_error::WL_DISPLAY_ERROR_INVALID_OBJECT as u32,
+                        "screenshooter failed: permission denied",
+                    );
+                    false
+                }
+            }
+        })
+        .on_request(|resource, request| handle_request(resource, request))
+        .on_destroy(move |_resource| {
+            let mut s = destroy_rc.borrow_mut();
+            s.client = None;
+            println!("destroy shooter")
+        });
+
+    Box::into_raw(Box::new(global));
+
+    use crate::ffi::evdev::{KEY_R, KEY_S};
+
+    let rc = Rc::clone(&shooter);
+    compositor.bind_key(
+        KEY_S,
+        ffi::weston_keyboard_modifier::MODIFIER_SUPER,
+        move |_, _, _| rc.borrow_mut().shoot(),
+    );
+
+    let rc = Rc::clone(&shooter);
+    compositor.bind_key(
+        KEY_R,
+        ffi::weston_keyboard_modifier::MODIFIER_SUPER,
+        move |_keyboard, _, _| rc.borrow_mut().record(),
+    );
+}
diff --git a/src/server.rs b/src/server.rs
index 9c8325a..cdc4e95 100644
--- a/src/server.rs
+++ b/src/server.rs
@@ -45,6 +45,10 @@
         }
     }
 
+    pub fn drop_native(&mut self) {
+        unsafe { ffi::wl_resource_destroy(self.native) }
+    }
+
     pub unsafe fn make_child_for<J>(&self, id: u32) -> Option<Main<J>>
     where
         J: wayland_server::Interface + From<Resource<J>> + AsRef<Resource<J>>,
@@ -80,6 +84,18 @@
         })
     }
 
+    pub fn post_error(&self, err: u32, msg: &str) {
+        unsafe {
+            let msg = std::ffi::CString::new(msg).expect("invalid error message");
+
+            ffi::wl_resource_post_error(self.native, err, msg.as_ptr())
+        }
+    }
+
+    pub fn post_no_memory(&self) {
+        unsafe { ffi::wl_resource_post_no_memory(self.native) }
+    }
+
     pub fn on_request<F>(&self, f: F) -> &Self
     where
         F: 'static + Fn(&mut Resource<I>, &I::Request),
@@ -167,7 +183,7 @@
 where
     I: wayland_server::Interface,
 {
-    handle_bind: Option<Box<dyn Fn(&mut Resource<I>)>>,
+    handle_bind: Option<Box<dyn Fn(&mut Resource<I>) -> bool>>,
     dispatcher: Option<Box<dyn Fn(&mut Resource<I>, &I::Request)>>,
     handle_destroy: Option<Box<dyn Fn(&mut Resource<I>)>>,
 }
@@ -192,7 +208,7 @@
 impl<I: wayland_server::Interface> Global<I> {
     pub fn on_bind<F>(mut self, f: F) -> Self
     where
-        F: 'static + Fn(&mut Resource<I>),
+        F: 'static + Fn(&mut Resource<I>) -> bool,
     {
         // hook for handling bind time checks or allocations
         self.handlers.handle_bind = Some(Box::new(f));
@@ -307,15 +323,21 @@
 
             println!("handlers: {:?}", handlers as *const _);
 
-            if let Some(ref handle_bind) = handlers.handle_bind {
+            let success = if let Some(ref handle_bind) = handlers.handle_bind {
                 println!(
                     "calling handle_bind for {}: {:?}",
                     I::NAME,
                     &(*handle_bind) as *const _
                 );
-                (*handle_bind)(&mut resource);
-                // xxx return value from handle_bind should indicate whether
-                // or not bind was successful
+                (*handle_bind)(&mut resource)
+            } else {
+                false
+            };
+
+            if !success {
+                println!("on_bind returns failure");
+                resource.drop_native();
+                return;
             }
 
             if let Some(ref dispatcher) = handlers.dispatcher {
diff --git a/src/splash.rs b/src/splash.rs
index 6fe9ebe..aa68cb3 100644
--- a/src/splash.rs
+++ b/src/splash.rs
@@ -67,7 +67,10 @@
     let global = compositor
         .server
         .create_global::<CroscompSplash>(version)
-        .on_bind(|_| println!("splash: handle bind"))
+        .on_bind(|_| {
+            println!("splash: handle bind");
+            true
+        })
         .on_request(|resource, request| handle_request(resource, request))
         .on_destroy(move |_resource| super::Shell::finish_init(&rc));
 
diff --git a/weston/desktop-shell/screenshooter.c b/weston/desktop-shell/screenshooter.c
deleted file mode 100644
index 0b93fe0..0000000
--- a/weston/desktop-shell/screenshooter.c
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright © 2008-2011 Kristian Høgsberg
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <stdint.h>
-#include <linux/input.h>
-
-#include <libweston/libweston.h>
-#include "weston.h"
-#include "weston-screenshooter-server-protocol.h"
-#include "shared/helpers.h"
-#include "shared/zalloc.h"
-#include <libweston/weston-log.h>
-
-struct screenshooter {
-	struct weston_compositor *ec;
-	struct wl_global *global;
-	struct wl_client *client;
-	struct weston_process process;
-	struct wl_listener destroy_listener;
-	struct weston_recorder *recorder;
-};
-
-static void
-screenshooter_done(void *data, enum weston_screenshooter_outcome outcome)
-{
-	struct wl_resource *resource = data;
-
-	switch (outcome) {
-	case WESTON_SCREENSHOOTER_SUCCESS:
-		weston_screenshooter_send_done(resource);
-		break;
-	case WESTON_SCREENSHOOTER_NO_MEMORY:
-		wl_resource_post_no_memory(resource);
-		break;
-	default:
-		break;
-	}
-}
-
-static void
-screenshooter_shoot(struct wl_client *client,
-		    struct wl_resource *resource,
-		    struct wl_resource *output_resource,
-		    struct wl_resource *buffer_resource)
-{
-	struct weston_output *output =
-		weston_head_from_resource(output_resource)->output;
-	struct weston_buffer *buffer =
-		weston_buffer_from_resource(buffer_resource);
-
-	if (buffer == NULL) {
-		wl_resource_post_no_memory(resource);
-		return;
-	}
-
-	weston_screenshooter_shoot(output, buffer, screenshooter_done, resource);
-}
-
-struct weston_screenshooter_interface screenshooter_implementation = {
-	screenshooter_shoot
-};
-
-static void
-bind_shooter(struct wl_client *client,
-	     void *data, uint32_t version, uint32_t id)
-{
-	struct screenshooter *shooter = data;
-	struct wl_resource *resource;
-	bool debug_enabled =
-		weston_compositor_is_debug_protocol_enabled(shooter->ec);
-
-	resource = wl_resource_create(client,
-				      &weston_screenshooter_interface, 1, id);
-
-	if (!debug_enabled && !shooter->client) {
-		wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
-				       "screenshooter failed: permission denied. "\
-				       "Debug protocol must be enabled");
-		return;
-	} else if (!debug_enabled && client != shooter->client) {
-		wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
-				       "screenshooter failed: permission denied.");
-		return;
-	}
-
-	wl_resource_set_implementation(resource, &screenshooter_implementation,
-				       data, NULL);
-}
-
-static void
-screenshooter_sigchld(struct weston_process *process, int status)
-{
-	struct screenshooter *shooter =
-		container_of(process, struct screenshooter, process);
-
-	shooter->client = NULL;
-}
-
-static void
-screenshooter_binding(struct weston_keyboard *keyboard,
-		      const struct timespec *time, uint32_t key, void *data)
-{
-	struct screenshooter *shooter = data;
-	char *screenshooter_exe;
-
-
-	screenshooter_exe = wet_get_bindir_path("weston-screenshooter");
-	if (!screenshooter_exe) {
-		weston_log("Could not construct screenshooter path.\n");
-		return;
-	}
-
-	if (!shooter->client)
-		shooter->client = weston_client_launch(shooter->ec,
-					&shooter->process,
-					screenshooter_exe, screenshooter_sigchld);
-	free(screenshooter_exe);
-}
-
-static void
-recorder_binding(struct weston_keyboard *keyboard, const struct timespec *time,
-		 uint32_t key, void *data)
-{
-	struct weston_compositor *ec = keyboard->seat->compositor;
-	struct weston_output *output;
-	struct screenshooter *shooter = data;
-	struct weston_recorder *recorder = shooter->recorder;;
-	static const char filename[] = "capture.wcap";
-
-	if (recorder) {
-		weston_recorder_stop(recorder);
-		shooter->recorder = NULL;
-	} else {
-		if (keyboard->focus && keyboard->focus->output)
-			output = keyboard->focus->output;
-		else
-			output = container_of(ec->output_list.next,
-					      struct weston_output, link);
-
-		shooter->recorder = weston_recorder_start(output, filename);
-	}
-}
-
-static void
-screenshooter_destroy(struct wl_listener *listener, void *data)
-{
-	struct screenshooter *shooter =
-		container_of(listener, struct screenshooter, destroy_listener);
-
-	wl_list_remove(&shooter->destroy_listener.link);
-
-	wl_global_destroy(shooter->global);
-	free(shooter);
-}
-
-WL_EXPORT void
-screenshooter_create(struct weston_compositor *ec)
-{
-	struct screenshooter *shooter;
-
-	shooter = zalloc(sizeof *shooter);
-	if (shooter == NULL)
-		return;
-
-	shooter->ec = ec;
-
-	shooter->global = wl_global_create(ec->wl_display,
-					   &weston_screenshooter_interface, 1,
-					   shooter, bind_shooter);
-	weston_compositor_add_key_binding(ec, KEY_S, MODIFIER_SUPER,
-					  screenshooter_binding, shooter);
-	weston_compositor_add_key_binding(ec, KEY_R, MODIFIER_SUPER,
-					  recorder_binding, shooter);
-
-	shooter->destroy_listener.notify = screenshooter_destroy;
-	wl_signal_add(&ec->destroy_signal, &shooter->destroy_listener);
-}