diff --git a/ctru-rs/Cargo.toml b/ctru-rs/Cargo.toml
index f33e177..29323b4 100644
--- a/ctru-rs/Cargo.toml
+++ b/ctru-rs/Cargo.toml
@@ -18,3 +18,6 @@ pthread-3ds = { git = "https://github.com/Meziu/pthread-3ds.git" }
 libc = { git = "https://github.com/Meziu/libc.git" }
 bitflags = "1.0.0"
 widestring = "0.2.2"
+
+[dev-dependencies]
+ferris-says = "0.2.1"
diff --git a/ctru-rs/examples/buttons.rs b/ctru-rs/examples/buttons.rs
index 36127cd..152ede6 100644
--- a/ctru-rs/examples/buttons.rs
+++ b/ctru-rs/examples/buttons.rs
@@ -1,5 +1,5 @@
 use ctru::console::Console;
-use ctru::gfx::{Gfx, Screen};
+use ctru::gfx::Gfx;
 use ctru::services::apt::Apt;
 use ctru::services::hid::{Hid, KeyPad};
 
@@ -9,7 +9,7 @@ fn main() {
     let apt = Apt::init().unwrap();
     let hid = Hid::init().unwrap();
     let gfx = Gfx::default();
-    let console = Console::init(&gfx, Screen::Top);
+    let console = Console::init(gfx.top_screen.borrow_mut());
 
     println!("Hi there! Try pressing a button");
     println!("\x1b[29;16HPress Start to exit");
diff --git a/ctru-rs/examples/gfx_wide_mode.rs b/ctru-rs/examples/gfx-wide-mode.rs
similarity index 62%
rename from ctru-rs/examples/gfx_wide_mode.rs
rename to ctru-rs/examples/gfx-wide-mode.rs
index f4ba365..fcf3fa9 100644
--- a/ctru-rs/examples/gfx_wide_mode.rs
+++ b/ctru-rs/examples/gfx-wide-mode.rs
@@ -1,7 +1,4 @@
-extern crate ctru;
-
 use ctru::console::Console;
-use ctru::gfx::Screen;
 use ctru::services::hid::KeyPad;
 use ctru::services::{Apt, Hid};
 use ctru::Gfx;
@@ -11,7 +8,7 @@ fn main() {
     let apt = Apt::init().unwrap();
     let hid = Hid::init().unwrap();
     let gfx = Gfx::default();
-    let _console = Console::init(&gfx, Screen::Top);
+    let mut console = Console::init(gfx.top_screen.borrow_mut());
 
     println!("Press A to enable/disable wide screen mode.");
 
@@ -23,7 +20,13 @@ fn main() {
         }
 
         if hid.keys_down().contains(KeyPad::KEY_A) {
-            gfx.set_wide_mode(!gfx.get_wide_mode());
+            drop(console);
+
+            let wide_mode = gfx.top_screen.borrow().get_wide_mode();
+            gfx.top_screen.borrow_mut().set_wide_mode(!wide_mode);
+
+            console = Console::init(gfx.top_screen.borrow_mut());
+            println!("Press A to enable/disable wide screen mode.");
         }
 
         gfx.flush_buffers();
diff --git a/ctru-rs/examples/hello-both-screens.rs b/ctru-rs/examples/hello-both-screens.rs
index 180b1b2..67113a3 100644
--- a/ctru-rs/examples/hello-both-screens.rs
+++ b/ctru-rs/examples/hello-both-screens.rs
@@ -1,5 +1,5 @@
 use ctru::console::Console;
-use ctru::gfx::{Gfx, Screen};
+use ctru::gfx::Gfx;
 use ctru::services::apt::Apt;
 use ctru::services::hid::{Hid, KeyPad};
 
@@ -11,11 +11,11 @@ fn main() {
     let gfx = Gfx::default();
 
     // Start a console on the top screen
-    let top_screen = Console::init(&gfx, Screen::Top);
+    let top_screen = Console::init(gfx.top_screen.borrow_mut());
 
     // Start a console on the bottom screen.
     // The most recently initialized console will be active by default
-    let bottom_screen = Console::init(&gfx, Screen::Bottom);
+    let bottom_screen = Console::init(gfx.bottom_screen.borrow_mut());
 
     // Let's print on the top screen first
     top_screen.select();
diff --git a/ctru-rs/examples/hello-world.rs b/ctru-rs/examples/hello-world.rs
index ccebef7..930549f 100644
--- a/ctru-rs/examples/hello-world.rs
+++ b/ctru-rs/examples/hello-world.rs
@@ -1,56 +1,41 @@
 use ctru::console::Console;
-use ctru::gfx::{Gfx, Screen};
+use ctru::gfx::Gfx;
 use ctru::services::apt::Apt;
 use ctru::services::hid::{Hid, KeyPad};
 
+use std::io::BufWriter;
+
 fn main() {
-    // Initialize ctrulib service handles.
-    // Service handles are internally reference-counted. When all instances of a
-    // service handle go out of scope, the service will be closed.
     ctru::init();
-
-    // The APT service handles application management functions, such as enabling sleep
-    // mode and jumping to the home menu or to other applications
-    let apt = Apt::init().unwrap();
-
-    // The HID service handles button and touch screen inputs.
-    let hid = Hid::init().unwrap();
-
-    // The GFX service manages the framebuffers for the top and bottom screens.
     let gfx = Gfx::default();
+    let hid = Hid::init().expect("Couldn't obtain HID controller");
+    let apt = Apt::init().expect("Couldn't obtain APT controller");
+    let _console = Console::init(gfx.top_screen.borrow_mut());
 
-    // Initialize a ctrulib console and direct standard output to it.
-    // Consoles can be initialized on both the top and bottom screens.
-    let _console = Console::init(&gfx, Screen::Top);
+    let out = b"Hello fellow Rustaceans, I'm on the Nintendo 3DS!";
+    let width = 24;
 
-    // Now we can print to stdout!
-    println!("Hello, world!");
+    let mut writer = BufWriter::new(Vec::new());
+    ferris_says::say(out, width, &mut writer).unwrap();
 
-    // We can use escape sequences to move the cursor around the terminal.
-    // The following text will be moved down 29 rows and right 16 characters
-    // before printing begins.
-    println!("\x1b[29;16HPress Start to exit");
+    println!(
+        "\x1b[0;0H{}",
+        String::from_utf8_lossy(&writer.into_inner().unwrap())
+    );
 
-    // Main application loop.
+    // Main loop
     while apt.main_loop() {
-        // Flushes and swaps the framebuffers when double-buffering
-        // is enabled
-        gfx.flush_buffers();
-        gfx.swap_buffers();
-
-        // Wait for the next frame to begin
-        gfx.wait_for_vblank();
-
-        // Scan for user input.
+        //Scan all the inputs. This should be done once for each frame
         hid.scan_input();
 
-        // Check if the user has pressed the given button on this frame.
-        // If so, break out of the loop.
         if hid.keys_down().contains(KeyPad::KEY_START) {
             break;
         }
-    }
+        // Flush and swap framebuffers
+        gfx.flush_buffers();
+        gfx.swap_buffers();
 
-    // All of our service handles will drop out of scope at this point,
-    // triggering the end of our application.
+        //Wait for VBlank
+        gfx.wait_for_vblank();
+    }
 }
diff --git a/ctru-rs/examples/network-sockets.rs b/ctru-rs/examples/network-sockets.rs
new file mode 100644
index 0000000..84978e9
--- /dev/null
+++ b/ctru-rs/examples/network-sockets.rs
@@ -0,0 +1,65 @@
+use ctru::console::Console;
+use ctru::gfx::Gfx;
+use ctru::services::apt::Apt;
+use ctru::services::hid::{Hid, KeyPad};
+use ctru::services::soc::Soc;
+
+use std::io::{Read, Write};
+use std::net::{Shutdown, TcpListener};
+use std::time::Duration;
+
+fn main() {
+    ctru::init();
+    let gfx = Gfx::default();
+    let _console = Console::init(gfx.top_screen.borrow_mut());
+    let hid = Hid::init().unwrap();
+    let apt = Apt::init().unwrap();
+
+    println!("\nlibctru sockets demo\n");
+
+    let soc = Soc::init().unwrap();
+
+    let server = TcpListener::bind("0.0.0.0:80").unwrap();
+    server.set_nonblocking(true).unwrap();
+
+    println!("Point your browser to http://{}/\n", soc.host_address());
+
+    while apt.main_loop() {
+        gfx.wait_for_vblank();
+
+        match server.accept() {
+            Ok((mut stream, socket_addr)) => {
+                println!("Got connection from {}", socket_addr);
+
+                let mut buf = [0u8; 4096];
+                match stream.read(&mut buf) {
+                    Ok(_) => {
+                        let req_str = String::from_utf8_lossy(&buf);
+                        println!("{}", req_str);
+                    }
+                    Err(e) => println!("Unable to read stream: {}", e),
+                }
+
+                let response = b"HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n<html><body>Hello world</body></html>\r\n";
+
+                if let Err(e) = stream.write(response) {
+                    println!("Error writing http response: {}", e);
+                }
+
+                stream.shutdown(Shutdown::Both).unwrap();
+            }
+            Err(e) => match e.kind() {
+                std::io::ErrorKind::WouldBlock => {}
+                _ => {
+                    println!("Error accepting connection: {}", e);
+                    std::thread::sleep(Duration::from_secs(2));
+                }
+            },
+        }
+
+        hid.scan_input();
+        if hid.keys_down().contains(KeyPad::KEY_START) {
+            break;
+        };
+    }
+}
diff --git a/ctru-rs/examples/software-keyboard.rs b/ctru-rs/examples/software-keyboard.rs
index b3b9347..6be9e81 100644
--- a/ctru-rs/examples/software-keyboard.rs
+++ b/ctru-rs/examples/software-keyboard.rs
@@ -1,6 +1,6 @@
 use ctru::applets::swkbd::{Button, Swkbd};
 use ctru::console::Console;
-use ctru::gfx::{Gfx, Screen};
+use ctru::gfx::Gfx;
 use ctru::services::apt::Apt;
 use ctru::services::hid::{Hid, KeyPad};
 
@@ -9,7 +9,7 @@ fn main() {
     let apt = Apt::init().unwrap();
     let hid = Hid::init().unwrap();
     let gfx = Gfx::default();
-    let _console = Console::init(&gfx, Screen::Top);
+    let _console = Console::init(gfx.top_screen.borrow_mut());
 
     println!("Press A to enter some text or press Start to quit");
 
diff --git a/ctru-rs/src/console.rs b/ctru-rs/src/console.rs
index 0c86129..2df1495 100644
--- a/ctru-rs/src/console.rs
+++ b/ctru-rs/src/console.rs
@@ -1,28 +1,25 @@
+use std::cell::RefMut;
 use std::default::Default;
-use std::marker::PhantomData;
 
 use ctru_sys::{consoleClear, consoleInit, consoleSelect, consoleSetWindow, PrintConsole};
 
-use crate::gfx::{Gfx, Screen};
+use crate::gfx::Screen;
 
-pub struct Console<'gfx> {
+pub struct Console<'screen> {
     context: Box<PrintConsole>,
-    _gfx: PhantomData<&'gfx ()>,
+    screen: RefMut<'screen, dyn Screen>,
 }
 
-impl<'gfx> Console<'gfx> {
+impl<'screen> Console<'screen> {
     /// Initialize a console on the chosen screen, overwriting whatever was on the screen
     /// previously (including other consoles). The new console is automatically selected for
     /// printing.
-    pub fn init(_gfx: &'gfx Gfx, screen: Screen) -> Self {
+    pub fn init(screen: RefMut<'screen, dyn Screen>) -> Self {
         let mut context = Box::new(PrintConsole::default());
 
-        unsafe { consoleInit(screen.into(), context.as_mut()) };
+        unsafe { consoleInit(screen.as_raw(), context.as_mut()) };
 
-        Console {
-            context,
-            _gfx: PhantomData,
-        }
+        Console { context, screen }
     }
 
     /// Select this console as the current target for stdout
diff --git a/ctru-rs/src/gfx.rs b/ctru-rs/src/gfx.rs
index 8bd4694..1092640 100644
--- a/ctru-rs/src/gfx.rs
+++ b/ctru-rs/src/gfx.rs
@@ -1,25 +1,56 @@
 //! LCD screens manipulation helper
 
+use std::cell::RefCell;
 use std::default::Default;
 use std::ops::Drop;
 
 use crate::services::gspgpu::{self, FramebufferFormat};
 
-/// A handle to libctru's gfx module. This module is a wrapper around the GSPGPU service that
-/// provides helper functions and utilities for software rendering.
-///
-/// The service exits when this struct is dropped.
-pub struct Gfx(());
+/// Trait implemented by TopScreen and BottomScreen for common methods
+pub trait Screen {
+    /// Returns the libctru value for the Screen kind
+    fn as_raw(&self) -> ctru_sys::gfxScreen_t;
 
-/// Available screens on the 3DS
-#[derive(Copy, Clone, Debug)]
-pub enum Screen {
-    /// The top screen
-    Top,
-    /// The bottom screen
-    Bottom,
+    /// Sets whether to use double buffering. Enabled by default.
+    ///
+    /// Note that even when double buffering is disabled, one should still use the `swap_buffers`
+    /// method on each frame to keep the gsp configuration up to date
+    fn set_double_buffering(&mut self, enabled: bool) {
+        unsafe { ctru_sys::gfxSetDoubleBuffering(self.as_raw(), enabled) }
+    }
+
+    /// Gets the framebuffer format
+    fn get_framebuffer_format(&self) -> FramebufferFormat {
+        unsafe { ctru_sys::gfxGetScreenFormat(self.as_raw()).into() }
+    }
+
+    /// Change the framebuffer format
+    fn set_framebuffer_format(&mut self, fmt: FramebufferFormat) {
+        unsafe { ctru_sys::gfxSetScreenFormat(self.as_raw(), fmt.into()) }
+    }
+
+    /// Returns a tuple containing a pointer to the specifified framebuffer (as determined by the
+    /// calling screen and `Side`), the width of the framebuffer in pixels, and the height of
+    /// the framebuffer in pixels
+    ///
+    /// Note that the pointer returned by this function can change after each call to this function
+    /// if double buffering is enabled
+    fn get_raw_framebuffer(&self, side: Side) -> (*mut u8, u16, u16) {
+        let mut width: u16 = 0;
+        let mut height: u16 = 0;
+        unsafe {
+            let buf: *mut u8 =
+                ctru_sys::gfxGetFramebuffer(self.as_raw(), side.into(), &mut width, &mut height);
+            (buf, width, height)
+        }
+    }
 }
 
+#[non_exhaustive]
+pub struct TopScreen;
+#[non_exhaustive]
+pub struct BottomScreen;
+
 #[derive(Copy, Clone, Debug)]
 /// Side of top screen framebuffer
 ///
@@ -31,6 +62,16 @@ pub enum Side {
     Right,
 }
 
+/// A handle to libctru's gfx module. This module is a wrapper around the GSPGPU service that
+/// provides helper functions and utilities for software rendering.
+///
+/// The service exits when this struct is dropped.
+#[non_exhaustive]
+pub struct Gfx {
+    pub top_screen: RefCell<TopScreen>,
+    pub bottom_screen: RefCell<BottomScreen>,
+}
+
 impl Gfx {
     /// Initialize the Gfx module with the chosen framebuffer formats for the top and bottom
     /// screens
@@ -44,32 +85,10 @@ impl Gfx {
         unsafe {
             ctru_sys::gfxInit(top_fb_fmt.into(), bottom_fb_fmt.into(), use_vram_buffers);
         }
-        Gfx(())
-    }
-
-    /// Enable or disable the 3D stereoscopic effect
-    pub fn set_3d_enabled(&self, enabled: bool) {
-        unsafe { ctru_sys::gfxSet3D(enabled) }
-    }
-
-    /// Enable or disable the wide screen mode (top screen).
-    ///
-    /// This only works when 3D is disabled.
-    pub fn set_wide_mode(&self, enabled: bool) {
-        unsafe { ctru_sys::gfxSetWide(enabled) };
-    }
-
-    /// Get the status of wide screen mode.
-    pub fn get_wide_mode(&self) -> bool {
-        unsafe { ctru_sys::gfxIsWide() }
-    }
-
-    /// Sets whether to use double buffering. Enabled by default.
-    ///
-    /// Note that even when double buffering is disabled, one should still use the `swap_buffers`
-    /// method on each frame to keep the gsp configuration up to date
-    pub fn set_double_buffering(&self, screen: Screen, enabled: bool) {
-        unsafe { ctru_sys::gfxSetDoubleBuffering(screen.into(), enabled) }
+        Gfx {
+            top_screen: RefCell::new(TopScreen),
+            bottom_screen: RefCell::new(BottomScreen),
+        }
     }
 
     /// Flushes the current framebuffers
@@ -97,41 +116,39 @@ impl Gfx {
     pub fn wait_for_vblank(&self) {
         gspgpu::wait_for_event(gspgpu::Event::VBlank0, true);
     }
+}
 
-    /// Gets the framebuffer format for a screen
-    pub fn get_framebuffer_format(&self, screen: Screen) -> FramebufferFormat {
-        unsafe { ctru_sys::gfxGetScreenFormat(screen.into()).into() }
-    }
-
-    /// Change the framebuffer format for a screen
-    pub fn set_framebuffer_format(&self, screen: Screen, fmt: FramebufferFormat) {
-        unsafe { ctru_sys::gfxSetScreenFormat(screen.into(), fmt.into()) }
+impl TopScreen {
+    /// Enable or disable the 3D stereoscopic effect
+    pub fn set_3d_enabled(&mut self, enabled: bool) {
+        unsafe {
+            ctru_sys::gfxSet3D(enabled);
+        }
     }
 
-    /// Returns a tuple containing a pointer to the specifified framebuffer (as determined by the
-    /// provided `Screen` and `Side`), the width of the framebuffer in pixels, and the height of
-    /// the framebuffer in pixels
-    ///
-    /// Note that the pointer returned by this function can change after each call to this function
-    /// if double buffering is enabled
-    pub fn get_raw_framebuffer(&self, screen: Screen, side: Side) -> (*mut u8, u16, u16) {
+    /// Enable or disable the wide screen mode (top screen).
+    /// This only works when 3D is disabled.
+    pub fn set_wide_mode(&mut self, enabled: bool) {
         unsafe {
-            let mut width: u16 = 0;
-            let mut height: u16 = 0;
-            let buf: *mut u8 =
-                ctru_sys::gfxGetFramebuffer(screen.into(), side.into(), &mut width, &mut height);
-            (buf, width, height)
+            ctru_sys::gfxSetWide(enabled);
         }
     }
+
+    /// Get the status of wide screen mode.
+    pub fn get_wide_mode(&self) -> bool {
+        unsafe { ctru_sys::gfxIsWide() }
+    }
 }
 
-impl From<Screen> for ctru_sys::gfxScreen_t {
-    fn from(g: Screen) -> ctru_sys::gfxScreen_t {
-        use self::Screen::*;
-        match g {
-            Top => ctru_sys::GFX_TOP,
-            Bottom => ctru_sys::GFX_BOTTOM,
-        }
+impl Screen for TopScreen {
+    fn as_raw(&self) -> ctru_sys::gfxScreen_t {
+        ctru_sys::GFX_TOP
+    }
+}
+
+impl Screen for BottomScreen {
+    fn as_raw(&self) -> ctru_sys::gfxScreen_t {
+        ctru_sys::GFX_BOTTOM
     }
 }
 
@@ -148,7 +165,10 @@ impl From<Side> for ctru_sys::gfx3dSide_t {
 impl Default for Gfx {
     fn default() -> Self {
         unsafe { ctru_sys::gfxInitDefault() };
-        Gfx(())
+        Gfx {
+            top_screen: RefCell::new(TopScreen),
+            bottom_screen: RefCell::new(BottomScreen),
+        }
     }
 }