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
use core::{From, Surface};
use core::compositor::{Compositor, Region};
use core::output::OutputTransform;
use core::shm::Buffer;
use core::ids::{SurfaceId, wrap_surface_id};

use ffi::interfaces::compositor::wl_compositor_create_surface;
use ffi::interfaces::surface::{wl_surface, wl_surface_destroy, wl_surface_attach,
                               wl_surface_commit, wl_surface_damage,
                               wl_surface_set_opaque_region,
                               wl_surface_set_input_region,
                               wl_surface_set_buffer_transform,
                               wl_surface_set_buffer_scale};
use ffi::FFI;

/// A wayland Surface.
///
/// This is the basic drawing surface. A surface needs to be assigned
/// a role and a buffer to be properly drawn on screen.
pub struct WSurface {
    _compositor: Compositor,
    ptr: *mut wl_surface
}

// WSurface is self owned
unsafe impl Send for WSurface {}
// The wayland library guaranties this.
unsafe impl Sync for WSurface {}

impl WSurface {
    /// Attaches given buffer to be the content of the image.
    ///
    /// The buffer is by the server to display it. If the content of the buffer
    /// change, it should be notified to the server by using the `Surface::damage(..)`
    /// method.
    ///
    /// If the attached buffer is destroyed while still in use, the content of the
    /// window becomes undefined.
    ///
    /// All coordinates are computed relative to the top-left corder of the buffer.
    ///
    /// This state is double-buffered, and require a call to `Surface::commit()` to
    /// be applied.
    pub fn attach(&self, buffer: &Buffer, x: i32, y: i32) {
        unsafe { wl_surface_attach(self.ptr, buffer.ptr_mut(), x, y) }
    }

    /// Commit the changes to the server.
    ///
    /// Atomically apply all the pending changes on this surface, on the order in which
    /// they were requested.
    pub fn commit(&self) {
        unsafe { wl_surface_commit(self.ptr) }
    }

    /// Mark part of this surface as damaged.
    ///
    /// Damaged area will be repainted by the server. This can be used to
    /// notify the server about a change in the buffer contents.
    ///
    /// (x, y) are he coordinate of the top-left corner.
    ///
    /// This state is double-buffered, and require a call to `Surface::commit()` to
    /// be applied.
    pub fn damage(&self, x:i32, y:i32, width: i32, height: i32) {
        unsafe { wl_surface_damage(self.ptr, x, y, width, height) }
    }

    /// Returns the unique `SurfaceId` associated to this surface.
    ///
    /// This struct can be tested for equality, and will be provided in event callbacks
    /// as a mean to identify the surface associated with the events.
    pub fn get_id(&self) -> SurfaceId {
        wrap_surface_id(self.ptr as usize)
    }

    /// Sets the opaque region of this surface.
    ///
    /// Marking part of a region as opaque allow the compositer to make optimisations
    /// on the drawing process (a window behind an opaque region does not need to be
    /// drawn).
    ///
    /// Marking as opaque a region that is actually transparent in the buffer data
    /// can cause drawing artifacts.
    ///
    /// By default the surface is marked as fully transparent.
    ///
    /// This state is double-buffered, and require a call to `Surface::commit()` to
    /// be applied.
    pub fn set_opaque_region(&self, region: &Region) {
        unsafe { wl_surface_set_opaque_region(self.ptr, region.ptr_mut()) }
    }

    /// Sets the input region of this surface.
    ///
    /// By default the surface has no input region.
    ///
    /// This state is double-buffered, and require a call to `Surface::commit()` to
    /// be applied.
    pub fn set_input_region(&self, region: &Region) {
        unsafe { wl_surface_set_input_region(self.ptr, region.ptr_mut()) }
    }

    /// Sets the transformation the server will apply to the buffer.
    ///
    /// The default value is `OutputTransform::WL_OUTPUT_TRANSFORM_NORMAL`.
    ///
    /// This state is double-buffered, and require a call to `Surface::commit()` to
    /// be applied.
    pub fn set_buffer_transform(&self, transform: OutputTransform) {
        unsafe { wl_surface_set_buffer_transform(self.ptr, transform as i32) }
    }

    /// Sets the scale the server will apply to the buffer.
    ///
    /// The drawed data will be of dimensions `(width/scale, height/scale)`.
    ///
    /// Scale must be positive or will be refused by the server.
    ///
    /// This state is double-buffered, and require a call to `Surface::commit()` to
    /// be applied.
    pub fn set_buffer_scale(&self, scale: i32) {
        unsafe { wl_surface_set_buffer_scale(self.ptr, scale) }
    }
}

impl From<Compositor> for WSurface {
    fn from(compositor: Compositor) -> WSurface {
        let ptr = unsafe { wl_compositor_create_surface(compositor.ptr_mut()) };
        WSurface {
            _compositor: compositor,
            ptr: ptr
        }
    }
}

impl Drop for WSurface {
    fn drop(&mut self) {
        unsafe { wl_surface_destroy(self.ptr) };
    }
}

impl FFI for WSurface {
    type Ptr = wl_surface;

    fn ptr(&self) -> *const wl_surface {
        self.ptr as *const wl_surface
    }

    unsafe fn ptr_mut(&self) -> *mut wl_surface {
        self.ptr
    }
}

impl Surface for WSurface {
    fn get_wsurface(&self) -> &WSurface {
        self
    }
}