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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183

#[cfg(unix)]
extern crate x11_dl;

#[cfg(windows)]
extern crate winapi;
#[cfg(windows)]
use frames::winapi::shared::windef::HWND;
#[cfg(windows)]
use frames::winapi::um::winuser::*;
#[cfg(windows)]
use frames::winapi::um::libloaderapi::GetModuleHandleW;

#[cfg(windows)]
use std::os::windows::ffi::OsStrExt;

#[cfg(windows)]
use std::os::raw::c_char;
#[cfg(windows)]
use std::io::Error;

use std::ffi::{CString};
#[cfg(windows)]
use std::ffi::{OsStr};
#[cfg(windows)]
use std::iter::once;
#[cfg(windows)]
use std::ptr::null_mut;

use std::mem;

type Callback = fn(*mut CWin); // callbacks get a mutable reference to win

// "Common window" - a basic window which will render on X11, Windorks, and Apple
pub struct CWin {
  title: String,
  desired_width_px: u16,
  desired_height_px: u16,
  pixels: Vec<Vec<u32>>,
  event_callbacks: Vec<Callback>,
}

impl CWin {
  pub fn new() -> CWin {
    let mut def_pix_buffer: Vec<Vec<u32>> = vec![];
    for _i in 0..4096 { // We'll store pixels as RGBA
      def_pix_buffer.push(vec![0xffffff00; 4096])
    }
    
    return CWin{
      title: "Untitled Window".to_string(),
      desired_width_px: 800,
      desired_height_px: 600,
      pixels: def_pix_buffer,
      event_callbacks: vec![],
    };
  }
  
  pub fn add_callback(&mut self, c: Callback) {
    self.event_callbacks.push(c);
  }
  
  pub fn call_all_callbacks(&mut self) {
    for c in self.event_callbacks.clone() { // todo we have to clone the callbacks vector to prevent them having a mutable refenrece to themselves - fix it
      (c)(self);
    }
  }
  
  pub fn display(&mut self) {
    // Lotsa platform-specific hackery
    #[cfg(unix)]
    unsafe {
      let xlib = x11_dl::xlib::Xlib::open().unwrap();
      
      let display = (xlib.XOpenDisplay)(&0/*null*/);
      let screen = (xlib.XDefaultScreen)(display);
      let window = (xlib.XCreateSimpleWindow)(
        display, (xlib.XRootWindow)(display, screen),
        0, 0, // x and y
        self.desired_width_px as u32, self.desired_height_px as u32,
        0 /*border_width*/, (xlib.XBlackPixel)(display, screen) /*border*/, (xlib.XWhitePixel)(display, screen) /*background*/
      );
      
      (xlib.XSelectInput)(display, window, x11_dl::xlib::ExposureMask | x11_dl::xlib::KeyPressMask);
      (xlib.XMapWindow)(display, window);
      
      loop {
        let mut event: x11_dl::xlib::XEvent = mem::zeroed(); //mem::uninitialized();
        (xlib.XNextEvent)(display, &mut event);
        
        if event.get_type() == x11_dl::xlib::Expose {
          let msg = CString::new(self.title.clone()).unwrap();
          (xlib.XFillRectangle)(display, window, (xlib.XDefaultGC)(display, screen), 20, 20, 10, 10);
          (xlib.XDrawString)(display, window, (xlib.XDefaultGC)(display, screen), 10, 50, msg.as_ptr(), 12 /*strlen msg*/);
        }
        if event.get_type() == x11_dl::xlib::KeyPress {
          break;
        }
      }
      (xlib.XCloseDisplay)(display);
      
    }
    
    #[cfg(windows)]
    unsafe {
      let win_window = create_win_window("WinName", self.title.as_str()).unwrap();
      
      loop {
        let mut message : MSG = mem::uninitialized();
        if GetMessageW( &mut message as *mut MSG, win_window.handle, 0, 0 ) > 0 {
            TranslateMessage( &message as *const MSG );
            DispatchMessageW( &message as *const MSG );
        }
        else {
            break;
        }
      }

      
    }
    
    #[cfg(target_os="macos")]
    {
      println!("Windorks support does not exist yet");
    }
    
  }
  
}

#[cfg(windows)]
struct Window {
  handle : HWND,
}

#[cfg(windows)]
fn win32_string( value : &str ) -> Vec<u16> {
    OsStr::new( value ).encode_wide().chain( once( 0 ) ).collect()
}

#[cfg(windows)]
fn create_win_window( name : &str, title : &str ) -> Result<Window, Error> {
    let name = win32_string( name );
    let title = win32_string( title );

    unsafe {
        let hinstance = GetModuleHandleW( null_mut() );
        let wnd_class = WNDCLASSW {
            style : CS_OWNDC | CS_HREDRAW | CS_VREDRAW,
            lpfnWndProc : Some( DefWindowProcW ),
            hInstance : hinstance,
            lpszClassName : name.as_ptr(),
            cbClsExtra : 0,
            cbWndExtra : 0,
            hIcon: null_mut(),
            hCursor: null_mut(),
            hbrBackground: null_mut(),
            lpszMenuName: null_mut(),
        };

        RegisterClassW( &wnd_class );

        let handle = CreateWindowExW(
            0,
            name.as_ptr(),
            title.as_ptr(),
            WS_OVERLAPPEDWINDOW | WS_VISIBLE,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            null_mut(),
            null_mut(),
            hinstance,
            null_mut() );

        if handle.is_null() {
            Err( Error::last_os_error() )
        } else {
            Ok( Window { handle } )
        }
    }
}