/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! GDI helpers.

use windows_sys::Win32::{
    Foundation::HWND,
    Graphics::Gdi::{self, GDI_ERROR, HDC, HGDIOBJ},
};

/// A GDI drawing context.
pub struct DC {
    hwnd: HWND,
    hdc: HDC,
}

impl DC {
    /// Create a new DC.
    pub fn new(hwnd: HWND) -> Option<Self> {
        let hdc = unsafe { Gdi::GetDC(hwnd) };
        (!hdc.is_null()).then_some(DC { hwnd, hdc })
    }

    /// Call the given function with a gdi object selected.
    pub fn with_object_selected<R>(&self, object: HGDIOBJ, f: impl FnOnce(HDC) -> R) -> Option<R> {
        let old_object = unsafe { Gdi::SelectObject(self.hdc, object) };
        if old_object.is_null() || old_object == GDI_ERROR as HGDIOBJ {
            return None;
        }
        let ret = f(self.hdc);
        // The prior object must be selected before releasing the DC. Ignore errors; this is
        // best-effort.
        unsafe { Gdi::SelectObject(self.hdc, old_object) };
        Some(ret)
    }
}

impl Drop for DC {
    fn drop(&mut self) {
        unsafe { Gdi::ReleaseDC(self.hwnd, self.hdc) };
    }
}
