bc286f77c64c9b5903beebb195f8ef2155071ad3
[platform/core/uifw/libds-tizen.git] / src / libds / output.c
1 #include <assert.h>
2 #include <stdlib.h>
3
4 #include "libds/log.h"
5 #include "libds/output.h"
6 #include "libds/interfaces/output.h"
7
8 static void output_handle_display_destroy(struct wl_listener *listener,
9         void *data);
10 static void output_enable(struct ds_output *output, bool enable);
11 static void output_state_clear(struct ds_output_state *state);
12 static void output_state_clear_buffer(struct ds_output_state *state);
13
14 WL_EXPORT void
15 ds_output_init(struct ds_output *output, struct ds_backend *backend,
16         const struct ds_output_interface *iface, struct wl_display *display)
17 {
18     assert(iface->commit);
19
20     output->backend = backend;
21     output->iface = iface;
22     output->display = display;
23
24     wl_list_init(&output->modes);
25
26     wl_signal_init(&output->events.destroy);
27     wl_signal_init(&output->events.frame);
28     wl_signal_init(&output->events.commit);
29
30     output->display_destroy.notify = output_handle_display_destroy;
31     wl_display_add_destroy_listener(display, &output->display_destroy);
32 }
33
34 WL_EXPORT void
35 ds_output_destroy(struct ds_output *output)
36 {
37     wl_list_remove(&output->display_destroy.link);
38
39     wl_signal_emit(&output->events.destroy, output);
40
41     if (output->iface && output->iface->destroy)
42         output->iface->destroy(output);
43     else
44         free(output);
45 }
46
47 void
48 ds_output_enable(struct ds_output *output)
49 {
50     output_enable(output, true);
51 }
52
53 void
54 ds_output_disable(struct ds_output *output)
55 {
56     output_enable(output, false);
57 }
58
59 WL_EXPORT bool
60 ds_output_commit(struct ds_output *output)
61 {
62     // TODO signal precommit
63
64     if (!output->iface->commit(output)) {
65         return false;
66     }
67
68     output_state_clear(&output->pending);
69
70     // TODO signal commit
71
72     return true;
73 }
74
75 WL_EXPORT void
76 ds_output_attach_buffer(struct ds_output *output, struct ds_buffer *buffer)
77 {
78     output_state_clear_buffer(&output->pending);
79     output->pending.committed |= DS_OUTPUT_STATE_BUFFER;
80     output->pending.buffer = ds_buffer_lock(buffer);
81 }
82
83 WL_EXPORT const struct ds_output_mode *
84 ds_output_get_preferred_mode(struct ds_output *output)
85 {
86     struct ds_output_mode *mode;
87
88     if (wl_list_empty(&output->modes))
89         return NULL;
90
91     wl_list_for_each(mode, &output->modes, link) {
92         if (mode->preferred)
93             return mode;
94     }
95
96     // No preferred mode, choose the first one
97     return wl_container_of(output->modes.next, mode, link);
98 }
99
100 WL_EXPORT void
101 ds_output_set_mode(struct ds_output *output, const struct ds_output_mode *mode)
102 {
103     output->pending.mode = NULL;
104     output->pending.committed &= ~DS_OUTPUT_STATE_MODE;
105
106     if (output->current_mode == mode) {
107         return;
108     }
109
110     output->pending.committed |= DS_OUTPUT_STATE_MODE;
111     output->pending.mode = mode;
112 }
113
114 WL_EXPORT void
115 ds_output_add_destroy_listener(struct ds_output *output,
116         struct wl_listener *listener)
117 {
118     wl_signal_add(&output->events.destroy, listener);
119 }
120
121 WL_EXPORT void
122 ds_output_add_frame_listener(struct ds_output *output,
123         struct wl_listener *listener)
124 {
125     wl_signal_add(&output->events.frame, listener);
126 }
127
128 WL_EXPORT void
129 ds_output_add_commit_listener(struct ds_output *output,
130         struct wl_listener *listener)
131 {
132     wl_signal_add(&output->events.commit, listener);
133 }
134
135 static void
136 output_handle_display_destroy(struct wl_listener *listener, void *data)
137 {
138     struct ds_output *output;
139
140     output = wl_container_of(listener, output, display_destroy);
141     // TODO
142     // destroy wl_global
143 }
144
145 static void
146 output_state_clear(struct ds_output_state *state)
147 {
148     output_state_clear_buffer(state);
149     state->committed = 0;
150 }
151
152 static void
153 output_state_clear_buffer(struct ds_output_state *state)
154 {
155     if (!(state->committed & DS_OUTPUT_STATE_BUFFER))
156         return;
157
158     ds_buffer_unlock(state->buffer);
159     state->buffer = NULL;
160
161     state->committed &= ~DS_OUTPUT_STATE_BUFFER;
162 }
163
164 static void
165 output_enable(struct ds_output *output, bool enable)
166 {
167     if (output->enabled == enable) {
168         output->pending.committed &= ~DS_OUTPUT_STATE_ENABLED;
169         return;
170     }
171
172     output->pending.committed |= DS_OUTPUT_STATE_ENABLED;
173     output->pending.enabled = enable;
174 }