| /* |
| * Graphics driver management functions |
| * |
| * Copyright 1996 Alexandre Julliard |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| |
| #include "config.h" |
| #include "wine/port.h" |
| |
| #include <string.h> |
| #include "winbase.h" |
| #include "winreg.h" |
| |
| #include "gdi.h" |
| #include "wine/debug.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(driver); |
| |
| struct graphics_driver |
| { |
| struct graphics_driver *next; |
| struct graphics_driver *prev; |
| HMODULE module; /* module handle */ |
| unsigned int count; /* reference count */ |
| DC_FUNCTIONS funcs; |
| }; |
| |
| static struct graphics_driver *first_driver; |
| static struct graphics_driver *display_driver; |
| static CRITICAL_SECTION driver_section = CRITICAL_SECTION_INIT( "driver_section" ); |
| |
| /********************************************************************** |
| * create_driver |
| * |
| * Allocate and fill the driver structure for a given module. |
| */ |
| static struct graphics_driver *create_driver( HMODULE module ) |
| { |
| struct graphics_driver *driver; |
| |
| if (!(driver = HeapAlloc( GetProcessHeap(), 0, sizeof(*driver)))) return NULL; |
| driver->next = NULL; |
| driver->prev = NULL; |
| driver->module = module; |
| driver->count = 1; |
| |
| /* fill the function table */ |
| |
| #define GET_FUNC(name) driver->funcs.p##name = (void*)GetProcAddress( module, #name ) |
| |
| GET_FUNC(AbortDoc); |
| GET_FUNC(AbortPath); |
| GET_FUNC(AngleArc); |
| GET_FUNC(Arc); |
| GET_FUNC(ArcTo); |
| GET_FUNC(BeginPath); |
| GET_FUNC(BitBlt); |
| GET_FUNC(ChoosePixelFormat); |
| GET_FUNC(Chord); |
| GET_FUNC(CloseFigure); |
| GET_FUNC(CreateBitmap); |
| GET_FUNC(CreateDC); |
| GET_FUNC(CreateDIBSection); |
| GET_FUNC(DeleteBitmap); |
| GET_FUNC(DeleteDC); |
| GET_FUNC(DescribePixelFormat); |
| GET_FUNC(DeviceCapabilities); |
| GET_FUNC(Ellipse); |
| GET_FUNC(EndDoc); |
| GET_FUNC(EndPage); |
| GET_FUNC(EndPath); |
| GET_FUNC(EnumDeviceFonts); |
| GET_FUNC(ExcludeClipRect); |
| GET_FUNC(ExtDeviceMode); |
| GET_FUNC(ExtEscape); |
| GET_FUNC(ExtFloodFill); |
| GET_FUNC(ExtSelectClipRgn); |
| GET_FUNC(ExtTextOut); |
| GET_FUNC(FillPath); |
| GET_FUNC(FillRgn); |
| GET_FUNC(FlattenPath); |
| GET_FUNC(FrameRgn); |
| GET_FUNC(GdiComment); |
| GET_FUNC(GetBitmapBits); |
| GET_FUNC(GetCharWidth); |
| GET_FUNC(GetDCOrgEx); |
| GET_FUNC(GetDIBColorTable); |
| GET_FUNC(GetDIBits); |
| GET_FUNC(GetDeviceCaps); |
| GET_FUNC(GetDeviceGammaRamp); |
| GET_FUNC(GetNearestColor); |
| GET_FUNC(GetPixel); |
| GET_FUNC(GetPixelFormat); |
| GET_FUNC(GetSystemPaletteEntries); |
| GET_FUNC(GetTextExtentPoint); |
| GET_FUNC(GetTextMetrics); |
| GET_FUNC(IntersectClipRect); |
| GET_FUNC(InvertRgn); |
| GET_FUNC(LineTo); |
| GET_FUNC(MoveTo); |
| GET_FUNC(ModifyWorldTransform); |
| GET_FUNC(OffsetClipRgn); |
| GET_FUNC(OffsetViewportOrg); |
| GET_FUNC(OffsetWindowOrg); |
| GET_FUNC(PaintRgn); |
| GET_FUNC(PatBlt); |
| GET_FUNC(Pie); |
| GET_FUNC(PolyBezier); |
| GET_FUNC(PolyBezierTo); |
| GET_FUNC(PolyDraw); |
| GET_FUNC(PolyPolygon); |
| GET_FUNC(PolyPolyline); |
| GET_FUNC(Polygon); |
| GET_FUNC(Polyline); |
| GET_FUNC(PolylineTo); |
| GET_FUNC(RealizeDefaultPalette); |
| GET_FUNC(RealizePalette); |
| GET_FUNC(Rectangle); |
| GET_FUNC(ResetDC); |
| GET_FUNC(RestoreDC); |
| GET_FUNC(RoundRect); |
| GET_FUNC(SaveDC); |
| GET_FUNC(ScaleViewportExt); |
| GET_FUNC(ScaleWindowExt); |
| GET_FUNC(SelectBitmap); |
| GET_FUNC(SelectBrush); |
| GET_FUNC(SelectClipPath); |
| GET_FUNC(SelectFont); |
| GET_FUNC(SelectPalette); |
| GET_FUNC(SelectPen); |
| GET_FUNC(SetBitmapBits); |
| GET_FUNC(SetBkColor); |
| GET_FUNC(SetBkMode); |
| GET_FUNC(SetDCOrg); |
| GET_FUNC(SetDIBColorTable); |
| GET_FUNC(SetDIBits); |
| GET_FUNC(SetDIBitsToDevice); |
| GET_FUNC(SetDeviceClipping); |
| GET_FUNC(SetDeviceGammaRamp); |
| GET_FUNC(SetMapMode); |
| GET_FUNC(SetMapperFlags); |
| GET_FUNC(SetPixel); |
| GET_FUNC(SetPixelFormat); |
| GET_FUNC(SetPolyFillMode); |
| GET_FUNC(SetROP2); |
| GET_FUNC(SetRelAbs); |
| GET_FUNC(SetStretchBltMode); |
| GET_FUNC(SetTextAlign); |
| GET_FUNC(SetTextCharacterExtra); |
| GET_FUNC(SetTextColor); |
| GET_FUNC(SetTextJustification); |
| GET_FUNC(SetViewportExt); |
| GET_FUNC(SetViewportOrg); |
| GET_FUNC(SetWindowExt); |
| GET_FUNC(SetWindowOrg); |
| GET_FUNC(SetWorldTransform); |
| GET_FUNC(StartDoc); |
| GET_FUNC(StartPage); |
| GET_FUNC(StretchBlt); |
| GET_FUNC(StretchDIBits); |
| GET_FUNC(StrokeAndFillPath); |
| GET_FUNC(StrokePath); |
| GET_FUNC(SwapBuffers); |
| GET_FUNC(WidenPath); |
| #undef GET_FUNC |
| |
| /* add it to the list */ |
| driver->prev = NULL; |
| if ((driver->next = first_driver)) driver->next->prev = driver; |
| first_driver = driver; |
| return driver; |
| } |
| |
| |
| /********************************************************************** |
| * load_display_driver |
| * |
| * Special case for loading the display driver: get the name from the config file |
| */ |
| static struct graphics_driver *load_display_driver(void) |
| { |
| char buffer[MAX_PATH]; |
| HMODULE module; |
| HKEY hkey; |
| |
| if (display_driver) /* already loaded */ |
| { |
| display_driver->count++; |
| return display_driver; |
| } |
| |
| strcpy( buffer, "x11drv" ); /* default value */ |
| if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\Wine", &hkey )) |
| { |
| DWORD type, count = sizeof(buffer); |
| RegQueryValueExA( hkey, "GraphicsDriver", 0, &type, buffer, &count ); |
| RegCloseKey( hkey ); |
| } |
| |
| if (!(module = LoadLibraryA( buffer ))) |
| { |
| MESSAGE( "Could not load graphics driver '%s'\n", buffer ); |
| return NULL; |
| } |
| |
| if (!(display_driver = create_driver( module ))) |
| { |
| MESSAGE( "Could not create graphics driver '%s'\n", buffer ); |
| FreeLibrary( module ); |
| return NULL; |
| } |
| |
| display_driver->count++; /* we don't want to free it */ |
| return display_driver; |
| } |
| |
| |
| /********************************************************************** |
| * DRIVER_load_driver |
| */ |
| const DC_FUNCTIONS *DRIVER_load_driver( LPCSTR name ) |
| { |
| HMODULE module; |
| struct graphics_driver *driver; |
| |
| EnterCriticalSection( &driver_section ); |
| |
| /* display driver is a special case */ |
| if (!strcasecmp( name, "display" )) |
| { |
| driver = load_display_driver(); |
| LeaveCriticalSection( &driver_section ); |
| return &driver->funcs; |
| } |
| |
| if ((module = GetModuleHandleA( name ))) |
| { |
| for (driver = first_driver; driver; driver = driver->next) |
| { |
| if (driver->module == module) |
| { |
| driver->count++; |
| LeaveCriticalSection( &driver_section ); |
| return &driver->funcs; |
| } |
| } |
| } |
| |
| if (!(module = LoadLibraryA( name ))) |
| { |
| LeaveCriticalSection( &driver_section ); |
| return NULL; |
| } |
| |
| if (!(driver = create_driver( module ))) |
| { |
| FreeLibrary( module ); |
| LeaveCriticalSection( &driver_section ); |
| return NULL; |
| } |
| |
| TRACE( "loaded driver %p for %s\n", driver, name ); |
| LeaveCriticalSection( &driver_section ); |
| return &driver->funcs; |
| } |
| |
| |
| /********************************************************************** |
| * DRIVER_get_driver |
| * |
| * Get a new copy of an existing driver. |
| */ |
| const DC_FUNCTIONS *DRIVER_get_driver( const DC_FUNCTIONS *funcs ) |
| { |
| struct graphics_driver *driver; |
| |
| EnterCriticalSection( &driver_section ); |
| for (driver = first_driver; driver; driver = driver->next) |
| if (&driver->funcs == funcs) break; |
| if (!driver) ERR( "driver not found, trouble ahead\n" ); |
| driver->count++; |
| LeaveCriticalSection( &driver_section ); |
| return funcs; |
| } |
| |
| |
| /********************************************************************** |
| * DRIVER_release_driver |
| * |
| * Release a driver by decrementing ref count and freeing it if needed. |
| */ |
| void DRIVER_release_driver( const DC_FUNCTIONS *funcs ) |
| { |
| struct graphics_driver *driver; |
| |
| EnterCriticalSection( &driver_section ); |
| |
| for (driver = first_driver; driver; driver = driver->next) |
| if (&driver->funcs == funcs) break; |
| |
| if (!driver) goto done; |
| if (--driver->count) goto done; |
| |
| /* removed last reference, free it */ |
| if (driver->next) driver->next->prev = driver->prev; |
| if (driver->prev) driver->prev->next = driver->next; |
| else first_driver = driver->next; |
| if (driver == display_driver) display_driver = NULL; |
| |
| FreeLibrary( driver->module ); |
| HeapFree( GetProcessHeap(), 0, driver ); |
| done: |
| LeaveCriticalSection( &driver_section ); |
| } |
| |
| |
| /***************************************************************************** |
| * DRIVER_GetDriverName |
| * |
| */ |
| BOOL DRIVER_GetDriverName( LPCSTR device, LPSTR driver, DWORD size ) |
| { |
| char *p; |
| |
| /* display is a special case */ |
| if (!strcasecmp( device, "display" )) |
| { |
| lstrcpynA( driver, "display", size ); |
| return TRUE; |
| } |
| |
| size = GetProfileStringA("devices", device, "", driver, size); |
| if(!size) { |
| WARN("Unable to find '%s' in [devices] section of win.ini\n", device); |
| return FALSE; |
| } |
| p = strchr(driver, ','); |
| if(!p) |
| { |
| WARN("'%s' entry in [devices] section of win.ini is malformed.\n", device); |
| return FALSE; |
| } |
| *p = '\0'; |
| TRACE("Found '%s' for '%s'\n", driver, device); |
| return TRUE; |
| } |
| |
| /***************************************************************************** |
| * @ [GDI32.100] |
| * |
| * This should thunk to 16-bit and simply call the proc with the given args. |
| */ |
| INT WINAPI GDI_CallDevInstall16( FARPROC16 lpfnDevInstallProc, HWND hWnd, |
| LPSTR lpModelName, LPSTR OldPort, LPSTR NewPort ) |
| { |
| FIXME("(%p, %p, %s, %s, %s)\n", lpfnDevInstallProc, hWnd, lpModelName, OldPort, NewPort ); |
| return -1; |
| } |
| |
| /***************************************************************************** |
| * @ [GDI32.101] |
| * |
| * This should load the correct driver for lpszDevice and calls this driver's |
| * ExtDeviceModePropSheet proc. |
| * |
| * Note: The driver calls a callback routine for each property sheet page; these |
| * pages are supposed to be filled into the structure pointed to by lpPropSheet. |
| * The layout of this structure is: |
| * |
| * struct |
| * { |
| * DWORD nPages; |
| * DWORD unknown; |
| * HPROPSHEETPAGE pages[10]; |
| * }; |
| */ |
| INT WINAPI GDI_CallExtDeviceModePropSheet16( HWND hWnd, LPCSTR lpszDevice, |
| LPCSTR lpszPort, LPVOID lpPropSheet ) |
| { |
| FIXME("(%p, %s, %s, %p)\n", hWnd, lpszDevice, lpszPort, lpPropSheet ); |
| return -1; |
| } |
| |
| /***************************************************************************** |
| * @ [GDI32.102] |
| * |
| * This should load the correct driver for lpszDevice and calls this driver's |
| * ExtDeviceMode proc. |
| */ |
| INT WINAPI GDI_CallExtDeviceMode16( HWND hwnd, |
| LPDEVMODEA lpdmOutput, LPSTR lpszDevice, |
| LPSTR lpszPort, LPDEVMODEA lpdmInput, |
| LPSTR lpszProfile, DWORD fwMode ) |
| { |
| char buf[300]; |
| HDC hdc; |
| DC *dc; |
| INT ret = -1; |
| INT (*pExtDeviceMode)(LPSTR,HWND,LPDEVMODEA,LPSTR,LPSTR,LPDEVMODEA,LPSTR,DWORD); |
| |
| TRACE("(%p, %p, %s, %s, %p, %s, %ld)\n", |
| hwnd, lpdmOutput, lpszDevice, lpszPort, lpdmInput, lpszProfile, fwMode ); |
| |
| if(!DRIVER_GetDriverName( lpszDevice, buf, sizeof(buf) )) return -1; |
| |
| if (!(hdc = CreateICA( buf, lpszDevice, lpszPort, NULL ))) return -1; |
| |
| if ((dc = DC_GetDCPtr( hdc ))) |
| { |
| pExtDeviceMode = dc->funcs->pExtDeviceMode; |
| GDI_ReleaseObj( hdc ); |
| if (pExtDeviceMode) |
| ret = pExtDeviceMode(buf, hwnd, lpdmOutput, lpszDevice, lpszPort, |
| lpdmInput, lpszProfile, fwMode); |
| } |
| DeleteDC( hdc ); |
| return ret; |
| } |
| |
| /**************************************************************************** |
| * @ [GDI32.103] |
| * |
| * This should load the correct driver for lpszDevice and calls this driver's |
| * AdvancedSetupDialog proc. |
| */ |
| INT WINAPI GDI_CallAdvancedSetupDialog16( HWND hwnd, LPSTR lpszDevice, |
| LPDEVMODEA devin, LPDEVMODEA devout ) |
| { |
| TRACE("(%p, %s, %p, %p)\n", hwnd, lpszDevice, devin, devout ); |
| return -1; |
| } |
| |
| /***************************************************************************** |
| * @ [GDI32.104] |
| * |
| * This should load the correct driver for lpszDevice and calls this driver's |
| * DeviceCapabilities proc. |
| */ |
| DWORD WINAPI GDI_CallDeviceCapabilities16( LPCSTR lpszDevice, LPCSTR lpszPort, |
| WORD fwCapability, LPSTR lpszOutput, |
| LPDEVMODEA lpdm ) |
| { |
| char buf[300]; |
| HDC hdc; |
| DC *dc; |
| INT ret = -1; |
| |
| TRACE("(%s, %s, %d, %p, %p)\n", lpszDevice, lpszPort, fwCapability, lpszOutput, lpdm ); |
| |
| if(!DRIVER_GetDriverName( lpszDevice, buf, sizeof(buf) )) return -1; |
| |
| if (!(hdc = CreateICA( buf, lpszDevice, lpszPort, NULL ))) return -1; |
| |
| if ((dc = DC_GetDCPtr( hdc ))) |
| { |
| if (dc->funcs->pDeviceCapabilities) |
| ret = dc->funcs->pDeviceCapabilities( buf, lpszDevice, lpszPort, |
| fwCapability, lpszOutput, lpdm ); |
| GDI_ReleaseObj( hdc ); |
| } |
| DeleteDC( hdc ); |
| return ret; |
| } |