Tscope5
display.c
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // __ ______
4 // / /_______________ ____ ___ / ____/
5 // / __/ ___/ ___/ __ \/ __ \/ _ \ /___ )
6 // / /_(__ ) /__/ /_/ / /_/ / __/ ____/ /
7 // \__/____/\___/\____/ .___/\___/ /_____/
8 // /_/
9 //
10 /// \file display.c
11 /// Definitions of display functions
12 /// \example display01.c
13 /// \example display01.cpp
14 /// \example display02.c
15 /// \example display03.c
16 /// \example display04.c
17 /// \example display05.c
18 ////////////////////////////////////////////////////////////////////////////////
19 
20 
21 #include "../include/tscope5/display.h"
22 #include "../include/tscope5/graphics.h"
23 #include "../include/tscope5/bitmaps.h"
24 #include "../include/tscope5/display_internal.h"
25 #include "../include/tscope5/system_internal.h"
26 #include "../include/tscope5/graphics_internal.h"
27 
28 
29 ////////////////////////////////////////////////////////////////////////////////
30 /// @name Basic operations
31 /// A display can either be a window or a fullscreen display.
32 /// There are three basic display operations:
33 /// - You will need to install a display with ts5_install_display()
34 /// before anything can be drawn.
35 /// - The contents of a display can be cleared with ts5_clear_display().
36 /// - Anything that is drawn on a display only becomes visible
37 /// after a call to ts5_flip_display().
38 //@{
39 ////////////////////////////////////////////////////////////////////////////////
40 
41 
42 ////////////////////////////////////////////////////////////////////////////////
43 /// Open a new display.
44 ///
45 /// \return The index of the new display.
46 ///
47 /// TS5_FULLSCREEN_WINDOW mode:
48 /// - A fullscreen display will be opened using the same
49 /// display size and refreshrate as the desktop.
50 /// - In this mode, the display size, position and refreshrate
51 /// cannot be set by the user. These parameters will be ignored.
52 /// - Tscope5 will check whether the new display is the first
53 /// display on the adapter. If not, the program is aborted.
54 ///
55 /// TS5_FULLSCREEN mode:
56 /// - A fullscreen display will be opened.
57 /// The user can specify the display size and refreshrate.
58 /// - In this mode, the display position cannot be set by the user.
59 /// This parameter will be ignored.
60 /// - Tscope5 will check whether the new display is the
61 /// first display on the adapter. If not, the program is aborted.
62 /// - Tscope5 will check whether the display size and refreshrate is
63 /// supported by the adapter. If not, the program is aborted.
64 /// - A call to ts5_print_status() will list all combinations of
65 /// size and refreshrate that are supported by the adapter.
66 ///
67 /// TS5_WINDOWED mode:
68 /// - Opens a window. The user can specifiy the display size and position.
69 /// - In this mode, the refreshrate cannot be set by the user.
70 /// This parameter will be ignored.
71 /// - Tscope5 will check whether the adapter is already in use by
72 /// a TS5_FULLSCREEN_WINDOW or TS5_FULLSCREEN display.
73 /// If so, the program is aborted.
74 /// - Tscope5 will check whether the window will fit on the display.
75 /// If not, the dimensions of the display are reduced.
76 /// - Tscope5 will check whether the window will be visible on the screen.
77 /// If not, the window position is changed.
78 ///
79 /// The new display is the drawing target for future drawing operations.
80 ////////////////////////////////////////////////////////////////////////////////
82 {
83  ts5_check_display("ts5_install_display");
84 
85  TS5_DISPLAY_STATUS request = ts5_nextdisplay;
86 
87  // TS5_FULLSCREEN_WINDOW
88  if (ts5_nextdisplay.display_mode == TS5_FULLSCREEN_WINDOW) {
89 
90  // the adapter cannot be in use by another tscope5 display
91  int i;
92  for (i = 0; i < _ts5_status.num_displays; i++) {
93 
94  if (_ts5_status.display[i].adapter
95  == ts5_nextdisplay.adapter) {
96  ts5_fatal ("%s: %s, %s (%d)\n", "ts5_install_display",
97  "cannot open fullscreen display",
98  "adapter already in use by another display", i);
99  }
100  }
101 
102  // copy relevant settings
103  request.w = 320;
104  request.h = 240;
105  request.x = -1;
106  request.y = -1;
107  request.refreshrate = -1;
108  request.display_mode = TS5_FULLSCREEN_WINDOW;
109  request.vsync_mode = ts5_nextdisplay.vsync_mode;
110  }
111 
112  // TS5_FULLSCREEN
113  if (ts5_nextdisplay.display_mode == TS5_FULLSCREEN) {
114 
115  // the adapter cannot be in use by another tscope5 display
116  int i;
117  for (i = 0; i < _ts5_status.num_displays; i++) {
118 
119  if (_ts5_status.display[i].adapter
120  == ts5_nextdisplay.adapter) {
121  ts5_fatal ("%s: %s, %s (%d)\n", "ts5_install_display",
122  "cannot open fullscreen display",
123  " adapter already in use by another display", i);
124  }
125  }
126 
127  // is the combination of display size and refresh rate supported by
128  // the adapter?
129  ALLEGRO_DISPLAY_MODE *mode;
130  mode = (ALLEGRO_DISPLAY_MODE *)al_malloc(sizeof(ALLEGRO_DISPLAY_MODE));
131  int nmodes = al_get_num_display_modes();
132  int found=0;
133 
134  for (i=0; i<nmodes; i++) {
135 
136  mode = al_get_display_mode(i, mode);
137 
138  if (mode->width==ts5_nextdisplay.w
139  && mode->height==ts5_nextdisplay.h
140  && (mode->refresh_rate==ts5_nextdisplay.refreshrate
141  || mode->refresh_rate==0)) {
142  found=1;
143  }
144  }
145 
146  al_free(mode);
147 
148  if (!found) {
149  ts5_fatal ("%s: %s (%d, %d) %s (%d) %s %d\n",
150  "ts5_install_display"
151  "the requested combination of size",
153  "and refreshate", ts5_nextdisplay.refreshrate,
154  "is not supported by display adapter",
155  ts5_nextdisplay.adapter);
156  }
157 
158  // copy relevant settings
159  request.w = ts5_nextdisplay.w;
160  request.h = ts5_nextdisplay.h;
161  request.x = -1;
162  request.y = -1;
163  request.refreshrate = ts5_nextdisplay.refreshrate;
164  request.display_mode = TS5_FULLSCREEN;
165  request.vsync_mode = ts5_nextdisplay.vsync_mode;
166  }
167 
168  // TS5_WINDOWED
169  if (ts5_nextdisplay.display_mode == TS5_WINDOWED) {
170 
171  // the adapter cannot be in used by a
172  // TS5_FULLSCREEN_WINDOW or TS5_FULLSCREEN display
173  int i;
174  for (i = 0; i < _ts5_status.num_displays; i++) {
175 
176  if (_ts5_status.display[i].adapter
177  == ts5_nextdisplay.adapter
178  && (_ts5_status.display[i].display_mode
179  == TS5_FULLSCREEN
180  || _ts5_status.display[i].display_mode
181  == TS5_FULLSCREEN_WINDOW)) {
182 
183  ts5_fatal ("%s: %s, %s (%d)\n", "ts5_install_display",
184  "cannot open display",
185  " adapter already in use by a fullscreen display",
186  i);
187  }
188  }
189 
190  // window should be at least 320 pixels wide
191  // and smaller than the width of the monitor
192  if (ts5_nextdisplay.w < 320 ) {
193  request.w = 320;
194  ts5_log(TS5_LOGLEVEL_1, "%s: %s %d (was %d)\n",
195  "ts5_install_display", "adjusting display width to",
196  request.w, ts5_nextdisplay.w);
197  }
198  else if (ts5_nextdisplay.w
199  > _ts5_status.display_adapter
200  [ts5_nextdisplay.adapter].w) {
201 
202  request.w = _ts5_status.display_adapter[ts5_nextdisplay.adapter].w;
203 
204  ts5_log(TS5_LOGLEVEL_1, "%s: %s %d (was %d)\n",
205  "ts5_install_display", "adjusting display width to",
206  request.w, ts5_nextdisplay.w);
207  }
208  else {
209  request.w = ts5_nextdisplay.w;
210  }
211 
212  // window should be at least 240 pixels high
213  // and smaller than the height of the monitor
214  if (ts5_nextdisplay.h < 240 ) {
215  request.h = 240;
216  ts5_log(TS5_LOGLEVEL_1, "%s: %s %d (was %d)\n",
217  "ts5_install_display", "adjusting display height to",
218  request.h, ts5_nextdisplay.h);
219  }
220  else if (ts5_nextdisplay.h
221  > _ts5_status.display_adapter
222  [ts5_nextdisplay.adapter].h) {
223 
224  request.h = _ts5_status.display_adapter
225  [ts5_nextdisplay.adapter].h;
226 
227  ts5_log(TS5_LOGLEVEL_1, "%s: %s %d (was %d)\n",
228  "ts5_install_display", "adjusting display height to",
229  request.h, ts5_nextdisplay.h);
230  }
231  else {
232  request.h = ts5_nextdisplay.h;
233  }
234 
235  request.x = ts5_nextdisplay.x;
236  request.y = ts5_nextdisplay.y;
237 
238  if (request.x == -1) {
239 
240  if (_ts5_status.graphics.coordinate_system
241  == TS5_CARTESIAN_COORDINATES) {
242 
243  request.x = (_ts5_status.display_adapter
244  [request.adapter].w - request.w)/2;
245  }
246  else {
247  request.x = 0;
248  }
249 
250  request.x += _ts5_status.display_adapter[request.adapter].x1;
251  }
252 
253  if (request.y == -1) {
254 
255  if (_ts5_status.graphics.coordinate_system
256  == TS5_CARTESIAN_COORDINATES) {
257 
258  request.y = (_ts5_status.display_adapter
259  [request.adapter].h - request.h)/2;
260  }
261  else {
262  request.y = 0;
263  }
264 
265  request.y += _ts5_status.display_adapter[request.adapter].y1;
266  }
267 
268  // copy relevant settings
269  request.refreshrate = -1;
270  request.display_mode = TS5_WINDOWED;
271  request.vsync_mode = ts5_nextdisplay.vsync_mode;
272  }
273 
274 
275  // pass on display parameters to Allegro
276  al_set_new_display_adapter(request.adapter);
277  al_set_new_display_refresh_rate(request.refreshrate);
278 
279  al_set_new_display_option(ALLEGRO_VSYNC, (int)request.vsync_mode,
280  ALLEGRO_SUGGEST);
281 
282  if (request.display_mode == TS5_WINDOWED) {
283  al_set_new_window_position(request.x, request.y);
284  }
285 
286  if (request.display_mode == TS5_FULLSCREEN_WINDOW) {
287  al_set_new_window_position(INT_MAX, INT_MAX);
288  }
289 
290  al_set_new_display_flags(request.display_mode);
291 
292  // update counters
293  _ts5_status.num_displays++;
294  _ts5_status.active_display = _ts5_status.num_displays - 1;
295 
296  // try top open display
297  ts5_log(TS5_LOGLEVEL_1, "ts5_install_display: Opening display\n");
298 
299  TS5_DISPLAY **display;
300  display = al_realloc(_ts5_data.display,
301  _ts5_status.num_displays * sizeof(TS5_DISPLAY *));
302 
303  if (display == NULL) {
304  ts5_fatal("%s: %s\n", "ts5_install_display",
305  "failed to allocate memory for display pointer");
306  }
307 
308  _ts5_data.display = (TS5_DISPLAY **) display;
309 
310  _ts5_data.display[_ts5_status.active_display] =
311  al_create_display(request.w, request.h);
312 
313  if (!_ts5_data.display[_ts5_status.active_display]) {
314  ts5_fatal("ts5_install_display: could not open display\n");
315  }
316 
317  if (ts5_nextdisplay.display_mode == TS5_FULLSCREEN_WINDOW) {
318 
319  request.w = _ts5_status.display_adapter[request.adapter].w;
320  request.h = _ts5_status.display_adapter[request.adapter].h;
321 
322  al_toggle_display_flag(_ts5_data.display[_ts5_status.active_display],
323  TS5_FULLSCREEN_WINDOW, 0);
324 
325  al_toggle_display_flag(_ts5_data.display[_ts5_status.active_display],
326  TS5_FULLSCREEN_WINDOW, 1);
327 
328  al_rest(0.1);
329  }
330 
331  // make a display buffer
332  TS5_BITMAP **display_buffer;
333 
334  display_buffer = al_realloc(_ts5_data.display_buffer,
335  _ts5_status.num_displays * sizeof(TS5_BITMAP *));
336 
337  if (display_buffer == NULL) {
338  ts5_fatal("%s: %s\n", "ts5_install_display",
339  "failed to allocate memory for display buffer pointer");
340  }
341 
342  _ts5_data.display_buffer = (TS5_BITMAP **) display_buffer;
343 
344  _ts5_data.display_buffer[_ts5_status.active_display] =
345  al_create_bitmap(request.w, request.h);
346 
347  if (!_ts5_data.display_buffer[_ts5_status.active_display]) {
348  ts5_fatal("ts5_install_display: could not open display buffer\n");
349  }
350 
351  // set the new display as the drawing target and clear the display
352  ts5_set_drawing_target(_ts5_data.display_buffer
353  [_ts5_status.active_display]);
354 
357 
358  // copy the settings in the structure
359  TS5_DISPLAY_STATUS *display_status;
360  display_status = al_realloc(_ts5_status.display,
361  _ts5_status.num_displays * sizeof(TS5_DISPLAY_STATUS));
362 
363  if (display_status == NULL) {
364  ts5_fatal("%s: %s\n", "ts5_install_display",
365  "failed to allocate memory for display settings");
366  }
367 
368  _ts5_status.display = (TS5_DISPLAY_STATUS *) display_status;
369 
370  _ts5_status.display[_ts5_status.active_display].adapter =
371  request.adapter;
372 
373  if (request.display_mode==TS5_WINDOWED) {
374 
375  al_get_window_position(_ts5_data.display[_ts5_status.active_display],
376  &request.x, &request.y);
377 
378  if (request.x + request.w
379  > _ts5_status.display_adapter[ts5_nextdisplay.adapter].x2) {
380 
381  int oldw = request.w;
382 
383  request.w = _ts5_status.display_adapter
384  [ts5_nextdisplay.adapter].x2 - request.x;
385 
386  al_resize_display(_ts5_data.display[_ts5_status.active_display],
387  request.w, request.h);
388 
389  ts5_log(TS5_LOGLEVEL_1, "%s: %s %d (was %d)\n",
390  "ts5_install_display", "adjusting display width to",
391  request.w, oldw);
392  }
393 
394  if (request.y + request.h > _ts5_status.display_adapter
395  [ts5_nextdisplay.adapter].y2) {
396 
397  int oldh = request.h;
398 
399  request.h = _ts5_status.display_adapter
400  [ts5_nextdisplay.adapter].y2 - request.y;
401 
402  al_resize_display(_ts5_data.display[_ts5_status.active_display],
403  request.w, request.h);
404 
405  al_set_window_position(_ts5_data.display
406  [_ts5_status.active_display],
407  request.x, request.y + (request.h-oldh));
408 
409  ts5_log(TS5_LOGLEVEL_1, "%s: %s %d (was %d)\n",
410  "ts5_install_display", "adjusting display height to",
411  request.h, oldh);
412 
413  al_get_window_position(
414  _ts5_data.display[_ts5_status.active_display],
415  &request.x, &request.y);
416  }
417 
418  request.x -= _ts5_status.display_adapter[request.adapter].x1;
419  request.y -= _ts5_status.display_adapter[request.adapter].y1;
420 
421  if (_ts5_status.graphics.coordinate_system
422  == TS5_CARTESIAN_COORDINATES) {
423 
424  request.x =
425  request.x
426  - (_ts5_status.display_adapter[request.adapter].w
427  - request.w)/2.0;
428 
429  request.y =
430  (_ts5_status.display_adapter[request.adapter].h
431  - request.h)/2.0
432  - request.y;
433  }
434  }
435 
436  _ts5_status.display[_ts5_status.active_display].x = request.x;
437  _ts5_status.display[_ts5_status.active_display].y = request.y;
438  _ts5_status.display[_ts5_status.active_display].w = request.w;
439  _ts5_status.display[_ts5_status.active_display].h = request.h;
440 
441  _ts5_status.display[_ts5_status.active_display].refreshrate =
442  request.refreshrate;
443 
444  _ts5_status.display[_ts5_status.active_display].display_mode =
445  request.display_mode;
446 
447  _ts5_status.display[_ts5_status.active_display].vsync_mode =
448  request.vsync_mode;
449 
450  atexit(ts5_uninstall_displays);
451 
452  return _ts5_status.active_display;
453 }
454 
455 
456 ////////////////////////////////////////////////////////////////////////////////
457 /// Clear the current drawing target.
458 ///
459 /// The drawing target can either be a display or a bitmap (to clear a bitmap:
460 /// set it as drawing target and call ts5_clear_display()).
461 ///
462 /// The background color is controlled by ts5_set_background_color().
463 ////////////////////////////////////////////////////////////////////////////////
465 {
466  ts5_check_display("ts5_clear_display");
467  ts5_log(TS5_LOGLEVEL_5, "ts5_clear_display()\n");
468 
469  if (_ts5_data.target == NULL) {
470  ts5_fatal("ts5_clear_display: target is a NULL pointer\n");
471  }
472 
473  al_clear_to_color(_ts5_status.graphics.background_color);
474 }
475 
476 
477 ////////////////////////////////////////////////////////////////////////////////
478 /// Make what has been drawn visible on the screen.
479 ///
480 /// \return The time when the display flip occurs.
481 ///
482 /// All drawing operations (primitives, text, bitmaps, ...)
483 /// are performed on a back buffer.
484 /// Once you have finished drawing you should call this function
485 /// to make your drawings visible on the screen.
486 /// After a call to this function the back buffer is not cleared.
487 ////////////////////////////////////////////////////////////////////////////////
489 {
490  ts5_check_display("ts5_flip_display");
491  ts5_log(TS5_LOGLEVEL_5, "ts5_flip_display()\n");
492 
493  al_set_target_backbuffer(_ts5_data.display[_ts5_status.active_display]);
494 
495  al_draw_bitmap(_ts5_data.display_buffer[_ts5_status.active_display],
496  0.0, 0.0, 0);
497 
498  al_flip_display();
499  al_clear_to_color(_ts5_status.graphics.background_color);
500 
501  al_set_target_bitmap(_ts5_data.display_buffer
502  [_ts5_status.active_display]);
503 
504  return al_get_time();
505 }
506 
507 
508 ////////////////////////////////////////////////////////////////////////////////
509 //@}
510 ////////////////////////////////////////////////////////////////////////////////
511 
512 
513 ////////////////////////////////////////////////////////////////////////////////
514 /// @name Setting the display target
515 /// Tscope5 supports multiple displays
516 /// (each call to ts5_install_display() opens a new display).
517 /// - By default everything is drawn on the display that was opened last.
518 /// - With ts5_set_active_display() you can change the target display.
519 ///
520 /// You can also redirect drawing to memory bitmaps (see bitmaps.c)
521 /// using ts5_set_drawing_target().
522 //@{
523 ////////////////////////////////////////////////////////////////////////////////
524 
525 
526 ////////////////////////////////////////////////////////////////////////////////
527 /// Set the active display.
528 ///
529 /// \param display Index of the display.
530 ///
531 /// \return The index of the previous active display.
532 ///
533 /// The 'active' display is the display that will be used
534 /// for drawing operations.
535 ////////////////////////////////////////////////////////////////////////////////
536 int ts5_set_active_display(const int display)
537 {
538  ts5_check_display2("ts5_set_active_display", display);
539  ts5_log(TS5_LOGLEVEL_4, "ts5_set_active_display(%d)\n", display);
540 
541  int retval = _ts5_status.active_display + 1;
542  _ts5_status.active_display = display - 1;
543  _ts5_data.target = _ts5_data.display_buffer[_ts5_status.active_display];
544  al_set_target_bitmap(_ts5_data.target);
545 
546  _ts5_status.graphics.target_width =
547  al_get_bitmap_width(_ts5_data.target);
548 
549  _ts5_status.graphics.target_height =
550  al_get_bitmap_height(_ts5_data.target);
551 
552  return retval;
553 }
554 
555 
556 ////////////////////////////////////////////////////////////////////////////////
557 /// Get the active display.
558 ///
559 /// \return The index of the active display.
560 ///
561 /// The 'active' display is the display that will be used
562 /// for drawing operations.
563 ////////////////////////////////////////////////////////////////////////////////
565 {
566  ts5_check_display("ts5_get_active_display");
567  ts5_log(TS5_LOGLEVEL_4, "ts5_get_active_display()\n");
568 
569  return _ts5_status.active_display + 1;
570 }
571 
572 
573 ////////////////////////////////////////////////////////////////////////////////
574 //@}
575 ////////////////////////////////////////////////////////////////////////////////
576 
577 
578 ////////////////////////////////////////////////////////////////////////////////
579 /// @name Display adapter settings
580 /// A display adapter is a physical monitor that is attached to the computer.
581 /// Tscope5 supports multiple display adapters.
582 /// Functions are available to query the number and dimensions of
583 /// each display adapter.
584 //@{
585 ////////////////////////////////////////////////////////////////////////////////
586 
587 
588 ////////////////////////////////////////////////////////////////////////////////
589 /// Get the number of display adapters that are connected to the system.
590 ///
591 /// \return The number of display adapters that are connected to the system.
592 ////////////////////////////////////////////////////////////////////////////////
594 {
595  ts5_check_display("ts5_get_num_display_adapters");
596  ts5_log(TS5_LOGLEVEL_4, "ts5_get_num_display_adapters()\n");
597 
598  return _ts5_status.num_display_adapters;
599 }
600 
601 
602 ////////////////////////////////////////////////////////////////////////////////
603 /// Get the size of the monitor attached to a display adapter.
604 ///
605 /// \param adapter Index of the display adapter.
606 /// \param w Variable that will store the width.
607 /// \param h Variable that will store the height.
608 ///
609 /// w and h are the maximum size of a window that can be opened on that adapter.
610 ///
611 /// Pass 0 to get the size of the display adapter for the next display.
612 ///
613 /// You can pass NULL for values you are not interested in.
614 ////////////////////////////////////////////////////////////////////////////////
615 void ts5_get_display_adapter_size(const int adapter, double *w, double *h)
616 {
617  ts5_check_display("ts5_get_display_adapter_size");
618  ts5_log(TS5_LOGLEVEL_4, "ts5_get_display_adapter_size(%d,%f,%f)\n",
619  adapter, w, h);
620 
621  double ww, hh;
622 
623  if (adapter < 0) {
624  ts5_fatal("ts5_get_display_adapter_size: adapter index not valid\n");
625  }
626  else if (adapter == 0) {
627  ww = _ts5_status.display_adapter[ts5_nextdisplay.adapter].w;
628  hh = _ts5_status.display_adapter[ts5_nextdisplay.adapter].h;
629  }
630  else if (adapter <= _ts5_status.num_display_adapters) {
631  ww = _ts5_status.display_adapter[adapter-1].w;
632  hh = _ts5_status.display_adapter[adapter-1].h;
633  }
634  else {
635  ts5_fatal("ts5_get_display_adapter_size: adapter index not valid\n");
636  }
637 
638  if (w) {
639  *w = ww;
640  }
641 
642  if (h) {
643  *h = hh;
644  }
645 }
646 
647 
648 ////////////////////////////////////////////////////////////////////////////////
649 /// Get the width of the monitor attached to a display adapter.
650 ///
651 /// \param adapter Index of the display adapter.
652 ///
653 /// \return the width of the display adapter.
654 ///
655 /// Pass 0 to get the width of the display adapter for the next display.
656 ////////////////////////////////////////////////////////////////////////////////
657 double ts5_get_display_adapter_width(const int adapter)
658 {
659  ts5_check_display("ts5_get_display_adapter_width");
660  ts5_log(TS5_LOGLEVEL_4, "ts5_get_display_adapter_width(%d)\n", adapter);
661 
662  double w;
663  ts5_get_display_adapter_size(adapter, &w, NULL);
664 
665  return w;
666 }
667 
668 
669 ////////////////////////////////////////////////////////////////////////////////
670 /// Get the heigth of the monitor attached to a display adapter.
671 ///
672 /// \param adapter Index of the display adapter.
673 ///
674 /// \return the height of the display adapter.
675 ///
676 /// Pass 0 to get the height of the display adapter for the next display.
677 ////////////////////////////////////////////////////////////////////////////////
678 double ts5_get_display_adapter_height(const int adapter)
679 {
680  ts5_check_display("ts5_get_display_adapter_height");
681  ts5_log(TS5_LOGLEVEL_4, "ts5_get_display_adapter_height(%d)\n", adapter);
682 
683  double h;
684  ts5_get_display_adapter_size(adapter, NULL, &h);
685 
686  return h;
687 }
688 
689 
690 ////////////////////////////////////////////////////////////////////////////////
691 //@}
692 ////////////////////////////////////////////////////////////////////////////////
693 
694 
695 ////////////////////////////////////////////////////////////////////////////////
696 /// @name Display settings
697 /// Before opening a display various settings can be requested
698 /// using the functions below.
699 /// Once a display is opened the settings remain until the end of the program.
700 //@{
701 ////////////////////////////////////////////////////////////////////////////////
702 
703 
704 ////////////////////////////////////////////////////////////////////////////////
705 /// Set the display adapter for the next display that will be opened.
706 ///
707 /// \param adapter Index of the active display adapter.
708 ///
709 /// \return The index of the previous active display adapter.
710 ///
711 /// A display adapter corresponds to a physical display that is
712 /// attached to the computer.
713 /// The first adapter has index 1, etc.
714 ///
715 /// The display is attached to adapter 1 by default.
716 ////////////////////////////////////////////////////////////////////////////////
717 int ts5_set_display_adapter(const int adapter)
718 {
719  ts5_check_display("ts5_set_display_adapter");
720  ts5_log(TS5_LOGLEVEL_4, "ts5_set_display_adapter(%d)\n", adapter);
721 
722  int retval = ts5_nextdisplay.adapter + 1;
723 
724  if (adapter > 0 && adapter <= _ts5_status.num_display_adapters) {
725  ts5_nextdisplay.adapter = adapter - 1;
726  ts5_log(TS5_LOGLEVEL_4, "%s: %s %d (was %d)\n",
727  "ts5_set_display_adapter",
728  "set display adapter for next display to",
729  retval-1, ts5_nextdisplay.adapter+1);
730  }
731  else {
732  ts5_fatal ("ts5_set_display_adapter: adapter index not valid\n");
733  }
734 
735  return retval;
736 }
737 
738 
739 ////////////////////////////////////////////////////////////////////////////////
740 /// Get the index of the display adapter of a display.
741 ///
742 /// \param display Index of the display.
743 ///
744 /// \return The index of the adapter that the display is attached to.
745 ///
746 /// Pass 0 to get the index of the display adapter for the next display.
747 ////////////////////////////////////////////////////////////////////////////////
748 int ts5_get_display_adapter(const int display)
749 {
750  ts5_check_display2("ts5_get_display_adapter", display);
751  ts5_log(TS5_LOGLEVEL_4, "ts5_get_display_adapter(%d)\n", display);
752 
753  int retval;
754 
755  if (display == 0) {
756  retval = ts5_nextdisplay.adapter + 1;
757  }
758  else {
759  retval = _ts5_status.display[display-1].adapter + 1;
760  }
761 
762  return retval;
763 }
764 
765 
766 ////////////////////////////////////////////////////////////////////////////////
767 /// Set the size of the next display.
768 ///
769 /// \param w Width of the next display in pixels.
770 /// \param h Height of the next display in pixels.
771 ///
772 /// The default width and height is 320 x 240. This is also the minimum.
773 ////////////////////////////////////////////////////////////////////////////////
774 void ts5_set_display_size(double w, double h)
775 {
776  ts5_check_display("ts5_set_display_size");
777  ts5_log(TS5_LOGLEVEL_4, "ts5_set_display_size(%f,%f)\n", w, h);
778 
779  int oldw = ts5_nextdisplay.w;
780  int oldh = ts5_nextdisplay.h;
781 
782  if (_ts5_status.graphics.coordinate_scale
783  == TS5_RELATIVE_COORDINATES) {
784  w *= _ts5_status.display_adapter[ts5_nextdisplay.adapter].w;
785  h *= _ts5_status.display_adapter[ts5_nextdisplay.adapter].h;
786  }
787 
788  ts5_nextdisplay.w = w;
789  ts5_nextdisplay.h = h;
790 
791  ts5_log(TS5_LOGLEVEL_4, "%s: %s %d x %d (was %d x %d)\n",
792  "ts5_set_display_size",
793  "set display size for next display to",
794  ts5_nextdisplay.w, ts5_nextdisplay.h, oldw, oldh);
795 }
796 
797 
798 ////////////////////////////////////////////////////////////////////////////////
799 /// Get the size of a display.
800 ///
801 /// \param display Index of the display.
802 /// \param w Variable that will store the width.
803 /// \param h Variable that will store the height.
804 ///
805 /// Set display to 0 to get the width of the next display.
806 ///
807 /// You can pass NULL for values you are not interested in.
808 ////////////////////////////////////////////////////////////////////////////////
809 void ts5_get_display_size(const int display, double *w, double *h)
810 {
811  ts5_check_display2("ts5_get_display_size", display);
812  ts5_log(TS5_LOGLEVEL_4, "ts5_get_display_size(%d,%p,%p)\n", display, w, h);
813 
814  double ww, hh;
815 
816  if (display == 0) {
817  ww = ts5_nextdisplay.w;
818  hh = ts5_nextdisplay.h;
819  }
820  else {
821  ww = _ts5_status.display[display-1].w;
822  hh = _ts5_status.display[display-1].h;
823  }
824 
825  if (w) {
826  *w = ww;
827  }
828 
829  if (h) {
830  *h = hh;
831  }
832 }
833 
834 
835 ////////////////////////////////////////////////////////////////////////////////
836 /// Get the width of a display.
837 ///
838 /// \param display Index of the display.
839 ///
840 /// \return the width of the display.
841 ///
842 /// Set display to 0 to get the width of the next display.
843 ////////////////////////////////////////////////////////////////////////////////
844 double ts5_get_display_width(const int display)
845 {
846  ts5_check_display2("ts5_get_display_width", display);
847  ts5_log(TS5_LOGLEVEL_4, "ts5_get_display_width(%d)\n", display);
848 
849  double w;
850  ts5_get_display_size(display, &w, NULL);
851 
852  return w;
853 }
854 
855 
856 ////////////////////////////////////////////////////////////////////////////////
857 /// Get the height of a display.
858 ///
859 /// \param display Index of the display.
860 ///
861 /// \return the height of the display.
862 ///
863 /// Set display to 0 to get the height of the next display.
864 ////////////////////////////////////////////////////////////////////////////////
865 double ts5_get_display_height(const int display)
866 {
867  ts5_check_display2("ts5_get_display_height", display);
868  ts5_log(TS5_LOGLEVEL_4, "ts5_get_display_height(%d)\n", display);
869 
870  double h;
871  ts5_get_display_size(display, NULL, &h);
872 
873  return h;
874 }
875 
876 
877 ////////////////////////////////////////////////////////////////////////////////
878 /// Set the position of the next display.
879 ///
880 /// \param x Horizontal position of the display on the desktop.
881 /// \param y Vertical position of the display on the desktop.
882 ///
883 /// Only meaningful for non-fullscreen displays.
884 ///
885 /// CARTESIAN coordinates: Center of the display is the origin,
886 /// default position is the center of the display.
887 ///
888 /// COMPUTER coordinates: The upper left corner of the display is the origin,
889 /// default position is top left corner of the display.
890 ////////////////////////////////////////////////////////////////////////////////
891 void ts5_set_display_position(double x, double y)
892 {
893  ts5_check_display("ts5_set_display_position");
894  ts5_log(TS5_LOGLEVEL_4, "ts5_set_display_position(%f,%f)\n", x, y);
895 
896  int oldx = ts5_nextdisplay.x;
897  int oldy = ts5_nextdisplay.y;
898 
899  if (_ts5_status.graphics.coordinate_scale
900  == TS5_RELATIVE_COORDINATES) {
901 
902  if (_ts5_status.graphics.coordinate_system
903  == TS5_CARTESIAN_COORDINATES) {
904 
905  x *= _ts5_status.display_adapter[ts5_nextdisplay.adapter].w
906  / 2.0;
907 
908  y *= _ts5_status.display_adapter[ts5_nextdisplay.adapter].h
909  / 2.0;
910  }
911  else {
912  x *= _ts5_status.display_adapter[ts5_nextdisplay.adapter].w;
913  y *= _ts5_status.display_adapter[ts5_nextdisplay.adapter].h;
914  }
915  }
916 
917  if (_ts5_status.graphics.coordinate_system
918  == TS5_CARTESIAN_COORDINATES) {
919 
920  x += _ts5_status.display_adapter[ts5_nextdisplay.adapter].w/2.0;
921  x -= ts5_nextdisplay.w/2.0;
922  y = -y;
923  y += _ts5_status.display_adapter[ts5_nextdisplay.adapter].h/2.0;
924  y -= ts5_nextdisplay.h/2.0;
925  }
926 
927  x += _ts5_status.display_adapter[ts5_nextdisplay.adapter].x1;
928  y += _ts5_status.display_adapter[ts5_nextdisplay.adapter].y1;
929 
930  ts5_nextdisplay.x = x;
931  ts5_nextdisplay.y = y;
932 
933  ts5_log(TS5_LOGLEVEL_4, "%s: %s (%d,%d) (was (%d,%d))\n",
934  "ts5_set_display_position",
935  "set display position for next display to",
937  oldx, oldy);
938 }
939 
940 
941 ////////////////////////////////////////////////////////////////////////////////
942 /// Get the position of a display.
943 ///
944 /// \param display Index of the display.
945 /// \param x Variable that will store the horizontal position.
946 /// \param y Variable that will store the vertical position.
947 ///
948 /// Only meaningful for non-fullscreen displays.
949 ///
950 /// Set display to 0 to get the x position of the next display.
951 ///
952 /// You can pass NULL for values you are not interested in.
953 ////////////////////////////////////////////////////////////////////////////////
954 void ts5_get_display_position(const int display, double *x, double *y)
955 {
956  ts5_check_display2("ts5_get_display_position", display);
957  ts5_log(TS5_LOGLEVEL_4, "ts5_get_display_position(%d,%p,%p)\n",
958  display, x, y);
959 
960  double xx, yy;
961  double dw, dh, aw, ah;
962 
963  // get the values we need
964  if (display != 0) {
965 
966  int adapter = ts5_get_display_adapter(display);
967  al_get_window_position(_ts5_data.display[display-1],
968  &_ts5_status.display[display-1].x,
969  &_ts5_status.display[display-1].y);
970 
971  xx = _ts5_status.display[display-1].x;
972  yy = _ts5_status.display[display-1].y;
973 
974  xx -= _ts5_status.display_adapter[adapter-1].x1;
975  yy -= _ts5_status.display_adapter[adapter-1].y1;
976 
977  dw = _ts5_status.display[display-1].w;
978  dh = _ts5_status.display[display-1].h;
979 
980  aw = _ts5_status.display_adapter[adapter-1].w;
981  ah = _ts5_status.display_adapter[adapter-1].h;
982  }
983  else {
984 
985  xx = ts5_nextdisplay.x;
986  yy = ts5_nextdisplay.y;
987 
988  dw = ts5_nextdisplay.w;
989  dh = ts5_nextdisplay.h;
990 
991  aw = _ts5_status.display_adapter[ts5_nextdisplay.adapter].w;
992  ah = _ts5_status.display_adapter[ts5_nextdisplay.adapter].h;
993  }
994 
995  // if the settings are not default, compute xx and yy
996  if (xx!=-1 && yy!=-1) {
997 
998 
999  // convert to cartesian if necessary
1000  if (_ts5_status.graphics.coordinate_system
1001  == TS5_CARTESIAN_COORDINATES) {
1002  xx = xx + dw/2.0 - aw/2.0;
1003  yy = ah/2.0 - yy - dh/2.0;
1004  }
1005 
1006  // convert to relative if necessary
1007  if (_ts5_status.graphics.coordinate_scale
1008  == TS5_RELATIVE_COORDINATES) {
1009 
1010  if (_ts5_status.graphics.coordinate_system
1011  == TS5_CARTESIAN_COORDINATES) {
1012  xx /= aw/2.0;
1013  yy /= ah/2.0;
1014  }
1015  else {
1016  xx /= aw;
1017  yy /= ah;
1018  }
1019  }
1020  }
1021 
1022  if (x) {
1023  *x = xx;
1024  }
1025 
1026  if (y) {
1027  *y = yy;
1028  }
1029 
1030 
1031 }
1032 
1033 
1034 ////////////////////////////////////////////////////////////////////////////////
1035 /// Get the horizontal position of a display.
1036 ///
1037 /// \param display Index of the display.
1038 ///
1039 /// \return
1040 /// The horizontal position of the display.
1041 ////////////////////////////////////////////////////////////////////////////////
1042 double ts5_get_display_x(const int display)
1043 {
1044  ts5_check_display2("ts5_get_display_x", display);
1045  ts5_log(TS5_LOGLEVEL_4, "ts5_get_display_x(%d)\n", display);
1046 
1047  double x;
1048  ts5_get_display_position(display, &x, NULL);
1049 
1050  return x;
1051 }
1052 
1053 
1054 ////////////////////////////////////////////////////////////////////////////////
1055 /// Get the vertical position of a display.
1056 ///
1057 /// \param display Index of the display.
1058 ///
1059 /// \return
1060 /// The vertical position of the display.
1061 ////////////////////////////////////////////////////////////////////////////////
1062 double ts5_get_display_y(const int display)
1063 {
1064  ts5_check_display2("ts5_get_display_y", display);
1065  ts5_log(TS5_LOGLEVEL_4, "ts5_get_display_y(%d)\n", display);
1066 
1067  double y;
1068  ts5_get_display_position(display, NULL, &y);
1069 
1070  return y;
1071 }
1072 
1073 
1074 
1075 
1076 ////////////////////////////////////////////////////////////////////////////////
1077 /// Set the requested refreshrate for the next display.
1078 ///
1079 /// \param rate Refreshrate in cycles per second.
1080 ///
1081 /// \return The previous refresh rate.
1082 ///
1083 /// The refreshrate can only be changed for real fullscreen displays.
1084 ///
1085 /// Even then this is only a request.
1086 ///
1087 /// The default value 0 (let the system choose).
1088 ////////////////////////////////////////////////////////////////////////////////
1089 int ts5_set_refreshrate(const int rate)
1090 {
1091  ts5_check_display("ts5_set_refreshrate");
1092  ts5_log(TS5_LOGLEVEL_4, "ts5_set_refreshrate(%d)\n", rate);
1093 
1094  int retval = ts5_nextdisplay.refreshrate;
1095 
1096  ts5_nextdisplay.refreshrate = rate;
1097 
1098  ts5_log(TS5_LOGLEVEL_4, "%s: %s %d (was %d)\n", "ts5_set_refreshrate",
1099  "set refreshrate for next display to",
1100  ts5_nextdisplay.refreshrate, retval);
1101 
1102  return retval;
1103 }
1104 
1105 
1106 ////////////////////////////////////////////////////////////////////////////////
1107 /// Get the refreshrate of a display.
1108 ///
1109 /// \param display Index of the display.
1110 ///
1111 /// \return The refresh rate of the display.
1112 ///
1113 /// Set display to 0 to get the refreshrate of the next display.
1114 ////////////////////////////////////////////////////////////////////////////////
1115 int ts5_get_refreshrate(const int display)
1116 {
1117  ts5_check_display2("ts5_get_refreshrate", display);
1118  ts5_log(TS5_LOGLEVEL_4, "ts5_get_refreshrate(%d)\n", display);
1119 
1120  int retval;
1121 
1122  if (display == 0) {
1123  retval = ts5_nextdisplay.refreshrate;
1124  }
1125  else {
1126  retval = _ts5_status.display[display-1].refreshrate;
1127  }
1128 
1129  return retval;
1130 }
1131 
1132 
1133 ////////////////////////////////////////////////////////////////////////////////
1134 /// Set the display mode for the next display.
1135 ///
1136 /// \param mode Window mode.
1137 /// Can be TS5_WINDOWED, TS5_FULLSCREEN or TS5_FULLSCREEN_WINDOW.
1138 ///
1139 /// \return The previous display mode.
1140 ///
1141 /// In TS5_WINDOWED mode the window can have any dimension that
1142 /// will fit on the physical display
1143 /// and the position of the window on the display can be adjusted.
1144 /// Multiple TS5_WINDOWED displays can be combined on one physical display.
1145 /// The refreshrate is always the refreshrate of the physical display.
1146 ///
1147 /// In TS5_FULLSCREEN_WINDOW mode the display always has the dimension
1148 /// of the desktop.
1149 /// The refreshrate is always the refreshrate of the physical display.
1150 /// Only one TS5_FULLSCREEN_WINDOW display can be used
1151 /// per physical display.
1152 ///
1153 /// TS5_FULLSCREEN modes are the most flexible:
1154 /// any combination of display dimension and refreshrate
1155 /// that is supported by the monitor can be set.
1156 /// Does not seem to work on Mac OS X.
1157 ///
1158 /// The default window mode is TS5_WINDOWED.
1159 ////////////////////////////////////////////////////////////////////////////////
1160 int ts5_set_display_mode(const int mode)
1161 {
1162  ts5_check_display("ts5_set_display_mode");
1163  ts5_log(TS5_LOGLEVEL_4, "ts5_set_display_mode(%d)\n", mode);
1164 
1165  int retval = ts5_nextdisplay.display_mode;
1166 
1167  if (mode != TS5_WINDOWED
1168  && mode != TS5_FULLSCREEN
1169  && mode != TS5_FULLSCREEN_WINDOW) {
1170  ts5_fatal ("%s: %s (%d)\n", "ts5_set_display_mode",
1171  "requested display mode not available", mode);
1172  }
1173 
1174  ts5_nextdisplay.display_mode = mode;
1175 
1176  ts5_log(TS5_LOGLEVEL_4, "%s: %s %d (was %d)\n", "ts5_set_display_mode",
1177  "set display mode for next display to",
1178  ts5_nextdisplay.display_mode, retval);
1179 
1180  return retval;
1181 }
1182 
1183 
1184 ////////////////////////////////////////////////////////////////////////////////
1185 /// Get the display mode of a display.
1186 ///
1187 /// \param display Index of the display.
1188 ///
1189 /// \return The window mode of the display.
1190 ///
1191 /// Set display to 0 to get the display mode of the next display.
1192 ////////////////////////////////////////////////////////////////////////////////
1193 int ts5_get_display_mode(const int display)
1194 {
1195  ts5_check_display2("ts5_get_display_mode", display);
1196  ts5_log(TS5_LOGLEVEL_4, "ts5_get_display_mode(%d)\n", display);
1197 
1198  int retval;
1199 
1200  if (display == 0) {
1201  retval = ts5_nextdisplay.display_mode;
1202  }
1203  else {
1204  retval = _ts5_status.display[display-1].display_mode;
1205  }
1206 
1207  return retval;
1208 }
1209 
1210 
1211 ////////////////////////////////////////////////////////////////////////////////
1212 /// Set the vsync mode for the next display.
1213 ///
1214 /// \param mode Vsync mode.
1215 /// Can be TS5_VSYNC_WHATEVER, TS5_VSYNC_ON or TS5_VSYNC_OFF.
1216 ///
1217 /// \return The previous vsync mode.
1218 ///
1219 /// The default vsync mode is TS5_VSYNC_ON.
1220 ////////////////////////////////////////////////////////////////////////////////
1221 int ts5_set_vsync_mode(const int mode)
1222 {
1223  ts5_check_display("ts5_set_vsync_mode");
1224  ts5_log(TS5_LOGLEVEL_4, "ts5_set_vsync_mode(%d)\n", mode);
1225 
1226  int retval = ts5_nextdisplay.vsync_mode;
1227 
1228  if (mode < TS5_VSYNC_WHATEVER || mode > TS5_VSYNC_OFF) {
1229  ts5_fatal("ts5_set_vsync_mode: mode should be 0, 1 or 2 (is %d)\n",
1230  mode);
1231  }
1232 
1233  ts5_nextdisplay.vsync_mode = mode;
1234 
1235  ts5_log(TS5_LOGLEVEL_4, "%s: %s %d (was %d)\n", "ts5_set_vsync_mode",
1236  "set vsync mode for next display to",
1237  ts5_nextdisplay.vsync_mode, retval);
1238 
1239  return retval;
1240 }
1241 
1242 
1243 ////////////////////////////////////////////////////////////////////////////////
1244 /// Get the vsync mode of a display.
1245 ///
1246 /// \param display Index of the display.
1247 ///
1248 /// \return The vsync mode of the display.
1249 ///
1250 /// Set display to 0 to get the requested vsync mode for the next display.
1251 ////////////////////////////////////////////////////////////////////////////////
1252 int ts5_get_vsync_mode(const int display)
1253 {
1254  ts5_check_display2("ts5_get_vsync_mode", display);
1255  ts5_log(TS5_LOGLEVEL_4, "ts5_get_vsync_mode(%d)\n", display);
1256 
1257  int retval;
1258 
1259  if (display == 0) {
1260  retval = ts5_nextdisplay.vsync_mode;
1261  }
1262  else {
1263  retval = _ts5_status.display[display-1].vsync_mode;
1264  }
1265 
1266  return retval;
1267 }
1268 
1269 
1270 ////////////////////////////////////////////////////////////////////////////////
1271 //@}
1272 ////////////////////////////////////////////////////////////////////////////////