├── examples ├── src │ ├── hello.ico │ ├── hello.rc │ ├── hello.exe.manifest │ └── hello.rs ├── Cargo.toml ├── build.rs └── Cargo.lock ├── .gitignore ├── AUTHORS.txt ├── Cargo.toml ├── Makefile ├── COPYRIGHT ├── src ├── instance.rs ├── dialog.rs ├── lib.rs ├── resource.rs ├── macros.rs ├── font.rs ├── wchar.rs ├── gdi.rs └── window.rs ├── LICENSE-MIT └── LICENSE-APACHE /examples/src/hello.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klutzy/rust-windows/HEAD/examples/src/hello.ico -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.dll 2 | *.dummy 3 | *.exe 4 | *.rlib 5 | *~ 6 | /target 7 | /examples/target 8 | /Cargo.lock 9 | -------------------------------------------------------------------------------- /AUTHORS.txt: -------------------------------------------------------------------------------- 1 | Rust-Windows was written by these people: 2 | 3 | klutzy 4 | Gigih Aji Ibrahim 5 | Pål-Kristian Engstad 6 | Kang Seonghoon 7 | Peter Reid 8 | -------------------------------------------------------------------------------- /examples/src/hello.rc: -------------------------------------------------------------------------------- 1 | #include "winuser.h" 2 | 3 | #define IDI_ICON 0x101 4 | #define MENU_MAIN 0x201 5 | #define MENU_NEW 0x202 6 | #define MENU_EXIT 0x203 7 | 8 | CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "hello.exe.manifest" 9 | 10 | IDI_ICON ICON "hello.ico" 11 | 12 | MENU_MAIN MENU { 13 | POPUP "&File" { 14 | MENUITEM "&New\tCtrl+N", MENU_NEW 15 | MENUITEM "E&xit", MENU_EXIT 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/src/hello.exe.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | 3 | name = "rust-windows" 4 | version = "0.0.1" 5 | authors = ["klutzy ", 6 | "Gigih Aji Ibrahim ", 7 | "Pål-Kristian Engstad ", 8 | "Kang Seonghoon ", 9 | "Peter Reid "] 10 | tags = [] 11 | 12 | [lib] 13 | name = "rust_windows" 14 | 15 | [dependencies] 16 | gdi32-sys = "*" 17 | kernel32-sys = "*" 18 | user32-sys = "*" 19 | winapi = "*" 20 | log="*" 21 | -------------------------------------------------------------------------------- /examples/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | 3 | name = "examples" 4 | version = "0.0.1" 5 | authors = [ 6 | "klutzy ", 7 | "Gigih Aji Ibrahim ", 8 | "Pål-Kristian Engstad ", 9 | "Kang Seonghoon ", 10 | "Peter Reid " 11 | ] 12 | build="build.rs" 13 | [[bin]] 14 | name = "hello" 15 | path = "src/hello.rs" 16 | 17 | [dependencies.rust-windows] 18 | path = ".." 19 | 20 | [dependencies] 21 | winapi = "*" 22 | log = "*" 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | RUSTC?=rustc.exe 2 | RUST_OPTS?= 3 | SRC=$(wildcard src/*.rs) $(wildcard src/ll/*.rs) 4 | 5 | .PHONY: all 6 | all: libwindows.dummy 7 | 8 | libwindows.dummy: $(SRC) 9 | $(RUSTC) src/lib.rs $(RUST_OPTS) 10 | touch $@ 11 | 12 | .PHONY: check 13 | check: $(SRC) 14 | $(RUSTC) --test -o $@ src/lib.rs 15 | ./$@ 16 | 17 | 18 | .PHONY: examples 19 | examples: libwindows.dummy 20 | $(MAKE) -C examples RUST_OPTS="$(RUST_OPTS)" RUSTC="$(RUSTC)" 21 | 22 | 23 | .PHONY: clean 24 | clean: 25 | rm -rf libwindows.dummy librust-windows-*.rlib rust-windows-*.dll *.exe 26 | $(MAKE) -C examples clean 27 | -------------------------------------------------------------------------------- /COPYRIGHT: -------------------------------------------------------------------------------- 1 | Short version for non-lawyers: 2 | 3 | The Rust-Windows Project is dual-licensed under Apache 2.0 and MIT 4 | terms. 5 | 6 | 7 | Longer version: 8 | 9 | The Rust-Windows Project is copyright 2015, The Rust-Windows Project 10 | Developers (given in the file AUTHORS.txt). 11 | 12 | Licensed under the Apache License, Version 2.0 13 | or the MIT 15 | license , 16 | at your option. All files in the project carrying such 17 | notice may not be copied, modified, or distributed except 18 | according to those terms. 19 | 20 | -------------------------------------------------------------------------------- /examples/build.rs: -------------------------------------------------------------------------------- 1 | use std::process::Command; 2 | use std::env; 3 | use std::path::Path; 4 | 5 | fn main() { 6 | let out_dir = env::var("OUT_DIR").ok().expect("can't find out_dir"); 7 | 8 | Command::new("windres").args(&["src/hello.rc", "-o"]) 9 | .arg(&format!("{}/hello.rc.o", out_dir)) 10 | .status().unwrap(); 11 | Command::new("ar").args(&["crus", "libhello_rc.a", "hello.rc.o"]) 12 | .current_dir(&Path::new(&out_dir)) 13 | .status().unwrap(); 14 | 15 | println!("cargo:rustc-link-search=native={}", out_dir); 16 | println!("cargo:rustc-link-lib=static=hello_rc"); 17 | } -------------------------------------------------------------------------------- /src/instance.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Rust-Windows Project Developers. See the 2 | // COPYRIGHT file at the top-level directory of this distribution. 3 | // 4 | // Licensed under the Apache License, Version 2.0 or the MIT license 6 | // , at your 7 | // option. This file may not be copied, modified, or distributed 8 | // except according to those terms. 9 | 10 | use std::ptr; 11 | 12 | use kernel32; 13 | use winapi::{HINSTANCE}; 14 | 15 | #[derive(Clone,Copy)] 16 | pub struct Instance { 17 | pub instance: HINSTANCE 18 | } 19 | 20 | impl Instance { 21 | pub fn main_instance() -> Instance { 22 | Instance { 23 | instance: unsafe { kernel32::GetModuleHandleW(ptr::null()) as HINSTANCE }, 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/dialog.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Rust-Windows Project Developers. See the 2 | // COPYRIGHT file at the top-level directory of this distribution. 3 | // 4 | // Licensed under the Apache License, Version 2.0 or the MIT license 6 | // , at your 7 | // option. This file may not be copied, modified, or distributed 8 | // except according to those terms. 9 | 10 | use super::wchar::ToCU16Str; 11 | use super::window::Window; 12 | 13 | use user32; 14 | 15 | pub trait DialogUtil { 16 | fn message_box(&self, msg: &str, title: &str); 17 | } 18 | 19 | impl DialogUtil for Window { 20 | fn message_box(&self, msg: &str, title: &str) { 21 | let msg_u = msg.to_c_u16(); 22 | let title_u = title.to_c_u16(); 23 | unsafe { 24 | user32::MessageBoxW(self.wnd, msg_u.as_ptr(), title_u.as_ptr(), 0u32); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 The Rust-Windows Project Developers 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /examples/Cargo.lock: -------------------------------------------------------------------------------- 1 | [root] 2 | name = "examples" 3 | version = "0.0.1" 4 | dependencies = [ 5 | "log 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 6 | "rust-windows 0.0.1", 7 | "winapi 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", 8 | ] 9 | 10 | [[package]] 11 | name = "gdi32-sys" 12 | version = "0.1.0" 13 | source = "registry+https://github.com/rust-lang/crates.io-index" 14 | dependencies = [ 15 | "winapi 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", 16 | ] 17 | 18 | [[package]] 19 | name = "kernel32-sys" 20 | version = "0.1.0" 21 | source = "registry+https://github.com/rust-lang/crates.io-index" 22 | dependencies = [ 23 | "winapi 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", 24 | ] 25 | 26 | [[package]] 27 | name = "libc" 28 | version = "0.1.6" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | 31 | [[package]] 32 | name = "log" 33 | version = "0.3.1" 34 | source = "registry+https://github.com/rust-lang/crates.io-index" 35 | dependencies = [ 36 | "libc 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 37 | ] 38 | 39 | [[package]] 40 | name = "rust-windows" 41 | version = "0.0.1" 42 | dependencies = [ 43 | "gdi32-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 44 | "kernel32-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 45 | "log 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 46 | "user32-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 47 | "winapi 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", 48 | ] 49 | 50 | [[package]] 51 | name = "user32-sys" 52 | version = "0.1.0" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | dependencies = [ 55 | "winapi 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", 56 | ] 57 | 58 | [[package]] 59 | name = "winapi" 60 | version = "0.1.17" 61 | source = "registry+https://github.com/rust-lang/crates.io-index" 62 | dependencies = [ 63 | "libc 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 64 | ] 65 | 66 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Rust-Windows Project Developers. See the 2 | // COPYRIGHT file at the top-level directory of this distribution. 3 | // 4 | // Licensed under the Apache License, Version 2.0 or the MIT license 6 | // , at your 7 | // option. This file may not be copied, modified, or distributed 8 | // except according to those terms. 9 | 10 | #![crate_type = "lib"] 11 | #![crate_type = "dylib"] 12 | #![crate_name = "rust_windows"] 13 | 14 | #[macro_use] 15 | extern crate log; 16 | extern crate gdi32; 17 | extern crate kernel32; 18 | extern crate user32; 19 | extern crate winapi; 20 | 21 | use std::ptr; 22 | use winapi::{DWORD, HWND, LONG, LPARAM, LPMSG, LRESULT, MSG, POINT, UINT, WPARAM}; 23 | 24 | #[macro_use] 25 | pub mod macros; 26 | pub mod instance; 27 | pub mod resource; 28 | pub mod font; 29 | pub mod wchar; 30 | pub mod window; 31 | pub mod gdi; 32 | pub mod dialog; 33 | 34 | pub fn get_last_error() -> DWORD { 35 | unsafe { kernel32::GetLastError() } 36 | } 37 | 38 | pub fn def_window_proc(hwnd: HWND, msg: UINT, w: WPARAM, l: LPARAM) -> LRESULT { 39 | unsafe { user32::DefWindowProcW(hwnd, msg, w, l) } 40 | } 41 | 42 | pub fn main_window_loop() -> usize { 43 | let mut msg = MSG { 44 | hwnd: ptr::null_mut(), 45 | message: 0 as UINT, 46 | wParam: 0 as WPARAM, 47 | lParam: 0 as LPARAM, 48 | time: 0 as DWORD, 49 | pt: POINT { x: 0 as LONG, y: 0 as LONG }, 50 | }; 51 | loop { 52 | let ret = unsafe { 53 | user32::GetMessageW(&mut msg as LPMSG, ptr::null_mut(), 54 | 0 as UINT, 0 as UINT) 55 | }; 56 | 57 | if ret == 0 { 58 | let exit_code = msg.wParam; 59 | return exit_code as usize; 60 | } 61 | else { 62 | unsafe { 63 | user32::TranslateMessage(&msg as *const MSG); 64 | user32::DispatchMessageW(&msg as *const MSG); 65 | } 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/resource.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Rust-Windows Project Developers. See the 2 | // COPYRIGHT file at the top-level directory of this distribution. 3 | // 4 | // Licensed under the Apache License, Version 2.0 or the MIT license 6 | // , at your 7 | // option. This file may not be copied, modified, or distributed 8 | // except according to those terms. 9 | 10 | use std::ptr; 11 | use std; 12 | 13 | use user32; 14 | use winapi::{HANDLE, UINT, c_int}; 15 | 16 | use wchar::ToCU16Str; 17 | use instance::Instance; 18 | 19 | pub trait ToHandle { 20 | fn to_handle(&self) -> HANDLE; 21 | } 22 | 23 | impl ToHandle for Option { 24 | fn to_handle(&self) -> HANDLE { 25 | match *self { 26 | None => ptr::null_mut(), 27 | Some(ref s) => s.to_handle(), 28 | } 29 | } 30 | } 31 | 32 | #[allow(non_camel_case_types)] 33 | #[derive(Clone,Copy)] 34 | pub enum ImageType { 35 | IMAGE_BITMAP = 0, 36 | IMAGE_ICON = 1, 37 | IMAGE_CURSOR = 2, 38 | } 39 | 40 | #[derive(Clone,Copy)] 41 | pub struct Image { 42 | pub image: HANDLE, 43 | } 44 | 45 | impl Image { 46 | pub fn load_resource(instance: Instance, id: isize, img_type: ImageType, width: isize, height: isize) -> Option { 47 | let img = unsafe { 48 | user32::LoadImageW( 49 | instance.instance, std::mem::transmute(id), img_type as UINT, 50 | width as c_int, height as c_int, 0x8000 51 | ) 52 | }; 53 | 54 | if img == ptr::null_mut() { 55 | None 56 | } else { 57 | Some(Image { image: img }) 58 | } 59 | } 60 | 61 | pub fn load_cursor_resource(id: isize) -> Option { 62 | let null_instance = Instance { instance: ptr::null_mut() }; 63 | Image::load_resource(null_instance, id, ImageType::IMAGE_CURSOR, 0, 0) 64 | } 65 | } 66 | 67 | impl ToHandle for Image { 68 | fn to_handle(&self) -> HANDLE { 69 | self.image 70 | } 71 | } 72 | 73 | pub enum MenuResource { 74 | MenuName(String), 75 | MenuId(isize), 76 | } 77 | 78 | impl MenuResource { 79 | pub fn with_menu_p(&self, f: F) -> T 80 | where F: FnOnce(*const u16) -> T { 81 | match *self { 82 | MenuResource::MenuName(ref s) => { 83 | let u = &s.to_c_u16(); 84 | f(u.as_ptr()) 85 | } 86 | MenuResource::MenuId(id) => unsafe { f(std::mem::transmute(id)) }, 87 | } 88 | } 89 | 90 | pub fn null() -> MenuResource { 91 | MenuResource::MenuId(0) 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/macros.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Rust-Windows Project Developers. See the 2 | // COPYRIGHT file at the top-level directory of this distribution. 3 | // 4 | // Licensed under the Apache License, Version 2.0 or the MIT license 6 | // , at your 7 | // option. This file may not be copied, modified, or distributed 8 | // except according to those terms. 9 | 10 | #[macro_export] 11 | macro_rules! wnd_proc_thunk( 12 | ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_CREATE) => ( 13 | if $msg == 0x0001 { // WM_CREATE 14 | let cs = unsafe { 15 | let pcs = ::std::mem::transmute::<::winapi::LPARAM, 16 | *const ::winapi::CREATESTRUCTW>($l); 17 | &(*pcs) 18 | }; 19 | let ret = $self_.on_create(cs); 20 | if ret { 21 | return 0 as ::winapi::LRESULT; 22 | } else { 23 | return -1 as ::winapi::LRESULT; 24 | } 25 | } 26 | ); 27 | ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_DESTROY) => ( 28 | if $msg == 0x0002 { // WM_DESTROY 29 | $self_.on_destroy(); 30 | return 0 as ::winapi::LRESULT; 31 | } 32 | ); 33 | ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_SIZE) => ( 34 | if $msg == 0x0005 { // WM_SIZE 35 | let l = $l as u32; 36 | let width = (l & 0xFFFF) as isize; 37 | let height = (l >> 16) as isize; 38 | $self_.on_size(width, height); 39 | return 0 as ::winapi::LRESULT; 40 | } 41 | ); 42 | ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_SETFOCUS) => ( 43 | if $msg == 0x0007 { // WM_SETFOCUS 44 | let w = ::windows::window::Window { wnd: $w as ::winapi::HWND }; 45 | $self_.on_focus(w); 46 | return 0 as ::winapi::LRESULT; 47 | } 48 | ); 49 | ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_PAINT) => ( 50 | if $msg == 0x000F { // WM_PAINT 51 | $self_.on_paint(); 52 | return 0 as ::winapi::LRESULT; 53 | } 54 | ); 55 | ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_LBUTTONDOWN) => ( 56 | if $msg == 0x0201 { // WM_LBUTTONDOWN 57 | let l = $l as u32; 58 | let x = (l & 0xFFFF) as isize; 59 | let y = (l >> 16) as isize; 60 | let flags = $w as u32; 61 | $self_.on_left_button_down(x, y, flags); 62 | return 0 as ::winapi::LRESULT; 63 | } 64 | ); 65 | ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_LBUTTONUP) => ( 66 | if $msg == 0x0202 { // WM_LBUTTONUP 67 | let l = $l as u32; 68 | let x = (l & 0xFFFF) as isize; 69 | let y = (l >> 16) as isize; 70 | let flags = $w as u32; 71 | $self_.on_left_button_up(x, y, flags); 72 | return 0 as ::winapi::LRESULT; 73 | } 74 | ); 75 | ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_KEYDOWN) => ( 76 | if $msg == 0x0100 { // WM_KEYDOWN 77 | return $self_.on_key_down($w as u8, $l as u32) as ::winapi::LRESULT; 78 | } 79 | ); 80 | ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_KEYUP) => ( 81 | if $msg == 0x0101 { // WM_KEYUP 82 | return $self_.on_key_up($w as u8, $l as u32) as ::winapi::LRESULT; 83 | } 84 | ); 85 | ($self_:ident, $msg:ident, $w:ident, $l:ident, WM_ERASEBKGND) => ( 86 | if $msg == 0x0014 { // WM_ERASEBKGND 87 | // Returning 1 means that the background no longer needs erasing. 88 | return $self_.on_erase_background() as ::winapi::LRESULT; 89 | } 90 | ); 91 | ($self_:ident, $msg:ident, $w:ident, $l:ident, ANY) => ( 92 | if let Some(result) = $self_.on_message($msg, $w, $l) { 93 | return result; 94 | } 95 | ); 96 | ); 97 | 98 | #[macro_export] 99 | macro_rules! wnd_proc( 100 | ($wnd:ident, $win:ident, $($msg:ident),+) => ( 101 | 102 | impl ::windows::window::WindowImpl for $wnd { 103 | fn wnd<'a>(&'a self) -> &'a ::windows::window::Window { 104 | &self.$win 105 | } 106 | 107 | fn wnd_mut<'a>(&'a mut self) -> &'a mut ::windows::window::Window { 108 | &mut self.$win 109 | } 110 | 111 | fn wnd_proc(&self, msg: ::winapi::UINT, w: ::winapi::WPARAM, 112 | l: ::winapi::LPARAM) -> ::winapi::LRESULT { 113 | $( 114 | wnd_proc_thunk!(self, msg, w, l, $msg); 115 | )+ 116 | ::windows::def_window_proc(self.wnd().wnd, msg, w, l) 117 | } 118 | } 119 | 120 | ) 121 | ); 122 | -------------------------------------------------------------------------------- /src/font.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Rust-Windows Project Developers. See the 2 | // COPYRIGHT file at the top-level directory of this distribution. 3 | // 4 | // Licensed under the Apache License, Version 2.0 or the MIT license 6 | // , at your 7 | // option. This file may not be copied, modified, or distributed 8 | // except according to those terms. 9 | 10 | #![allow(non_camel_case_types)] 11 | 12 | use std::ptr; 13 | use std::default::Default; 14 | 15 | use gdi32; 16 | use winapi::{DWORD, HFONT, c_int}; 17 | 18 | use wchar::ToCU16Str; 19 | 20 | #[derive(Clone,Copy)] 21 | pub enum CharSet { 22 | ANSI_CHARSET = 0, 23 | DEFAULT_CHARSET = 1, 24 | SYMBOL_CHARSET = 2, 25 | SHIFTJIS_CHARSET = 128, 26 | // HANGEUL_CHARSET = 129, 27 | HANGUL_CHARSET = 129, 28 | GB2312_CHARSET = 134, 29 | CHINESEBIG5_CHARSET = 136, 30 | GREEK_CHARSET = 161, 31 | TURKISH_CHARSET = 162, 32 | HEBREW_CHARSET = 177, 33 | ARABIC_CHARSET = 178, 34 | BALTIC_CHARSET = 186, 35 | RUSSIAN_CHARSET = 204, 36 | THAI_CHARSET = 222, 37 | EASTEUROPE_CHARSET = 238, 38 | OEM_CHARSET = 255, 39 | JOHAB_CHARSET = 130, 40 | VIETNAMESE_CHARSET = 163, 41 | MAC_CHARSET = 77, 42 | } 43 | 44 | #[derive(Clone,Copy)] 45 | pub enum OutputPrecision { 46 | OUT_DEFAULT_PRECIS = 0, 47 | OUT_STRING_PRECIS = 1, 48 | OUT_CHARACTER_PRECIS = 2, 49 | OUT_STROKE_PRECIS = 3, 50 | OUT_TT_PRECIS = 4, 51 | OUT_DEVICE_PRECIS = 5, 52 | OUT_RASTER_PRECIS = 6, 53 | OUT_TT_ONLY_PRECIS = 7, 54 | OUT_OUTLINE_PRECIS = 8, 55 | OUT_PS_ONLY_PRECIS = 10, 56 | } 57 | 58 | #[derive(Clone,Copy)] 59 | pub enum ClipPrecision { 60 | CLIP_DEFAULT_PRECIS = 0, 61 | CLIP_CHARACTER_PRECIS = 1, 62 | CLIP_STROKE_PRECIS = 2, 63 | CLIP_MASK = 15, 64 | CLIP_LH_ANGLES = 16, 65 | CLIP_TT_ALWAYS = 32, 66 | CLIP_EMBEDDED = 128, 67 | // TODO: 68 | // CLIP_DFA_DISABLE 69 | // CLIP_DFA_OVERRIDE 70 | } 71 | 72 | #[derive(Clone,Copy)] 73 | pub enum Quality { 74 | DEFAULT_QUALITY = 0, 75 | DRAFT_QUALITY = 1, 76 | PROOF_QUALITY = 2, 77 | NONANTIALIASED_QUALITY = 3, 78 | ANTIALIASED_QUALITY = 4, 79 | // #if _WIN32_WINNT >= 0x0500 80 | CLEARTYPE_QUALITY = 5, 81 | } 82 | 83 | #[derive(Clone,Copy)] 84 | pub enum Pitch { 85 | DEFAULT_PITCH = 0, 86 | FIXED_PITCH = 1, 87 | VARIABLE_PITCH = 2, 88 | } 89 | 90 | #[derive(Clone,Copy)] 91 | pub enum Family { 92 | FF_DECORATIVE = 80, 93 | FF_DONTCARE = 0, 94 | FF_MODERN = 48, 95 | FF_ROMAN = 16, 96 | FF_SCRIPT = 64, 97 | FF_SWISS = 32, 98 | } 99 | 100 | pub struct FontAttr { 101 | pub height: isize, 102 | pub width: isize, 103 | pub escapement: isize, 104 | pub orientation: isize, 105 | pub weight: isize, 106 | pub italic: bool, 107 | pub underline: bool, 108 | pub strike_out: bool, 109 | pub char_set: CharSet, 110 | pub output_precision: OutputPrecision, 111 | pub clip_precision: ClipPrecision, 112 | pub quality: Quality, 113 | pub pitch: Pitch, 114 | pub family: Family, 115 | pub face: Option, 116 | } 117 | 118 | impl Default for FontAttr { 119 | fn default() -> FontAttr { 120 | FontAttr { 121 | height: 0, 122 | width: 0, 123 | escapement: 0, 124 | orientation: 0, 125 | weight: 400, // FW_NORMAL. TODO use FW_DONTCARE (0)? 126 | italic: false, 127 | underline: false, 128 | strike_out: false, 129 | char_set: CharSet::DEFAULT_CHARSET, 130 | output_precision: OutputPrecision::OUT_DEFAULT_PRECIS, 131 | clip_precision: ClipPrecision::CLIP_DEFAULT_PRECIS, 132 | quality: Quality::DEFAULT_QUALITY, 133 | pitch: Pitch::DEFAULT_PITCH, 134 | family: Family::FF_DONTCARE, 135 | face: None, 136 | } 137 | } 138 | } 139 | 140 | #[derive(Copy)] 141 | pub struct Font { 142 | pub font: HFONT, 143 | } 144 | 145 | impl Clone for Font { 146 | fn clone(&self) -> Font { 147 | Font { 148 | font: self.font, 149 | } 150 | } 151 | } 152 | 153 | impl Font { 154 | pub fn new(attr: &FontAttr) -> Option { 155 | let face = attr.face.to_c_u16(); 156 | let hfont = unsafe { 157 | gdi32::CreateFontW( 158 | attr.height as c_int, 159 | attr.width as c_int, 160 | attr.escapement as c_int, 161 | attr.orientation as c_int, 162 | attr.weight as c_int, 163 | attr.italic as DWORD, 164 | attr.underline as DWORD, 165 | attr.strike_out as DWORD, 166 | attr.char_set as DWORD, 167 | attr.output_precision as DWORD, 168 | attr.clip_precision as DWORD, 169 | attr.quality as DWORD, 170 | (attr.pitch as DWORD) | (attr.family as DWORD), 171 | if face.len()==0 { ptr::null_mut() } else { face.as_ptr() }, 172 | ) 173 | }; 174 | if hfont == ptr::null_mut() { 175 | None 176 | } 177 | else { 178 | Some(Font { font: hfont }) 179 | } 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /src/wchar.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Rust-Windows Project Developers. See the 2 | // COPYRIGHT file at the top-level directory of this distribution. 3 | // 4 | // Licensed under the Apache License, Version 2.0 or the MIT license 6 | // , at your 7 | // option. This file may not be copied, modified, or distributed 8 | // except according to those terms. 9 | 10 | use std::mem; 11 | use std::ffi::{OsStr,OsString}; 12 | use std::fmt; 13 | use std::fmt::Display; 14 | use std::os::windows::ffi::{OsStrExt, OsStringExt}; 15 | use std::vec::Vec; 16 | 17 | // Helper struct for *u16 manipulation. 18 | #[allow(missing_copy_implementations)] 19 | pub struct CU16String { 20 | buf: *const u16, 21 | /// length of buffer, including null 22 | len: usize, 23 | } 24 | 25 | impl CU16String { 26 | /// Create a CU16String from a pointer. 27 | pub unsafe fn new(buf: *const u16) -> CU16String { 28 | CU16String { 29 | buf: buf, 30 | len: { 31 | let mut length_counter = 0; 32 | loop { 33 | if *buf.offset(length_counter)==0 { 34 | break; 35 | } 36 | length_counter += 1; 37 | } 38 | length_counter += 1; 39 | length_counter as usize 40 | } 41 | } 42 | } 43 | 44 | /// Converts the CU16String into a `&[u16]` without copying. 45 | /// NULL is not included. 46 | /// 47 | /// # Failure 48 | /// 49 | /// Fails if the CU16String is null. 50 | #[inline] 51 | pub fn as_u16_vec<'a>(&'a self) -> &'a [u16] { 52 | if self.buf.is_null() { panic!("CU16String is null!"); } 53 | unsafe { 54 | mem::transmute((self.buf, self.len - 1)) 55 | } 56 | } 57 | } 58 | 59 | impl fmt::Display for CU16String { 60 | #[inline] 61 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 62 | let s = if self.buf.is_null() { 63 | "".to_string() 64 | } else { 65 | String::from_utf16_lossy(self.as_u16_vec()) 66 | }; 67 | s.fmt(f) 68 | } 69 | } 70 | 71 | /// Parses a C utf-16 "multistring". 72 | /// See `std::c_str::from_c_multistring` for detailed explanation. 73 | pub unsafe fn from_c_u16_multistring(buf: *const u16, count: Option, mut f: F) -> usize 74 | where F: FnMut(&[u16]) { 75 | let mut curr_ptr: usize = buf as usize; 76 | let mut ctr = 0; 77 | let (limited_count, limit) = match count { 78 | Some(limit) => (true, limit), 79 | None => (false, 0) 80 | }; 81 | while ((limited_count && ctr < limit) || !limited_count) 82 | && *(curr_ptr as *const u16) != 0 as u16 { 83 | let cstr = CU16String::new(curr_ptr as *const u16); 84 | f(cstr.as_u16_vec()); 85 | curr_ptr += cstr.len * 2; 86 | ctr += 1; 87 | } 88 | return ctr; 89 | } 90 | 91 | /// A generic trait for converting a value to a `CU16String`, like `ToCStr`. 92 | pub trait ToCU16Str { 93 | fn to_c_u16(&self) -> Vec; 94 | } 95 | 96 | impl<'a> ToCU16Str for &'a str { 97 | fn to_c_u16(&self) -> Vec { 98 | let mut t : Vec = OsStr::new( self ) 99 | .encode_wide() 100 | .chain(Some(0).into_iter()) 101 | .collect::>(); 102 | t.push(0u16); 103 | t 104 | } 105 | } 106 | 107 | impl ToCU16Str for String { 108 | fn to_c_u16(&self) -> Vec { 109 | let x : &str = &self; 110 | x.to_c_u16() 111 | } 112 | } 113 | 114 | impl ToCU16Str for Option { 115 | fn to_c_u16(&self) -> Vec { 116 | match self { 117 | &None => Vec::new(), 118 | &Some(ref s) => (&s).to_c_u16(), 119 | } 120 | } 121 | } 122 | 123 | pub trait FromCU16Str { 124 | fn from_c_u16(wide: &Vec) -> Option; 125 | } 126 | 127 | impl FromCU16Str for String { 128 | fn from_c_u16(wide: &Vec) -> Option { 129 | let t = OsString::from_wide(wide); 130 | t.to_str().map( str::to_string ) 131 | } 132 | } 133 | 134 | #[cfg(test)] 135 | mod test { 136 | use super::CU16String; 137 | use super::from_c_u16_multistring; 138 | 139 | #[test] 140 | fn test_as_u16_vec() { 141 | let u16s: &[u16] = &[ 142 | 0xac00, 0x20, 0xac00, 0x00, 143 | ]; 144 | 145 | let cu = unsafe { CU16String::new(u16s.as_ptr()) }; 146 | let v = cu.as_u16_vec(); 147 | assert_eq!(v, &u16s[..u16s.len() - 1]); 148 | } 149 | 150 | #[test] 151 | fn test_from_c_u16_multistring() { 152 | let test: &[u16] = &[ 153 | 0xac00, 0x00, 154 | 0xac00, 0xac00, 0x00, 155 | 0xac00, 0xac00, 0xac00, 0x00, 156 | 0xac00, 0xac00, 0xac00, 0xac02, 0x00, 157 | 0x00, 158 | ]; 159 | let compare = [ 160 | "가", 161 | "가가", 162 | "가가가", 163 | "가가가갂", 164 | ]; 165 | let mut i = 0; 166 | let buf = test.as_ptr(); 167 | unsafe { 168 | from_c_u16_multistring(buf, None, |p| { 169 | let b = String::from_utf16(p).unwrap(); 170 | assert_eq!(b, compare[i].to_owned()); 171 | assert_eq!(b.chars().count(), i + 1); 172 | i += 1; 173 | }); 174 | } 175 | assert_eq!(i, 4); 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /src/gdi.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Rust-Windows Project Developers. See the 2 | // COPYRIGHT file at the top-level directory of this distribution. 3 | // 4 | // Licensed under the Apache License, Version 2.0 or the MIT license 6 | // , at your 7 | // option. This file may not be copied, modified, or distributed 8 | // except according to those terms. 9 | 10 | use std::ptr; 11 | use std::ffi::OsStr; 12 | use std::os::windows::ffi::OsStrExt; 13 | 14 | use gdi32; 15 | use user32; 16 | use winapi::{ 17 | BOOL, BYTE, COLORREF, DWORD, HANDLE, HBITMAP, HBRUSH, HDC, HFONT, HGDIOBJ, HWND, LONG, 18 | PAINTSTRUCT, RECT, c_int, 19 | }; 20 | 21 | use font::Font; 22 | use window::WindowImpl; 23 | 24 | #[derive(Clone,Copy)] 25 | pub struct Dc { 26 | pub raw: HDC, 27 | } 28 | 29 | impl Dc { 30 | pub fn raw(&self) -> HDC { 31 | self.raw 32 | } 33 | 34 | pub fn text_out(&self, x: isize, y: isize, s: &str) -> bool { 35 | let mut s16 : Vec = OsStr::new( s ) 36 | .encode_wide() 37 | .chain(Some(0).into_iter()) 38 | .collect::>(); 39 | let len = s16.len(); 40 | 41 | s16.push(0u16); 42 | let ret = unsafe { 43 | gdi32::TextOutW(self.raw, x as c_int, y as c_int, s16.as_mut_ptr(), len as i32) 44 | }; 45 | ret != 0 46 | } 47 | 48 | pub fn select_object(&self, handle: HANDLE) -> HANDLE { 49 | unsafe { gdi32::SelectObject(self.raw, handle as HGDIOBJ) } 50 | } 51 | 52 | pub fn select_font(&self, font: &Font) -> Option { 53 | let res = self.select_object(font.font as HANDLE); 54 | if res.is_null() { 55 | None 56 | } else { 57 | Some(Font { font: res as HFONT }) 58 | } 59 | } 60 | 61 | pub fn set_text_color(&self, color: COLORREF) -> COLORREF { 62 | unsafe { gdi32::SetTextColor(self.raw, color) } 63 | } 64 | 65 | pub fn set_background_color(&self, color: COLORREF) -> COLORREF { 66 | unsafe { gdi32::SetBkColor(self.raw, color) } 67 | } 68 | 69 | pub fn create_compatible_bitmap(&self, width: isize, height: isize) -> Bitmap { 70 | let raw = unsafe { 71 | gdi32::CreateCompatibleBitmap(self.raw, width as c_int, height as c_int) 72 | }; 73 | Bitmap { raw: raw } 74 | } 75 | 76 | pub fn bit_blt(&self, pos: (isize, isize), size: (isize, isize), src: &Dc, 77 | src_pos: (isize, isize), flag: DWORD) -> bool { 78 | let res = unsafe { 79 | let (px, py) = pos; 80 | let (w, h) = size; 81 | let (sx, sy) = src_pos; 82 | gdi32::BitBlt(self.raw, px as c_int, py as c_int, w as c_int, h as c_int, 83 | src.raw, sx as c_int, sy as c_int, flag) 84 | }; 85 | return res != 0; 86 | } 87 | 88 | pub fn fill_rect(&self, left_top: (isize, isize), right_bottom: (isize, isize), brush: HBRUSH) -> bool { 89 | let (left, top) = left_top; 90 | let (right, bottom) = right_bottom; 91 | let rect = RECT { 92 | left: left as LONG, top: top as LONG, 93 | right: right as LONG, bottom: bottom as LONG 94 | }; 95 | let res = unsafe { 96 | user32::FillRect(self.raw, &rect, brush) 97 | }; 98 | return res != 0; 99 | } 100 | 101 | pub fn rect(&self, left_top: (isize, isize), right_bottom: (isize, isize)) -> bool { 102 | let (left, top) = left_top; 103 | let (right, bottom) = right_bottom; 104 | let res = unsafe { 105 | gdi32::Rectangle(self.raw, left as c_int, top as c_int, right as c_int, bottom as c_int) 106 | }; 107 | return res != 0; 108 | } 109 | 110 | } 111 | 112 | pub struct PaintDc { 113 | pub dc: Dc, 114 | pub wnd: HWND, 115 | pub ps: PAINTSTRUCT, 116 | } 117 | 118 | impl PaintDc { 119 | pub fn new(w: &W) -> Option { 120 | let mut ps = PAINTSTRUCT { 121 | hdc: ptr::null_mut(), 122 | fErase: 0 as BOOL, 123 | rcPaint: RECT { 124 | left: 0 as LONG, top: 0 as LONG, 125 | right: 0 as LONG, bottom: 0 as LONG 126 | }, 127 | fRestore: 0 as BOOL, 128 | fIncUpdate: 0 as BOOL, 129 | rgbReserved: [0 as BYTE; 32], 130 | }; 131 | 132 | let wnd = w.wnd().wnd; 133 | let dc = unsafe { user32::BeginPaint(wnd, &mut ps) }; 134 | if dc.is_null() { 135 | return None; 136 | } 137 | 138 | let pdc = PaintDc { 139 | dc: Dc { raw: dc }, 140 | wnd: wnd, 141 | ps: ps, 142 | }; 143 | Some(pdc) 144 | } 145 | } 146 | 147 | impl Drop for PaintDc { 148 | fn drop(&mut self) { 149 | unsafe { user32::EndPaint(self.wnd, &self.ps) }; 150 | } 151 | } 152 | 153 | pub struct MemoryDc { 154 | pub dc: Dc, 155 | } 156 | 157 | impl MemoryDc { 158 | pub fn new(dc: &Dc) -> Option { 159 | let hdc = unsafe { gdi32::CreateCompatibleDC(dc.raw) }; 160 | if hdc.is_null() { 161 | return None; 162 | } 163 | 164 | Some(MemoryDc { dc: Dc { raw: hdc } }) 165 | } 166 | } 167 | 168 | impl Drop for MemoryDc { 169 | fn drop(&mut self) { 170 | unsafe { gdi32::DeleteDC(self.dc.raw) }; 171 | } 172 | } 173 | 174 | pub struct Bitmap { 175 | raw: HBITMAP, 176 | } 177 | 178 | impl Drop for Bitmap { 179 | fn drop(&mut self) { 180 | unsafe { gdi32::DeleteObject(self.raw as HGDIOBJ) }; 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /examples/src/hello.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Rust-Windows Project Developers. See the 2 | // COPYRIGHT file at the top-level directory of this distribution. 3 | // 4 | // Licensed under the Apache License, Version 2.0 or the MIT license 6 | // , at your 7 | // option. This file may not be copied, modified, or distributed 8 | // except according to those terms. 9 | 10 | //#![feature(core, exit_status)] 11 | 12 | #[macro_use] 13 | extern crate log; 14 | 15 | extern crate winapi; 16 | 17 | #[macro_use] 18 | extern crate rust_windows as windows; 19 | 20 | use std::ptr; 21 | use std::cell::RefCell; 22 | use std::default::Default; 23 | use std::env; 24 | 25 | use winapi::{UINT, HBRUSH, CREATESTRUCTW}; 26 | use winapi::{DWORD, WORD, LPARAM, WPARAM, LRESULT}; 27 | use winapi::{WM_COMMAND, WM_DESTROY}; 28 | use winapi::minwindef::LOWORD; 29 | 30 | use windows::main_window_loop; 31 | use windows::instance::Instance; 32 | use windows::resource::*; 33 | use windows::window::{WindowImpl, Window, WndClass, WindowParams}; 34 | use windows::window::{OnCreate, OnSize, OnDestroy, OnPaint, OnFocus, OnMessage}; 35 | use windows::window; 36 | use windows::gdi::PaintDc; 37 | use windows::font::Font; 38 | use windows::font; 39 | use windows::dialog::DialogUtil; 40 | 41 | // TODO duplicate of hello.rc 42 | const IDI_ICON: isize = 0x101; 43 | const MENU_MAIN: isize = 0x201; 44 | const MENU_NEW: WORD = 0x202; 45 | const MENU_EXIT: WORD = 0x203; 46 | 47 | struct MainFrame { 48 | win: Window, 49 | title: String, 50 | text_height: isize, 51 | edit: RefCell>, 52 | font: RefCell>, 53 | } 54 | 55 | wnd_proc!(MainFrame, win, WM_CREATE, WM_DESTROY, WM_SIZE, WM_SETFOCUS, WM_PAINT, ANY); 56 | 57 | impl OnCreate for MainFrame { 58 | fn on_create(&self, _cs: &CREATESTRUCTW) -> bool { 59 | let rect = self.win.client_rect().unwrap(); 60 | let params = WindowParams { 61 | window_name: "Hello World".to_string(), 62 | style: window::WS_CHILD | window::WS_VISIBLE | window::WS_BORDER | window::WS_VSCROLL | 63 | window::ES_AUTOVSCROLL | window::ES_MULTILINE | window::ES_NOHIDESEL, 64 | x: 0, 65 | y: self.text_height, 66 | width: rect.right as isize, 67 | height: rect.bottom as isize - self.text_height, 68 | parent: self.win, 69 | menu: ptr::null_mut(), 70 | ex_style: 0, 71 | }; 72 | let edit = Window::new(Instance::main_instance(), None, "EDIT", ¶ms); 73 | match edit { 74 | None => false, 75 | Some(e) => { 76 | let font_attr = Default::default(); 77 | let font = font::Font::new(&font_attr); 78 | match font { 79 | None => false, 80 | Some(f) => { 81 | static WM_SETFONT: UINT = 0x0030; 82 | unsafe { 83 | e.send_message(WM_SETFONT, std::mem::transmute(f.font), 0); 84 | } 85 | *self.edit.borrow_mut() = Some(e); 86 | *self.font.borrow_mut() = Some(f); 87 | true 88 | } 89 | } 90 | } 91 | } 92 | } 93 | } 94 | 95 | impl OnSize for MainFrame { 96 | fn on_size(&self, width: isize, height: isize) { 97 | // SWP_NOOWNERZORDER | SWP_NOZORDER 98 | let h = self.text_height; 99 | self.edit.borrow().expect("edit is empty") 100 | .set_window_pos(0, h, width, height - h, 0x200 | 0x4); 101 | } 102 | } 103 | 104 | impl OnDestroy for MainFrame {} 105 | 106 | impl OnPaint for MainFrame { 107 | fn on_paint(&self) { 108 | let font = self.font.borrow(); 109 | let pdc = PaintDc::new(self).expect("Paint DC"); 110 | pdc.dc.select_font(&font.expect("font is empty")); 111 | pdc.dc.text_out(0, 0, self.title.as_ref()); 112 | } 113 | } 114 | 115 | impl OnFocus for MainFrame { 116 | fn on_focus(&self, _w: Window) { 117 | self.edit.borrow().expect("edit is empty").set_focus(); 118 | } 119 | } 120 | 121 | impl OnMessage for MainFrame { 122 | fn on_message(&self, _message: UINT, _wparam: WPARAM, _lparam: LPARAM) -> Option { 123 | match _message { 124 | WM_COMMAND => { 125 | let menu = LOWORD( _wparam as DWORD ); 126 | match menu { 127 | MENU_NEW => { 128 | self.win.message_box( "New document.", "New..." ); 129 | self.edit.borrow().expect("edit is empty") 130 | .set_window_text( "Hello World" ); 131 | }, 132 | MENU_EXIT => { 133 | self.win.send_message( WM_DESTROY, 0, 0 ); 134 | }, 135 | _ => {} 136 | } 137 | }, 138 | 139 | _ => { /* Other messages. */ } 140 | } 141 | 142 | None 143 | } 144 | } 145 | 146 | impl MainFrame { 147 | fn new(instance: Instance, title: String, text_height: isize) -> Option { 148 | let icon = Image::load_resource(instance, IDI_ICON, ImageType::IMAGE_ICON, 0, 0); 149 | let wnd_class = WndClass { 150 | classname: "MainFrame".to_string(), 151 | style: 0x0001 | 0x0002, // CS_HREDRAW | CS_VREDRAW 152 | icon: icon, 153 | icon_small: None, 154 | cursor: Image::load_cursor_resource(32514), // hourglass 155 | background: (5 + 1) as HBRUSH, 156 | menu: MenuResource::MenuId(MENU_MAIN), 157 | cls_extra: 0, 158 | wnd_extra: 0, 159 | }; 160 | let res = wnd_class.register(instance); 161 | if !res { 162 | return None; 163 | } 164 | 165 | let wproc = Box::new(MainFrame { 166 | win: Window::null(), 167 | title: title.clone(), 168 | text_height: text_height, 169 | edit: RefCell::new(None), 170 | font: RefCell::new(None), 171 | }); 172 | 173 | let win_params = WindowParams { 174 | window_name: title, 175 | style: window::WS_OVERLAPPEDWINDOW, 176 | x: 0, 177 | y: 0, 178 | width: 400, 179 | height: 400, 180 | parent: Window::null(), 181 | menu: ptr::null_mut(), 182 | ex_style: 0, 183 | }; 184 | 185 | Window::new(instance, Some(wproc as Box), 186 | wnd_class.classname.as_ref(), &win_params) 187 | } 188 | } 189 | 190 | fn main() { 191 | let instance = Instance::main_instance(); 192 | let main = MainFrame::new(instance, "Hello Rust".to_string(), 20); 193 | let main = main.unwrap(); 194 | 195 | main.show(1); 196 | main.update(); 197 | 198 | let exit_code = main_window_loop(); 199 | //env::set_exit_status(exit_code as i32); 200 | } 201 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /src/window.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Rust-Windows Project Developers. See the 2 | // COPYRIGHT file at the top-level directory of this distribution. 3 | // 4 | // Licensed under the Apache License, Version 2.0 or the MIT license 6 | // , at your 7 | // option. This file may not be copied, modified, or distributed 8 | // except according to those terms. 9 | 10 | use std::ptr; 11 | use std; 12 | use std::cell::RefCell; 13 | use std::rc::Rc; 14 | use std::collections::HashMap; 15 | 16 | use user32; 17 | use winapi::{ 18 | BOOL, CREATESTRUCTW, HBRUSH, HCURSOR, HICON, HMENU, HWND, INT, LPARAM, LRESULT, RECT, UINT, 19 | WNDCLASSEXW, WPARAM, c_int, 20 | }; 21 | 22 | use wchar::{FromCU16Str,ToCU16Str}; 23 | use instance::Instance; 24 | use resource::*; 25 | 26 | pub struct WndClass { 27 | pub classname: String, 28 | pub style: usize, 29 | pub icon: Option, 30 | pub icon_small: Option, 31 | pub cursor: Option, 32 | pub background: HBRUSH, 33 | pub menu: MenuResource, 34 | pub cls_extra: isize, 35 | pub wnd_extra: isize, 36 | } 37 | 38 | impl WndClass { 39 | pub fn register(&self, instance: Instance) -> bool { 40 | self.menu.with_menu_p(|menu_p| { 41 | let clsname_u = self.classname.to_c_u16(); 42 | let wcex = WNDCLASSEXW { 43 | cbSize: std::mem::size_of::() as UINT, 44 | style: self.style as UINT, 45 | lpfnWndProc: Some(main_wnd_proc), 46 | cbClsExtra: self.cls_extra as INT, 47 | cbWndExtra: self.wnd_extra as INT, 48 | hInstance: instance.instance, 49 | hIcon: self.icon.to_handle() as HICON, 50 | hCursor: self.cursor.to_handle() as HCURSOR, 51 | hbrBackground: self.background, 52 | lpszMenuName: menu_p, 53 | lpszClassName: clsname_u.as_ptr(), 54 | hIconSm: self.icon_small.to_handle() as HICON, 55 | }; 56 | 57 | let res = unsafe { user32::RegisterClassExW(&wcex) }; 58 | res != 0 59 | }) 60 | } 61 | } 62 | 63 | pub static WS_BORDER: u32 = 0x800000; 64 | pub static WS_CAPTION: u32 = 0xc00000; 65 | pub static WS_CHILD: u32 = 0x40000000; 66 | pub static WS_CHILDWINDOW: u32 = 0x40000000; 67 | pub static WS_CLIPCHILDREN: u32 = 0x2000000; 68 | pub static WS_CLIPSIBLINGS: u32 = 0x4000000; 69 | pub static WS_DISABLED: u32 = 0x8000000; 70 | pub static WS_DLGFRAME: u32 = 0x400000; 71 | pub static WS_GROUP: u32 = 0x20000; 72 | pub static WS_HSCROLL: u32 = 0x100000; 73 | pub static WS_ICONIC: u32 = 0x20000000; 74 | pub static WS_MAXIMIZE: u32 = 0x1000000; 75 | pub static WS_MAXIMIZEBOX: u32 = 0x10000; 76 | pub static WS_MINIMIZE: u32 = 0x20000000; 77 | pub static WS_MINIMIZEBOX: u32 = 0x20000; 78 | pub static WS_OVERLAPPED: u32 = 0; 79 | pub static WS_OVERLAPPEDWINDOW: u32 = 0xcf0000; 80 | pub static WS_POPUP: u32 = 0x80000000; 81 | pub static WS_POPUPWINDOW: u32 = 0x80880000; 82 | pub static WS_SIZEBOX: u32 = 0x40000; 83 | pub static WS_SYSMENU: u32 = 0x80000; 84 | pub static WS_TABSTOP: u32 = 0x10000; 85 | pub static WS_THICKFRAME: u32 = 0x40000; 86 | pub static WS_TILED: u32 = 0; 87 | pub static WS_TILEDWINDOW: u32 = 0xcf0000; 88 | pub static WS_VISIBLE: u32 = 0x10000000; 89 | pub static WS_VSCROLL: u32 = 0x200000; 90 | 91 | pub static ES_AUTOHSCROLL: u32 = 128; 92 | pub static ES_AUTOVSCROLL: u32 = 64; 93 | pub static ES_CENTER: u32 = 1; 94 | pub static ES_LEFT: u32 = 0; 95 | pub static ES_LOWERCASE: u32 = 16; 96 | pub static ES_MULTILINE: u32 = 4; 97 | pub static ES_NOHIDESEL: u32 = 256; 98 | pub static ES_NUMBER: u32 = 0x2000; 99 | pub static ES_OEMCONVERT: u32 = 0x400; 100 | pub static ES_PASSWORD: u32 = 32; 101 | pub static ES_READONLY: u32 = 0x800; 102 | pub static ES_RIGHT: u32 = 2; 103 | pub static ES_UPPERCASE: u32 = 8; 104 | pub static ES_WANTRETURN: u32 = 4096; 105 | 106 | pub struct WindowParams { 107 | pub window_name: String, 108 | pub style: u32, 109 | pub x: isize, 110 | pub y: isize, 111 | pub width: isize, 112 | pub height: isize, 113 | pub parent: Window, 114 | pub menu: HMENU, 115 | pub ex_style: u32, 116 | } 117 | 118 | #[derive(PartialEq, Eq, Hash, Copy)] 119 | pub struct Window { 120 | pub wnd: HWND, 121 | } 122 | 123 | // Sending across threads allows, for example, a worker thread to communicate 124 | // with a UI thread via PostMessage. 125 | unsafe impl Send for Window {} 126 | 127 | impl Clone for Window { 128 | fn clone(&self) -> Window { 129 | Window { 130 | wnd: self.wnd, 131 | } 132 | } 133 | } 134 | 135 | impl Window { 136 | pub fn null() -> Window { 137 | Window { 138 | wnd: ptr::null_mut(), 139 | } 140 | } 141 | 142 | pub fn new( 143 | instance: Instance, wproc: Option>, classname: &str, params: &WindowParams 144 | ) -> Option { 145 | KEY_INIT_WND.with(move |f| *f.borrow_mut() = wproc); 146 | 147 | let wnd = unsafe { 148 | let clsname_u = classname.to_c_u16(); 149 | let title_u = params.window_name.to_c_u16(); 150 | let wnd = user32::CreateWindowExW( 151 | params.ex_style, clsname_u.as_ptr(), title_u.as_ptr(), params.style, 152 | params.x as c_int, params.y as c_int, 153 | params.width as c_int, params.height as c_int, 154 | params.parent.wnd, params.menu, instance.instance, 155 | ptr::null_mut() 156 | ); 157 | wnd 158 | }; 159 | 160 | if wnd != ptr::null_mut() { 161 | Some(Window { wnd: wnd }) 162 | } else { 163 | None 164 | } 165 | } 166 | 167 | pub fn show(&self, cmd_show: isize) -> bool { 168 | unsafe { user32::ShowWindow(self.wnd, cmd_show as c_int) == 0 } 169 | } 170 | 171 | pub fn show_async(&self, cmd_show: isize) -> bool { 172 | unsafe { user32::ShowWindowAsync(self.wnd, cmd_show as c_int) == 0 } 173 | } 174 | 175 | pub fn update(&self) -> bool { 176 | unsafe { user32::UpdateWindow(self.wnd) == 0 } 177 | } 178 | 179 | pub fn client_rect(&self) -> Option { 180 | let mut rect = RECT { 181 | left: 0, 182 | top: 0, 183 | right: 0, 184 | bottom: 0, 185 | }; 186 | let res = unsafe { 187 | user32::GetClientRect(self.wnd, &mut rect as *mut RECT) 188 | } != 0; 189 | match res { 190 | true => Some(rect), 191 | false => None, 192 | } 193 | } 194 | 195 | pub fn set_window_pos( 196 | &self, x: isize, y: isize, width: isize, height: isize, flags: UINT 197 | ) -> bool { 198 | // TODO: hwndInsertAfter 199 | unsafe { 200 | user32::SetWindowPos( 201 | self.wnd, ptr::null_mut(), x as c_int, y as c_int, 202 | width as c_int, height as c_int, flags 203 | ) != 0 204 | } 205 | } 206 | 207 | pub fn set_focus(&self) -> Window { 208 | unsafe { 209 | Window { 210 | wnd: user32::SetFocus(self.wnd) 211 | } 212 | } 213 | } 214 | 215 | pub fn send_message(&self, msg: UINT, wparam: WPARAM, lparam: LPARAM) -> LRESULT { 216 | unsafe { 217 | user32::SendMessageW(self.wnd, msg, wparam, lparam) 218 | } 219 | } 220 | 221 | pub fn post_message(&self, msg: UINT, wparam: WPARAM, lparam: LPARAM) -> bool { 222 | 1 == unsafe { 223 | user32::PostMessageW(self.wnd, msg, wparam, lparam) 224 | } 225 | } 226 | 227 | pub fn invalidate_rect(&self, rect: RECT, erase: bool) -> bool { 228 | 1 == unsafe { 229 | user32::InvalidateRect(self.wnd, &rect, erase as BOOL) 230 | } 231 | } 232 | 233 | pub fn invalidate(&self, erase: bool) -> bool { 234 | 1 == unsafe { 235 | user32::InvalidateRect(self.wnd, ptr::null(), erase as BOOL) 236 | } 237 | } 238 | 239 | pub fn get_window_text(&self) -> String { 240 | unsafe { 241 | let len = user32::GetWindowTextLengthW(self.wnd); 242 | let mut buf = vec![ 0u16; (len+1) as usize ]; 243 | 244 | let read = user32::GetWindowTextW(self.wnd, buf.as_mut_ptr(), (len+1) ); 245 | if read == len { 246 | match String::from_c_u16(&buf) { 247 | None => String::new(), 248 | Some(s) => s 249 | } 250 | } else { 251 | String::new() 252 | } 253 | } 254 | } 255 | 256 | pub fn set_window_text(&self, text: &str ) -> bool { 257 | let text_u = text.to_c_u16(); 258 | 1 == unsafe { 259 | user32::SetWindowTextW(self.wnd, text_u.as_ptr()) 260 | } 261 | } 262 | } 263 | 264 | pub trait WindowImpl { 265 | fn wnd<'a>(&'a self) -> &'a Window; 266 | fn wnd_mut<'a>(&'a mut self) -> &'a mut Window; 267 | fn wnd_proc(&self, msg: UINT, w: WPARAM, l: LPARAM) -> LRESULT; 268 | } 269 | 270 | /// A thread-local global map from windows to the above WindowImpl trait object 271 | /// RefCell is necessary for mutability. 272 | /// Rc is necessary so multiple main_wnd_procs on the same stack can reference it at once. 273 | /// Box is necessary because WindowImpl is unsized, so can't be Rc'ed directly. 274 | thread_local!(static KEY_WIN_MAP: RefCell>>> = RefCell::new(HashMap::new())); 275 | 276 | /// A thread-local global pointing to the initial window 277 | thread_local!(static KEY_INIT_WND: RefCell>> = RefCell::new(None)); 278 | 279 | fn associate_window_impl(win: Window, wnd_impl: Box) { 280 | KEY_WIN_MAP.with(move |wmap_cell| { 281 | let mut wmap = wmap_cell.borrow_mut(); 282 | wmap.insert(win, Rc::new(wnd_impl)); 283 | }); 284 | } 285 | 286 | fn promote_init_wnd(win: Window) { 287 | KEY_INIT_WND.with(move |maybe_initial_cell| { 288 | let mut maybe_initial = maybe_initial_cell.borrow_mut(); 289 | if let Some(mut wnd_impl) = maybe_initial.take() { 290 | wnd_impl.wnd_mut().wnd = win.wnd; 291 | associate_window_impl(win, wnd_impl); 292 | } 293 | }); 294 | } 295 | 296 | fn lookup_wnd_impl(wnd: HWND) -> Option>> { 297 | KEY_WIN_MAP.with(|wmap_cell| { 298 | if let Some(wnd_impl) = wmap_cell.borrow().get(&Window{wnd: wnd}) { 299 | return Some(wnd_impl.clone()); 300 | } 301 | return None; 302 | }) 303 | } 304 | 305 | pub unsafe extern "system" fn main_wnd_proc(wnd: HWND, 306 | msg: UINT, 307 | w: WPARAM, 308 | l: LPARAM) -> LRESULT { 309 | promote_init_wnd(Window { wnd: wnd }); 310 | 311 | if let Some(wnd_impl) = lookup_wnd_impl(wnd) { 312 | wnd_impl.wnd_proc(msg, w, l) 313 | } else { 314 | super::def_window_proc(wnd, msg, w, l) 315 | } 316 | } 317 | 318 | 319 | pub trait OnCreate { 320 | fn on_create(&self, _cs: &CREATESTRUCTW) -> bool { 321 | true 322 | } 323 | } 324 | 325 | pub trait OnDestroy { 326 | fn on_destroy(&self) { 327 | unsafe { 328 | user32::PostQuitMessage(0 as c_int); 329 | } 330 | } 331 | } 332 | 333 | pub trait OnPaint { 334 | fn on_paint(&self) { 335 | } 336 | } 337 | 338 | pub trait OnSize { 339 | fn on_size(&self, _width: isize, _height: isize) { 340 | } 341 | } 342 | 343 | pub trait OnFocus { 344 | fn on_focus(&self, _prev: Window) { 345 | } 346 | } 347 | 348 | pub trait OnLeftButtonDown { 349 | fn on_left_button_down(&self, _x: isize, _y: isize, _flags: u32) { 350 | } 351 | } 352 | 353 | pub trait OnLeftButtonUp { 354 | fn on_left_button_up(&self, _x: isize, _y: isize, _flags: u32) { 355 | } 356 | } 357 | 358 | pub trait OnKeyDown { 359 | fn on_key_down(&self, _keycode: u8, _flags: u32) -> bool { 360 | return false; 361 | } 362 | } 363 | 364 | pub trait OnKeyUp { 365 | fn on_key_up(&self, _keycode: u8, _flags: u32) -> bool { 366 | return false; 367 | } 368 | } 369 | 370 | pub trait OnEraseBackground { 371 | fn on_erase_background(&self) -> bool { 372 | false 373 | } 374 | } 375 | 376 | pub trait OnMessage { 377 | fn on_message(&self, _message: UINT, _wparam: WPARAM, _lparam: LPARAM) -> Option { 378 | None 379 | } 380 | } 381 | --------------------------------------------------------------------------------