1 /*
2 * libcaca Colour ASCII-Art library
3 * Copyright (c) 2002-2012 Sam Hocevar <sam@hocevar.net>
4 * All Rights Reserved
5 *
6 * This library is free software. It comes without any warranty, to
7 * the extent permitted by applicable law. You can redistribute it
8 * and/or modify it under the terms of the Do What the Fuck You Want
9 * to Public License, Version 2, as published by Sam Hocevar. See
10 * http://www.wtfpl.net/ for more details.
11 */
12
13 /*
14 * This file contains character and string drawing functions.
15 */
16
17 #include "config.h"
18
19 #if !defined(__KERNEL__)
20 # include <stdio.h>
21 # include <stdlib.h>
22 # include <string.h>
23 #endif
24
25 #include "caca.h"
26 #include "caca_internals.h"
27
28 /** \brief Set the display title.
29 *
30 * If libcaca runs in a window, try to change its title. This works with
31 * the ncurses, S-Lang, OpenGL, X11 and Win32 drivers.
32 *
33 * If an error occurs, -1 is returned and \b errno is set accordingly:
34 * - \c ENOSYS Display driver does not support setting the window title.
35 *
36 * \param dp The libcaca display context.
37 * \param title The desired display title.
38 * \return 0 upon success, -1 if an error occurred.
39 */
caca_set_display_title(caca_display_t * dp,char const * title)40 int caca_set_display_title(caca_display_t *dp, char const *title)
41 {
42 int ret = dp->drv.set_display_title(dp, title);
43
44 if(ret)
45 seterrno(ENOSYS);
46
47 return ret;
48 }
49
50 /** \brief Get the display width.
51 *
52 * If libcaca runs in a window, get the usable window width. This value can
53 * be used for aspect ratio calculation. If libcaca does not run in a window
54 * or if there is no way to know the font size, most drivers will assume a
55 * 6x10 font is being used. Note that the units are not necessarily pixels.
56 *
57 * This function never fails.
58 *
59 * \param dp The libcaca display context.
60 * \return The display width.
61 */
caca_get_display_width(caca_display_t const * dp)62 int caca_get_display_width(caca_display_t const *dp)
63 {
64 return dp->drv.get_display_width(dp);
65 }
66
67 /** \brief Get the display height.
68 *
69 * If libcaca runs in a window, get the usable window height. This value can
70 * be used for aspect ratio calculation. If libcaca does not run in a window
71 * or if there is no way to know the font size, assume a 6x10 font is being
72 * used. Note that the units are not necessarily pixels.
73 *
74 * This function never fails.
75 *
76 * \param dp The libcaca display context.
77 * \return The display height.
78 */
caca_get_display_height(caca_display_t const * dp)79 int caca_get_display_height(caca_display_t const *dp)
80 {
81 return dp->drv.get_display_height(dp);
82 }
83
84 /** \brief Set the refresh delay.
85 *
86 * Set the refresh delay in microseconds. The refresh delay is used by
87 * caca_refresh_display() to achieve constant framerate. See the
88 * caca_refresh_display() documentation for more details.
89 *
90 * If the argument is zero, constant framerate is disabled. This is the
91 * default behaviour.
92 *
93 * If an error occurs, -1 is returned and \b errno is set accordingly:
94 * - \c EINVAL Refresh delay value is invalid.
95 *
96 * \param dp The libcaca display context.
97 * \param usec The refresh delay in microseconds.
98 * \return 0 upon success, -1 if an error occurred.
99 */
caca_set_display_time(caca_display_t * dp,int usec)100 int caca_set_display_time(caca_display_t *dp, int usec)
101 {
102 if(usec < 0)
103 {
104 seterrno(EINVAL);
105 return -1;
106 }
107
108 dp->delay = usec;
109 return 0;
110 }
111
112 /** \brief Get the display's average rendering time.
113 *
114 * Get the average rendering time, which is the average measured time
115 * between two caca_refresh_display() calls, in microseconds. If constant
116 * framerate was activated by calling caca_set_display_time(), the average
117 * rendering time will be close to the requested delay even if the real
118 * rendering time was shorter.
119 *
120 * This function never fails.
121 *
122 * \param dp The libcaca display context.
123 * \return The render time in microseconds.
124 */
caca_get_display_time(caca_display_t const * dp)125 int caca_get_display_time(caca_display_t const *dp)
126 {
127 return dp->rendertime;
128 }
129
130 /** \brief Flush pending changes and redraw the screen.
131 *
132 * Flush all graphical operations and print them to the display device.
133 * Nothing will show on the screen until this function is called.
134 *
135 * If caca_set_display_time() was called with a non-zero value,
136 * caca_refresh_display() will use that value to achieve constant
137 * framerate: if two consecutive calls to caca_refresh_display() are within
138 * a time range shorter than the value set with caca_set_display_time(),
139 * the second call will be delayed before performing the screen refresh.
140 *
141 * This function never fails.
142 *
143 * \param dp The libcaca display context.
144 * \return This function always returns 0.
145 */
caca_refresh_display(caca_display_t * dp)146 int caca_refresh_display(caca_display_t *dp)
147 {
148 #if defined PROF
149 caca_timer_t proftimer = { 0, 0 };
150 #endif
151 #if !defined(_DOXYGEN_SKIP_ME)
152 # define IDLE_USEC 5000
153 #endif
154 int ticks = dp->lastticks + _caca_getticks(&dp->timer);
155
156 #if defined PROF
157 _caca_getticks(&proftimer);
158 #endif
159 dp->drv.display(dp);
160 #if defined PROF
161 STAT_IADD(&dp->display_stat, _caca_getticks(&proftimer));
162 #endif
163
164 /* Invalidate the dirty rectangle */
165 caca_clear_dirty_rect_list(dp->cv);
166
167 /* Once the display is finished, we can ack resizes */
168 if(dp->resize.resized)
169 {
170 dp->resize.resized = 0;
171 _caca_handle_resize(dp);
172 }
173
174 #if defined PROF
175 _caca_getticks(&proftimer);
176 #endif
177 /* Wait until dp->delay + time of last call */
178 ticks += _caca_getticks(&dp->timer);
179 for(ticks += _caca_getticks(&dp->timer);
180 ticks + IDLE_USEC < (int)dp->delay;
181 ticks += _caca_getticks(&dp->timer))
182 {
183 _caca_sleep(IDLE_USEC);
184 }
185 #if defined PROF
186 STAT_IADD(&dp->wait_stat, _caca_getticks(&proftimer));
187 #endif
188
189 /* Update the render time */
190 dp->rendertime = ticks;
191
192 dp->lastticks = ticks - dp->delay;
193
194 /* If we drifted too much, it's bad, bad, bad. */
195 if(dp->lastticks > (int)dp->delay)
196 dp->lastticks = 0;
197
198 #if defined PROF
199 _caca_dump_stats();
200 #endif
201
202 return 0;
203 }
204
205 /** \brief Show or hide the cursor.
206 *
207 * Show or hide the cursor, for devices that support such a feature.
208 *
209 * If an error occurs, -1 is returned and \b errno is set accordingly:
210 * - \c ENOSYS Display driver does not support showing the cursor.
211 *
212 * \param dp The libcaca display context.
213 * \param flag 0 hides the cursor, 1 shows the system's default cursor
214 * (usually a white rectangle). Other values are reserved for
215 * future use.
216 * \return 0 upon success, -1 if an error occurred.
217 */
caca_set_cursor(caca_display_t * dp,int flag)218 int caca_set_cursor(caca_display_t *dp, int flag)
219 {
220 if(!dp->drv.set_cursor)
221 {
222 seterrno(ENOSYS);
223 return -1;
224 }
225
226 dp->drv.set_cursor(dp, flag);
227 return 0;
228 }
229
230 /** \brief Show or hide the mouse pointer.
231 *
232 * Show or hide the mouse pointer. This function works with the ncurses,
233 * S-Lang and X11 drivers.
234 *
235 * If an error occurs, -1 is returned and \b errno is set accordingly:
236 * - \c ENOSYS Display driver does not support hiding the mouse pointer.
237 *
238 * \param dp The libcaca display context.
239 * \param flag 0 hides the pointer, 1 shows the system's default pointer
240 * (usually an arrow). Other values are reserved for future use.
241 * \return 0 upon success, -1 if an error occurred.
242 */
caca_set_mouse(caca_display_t * dp,int flag)243 int caca_set_mouse(caca_display_t *dp, int flag)
244 {
245 if(!dp->drv.set_mouse)
246 {
247 seterrno(ENOSYS);
248 return -1;
249 }
250
251 dp->drv.set_mouse(dp, flag);
252 return 0;
253 }
254
255 /*
256 * XXX: following functions are local
257 */
258
_caca_handle_resize(caca_display_t * dp)259 void _caca_handle_resize(caca_display_t *dp)
260 {
261 dp->drv.handle_resize(dp);
262
263 /* Tell libcaca we changed size */
264 if(dp->resize.w != caca_get_canvas_width(dp->cv)
265 || dp->resize.h != caca_get_canvas_height(dp->cv))
266 {
267 dp->resize.allow = 1;
268 caca_set_canvas_size(dp->cv, dp->resize.w, dp->resize.h);
269 dp->resize.allow = 0;
270 }
271 }
272
_caca_set_term_title(char const * str)273 void _caca_set_term_title(char const *str)
274 {
275 #if defined(HAVE_GETENV)
276 char *term;
277
278 term = getenv("TERM");
279
280 if(!term || !strcmp(term, "linux"))
281 return;
282 #endif
283
284 fprintf(stdout, "\033]0;%s\007", str);
285 fflush(stdout);
286 }
287
288