1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
mod image;

pub use self::image::ClipImage;
use clip_sys::{
  clip_empty_format, clip_get_image, clip_get_paths, clip_get_text, clip_has, clip_image,
  clip_image_format, clip_path, clip_paths_format, clip_set_text, clip_text_format,
};
use failure::{err_msg, Error};
use std::path::PathBuf;

#[derive(Debug)]
pub enum ClipFormat {
  Empty,
  Text,
  Image,
  Paths,
}

pub struct Clip;

impl Clip {
  pub fn has_format(format: ClipFormat) -> bool {
    unsafe {
      let clip_format = match format {
        ClipFormat::Empty => clip_empty_format(),
        ClipFormat::Text => clip_text_format(),
        ClipFormat::Image => clip_image_format(),
        ClipFormat::Paths => clip_paths_format(),
      };

      clip_has(clip_format)
    }
  }

  pub fn get_format() -> Option<ClipFormat> {
    Some(if Clip::has_format(ClipFormat::Image) {
      ClipFormat::Image
    } else if Clip::has_format(ClipFormat::Paths) {
      ClipFormat::Paths
    } else if Clip::has_format(ClipFormat::Text) {
      ClipFormat::Text
    } else if Clip::has_format(ClipFormat::Empty) {
      ClipFormat::Empty
    } else {
      return None;
    })
  }

  pub fn set_text(text: String) -> Result<(), Error> {
    use std::ffi::CString;

    let c_string = CString::new(text)?;

    let did_set = unsafe { clip_set_text(c_string.as_ptr()) };

    if !did_set {
      Err(err_msg("couldn't set clipboard text"))
    } else {
      Ok(())
    }
  }

  pub fn get_text() -> Result<String, Error> {
    Ok(unsafe { clip_get_text() }.to_string()?)
  }

  pub fn get_image() -> Result<ClipImage, Error> {
    let mut img = unsafe { clip_image::new() };

    let ok = unsafe { clip_get_image(&mut img) };
    if !ok {
      return Err(err_msg("couldn't get image"));
    }

    Ok(ClipImage::from_clip_image(img))
  }

  pub fn get_paths() -> Result<Vec<PathBuf>, Error> {
    const PATHS_CAPACITY: usize = 100;

    let mut paths: [clip_path; PATHS_CAPACITY] = unsafe { std::mem::zeroed() };

    let paths_length = unsafe { clip_get_paths(paths.as_mut_ptr(), &(PATHS_CAPACITY as u64)) };
    assert!(paths_length > 0);

    println!("{}", paths_length);

    let paths: Vec<PathBuf> = paths[..paths_length as usize]
      .iter()
      .map(|path| {
        if path.wide {
          #[cfg(target_os = "windows")]
          {
            use std::os::windows::ffi::OsStringExt;

            let buf = unsafe { &path.buf.wide[..path.length as usize] };

            PathBuf::from(std::ffi::OsString::from_wide(buf))
          }

          #[cfg(not(target_os = "windows"))]
          {
            unimplemented!("path.wide");
          }
        } else {
          let buf = unsafe { &path.buf.ansi[..path.length as usize] };
          let buf = unsafe { &*(buf as *const [i8] as *const [u8]) };
          let buf = buf.to_vec();

          PathBuf::from(String::from_utf8(buf).unwrap())
        }
      })
      .collect();

    println!("{:#?}", paths);

    Ok(paths)
  }
}