button_cb: Option<ButtonCb>,
     slider_cb: Option<SliderCb>,
     swipe_cb: Option<SwipeCb>,
+    tap_cb: Option<ButtonCb>,
     child_bar: Option<ItemId>,
 }
 
             self.scrubber = None;
             self.button_cb = None;
             self.swipe_cb = None;
+            self.tap_cb = None;
             self.slider_cb = None;
         }
     }
             None => None,
         }
     }
+    fn find_tap_cb(&self, item: u64) -> Option<&ButtonCb> {
+        match self.item_map.values().into_iter().filter(|x| {
+            x.control.is_some() && x.control.unwrap() as u64 == item
+        }).next() {
+            Some(item) => item.tap_cb.as_ref(),
+            None => None,
+        }
+    }
     fn find_slider_cb(&self, sldr: u64) -> Option<&SliderCb> {
         match self.item_map.values().into_iter().filter(|x| {
             x._type == ItemType::Slider && x.view as u64 == sldr
                 button_cb: None,
                 slider_cb: None,
                 swipe_cb: None,
+                tap_cb: None,
                 child_bar: Some(bar as ItemId),
             };
             self.item_map.insert(item as u64, internal);
                 button_cb: None,
                 slider_cb: None,
                 swipe_cb: None,
+                tap_cb: None,
                 child_bar: None
             };
             self.item_map.insert(item as u64, internal);
                 button_cb: None,
                 slider_cb: None,
                 swipe_cb: None,
+                tap_cb: None,
                 child_bar: None,
             };
             self.item_map.insert(item as u64, internal);
                                                  action: sel!(swipeGesture:)];
             msg_send![gesture, setAllowedTouchTypes: 1]; // NSTouchTypeMaskDirect
             msg_send![view, addGestureRecognizer: gesture];
+            msg_send![gesture, release];
             let mut internal_item = self.item_map.remove(item_id).unwrap();
             internal_item.swipe_cb = Some(cb);
             self.item_map.insert(*item_id, internal_item);
         }
     }
 
+    fn add_item_tap_gesture(&mut self, item_id: &ItemId, taps: u32,
+                            fingers: u32, cb: ButtonCb) {
+        unsafe {
+            let item = *item_id as *mut Object;
+            let view: *mut Object = msg_send![item, view];
+            if view == nil {
+                return;
+            }
+            msg_send![view, setAllowedTouchTypes: 1]; // NSTouchTypeMaskDirect
+            let cls = Class::get("NSClickGestureRecognizer").unwrap();
+            let gesture: *mut Object = msg_send![cls, alloc];
+            let gesture: *mut Object = msg_send![gesture,
+                                                 initWithTarget: self.objc.clone()
+                                                 action: sel!(tapGesture:)];
+            msg_send![gesture, setAllowedTouchTypes: 1]; // NSTouchTypeMaskDirect
+            msg_send![gesture, setNumberOfTouchesRequired: fingers];
+            msg_send![gesture, setNumberOfClicksRequired: taps];
+            msg_send![view, addGestureRecognizer: gesture];
+            msg_send![gesture, release];
+            let mut internal_item = self.item_map.remove(item_id).unwrap();
+            internal_item.tap_cb = Some(cb);
+            self.item_map.insert(*item_id, internal_item);
+        }
+    }
+
     fn create_spacer(&mut self, space: SpacerType) -> ItemId {
         unsafe {
             let s = match space {
                 button_cb: None,
                 slider_cb: None,
                 swipe_cb: None,
+                tap_cb: None,
                 child_bar: None,
             };
             self.item_map.insert(s as u64, internal);
                 button_cb: Some(cb),
                 slider_cb: None,
                 swipe_cb: None,
+                tap_cb: None,
                 child_bar: None,
             };
             self.item_map.insert(item as u64, internal);
                 button_cb: None,
                 slider_cb: Some(cb),
                 swipe_cb: None,
+                tap_cb: None,
                 child_bar: None,
             };
             self.item_map.insert(item as u64, internal);
                     }
                 }
             }
+            extern fn objc_tap_gesture(this: &mut Object, _cmd: Sel, sender: u64) {
+                unsafe {
+                    let ptr: u64 = *this.get_ivar("_rust_wrapper");
+                    let wrapper = &mut *(ptr as *mut RustTouchbarDelegateWrapper);
+                    let gesture = sender as *mut Object;
+                    let view: *mut Object = msg_send![gesture, view];
+                    if let Some(ref cb) = wrapper.find_tap_cb(view as u64) {
+                        // Sender is the view.  Find the owning touchbar item:
+                        let item = wrapper.find_view_from_control(&(view as u64)).unwrap();
+                        cb(&(item as u64));
+                    }
+                }
+            }
             extern fn objc_swipe_gesture(this: &mut Object, _cmd: Sel, sender: u64) {
                 unsafe {
                     let ptr: u64 = *this.get_ivar("_rust_wrapper");
                 let f: extern fn(&mut Object, Sel, u64) = objc_button;
                 decl.add_method(sel!(button:), f);
 
+                let f: extern fn(&mut Object, Sel, u64) = objc_tap_gesture;
+                decl.add_method(sel!(tapGesture:), f);
+
                 let f: extern fn(&mut Object, Sel, u64) = objc_swipe_gesture;
                 decl.add_method(sel!(swipeGesture:), f);