add option for classic magicmenu "mixed" menu style (pull donw on screen title, pop...
[AROS.git] / rom / graphics / getdisplayinfodata.c
blob9a07d7d47960f03a3f6c20e1edd1aba08ae0a366
1 /*
2 Copyright © 1995-2013, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Graphics function GetDisplayInfoData()
6 Lang: english
7 */
9 #include <aros/debug.h>
10 #include <proto/graphics.h>
11 #include <graphics/displayinfo.h>
12 #include <hidd/graphics.h>
13 #include <proto/oop.h>
14 #include <stdio.h>
15 #include <string.h>
17 #include "graphics_intern.h"
18 #include "compositing_driver.h"
19 #include "dispinfo.h"
21 /****************************************************************************************/
23 static const ULONG size_checks[] =
25 sizeof(struct DisplayInfo),
26 sizeof(struct DimensionInfo),
27 sizeof(struct MonitorInfo),
28 sizeof(struct NameInfo),
31 #define KNOWN_IDS 4
33 static ULONG check_sizes(ULONG tagID, ULONG size);
34 static UBYTE popcount(IPTR x);
36 #define DLONGSZ (sizeof (ULONG) * 2)
37 #define DTAG_TO_IDX(dtag) (((dtag) & 0x7FFFF000) >> 12)
40 * Resolution calculation rules.
42 * MonitorSpec:
43 * ratioh, ratiov - ratio between size of a 1084S and the current monitor
44 * (larger fractions are larger monitors, smaller are smaller)
46 * Screen Resolution:
47 * Since this is related to mouse ticks, it would make sense for this
48 * calculation to be a inverse relationship to overall DPI, instead of
49 * to the number of pixels in the display.
51 * Therefore, Screen Resolution would be calculated as:
53 * res.x = (1280 * 11 * ratioh / pixel_width) >> RATIO_FIXEDPART
54 * res.y = (1024 * 11 * ratiov / pixel_height) >> RATIO_FIXEDPART
56 * Screen DPI can be directly calculated from DrawInfo Resolution as:
58 * #define C_1084_WIDTH_CIN 104 // 10.4 " in centi-inches
59 * #define C_1084_HEIGHT_CIN 78 // 7.8 " in centi-inches
61 * dpi.x = (11 * 1280 * 10) / C_1084_WIDTH_CIN / res.x
62 * dpi.y = (11 * 1024 * 10) / C_1084_HEIGHT_CIN / res.y
64 * Screen DPC (dots per centimeter) is calculated as:
66 * #define C_1084_WIDTH_MM 264 // 10.4 " in mm
67 * #define C_1084_HEIGHT_MM 198 // 7.8 " in mm
69 * dpc.x = 11 * 1280 * 10 / C_1084_WIDTH_MM / res.x
70 * dpc.y = 11 * 1024 * 10 / C_1084_HEIGHT_MM / res.y
72 * Jason S. McMullan <jason.mcmullan@gmail.com>
74 static inline void CalcScreenResolution(Point *res, const struct MonitorSpec *mspc,
75 OOP_Object *sync, struct GfxBase *GfxBase)
77 IPTR width, height;
79 OOP_GetAttr(sync, aHidd_Sync_HDisp, &width);
80 OOP_GetAttr(sync, aHidd_Sync_VDisp, &height);
82 res->x = (1280 * 11 * mspc->ratioh / width ) >> RATIO_FIXEDPART;
83 res->y = (1024 * 11 * mspc->ratiov / height) >> RATIO_FIXEDPART;
86 /*****************************************************************************
88 NAME */
89 #include <proto/graphics.h>
91 AROS_LH5(ULONG, GetDisplayInfoData,
93 /* SYNOPSIS */
94 AROS_LHA(DisplayInfoHandle, handle, A0),
95 AROS_LHA(UBYTE *, buf, A1),
96 AROS_LHA(ULONG, size, D0),
97 AROS_LHA(ULONG, tagID, D1),
98 AROS_LHA(ULONG, ID, D2),
100 /* LOCATION */
101 struct GfxBase *, GfxBase, 126, Graphics)
103 /* FUNCTION
104 Fills buffer with information about displayinfo handle.
106 INPUTS
107 handle - displayinfo handle
108 buf - pointer to destination buffer
109 size - buffer size in bytes
110 tagID - data chunk type
111 DTAG_DISP (DisplayInfo)
112 DTAG_DIMS (DimensionInfo)
113 DTAG_MNTR (MonitorInfo)
114 DTAG_NAME (NameInfo)
115 ID - displayinfo identifier, optionally used if handle is NULL
117 RESULT
118 result - if positive, number of bytes actually transferred
119 if zero, no information for ID was available
121 NOTES
123 EXAMPLE
125 BUGS
127 SEE ALSO
128 FindDisplayInfo(), NextDisplayInfo(), graphics/displayinfo.h
130 INTERNALS
131 This function provides private data in reserved fields of DimensionInfo.
132 It is required by other AROS components. Please keep this in sync when
133 changing the code.
135 HISTORY
137 ******************************************************************************/
139 AROS_LIBFUNC_INIT
141 struct QueryHeader *qh;
142 ULONG structsize;
143 OOP_Object *gfxhidd, *sync, *pf;
144 HIDDT_ModeID hiddmode;
145 struct HIDD_ModeProperties HIDDProps = {0};
147 if (NULL == handle)
149 /* FindDisplayInfo() handles INVALID_ID itself */
150 handle = FindDisplayInfo(ID);
152 else
155 * ID is likely INVALID_ID, but we need its value.
156 * Get it from the handle.
158 ID = DIH(handle)->id | DIH(handle)->drv->id;
161 if (NULL == handle)
163 D(bug("!!! COULD NOT GET HANDLE IN GetDisplayInfoData()\n"));
164 return 0;
167 gfxhidd = DIH(handle)->drv->gfxhidd;
168 hiddmode = DIH(handle)->id;
170 /* Get mode info from the HIDD */
171 if (!HIDD_Gfx_GetMode(gfxhidd, hiddmode, &sync, &pf))
173 D(bug("NO VALID MODE PASSED TO GetDisplayInfoData() !!!\n"));
174 return 0;
177 D(bug("GetDisplayInfoData(handle=%d, tagID=%x)\n"
178 , (ULONG)handle, tagID));
180 /* Build the queryheader */
181 structsize = check_sizes(tagID, size);
182 if (!structsize)
183 return 0;
184 qh = AllocMem(structsize, MEMF_CLEAR);
185 if (!qh)
186 return 0;
188 /* Fill in the queryheader */
189 qh->StructID = tagID;
190 qh->DisplayID = ID;
191 qh->SkipID = TAG_SKIP;
193 qh->Length = (structsize + (DLONGSZ - 1)) / DLONGSZ;
195 switch (tagID)
197 case DTAG_DISP:
199 struct DisplayInfo *di;
200 const struct MonitorSpec *ms;
201 IPTR redmask, greenmask, bluemask;
202 IPTR val = 0;
204 HIDD_Gfx_ModeProperties(gfxhidd, hiddmode, &HIDDProps, sizeof(HIDDProps));
206 di = (struct DisplayInfo *)qh;
208 /* All modes returned from the HIDD are available */
209 di->NotAvailable = FALSE;
212 * Set the propertyflags. We always set DIPF_IS_SPRITES because we always emulate
213 * one sprite for mouse pointer.
215 di->PropertyFlags = DIPF_IS_SPRITES | HIDDProps.DisplayInfoFlags;
218 * Some more tweaks.
219 * All non-planar modes are considered Workbench-compatible. This is done
220 * for compatibility with existing RTG drivers which never set this flag themselves.
221 * This can be considered historical, in initial API design HIDD_Gfx_ModeProperties()
222 * did not exist at all and this flag was simply always set.
223 * In fact all modes can be considered Workbench-compatible. This flag is
224 * known to be used by original AmigaOS screenmode prefs program to filter out
225 * some modes. This program has many replacement which do not obey this flag,
226 * enabling opening Workbench on HAM screen for example.
227 * But we delegate setting this flag to the driver for planar modes. We do it
228 * for 100% compatibility of chipset driver. What if some m68k program has its own
229 * weird assumptions about this bit ?
230 * One more thing to note: we don't set DIPF_IS_FOREIGN bit. It is actually used
231 * only by Picasso96 and only for modes that are not graphics.library compatible.
232 * Many m68k RTG games rely on this flag not being set.
234 OOP_GetAttr(pf, aHidd_PixFmt_StdPixFmt, &val);
235 if (val != vHidd_StdPixFmt_Plane)
236 di->PropertyFlags |= DIPF_IS_WB;
238 /* Compute red green and blue bits */
239 OOP_GetAttr(pf, aHidd_PixFmt_RedMask, &redmask);
240 OOP_GetAttr(pf, aHidd_PixFmt_GreenMask, &greenmask);
241 OOP_GetAttr(pf, aHidd_PixFmt_BlueMask, &bluemask);
243 /* Use gcc builtin function */
244 /* weissms: do not use, can cause undefined symbol _GLOBAL_OFFSET_TABLE_
245 * should work if we use a real cross compiler with static libgcc
246 di->RedBits = __builtin_popcount(redmask);
247 di->GreenBits = __builtin_popcount(greenmask);
248 di->BlueBits = __builtin_popcount(bluemask);
251 di->RedBits = popcount(redmask);
252 di->GreenBits = popcount(greenmask);
253 di->BlueBits = popcount(bluemask);
256 * If number of colors is too large, PaletteRange is set to 65535.
257 * This is the behavior of original AmigaOS(tm).
259 val = di->RedBits * di->GreenBits * di->BlueBits;
260 di->PaletteRange = (val > 65535) ? 65535 : val;
262 /* Display resolution in ticks */
263 OOP_GetAttr(sync, aHidd_Sync_MonitorSpec, (IPTR *)&ms);
264 CalcScreenResolution(&di->Resolution, ms, sync, GfxBase);
266 OOP_GetAttr(sync, aHidd_Sync_PixelClock, &val);
267 if (val)
268 di->PixelSpeed = 1000000000 / val;
271 * If the driver says it does not support sprites, we return one sprite.
272 * We emulate it by software in such a case because it's necessary for
273 * the mouse pointer.
275 di->NumStdSprites = (HIDDProps.DisplayInfoFlags & DIPF_IS_SPRITES) ? HIDDProps.NumHWSprites : 1;
277 /* At the moment sprites always have the same resolution as display */
278 di->SpriteResolution = di->Resolution;
280 break;
283 case DTAG_DIMS:
285 struct DimensionInfo *di;
286 IPTR depth, width, height;
287 IPTR minwidth, minheight;
288 IPTR maxwidth, maxheight;
290 OOP_GetAttr(pf, aHidd_PixFmt_Depth, &depth);
291 OOP_GetAttr(sync, aHidd_Sync_HDisp, &width);
292 OOP_GetAttr(sync, aHidd_Sync_VDisp, &height);
293 OOP_GetAttr(sync, aHidd_Sync_HMin, &minwidth);
294 OOP_GetAttr(sync, aHidd_Sync_VMin, &minheight);
295 OOP_GetAttr(sync, aHidd_Sync_HMax, &maxwidth);
296 OOP_GetAttr(sync, aHidd_Sync_VMax, &maxheight);
298 di = (struct DimensionInfo *)qh;
299 di->MaxDepth = depth;
301 di->MinRasterWidth = minwidth;
302 di->MinRasterHeight = minheight;
303 di->MaxRasterWidth = maxwidth;
304 di->MaxRasterHeight = maxheight;
306 di->Nominal.MinX = 0;
307 di->Nominal.MinY = 0;
308 di->Nominal.MaxX = width - 1;
309 di->Nominal.MaxY = height - 1;
311 di->MaxOScan = di->Nominal;
312 di->VideoOScan = di->Nominal;
313 di->TxtOScan = di->Nominal;
314 di->StdOScan = di->Nominal;
316 * FIXME: our graphics subsystem does not have overscan API.
317 di->MaxOScan.MinX = di->Nominal.MinX;
318 di->MaxOScan.MinY = di->Nominal.MinY;
319 di->MaxOScan.MaxX = di->Nominal.MaxX;
320 di->MaxOScan.MaxY = di->Nominal.MaxY;
322 di->VideoOScan.MinX = di->Nominal.MinX;
323 di->VideoOScan.MinY = di->Nominal.MinY;
324 di->VideoOScan.MaxX = di->Nominal.MaxX;
325 di->VideoOScan.MaxY = di->Nominal.MaxY;
327 di->TxtOScan.MinX = di->Nominal.MinX;
328 di->TxtOScan.MinY = di->Nominal.MinY;
329 di->TxtOScan.MaxX = di->Nominal.MaxX;
330 di->TxtOScan.MaxY = di->Nominal.MaxY;
332 di->StdOScan.MinX = di->Nominal.MinX;
333 di->StdOScan.MinY = di->Nominal.MinY;
334 di->StdOScan.MaxX = di->Nominal.MaxX;
335 di->StdOScan.MaxY = di->Nominal.MaxY;
339 * reserved[0] is HIDD composition flags for intuition.library/OpenScreen().
340 * It can't be done in another way because only we (graphics.library) know about existence
341 * of software screen composition.
343 if (DIH(handle)->drv->composer)
345 OOP_GetAttr(DIH(handle)->drv->composer, aHidd_Compositing_Capabilities, &di->reserved[0]);
347 else
349 HIDD_Gfx_ModeProperties(gfxhidd, hiddmode, &HIDDProps, sizeof(HIDDProps));
350 di->reserved[0] = HIDDProps.CompositionFlags;
353 /* This is for cybergraphics.library */
354 di->reserved[1] = (IPTR)pf;
356 break;
359 case DTAG_MNTR:
361 struct MonitorInfo *mi = (struct MonitorInfo *)qh;
363 OOP_GetAttr(sync, aHidd_Sync_MonitorSpec, (IPTR *)&mi->Mspc);
366 mi->ViewPosition.X = ?;
367 mi->ViewPosition.Y = ?;
368 mi->MinRow = ?;
369 mi->MouseTicks.X = ?;
370 mi->MouseTicks.Y = ?;
371 mi->DefaultViewPosition.X = ?;
372 mi->DefaultViewPosition.Y = ?;
375 /* Resolution in ticks */
376 CalcScreenResolution(&mi->ViewResolution, mi->Mspc, sync, GfxBase);
378 mi->TotalRows = mi->Mspc->total_rows;
379 mi->TotalColorClocks = mi->Mspc->total_colorclocks;
380 mi->ViewPositionRange = mi->Mspc->ms_LegalView;
383 * FIXME: For now we don't have a concept of preferred ModeID.
384 * However, see graphics_driver.c/driver_Setup(), it can be useful.
386 mi->PreferredModeID = ID;
388 if (DIH(handle)->drv->composer)
391 * If we have software screen composition, we know we can compose.
392 * We use MCOMPAT_MIXED here because of changed understanding of what is "monitor".
393 * In AmigaOS(tm) a "monitor" is actually a sync (video mode). Different "monitors"
394 * are actually different modes of the same display (PAL, NTSC, VGA, etc).
395 * In AROS a "monitor" is a single physical display device. Of course we can do
396 * composition only on a single display, but we can compose together different
397 * syncs.
399 mi->Compatibility = MCOMPAT_MIXED;
401 else
403 /* Otherwise query the driver */
404 HIDD_Gfx_ModeProperties(gfxhidd, hiddmode, &HIDDProps, sizeof(HIDDProps));
406 if (HIDDProps.CompositionFlags)
407 mi->Compatibility = (HIDDProps.CompositionFlags & COMPF_SAME) ? MCOMPAT_SELF : MCOMPAT_MIXED;
408 else
409 mi->Compatibility = MCOMPAT_NOBODY;
412 break;
415 case DTAG_NAME:
417 struct NameInfo *ni;
418 IPTR depth, stdpixfmt;
419 STRPTR sync_description;
421 OOP_GetAttr(pf, aHidd_PixFmt_Depth, &depth);
422 OOP_GetAttr(pf, aHidd_PixFmt_StdPixFmt, &stdpixfmt);
424 OOP_GetAttr(sync, aHidd_Sync_Description, (IPTR *)&sync_description);
425 ni = (struct NameInfo *)qh;
427 if (sync_description && sync_description[0] &&
428 (IS_REAL_STDPIXFMT(stdpixfmt) || (stdpixfmt == vHidd_StdPixFmt_Unknown)))
430 STRPTR pixfmt_name = "";
432 switch(stdpixfmt)
434 case vHidd_StdPixFmt_RGB16:
435 case vHidd_StdPixFmt_RGB15:
436 case vHidd_StdPixFmt_RGB24:
437 pixfmt_name = "RGB";
438 break;
440 case vHidd_StdPixFmt_RGB16_LE:
441 case vHidd_StdPixFmt_RGB15_LE:
442 pixfmt_name = "RGB PC";
443 break;
445 case vHidd_StdPixFmt_BGR24:
446 case vHidd_StdPixFmt_BGR16:
447 case vHidd_StdPixFmt_BGR15:
448 pixfmt_name = "BGR";
449 break;
451 case vHidd_StdPixFmt_BGR16_LE:
452 case vHidd_StdPixFmt_BGR15_LE:
453 pixfmt_name = "BGR PC";
454 break;
456 case vHidd_StdPixFmt_ARGB32:
457 pixfmt_name = "ARGB";
458 break;
460 case vHidd_StdPixFmt_BGRA32:
461 pixfmt_name = "BGRA";
462 break;
464 case vHidd_StdPixFmt_RGBA32:
465 pixfmt_name = "RGBA";
466 break;
468 case vHidd_StdPixFmt_0RGB32:
469 pixfmt_name = "0RGB";
470 break;
472 case vHidd_StdPixFmt_BGR032:
473 pixfmt_name = "BGR0";
474 break;
476 case vHidd_StdPixFmt_RGB032:
477 pixfmt_name = "RGB0";
478 break;
481 if (stdpixfmt != vHidd_StdPixFmt_Plane)
482 snprintf(ni->Name, DISPLAYNAMELEN, "%s %2dbit %s",
483 sync_description, (int)depth, pixfmt_name);
484 else
485 strncpy(ni->Name, sync_description, DISPLAYNAMELEN);
487 else
489 IPTR width = 0;
490 IPTR height = 0;
492 OOP_GetAttr(sync, aHidd_Sync_HDisp, &width);
493 OOP_GetAttr(sync, aHidd_Sync_VDisp, &height);
494 snprintf(ni->Name, DISPLAYNAMELEN, "AROS: %ldx%ldx%ld", width, height, depth);
496 break;
499 default:
500 D(bug("!!! UNKNOWN tagID IN CALL TO GetDisplayInfoData() !!!\n"));
501 break;
504 D(bug("GDID: %d\n", structsize));
506 if (size > structsize)
507 size = structsize;
508 CopyMem(qh, buf, size);
509 FreeMem(qh, structsize);
510 /* NULL-terminate the name in case if it was trimmed */
511 if (tagID == DTAG_NAME)
512 buf[size - 1] = 0;
514 return size;
516 AROS_LIBFUNC_EXIT
518 } /* GetDisplayInfoData */
520 /****************************************************************************************/
522 static ULONG check_sizes(ULONG tagID, ULONG size)
524 ULONG idx;
526 idx = DTAG_TO_IDX(tagID);
528 if (idx > KNOWN_IDS)
530 D(bug("!!! INVALID tagID TO GetDisplayInfoData"));
531 return 0;
534 return size_checks[idx];
537 /* taken from http://en.wikipedia.org/wiki/Hamming_weight */
538 static UBYTE popcount(IPTR x) {
539 UBYTE count;
540 for (count=0; x; count++)
541 x &= x-1;
542 return count;