Initial commit
This commit is contained in:
282
libsst-wm/API.c
Normal file
282
libsst-wm/API.c
Normal file
@@ -0,0 +1,282 @@
|
||||
/*
|
||||
API.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 1/8/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
The libsst-wm API. Mostly calls into the current driver.
|
||||
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
#include "APIPrivate.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
#if defined(HAVE_XLIB)
|
||||
extern struct SST_WM_Driver XlibDriver;
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
extern struct SST_WM_Driver Win32Driver;
|
||||
#endif
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const static struct SST_WM_Driver* drivers[] = {
|
||||
#if defined(HAVE_XLIB)
|
||||
&XlibDriver,
|
||||
#endif
|
||||
#if defined(_WIN32)
|
||||
&Win32Driver,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct SST_WM_Driver* driver = NULL;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
int SST_WM_Init(void) {
|
||||
size_t i;
|
||||
/* Try to initialize a driver. If it fails, then try the next. First successful one wins */
|
||||
for(i=0; drivers[i] != NULL; i++) {
|
||||
if(drivers[i]->init() != 0) {
|
||||
driver = drivers[i];
|
||||
printf("libsst-wm: Using driver \"%s\"", driver->name);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* No suitable driver found */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void SST_WM_Shutdown(void) {
|
||||
if(driver != NULL) {
|
||||
driver->shutdown();
|
||||
driver = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
SST_DisplayTarget SST_WM_CreateDisplayTarget(size_t adapterIndex, size_t screenIndexOrMultihead) {
|
||||
return driver->window->CreateDisplayTarget(adapterIndex, screenIndexOrMultihead);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
size_t SST_WM_GetDisplayTargetScreenCount(SST_DisplayTarget target) {
|
||||
return driver->window->GetDisplayTargetScreenCount(target);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
SST_Window SST_WM_CreateWindowOnScreen(SST_DisplayTarget target, size_t screenIndex, uint32_t x, uint32_t y, uint32_t width, uint32_t height, const char* title) {
|
||||
return driver->window->CreateWindowOnScreen(target, screenIndex, x, y, width, height, title);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
SST_DisplayTarget SST_WM_GetWindowDisplayTarget(SST_Window window) {
|
||||
return driver->window->GetWindowDisplayTarget(window);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void SST_WM_SetWindowText(SST_Window window, const char* titleBar) {
|
||||
driver->window->SetWindowText(window, titleBar);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void SST_WM_GetWindowRect(SST_Window window, SST_Rect* rectReturn) {
|
||||
driver->window->GetWindowRect(window, rectReturn);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void SST_WM_MoveWindowOnScreen(SST_Window window, size_t screenIndex, uint32_t x, uint32_t y) {
|
||||
driver->window->MoveWindowOnScreen(window, screenIndex, x, y);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void SST_WM_ResizeWindow(SST_Window window, uint32_t width, uint32_t height) {
|
||||
driver->window->ResizeWindow(window, width, height);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
int SST_WM_ShowDialogBox(SST_DisplayTarget target, SST_Window parent, const char* caption, const char* message, const char** buttons, int nrButtons) {
|
||||
return driver->window->ShowDialogBox(target, parent, caption, message, buttons, nrButtons);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void SST_WM_SetWindowState(SST_Window window, SST_WMWindowState state, uint32_t param) {
|
||||
driver->window->SetWindowState(window, state, param);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void SST_WM_SetDisplayTargetState(SST_DisplayTarget target, SST_WMDisplayTargetState state, uint32_t param) {
|
||||
driver->window->SetDisplayTargetState(target, state, param);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void SST_WM_DestroyWindow(SST_Window window) {
|
||||
driver->window->DestroyWindow(window);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void SST_WM_DestroyDisplayTarget(SST_DisplayTarget target) {
|
||||
driver->window->DestroyDisplayTarget(target);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
SST_GraphicsEnumerator SST_WM_CreateGraphicsEnumerator(void) {
|
||||
return driver->enumf->CreateGraphicsEnumerator();
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
size_t SST_WM_GetEnumAdapterCount(SST_GraphicsEnumerator enumerator) {
|
||||
return driver->enumf->GetEnumAdapterCount(enumerator);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void SST_WM_GetEnumAdapterName(SST_GraphicsEnumerator enumerator, size_t adapterIndex, char* nameReturn, size_t* bufferSize) {
|
||||
driver->enumf->GetEnumAdapterName(enumerator, adapterIndex, nameReturn, bufferSize);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
size_t SST_WM_GetEnumScreenCount(SST_GraphicsEnumerator enumerator, size_t adapterIndex) {
|
||||
return driver->enumf->GetEnumScreenCount(enumerator, adapterIndex);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void SST_WM_GetEnumVideoModes(SST_GraphicsEnumerator enumerator, size_t adapterIndex, size_t screenIndex, SST_VideoMode* modesReturn, size_t* modeCountReturn) {
|
||||
driver->enumf->GetEnumVideoModes(enumerator, adapterIndex, screenIndex, modesReturn, modeCountReturn);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void SST_WM_GetEnumCurrentVideoMode(SST_GraphicsEnumerator enumerator, size_t adapterIndex, size_t screenIndex, SST_VideoMode* mode) {
|
||||
driver->enumf->GetEnumCurrentVideoMode(enumerator, adapterIndex, screenIndex, mode);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void SST_WM_DestroyGraphicsEnumerator(SST_GraphicsEnumerator enumerator) {
|
||||
driver->enumf->DestroyGraphicsEnumerator(enumerator);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
int SST_WM_GetEvent(SST_DisplayTarget target, SST_WMEvent* eventReturn) {
|
||||
return driver->event->GetEvent(target, eventReturn);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
int SST_WM_SendUserEvent(SST_DisplayTarget target, const SST_WMEvent* event)
|
||||
{
|
||||
EventQueue* eq;
|
||||
SST_WMEvent* newEvent;
|
||||
|
||||
eq = driver->event->getUserEventQueue(target);
|
||||
|
||||
driver->event->lockUserEventQueue(target);
|
||||
newEvent = AllocSlotInEQ(eq);
|
||||
if(newEvent)
|
||||
memcpy(newEvent, event, sizeof(SST_WMEvent));
|
||||
driver->event->unlockUserEventQueue(target);
|
||||
|
||||
return (newEvent != NULL);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
SST_OpenGLContext SST_WM_CreateOpenGLContext(SST_DisplayTarget target, SST_WMOpenGLType apiType, const SST_OpenGLContextAttributes* attribs, SST_OpenGLContextAttributes* selectedAttribsReturn) {
|
||||
return driver->opengl->CreateOpenGLContext(target, apiType, attribs, selectedAttribsReturn);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
SST_OpenGLContext SST_WM_CreateSlaveOpenGLContext(SST_OpenGLContext masterGLContext) {
|
||||
return driver->opengl->CreateSlaveOpenGLContext(masterGLContext);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void SST_WM_SwapOpenGLBuffers(SST_OpenGLContext ctx) {
|
||||
driver->opengl->SwapOpenGLBuffers(ctx);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
int SST_WM_BindOpenGLContext(SST_OpenGLContext ctx, SST_Window window) {
|
||||
return driver->opengl->BindOpenGLContext(ctx, window);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void SST_WM_DestroyOpenGLContext(SST_OpenGLContext ctx) {
|
||||
driver->opengl->DestroyOpenGLContext(ctx);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
int SST_WM_EnableSoftwareRendering(SST_Window window) {
|
||||
return driver->render->EnableSoftwareRendering(window);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void SST_WM_DisableSoftwareRendering(SST_Window window) {
|
||||
driver->render->DisableSoftwareRendering(window);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void* SST_WM_LockBackbuffer(SST_Window window, size_t* pitchReturn) {
|
||||
return driver->render->LockBackbuffer(window, pitchReturn);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void SST_WM_UnlockBackbuffer(SST_Window window) {
|
||||
driver->render->UnlockBackbuffer(window);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
int SST_WM_SetVideoModeOnScreen(SST_DisplayTarget target, size_t screenIndex, const SST_VideoMode* vmode) {
|
||||
return driver->video->SetVideoModeOnScreen(target,screenIndex,vmode);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
int SST_WM_GetVideoModeOnScreen(SST_DisplayTarget target, size_t screenIndex, SST_VideoMode* vmodeReturn) {
|
||||
return driver->video->GetVideoModeOnScreen(target, screenIndex, vmodeReturn);
|
||||
}
|
||||
104
libsst-wm/APIPrivate.h
Normal file
104
libsst-wm/APIPrivate.h
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
APIPrivate.h
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 4/29/2014
|
||||
|
||||
Purpose:
|
||||
|
||||
Private API used internally for different WM drivers
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef _APIPRIVATE_H
|
||||
#define _APIPRIVATE_H
|
||||
|
||||
#include <SST/SST_WM.h>
|
||||
#include "EventQueue.h"
|
||||
|
||||
struct SST_WM_WindowFuncs
|
||||
{
|
||||
SST_DisplayTarget (*CreateDisplayTarget)(size_t adapterIndex, size_t screenIndexOrMultihead);
|
||||
size_t (*GetDisplayTargetScreenCount)(SST_DisplayTarget target);
|
||||
SST_Window (*CreateWindowOnScreen)(SST_DisplayTarget target, size_t screenIndex, uint32_t x, uint32_t y, uint32_t width, uint32_t height, const char* title);
|
||||
SST_DisplayTarget (*GetWindowDisplayTarget)(SST_Window window);
|
||||
void (*SetWindowText)(SST_Window window, const char* titleBar);
|
||||
void (*GetWindowRect)(SST_Window window, SST_Rect* rectReturn);
|
||||
void (*MoveWindowOnScreen)(SST_Window window, size_t screenIndex, uint32_t x, uint32_t y);
|
||||
void (*ResizeWindow)(SST_Window window, uint32_t width, uint32_t height);
|
||||
int (*ShowDialogBox)(SST_DisplayTarget target, SST_Window parent, const char* caption, const char* message, const char** buttons, int nrButtons);
|
||||
void (*SetWindowState)(SST_Window window, SST_WMWindowState state, uint32_t param);
|
||||
void (*SetDisplayTargetState)(SST_DisplayTarget target, SST_WMDisplayTargetState state, uint32_t param);
|
||||
void (*DestroyWindow)(SST_Window window);
|
||||
void (*DestroyDisplayTarget)(SST_DisplayTarget target);
|
||||
};
|
||||
|
||||
struct SST_WM_EnumFuncs
|
||||
{
|
||||
SST_GraphicsEnumerator (*CreateGraphicsEnumerator)(void);
|
||||
size_t (*GetEnumAdapterCount)(SST_GraphicsEnumerator enumerator);
|
||||
void (*GetEnumAdapterName)(SST_GraphicsEnumerator enumerator, size_t adapterIndex, char* nameReturn, size_t* bufferSize);
|
||||
size_t (*GetEnumScreenCount)(SST_GraphicsEnumerator enumerator, size_t adapterIndex);
|
||||
void (*GetEnumVideoModes)(SST_GraphicsEnumerator enumerator, size_t adapterIndex, size_t screenIndex, SST_VideoMode* modesReturn, size_t* modeCountReturn);
|
||||
void (*GetEnumCurrentVideoMode)(SST_GraphicsEnumerator enumerator, size_t adapterIndex, size_t screenIndex, SST_VideoMode* mode);
|
||||
void (*DestroyGraphicsEnumerator)(SST_GraphicsEnumerator enumerator);
|
||||
};
|
||||
|
||||
struct SST_WM_EventFuncs
|
||||
{
|
||||
int (*GetEvent)(SST_DisplayTarget target, SST_WMEvent* eventReturn);
|
||||
|
||||
/* These aren't public API, but they are driver-specific */
|
||||
EventQueue* (*getUserEventQueue)(SST_DisplayTarget target);
|
||||
void (*lockUserEventQueue)(SST_DisplayTarget target);
|
||||
void (*unlockUserEventQueue)(SST_DisplayTarget target);
|
||||
};
|
||||
|
||||
struct SST_WM_OpenGLFuncs
|
||||
{
|
||||
SST_OpenGLContext (*CreateOpenGLContext)(SST_DisplayTarget target, SST_WMOpenGLType apiType, const SST_OpenGLContextAttributes* attribs, SST_OpenGLContextAttributes* selectedAttribsReturn);
|
||||
SST_OpenGLContext(*CreateSlaveOpenGLContext)(SST_OpenGLContext masterGLContext);
|
||||
void (*SwapOpenGLBuffers)(SST_OpenGLContext ctx);
|
||||
int (*BindOpenGLContext)(SST_OpenGLContext ctx, SST_Window window);
|
||||
void (*DestroyOpenGLContext)(SST_OpenGLContext ctx);
|
||||
};
|
||||
|
||||
struct SST_WM_RenderFuncs
|
||||
{
|
||||
int (*EnableSoftwareRendering)(SST_Window window);
|
||||
void (*DisableSoftwareRendering)(SST_Window window);
|
||||
void* (*LockBackbuffer)(SST_Window window, size_t* pitchReturn);
|
||||
void (*UnlockBackbuffer)(SST_Window window);
|
||||
};
|
||||
|
||||
struct SST_WM_VideoModeFuncs
|
||||
{
|
||||
int (*SetVideoModeOnScreen)(SST_DisplayTarget target, size_t screenIndex, const SST_VideoMode* vmode);
|
||||
int (*GetVideoModeOnScreen)(SST_DisplayTarget target, size_t screenIndex, SST_VideoMode* vmodeReturn);
|
||||
|
||||
};
|
||||
|
||||
struct SST_WM_Driver
|
||||
{
|
||||
const char* name;
|
||||
int (*init)();
|
||||
void (*shutdown)();
|
||||
const struct SST_WM_WindowFuncs* window; /* SST_WMWindow.h */
|
||||
const struct SST_WM_EnumFuncs* enumf; /* SST_WMEnum.h */
|
||||
const struct SST_WM_EventFuncs* event; /* SST_WMEvent.h */
|
||||
const struct SST_WM_OpenGLFuncs* opengl; /* SST_WMOpenGL.h */
|
||||
const struct SST_WM_RenderFuncs* render; /* SST_WMREnder.h */
|
||||
const struct SST_WM_VideoModeFuncs* video; /* SST_WMVideoMode.h */
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
147
libsst-wm/EventQueue.h
Normal file
147
libsst-wm/EventQueue.h
Normal file
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
EventQueue.h
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 6/18/2012
|
||||
|
||||
Purpose:
|
||||
|
||||
Common event queue code for libsst-wm implementations
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef _EVENTQUEUE_H
|
||||
#define _EVENTQUEUE_H
|
||||
|
||||
#include <SST/SST_WMEvent.h>
|
||||
#include <SST/SST_Build.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct EventQueue
|
||||
{
|
||||
SST_WMEvent* events;
|
||||
size_t head; /* Index of next item to add (i.e. unused slot) */
|
||||
size_t tail; /* Index of next item to remove (i.e. used slot) */
|
||||
size_t count; /* Number of items in the queue */
|
||||
size_t storageSize; /* Size of the backing storage */
|
||||
} EventQueue;
|
||||
|
||||
#define EQ_DEFAULT_SIZE 32 /* Default capacity of the event queue. It may grow beyond this. */
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
/* Initialize an event queue structure, returning non-zero if successful */
|
||||
static INLINE int InitEQ(EventQueue* q)
|
||||
{
|
||||
/* Allocate raw storage for event queue */
|
||||
q->events = (SST_WMEvent*)malloc(EQ_DEFAULT_SIZE * sizeof(SST_WMEvent));
|
||||
if(q->events == NULL)
|
||||
return 0;
|
||||
|
||||
/* Initialize storage */
|
||||
q->head = 0;
|
||||
q->tail = 0;
|
||||
q->count = 0;
|
||||
q->storageSize = EQ_DEFAULT_SIZE;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
/* Allocate a slot from the queue (as if adding) and return pointer. This manually
|
||||
eliminates copying a SST_WMEvent structure that most "enqueue" operation require. */
|
||||
static INLINE SST_WMEvent* AllocSlotInEQ(EventQueue* q)
|
||||
{
|
||||
SST_WMEvent* slot;
|
||||
|
||||
/* Need to increase capacity? */
|
||||
if(q->head == q->tail && q->count == q->storageSize)
|
||||
{
|
||||
const size_t newSize = q->storageSize * 2;
|
||||
SST_WMEvent* events;
|
||||
|
||||
/* Expand the queue */
|
||||
events = realloc(q->events, newSize * sizeof(SST_WMEvent));
|
||||
if(events == NULL)
|
||||
return NULL;
|
||||
|
||||
/* All 'count' items from [0,tail] need to be moved to [oldSize, oldSize+count] */
|
||||
if(q->tail != 0)
|
||||
{
|
||||
/*
|
||||
1) A full queue
|
||||
v--h
|
||||
[G][H][A][B][C][D][E][F]
|
||||
^--t
|
||||
|
||||
2) Resized
|
||||
v--h
|
||||
[G][H][A][B][C][D][E][F][ ][ ][ ][ ][ ][ ][ ][ ]
|
||||
^--t
|
||||
|
||||
3) Shift elements from 0 to tail to end, update head ptr
|
||||
v--h
|
||||
[ ][ ][A][B][C][D][E][F][G][H][ ][ ][ ][ ][ ][ ]
|
||||
^--t
|
||||
|
||||
*/
|
||||
|
||||
/* Shift elements */
|
||||
memmove(&events[q->storageSize], &events[0], q->tail * sizeof(SST_WMEvent));
|
||||
|
||||
}
|
||||
|
||||
/* Adjust head pointer to point to next empty slot */
|
||||
q->head = q->tail + q->storageSize;
|
||||
|
||||
/* Update storage fields */
|
||||
q->storageSize = newSize;
|
||||
q->events = events;
|
||||
} /* if(needed to increase capacity) */
|
||||
|
||||
/* Get the pointer to the slot where the event may be stored */
|
||||
slot = &q->events[q->head];
|
||||
|
||||
/* Advance the head pointer by 1 */
|
||||
q->head = (q->head + 1) % q->storageSize;
|
||||
q->count += 1;
|
||||
|
||||
/* Return the slot */
|
||||
return slot;
|
||||
}
|
||||
|
||||
static INLINE int RemoveFromEQ(EventQueue* q, SST_WMEvent* event)
|
||||
{
|
||||
/* Completely empty? */
|
||||
if(q->head == q->tail && q->count != q->storageSize)
|
||||
return 0;
|
||||
|
||||
/* Copy the structure */
|
||||
*event = q->events[q->tail];
|
||||
|
||||
/* Advance the tail pointer by 1 */
|
||||
q->tail = (q->tail + 1) % q->storageSize;
|
||||
q->count -= 1;
|
||||
|
||||
/* OK */
|
||||
return 1;
|
||||
}
|
||||
|
||||
static INLINE void DestroyEQ(EventQueue* q)
|
||||
{
|
||||
if(q->events != NULL)
|
||||
free(q->events);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
32
libsst-wm/MacOSX/MacOSXPrivate.h
Normal file
32
libsst-wm/MacOSX/MacOSXPrivate.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
MacOSXPrivate.h
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 1/7/2012
|
||||
|
||||
Purpose:
|
||||
|
||||
Private defintions and functions for MacOS X implementation of libsst-wm
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef _MACOSXPRIVATE_H
|
||||
#define _MACOSXPRIVATE_H
|
||||
|
||||
typedef struct SST_GraphicsEnumerator_MacOSX
|
||||
{
|
||||
size_t nrAdapters;
|
||||
size_t nrScreens;
|
||||
} SST_GraphicsEnumerator_MacOSX;
|
||||
|
||||
#endif
|
||||
|
||||
145
libsst-wm/MacOSX/SST_WMEnum_MacOSX.m
Normal file
145
libsst-wm/MacOSX/SST_WMEnum_MacOSX.m
Normal file
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
SST_WMEnum_MacOSX.m
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 11/16/2012
|
||||
|
||||
Purpose:
|
||||
|
||||
Enumerates graphics adapters and screens on MacOS X
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <IOKit/IOKitLib.h>
|
||||
|
||||
#include <SST/SST_WM.h>
|
||||
#include "MacOSXPrivate.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
SST_GraphicsEnumerator SST_WM_CreateGraphicsEnumerator(void)
|
||||
{
|
||||
SST_GraphicsEnumerator_MacOSX* enumerator;
|
||||
uint32_t count = 0, i;
|
||||
CGDirectDisplayID* ids;
|
||||
|
||||
/* Get list of active displays */
|
||||
CGGetActiveDisplayList(UINT32_MAX, NULL, &count);
|
||||
if(count == 0)
|
||||
return NULL;
|
||||
|
||||
/* Allocate array of displays, then fetch */
|
||||
ids = malloc(sizeof(CGDirectDisplayID) * count);
|
||||
if(ids == NULL)
|
||||
return NULL;
|
||||
if(CGGetActiveDisplayList(count, ids, &count) != kCGErrorSuccess)
|
||||
{
|
||||
free(ids);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Match GPU to display */
|
||||
for(i=0; i<count; i++)
|
||||
{
|
||||
io_service_t port = CGDisplayIOServicePort(ids[i]); /* Port is owned by CG, don't release */
|
||||
|
||||
/* TODO: derp how does one do this using I/O Kit? */
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* Allocate enumerator object */
|
||||
enumerator = malloc(sizeof(SST_GraphicsEnumerator_MacOSX));
|
||||
if(enumerator == NULL)
|
||||
return NULL;
|
||||
|
||||
|
||||
|
||||
|
||||
return (SST_GraphicsEnumerator)enumerator;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
size_t SST_WM_GetEnumAdapterCount(SST_GraphicsEnumerator enumerator)
|
||||
{
|
||||
/* TODO: Implement */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void SST_WM_GetEnumAdapterName(SST_GraphicsEnumerator enumerator, size_t adapterId,char* nameReturn, size_t* bufferSize)
|
||||
{
|
||||
/* TODO: Implement fully */
|
||||
const char* s = "Default Adapter";
|
||||
|
||||
/* Query name length */
|
||||
if(nameReturn == NULL)
|
||||
*bufferSize = strlen(s) + 1;
|
||||
else
|
||||
{
|
||||
size_t copyAmount;
|
||||
|
||||
/* Nothing to do? */
|
||||
if(*bufferSize == 0)
|
||||
return;
|
||||
|
||||
/* Use min(len, (*bufferSize)-1) */
|
||||
copyAmount = strlen(s);
|
||||
if(copyAmount > (*bufferSize)-1)
|
||||
copyAmount = (*bufferSize)-1;
|
||||
|
||||
memcpy(nameReturn, s, copyAmount);
|
||||
nameReturn[copyAmount] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
size_t SST_WM_GetEnumScreenCount(SST_GraphicsEnumerator enumerator, size_t adapterId)
|
||||
{
|
||||
/* TODO: Implement */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void SST_WM_GetEnumVideoModes(SST_GraphicsEnumerator enumerator, size_t adapterId, size_t screenId, SST_VideoMode* modesReturn, size_t* modeCountReturn)
|
||||
{
|
||||
/* TODO: Implement */
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void SST_WM_GetEnumCurrentVideoMode(SST_GraphicsEnumerator enumerator, size_t adapterId, size_t screenId, SST_VideoMode* mode)
|
||||
{
|
||||
/* TODO: Implement */
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void SST_WM_DestroyGraphicsEnumerator(SST_GraphicsEnumerator enumerator)
|
||||
{
|
||||
/* TODO: Implement */
|
||||
SST_GraphicsEnumerator_MacOSX* enumMac = (SST_GraphicsEnumerator_MacOSX*)enumerator;
|
||||
|
||||
free(enumMac);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
53
libsst-wm/Makefile
Normal file
53
libsst-wm/Makefile
Normal file
@@ -0,0 +1,53 @@
|
||||
# libsst-wm/Makefile
|
||||
# Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
# Created: 11/16/2012
|
||||
#
|
||||
# Purpose:
|
||||
#
|
||||
# Makefile for libsst-wm
|
||||
#
|
||||
# License:
|
||||
#
|
||||
# This program is free software. It comes without any warranty, to
|
||||
# the extent permitted by applicable law. You can redistribute it
|
||||
# and/or modify it under the terms of the Do What The Fuck You Want
|
||||
# To Public License, Version 2, as published by Sam Hocevar. See
|
||||
# http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
BINNAME := $(DIST)/libsst-wm.a
|
||||
ifeq ($(TARGET),debug)
|
||||
BINNAME := $(subst .a,_d.a, $(BINNAME))
|
||||
endif
|
||||
|
||||
# Now, include the window system drivers (detection occurs inside)
|
||||
#include Win32/sources.mk
|
||||
#include RaspPi/sources.mk
|
||||
include Xlib/sources.mk
|
||||
|
||||
SRC += API.c
|
||||
|
||||
OBJ := $(addprefix obj/$(ARCH)/$(TARGET)/,$(subst .m,.o,$(subst .c,.o,$(SRC))))
|
||||
$(shell mkdir -p obj/$(ARCH)/$(TARGET))
|
||||
$(shell mkdir -p obj/$(ARCH)/$(TARGET)/Xlib)
|
||||
$(shell mkdir -p obj/$(ARCH)/$(TARGET)/RaspPi)
|
||||
$(shell mkdir -p obj/$(ARCH)/$(TARGET)/Win32)
|
||||
$(shell mkdir -p obj/$(ARCH)/$(TARGET)/MacOSX)
|
||||
|
||||
$(BINNAME): $(OBJ)
|
||||
$(AR) cru $@ $+
|
||||
$(RANLIB) $@
|
||||
|
||||
# CLEAN
|
||||
clean:
|
||||
@-rm -r -f obj $(DIST)/libsst-wm*.a
|
||||
|
||||
# *.c files to *.o files
|
||||
obj/$(ARCH)/$(TARGET)/%.o: %.c
|
||||
@echo CC $@
|
||||
@$(CC) -I. $(CFLAGS) -c $*.c -o obj/$(ARCH)/$(TARGET)/$*.o
|
||||
|
||||
|
||||
# *.m files to *.o files (Mac)
|
||||
obj/$(ARCH)/$(TARGET)/%.o: %.m
|
||||
@echo OBJCC $@
|
||||
@$(CC) $(CFLAGS) -c $*.m -o obj/$(ARCH)/$(TARGET)/$*.o
|
||||
80
libsst-wm/RaspPi/RaspPiPrivate.h
Normal file
80
libsst-wm/RaspPi/RaspPiPrivate.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
RaspPiPrivate.h
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 6/25/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
Private defintions and functions for Raspberry Pi implementation of
|
||||
libsst-wm
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef _RASPPIPRIVATE_H
|
||||
#define _RASPPIPRIVATE_H
|
||||
|
||||
#include <bcm_host.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <SST/SST_WMTypes.h>
|
||||
#include "EventQueue.h"
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
struct SST_Window_RaspPi;
|
||||
|
||||
typedef struct SST_DisplayTarget_RaspPi
|
||||
{
|
||||
EventQueue eventQueue;
|
||||
EventQueue userEventQueue;
|
||||
uint8_t keymapBitvector[32]; /* Bitmap similar to XQueryKeymap() */
|
||||
pthread_mutex_t eventLock; /* Lock protecting user events */
|
||||
struct SST_Window_RaspPi* firstWindow; /* Window */
|
||||
int relativeMouse;
|
||||
DISPMANX_DISPLAY_HANDLE_T display;
|
||||
} SST_DisplayTarget_RaspPi;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
typedef struct SST_Window_RaspPi
|
||||
{
|
||||
SST_DisplayTarget_RaspPi* owner;
|
||||
struct SST_Window_RaspPi* next;
|
||||
int isFullscreen;
|
||||
uint32_t x, y;
|
||||
uint32_t w, h;
|
||||
|
||||
DISPMANX_ELEMENT_HANDLE_T element;
|
||||
|
||||
/* Software rendering support */
|
||||
void* softwareBackbuffer;
|
||||
uint32_t softwarePitch;
|
||||
DISPMANX_RESOURCE_HANDLE_T softwareImage;
|
||||
VC_RECT_T softwareRect;
|
||||
} SST_Window_RaspPi;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
typedef struct SST_OpenGLContext_RaspPi
|
||||
{
|
||||
SST_DisplayTarget_RaspPi* displayTarget;
|
||||
uint16_t ctxVersion[2]; /* context version major/minor */
|
||||
int debugEnabled; /* Did we use debug OpenGL context support? */
|
||||
|
||||
/* EGL fields */
|
||||
/* TODO */
|
||||
} SST_OpenGLContext_RaspPi;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
#endif
|
||||
49
libsst-wm/RaspPi/SST_WMDialogBox_RaspPi.c
Normal file
49
libsst-wm/RaspPi/SST_WMDialogBox_RaspPi.c
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
SST_WMDialogBox_RaspPi.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 6/25/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
Simple dialog box window
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#include "RaspPiPrivate.h"
|
||||
|
||||
#define BUTTON_HSPACE 16 /* Space on either side of a button */
|
||||
#define BUTTON_VSPACE 16 /* Space between top of button and dialog text */
|
||||
#define TEXT_HSPACE 16
|
||||
#define TEXT_VSPACE 16
|
||||
|
||||
typedef struct DialogBoxData
|
||||
{
|
||||
const char* message;
|
||||
int lenMessage;
|
||||
int buttonId;
|
||||
int exitTime;
|
||||
} DialogBoxData;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
int SST_WM_ShowDialogBox(SST_DisplayTarget target, SST_Window parent, const char* caption, const char* message, const char** buttons, int nrButtons)
|
||||
{
|
||||
/* TODO: helluvalota work */
|
||||
(void)target;
|
||||
(void)parent;
|
||||
(void)caption;
|
||||
(void)message;
|
||||
(void)buttons;
|
||||
(void)nrButtons;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
144
libsst-wm/RaspPi/SST_WMEnum_RaspPi.c
Normal file
144
libsst-wm/RaspPi/SST_WMEnum_RaspPi.c
Normal file
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
SST_WMEnum_RaspPi.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 5/31/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
Raspberry Pi native (no display server) port for Linux
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#include <SST/SST_WM.h>
|
||||
|
||||
#include <bcm_host.h> /* R-Pi header */
|
||||
|
||||
#include <string.h> /* strlen() etc. */
|
||||
#include <stdlib.h>
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
SST_GraphicsEnumerator SST_WM_CreateGraphicsEnumerator(void)
|
||||
{
|
||||
/* Call this just in case. Multiple calls do not affect anything */
|
||||
bcm_host_init();
|
||||
|
||||
return (void*)(uintptr_t)(0x40000000); /* No, it is meaningless */
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
size_t SST_WM_GetEnumAdapterCount(SST_GraphicsEnumerator enumerator)
|
||||
{
|
||||
(void)enumerator;
|
||||
|
||||
/* R-Pi only has the one on-chip device */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void SST_WM_GetEnumAdapterName(SST_GraphicsEnumerator enumerator, size_t adapterId, char* nameReturn, size_t* bufferSize)
|
||||
{
|
||||
size_t len;
|
||||
const char* name = "VideoCore IV (R) GPU";
|
||||
|
||||
(void)enumerator;
|
||||
(void)adapterId;
|
||||
|
||||
len = strlen(name);
|
||||
|
||||
/* Query name length */
|
||||
if(nameReturn == NULL)
|
||||
{
|
||||
*bufferSize = len+1;
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t copyAmount;
|
||||
|
||||
/* Nothing to do? */
|
||||
if(*bufferSize == 0)
|
||||
return;
|
||||
|
||||
/* Use min(len, (*bufferSize)-1) */
|
||||
copyAmount = len;
|
||||
if(copyAmount > (*bufferSize)-1)
|
||||
copyAmount = (*bufferSize)-1;
|
||||
|
||||
memcpy(nameReturn, name, copyAmount);
|
||||
nameReturn[copyAmount] = '\0';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
size_t SST_WM_GetEnumScreenCount(SST_GraphicsEnumerator enumerator, size_t adapterId)
|
||||
{
|
||||
(void)enumerator;
|
||||
(void)adapterId;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void SST_WM_GetEnumVideoModes(SST_GraphicsEnumerator enumerator, size_t adapterId, size_t screenId, SST_VideoMode* modesReturn, size_t* modeCountReturn)
|
||||
{
|
||||
(void)enumerator;
|
||||
|
||||
/* Only one adapter/screen supported */
|
||||
if(adapterId != 0 || screenId != 0)
|
||||
return;
|
||||
|
||||
if(modesReturn == NULL)
|
||||
*modeCountReturn = 1;
|
||||
else
|
||||
{
|
||||
/* TODO: there might be a way to do this, but it
|
||||
is very manual. Just return current resolution. */
|
||||
uint32_t w, h;
|
||||
|
||||
graphics_get_display_size(0, &w, &h);
|
||||
|
||||
modesReturn[0].bpp = 16; /* TODO: not always 16 */
|
||||
modesReturn[0].width = w;
|
||||
modesReturn[0].height = h;
|
||||
modesReturn[0].refreshRate = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void SST_WM_GetEnumCurrentVideoMode(SST_GraphicsEnumerator enumerator, size_t adapterId, size_t screenId, SST_VideoMode* mode)
|
||||
{
|
||||
uint32_t w, h;
|
||||
(void)enumerator;
|
||||
|
||||
if(adapterId != 0 || screenId != 0)
|
||||
return;
|
||||
|
||||
/* TODO: does this reflect changes made with fbset? */
|
||||
graphics_get_display_size(0, &w, &h);
|
||||
|
||||
mode->bpp = 16;
|
||||
mode->width = w;
|
||||
mode->height = h;
|
||||
mode->refreshRate = 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void SST_WM_DestroyGraphicsEnumerator(SST_GraphicsEnumerator enumerator)
|
||||
{
|
||||
(void)enumerator;
|
||||
}
|
||||
60
libsst-wm/RaspPi/SST_WMEvent_RaspPi.c
Normal file
60
libsst-wm/RaspPi/SST_WMEvent_RaspPi.c
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
SST_WMEvent_Win32.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 6/25/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
Raspberry Pi "window" event functions
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#include <SST/SST_WMEvent.h>
|
||||
#include "RaspPiPrivate.h"
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
int SST_WM_GetEvent(SST_DisplayTarget target, SST_WMEvent* eventReturn)
|
||||
{
|
||||
SST_DisplayTarget_RaspPi* displayTarget = (SST_DisplayTarget_RaspPi*)target;
|
||||
|
||||
/* Check for user events */
|
||||
if(RemoveFromEQ(&displayTarget->userEventQueue, eventReturn))
|
||||
return 1;
|
||||
|
||||
if(RemoveFromEQ(&displayTarget->eventQueue, eventReturn))
|
||||
return 1;
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/* These functions are used by SST_WMEvent_Common.c */
|
||||
EventQueue* getUserEventQueue(SST_DisplayTarget target)
|
||||
{
|
||||
|
||||
SST_DisplayTarget_RaspPi* displayTarget = (SST_DisplayTarget_RaspPi*)target;
|
||||
return &displayTarget->userEventQueue;
|
||||
}
|
||||
|
||||
void lockUserEventQueue(SST_DisplayTarget target)
|
||||
{
|
||||
SST_DisplayTarget_RaspPi* displayTarget = (SST_DisplayTarget_RaspPi*)target;
|
||||
pthread_mutex_lock(&displayTarget->eventLock);
|
||||
}
|
||||
|
||||
void unlockUserEventQueue(SST_DisplayTarget target)
|
||||
{
|
||||
SST_DisplayTarget_RaspPi* displayTarget = (SST_DisplayTarget_RaspPi*)target;
|
||||
pthread_mutex_unlock(&displayTarget->eventLock);
|
||||
}
|
||||
|
||||
113
libsst-wm/RaspPi/SST_WMRender_RaspPi.c
Normal file
113
libsst-wm/RaspPi/SST_WMRender_RaspPi.c
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
SST_WMRender_RaspPi.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 6/25/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
Software rendering support for Raspberry Pi
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#include "RaspPiPrivate.h"
|
||||
#include <SST/SST_WMWindow.h>
|
||||
|
||||
#define ROUNDUP(val, power) ((val + (power)-1) & ~((power)-1))
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
int SST_WM_EnableSoftwareRendering(SST_Window window)
|
||||
{
|
||||
SST_Window_RaspPi* win = (SST_Window_RaspPi*)window;
|
||||
DISPMANX_UPDATE_HANDLE_T update;
|
||||
|
||||
/* Each pixel is 4 bytes. */
|
||||
uint32_t pitch = win->w * sizeof(uint32_t);
|
||||
uint32_t dummy;
|
||||
|
||||
/* Pitch must be a multiple of 32 bytes, so round up */
|
||||
pitch = ROUNDUP(pitch, 32);
|
||||
|
||||
/* TODO: what does vc_dispmanx_resource_create() return on error? */
|
||||
/* Last parameter "dummy" is always set to zero according to source code, must be from other videocore versions */
|
||||
win->softwareImage = vc_dispmanx_resource_create(VC_IMAGE_ARGB8888, win->w, win->h, &dummy);
|
||||
win->softwareBackbuffer = calloc(win->h, pitch);
|
||||
win->softwarePitch = pitch;
|
||||
|
||||
/* TODO: wtf, why << 16 */
|
||||
vc_dispmanx_rect_set(&win->softwareRect, 0, 0, win->w << 16, win->h << 16 );
|
||||
|
||||
if(win->softwareBackbuffer == NULL)
|
||||
return 0;
|
||||
|
||||
/* Update dispmanx to bind the new image to the */
|
||||
update = vc_dispmanx_update_start(0);
|
||||
vc_dispmanx_element_change_source(update, win->element, win->softwareImage);
|
||||
vc_dispmanx_update_submit_sync(update);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void SST_WM_DisableSoftwareRendering(SST_Window window)
|
||||
{
|
||||
SST_Window_RaspPi* win = (SST_Window_RaspPi*)window;
|
||||
DISPMANX_UPDATE_HANDLE_T update;
|
||||
|
||||
/* Update dispmanx; remove the resource from the window element */
|
||||
update = vc_dispmanx_update_start(0);
|
||||
|
||||
vc_dispmanx_element_change_source(update, win->element, 0);
|
||||
|
||||
vc_dispmanx_update_submit_sync(update);
|
||||
|
||||
/* Now we can delete the resource */
|
||||
if(win->softwareImage != 0)
|
||||
{
|
||||
vc_dispmanx_resource_delete(win->softwareImage);
|
||||
win->softwareImage = 0;
|
||||
}
|
||||
|
||||
if(win->softwareBackbuffer)
|
||||
{
|
||||
free(win->softwareBackbuffer);
|
||||
win->softwareBackbuffer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void* SST_WM_LockBackbuffer(SST_Window window, size_t* pitchReturn)
|
||||
{
|
||||
SST_Window_RaspPi* win = (SST_Window_RaspPi*)window;
|
||||
|
||||
*pitchReturn = win->softwarePitch;
|
||||
|
||||
return win->softwareBackbuffer;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void SST_WM_UnlockBackbuffer(SST_Window window)
|
||||
{
|
||||
SST_Window_RaspPi* win = (SST_Window_RaspPi*)window;
|
||||
VC_RECT_T blit;
|
||||
|
||||
blit.x = blit.y = 0;
|
||||
blit.width = win->w;
|
||||
blit.height = win->h;
|
||||
|
||||
/* Push the pixels to the resource */
|
||||
vc_dispmanx_resource_write_data(win->softwareImage, VC_IMAGE_ARGB8888, win->softwarePitch, win->softwareBackbuffer, &blit);
|
||||
|
||||
}
|
||||
|
||||
56
libsst-wm/RaspPi/SST_WMVideoMode_RaspPi.c
Normal file
56
libsst-wm/RaspPi/SST_WMVideoMode_RaspPi.c
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
SST_WMVideoMode_RaspPi.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 6/25/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
Video mode setting functions for the Raspberry Pi
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#include "RaspPiPrivate.h"
|
||||
|
||||
/*
|
||||
Right now, these are essentially no-ops. The vc_tv_xxx API can be used
|
||||
to query and change the video mode
|
||||
*/
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
int SST_WM_SetVideoModeOnScreen(SST_DisplayTarget target, size_t screenIndex, const SST_VideoMode* vmode)
|
||||
{
|
||||
SST_DisplayTarget_RaspPi* displayTarget = (SST_DisplayTarget_RaspPi*)target;
|
||||
|
||||
/* Must be screen 0 */
|
||||
if(screenIndex != 0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
int SST_WM_GetVideoModeOnScreen(SST_DisplayTarget target, size_t screenIndex, SST_VideoMode* vmodeReturn)
|
||||
{
|
||||
SST_DisplayTarget_RaspPi* displayTarget = (SST_DisplayTarget_RaspPi*)target;
|
||||
|
||||
/* Must be screen 0 */
|
||||
if(screenIndex != 0)
|
||||
return 0;
|
||||
|
||||
vmodeReturn->bpp = 16; /* ? The HWS runs at what depth? */
|
||||
vmodeReturn->width = 0;
|
||||
vmodeReturn->height = 0;
|
||||
vmodeReturn->refreshRate = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
390
libsst-wm/RaspPi/SST_WMWindow_RaspPi.c
Normal file
390
libsst-wm/RaspPi/SST_WMWindow_RaspPi.c
Normal file
@@ -0,0 +1,390 @@
|
||||
/*
|
||||
SST_WMWindow_RaspPi.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 1/8/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
Window emulation for native Raspberry Pi port
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#include <SST/SST_WMWindow.h>
|
||||
#include "RaspPiPrivate.h"
|
||||
#include "EventQueue.h"
|
||||
|
||||
#define WINDOW_LAYER 2000
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void destroyWin(SST_Window_RaspPi* win)
|
||||
{
|
||||
/* Only after an element is removed can the resource under it
|
||||
be deleted. */
|
||||
if(win->element != 0)
|
||||
{
|
||||
DISPMANX_UPDATE_HANDLE_T update;
|
||||
|
||||
update = vc_dispmanx_update_start(0);
|
||||
vc_dispmanx_element_remove(update, win->element);
|
||||
vc_dispmanx_update_submit_sync(update);
|
||||
}
|
||||
|
||||
if(win->softwareImage != 0)
|
||||
vc_dispmanx_resource_delete(win->softwareImage);
|
||||
|
||||
free(win);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
SST_DisplayTarget SST_WM_CreateDisplayTarget(size_t adapterIndex, size_t screenIndexOrMultihead)
|
||||
{
|
||||
SST_DisplayTarget_RaspPi* displayTarget;
|
||||
|
||||
/* > 1 adapters not supported, multihead not supported */
|
||||
if(screenIndexOrMultihead != 0 || adapterIndex != 0)
|
||||
return NULL;
|
||||
|
||||
displayTarget = (SST_DisplayTarget_RaspPi*)malloc(sizeof(SST_DisplayTarget_RaspPi));
|
||||
if(displayTarget == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Initialize lock for user events */
|
||||
if(pthread_mutex_init(&displayTarget->eventLock, NULL) != 0)
|
||||
{
|
||||
free(displayTarget);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(InitEQ(&displayTarget->eventQueue) == 0)
|
||||
{
|
||||
pthread_mutex_destroy(&displayTarget->eventLock);
|
||||
free(displayTarget);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(InitEQ(&displayTarget->userEventQueue) == 0)
|
||||
{
|
||||
DestroyEQ(&displayTarget->eventQueue);
|
||||
pthread_mutex_destroy(&displayTarget->eventLock);
|
||||
free(displayTarget);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Save fields */
|
||||
displayTarget->firstWindow = NULL;
|
||||
displayTarget->relativeMouse = 0;
|
||||
displayTarget->display = vc_dispmanx_display_open(DISPMANX_ID_MAIN_LCD);
|
||||
memset(displayTarget->keymapBitvector, 0, sizeof(displayTarget->keymapBitvector));
|
||||
|
||||
return (SST_DisplayTarget)displayTarget;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
size_t SST_WM_GetDisplayTargetScreenCount(SST_DisplayTarget target)
|
||||
{
|
||||
(void)target;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
SST_Window SST_WM_CreateWindowOnScreen(SST_DisplayTarget target, size_t screenIndex, uint32_t x, uint32_t y, uint32_t width, uint32_t height, const char* title)
|
||||
{
|
||||
SST_Window_RaspPi* win;
|
||||
SST_DisplayTarget_RaspPi* displayTarget = (SST_DisplayTarget_RaspPi*)target;
|
||||
SST_WMEvent* event;
|
||||
DISPMANX_UPDATE_HANDLE_T update;
|
||||
VC_DISPMANX_ALPHA_T alpha;
|
||||
VC_RECT_T srcRect, dstRect;
|
||||
|
||||
/* Title is not used */
|
||||
(void)title;
|
||||
|
||||
/* Must be on screen 0 */
|
||||
if(screenIndex != 0)
|
||||
return NULL;
|
||||
|
||||
/* Allocate SST window structure */
|
||||
win = (SST_Window_RaspPi*)calloc(1, sizeof(SST_Window_RaspPi));
|
||||
if(win == NULL)
|
||||
return NULL;
|
||||
|
||||
/* link the window */
|
||||
displayTarget->firstWindow = win;
|
||||
win->next = displayTarget->firstWindow;
|
||||
win->owner = displayTarget;
|
||||
win->x = x;
|
||||
win->y = y;
|
||||
win->w = width;
|
||||
win->h = height;
|
||||
|
||||
srcRect.x = srcRect.y = 0;
|
||||
srcRect.width = width << 16; srcRect.height = height << 16;
|
||||
|
||||
dstRect.x = x; dstRect.y = y;
|
||||
dstRect.width = width; dstRect.height = height;
|
||||
|
||||
/* TODO: clip these so they make sense */
|
||||
|
||||
alpha.flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS;
|
||||
alpha.opacity = 0xFF;
|
||||
alpha.mask = 0;
|
||||
|
||||
update = vc_dispmanx_update_start(0);
|
||||
win->element = vc_dispmanx_element_add(update, displayTarget->display,
|
||||
WINDOW_LAYER,
|
||||
&dstRect,
|
||||
0, &srcRect, /* no source data */
|
||||
DISPMANX_PROTECTION_NONE, /* no content protection */
|
||||
&alpha, NULL, /* Alpha/clamp/transform parameters */
|
||||
VC_IMAGE_ROT0); /* No rotation required */
|
||||
|
||||
|
||||
vc_dispmanx_update_submit_sync(update);
|
||||
|
||||
/* Add a SSTWMEVENT_CREATED event */
|
||||
event = AllocSlotInEQ(&displayTarget->eventQueue);
|
||||
if(event != NULL)
|
||||
{
|
||||
event->window = win;
|
||||
event->type = SSTWMEVENT_CREATED;
|
||||
memset(&event->details, 0, sizeof(event->details));
|
||||
}
|
||||
|
||||
return (SST_Window)win;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
SST_DisplayTarget SST_WM_GetWindowDisplayTarget(SST_Window window)
|
||||
{
|
||||
SST_Window_RaspPi* win = (SST_Window_RaspPi*)window;
|
||||
|
||||
return win->owner;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void SST_WM_SetWindowText(SST_Window window, const char* titleBar)
|
||||
{
|
||||
/* There is no way to do this; Ignore. */
|
||||
(void)window;
|
||||
(void)titleBar;
|
||||
}
|
||||
/******************************************************************************/
|
||||
|
||||
void SST_WM_GetWindowRect(SST_Window window, SST_Rect* rectReturn)
|
||||
{
|
||||
SST_Window_RaspPi* win = (SST_Window_RaspPi*)window;
|
||||
|
||||
rectReturn->x = win->x;
|
||||
rectReturn->y = win->y;
|
||||
rectReturn->width = win->w;
|
||||
rectReturn->height = win->h;
|
||||
return;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void SST_WM_MoveWindowOnScreen(SST_Window window, size_t screenIndex, uint32_t x, uint32_t y)
|
||||
{
|
||||
SST_Window_RaspPi* win = (SST_Window_RaspPi*)window;
|
||||
|
||||
/* Only allow operations on screen 0 */
|
||||
if(screenIndex != SST_SAME_SCREEN && screenIndex != 0)
|
||||
return;
|
||||
|
||||
/* TODO: verify these coords make any sense */
|
||||
win->x = x;
|
||||
win->y = y;
|
||||
/* TODO: send message */
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void SST_WM_ResizeWindow(SST_Window window, uint32_t width, uint32_t height)
|
||||
{
|
||||
SST_Window_RaspPi* win = (SST_Window_RaspPi*)window;
|
||||
/* TODO: verify these coords make any sense */
|
||||
win->w = width;
|
||||
win->h = height;
|
||||
/* TODO: send a message */
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void SST_WM_SetWindowState(SST_Window window, SST_WMWindowState state, uint32_t param)
|
||||
{
|
||||
SST_Window_RaspPi* win = (SST_Window_RaspPi*)window;
|
||||
|
||||
switch(state)
|
||||
{
|
||||
case SSTWS_SHOWN:
|
||||
{
|
||||
/* Map or unmap the window respectively */
|
||||
if(param == 0)
|
||||
{
|
||||
/* TODO: hide window */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* TODO: show window */
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* Turn on/off resizeability */
|
||||
case SSTWS_RESIZEABLE:
|
||||
{
|
||||
/* No-op. */
|
||||
break;
|
||||
}
|
||||
|
||||
case SSTWS_FULLSCREEN:
|
||||
{
|
||||
|
||||
/* Enabling fullscreen? */
|
||||
if(param && !win->isFullscreen)
|
||||
{
|
||||
/* TODO: save old X/Y/W/H */
|
||||
win->isFullscreen = 1;
|
||||
}
|
||||
else if(win->isFullscreen)
|
||||
{
|
||||
/* TODO: restore old X/Y/W/H */
|
||||
win->isFullscreen = 0;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case SSTWS_MINIMIZED:
|
||||
{
|
||||
if(param == 0) /* Maximize */
|
||||
{
|
||||
/* TODO: maximize? */
|
||||
}
|
||||
else /* Minimize */
|
||||
{
|
||||
/* TODO: minimize? */
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void SST_WM_SetDisplayTargetState(SST_DisplayTarget target, SST_WMDisplayTargetState state, uint32_t param)
|
||||
{
|
||||
SST_DisplayTarget_RaspPi* displayTarget = (SST_DisplayTarget_RaspPi*)target;
|
||||
|
||||
switch(state)
|
||||
{
|
||||
case SSTDTS_RELMOUSE:
|
||||
{
|
||||
/* Disabling? */
|
||||
if(displayTarget->relativeMouse && param == 0)
|
||||
{
|
||||
/* TODO */
|
||||
}
|
||||
else if(!displayTarget->relativeMouse && param != 0) /* Enabling? */
|
||||
{
|
||||
/* TODO */
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void SST_WM_DestroyWindow(SST_Window window)
|
||||
{
|
||||
SST_DisplayTarget_RaspPi* displayTarget;
|
||||
SST_Window_RaspPi* win = (SST_Window_RaspPi*)window;
|
||||
SST_Window_RaspPi* nextWin;
|
||||
|
||||
displayTarget = win->owner;
|
||||
nextWin = displayTarget->firstWindow;
|
||||
|
||||
/* Special case: root window */
|
||||
if(nextWin == win)
|
||||
{
|
||||
/* Set new root to be this->next */
|
||||
displayTarget->firstWindow = win->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
int found = 0;
|
||||
|
||||
/* Check list */
|
||||
while(nextWin)
|
||||
{
|
||||
/* Did we find the window? */
|
||||
if(nextWin->next == win)
|
||||
{
|
||||
/* Remove this window from the linked list */
|
||||
nextWin->next = win->next;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
else
|
||||
nextWin = nextWin->next;
|
||||
}
|
||||
|
||||
/* Don't destroy another display target's window */
|
||||
if(!found)
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
/* Actually destroy the window window */
|
||||
destroyWin(win);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void SST_WM_DestroyDisplayTarget(SST_DisplayTarget target)
|
||||
{
|
||||
SST_DisplayTarget_RaspPi* displayTarget = (SST_DisplayTarget_RaspPi*)target;
|
||||
SST_Window_RaspPi* window = displayTarget->firstWindow;
|
||||
|
||||
/* Destroy window */
|
||||
while(window)
|
||||
{
|
||||
SST_Window_RaspPi* next = window->next;
|
||||
destroyWin(window);
|
||||
window = next;
|
||||
}
|
||||
|
||||
/* Delete any events */
|
||||
DestroyEQ(&displayTarget->eventQueue);
|
||||
DestroyEQ(&displayTarget->userEventQueue);
|
||||
pthread_mutex_destroy(&displayTarget->eventLock);
|
||||
|
||||
vc_dispmanx_display_close(displayTarget->display);
|
||||
|
||||
/* Free structure */
|
||||
free(displayTarget);
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
|
||||
319
libsst-wm/Win32/SST_WMDialogBox_Win32.c
Normal file
319
libsst-wm/Win32/SST_WMDialogBox_Win32.c
Normal file
@@ -0,0 +1,319 @@
|
||||
/*
|
||||
SST_WMDialogBox_Win32.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 1/5/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
Model
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#include "Win32Private.h"
|
||||
|
||||
#define BUTTON_HSPACE 16 /* Space on either side of a button */
|
||||
#define BUTTON_VSPACE 16 /* Space between top of button and dialog text */
|
||||
#define TEXT_HSPACE 16
|
||||
#define TEXT_VSPACE 16
|
||||
|
||||
typedef struct DialogBoxData
|
||||
{
|
||||
const char* message;
|
||||
int lenMessage;
|
||||
int buttonId;
|
||||
int exitTime;
|
||||
} DialogBoxData;
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static LONG dlgRegCount = 0;
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static LRESULT WINAPI libsstDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
static HWND createButton(HWND owner, int id, const char* label, int x, int y, int w, int h);
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
int Win32_ShowDialogBox(SST_DisplayTarget target, SST_Window parent, const char* caption, const char* message, const char** buttons, int nrButtons)
|
||||
{
|
||||
SST_Window_Win32* win = (SST_Window_Win32*)parent;
|
||||
SST_DisplayTarget_Win32* displayTarget = (SST_DisplayTarget_Win32*)target;
|
||||
HWND hWnd;
|
||||
HWND hParentWnd = NULL;
|
||||
MSG msg;
|
||||
HDC hDC;
|
||||
HFONT hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
|
||||
|
||||
/* Compute size of a button. This is absolutely arcane, but the 50x14 units and the /4 /8 are documented. Somewhere... */
|
||||
uint32_t units = (uint32_t)GetDialogBaseUnits();
|
||||
int horiz = (int)MulDiv((units & 0xFF), 50, 4);
|
||||
int vert = (int)MulDiv((units >> 16), 14, 8);
|
||||
int w, h;
|
||||
int returnCode;
|
||||
|
||||
/* Window rectangle computation */
|
||||
DWORD style = WS_CAPTION | WS_SYSMENU | WS_CLIPCHILDREN;
|
||||
DWORD styleEx = 0;
|
||||
RECT r;
|
||||
RECT textRect;
|
||||
RECT centerOn;
|
||||
DialogBoxData* dlgData;
|
||||
|
||||
/* Allocate dialog box data */
|
||||
dlgData = (DialogBoxData*)HeapAlloc(GetProcessHeap(), 0, sizeof(DialogBoxData));
|
||||
if(dlgData == NULL)
|
||||
return -1;
|
||||
|
||||
dlgData->message = message;
|
||||
dlgData->lenMessage = (int)strlen(message);
|
||||
dlgData->buttonId = -1;
|
||||
dlgData->exitTime = 0;
|
||||
/*
|
||||
First, figure out a good area to center the dialog box on. It's highly unintuitive to have it
|
||||
it mapped in the top-left corner. We center it on the parent window (if possible) or the monitor
|
||||
otherwise.
|
||||
*/
|
||||
|
||||
/* Have a parent window? */
|
||||
if(win != NULL)
|
||||
{
|
||||
/* Then center on it */
|
||||
hParentWnd = win->hWnd;
|
||||
GetWindowRect(hParentWnd, ¢erOn);
|
||||
}
|
||||
else /* Otherwise center on default display */
|
||||
{
|
||||
FindMonitorInfo fmi;
|
||||
|
||||
/* Attempt to find the monitor associated with a display device */
|
||||
findMonitor(&displayTarget->devs[0], &fmi);
|
||||
|
||||
/* Didn't find it? */
|
||||
if(!fmi.foundIt)
|
||||
return -1;
|
||||
|
||||
/* Center on the monitor */
|
||||
centerOn.top = fmi.top;
|
||||
centerOn.left = fmi.left;
|
||||
centerOn.bottom = fmi.bottom;
|
||||
centerOn.right = fmi.right;
|
||||
}
|
||||
|
||||
/* Start the window as if it was at (0,0) */
|
||||
r.top = 0;
|
||||
r.left = 0;
|
||||
r.bottom = 2*BUTTON_VSPACE+vert; /* Enough space for a button and vertical padding above and below it */
|
||||
r.right = (LONG)nrButtons*(horiz + BUTTON_HSPACE)+BUTTON_HSPACE;
|
||||
|
||||
/* Now we need to compute the area requried to display the text. This will be summed with the area required for the buttons on the Y axis, but
|
||||
the X axis will be the maximum of the two. */
|
||||
/* 1) Create a fake DC to compute the size of the text's rect */
|
||||
hDC = CreateDC("DISPLAY", NULL, NULL, NULL);
|
||||
SelectObject(hDC, (HGDIOBJ)hFont);
|
||||
|
||||
/* 2) Actually compute the rect using DrawTextEx() and DT_CALCRECT. */
|
||||
memset(&textRect, 0, sizeof(textRect));
|
||||
DrawTextExA(hDC, (LPSTR)dlgData->message, dlgData->lenMessage, &textRect, DT_CALCRECT | DT_TOP | DT_LEFT, NULL);
|
||||
DeleteDC(hDC);
|
||||
|
||||
/* 3) Add a border around the entire thing */
|
||||
textRect.bottom += 2*TEXT_VSPACE;
|
||||
textRect.right += 2*TEXT_HSPACE;
|
||||
|
||||
/* For the X-axis, we want the maximum of the amount of space it takes to display buttons and text */
|
||||
if(r.right < textRect.right)
|
||||
r.right = textRect.right;
|
||||
|
||||
/* For the Y-aaxis, just append space to the top of dialog box for the text rect */
|
||||
r.bottom += textRect.bottom;
|
||||
|
||||
/* Move the window to the center of the screen: */
|
||||
/* 1) Compute width and height of window */
|
||||
w = r.right - r.left;
|
||||
h = r.bottom - r.top;
|
||||
|
||||
AdjustWindowRectEx(&r, style, FALSE, styleEx);
|
||||
|
||||
/* After we adjusted the size of the window so that the client area is constant, we need
|
||||
to move it back to (0,0). */
|
||||
if(r.top != 0)
|
||||
{
|
||||
LONG d = -r.top;
|
||||
|
||||
r.top = 0;
|
||||
r.bottom += d;
|
||||
}
|
||||
if(r.left != 0)
|
||||
{
|
||||
LONG d = -r.left;
|
||||
|
||||
r.left = 0;
|
||||
r.right += d;
|
||||
}
|
||||
|
||||
/* 2) Adjust so it fits on the screen by doing: `adjust = (center - size) /2` */
|
||||
r.left += ((centerOn.right - centerOn.left) - w) / 2;
|
||||
r.right += ((centerOn.right - centerOn.left) - w) / 2;
|
||||
r.top += ((centerOn.bottom - centerOn.top) - h) / 2;
|
||||
r.bottom += ((centerOn.bottom - centerOn.top) - h) / 2;
|
||||
|
||||
/* You can't create a window without registering the class, so let's do it now. Since
|
||||
this function has "Concurrent" access, use an atomic operation to decide if it is necessary. */
|
||||
if(InterlockedIncrement(&dlgRegCount) == 1)
|
||||
{
|
||||
WNDCLASSEXA wc;
|
||||
|
||||
memset(&wc, 0, sizeof(wc));
|
||||
wc.cbSize = sizeof(wc);
|
||||
wc.lpszClassName = SST_DLGCLASS;
|
||||
wc.hInstance = GetModuleHandleA(NULL);
|
||||
wc.lpfnWndProc = libsstDlgProc;
|
||||
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
|
||||
wc.style = CS_OWNDC;
|
||||
wc.hbrBackground = (HBRUSH)(uintptr_t)(COLOR_WINDOW+1);
|
||||
RegisterClassExA(&wc);
|
||||
} /* TODO: I suppose it is possible that someone could turn this into a race condition. Priority = lowest */
|
||||
|
||||
/* FINALLY, create the dialog window */
|
||||
hWnd = CreateWindowExA(styleEx,
|
||||
SST_DLGCLASS,
|
||||
caption,
|
||||
style,
|
||||
r.left, r.top, /* XY position */
|
||||
r.right-r.left, r.bottom-r.top, /* Size */
|
||||
hParentWnd,
|
||||
(NULL),
|
||||
GetModuleHandleA(NULL),
|
||||
NULL);
|
||||
|
||||
/* Made the window successfully? */
|
||||
if(hWnd != NULL)
|
||||
{
|
||||
int i;
|
||||
POINT bottomRight;
|
||||
RECT clientRect;
|
||||
SetWindowLongPtrA(hWnd, GWLP_USERDATA, (LONG_PTR)dlgData);
|
||||
|
||||
ShowWindow(hWnd, SW_SHOW);
|
||||
|
||||
/* Get the coordinates of the bottom right pixel */
|
||||
GetClientRect(hWnd, &clientRect);
|
||||
bottomRight.x = clientRect.right;
|
||||
bottomRight.y = clientRect.bottom;
|
||||
|
||||
/* Create the dialog buttons in reverse order starting at the right end of the dialog and moving left */
|
||||
for(i=0; i<nrButtons; i++)
|
||||
{
|
||||
HWND hButton = createButton(hWnd, nrButtons-1-i, buttons[nrButtons-1-i], bottomRight.x-((i+1)*(BUTTON_HSPACE+horiz)), bottomRight.y-(BUTTON_VSPACE+vert), horiz, vert);
|
||||
|
||||
/* Set the font on them too */
|
||||
SendMessage(hButton, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0));
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
while(PeekMessageA(&msg, hWnd, 0, 0, PM_REMOVE))
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageA(&msg);
|
||||
}
|
||||
} while(!dlgData->exitTime);
|
||||
}
|
||||
|
||||
returnCode = dlgData->buttonId;
|
||||
|
||||
HeapFree(GetProcessHeap(), 0,dlgData);
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static LRESULT WINAPI libsstDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
DialogBoxData* dlgData = (DialogBoxData*)GetWindowLongPtrA(hWnd, GWLP_USERDATA);
|
||||
|
||||
|
||||
switch(msg)
|
||||
{
|
||||
case WM_PAINT:
|
||||
{
|
||||
PAINTSTRUCT ps;
|
||||
RECT r;
|
||||
HDC hDC;
|
||||
|
||||
|
||||
if(dlgData)
|
||||
{
|
||||
hDC = BeginPaint(hWnd, &ps);
|
||||
|
||||
SelectObject(hDC, GetStockObject(DEFAULT_GUI_FONT));
|
||||
|
||||
GetClientRect(hWnd, &r);
|
||||
|
||||
r.left += TEXT_HSPACE;
|
||||
r.right -= TEXT_HSPACE;
|
||||
r.top += TEXT_VSPACE;
|
||||
r.bottom -= TEXT_VSPACE;
|
||||
|
||||
DrawTextExA(hDC, (LPSTR)dlgData->message, dlgData->lenMessage, &r, DT_TOP | DT_LEFT, NULL);
|
||||
EndPaint(hWnd, &ps);
|
||||
}
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Aborting the dialog */
|
||||
case WM_CLOSE:
|
||||
dlgData->buttonId = -1;
|
||||
dlgData->exitTime = 1;
|
||||
DestroyWindow(hWnd);
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case WM_COMMAND:
|
||||
{
|
||||
if(HIWORD(wParam) == BN_CLICKED)
|
||||
{
|
||||
dlgData->buttonId = (int)LOWORD(wParam);
|
||||
dlgData->exitTime = 1;
|
||||
|
||||
DestroyWindow(hWnd);
|
||||
}
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return DefWindowProc(hWnd, msg, wParam, lParam);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static HWND createButton(HWND owner, int id, const char* label, int x, int y, int w, int h)
|
||||
{
|
||||
HWND hWnd = CreateWindowExA(0,
|
||||
"BUTTON",
|
||||
label,
|
||||
WS_TABSTOP|WS_VISIBLE|
|
||||
WS_CHILD|BS_DEFPUSHBUTTON,
|
||||
x, y,
|
||||
w, h,
|
||||
owner,
|
||||
(HMENU)(uintptr_t)id,
|
||||
GetModuleHandleA(NULL),
|
||||
NULL);
|
||||
return hWnd;
|
||||
}
|
||||
|
||||
268
libsst-wm/Win32/SST_WMEnum_Win32.c
Normal file
268
libsst-wm/Win32/SST_WMEnum_Win32.c
Normal file
@@ -0,0 +1,268 @@
|
||||
/*
|
||||
SST_WMEnum_Win32.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 1/7/2012
|
||||
|
||||
Purpose:
|
||||
|
||||
Enumerates graphics adapters and screens.
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#include <SST/SST_WM.h>
|
||||
|
||||
#include "Win32Private.h"
|
||||
#include "../APIPrivate.h"
|
||||
|
||||
#include <string.h> /* strlen() etc. */
|
||||
#include <stdlib.h>
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static SST_GraphicsEnumerator Win32_CreateGraphicsEnumerator(void)
|
||||
{
|
||||
DISPLAY_DEVICEA* devsFound = NULL;
|
||||
char* adapterNames;
|
||||
char* adapterGUIDs;
|
||||
size_t* screenCount;
|
||||
size_t adapterCount;
|
||||
size_t devCount = 0;
|
||||
size_t ASPairCount = 0;
|
||||
size_t i;
|
||||
SST_GraphicsEnumerator_Win32* enumerator;
|
||||
ASMapEntry* ASMap;
|
||||
HANDLE hProcessHeap;
|
||||
|
||||
/* Get a list of Win32 display devices */
|
||||
devsFound = get_win32devs(&devCount);
|
||||
if(devsFound == NULL)
|
||||
return NULL;
|
||||
|
||||
hProcessHeap = GetProcessHeap();
|
||||
|
||||
/* Get a list of the graphics adapters' names */
|
||||
adapterNames = get_adapters(devsFound, devCount, &adapterCount, &adapterGUIDs);
|
||||
if(adapterNames == NULL)
|
||||
{
|
||||
HeapFree(hProcessHeap, 0, devsFound);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Make a map of adapter->screen count */
|
||||
screenCount = HeapAlloc(hProcessHeap, 0, adapterCount*sizeof(size_t));
|
||||
if(screenCount == NULL)
|
||||
{
|
||||
HeapFree(hProcessHeap, 0, adapterGUIDs);
|
||||
HeapFree(hProcessHeap, 0, adapterNames);
|
||||
HeapFree(hProcessHeap, 0, devsFound);
|
||||
return NULL;
|
||||
}
|
||||
for(i=0; i<adapterCount; i++)
|
||||
screenCount[i] = 0;
|
||||
|
||||
/* Attempt to build the adapter-screen map */
|
||||
ASMap = build_asmap(devsFound, adapterGUIDs, devCount, adapterCount, screenCount, &ASPairCount);
|
||||
if(ASMap == NULL)
|
||||
{
|
||||
HeapFree(hProcessHeap, 0, adapterGUIDs);
|
||||
HeapFree(hProcessHeap, 0, adapterNames);
|
||||
HeapFree(hProcessHeap, 0, devsFound);
|
||||
HeapFree(hProcessHeap, 0, screenCount);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Done with GUIDs */
|
||||
HeapFree(hProcessHeap, 0, adapterGUIDs);
|
||||
|
||||
/* Get the list of video modes for each adapter-screen pair */
|
||||
for(i=0; i<ASPairCount; i++)
|
||||
{
|
||||
size_t vmodeCount;
|
||||
SST_VideoMode* vmodes;
|
||||
|
||||
vmodes = get_vmodes(ASMap[i].dev, &vmodeCount, &ASMap[i].defaultVmode);
|
||||
if(vmodes == NULL)
|
||||
{
|
||||
size_t j;
|
||||
for(j=0; j<i; j++)
|
||||
HeapFree(hProcessHeap, 0, ASMap[i].vmodes);
|
||||
HeapFree(hProcessHeap, 0, adapterNames);
|
||||
HeapFree(hProcessHeap, 0, devsFound);
|
||||
HeapFree(hProcessHeap, 0, screenCount);
|
||||
HeapFree(hProcessHeap, 0, ASMap);
|
||||
return NULL;
|
||||
}
|
||||
/* Save the screens for this */
|
||||
ASMap[i].vmodeCount = vmodeCount;
|
||||
ASMap[i].vmodes = vmodes;
|
||||
}
|
||||
|
||||
/* Prepare a structure to return... */
|
||||
enumerator = HeapAlloc(hProcessHeap, 0, sizeof(SST_GraphicsEnumerator_Win32));
|
||||
if(enumerator == NULL)
|
||||
{
|
||||
/* Doh! So close :\ */
|
||||
size_t j;
|
||||
for(j=0; j<i; j++)
|
||||
HeapFree(hProcessHeap, 0, ASMap[i].vmodes);
|
||||
|
||||
HeapFree(hProcessHeap, 0, adapterNames);
|
||||
HeapFree(hProcessHeap, 0, devsFound);
|
||||
HeapFree(hProcessHeap, 0, screenCount);
|
||||
HeapFree(hProcessHeap, 0, ASMap);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Save fields */
|
||||
enumerator->adapterNames = adapterNames;
|
||||
enumerator->adapterCount = adapterCount;
|
||||
enumerator->devCount = devCount;
|
||||
enumerator->devsFound = devsFound;
|
||||
enumerator->screenCount = screenCount;
|
||||
enumerator->ASMap = ASMap;
|
||||
enumerator->ASPairCount = ASPairCount;
|
||||
|
||||
return enumerator;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static size_t Win32_GetEnumAdapterCount(SST_GraphicsEnumerator enumerator)
|
||||
{
|
||||
SST_GraphicsEnumerator_Win32* enumWin32 = (SST_GraphicsEnumerator_Win32*)enumerator;
|
||||
|
||||
return enumWin32->adapterCount;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static void Win32_GetEnumAdapterName(SST_GraphicsEnumerator enumerator, size_t adapterId, char* nameReturn, size_t* bufferSize)
|
||||
{
|
||||
SST_GraphicsEnumerator_Win32* enumWin32 = (SST_GraphicsEnumerator_Win32*)enumerator;
|
||||
size_t len;
|
||||
const char* name = &enumWin32->adapterNames[adapterId * ADAPTER_NAME_STRLEN];
|
||||
|
||||
len = strlen(name);
|
||||
|
||||
/* Query name length */
|
||||
if(nameReturn == NULL)
|
||||
{
|
||||
*bufferSize = len+1;
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t copyAmount;
|
||||
|
||||
/* Nothing to do? */
|
||||
if(*bufferSize == 0)
|
||||
return;
|
||||
|
||||
/* Use min(len, (*bufferSize)-1) */
|
||||
copyAmount = len;
|
||||
if(copyAmount > (*bufferSize)-1)
|
||||
copyAmount = (*bufferSize)-1;
|
||||
|
||||
memcpy(nameReturn, name, copyAmount);
|
||||
nameReturn[copyAmount] = '\0';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static size_t Win32_GetEnumScreenCount(SST_GraphicsEnumerator enumerator, size_t adapterId)
|
||||
{
|
||||
SST_GraphicsEnumerator_Win32* enumWin32 = (SST_GraphicsEnumerator_Win32*)enumerator;
|
||||
|
||||
return enumWin32->screenCount[adapterId];
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static void Win32_GetEnumVideoModes(SST_GraphicsEnumerator enumerator, size_t adapterId, size_t screenId, SST_VideoMode* modesReturn, size_t* modeCountReturn)
|
||||
{
|
||||
SST_GraphicsEnumerator_Win32* enumWin32 = (SST_GraphicsEnumerator_Win32*)enumerator;
|
||||
size_t i;
|
||||
ASMapEntry* entry = NULL;
|
||||
|
||||
/* Determine which adapter-screen pair to use */
|
||||
for(i=0; i<enumWin32->ASPairCount; i++)
|
||||
{
|
||||
entry = &enumWin32->ASMap[i];
|
||||
if(entry->adapter == adapterId && entry->screen == screenId)
|
||||
{
|
||||
entry = &enumWin32->ASMap[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* When 'modesReturn' is null, user is getting mode count */
|
||||
if(modesReturn == NULL)
|
||||
*modeCountReturn = entry->vmodeCount;
|
||||
else /* else, copy '*modeCountReturn' number of modes */
|
||||
{
|
||||
size_t nrCopy = *modeCountReturn;
|
||||
if(nrCopy > entry->vmodeCount)
|
||||
nrCopy = entry->vmodeCount;
|
||||
|
||||
memcpy(modesReturn, entry->vmodes, sizeof(SST_VideoMode) * nrCopy);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static void Win32_GetEnumCurrentVideoMode(SST_GraphicsEnumerator enumerator, size_t adapterId, size_t screenId, SST_VideoMode* mode)
|
||||
{
|
||||
SST_GraphicsEnumerator_Win32* enumWin32 = (SST_GraphicsEnumerator_Win32*)enumerator;
|
||||
size_t i;
|
||||
|
||||
for(i=0; i<enumWin32->ASPairCount; i++)
|
||||
{
|
||||
if(enumWin32->ASMap[i].adapter == adapterId && enumWin32->ASMap[i].screen == screenId)
|
||||
{
|
||||
*mode = enumWin32->ASMap[i].defaultVmode;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static void Win32_DestroyGraphicsEnumerator(SST_GraphicsEnumerator enumerator)
|
||||
{
|
||||
SST_GraphicsEnumerator_Win32* enumWin32 = (SST_GraphicsEnumerator_Win32*)enumerator;
|
||||
size_t i;
|
||||
HANDLE hProcessHeap;
|
||||
|
||||
hProcessHeap = GetProcessHeap();
|
||||
|
||||
HeapFree(hProcessHeap, 0, enumWin32->adapterNames);
|
||||
HeapFree(hProcessHeap, 0, enumWin32->devsFound);
|
||||
HeapFree(hProcessHeap, 0, enumWin32->screenCount);
|
||||
|
||||
/* Free modes for each adapter-screen pair */
|
||||
for(i=0; i<enumWin32->ASPairCount; i++)
|
||||
HeapFree(hProcessHeap, 0, enumWin32->ASMap[i].vmodes);
|
||||
HeapFree(hProcessHeap, 0, enumWin32->ASMap);
|
||||
|
||||
HeapFree(hProcessHeap, 0, enumWin32);
|
||||
}
|
||||
|
||||
struct SST_WM_EnumFuncs Win32_EnumFuncs = {
|
||||
Win32_CreateGraphicsEnumerator,
|
||||
Win32_GetEnumAdapterCount,
|
||||
Win32_GetEnumAdapterName,
|
||||
Win32_GetEnumScreenCount,
|
||||
Win32_GetEnumVideoModes,
|
||||
Win32_GetEnumCurrentVideoMode,
|
||||
Win32_DestroyGraphicsEnumerator
|
||||
};
|
||||
90
libsst-wm/Win32/SST_WMEvent_Win32.c
Normal file
90
libsst-wm/Win32/SST_WMEvent_Win32.c
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
SST_WMEvent_Win32.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 6/5/2012
|
||||
|
||||
Purpose:
|
||||
|
||||
Window event functions
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#include <SST/SST_WMEvent.h>
|
||||
#include "Win32Private.h"
|
||||
#include "../APIPrivate.h"
|
||||
static void copyAndRemoveUserEvent(SST_DisplayTarget_Win32* displayTarget, SST_WMEvent* eventReturn);
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static int Win32_GetEvent(SST_DisplayTarget target, SST_WMEvent* eventReturn)
|
||||
{
|
||||
MSG msg;
|
||||
SST_DisplayTarget_Win32* displayTarget = (SST_DisplayTarget_Win32*)target;
|
||||
SST_Window_Win32* win;
|
||||
int found = 0;
|
||||
|
||||
/* First, get Win32 messages and dispatch to winproc. We
|
||||
do this immediately, otherwise the OS thinks we've hung. */
|
||||
while(PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageA(&msg);
|
||||
}
|
||||
|
||||
/* Check for user events */
|
||||
if(RemoveFromEQ(&displayTarget->userEventQueue, eventReturn))
|
||||
return 1;
|
||||
|
||||
/* Now check each window's event queue */
|
||||
win = displayTarget->firstWindow;
|
||||
while(win)
|
||||
{
|
||||
if(RemoveFromEQ(&win->eventQueue, eventReturn))
|
||||
{
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
win = win->next;
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
/* Platform-specific code dealing with user event queue */
|
||||
|
||||
static void Win32_lockUserEventQueue(SST_DisplayTarget target)
|
||||
{
|
||||
SST_DisplayTarget_Win32* displayTarget = (SST_DisplayTarget_Win32*)target;
|
||||
EnterCriticalSection(&displayTarget->userEventLock);
|
||||
}
|
||||
|
||||
static void Win32_unlockUserEventQueue(SST_DisplayTarget target)
|
||||
{
|
||||
SST_DisplayTarget_Win32* displayTarget = (SST_DisplayTarget_Win32*)target;
|
||||
LeaveCriticalSection(&displayTarget->userEventLock);
|
||||
}
|
||||
|
||||
static EventQueue* Win32_getUserEventQueue(SST_DisplayTarget target)
|
||||
{
|
||||
|
||||
SST_DisplayTarget_Win32* displayTarget = (SST_DisplayTarget_Win32*)target;
|
||||
return &displayTarget->userEventQueue;
|
||||
}
|
||||
|
||||
const struct SST_WM_EventFuncs Win32_EventFuncs = {
|
||||
Win32_GetEvent,
|
||||
Win32_getUserEventQueue,
|
||||
Win32_lockUserEventQueue,
|
||||
Win32_unlockUserEventQueue
|
||||
};
|
||||
26
libsst-wm/Win32/SST_WMNonPortable_Win32.c
Normal file
26
libsst-wm/Win32/SST_WMNonPortable_Win32.c
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
SST_WMNonPortable_Win32.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 6/1/2012
|
||||
|
||||
Purpose:
|
||||
|
||||
Non-portable API calls in libsst-wm for the Win32 platform
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#include "Win32Private.h"
|
||||
|
||||
HWND SST_WM_GetHWNDWin32(SST_Window window)
|
||||
{
|
||||
return ((SST_Window_Win32*)window)->hWnd;
|
||||
}
|
||||
|
||||
848
libsst-wm/Win32/SST_WMOpenGL_Win32.c
Normal file
848
libsst-wm/Win32/SST_WMOpenGL_Win32.c
Normal file
@@ -0,0 +1,848 @@
|
||||
/*
|
||||
SST_WMOpenGL_Win32.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 6/28/2012
|
||||
|
||||
Purpose:
|
||||
|
||||
OpenGL context creation
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
#include <SST/SST_WMOpenGL.h>
|
||||
#include "Win32Private.h"
|
||||
#include "../APIPrivate.h"
|
||||
#include <GL/gl.h>
|
||||
|
||||
/*
|
||||
NOTE: Herein lines madness. Abandon faith all ye who would enter.
|
||||
|
||||
Windows has been notoriously bad at keeping up with OpenGL progress. In particular, to get a modern context,
|
||||
one must:
|
||||
|
||||
1) Create a fake window
|
||||
2) Select a fake pixel format
|
||||
4) Create a fake GL context
|
||||
5) Bind that context
|
||||
6) Resolve the wglGetExtensionStringARB() symbol
|
||||
7) Call wglGetExtensionStringARB() and check for various WGL extensions
|
||||
8) Resolve required extensions
|
||||
9) Select a real pixel format
|
||||
10) Create a real context
|
||||
|
||||
This doesn't even consider the complexity of handling issues such as pushing/popping the current OpenGL context
|
||||
so that calling SST_WM_CreateOpenGLContext() doesn't result in losing the currently active context, or providing
|
||||
fallbacks in case the person wants GL <= 2.x and doesn't have the GL >= 3.x WGL extensions. So much madness.
|
||||
*/
|
||||
|
||||
/* Create a temporary 1x1 window that is invisible */
|
||||
static HWND createTmpWindow(SST_DisplayTarget_Win32* copyFrom);
|
||||
|
||||
/* Create OpenGL context that would probably work with Windows 95 */
|
||||
static SST_OpenGLContext legacyCreateOpenGLContext(SST_DisplayTarget_Win32* win, const SST_OpenGLContextAttributes* attribs, SST_OpenGLContextAttributes* selectedAttribsReturn, HMODULE opengl32, WGLFunctions* wgl);
|
||||
|
||||
/* Use wglChoosePixelFormatARB() to find a useful pixel format */
|
||||
static int modernChoosePixelFormat(HDC hDC, WGLFunctions* wgl, const SST_OpenGLContextAttributes* attribs);
|
||||
|
||||
/* Get selected pixel format return value information */
|
||||
static void modernGetPixelInfo(HDC hDC, int format, WGLFunctions* wgl, SST_OpenGLContextAttributes* selectedAttribsReturn);
|
||||
|
||||
static int* addAttr(int* ptr, int x, int y)
|
||||
{
|
||||
ptr[0] = x;
|
||||
ptr[1] = y;
|
||||
return ptr + 2;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static SST_OpenGLContext Win32_CreateOpenGLContext(SST_DisplayTarget target, SST_WMOpenGLType apiType, const SST_OpenGLContextAttributes* attribs, SST_OpenGLContextAttributes* selectedAttribsReturn)
|
||||
{
|
||||
HMODULE opengl32;
|
||||
HWND hTmpWnd, hTmpWnd2;
|
||||
HDC hTmpDC, hTmpDC2, oldDC = NULL;
|
||||
HGLRC hTmpCtx, oldRC = NULL;
|
||||
PIXELFORMATDESCRIPTOR pfd;
|
||||
WGLFunctions wgl;
|
||||
SST_DisplayTarget_Win32* displayTarget = (SST_DisplayTarget_Win32*)target;
|
||||
SST_OpenGLContext_Win32* glctx;
|
||||
int format;
|
||||
int OK;
|
||||
|
||||
/* Win32 doesn't have OpenGL ES AFAIK. */
|
||||
if(apiType == SSTGL_OPENGL_ES)
|
||||
return NULL;
|
||||
|
||||
/* Load opengl32.dll */
|
||||
opengl32 = LoadLibraryA("opengl32.dll");
|
||||
if(opengl32 == NULL)
|
||||
return NULL;
|
||||
|
||||
memset(&wgl, 0, sizeof(wgl));
|
||||
resolveWGLSymbols(opengl32, &wgl);
|
||||
|
||||
/*
|
||||
OK, this next code attempts to create an invisible window which can then be used
|
||||
to bind a fake GL context to. This allows us to grab WGL extensions for advanced
|
||||
OpenGL context creation (i.e. forward compatible contexts). If this isn't supported,
|
||||
then old style context creation will be used as a fallback.
|
||||
*/
|
||||
hTmpWnd = createTmpWindow(displayTarget);
|
||||
if(hTmpWnd == NULL)
|
||||
{
|
||||
FreeLibrary(opengl32);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Grab the window's DC */
|
||||
hTmpDC = GetDC(hTmpWnd);
|
||||
|
||||
/* Initialize pixel format descriptor to find 24-bit color / double-buffered / render to window */
|
||||
memset(&pfd, 0, sizeof(pfd));
|
||||
pfd.nSize = sizeof(pfd);
|
||||
pfd.nVersion = 1;
|
||||
pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW;
|
||||
pfd.iPixelType = PFD_TYPE_RGBA;
|
||||
pfd.cColorBits = 24;
|
||||
pfd.cRedBits = 8;
|
||||
pfd.cGreenBits = 8;
|
||||
pfd.cBlueBits = 8;
|
||||
pfd.cDepthBits = 24;
|
||||
pfd.iLayerType = PFD_MAIN_PLANE;
|
||||
|
||||
/* Attempt to find a matching pixel format */
|
||||
OK = 0;
|
||||
hTmpCtx = NULL;
|
||||
format = ChoosePixelFormat(hTmpDC, &pfd);
|
||||
if(format > 0)
|
||||
{
|
||||
/* Attempt to set the pixel format */
|
||||
OK = (int)SetPixelFormat(hTmpDC, format, &pfd);
|
||||
if(OK)
|
||||
{
|
||||
/* Create the context */
|
||||
hTmpCtx = wgl.CreateContext(hTmpDC);
|
||||
OK = (hTmpCtx != NULL);
|
||||
|
||||
/* Bind it */
|
||||
if(OK)
|
||||
{
|
||||
/* Save old context */
|
||||
oldDC = wgl.GetCurrentDC();
|
||||
oldRC = wgl.GetCurrentContext();
|
||||
|
||||
OK = (int)wgl.MakeCurrent(hTmpDC, hTmpCtx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Failed in any of these steps? */
|
||||
if(!OK)
|
||||
{
|
||||
if(hTmpCtx != NULL)
|
||||
{
|
||||
wgl.DeleteContext(hTmpCtx);
|
||||
|
||||
/* Restore old context (since wglMakeCurrent() failed with new context) */
|
||||
wgl.MakeCurrent(oldDC, oldRC);
|
||||
|
||||
}
|
||||
ReleaseDC(hTmpWnd, hTmpDC);
|
||||
DestroyWindow(hTmpWnd);
|
||||
FreeLibrary(opengl32);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Resolve context-specific strings */
|
||||
resolveWGLExtSymbols(hTmpDC, &wgl);
|
||||
|
||||
/* Only "legacy" context functions allowed? */
|
||||
if(wgl.ChoosePixelFormatARB == NULL || wgl.CreateContextAttribsARB == NULL)
|
||||
{
|
||||
/* Remove temporary context / window, they aren't needed for legacy contexts */
|
||||
wgl.MakeCurrent(oldDC, oldRC);
|
||||
wgl.DeleteContext(hTmpCtx);
|
||||
ReleaseDC(hTmpWnd, hTmpDC);
|
||||
DestroyWindow(hTmpWnd);
|
||||
|
||||
/* Just make a legacy context */
|
||||
return legacyCreateOpenGLContext(displayTarget, attribs, selectedAttribsReturn, opengl32, &wgl);
|
||||
}
|
||||
else /* "Modern" context creation */
|
||||
{
|
||||
#define MAX_CTX_ATTRS 16
|
||||
int contextAttrs[MAX_CTX_ATTRS];
|
||||
int* ptr;
|
||||
HGLRC hGLRC;
|
||||
size_t i;
|
||||
int ctxFlags = 0;
|
||||
|
||||
/* Create another set of temporary handles. Since we already called
|
||||
SetPixelFormat() on hTmpDC, we can't set it to the new pixel format
|
||||
that we picked with modernChoosePixelFormat(). Thus, if we do wglCreateContext() with
|
||||
hTmpDC, we'll get an invalid context. Instead, create a new window/DC and use the new
|
||||
pixel format. */
|
||||
hTmpWnd2 = createTmpWindow(displayTarget);
|
||||
hTmpDC2 = GetDC(hTmpWnd2);
|
||||
|
||||
/* Choose a pixel format */
|
||||
format = modernChoosePixelFormat(hTmpDC2, &wgl, attribs);
|
||||
if(format == 0)
|
||||
{
|
||||
wgl.MakeCurrent(oldDC, oldRC);
|
||||
wgl.DeleteContext(hTmpCtx);
|
||||
ReleaseDC(hTmpWnd, hTmpDC);
|
||||
DestroyWindow(hTmpWnd);
|
||||
}
|
||||
SetPixelFormat(hTmpDC2, format, NULL);
|
||||
|
||||
i = 0;
|
||||
|
||||
if(attribs->debugEnabled)
|
||||
ctxFlags |= WGL_CONTEXT_DEBUG_BIT_ARB;
|
||||
ptr = contextAttrs;
|
||||
ptr = addAttr(ptr, WGL_CONTEXT_MAJOR_VERSION_ARB, attribs->contextVersionMajor);
|
||||
ptr = addAttr(ptr, WGL_CONTEXT_MINOR_VERSION_ARB, attribs->contextVersionMinor);
|
||||
ptr = addAttr(ptr, WGL_CONTEXT_LAYER_PLANE_ARB, 0);
|
||||
|
||||
/* If WGL_ARB_create_context_profile is supported, add a profile mask */
|
||||
if(wgl.supportsProfiles)
|
||||
ptr = addAttr(ptr, WGL_CONTEXT_PROFILE_MASK_ARB, (attribs->legacyEnabled ? WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB : WGL_CONTEXT_CORE_PROFILE_BIT_ARB));
|
||||
|
||||
/* Legacy-free? */
|
||||
if(!attribs->legacyEnabled)
|
||||
ctxFlags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
|
||||
|
||||
/* Debug mode? */
|
||||
if(attribs->debugEnabled)
|
||||
ctxFlags |= WGL_CONTEXT_DEBUG_BIT_ARB;
|
||||
|
||||
ptr = addAttr(ptr, WGL_CONTEXT_FLAGS_ARB, ctxFlags);
|
||||
*ptr = 0;
|
||||
|
||||
|
||||
|
||||
/* Create the OpenGL context */
|
||||
hGLRC = wgl.CreateContextAttribsARB(hTmpDC2, NULL, contextAttrs);
|
||||
glctx = (SST_OpenGLContext_Win32*)HeapAlloc(GetProcessHeap(), 0, sizeof(SST_OpenGLContext_Win32));
|
||||
if(hGLRC == NULL || glctx == NULL)
|
||||
{
|
||||
if(hGLRC != NULL)
|
||||
wgl.DeleteContext(hGLRC);
|
||||
if(glctx != NULL)
|
||||
HeapFree(GetProcessHeap(), 0, glctx);
|
||||
wgl.MakeCurrent(oldDC, oldRC);
|
||||
wgl.DeleteContext(hTmpCtx);
|
||||
ReleaseDC(hTmpWnd, hTmpDC);
|
||||
DestroyWindow(hTmpWnd);
|
||||
ReleaseDC(hTmpWnd2, hTmpDC2);
|
||||
DestroyWindow(hTmpWnd2);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
glctx->displayTarget = displayTarget;
|
||||
glctx->context = hGLRC;
|
||||
glctx->hDCActive = NULL;
|
||||
glctx->hSlaveWnd = NULL;
|
||||
glctx->opengl32 = opengl32;
|
||||
glctx->pixelFormat = format;
|
||||
glctx->wgl = wgl;
|
||||
glctx->isLegacy = FALSE;
|
||||
glctx->ctxVersion[0] = (short)attribs->contextVersionMajor;
|
||||
glctx->ctxVersion[1] = (short)attribs->contextVersionMinor;
|
||||
glctx->legacyEnabled = attribs->legacyEnabled? TRUE : FALSE;
|
||||
glctx->debugEnabled = attribs->debugEnabled? TRUE : FALSE;
|
||||
|
||||
if(selectedAttribsReturn)
|
||||
{
|
||||
modernGetPixelInfo(hTmpDC2, format, &wgl, selectedAttribsReturn);
|
||||
selectedAttribsReturn->contextVersionMajor = attribs->contextVersionMajor;
|
||||
selectedAttribsReturn->contextVersionMinor = attribs->contextVersionMinor;
|
||||
selectedAttribsReturn->legacyEnabled = (attribs->legacyEnabled ? 1 : 0);
|
||||
selectedAttribsReturn->debugEnabled = (ctxFlags & WGL_CONTEXT_DEBUG_BIT_ARB ? 1 : 0);
|
||||
}
|
||||
|
||||
/* Delete temporary window */
|
||||
wgl.MakeCurrent(oldDC, oldRC);
|
||||
wgl.DeleteContext(hTmpCtx);
|
||||
ReleaseDC(hTmpWnd, hTmpDC);
|
||||
DestroyWindow(hTmpWnd);
|
||||
ReleaseDC(hTmpWnd2, hTmpDC2);
|
||||
DestroyWindow(hTmpWnd2);
|
||||
}
|
||||
|
||||
return glctx;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static SST_OpenGLContext Win32_CreateSlaveOpenGLContext(SST_OpenGLContext masterGLContext)
|
||||
{
|
||||
SST_OpenGLContext_Win32* master = (SST_OpenGLContext_Win32*)masterGLContext;
|
||||
SST_OpenGLContext_Win32* slave;
|
||||
HWND hInvisWnd;
|
||||
FindMonitorInfo fmi;
|
||||
HDC hDC = NULL;
|
||||
HGLRC hGLRC = NULL;
|
||||
BOOL ok;
|
||||
const WGLFunctions* wgl = &master->wgl;
|
||||
|
||||
/* Since the slave context merely needs to be on *a* screen controlled by the display target, just use the first one */
|
||||
findMonitor(&master->displayTarget->devs[0], &fmi);
|
||||
if(!fmi.foundIt)
|
||||
return NULL;
|
||||
|
||||
/* Make 1x1 hidden window that doesn't appear in the titlebar and has no borders */
|
||||
hInvisWnd = CreateWindowExA(WS_EX_TOOLWINDOW, SST_WINCLASS, "(temp)", WS_POPUP, fmi.left, fmi.top, 1, 1, NULL, NULL, GetModuleHandleA(NULL), NULL);
|
||||
if(hInvisWnd == NULL)
|
||||
return NULL;
|
||||
ShowWindow(hInvisWnd, SW_HIDE);
|
||||
|
||||
/* Allocate context structure */
|
||||
slave = HeapAlloc(GetProcessHeap(), 0, sizeof(SST_OpenGLContext_Win32));
|
||||
if(slave == NULL)
|
||||
{
|
||||
DestroyWindow(hInvisWnd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ok = FALSE;
|
||||
hDC = GetDC(hInvisWnd);
|
||||
|
||||
/* If master context was done using legacy functions... */
|
||||
if(master->isLegacy)
|
||||
{
|
||||
PIXELFORMATDESCRIPTOR pfd;
|
||||
|
||||
/* Get the PFD for this pixel foramt */
|
||||
DescribePixelFormat(hDC, master->pixelFormat, sizeof(pfd), &pfd);
|
||||
|
||||
/* Set it */
|
||||
if(SetPixelFormat(hDC, master->pixelFormat, &pfd))
|
||||
{
|
||||
hGLRC = wgl->CreateContext(hDC);
|
||||
if(hGLRC != NULL)
|
||||
{
|
||||
if(wgl->ShareLists(master->context, hGLRC))
|
||||
ok = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else /* Modern OpenGL functions */
|
||||
{
|
||||
if(SetPixelFormat(hDC, master->pixelFormat, NULL))
|
||||
{
|
||||
HGLRC oldRC;
|
||||
HDC oldDC;
|
||||
|
||||
oldDC = wgl->GetCurrentDC();
|
||||
oldRC = wgl->GetCurrentContext();
|
||||
|
||||
/* Bind master context so we can call wgl extension functions. Note that we're using
|
||||
the invisible window's HDC. This should work because we just set the pixel format to be
|
||||
identical to the master context, meaning they should be compatible */
|
||||
if(wgl->MakeCurrent(hDC, master->context))
|
||||
{
|
||||
int attrs[16];
|
||||
int* ptr = attrs;
|
||||
int ctxFlags;
|
||||
|
||||
if(master->debugEnabled)
|
||||
ctxFlags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
|
||||
|
||||
ptr = addAttr(ptr, WGL_CONTEXT_MAJOR_VERSION_ARB, master->ctxVersion[0]);
|
||||
ptr = addAttr(ptr, WGL_CONTEXT_MINOR_VERSION_ARB, master->ctxVersion[1]);
|
||||
ptr = addAttr(ptr, WGL_CONTEXT_LAYER_PLANE_ARB, 0);
|
||||
|
||||
/* If WGL_ARB_create_context_profile is supported, add a profile mask */
|
||||
if(wgl->supportsProfiles)
|
||||
ptr = addAttr(ptr, WGL_CONTEXT_PROFILE_MASK_ARB, (master->legacyEnabled ? WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB : WGL_CONTEXT_CORE_PROFILE_BIT_ARB));
|
||||
|
||||
/* Legacy-free? */
|
||||
if(!master->legacyEnabled)
|
||||
ctxFlags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
|
||||
|
||||
/* Debug mode? */
|
||||
if(master->debugEnabled)
|
||||
ctxFlags |= WGL_CONTEXT_DEBUG_BIT_ARB;
|
||||
|
||||
ptr = addAttr(ptr, WGL_CONTEXT_FLAGS_ARB, ctxFlags);
|
||||
*ptr = 0;
|
||||
|
||||
/* Create the new context, sharing with the master context */
|
||||
hGLRC = wgl->CreateContextAttribsARB(hDC, master->context, attrs);
|
||||
if(hGLRC != NULL)
|
||||
ok = TRUE;
|
||||
}
|
||||
|
||||
/* Restore old context */
|
||||
wgl->MakeCurrent(oldDC, oldRC);
|
||||
}
|
||||
}
|
||||
|
||||
/* Done with the DC */
|
||||
if(hDC)
|
||||
ReleaseDC(hInvisWnd, hDC);
|
||||
|
||||
/* Did we succeed in making the slave context? */
|
||||
if(ok)
|
||||
{
|
||||
/* Set up slave context info */
|
||||
slave->context = hGLRC;
|
||||
slave->displayTarget = master->displayTarget;
|
||||
slave->hDCActive = NULL;
|
||||
slave->hSlaveWnd = hInvisWnd;
|
||||
slave->isLegacy = master->isLegacy;
|
||||
slave->opengl32 = LoadLibraryA("opengl32.dll"); /* Need to increase ref count for opengl32.dll */
|
||||
slave->pixelFormat = master->pixelFormat;
|
||||
slave->wgl = master->wgl; /* TODO: should be safe, right? context dependent, but same device/GL impl... */
|
||||
slave->ctxVersion[0] = master->ctxVersion[0];
|
||||
slave->ctxVersion[1] = master->ctxVersion[1];
|
||||
slave->legacyEnabled = master->legacyEnabled;
|
||||
slave->debugEnabled = master->debugEnabled;
|
||||
}
|
||||
else /* Failure, clean up */
|
||||
{
|
||||
if(hGLRC)
|
||||
master->wgl.DeleteContext(hGLRC);
|
||||
|
||||
DestroyWindow(hInvisWnd);
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, slave);
|
||||
slave = NULL;
|
||||
}
|
||||
|
||||
return slave;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static void Win32_SwapOpenGLBuffers(SST_OpenGLContext ctx)
|
||||
{
|
||||
SST_OpenGLContext_Win32* glctx = (SST_OpenGLContext_Win32*)ctx;
|
||||
|
||||
SwapBuffers(glctx->hDCActive);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static int Win32_BindOpenGLContext(SST_OpenGLContext ctx, SST_Window window)
|
||||
{
|
||||
SST_OpenGLContext_Win32* glctx = (SST_OpenGLContext_Win32*)ctx;
|
||||
SST_Window_Win32* win = (SST_Window_Win32*)window;
|
||||
|
||||
/* Unbinding a context from a thread */
|
||||
if(ctx == NULL)
|
||||
{
|
||||
HMODULE opengl32;
|
||||
|
||||
/* We actually need some WGL symbols. Oops. That's OK, we can just grab the symbol */
|
||||
pf_wglMakeCurrent sst_wglMakeCurrent;
|
||||
pf_wglGetCurrentDC sst_wglGetCurrentDC;
|
||||
|
||||
/* We use LoadLibrary() instead of GetModuleHandle() so that we don't unmap the DLL
|
||||
in the middle of using it. */
|
||||
opengl32 = LoadLibraryA("opengl32.dll");
|
||||
if(opengl32)
|
||||
{
|
||||
HDC hDC;
|
||||
HWND hWnd;
|
||||
|
||||
sst_wglMakeCurrent = (pf_wglMakeCurrent)GetProcAddress(opengl32, "wglMakeCurrent");
|
||||
sst_wglGetCurrentDC = (pf_wglGetCurrentDC)GetProcAddress(opengl32, "wglGetCurrentDC");
|
||||
|
||||
/* Release the DC */
|
||||
hDC = sst_wglGetCurrentDC();
|
||||
hWnd = WindowFromDC(hDC);
|
||||
if(hDC != NULL && hWnd != NULL)
|
||||
ReleaseDC(hWnd, hDC);
|
||||
|
||||
/* OK, unbind it */
|
||||
sst_wglMakeCurrent(NULL, NULL);
|
||||
|
||||
FreeLibrary(opengl32);
|
||||
}
|
||||
|
||||
/* OK */
|
||||
return 1;
|
||||
}
|
||||
else /* Have a valid context */
|
||||
{
|
||||
HDC hDC, oldDC;
|
||||
HGLRC oldRC;
|
||||
|
||||
if( (glctx->hSlaveWnd != NULL && win != NULL) || /* Slave context provided a SST_Window */
|
||||
(glctx->hSlaveWnd == NULL && win == NULL) /* Master context with no SST_Window */
|
||||
)
|
||||
{
|
||||
/* Both are illegal according the the functions */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get old context info */
|
||||
oldDC = glctx->wgl.GetCurrentDC();
|
||||
oldRC = glctx->wgl.GetCurrentContext();
|
||||
|
||||
/* First, are we re-binding the same context? If so, then just return "success" */
|
||||
if( oldDC != NULL && oldRC != NULL &&
|
||||
oldDC == glctx->hDCActive && oldRC == glctx->context)
|
||||
return 1;
|
||||
|
||||
/* Binding master context to a window */
|
||||
if(win != NULL)
|
||||
{
|
||||
hDC = GetDC(win->hWnd);
|
||||
|
||||
/* Haven't set the pixel format for this window yet? */
|
||||
if(!win->setPixelFormat)
|
||||
{
|
||||
PIXELFORMATDESCRIPTOR pfd;
|
||||
DescribePixelFormat(hDC, glctx->pixelFormat, sizeof(pfd), &pfd);
|
||||
|
||||
if(SetPixelFormat(hDC, glctx->pixelFormat, &pfd))
|
||||
{
|
||||
/* OK, mark that we've set this window's pixel format once, and we won't do it again. */
|
||||
win->setPixelFormat = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Failed to set this window's pixel format, so we can't do much */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else /* Bind slave context */
|
||||
{
|
||||
hDC = GetDC(glctx->hSlaveWnd);
|
||||
|
||||
}
|
||||
|
||||
/* Make current */
|
||||
if(!glctx->wgl.MakeCurrent(hDC, glctx->context))
|
||||
{
|
||||
/* Failed -- restore old context settings */
|
||||
glctx->wgl.MakeCurrent(oldDC, oldRC);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Since we were successful, release the old DC */
|
||||
if(oldDC)
|
||||
{
|
||||
HWND hWnd = WindowFromDC(oldDC);
|
||||
if(hWnd)
|
||||
ReleaseDC(hWnd, oldDC);
|
||||
}
|
||||
|
||||
/* Save window / DC */
|
||||
glctx->hDCActive = hDC;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static void Win32_DestroyOpenGLContext(SST_OpenGLContext ctx)
|
||||
{
|
||||
SST_OpenGLContext_Win32* glctx = (SST_OpenGLContext_Win32*)ctx;
|
||||
|
||||
if(glctx->hSlaveWnd)
|
||||
DestroyWindow(glctx->hSlaveWnd);
|
||||
|
||||
glctx->wgl.DeleteContext(glctx->context);
|
||||
FreeLibrary(glctx->opengl32);
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, glctx);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static HWND createTmpWindow(SST_DisplayTarget_Win32* copyFrom)
|
||||
{
|
||||
HWND hTmpWnd;
|
||||
FindMonitorInfo fmi;
|
||||
|
||||
/* Find the first monitor */
|
||||
findMonitor(©From->devs[0], &fmi);
|
||||
if(!fmi.foundIt)
|
||||
return NULL;
|
||||
|
||||
/* Make 1x1 hidden window that doesn't appear in the titlebar and has no borders */
|
||||
hTmpWnd = CreateWindowExA(WS_EX_TOOLWINDOW, SST_WINCLASS, "(temp)", WS_POPUP, fmi.left, fmi.top, 1, 1, NULL, NULL, GetModuleHandleA(NULL), NULL);
|
||||
if(hTmpWnd == NULL)
|
||||
return NULL;
|
||||
|
||||
ShowWindow(hTmpWnd, SW_HIDE);
|
||||
|
||||
return hTmpWnd;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static SST_OpenGLContext legacyCreateOpenGLContext(SST_DisplayTarget_Win32* displayTarget, const SST_OpenGLContextAttributes* attribs, SST_OpenGLContextAttributes* selectedAttribsReturn, HMODULE opengl32, WGLFunctions* wgl)
|
||||
{
|
||||
PIXELFORMATDESCRIPTOR pfd;
|
||||
HWND hWnd;
|
||||
HDC hDC, oldDC = NULL;
|
||||
HGLRC hGLRC, oldRC = NULL;
|
||||
int format;
|
||||
int major, minor;
|
||||
const char* version;
|
||||
const GLubyte* (APIENTRY *sst_glGetString)(GLenum);
|
||||
SST_OpenGLContext_Win32* ctx;
|
||||
BYTE rgb[3] = { 1, 1, 1 };
|
||||
|
||||
/* No multisample support, but 2x or greater MSAA requested -> fail */
|
||||
if(attribs->multisampleFactor > 1)
|
||||
{
|
||||
FreeLibrary(opengl32);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Allocate a GL context */
|
||||
ctx = (SST_OpenGLContext_Win32*)HeapAlloc(GetProcessHeap(), 0, sizeof(SST_OpenGLContext_Win32));
|
||||
if(ctx == NULL)
|
||||
{
|
||||
FreeLibrary(opengl32);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get window DC */
|
||||
hWnd = createTmpWindow(displayTarget);
|
||||
hDC = GetDC(hWnd);
|
||||
|
||||
/* We can't do MSAA at all, though */
|
||||
if(attribs->multisampleFactor > 1)
|
||||
{
|
||||
FreeLibrary(opengl32);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Figure out how to set up color bits. These are minimums. MSDN states that they
|
||||
are "Not used", but be safe anyways. */
|
||||
if(attribs->colorBits == 24)
|
||||
{
|
||||
rgb[0] = rgb[1] = rgb[2] = 8;
|
||||
}
|
||||
else if(attribs->colorBits == 16 || attribs->colorBits == 15)
|
||||
{
|
||||
/* 555 or 565 color. Set all to 5 since "minimum" of 5 allows for 565 too */
|
||||
rgb[0] = rgb[1] = rgb[2] = 5;
|
||||
}
|
||||
|
||||
/* Initialize the PFD */
|
||||
memset(&pfd, 0, sizeof(pfd));
|
||||
pfd.nSize = sizeof(pfd);
|
||||
pfd.nVersion = 1;
|
||||
pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW | (attribs->stereoEnabled? PFD_STEREO : 0);
|
||||
pfd.iPixelType = PFD_TYPE_RGBA;
|
||||
pfd.cColorBits = attribs->colorBits;
|
||||
pfd.cAlphaBits = attribs->alphaBits;
|
||||
pfd.cRedBits = rgb[0];
|
||||
pfd.cGreenBits = rgb[1];
|
||||
pfd.cBlueBits = rgb[2];
|
||||
pfd.cDepthBits = attribs->depthBits;
|
||||
pfd.cStencilBits = attribs->stencilBits;
|
||||
pfd.iLayerType = PFD_MAIN_PLANE;
|
||||
|
||||
/* Get a compatiable pixel format */
|
||||
format = ChoosePixelFormat(hDC, &pfd);
|
||||
if(format == 0)
|
||||
{
|
||||
ReleaseDC(hWnd, hDC);
|
||||
DestroyWindow(hWnd);
|
||||
FreeLibrary(opengl32);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get info about the pixel format we're using */
|
||||
if(selectedAttribsReturn != NULL)
|
||||
{
|
||||
PIXELFORMATDESCRIPTOR spfd;
|
||||
DescribePixelFormat(hDC, format, sizeof(spfd), &spfd);
|
||||
|
||||
selectedAttribsReturn->alphaBits = pfd.cAlphaBits;
|
||||
selectedAttribsReturn->colorBits = pfd.cColorBits;
|
||||
selectedAttribsReturn->contextVersionMajor = 0;
|
||||
selectedAttribsReturn->contextVersionMinor = 0;
|
||||
selectedAttribsReturn->depthBits = pfd.cDepthBits;
|
||||
selectedAttribsReturn->multisampleFactor = 1;
|
||||
selectedAttribsReturn->stencilBits = pfd.cStencilBits;
|
||||
selectedAttribsReturn->stereoEnabled = (pfd.dwFlags & PFD_STEREO);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* Set the pixel format for the device */
|
||||
if(!SetPixelFormat(hDC, format, &pfd))
|
||||
{
|
||||
ReleaseDC(hWnd, hDC);
|
||||
DestroyWindow(hWnd);
|
||||
FreeLibrary(opengl32);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Create the GL context */
|
||||
hGLRC = wgl->CreateContext(hDC);
|
||||
if(hGLRC == NULL)
|
||||
{
|
||||
ReleaseDC(hWnd, hDC);
|
||||
DestroyWindow(hWnd);
|
||||
FreeLibrary(opengl32);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Activate the context to see if correct version was set */
|
||||
oldDC = wgl->GetCurrentDC();
|
||||
oldRC = wgl->GetCurrentContext();
|
||||
if(!wgl->MakeCurrent(hDC, hGLRC))
|
||||
{
|
||||
wgl->DeleteContext(hGLRC);
|
||||
ReleaseDC(hWnd, hDC);
|
||||
DestroyWindow(hWnd);
|
||||
FreeLibrary(opengl32);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Resolve glGetString() and call it to check version number matching */
|
||||
sst_glGetString = (const GLubyte* (APIENTRY*)(GLenum name))GetProcAddress(opengl32, "glGetString");
|
||||
version = (const char*)sst_glGetString(GL_VERSION);
|
||||
major = (int)(version[0] - '0'); /* "X.Y" -> [0]:major, [2]:minor */
|
||||
minor = (int)(version[2] - '0');
|
||||
|
||||
/* Got version info. Detach our context, restore old one */
|
||||
wgl->MakeCurrent(oldDC, oldRC);
|
||||
|
||||
/* Save context version information */
|
||||
if(selectedAttribsReturn != NULL)
|
||||
{
|
||||
selectedAttribsReturn->contextVersionMajor = (uint8_t)major;
|
||||
selectedAttribsReturn->contextVersionMinor = (uint8_t)minor;
|
||||
}
|
||||
|
||||
/* If the major version is too low or the major version is OK, but the minor version is lacking, then fail */
|
||||
if(major < attribs->contextVersionMajor ||
|
||||
(major == attribs->contextVersionMajor && minor < attribs->contextVersionMinor))
|
||||
{
|
||||
wgl->DeleteContext(hGLRC);
|
||||
ReleaseDC(hWnd, hDC);
|
||||
DestroyWindow(hWnd);
|
||||
FreeLibrary(opengl32);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ReleaseDC(hWnd, hDC);
|
||||
DestroyWindow(hWnd);
|
||||
|
||||
ctx->displayTarget = displayTarget;
|
||||
ctx->hSlaveWnd = NULL;
|
||||
ctx->hDCActive = NULL;
|
||||
ctx->opengl32 = opengl32;
|
||||
ctx->wgl = *wgl;
|
||||
ctx->pixelFormat = format;
|
||||
ctx->context = hGLRC;
|
||||
ctx->isLegacy = TRUE;
|
||||
ctx->ctxVersion[0] = (short)major;
|
||||
ctx->ctxVersion[1] = (short)minor;
|
||||
ctx->legacyEnabled = FALSE; /* These refer to profiles in GL >= 3.x contexts. Here they are meaningless, so set to false */
|
||||
ctx->debugEnabled = FALSE;
|
||||
|
||||
return (SST_OpenGLContext)ctx;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static int modernChoosePixelFormat(HDC hDC, WGLFunctions* wgl, const SST_OpenGLContextAttributes* attribs)
|
||||
{
|
||||
int attrs[MAX_GL_ATTRS];
|
||||
int format;
|
||||
int* ptr = attrs;
|
||||
UINT nrFormats;
|
||||
BOOL ok;
|
||||
|
||||
|
||||
/* Set up basic attributes */
|
||||
ptr = addAttr(ptr, WGL_DRAW_TO_WINDOW_ARB, GL_TRUE);
|
||||
ptr = addAttr(ptr, WGL_SUPPORT_OPENGL_ARB, GL_TRUE);
|
||||
ptr = addAttr(ptr, WGL_DOUBLE_BUFFER_ARB, GL_TRUE);
|
||||
ptr = addAttr(ptr, WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB);
|
||||
ptr = addAttr(ptr, WGL_COLOR_BITS_ARB, attribs->colorBits);
|
||||
ptr = addAttr(ptr, WGL_ALPHA_BITS_ARB, attribs->alphaBits);
|
||||
ptr = addAttr(ptr, WGL_DEPTH_BITS_ARB, attribs->depthBits);
|
||||
ptr = addAttr(ptr, WGL_STENCIL_BITS_ARB, attribs->stencilBits);
|
||||
ptr = addAttr(ptr, WGL_STEREO_ARB, attribs->stereoEnabled ? GL_TRUE : GL_FALSE); /* Must be GL_TRUE || GL_FALSE, not just "non-zero" */
|
||||
|
||||
/* Multisampling requested? */
|
||||
if(attribs->multisampleFactor > 1)
|
||||
{
|
||||
/* Is it supported? */
|
||||
if(wgl->supportsMultisample)
|
||||
{
|
||||
ptr = addAttr(ptr, WGL_SAMPLE_BUFFERS_ARB, 1);
|
||||
ptr = addAttr(ptr, WGL_SAMPLES_ARB, attribs->multisampleFactor);
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
*ptr = 0;
|
||||
|
||||
nrFormats = 0;
|
||||
/* Attempt to get pixel formats that match ours */
|
||||
ok = wgl->ChoosePixelFormatARB(hDC, attrs, NULL, 1, &format, &nrFormats);
|
||||
|
||||
/* This can return success with 0 formats, so check if it was actually "successful" in finding > 0 formats */
|
||||
if(!ok || nrFormats == 0)
|
||||
return 0;
|
||||
|
||||
return format;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static void modernGetPixelInfo(HDC hDC, int format, WGLFunctions* wgl, SST_OpenGLContextAttributes* selectedAttribsReturn)
|
||||
{
|
||||
int attrs[8];
|
||||
int values[8] = { 0 };
|
||||
int attrCount;
|
||||
|
||||
attrs[0] = WGL_COLOR_BITS_ARB;
|
||||
attrs[1] = WGL_ALPHA_BITS_ARB;
|
||||
attrs[2] = WGL_DEPTH_BITS_ARB;
|
||||
attrs[3] = WGL_STENCIL_BITS_ARB;
|
||||
attrs[4] = WGL_STEREO_ARB;
|
||||
attrs[5] = WGL_SAMPLE_BUFFERS_ARB;
|
||||
|
||||
/* Check multisample */
|
||||
attrCount = (wgl->supportsMultisample ? 6 : 5);
|
||||
|
||||
|
||||
wgl->GetPixelFormatAttribivARB(hDC, format, 0, attrCount, attrs, values);
|
||||
|
||||
|
||||
selectedAttribsReturn->colorBits = (uint8_t)values[0];
|
||||
selectedAttribsReturn->alphaBits = (uint8_t)values[1];
|
||||
selectedAttribsReturn->depthBits = (uint8_t)values[2];
|
||||
selectedAttribsReturn->stencilBits = (uint8_t)values[3];
|
||||
selectedAttribsReturn->stereoEnabled = (uint8_t)values[4];
|
||||
if(wgl->supportsMultisample)
|
||||
selectedAttribsReturn->multisampleFactor = (uint8_t)values[5];
|
||||
else
|
||||
selectedAttribsReturn->multisampleFactor = 1;
|
||||
|
||||
}
|
||||
|
||||
const struct SST_WM_OpenGLFuncs Win32_OpenGLFuncs = {
|
||||
Win32_CreateOpenGLContext,
|
||||
Win32_CreateSlaveOpenGLContext,
|
||||
Win32_SwapOpenGLBuffers,
|
||||
Win32_BindOpenGLContext,
|
||||
Win32_DestroyOpenGLContext
|
||||
};
|
||||
97
libsst-wm/Win32/SST_WMRender_Win32.c
Normal file
97
libsst-wm/Win32/SST_WMRender_Win32.c
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
SST_WMRender_Win32.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 9/19/2012
|
||||
|
||||
Purpose:
|
||||
|
||||
Software rendering support (Win32)
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#include "Win32Private.h"
|
||||
#include "../APIPrivate.h"
|
||||
#include <SST/SST_WMWindow.h>
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static int Win32_EnableSoftwareRendering(SST_Window window)
|
||||
{
|
||||
SST_Window_Win32* win = (SST_Window_Win32*)window;
|
||||
HDC hDC;
|
||||
HDC hDCTmp;
|
||||
HBITMAP hBMP;
|
||||
RECT r;
|
||||
|
||||
hDCTmp = GetDC(win->hWnd);
|
||||
hDC = CreateCompatibleDC(hDCTmp);
|
||||
|
||||
if(GetDeviceCaps(hDCTmp, BITSPIXEL) != 32)
|
||||
{
|
||||
DeleteDC(hDC);
|
||||
return 0;
|
||||
}
|
||||
|
||||
GetClientRect(win->hWnd, &r);
|
||||
|
||||
hBMP = CreateCompatibleBitmap(hDCTmp, r.right, r.bottom);
|
||||
SelectObject(hDC, hBMP);
|
||||
|
||||
ReleaseDC(win->hWnd, hDCTmp);
|
||||
|
||||
win->softwareDC = hDC;
|
||||
win->softwareImage = hBMP;
|
||||
win->softwareBackbuffer = HeapAlloc(GetProcessHeap(), 0, (SIZE_T)r.right * (SIZE_T)r.bottom * 4);
|
||||
win->softwarePitch = r.right * 4;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static void Win32_DisableSoftwareRendering(SST_Window window)
|
||||
{
|
||||
SST_Window_Win32* win = (SST_Window_Win32*)window;
|
||||
|
||||
if(win->softwareBackbuffer)
|
||||
HeapFree(GetProcessHeap(), 0, win->softwareBackbuffer);
|
||||
if(win->softwareDC)
|
||||
DeleteDC(win->softwareDC);
|
||||
if(win->softwareImage)
|
||||
DeleteObject(win->softwareImage);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static void* Win32_LockBackbuffer(SST_Window window, size_t* pitchReturn)
|
||||
{
|
||||
SST_Window_Win32* win = (SST_Window_Win32*)window;
|
||||
|
||||
*pitchReturn = win->softwarePitch;
|
||||
|
||||
return win->softwareBackbuffer;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static void Win32_UnlockBackbuffer(SST_Window window)
|
||||
{
|
||||
SST_Window_Win32* win = (SST_Window_Win32*)window;
|
||||
InvalidateRect(win->hWnd, NULL, FALSE);
|
||||
UpdateWindow(win->hWnd);
|
||||
}
|
||||
|
||||
struct SST_WM_RenderFuncs Win32_RenderFuncs = {
|
||||
Win32_EnableSoftwareRendering,
|
||||
Win32_DisableSoftwareRendering,
|
||||
Win32_LockBackbuffer,
|
||||
Win32_UnlockBackbuffer
|
||||
};
|
||||
72
libsst-wm/Win32/SST_WMVideoMode_Win32.c
Normal file
72
libsst-wm/Win32/SST_WMVideoMode_Win32.c
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
SST_WMVideoMode_Win32.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 6/26/2012
|
||||
|
||||
Purpose:
|
||||
|
||||
Video mode setting functions
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#include "Win32Private.h"
|
||||
#include "../APIPrivate.h"
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static int Win32_SetVideoModeOnScreen(SST_DisplayTarget target, size_t screenIndex, const SST_VideoMode* vmode)
|
||||
{
|
||||
DEVMODEA devMode;
|
||||
SST_DisplayTarget_Win32* displayTarget = (SST_DisplayTarget_Win32*)target;
|
||||
const DISPLAY_DEVICEA* dev = &displayTarget->devs[screenIndex];
|
||||
|
||||
memset(&devMode, 0, sizeof(devMode));
|
||||
devMode.dmSize = sizeof(devMode);
|
||||
devMode.dmBitsPerPel = vmode->bpp;
|
||||
devMode.dmPelsWidth = vmode->width;
|
||||
devMode.dmPelsHeight = vmode->height;
|
||||
devMode.dmDisplayFrequency = vmode->refreshRate;
|
||||
devMode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY;
|
||||
|
||||
return (ChangeDisplaySettingsExA(dev->DeviceName, &devMode, NULL, CDS_FULLSCREEN, NULL) == DISP_CHANGE_SUCCESSFUL);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static int Win32_GetVideoModeOnScreen(SST_DisplayTarget target, size_t screenIndex, SST_VideoMode* vmodeReturn)
|
||||
{
|
||||
SST_DisplayTarget_Win32* displayTarget = (SST_DisplayTarget_Win32*)target;
|
||||
const DISPLAY_DEVICEA* dev = &displayTarget->devs[screenIndex];
|
||||
DEVMODEA devMode;
|
||||
int ok = 0;
|
||||
|
||||
devMode.dmSize = sizeof(devMode);
|
||||
|
||||
if(EnumDisplaySettingsA(dev->DeviceName, ENUM_CURRENT_SETTINGS, &devMode))
|
||||
{
|
||||
vmodeReturn->bpp = devMode.dmBitsPerPel;
|
||||
vmodeReturn->width = devMode.dmPelsWidth;
|
||||
vmodeReturn->height = devMode.dmPelsHeight;
|
||||
vmodeReturn->refreshRate = devMode.dmDisplayFrequency;
|
||||
|
||||
if(vmodeReturn->refreshRate == 1)
|
||||
vmodeReturn->refreshRate = SST_DEFAULT_REFRESHRATE;
|
||||
|
||||
ok = 1;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
const struct SST_WM_VideoModeFuncs Win32_VideoModeFuncs = {
|
||||
Win32_SetVideoModeOnScreen,
|
||||
Win32_GetVideoModeOnScreen
|
||||
};
|
||||
667
libsst-wm/Win32/SST_WMWindow_Win32.c
Normal file
667
libsst-wm/Win32/SST_WMWindow_Win32.c
Normal file
@@ -0,0 +1,667 @@
|
||||
/*
|
||||
SST_WMWindow_Win32.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 6/1/2012
|
||||
|
||||
Purpose:
|
||||
|
||||
Window creation (Win32)
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#include <SST/SST_WMWindow.h>
|
||||
#include "Win32Private.h"
|
||||
#include "../EventQueue.h"
|
||||
#include "../APIPrivate.h"
|
||||
|
||||
static LONG regRefCount = 0;
|
||||
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static SST_DisplayTarget Win32_CreateDisplayTarget(size_t adapterIndex, size_t screenIndexOrMultihead)
|
||||
{
|
||||
DISPLAY_DEVICEA* devs;
|
||||
size_t devCount;
|
||||
SST_DisplayTarget_Win32* displayTarget;
|
||||
|
||||
|
||||
/* Get Win32 devices */
|
||||
devs = get_win32devs(&devCount);
|
||||
if(devs == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Filter the list */
|
||||
devCount = filter_win32devs(devs, devCount, adapterIndex);
|
||||
if(devCount == 0)
|
||||
{
|
||||
HeapFree(GetProcessHeap(), 0, devs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Not doing multihead? */
|
||||
if(screenIndexOrMultihead != SST_MULTIHEAD)
|
||||
{
|
||||
/* Does the screen index exceed the number of attached screens? */
|
||||
if(screenIndexOrMultihead >= devCount)
|
||||
{
|
||||
/* Failure */
|
||||
HeapFree(GetProcessHeap(), 0, devs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Allocate a display target structure */
|
||||
displayTarget = (SST_DisplayTarget_Win32*)HeapAlloc(GetProcessHeap(), 0, sizeof(SST_DisplayTarget_Win32));
|
||||
if(displayTarget == NULL)
|
||||
{
|
||||
/* Failure */
|
||||
HeapFree(GetProcessHeap(), 0, devs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Initialize user event queue */
|
||||
if(!InitEQ(&displayTarget->userEventQueue))
|
||||
{
|
||||
/* Failure */
|
||||
HeapFree(GetProcessHeap(), 0, displayTarget);
|
||||
HeapFree(GetProcessHeap(), 0, devs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
InitializeCriticalSection(&displayTarget->userEventLock);
|
||||
displayTarget->devs = devs;
|
||||
displayTarget->screenCount = devCount;
|
||||
displayTarget->screenIndex = screenIndexOrMultihead;
|
||||
displayTarget->firstWindow = NULL;
|
||||
displayTarget->relativeMouse = FALSE;
|
||||
|
||||
/* Register class if the refcount == 1 */
|
||||
if(InterlockedIncrement(®RefCount) == 1)
|
||||
{
|
||||
WNDCLASSEXA wc;
|
||||
|
||||
memset(&wc, 0, sizeof(wc));
|
||||
wc.cbSize = sizeof(wc);
|
||||
wc.lpszClassName = SST_WINCLASS;
|
||||
wc.hInstance = GetModuleHandleA(NULL);
|
||||
wc.lpfnWndProc = libsstWndProc;
|
||||
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
|
||||
wc.style = CS_OWNDC;
|
||||
wc.hbrBackground = (HBRUSH)(uintptr_t)(COLOR_WINDOW+1);
|
||||
RegisterClassExA(&wc);
|
||||
}
|
||||
|
||||
return (SST_DisplayTarget)displayTarget;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static size_t Win32_GetDisplayTargetScreenCount(SST_DisplayTarget target)
|
||||
{
|
||||
SST_DisplayTarget_Win32* displayTarget = (SST_DisplayTarget_Win32*)target;
|
||||
|
||||
/*
|
||||
Multihead -> real screen count
|
||||
Otherwise -> 1
|
||||
*/
|
||||
if(displayTarget->screenIndex == SST_MULTIHEAD)
|
||||
return displayTarget->screenCount;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static SST_Window Win32_CreateWindowOnScreen(SST_DisplayTarget target, size_t screenIndex, uint32_t x, uint32_t y, uint32_t width, uint32_t height, const char* title)
|
||||
{
|
||||
RECT r;
|
||||
DWORD style, styleEx;
|
||||
HWND hWnd;
|
||||
SST_Window_Win32* win;
|
||||
SST_DisplayTarget_Win32* displayTarget = (SST_DisplayTarget_Win32*)target;
|
||||
FindMonitorInfo fmi;
|
||||
|
||||
/* Attempt to find the monitor associated with a display device */
|
||||
findMonitor(&displayTarget->devs[screenIndex], &fmi);
|
||||
|
||||
/* Didn't find it? */
|
||||
if(!fmi.foundIt)
|
||||
return NULL;
|
||||
|
||||
/* Allocate SST window structure */
|
||||
win = (SST_Window_Win32*)HeapAlloc(GetProcessHeap(), 0, sizeof(SST_Window_Win32));
|
||||
if(win == NULL)
|
||||
return NULL;
|
||||
|
||||
win->owner = displayTarget;
|
||||
win->next = displayTarget->firstWindow;
|
||||
win->owner = displayTarget;
|
||||
win->isFullscreen = FALSE;
|
||||
win->setPixelFormat = FALSE;
|
||||
win->softwareBackbuffer = NULL;
|
||||
win->softwareDC = NULL;
|
||||
win->softwareImage = NULL;
|
||||
win->softwarePitch = 0;
|
||||
|
||||
/* These styles may be useful later.
|
||||
DWORD style = (Fullscreen ? WS_POPUP : WS_CAPTION | WS_SYSMENU);
|
||||
DWORD styleEx = (Multihead2ndWindow? WS_EX_TOOLWINDOW : WS_EX_APPWINDOW);
|
||||
*/
|
||||
style = WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
|
||||
styleEx = WS_EX_APPWINDOW;
|
||||
|
||||
/* Start the window relative to those coordinates */
|
||||
r.top = 0;
|
||||
r.left = 0;
|
||||
r.bottom = (LONG)height;
|
||||
r.right = (LONG)width;
|
||||
AdjustWindowRectEx(&r, style, FALSE, styleEx);
|
||||
|
||||
if(r.top != 0)
|
||||
{
|
||||
LONG d = -r.top;
|
||||
|
||||
r.top = 0;
|
||||
r.bottom += d;
|
||||
}
|
||||
if(r.left != 0)
|
||||
{
|
||||
LONG d = -r.left;
|
||||
|
||||
r.left = 0;
|
||||
r.right += d;
|
||||
}
|
||||
|
||||
r.top += fmi.top + (LONG)y;
|
||||
r.left += fmi.left + (LONG)x;
|
||||
r.bottom += r.top;
|
||||
r.right += r.left;
|
||||
|
||||
|
||||
hWnd = CreateWindowExA(
|
||||
styleEx,
|
||||
SST_WINCLASS,
|
||||
title,
|
||||
style,
|
||||
r.left, r.top, /* XY position */
|
||||
r.right-r.left, r.bottom-r.top, /* Position */
|
||||
NULL, /* parent window */
|
||||
NULL, GetModuleHandleA(NULL), win);
|
||||
|
||||
/* Failed to create window */
|
||||
if(hWnd == NULL)
|
||||
{
|
||||
HeapFree(GetProcessHeap(), 0, win);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Save window info */
|
||||
win->hWnd = hWnd;
|
||||
|
||||
ShowWindow(hWnd, SW_SHOW);
|
||||
|
||||
/* Link window as new root */
|
||||
displayTarget->firstWindow = win;
|
||||
|
||||
return (SST_Window)win;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static SST_DisplayTarget Win32_GetWindowDisplayTarget(SST_Window window)
|
||||
{
|
||||
SST_Window_Win32* win = (SST_Window_Win32*)window;
|
||||
|
||||
return win->owner;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static void Win32_SetWindowText(SST_Window window, const char* titleBar)
|
||||
{
|
||||
SST_Window_Win32* win = (SST_Window_Win32*)window;
|
||||
|
||||
SetWindowTextA(win->hWnd, titleBar);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static void Win32_GetWindowRect(SST_Window window, SST_Rect* rectReturn)
|
||||
{
|
||||
SST_Window_Win32* win = (SST_Window_Win32*)window;
|
||||
MONITORINFO info;
|
||||
RECT rectClient;
|
||||
RECT rectWin;
|
||||
|
||||
/* Get info about the monitor the window is on */
|
||||
info.cbSize = sizeof(info);
|
||||
if(!GetMonitorInfoA(MonitorFromWindow(win->hWnd, MONITOR_DEFAULTTONEAREST), &info))
|
||||
return;
|
||||
|
||||
/* This returns (0,0) - (w,h). I don't know why they bother using a RECT instead
|
||||
of a POINT structure, since the top/left is always (0,0). */
|
||||
GetClientRect(win->hWnd, &rectClient);
|
||||
|
||||
GetWindowRect(win->hWnd, &rectWin);
|
||||
|
||||
rectReturn->x = (uint32_t)(rectWin.left - info.rcMonitor.left);
|
||||
rectReturn->y = (uint32_t)(rectWin.top - info.rcMonitor.top);
|
||||
rectReturn->width = (uint32_t)rectClient.right;
|
||||
rectReturn->height = (uint32_t)rectClient.bottom;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static void Win32_MoveWindowOnScreen(SST_Window window, size_t screenIndex, uint32_t x, uint32_t y)
|
||||
{
|
||||
FindMonitorInfo fmi;
|
||||
SST_Window_Win32* win = (SST_Window_Win32*)window;
|
||||
SST_DisplayTarget_Win32* displayTarget = win->owner;
|
||||
int px, py;
|
||||
|
||||
if(screenIndex != SST_SAME_SCREEN)
|
||||
{
|
||||
/* Atttempt to find the monitor associated with a display device */
|
||||
findMonitor(&displayTarget->devs[screenIndex], &fmi);
|
||||
|
||||
/* Didn't find it? (monitor unplugged?) */
|
||||
if(!fmi.foundIt)
|
||||
return;
|
||||
|
||||
/* New position = monitor base + offset */
|
||||
px = (int)x + (int)fmi.top;
|
||||
py = (int)y + (int)fmi.left;
|
||||
}
|
||||
else /* Move relative to the same screen */
|
||||
{
|
||||
MONITORINFO info;
|
||||
|
||||
/* Get info about the monitor the window is on */
|
||||
info.cbSize = sizeof(info);
|
||||
if(!GetMonitorInfoA(MonitorFromWindow(win->hWnd, MONITOR_DEFAULTTONEAREST), &info))
|
||||
return;
|
||||
|
||||
px = (int)x + (int)info.rcMonitor.left;
|
||||
py = (int)y + (int)info.rcMonitor.top;
|
||||
}
|
||||
|
||||
SetWindowPos(win->hWnd, NULL,
|
||||
px, py,
|
||||
0, 0,
|
||||
SWP_NOOWNERZORDER | SWP_NOSIZE);
|
||||
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static void Win32_ResizeWindow(SST_Window window, uint32_t width, uint32_t height)
|
||||
{
|
||||
SST_Window_Win32* win = (SST_Window_Win32*)window;
|
||||
RECT r;
|
||||
BOOL hasMenu;
|
||||
HWND hParent;
|
||||
|
||||
/* Get the client & window rect */
|
||||
GetClientRect(win->hWnd, &r);
|
||||
|
||||
r.right = r.left + (LONG)width;
|
||||
r.bottom = r.top + (LONG)height;
|
||||
|
||||
hParent = (HWND)GetWindowLongPtrA(win->hWnd, GWLP_HWNDPARENT);
|
||||
if(hParent == NULL)
|
||||
hasMenu = (GetMenu(win->hWnd) != NULL);
|
||||
else
|
||||
hasMenu = FALSE;
|
||||
|
||||
|
||||
AdjustWindowRectEx(&r, GetWindowLongA(win->hWnd, GWL_STYLE), hasMenu, GetWindowLongA(win->hWnd, GWL_EXSTYLE));
|
||||
|
||||
SetWindowPos(win->hWnd, NULL, 0, 0, r.right - r.left, r.bottom - r.top, SWP_NOOWNERZORDER | SWP_NOMOVE);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static void Win32_SetWindowState(SST_Window window, SST_WMWindowState state, uint32_t param)
|
||||
{
|
||||
SST_Window_Win32* win = (SST_Window_Win32*)window;
|
||||
|
||||
switch(state)
|
||||
{
|
||||
case SSTWS_SHOWN:
|
||||
{
|
||||
int cmd;
|
||||
if(param == 0)
|
||||
cmd = SW_HIDE;
|
||||
else
|
||||
cmd = SW_SHOW;
|
||||
|
||||
ShowWindow(win->hWnd, cmd);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Turn on/off resizeability */
|
||||
case SSTWS_RESIZEABLE:
|
||||
{
|
||||
DWORD style;
|
||||
RECT rect;
|
||||
POINT tl, br;
|
||||
|
||||
/* Get info about the window */
|
||||
style = GetWindowLongA(win->hWnd, GWL_STYLE);
|
||||
GetClientRect(win->hWnd, &rect);
|
||||
|
||||
tl.x = rect.left;
|
||||
tl.y = rect.top;
|
||||
|
||||
br.x = rect.right;
|
||||
br.y = rect.bottom;
|
||||
|
||||
ClientToScreen(win->hWnd, &tl);
|
||||
ClientToScreen(win->hWnd, &br);
|
||||
|
||||
rect.left = tl.x;
|
||||
rect.top = tl.y;
|
||||
rect.right = br.x;
|
||||
rect.bottom = br.y;
|
||||
|
||||
|
||||
if(param == 0)
|
||||
style &= ~(WS_THICKFRAME | WS_MAXIMIZEBOX);
|
||||
else
|
||||
style |= (WS_THICKFRAME | WS_MAXIMIZEBOX);
|
||||
|
||||
AdjustWindowRectEx(&rect, style, (GetMenu(win->hWnd) ? TRUE : FALSE), GetWindowLongA(win->hWnd, GWL_EXSTYLE));
|
||||
SetWindowLongA(win->hWnd, GWL_STYLE, (LONG)style);
|
||||
|
||||
/* MSDN: "Certain window data is cached, so changes you make using SetWindowLong() will not take effect until you
|
||||
call the SetWindowPos() function." So, let's update it... */
|
||||
SetWindowPos(win->hWnd, NULL,
|
||||
rect.left, rect.top,
|
||||
rect.right - rect.left,
|
||||
rect.bottom - rect.top,
|
||||
SWP_NOZORDER | SWP_FRAMECHANGED);
|
||||
break;
|
||||
}
|
||||
|
||||
case SSTWS_FULLSCREEN:
|
||||
{
|
||||
DWORD style;
|
||||
|
||||
/* Enabling fullscreen? */
|
||||
if(param && !win->isFullscreen)
|
||||
{
|
||||
MONITORINFO info;
|
||||
RECT r;
|
||||
POINT pt;
|
||||
|
||||
/* Get current window style */
|
||||
style = GetWindowLongA(win->hWnd, GWL_STYLE);
|
||||
|
||||
/* Save info about the window so when we exit fullscreen, we're good */
|
||||
win->wp.length = sizeof(win->wp);
|
||||
GetWindowPlacement(win->hWnd, &win->wp);
|
||||
GetWindowRect(win->hWnd, &r);
|
||||
pt.x = r.top;
|
||||
pt.y = r.left;
|
||||
|
||||
|
||||
|
||||
/* Get info about the monitor the window is on */
|
||||
info.cbSize = sizeof(MONITORINFO);
|
||||
GetMonitorInfo(MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST), &info);
|
||||
|
||||
/* Remove title bar, caption, etc. */
|
||||
SetWindowLong(win->hWnd, GWL_STYLE, style & (~WS_OVERLAPPEDWINDOW));
|
||||
|
||||
/* Move & resize to cover entire screen */
|
||||
SetWindowPos(win->hWnd, HWND_TOP,
|
||||
(int)info.rcMonitor.left, (int)info.rcMonitor.top, /* Position window in the top-left corner */
|
||||
(int)(info.rcMonitor.right - info.rcMonitor.left), /* Width = width of monitor */
|
||||
(int)(info.rcMonitor.bottom - info.rcMonitor.top), /* Height = height of monitor */
|
||||
SWP_NOOWNERZORDER | SWP_FRAMECHANGED); /* Don't change*/
|
||||
|
||||
|
||||
win->isFullscreen = TRUE;
|
||||
}
|
||||
else if(win->isFullscreen) /* Disabling fullscreen */
|
||||
{
|
||||
style = GetWindowLongA(win->hWnd, GWL_STYLE);
|
||||
SetWindowLong(win->hWnd, GWL_STYLE, style | WS_OVERLAPPEDWINDOW);
|
||||
|
||||
/* Restore old window placement */
|
||||
SetWindowPlacement(win->hWnd, &win->wp);
|
||||
SetWindowPos(win->hWnd, NULL, 0, 0, 0, 0,
|
||||
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
|
||||
|
||||
win->isFullscreen = FALSE;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case SSTWS_MINIMIZED:
|
||||
{
|
||||
int cmd;
|
||||
if(param == 0)
|
||||
{
|
||||
SST_WMEvent* event;
|
||||
cmd = SW_RESTORE;
|
||||
|
||||
/* Win32 doesn't send a restore message if pragmatically restored, so do it ourselves */
|
||||
event = AllocSlotInEQ(&win->eventQueue);
|
||||
if(event)
|
||||
{
|
||||
event->window = win;
|
||||
event->type = SSTWMEVENT_RESTORED;
|
||||
memset(&event->details, 0, sizeof(event->details));
|
||||
}
|
||||
}
|
||||
else
|
||||
cmd = SW_MINIMIZE;
|
||||
|
||||
ShowWindow(win->hWnd, cmd);
|
||||
break;
|
||||
}
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static void Win32_SetDisplayTargetState(SST_DisplayTarget target, SST_WMDisplayTargetState state, uint32_t param)
|
||||
{
|
||||
SST_DisplayTarget_Win32* displayTarget = (SST_DisplayTarget_Win32*)target;
|
||||
|
||||
switch(state)
|
||||
{
|
||||
case SSTDTS_RELMOUSE:
|
||||
{
|
||||
RAWINPUTDEVICE rawMouse = { 0x01, 0x02, 0, NULL }; /* Mouse: UsagePage = 1, Usage = 2 */
|
||||
|
||||
/* Disabling? */
|
||||
if(displayTarget->relativeMouse && param == 0)
|
||||
{
|
||||
rawMouse.dwFlags |= RIDEV_REMOVE;
|
||||
|
||||
/* Attempt to unregister raw mouse. If successful, set 'relativeMouse' to FALSE */
|
||||
if(RegisterRawInputDevices(&rawMouse, 1, sizeof(RAWINPUTDEVICE)))
|
||||
{
|
||||
displayTarget->relativeMouse = FALSE;
|
||||
ClipCursor(NULL);
|
||||
ShowCursor(TRUE);
|
||||
}
|
||||
}
|
||||
else if(!displayTarget->relativeMouse && param != 0) /* Enabling? */
|
||||
{
|
||||
if(RegisterRawInputDevices(&rawMouse, 1, sizeof(RAWINPUTDEVICE)))
|
||||
{
|
||||
HWND active;
|
||||
SST_Window_Win32* win;
|
||||
|
||||
displayTarget->relativeMouse = TRUE;
|
||||
ShowCursor(FALSE);
|
||||
|
||||
/* Decide if this window belows to any in this display target, if so, lock cursor into it */
|
||||
active = GetActiveWindow();
|
||||
win = displayTarget->firstWindow;
|
||||
|
||||
while(win)
|
||||
{
|
||||
/* It does belong to this display target, so lock it into place */
|
||||
if(win->hWnd == active)
|
||||
{
|
||||
LONG cx, cy;
|
||||
RECT rect;
|
||||
|
||||
GetWindowRect(win->hWnd, &rect);
|
||||
cx = (rect.left + rect.right) / 2;
|
||||
cy = (rect.top + rect.bottom) / 2;
|
||||
|
||||
/* Ensure cursor cannot leave the center of the window */
|
||||
rect.left = cx-1;
|
||||
rect.right = cx+1;
|
||||
rect.top = cy-1;
|
||||
rect.bottom = cy+1;
|
||||
ClipCursor(&rect);
|
||||
break;
|
||||
}
|
||||
else
|
||||
win = win->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static void Win32_DestroyWindow(SST_Window window)
|
||||
{
|
||||
SST_DisplayTarget_Win32* displayTarget;
|
||||
SST_Window_Win32* win = (SST_Window_Win32*)window;
|
||||
SST_Window_Win32* nextWin;
|
||||
|
||||
displayTarget = win->owner;
|
||||
nextWin = displayTarget->firstWindow;
|
||||
|
||||
/* Special case: root window */
|
||||
if(nextWin == win)
|
||||
{
|
||||
/* Set new root to be this->next */
|
||||
displayTarget->firstWindow = win->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
int found = 0;
|
||||
|
||||
/* Check list */
|
||||
while(nextWin)
|
||||
{
|
||||
/* Did we find the window? */
|
||||
if(nextWin->next == win)
|
||||
{
|
||||
/* Remove this window from the linked list */
|
||||
nextWin->next = win->next;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
else
|
||||
nextWin = nextWin->next;
|
||||
}
|
||||
|
||||
/* Don't destroy another display target's window */
|
||||
if(!found)
|
||||
return;
|
||||
|
||||
}
|
||||
/* Actually destroy the Win32 window */
|
||||
DestroyWindow(win->hWnd);
|
||||
|
||||
if(win->softwareBackbuffer)
|
||||
HeapFree(GetProcessHeap(), 0, win->softwareBackbuffer);
|
||||
if(win->softwareDC)
|
||||
DeleteDC(win->softwareDC);
|
||||
if(win->softwareImage)
|
||||
DeleteObject(win->softwareImage);
|
||||
|
||||
|
||||
/* TODO empty message queue? */
|
||||
|
||||
/* Free the window */
|
||||
HeapFree(GetProcessHeap(), 0, win);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static void Win32_DestroyDisplayTarget(SST_DisplayTarget target)
|
||||
{
|
||||
SST_DisplayTarget_Win32* displayTarget = (SST_DisplayTarget_Win32*)target;
|
||||
SST_Window_Win32* window = displayTarget->firstWindow;
|
||||
|
||||
/* Destroy all windows */
|
||||
while(window)
|
||||
{
|
||||
/* Save the next window */
|
||||
SST_Window_Win32* next = window->next;
|
||||
|
||||
/* Actually destroy the Win32 window handle */
|
||||
DestroyWindow(window->hWnd);
|
||||
HeapFree(GetProcessHeap(), 0, window);
|
||||
|
||||
/*
|
||||
TODO: should we empty the message queue of all messages owned by this window? Do
|
||||
they automatically get removed? Aiiyeeee!
|
||||
*/
|
||||
|
||||
/* Move to next window */
|
||||
window = next;
|
||||
}
|
||||
|
||||
/* Delete user event queue lock */
|
||||
DeleteCriticalSection(&displayTarget->userEventLock);
|
||||
|
||||
|
||||
/* Free structures */
|
||||
DestroyEQ(&displayTarget->userEventQueue);
|
||||
HeapFree(GetProcessHeap(), 0, displayTarget->devs);
|
||||
HeapFree(GetProcessHeap(), 0, displayTarget);
|
||||
|
||||
/* Unregister */
|
||||
if(InterlockedDecrement(®RefCount) == 0)
|
||||
UnregisterClassA(SST_WINCLASS, GetModuleHandleA(NULL));
|
||||
}
|
||||
|
||||
extern int Win32_ShowDialogBox(SST_DisplayTarget target, SST_Window parent, const char* caption, const char* message, const char** buttons, int nrButtons);
|
||||
|
||||
const struct SST_WM_WindowFuncs Win32_WindowFuncs = {
|
||||
Win32_CreateDisplayTarget,
|
||||
Win32_GetDisplayTargetScreenCount,
|
||||
Win32_CreateWindowOnScreen,
|
||||
Win32_GetWindowDisplayTarget,
|
||||
Win32_SetWindowText,
|
||||
Win32_GetWindowRect,
|
||||
Win32_MoveWindowOnScreen,
|
||||
Win32_ResizeWindow,
|
||||
Win32_ShowDialogBox,
|
||||
Win32_SetWindowState,
|
||||
Win32_SetDisplayTargetState,
|
||||
Win32_DestroyWindow,
|
||||
Win32_DestroyDisplayTarget
|
||||
};
|
||||
62
libsst-wm/Win32/Win32Driver.c
Normal file
62
libsst-wm/Win32/Win32Driver.c
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
Win32Driver.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 12/18/2014
|
||||
|
||||
Purpose:
|
||||
|
||||
Windows (Win32 API) driver for libsst-wm
|
||||
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
#include "../APIPrivate.h"
|
||||
#include "Win32Private.h"
|
||||
|
||||
extern const struct SST_WM_WindowFuncs Win32_WindowFuncs;
|
||||
extern const struct SST_WM_EnumFuncs Win32_EnumFuncs;
|
||||
extern const struct SST_WM_EventFuncs Win32_EventFuncs;
|
||||
extern const struct SST_WM_OpenGLFuncs Win32_OpenGLFuncs;
|
||||
extern const struct SST_WM_RenderFuncs Win32_RenderFuncs;
|
||||
extern const struct SST_WM_VideoModeFuncs Win32_VideoModeFuncs;
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
int Win32_init()
|
||||
{
|
||||
if(getenv("LIBSST_NO_WIN32"))
|
||||
return 0;
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void Win32_shutdown()
|
||||
{
|
||||
/* Nothing to do (now) */
|
||||
return;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const struct SST_WM_Driver Win32Driver = {
|
||||
"Win32 Driver",
|
||||
Win32_init,
|
||||
Win32_shutdown,
|
||||
&Win32_WindowFuncs,
|
||||
&Win32_EnumFuncs,
|
||||
&Win32_EventFuncs,
|
||||
&Win32_OpenGLFuncs,
|
||||
&Win32_RenderFuncs,
|
||||
&Win32_VideoModeFuncs
|
||||
};
|
||||
1351
libsst-wm/Win32/Win32Private.c
Normal file
1351
libsst-wm/Win32/Win32Private.c
Normal file
File diff suppressed because it is too large
Load Diff
267
libsst-wm/Win32/Win32Private.h
Normal file
267
libsst-wm/Win32/Win32Private.h
Normal file
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
Win32Private.h
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 1/7/2012
|
||||
|
||||
Purpose:
|
||||
|
||||
Private defintions and functions for Win32 implementation of libsst-wm
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef _WIN32PRIVATE_H
|
||||
#define _WIN32PRIVATE_H
|
||||
|
||||
#include <windows.h>
|
||||
#include <windowsx.h> /* More Win32 macros */
|
||||
#include <GL/gl.h>
|
||||
#include <SST/SST_WMTypes.h>
|
||||
#include "../EventQueue.h"
|
||||
|
||||
#define ADAPTER_NAME_STRLEN 128
|
||||
#define STRLEN_GUID ((size_t)64) /* Storage enough to hold a Win32 GUID if it was written as a string of hex characters with dashes (need only like 36-38) */
|
||||
#define MIN_BPP 24 /* Minimum BPP for a mode to be considered */
|
||||
#define SST_WINCLASS "libsstwm"
|
||||
#define SST_DLGCLASS "libsstwmdlg"
|
||||
#define MAX_GL_ATTRS 32
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
typedef HGLRC (WINAPI * pf_wglCreateContext)(HDC hdc);
|
||||
typedef BOOL (WINAPI * pf_wglMakeCurrent)(HDC hdc, HGLRC hglrc);
|
||||
typedef PROC (WINAPI * pf_wglGetProcAddress)(LPCSTR lpszProc);
|
||||
typedef BOOL (WINAPI * pf_wglDeleteContext)(HGLRC hglrc);
|
||||
typedef BOOL (WINAPI * pf_wglShareLists)(HGLRC hglrc1, HGLRC hglrc2);
|
||||
typedef HGLRC (WINAPI * pf_wglGetCurrentContext)(void);
|
||||
typedef HDC (WINAPI * pf_wglGetCurrentDC)(void);
|
||||
typedef const char* (WINAPI * pf_wglGetExtensionsStringARB)(HDC hdc);
|
||||
typedef BOOL (WINAPI * pf_wglChoosePixelFormatARB)(HDC hdc, const int* piAttribIList, const FLOAT* pfAttribFList, UINT nMaxFormats, int* piFormats, UINT* nNumFormats);
|
||||
typedef HGLRC (WINAPI * pf_wglCreateContextAttribsARB)(HDC hDC, HGLRC hshareContext, const int *attribList);
|
||||
typedef BOOL (WINAPI * pf_wglGetPixelFormatAttribivARB)(HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues);
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
/*
|
||||
Note about memory management -- these functions all use the Win32 API (HeapAlloc()/HeapFree()) instead of the CRT functions (malloc()/free()).
|
||||
This is so that it has less of dependency on the CRT.
|
||||
*/
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
/* Structure to maps an adapter-display pair to a DISPLAY_DEVICE */
|
||||
typedef struct ASMapEntry
|
||||
{
|
||||
SST_VideoMode defaultVmode;
|
||||
const DISPLAY_DEVICEA* dev;
|
||||
SST_VideoMode* vmodes;
|
||||
size_t adapter;
|
||||
size_t screen;
|
||||
size_t vmodeCount;
|
||||
} ASMapEntry;
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
typedef struct FindMonitorInfo
|
||||
{
|
||||
const DISPLAY_DEVICEA* dev; /* Name of the device we are trying to find a matching HMONITOR for */
|
||||
BOOL foundIt; /* Did we find it? */
|
||||
LONG top, left; /* Monitor corner (top,left) */
|
||||
LONG bottom, right;
|
||||
} FindMonitorInfo;
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
typedef struct SST_GraphicsEnumerator_Win32
|
||||
{
|
||||
char* adapterNames;
|
||||
DISPLAY_DEVICEA* devsFound;
|
||||
size_t* screenCount;
|
||||
ASMapEntry* ASMap;
|
||||
|
||||
|
||||
size_t adapterCount;
|
||||
size_t devCount;
|
||||
size_t ASPairCount;
|
||||
} SST_GraphicsEnumerator_Win32;
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
typedef struct SST_DisplayTarget_Win32
|
||||
{
|
||||
CRITICAL_SECTION userEventLock; /* Lock protection user events */
|
||||
EventQueue userEventQueue;
|
||||
DISPLAY_DEVICEA* devs; /* Array of devices representing this display target */
|
||||
struct SST_Window_Win32* firstWindow; /* First window in a list of windows */
|
||||
size_t screenCount;
|
||||
size_t screenIndex;
|
||||
BOOL relativeMouse;
|
||||
} SST_DisplayTarget_Win32;
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
typedef struct SST_Window_Win32
|
||||
{
|
||||
WINDOWPLACEMENT wp;
|
||||
EventQueue eventQueue;
|
||||
struct SST_Window_Win32* next;
|
||||
SST_DisplayTarget_Win32* owner;
|
||||
HWND hWnd;
|
||||
BOOL isFullscreen;
|
||||
BOOL setPixelFormat; /* If TRUE, then SetPixelFormat() was called on this window */
|
||||
|
||||
|
||||
/* Software rendering support */
|
||||
HBITMAP softwareImage;
|
||||
HDC softwareDC;
|
||||
void* softwareBackbuffer;
|
||||
size_t softwarePitch;
|
||||
|
||||
} SST_Window_Win32;
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
typedef struct WGLFunctions
|
||||
{
|
||||
pf_wglCreateContext CreateContext;
|
||||
pf_wglMakeCurrent MakeCurrent;
|
||||
pf_wglGetProcAddress GetProcAddress;
|
||||
pf_wglDeleteContext DeleteContext;
|
||||
pf_wglShareLists ShareLists;
|
||||
pf_wglGetCurrentContext GetCurrentContext;
|
||||
pf_wglGetCurrentDC GetCurrentDC;
|
||||
|
||||
/* WGL Extensions */
|
||||
pf_wglGetExtensionsStringARB GetExtensionsStringARB;
|
||||
pf_wglChoosePixelFormatARB ChoosePixelFormatARB;
|
||||
pf_wglCreateContextAttribsARB CreateContextAttribsARB;
|
||||
pf_wglGetPixelFormatAttribivARB GetPixelFormatAttribivARB;
|
||||
|
||||
BOOL supportsProfiles;
|
||||
BOOL supportsMultisample;
|
||||
} WGLFunctions;
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
typedef struct SST_OpenGLContext_Win32
|
||||
{
|
||||
WGLFunctions wgl;
|
||||
SST_DisplayTarget_Win32* displayTarget;
|
||||
HMODULE opengl32;
|
||||
HGLRC context;
|
||||
HDC hDCActive;
|
||||
HWND hSlaveWnd; /* Slave contexts use a dummy window. Regular (master) GL contexts have this as NULL */
|
||||
int pixelFormat;
|
||||
short ctxVersion[2]; /* context version major/minor */
|
||||
BOOL isLegacy; /* Did we use legacy context creation functions? */
|
||||
BOOL legacyEnabled; /* Did we use legacy OpenGL (< 3.0) context support? */
|
||||
BOOL debugEnabled; /* Did we use debug OpenGL context support? */
|
||||
} SST_OpenGLContext_Win32;
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
DISPLAY_DEVICEA* get_win32devs(size_t* devCountReturn);
|
||||
|
||||
char* get_adapters(const DISPLAY_DEVICEA* devsFound, size_t devCount, size_t* adapterCountReturn, char** adapterGUIDReturn);
|
||||
|
||||
/*
|
||||
Filter a list of Win32 devices in-place; modify list so that only relevant Win32 devices are returned.
|
||||
For example, if there are 3 devices: { Gpu0Screen0, Gpu1Screen0, Gpu1Screen1}, and adapterIndex == 1,
|
||||
then this returns { Gpu1Screen0, Gpu1Screen1 } in place. The number of devices in the filtered list are
|
||||
returned (in the example, 2).
|
||||
*/
|
||||
size_t filter_win32devs(DISPLAY_DEVICEA* devsFound, size_t devCount, size_t adapterIndex);
|
||||
|
||||
ASMapEntry* build_asmap(const DISPLAY_DEVICEA* devsFound, const char* adapterGUIDs, size_t devCount, size_t adapterCount, size_t* screenCount, size_t* mapSizeReturn);
|
||||
|
||||
SST_VideoMode* get_vmodes(const DISPLAY_DEVICEA* dev, size_t* modeCountReturn, SST_VideoMode* defaultMode);
|
||||
|
||||
LRESULT WINAPI libsstWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
void resolveWGLSymbols(HMODULE opengl32, WGLFunctions* wgl);
|
||||
void resolveWGLExtSymbols(HDC hDC, WGLFunctions* wgl);
|
||||
|
||||
void findMonitor(const DISPLAY_DEVICEA* dev, FindMonitorInfo* fmi);
|
||||
|
||||
/* WGL_ARB_multisample */
|
||||
#define WGL_SAMPLE_BUFFERS_ARB 0x2041
|
||||
#define WGL_SAMPLES_ARB 0x2042
|
||||
|
||||
/* WGL_ARB_pixel_format */
|
||||
#define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000
|
||||
#define WGL_DRAW_TO_WINDOW_ARB 0x2001
|
||||
#define WGL_DRAW_TO_BITMAP_ARB 0x2002
|
||||
#define WGL_ACCELERATION_ARB 0x2003
|
||||
#define WGL_NEED_PALETTE_ARB 0x2004
|
||||
#define WGL_NEED_SYSTEM_PALETTE_ARB 0x2005
|
||||
#define WGL_SWAP_LAYER_BUFFERS_ARB 0x2006
|
||||
#define WGL_SWAP_METHOD_ARB 0x2007
|
||||
#define WGL_NUMBER_OVERLAYS_ARB 0x2008
|
||||
#define WGL_NUMBER_UNDERLAYS_ARB 0x2009
|
||||
#define WGL_TRANSPARENT_ARB 0x200A
|
||||
#define WGL_TRANSPARENT_RED_VALUE_ARB 0x2037
|
||||
#define WGL_TRANSPARENT_GREEN_VALUE_ARB 0x2038
|
||||
#define WGL_TRANSPARENT_BLUE_VALUE_ARB 0x2039
|
||||
#define WGL_TRANSPARENT_ALPHA_VALUE_ARB 0x203A
|
||||
#define WGL_TRANSPARENT_INDEX_VALUE_ARB 0x203B
|
||||
#define WGL_SHARE_DEPTH_ARB 0x200C
|
||||
#define WGL_SHARE_STENCIL_ARB 0x200D
|
||||
#define WGL_SHARE_ACCUM_ARB 0x200E
|
||||
#define WGL_SUPPORT_GDI_ARB 0x200F
|
||||
#define WGL_SUPPORT_OPENGL_ARB 0x2010
|
||||
#define WGL_DOUBLE_BUFFER_ARB 0x2011
|
||||
#define WGL_STEREO_ARB 0x2012
|
||||
#define WGL_PIXEL_TYPE_ARB 0x2013
|
||||
#define WGL_COLOR_BITS_ARB 0x2014
|
||||
#define WGL_RED_BITS_ARB 0x2015
|
||||
#define WGL_RED_SHIFT_ARB 0x2016
|
||||
#define WGL_GREEN_BITS_ARB 0x2017
|
||||
#define WGL_GREEN_SHIFT_ARB 0x2018
|
||||
#define WGL_BLUE_BITS_ARB 0x2019
|
||||
#define WGL_BLUE_SHIFT_ARB 0x201A
|
||||
#define WGL_ALPHA_BITS_ARB 0x201B
|
||||
#define WGL_ALPHA_SHIFT_ARB 0x201C
|
||||
#define WGL_ACCUM_BITS_ARB 0x201D
|
||||
#define WGL_ACCUM_RED_BITS_ARB 0x201E
|
||||
#define WGL_ACCUM_GREEN_BITS_ARB 0x201F
|
||||
#define WGL_ACCUM_BLUE_BITS_ARB 0x2020
|
||||
#define WGL_ACCUM_ALPHA_BITS_ARB 0x2021
|
||||
#define WGL_DEPTH_BITS_ARB 0x2022
|
||||
#define WGL_STENCIL_BITS_ARB 0x2023
|
||||
#define WGL_AUX_BUFFERS_ARB 0x2024
|
||||
|
||||
#define WGL_NO_ACCELERATION_ARB 0x2025
|
||||
#define WGL_GENERIC_ACCELERATION_ARB 0x2026
|
||||
#define WGL_FULL_ACCELERATION_ARB 0x2027
|
||||
|
||||
#define WGL_SWAP_EXCHANGE_ARB 0x2028
|
||||
#define WGL_SWAP_COPY_ARB 0x2029
|
||||
#define WGL_SWAP_UNDEFINED_ARB 0x202A
|
||||
|
||||
#define WGL_TYPE_RGBA_ARB 0x202B
|
||||
#define WGL_TYPE_COLORINDEX_ARB 0x202C
|
||||
|
||||
/* WGL_ARB_create_context */
|
||||
#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
|
||||
#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
|
||||
#define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093
|
||||
#define WGL_CONTEXT_FLAGS_ARB 0x2094
|
||||
#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
|
||||
#define WGL_CONTEXT_DEBUG_BIT_ARB 0x0001
|
||||
#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002
|
||||
#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
|
||||
#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
|
||||
#define ERROR_INVALID_VERSION_ARB 0x2095
|
||||
#define ERROR_INVALID_PROFILE_ARB 0x2096
|
||||
|
||||
#endif
|
||||
374
libsst-wm/Xlib/GLXPrivate.c
Normal file
374
libsst-wm/Xlib/GLXPrivate.c
Normal file
@@ -0,0 +1,374 @@
|
||||
/*
|
||||
GLXPrivate.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 1/11/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
OpenGL on X Windows (GLX) utility code
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#include <SST/SST_WMOpenGL.h>
|
||||
#include "XlibPrivate.h"
|
||||
#include <dlfcn.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* GL constants */
|
||||
#define GL_VERSION 0x1F02
|
||||
|
||||
/* GLX constants */
|
||||
#define GLX_DOUBLEBUFFER 5
|
||||
#define GLX_STEREO 6
|
||||
#define GLX_AUX_BUFFERS 7
|
||||
#define GLX_RED_SIZE 8
|
||||
#define GLX_GREEN_SIZE 9
|
||||
#define GLX_BLUE_SIZE 10
|
||||
#define GLX_ALPHA_SIZE 11
|
||||
#define GLX_DEPTH_SIZE 12
|
||||
#define GLX_STENCIL_SIZE 13
|
||||
#define GLX_DRAWABLE_TYPE 0x8010
|
||||
#define GLX_RGBA_TYPE 0x8014
|
||||
#define GLX_WINDOW_BIT 0x00000001
|
||||
#define GLX_PIXMAP_BIT 0x00000002
|
||||
#define GLX_PBUFFER_BIT 0x00000004
|
||||
|
||||
/* GLX_ARB_multisample */
|
||||
#define GLX_SAMPLE_BUFFERS_ARB 100000
|
||||
#define GLX_SAMPLES_ARB 100001
|
||||
|
||||
#define GLX_PBUFFER_HEIGHT 0x8040
|
||||
#define GLX_PBUFFER_WIDTH 0x8041
|
||||
|
||||
/* GLX_ARB_create_context[_profile] */
|
||||
#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
|
||||
#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
|
||||
#define GLX_CONTEXT_FLAGS_ARB 0x2094
|
||||
#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126
|
||||
#define GLX_CONTEXT_DEBUG_BIT_ARB 0x0001
|
||||
#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002
|
||||
#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
|
||||
#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
|
||||
|
||||
GLXFunctions glX = { 0 };
|
||||
|
||||
static void setupAttribs(int* glxAttr, const SST_OpenGLContextAttributes* attribs, Bool supportsMultisample);
|
||||
static int* addAttr(int* ptr, int attr, int value)
|
||||
{
|
||||
ptr[0] = attr;
|
||||
ptr[1] = value;
|
||||
return ptr + 2;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
int loadGLX()
|
||||
{
|
||||
const int flags = RTLD_LAZY | RTLD_GLOBAL;
|
||||
void* libGL;
|
||||
|
||||
/* Set all values to null/0/false */
|
||||
memset(&glX, 0, sizeof(GLXFunctions));
|
||||
|
||||
/* Load OpenGL library with proper DT_SONAME */
|
||||
libGL = dlopen("libGL.so.1", flags);
|
||||
if(libGL == NULL)
|
||||
{
|
||||
/* Failed...try generic name for it */
|
||||
libGL = dlopen("libGL.so", flags);
|
||||
if(libGL == NULL)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Resolve symbols */
|
||||
glX.QueryExtension = dlsym(libGL, "glXQueryExtension");
|
||||
glX.QueryVersion = dlsym(libGL, "glXQueryVersion");
|
||||
glX.QueryExtensionsString = dlsym(libGL, "glXQueryExtensionsString");
|
||||
glX.ChooseFBConfig = dlsym(libGL, "glXChooseFBConfig");
|
||||
glX.CreateNewContext = dlsym(libGL, "glXCreateNewContext");
|
||||
glX.DestroyContext = dlsym(libGL, "glXDestroyContext");
|
||||
glX.MakeContextCurrent = dlsym(libGL, "glXMakeContextCurrent");
|
||||
glX.GetCurrentContext = dlsym(libGL, "glXGetCurrentContext");
|
||||
glX.SwapBuffers = dlsym(libGL, "glXSwapBuffers");
|
||||
glX.CreatePbuffer = dlsym(libGL, "glXCreatePbuffer");
|
||||
glX.DestroyPbuffer = dlsym(libGL, "glXDestroyPbuffer");
|
||||
|
||||
/* On Linux, glXGetProcAddressARB() is statically exported from libGL.so as part of LSB. However,
|
||||
on non-LSB compliant or other UNIX systems, the -ARB version may not exist. Try the unsuffixed
|
||||
form if the -ARB variant does not exist. */
|
||||
glX.GetProcAddressARB = dlsym(libGL, "glXGetProcAddressARB");
|
||||
if(glX.GetProcAddressARB == NULL)
|
||||
glX.GetProcAddressARB = dlsym(libGL, "glXGetProcAddress");
|
||||
|
||||
/* We dont resolve glXCreateContextAttribsARB yet; first check GLX extension strings. */
|
||||
glX.CreateContextAttribsARB = NULL;
|
||||
|
||||
/* Save library handle */
|
||||
glX.libGL = libGL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void unloadGLX()
|
||||
{
|
||||
dlclose(glX.libGL);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
int isGLXLoaded()
|
||||
{
|
||||
return (glX.libGL != NULL);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
int isGLXSupported(Display* display)
|
||||
{
|
||||
int major = 0, minor = 0;
|
||||
int combined;
|
||||
const char* ext;
|
||||
|
||||
/* Query if the X server supports GLX. If it doesn't, then nothing to do */
|
||||
if(glX.QueryExtension(display, NULL, NULL) == False)
|
||||
{
|
||||
fprintf(stderr, "%s:GLX extension not supported on this connection.\n", "libsst-wm");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Query the version; we need 1.3 or later */
|
||||
if(glX.QueryVersion(display, &major, &minor) == False)
|
||||
{
|
||||
fprintf(stderr, "%s:Unable to query GLX version.\n", "libsst-wm");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Fail on less than 1.3 */
|
||||
combined = (major << 8) | minor;
|
||||
if(combined < 0x13)
|
||||
{
|
||||
fprintf(stderr, "%s:GLX version 1.3 required, found %d.%d\n", "libsst-wm", major, minor);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ext = glX.QueryExtensionsString(display, DefaultScreen(display));
|
||||
|
||||
/* "GLX_ARB_create_context" and "GLX_ARB_create_context_profile" might both match the first strstr(),
|
||||
but "GLX_ARB_create_context_profile" requires the former, so it's all good.
|
||||
TODO: write less stupid extension checker - one day may not be true */
|
||||
if(combined >= 0x14) /* GLX 1.4 required for GLX_ARB_create_context */
|
||||
{
|
||||
glX.supportsCreateContextARB = (Bool)(strstr(ext, "GLX_ARB_create_context") != NULL);
|
||||
glX.supportsProfiles = (Bool)(strstr(ext, "GLX_ARB_create_context_profile") != NULL);
|
||||
|
||||
/* Supposedly GLX_ARB_create_context is supported. Try to resolve the symbol. If we can't,
|
||||
then backout. */
|
||||
if(glX.supportsCreateContextARB) {
|
||||
glX.CreateContextAttribsARB = glX.GetProcAddressARB("glXCreateContextAttribsARB");
|
||||
if(glX.CreateContextAttribsARB == NULL) {
|
||||
glX.supportsCreateContextARB = False;
|
||||
}
|
||||
}
|
||||
}
|
||||
else /* Don't have GLX 1.4, so can't possibly have these */
|
||||
{
|
||||
glX.supportsCreateContextARB = False;
|
||||
glX.supportsProfiles = False;
|
||||
}
|
||||
|
||||
glX.supportsMultisample = (Bool)(strstr(ext, "GLX_ARB_multisample") != NULL);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
SST_OpenGLContext GLXCreateOpenGLContext(SST_DisplayTarget_Xlib* displayTarget, SST_WMOpenGLType apiType, const SST_OpenGLContextAttributes* attribs, SST_OpenGLContextAttributes* selectedAttribsReturn)
|
||||
{
|
||||
int attr[MAX_GL_ATTRS];
|
||||
Display* display = displayTarget->display;
|
||||
GLXFBConfig* configs;
|
||||
GLXFBConfig fbconfig;
|
||||
GLXContext ctx;
|
||||
int nrConfigs = 0;
|
||||
SST_OpenGLContext_Xlib* GLctx;
|
||||
uint8_t major, minor;
|
||||
GLXPbuffer pb;
|
||||
const int pbattr[5] = { GLX_PBUFFER_WIDTH, 1, GLX_PBUFFER_HEIGHT, 1, None };
|
||||
|
||||
/* GLX cannot be used to do anything other than standard OpenGL */
|
||||
if(apiType != SSTGL_OPENGL)
|
||||
return NULL;
|
||||
|
||||
/* GLX doesn't support multisampling, but it was explicitly requested */
|
||||
if(!glX.supportsMultisample && attribs->multisampleFactor > 1)
|
||||
return NULL;
|
||||
|
||||
/* Copy SST attributes to GLX attributes */
|
||||
setupAttribs(attr, attribs, glX.supportsMultisample);
|
||||
|
||||
/* Get a list of configs -- we're going to only use the first one though */
|
||||
configs = glX.ChooseFBConfig(display, DefaultScreen(display), attr, &nrConfigs);
|
||||
if(configs == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Copy first FBConfig entry, free array */
|
||||
fbconfig = *configs;
|
||||
X.Free(configs);
|
||||
|
||||
/* Use the new create context functions? */
|
||||
if(glX.supportsCreateContextARB)
|
||||
{
|
||||
int attr[32];
|
||||
int* ptr = &attr[0];
|
||||
int ctxFlags = 0;
|
||||
|
||||
/* Set the major/minor version */
|
||||
ptr = addAttr(ptr, GLX_CONTEXT_MAJOR_VERSION_ARB, attribs->contextVersionMajor);
|
||||
ptr = addAttr(ptr, GLX_CONTEXT_MINOR_VERSION_ARB, attribs->contextVersionMinor);
|
||||
|
||||
/* If GLX_ARB_create_context_profile is supported, add a profile mask */
|
||||
if(glX.supportsProfiles)
|
||||
ptr = addAttr(ptr, GLX_CONTEXT_PROFILE_MASK_ARB, (attribs->legacyEnabled ? GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB : GLX_CONTEXT_CORE_PROFILE_BIT_ARB));
|
||||
|
||||
/* Enable/disable forward compatibility */
|
||||
if(!attribs->legacyEnabled)
|
||||
ctxFlags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
|
||||
|
||||
/* Debug mode? */
|
||||
if(attribs->debugEnabled)
|
||||
ctxFlags |= GLX_CONTEXT_DEBUG_BIT_ARB;
|
||||
|
||||
ptr = addAttr(ptr, GLX_CONTEXT_FLAGS_ARB, ctxFlags);
|
||||
*ptr = None;
|
||||
|
||||
|
||||
ctx = glX.CreateContextAttribsARB(display, fbconfig, NULL, True, attr);
|
||||
if(ctx == NULL)
|
||||
return NULL;
|
||||
|
||||
}
|
||||
else /* Use older GLX 1.3 glXCreateNewContext() function */
|
||||
{
|
||||
/* Attempt to create an OpenGL context */
|
||||
ctx = glX.CreateNewContext(display, fbconfig, GLX_RGBA_TYPE, NULL, True);
|
||||
if(ctx == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* In order to check the version number, we're going to need to create
|
||||
a temporary context. I'm using a Pbuffer to do so. */
|
||||
pb = glX.CreatePbuffer(display, fbconfig, pbattr);
|
||||
if(pb == None)
|
||||
{
|
||||
glX.DestroyContext(display, ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Activate it */
|
||||
if(glX.MakeContextCurrent(display, pb, pb, ctx))
|
||||
{
|
||||
const char* (*pglGetString)(unsigned int);
|
||||
const char* version;
|
||||
|
||||
/* Check libGL for this */
|
||||
pglGetString = dlsym(glX.libGL, "glGetString");
|
||||
|
||||
version = pglGetString(GL_VERSION);
|
||||
|
||||
major = (uint8_t)(version[0] - '0'); /* "X.Y" -> [0]:major, [2]:minor */
|
||||
minor = (uint8_t)(version[2] - '0');
|
||||
|
||||
/* Save context version information */
|
||||
if(selectedAttribsReturn != NULL)
|
||||
{
|
||||
selectedAttribsReturn->contextVersionMajor = (uint8_t)major;
|
||||
selectedAttribsReturn->contextVersionMinor = (uint8_t)minor;
|
||||
}
|
||||
|
||||
/* OK, we have the information we need. Unbind the context and destroy the Pbuffer */
|
||||
glX.MakeContextCurrent(display, None, None, NULL);
|
||||
glX.DestroyPbuffer(display, pb);
|
||||
|
||||
/* If the major version is too low or the major version is OK, but the minor version is lacking, then fail */
|
||||
if(major < attribs->contextVersionMajor || (major == attribs->contextVersionMajor && minor < attribs->contextVersionMinor))
|
||||
{
|
||||
glX.DestroyContext(display, ctx);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else /* Failed to make current */
|
||||
{
|
||||
glX.DestroyContext(display, ctx);
|
||||
glX.DestroyPbuffer(display, pb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GLctx = (SST_OpenGLContext_Xlib*)malloc(sizeof(SST_OpenGLContext_Xlib));
|
||||
if(GLctx == NULL)
|
||||
{
|
||||
glX.DestroyContext(display, ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GLctx->glxcontext = ctx;
|
||||
GLctx->displayTarget = displayTarget;
|
||||
GLctx->ctxVersion[0] = major;
|
||||
GLctx->ctxVersion[1] = minor;
|
||||
|
||||
return GLctx;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void setupAttribs(int* glxAttr, const SST_OpenGLContextAttributes* attribs, Bool supportsMultisample)
|
||||
{
|
||||
int* ptr = glxAttr;
|
||||
int r, b, g;
|
||||
|
||||
|
||||
switch(attribs->colorBits)
|
||||
{
|
||||
/* Since these values are "at least", 5-5-5 and 5-6-5 configurations can use the same number */
|
||||
case 15:
|
||||
case 16:
|
||||
r = g = b = 5;
|
||||
break;
|
||||
|
||||
case 24:
|
||||
r = g = b = 8;
|
||||
|
||||
}
|
||||
|
||||
ptr = addAttr(ptr, GLX_DOUBLEBUFFER, True);
|
||||
ptr = addAttr(ptr, GLX_STEREO, (attribs-> stereoEnabled != 0));
|
||||
ptr = addAttr(ptr, GLX_RED_SIZE, r);
|
||||
ptr = addAttr(ptr, GLX_GREEN_SIZE, r);
|
||||
ptr = addAttr(ptr, GLX_BLUE_SIZE, b);
|
||||
ptr = addAttr(ptr, GLX_ALPHA_SIZE, ((int)attribs->alphaBits) & 0xFF);
|
||||
ptr = addAttr(ptr, GLX_DEPTH_SIZE, ((int)attribs->depthBits) & 0xFF);
|
||||
ptr = addAttr(ptr, GLX_STENCIL_SIZE, ((int)attribs->stencilBits) & 0xFF);
|
||||
|
||||
/* Add multisample attributes as appropriate */
|
||||
if(attribs->multisampleFactor > 1 && supportsMultisample)
|
||||
{
|
||||
ptr = addAttr(ptr, GLX_SAMPLE_BUFFERS_ARB, 1);
|
||||
ptr = addAttr(ptr, GLX_SAMPLES_ARB, ((int)attribs->multisampleFactor) & 0xFF);
|
||||
}
|
||||
|
||||
/* End attribute list */
|
||||
*ptr = None;
|
||||
|
||||
}
|
||||
95
libsst-wm/Xlib/GLXPrivate.h
Normal file
95
libsst-wm/Xlib/GLXPrivate.h
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
GLXPrivate.h
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 1/11/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
OpenGL on X Windows (GLX) utility code
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef _GLXPRIVATE_H
|
||||
#define _GLXPRIVATE_H
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <SST/SST_WMOpenGL.h>
|
||||
|
||||
struct SST_DisplayTarget_Xlib;
|
||||
|
||||
#define MAX_GL_ATTRS 32
|
||||
|
||||
/* glx.h types */
|
||||
typedef XID GLXDrawable;
|
||||
typedef XID GLXWindow;
|
||||
typedef XID GLXPbuffer;
|
||||
typedef struct __fakeGLXContext* GLXContext;
|
||||
typedef struct __fakeGLXFBConfig* GLXFBConfig;
|
||||
|
||||
typedef Bool (*pf_glXQueryExtension)(Display* dpy, int* errorBase, int* eventBase);
|
||||
typedef Bool (*pf_glXQueryVersion)(Display* dpy, int* major, int* minor);
|
||||
typedef const char* (*pf_glXQueryExtensionsString)(Display* dpy, int screen);
|
||||
typedef GLXFBConfig* (*pf_glXChooseFBConfig)(Display* dpy, int screen, const int* attrib_list, int* nelements);
|
||||
typedef GLXContext (*pf_glXCreateNewContext)(Display* dpy, GLXFBConfig config, int render_type, GLXContext share_list, Bool direct);
|
||||
typedef void (*pf_glXDestroyContext)(Display* dpy, GLXContext ctx);
|
||||
typedef Bool (*pf_glXMakeContextCurrent)(Display* display, GLXDrawable draw, GLXDrawable read, GLXContext ctx);
|
||||
typedef GLXContext (*pf_glXGetCurrentContext)(void);
|
||||
typedef void (*pf_glXSwapBuffers)(Display * dpy, GLXDrawable drawable);
|
||||
typedef GLXPbuffer (*pf_glXCreatePbuffer)(Display* dpy, GLXFBConfig config, const int* attrib_list);
|
||||
typedef void (*pf_glXDestroyPbuffer)(Display* dpy, GLXPbuffer pbuf);
|
||||
typedef GLXContext (*pf_glXCreateContextAttribsARB)(Display* dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int* attrib_list);
|
||||
|
||||
typedef void* (*pf_glXGetProcAddressARB)(const char* procName);
|
||||
|
||||
typedef struct GLXFunctions
|
||||
{
|
||||
pf_glXQueryExtension QueryExtension;
|
||||
pf_glXQueryVersion QueryVersion;
|
||||
pf_glXQueryExtensionsString QueryExtensionsString;
|
||||
pf_glXChooseFBConfig ChooseFBConfig;
|
||||
pf_glXCreateNewContext CreateNewContext;
|
||||
pf_glXDestroyContext DestroyContext;
|
||||
pf_glXMakeContextCurrent MakeContextCurrent;
|
||||
pf_glXGetCurrentContext GetCurrentContext;
|
||||
pf_glXSwapBuffers SwapBuffers;
|
||||
pf_glXCreatePbuffer CreatePbuffer;
|
||||
pf_glXDestroyPbuffer DestroyPbuffer;
|
||||
pf_glXCreateContextAttribsARB CreateContextAttribsARB;
|
||||
pf_glXGetProcAddressARB GetProcAddressARB;
|
||||
|
||||
Bool supportsCreateContextARB;
|
||||
Bool supportsProfiles;
|
||||
Bool supportsMultisample;
|
||||
void* libGL;
|
||||
} GLXFunctions;
|
||||
|
||||
extern GLXFunctions glX;
|
||||
|
||||
/* Load libGL and resolve GLX symbols */
|
||||
int loadGLX();
|
||||
|
||||
/* Unload libGL */
|
||||
void unloadGLX();
|
||||
|
||||
/* Check if libGL was loaded */
|
||||
int isGLXLoaded();
|
||||
|
||||
/* Check if GLX is supported by the X server, and a usable version */
|
||||
int isGLXSupported(Display* display);
|
||||
|
||||
/* Create a GLX context */
|
||||
SST_OpenGLContext GLXCreateOpenGLContext(struct SST_DisplayTarget_Xlib* target, SST_WMOpenGLType apiType, const SST_OpenGLContextAttributes* attribs, SST_OpenGLContextAttributes* selectedAttribsReturn);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
49
libsst-wm/Xlib/SST_WMDialogBox_Xlib.c
Normal file
49
libsst-wm/Xlib/SST_WMDialogBox_Xlib.c
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
SST_WMDialogBox_Xlib.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 1/5/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
Simple dialog box window (Xlib)
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#include "XlibPrivate.h"
|
||||
|
||||
#define BUTTON_HSPACE 16 /* Space on either side of a button */
|
||||
#define BUTTON_VSPACE 16 /* Space between top of button and dialog text */
|
||||
#define TEXT_HSPACE 16
|
||||
#define TEXT_VSPACE 16
|
||||
|
||||
typedef struct DialogBoxData
|
||||
{
|
||||
const char* message;
|
||||
int lenMessage;
|
||||
int buttonId;
|
||||
int exitTime;
|
||||
} DialogBoxData;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
int Xlib_ShowDialogBox(SST_DisplayTarget target, SST_Window parent, const char* caption, const char* message, const char** buttons, int nrButtons)
|
||||
{
|
||||
/* TODO: helluvalota work */
|
||||
(void)target;
|
||||
(void)parent;
|
||||
(void)caption;
|
||||
(void)message;
|
||||
(void)buttons;
|
||||
(void)nrButtons;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
166
libsst-wm/Xlib/SST_WMEnum_Xlib.c
Normal file
166
libsst-wm/Xlib/SST_WMEnum_Xlib.c
Normal file
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
SST_WMEnum_Xlib.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 1/8/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
Enumerates graphics adapters and screens.
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#include <SST/SST_WM.h>
|
||||
|
||||
#include "XlibPrivate.h"
|
||||
#include "APIPrivate.h"
|
||||
#include <string.h> /* strlen() etc. */
|
||||
#include <stdlib.h>
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static SST_GraphicsEnumerator Xlib_CreateGraphicsEnumerator(void)
|
||||
{
|
||||
Display* display;
|
||||
SST_GraphicsEnumerator_Xlib* enumerator;
|
||||
|
||||
enumerator = (SST_GraphicsEnumerator_Xlib*)malloc(sizeof(SST_GraphicsEnumerator_Xlib));
|
||||
|
||||
if(enumerator == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Open the display */
|
||||
display = X.OpenDisplay(NULL);
|
||||
if(display == NULL)
|
||||
{
|
||||
free(enumerator);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Save and return */
|
||||
enumerator->bpp = (uint32_t)DefaultDepth(display, DefaultScreen(display));
|
||||
enumerator->width = (uint32_t)DisplayWidth(display, DefaultScreen(display));
|
||||
enumerator->height = (uint32_t)DisplayHeight(display, DefaultScreen(display));
|
||||
|
||||
/* Done with display */
|
||||
X.CloseDisplay(display);
|
||||
|
||||
return enumerator;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static size_t Xlib_GetEnumAdapterCount(SST_GraphicsEnumerator enumerator)
|
||||
{
|
||||
(void)enumerator;
|
||||
|
||||
/* Only support 1 adapter */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void Xlib_GetEnumAdapterName(SST_GraphicsEnumerator enumerator, size_t adapterId, char* nameReturn, size_t* bufferSize)
|
||||
{
|
||||
size_t len;
|
||||
const char* name = "X Display Device";
|
||||
|
||||
(void)enumerator;
|
||||
(void)adapterId;
|
||||
|
||||
len = strlen(name);
|
||||
|
||||
/* Query name length */
|
||||
if(nameReturn == NULL)
|
||||
{
|
||||
*bufferSize = len+1;
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t copyAmount;
|
||||
|
||||
/* Nothing to do? */
|
||||
if(*bufferSize == 0)
|
||||
return;
|
||||
|
||||
/* Use min(len, (*bufferSize)-1) */
|
||||
copyAmount = len;
|
||||
if(copyAmount > (*bufferSize)-1)
|
||||
copyAmount = (*bufferSize)-1;
|
||||
|
||||
memcpy(nameReturn, name, copyAmount);
|
||||
nameReturn[copyAmount] = '\0';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static size_t Xlib_GetEnumScreenCount(SST_GraphicsEnumerator enumerator, size_t adapterId)
|
||||
{
|
||||
(void)enumerator;
|
||||
(void)adapterId;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void Xlib_GetEnumVideoModes(SST_GraphicsEnumerator enumerator, size_t adapterId, size_t screenId, SST_VideoMode* modesReturn, size_t* modeCountReturn)
|
||||
{
|
||||
SST_GraphicsEnumerator_Xlib* enumXlib = (SST_GraphicsEnumerator_Xlib*)enumerator;
|
||||
|
||||
/* Only one adapter/screen supported */
|
||||
if(adapterId != 0 || screenId != 0)
|
||||
return;
|
||||
|
||||
if(modesReturn == NULL)
|
||||
*modeCountReturn = 1;
|
||||
else
|
||||
{
|
||||
modesReturn[0].bpp = enumXlib->bpp;
|
||||
modesReturn[0].width = enumXlib->width;
|
||||
modesReturn[0].height = enumXlib->height;
|
||||
modesReturn[0].refreshRate = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void Xlib_GetEnumCurrentVideoMode(SST_GraphicsEnumerator enumerator, size_t adapterId, size_t screenId, SST_VideoMode* mode)
|
||||
{
|
||||
SST_GraphicsEnumerator_Xlib* enumXlib = (SST_GraphicsEnumerator_Xlib*)enumerator;
|
||||
if(adapterId != 0 || screenId != 0)
|
||||
return;
|
||||
|
||||
mode->bpp = enumXlib->bpp;
|
||||
mode->width = enumXlib->width;
|
||||
mode->height = enumXlib->height;
|
||||
mode->refreshRate = 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void Xlib_DestroyGraphicsEnumerator(SST_GraphicsEnumerator enumerator)
|
||||
{
|
||||
free(enumerator);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
struct SST_WM_EnumFuncs Xlib_EnumFuncs = {
|
||||
Xlib_CreateGraphicsEnumerator,
|
||||
Xlib_GetEnumAdapterCount,
|
||||
Xlib_GetEnumAdapterName,
|
||||
Xlib_GetEnumScreenCount,
|
||||
Xlib_GetEnumVideoModes,
|
||||
Xlib_GetEnumCurrentVideoMode,
|
||||
Xlib_DestroyGraphicsEnumerator
|
||||
};
|
||||
|
||||
482
libsst-wm/Xlib/SST_WMEvent_Xlib.c
Normal file
482
libsst-wm/Xlib/SST_WMEvent_Xlib.c
Normal file
@@ -0,0 +1,482 @@
|
||||
/*
|
||||
SST_WMEvent_Xlib.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 1/8/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
Window event functions (Xlib)
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#include <SST/SST_WMEvent.h>
|
||||
#include "XlibPrivate.h"
|
||||
#include "APIPrivate.h"
|
||||
|
||||
static SST_WMKey XlibKeyToSSTKey(XEvent* e, uint32_t* utf32Return);
|
||||
|
||||
#ifdef HAVE_XINPUT2
|
||||
static void handleXI2Event(SST_DisplayTarget_Xlib*, XGenericEventCookie* cookie);
|
||||
#endif
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static int Xlib_GetEvent(SST_DisplayTarget target, SST_WMEvent* eventReturn)
|
||||
{
|
||||
XEvent e;
|
||||
SST_DisplayTarget_Xlib* displayTarget = (SST_DisplayTarget_Xlib*)target;
|
||||
Display* display = displayTarget->display;
|
||||
EventQueue* q = &displayTarget->eventQueue;
|
||||
|
||||
/* Read all X events */
|
||||
while(X.Pending(display))
|
||||
{
|
||||
SST_Window_Xlib* win = NULL;
|
||||
SST_Window_Xlib* next;
|
||||
SST_WMEvent* event;
|
||||
#ifdef HAVE_XINPUT2
|
||||
XGenericEventCookie* cookie = &e.xcookie;
|
||||
#endif
|
||||
int up = 1;
|
||||
|
||||
X.NextEvent(display, &e);
|
||||
|
||||
/* Find the window for which this matches and save into 'win' */
|
||||
next = displayTarget->firstWindow;
|
||||
while(next)
|
||||
{
|
||||
/* Window ID matches this event? */
|
||||
if(next->xwin == e.xany.window)
|
||||
{
|
||||
/* Found it, stop here */
|
||||
win = next;
|
||||
break;
|
||||
}
|
||||
|
||||
next = next->next;
|
||||
}
|
||||
|
||||
#ifdef HAVE_XINPUT2
|
||||
/* Handle X extension events */
|
||||
if(cookie->type == GenericEvent && cookie->extension == displayTarget->xi2opcode)
|
||||
{
|
||||
X.GetEventData(display, cookie);
|
||||
handleXI2Event(displayTarget, cookie);
|
||||
X.FreeEventData(display, cookie);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Event doesn't apply to any window we own, ignore it */
|
||||
if(win == NULL)
|
||||
continue;
|
||||
|
||||
switch(e.type)
|
||||
{
|
||||
/* Moved mouse */
|
||||
case MotionNotify:
|
||||
{
|
||||
//Ignore MotionNotify when using relative mouse movements
|
||||
if(!displayTarget->relativeMouse)
|
||||
{
|
||||
event = AllocSlotInEQ(q);
|
||||
if(event)
|
||||
{
|
||||
event->window = win;
|
||||
event->type = SSTWMEVENT_MOUSEMOVED;
|
||||
event->details.mouseEvent.x = (uint32_t)e.xmotion.x;
|
||||
event->details.mouseEvent.y = (uint32_t)e.xmotion.y;
|
||||
event->details.mouseEvent.button = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ButtonPress: up = 0; /* Intentional fall through */
|
||||
case ButtonRelease:
|
||||
{
|
||||
const uint32_t button = e.xbutton.button;
|
||||
|
||||
event = AllocSlotInEQ(q);
|
||||
if(event)
|
||||
{
|
||||
event->window = win;
|
||||
|
||||
/* Button press (1 - 3) */
|
||||
if(button >= Button1 && button <= Button3)
|
||||
{
|
||||
event->type = (up ? SSTWMEVENT_MOUSEUP : SSTWMEVENT_MOUSEDOWN);
|
||||
event->details.mouseEvent.x = (uint32_t)e.xbutton.x;
|
||||
event->details.mouseEvent.y = (uint32_t)e.xbutton.y;
|
||||
event->details.mouseEvent.button = SST_MB1 + (button - Button1);
|
||||
}
|
||||
else if(e.type == ButtonPress) /* Scroll wheel. Button4 = scroll up, Button5 = scroll down. */
|
||||
{ /* X will send two events: press/release for a single scroll. Only send 1 event */
|
||||
event->type = SSTWMEVENT_MOUSEWHEEL;
|
||||
event->details.scrollEvent.vscroll = (button == Button4 ? 1.0f : -1.0f);
|
||||
event->details.scrollEvent.hscroll = 0.0f; /* TODO: how to get horizonal scroll wheel? */
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case KeyPress: up = 0; /* Intentional fall through */
|
||||
case KeyRelease:
|
||||
{
|
||||
uint32_t modState = 0;
|
||||
uint8_t whichBit = e.xkey.keycode % 8;
|
||||
uint32_t whichByte = e.xkey.keycode / 8;
|
||||
|
||||
/*
|
||||
X will autorepeat with a bunch of keyd release messages. We only want the key up, so it looks like:
|
||||
PPPPPPPPPPPPPR
|
||||
instead of:
|
||||
PRPRPRPRPRPRPR
|
||||
|
||||
To find this out, when receive a KeyRelease message, we check if there is another KeyPress message with the same
|
||||
exact time. If so, we ignore this KeyRelease message.
|
||||
*/
|
||||
if(e.xany.type == KeyRelease)
|
||||
{
|
||||
if(X.Pending(display))
|
||||
{
|
||||
XEvent nextEvent;
|
||||
X.PeekEvent(display, &nextEvent);
|
||||
|
||||
if( nextEvent.type == KeyPress && /* Opposite of KeyRelease */
|
||||
nextEvent.xkey.keycode == e.xkey.keycode && /* Same key code */
|
||||
nextEvent.xkey.time == e.xkey.time) /* Same time */
|
||||
{
|
||||
/* Ignore it */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* OK, really is a key release then -- unset this bit */
|
||||
displayTarget->keymapBitvector[whichByte] &= ~(1 << whichBit);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
if(displayTarget->keymapBitvector[whichByte] >> whichBit)
|
||||
modState |= SSTKEYMOD_REPEAT;
|
||||
|
||||
/* TODO: how to set SSTKEYMOD_REPEAT flag? Maybe use XQueryKeymap()? */
|
||||
displayTarget->keymapBitvector[whichByte] |= (1 << whichBit);
|
||||
|
||||
}
|
||||
|
||||
|
||||
event = AllocSlotInEQ(q);
|
||||
if(event)
|
||||
{
|
||||
SST_WMKey key;
|
||||
uint32_t utf32;
|
||||
|
||||
key = XlibKeyToSSTKey(&e, &utf32);
|
||||
|
||||
event->window = win;
|
||||
event->type = (up ? SSTWMEVENT_KEYUP : SSTWMEVENT_KEYDOWN);
|
||||
event->details.keyEvent.key = key;
|
||||
event->details.keyEvent.utf32 = utf32;
|
||||
event->details.keyEvent.modifierState = modState;
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Window shown */
|
||||
case Expose:
|
||||
{
|
||||
/* TODO: software rendering should blit image */
|
||||
break;
|
||||
}
|
||||
|
||||
case ConfigureNotify:
|
||||
{
|
||||
/* Clients are told to ignore this message if override_redirect is true. */
|
||||
if(e.xconfigure.override_redirect == False)
|
||||
{
|
||||
const XConfigureEvent* xc = (const XConfigureEvent*)&e.xconfigure;
|
||||
|
||||
/* Check if window moved */
|
||||
if(win->lastX != xc->x || win->lastY != xc->y)
|
||||
{
|
||||
event = AllocSlotInEQ(q);
|
||||
if(event)
|
||||
{
|
||||
event->window = win;
|
||||
event->type = SSTWMEVENT_MOVED;
|
||||
event->details.winEvent.x = (uint32_t)(xc->x < 0 ? 0 : xc->x);
|
||||
event->details.winEvent.y = (uint32_t)(xc->y < 0 ? 0 : xc->y);
|
||||
}
|
||||
}
|
||||
|
||||
if(win->lastWidth != xc->width || win->lastHeight != xc->height)
|
||||
{
|
||||
event = AllocSlotInEQ(q);
|
||||
if(event)
|
||||
{
|
||||
event->window = win;
|
||||
event->type = SSTWMEVENT_RESIZED;
|
||||
event->details.winEvent.x = (uint32_t)xc->width;
|
||||
event->details.winEvent.y = (uint32_t)xc->height;
|
||||
}
|
||||
|
||||
win->lastWidth = xc->width;
|
||||
win->lastHeight = xc->height;
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ClientMessage:
|
||||
{
|
||||
/* Close window attempt? */
|
||||
if(e.xclient.message_type == displayTarget->atomWmProtocols &&
|
||||
(Atom)e.xclient.data.l[0] == displayTarget->atomWmDeleteWindow)
|
||||
{
|
||||
event = AllocSlotInEQ(q);
|
||||
if(event)
|
||||
{
|
||||
event->window = win;
|
||||
event->type = SSTWMEVENT_CLOSE;
|
||||
memset(&event->details, 0, sizeof(event->details));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Dequeue for user events first */
|
||||
if(RemoveFromEQ(&displayTarget->userEventQueue, eventReturn))
|
||||
return 1;
|
||||
|
||||
/* Remove system events next */
|
||||
if(RemoveFromEQ(&displayTarget->eventQueue, eventReturn))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static EventQueue* Xlib_getUserEventQueue(SST_DisplayTarget target)
|
||||
{
|
||||
|
||||
SST_DisplayTarget_Xlib* displayTarget = (SST_DisplayTarget_Xlib*)target;
|
||||
return &displayTarget->userEventQueue;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
static void Xlib_lockUserEventQueue(SST_DisplayTarget target)
|
||||
{
|
||||
SST_DisplayTarget_Xlib* displayTarget = (SST_DisplayTarget_Xlib*)target;
|
||||
pthread_mutex_lock(&displayTarget->eventLock);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void Xlib_unlockUserEventQueue(SST_DisplayTarget target)
|
||||
{
|
||||
SST_DisplayTarget_Xlib* displayTarget = (SST_DisplayTarget_Xlib*)target;
|
||||
pthread_mutex_unlock(&displayTarget->eventLock);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static SST_WMKey XlibKeyToSSTKey(XEvent* e, uint32_t* utf32Return)
|
||||
{
|
||||
uint8_t chars[8];
|
||||
uint32_t utf32;
|
||||
|
||||
KeySym keycode;
|
||||
|
||||
X.LookupString(&e->xkey, (char*)chars, sizeof(chars), &keycode, NULL);
|
||||
|
||||
/* TODO: figure out how to extract multicharacter values */
|
||||
utf32 = (uint32_t)chars[0];
|
||||
|
||||
/* X allows Ctrl+[a-z] to generate some weird characters */
|
||||
if(utf32 < 0x20u)
|
||||
utf32 = 0;
|
||||
|
||||
*utf32Return = utf32;
|
||||
|
||||
/* 0 - 9 */
|
||||
if(keycode >= XK_0 && keycode <= XK_9)
|
||||
return (SST_WMKey)(SSTWMKEY_0 + (keycode - XK_0));
|
||||
|
||||
/* Keypad 0 - 9 */
|
||||
if(keycode >= XK_KP_0 && keycode <= XK_KP_9)
|
||||
return (SST_WMKey)(SSTWMKEY_KEYPAD_0 + (keycode - XK_KP_0));
|
||||
|
||||
/* Capital A-Z */
|
||||
if(keycode >= XK_A && keycode <= XK_Z)
|
||||
return (SST_WMKey)(SSTWMKEY_A + (keycode - XK_A));
|
||||
|
||||
/* Lower case A-Z */
|
||||
if(keycode >= XK_a && keycode <= XK_z)
|
||||
return (SST_WMKey)(SSTWMKEY_A + (keycode - XK_a));
|
||||
|
||||
/* Function keys (F1-F15) */
|
||||
if(keycode >= XK_F1 && keycode <= XK_F15)
|
||||
return (SST_WMKey)(SSTWMKEY_F1 + (keycode - XK_F1));
|
||||
|
||||
switch(keycode)
|
||||
{
|
||||
|
||||
case XK_BackSpace: return SSTWMKEY_BACKSPACE;
|
||||
case XK_Tab: return SSTWMKEY_TAB;
|
||||
case XK_Return: return SSTWMKEY_RETURN;
|
||||
|
||||
case XK_Escape: return SSTWMKEY_ESCAPE;
|
||||
case XK_space: return SSTWMKEY_SPACE;
|
||||
case XK_Caps_Lock: return SSTWMKEY_CAPSLOCK;
|
||||
#if 0
|
||||
case VK_OEM_COMMA : return SSTWMKEY_COMMA;
|
||||
case VK_OEM_PERIOD: return SSTWMKEY_PERIOD;
|
||||
case VK_OEM_2: return SSTWMKEY_FORWARDSLASH; /* '/?' key */
|
||||
case VK_OEM_1: return SSTWMKEY_SEMICOLON; /* ';:' key */
|
||||
case VK_OEM_7: return SSTWMKEY_QUOTES; /* single-quote/double quotes key */
|
||||
case VK_OEM_4: return SSTWMKEY_OPENBRACKET; /* '{{' key */
|
||||
case VK_OEM_6: return SSTWMKEY_CLOSEBRACKET; /* ']}' key */
|
||||
case VK_OEM_5: return SSTWMKEY_BACKSLASH; /* '\|' key */
|
||||
case VK_OEM_MINUS : return SSTWMKEY_UNDERBAR;
|
||||
case VK_OEM_PLUS: return SSTWMKEY_EQUALS;
|
||||
#endif
|
||||
|
||||
//Keypad
|
||||
case XK_KP_Enter: return SSTWMKEY_KEYPAD_ENTER;
|
||||
case XK_Num_Lock: return SSTWMKEY_NUMLOCK;
|
||||
case XK_KP_Decimal: return SSTWMKEY_KEYPAD_PERIOD;
|
||||
case XK_KP_Divide: return SSTWMKEY_KEYPAD_DIVIDE;
|
||||
case XK_KP_Multiply: return SSTWMKEY_KEYPAD_MULTIPLY;
|
||||
case XK_KP_Subtract: return SSTWMKEY_KEYPAD_MINUS;
|
||||
case XK_KP_Add: return SSTWMKEY_KEYPAD_PLUS;
|
||||
|
||||
/* Arrow keys */
|
||||
case XK_Up: return SSTWMKEY_ARROW_UP;
|
||||
case XK_Down: return SSTWMKEY_ARROW_DOWN;
|
||||
case XK_Left: return SSTWMKEY_ARROW_LEFT;
|
||||
case XK_Right: return SSTWMKEY_ARROW_RIGHT;
|
||||
|
||||
/* The page up/down block */
|
||||
case XK_Insert: return SSTWMKEY_INSERT;
|
||||
case XK_Home: return SSTWMKEY_HOME;
|
||||
case XK_End: return SSTWMKEY_END;
|
||||
case XK_Page_Up: return SSTWMKEY_PAGEUP;
|
||||
case XK_Page_Down: return SSTWMKEY_PAGEDOWN;
|
||||
case XK_Delete: return SSTWMKEY_DELETE;
|
||||
|
||||
case XK_Shift_L: return SSTWMKEY_LEFTSHIFT;
|
||||
case XK_Shift_R: return SSTWMKEY_RIGHTSHIFT;
|
||||
case XK_Control_L: return SSTWMKEY_LEFTCONTROL;
|
||||
case XK_Control_R: return SSTWMKEY_RIGHTCONTROL;
|
||||
case XK_Alt_L: return SSTWMKEY_LEFTALT;
|
||||
case XK_Alt_R: return SSTWMKEY_RIGHTALT;
|
||||
case XK_Super_L: return SSTWMKEY_LEFTSUPER;
|
||||
case XK_Super_R: return SSTWMKEY_RIGHTSUPER;
|
||||
#if 0
|
||||
/* Misc */
|
||||
case VK_SNAPSHOT: return SSTWMKEY_PRINTSCREEN;
|
||||
case VK_SCROLL: return SSTWMKEY_SCROLLLOCK;
|
||||
case VK_PAUSE: return SSTWMKEY_PAUSE;
|
||||
#endif
|
||||
case XK_asciitilde: return SSTWMKEY_TILDE; /* `~ key */
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
return SSTWMKEY_NONE;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
#ifdef HAVE_XINPUT2
|
||||
|
||||
static size_t min2(size_t x, size_t y) { return (x < y ? x : y); }
|
||||
|
||||
static void extractXI2values(const XIRawEvent* rawev, double* valuesReturn, size_t valueArraySize) {
|
||||
size_t i;
|
||||
const double* raw_values = rawev->raw_values;
|
||||
const unsigned char* mask = rawev->valuators.mask;
|
||||
const size_t elemsToCheck = min2(valueArraySize, rawev->valuators.mask_len * 8);
|
||||
|
||||
/* From what I can understand, raw_values[] is a compressed array. XIMaskIsSet(mask,i)
|
||||
is used to check whether element i of the output should be read from raw_values[]. So
|
||||
for example, raw_values[] could be just { 3.0, 5.0}, but the mask could be 1001b, which
|
||||
means that:
|
||||
XIMaskIsSet(1001b,0) == true; -> output[0] = 3.0 (raw_values[0)]
|
||||
XIMaskIsSet(1001b,1) == false; -> output[1] = 0.0 (default value)
|
||||
XIMaskIsSet(1001b,2) == false; -> output[2] = 0.0 (default value)
|
||||
XIMaskIsSet(1001b,3) == true; -> output[3] = 5.0 (raw_values[1])
|
||||
*/
|
||||
for(i=0; i < elemsToCheck; i++) {
|
||||
if(XIMaskIsSet(mask, i)) {
|
||||
valuesReturn[i] = *raw_values;
|
||||
raw_values++;
|
||||
} else {
|
||||
valuesReturn[i] = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Any uninitialized elements at the end set to zero */
|
||||
if(elemsToCheck < valueArraySize) {
|
||||
memset(&valuesReturn[elemsToCheck], 0, (valueArraySize-elemsToCheck)*sizeof(*valuesReturn));
|
||||
}
|
||||
}
|
||||
|
||||
static void handleXI2Event(SST_DisplayTarget_Xlib* displayTarget, XGenericEventCookie* cookie)
|
||||
{
|
||||
XIDeviceEvent* ev = (XIDeviceEvent*)cookie->data;
|
||||
EventQueue* q = &displayTarget->eventQueue;
|
||||
SST_WMEvent* event;
|
||||
|
||||
switch(ev->evtype)
|
||||
{
|
||||
case XI_RawButtonPress:
|
||||
case XI_RawButtonRelease:
|
||||
break;
|
||||
|
||||
case XI_RawMotion:
|
||||
{
|
||||
XIRawEvent* re = (XIRawEvent*)cookie->data;
|
||||
|
||||
event = AllocSlotInEQ(q);
|
||||
if(event)
|
||||
{
|
||||
double rel[2];
|
||||
|
||||
extractXI2values(re, rel, 2);
|
||||
|
||||
event->window = NULL; /* TODO: ... ?*/
|
||||
event->type = SSTWMEVENT_MOUSERELMOVED;
|
||||
event->details.relMouseEvent.relx = (int32_t)rel[0];
|
||||
event->details.relMouseEvent.rely = (int32_t)rel[1];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
const struct SST_WM_EventFuncs Xlib_EventFuncs = {
|
||||
Xlib_GetEvent,
|
||||
Xlib_getUserEventQueue,
|
||||
Xlib_lockUserEventQueue,
|
||||
Xlib_unlockUserEventQueue
|
||||
};
|
||||
|
||||
38
libsst-wm/Xlib/SST_WMNonPortable_Xlib.c
Normal file
38
libsst-wm/Xlib/SST_WMNonPortable_Xlib.c
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
SST_WMNonPortable_Xlib.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 1/8/2012
|
||||
|
||||
Purpose:
|
||||
|
||||
Non-portable API calls in libsst-wm for the Xlib platform
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#include "XlibPrivate.h"
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
Display* SST_WM_GetDisplayX11(SST_Window window)
|
||||
{
|
||||
SST_Window_Xlib* win = (SST_Window_Xlib*)window;
|
||||
|
||||
return win->owner->display;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
Window SST_WM_GetWindowX11(SST_Window window)
|
||||
{
|
||||
SST_Window_Xlib* win = (SST_Window_Xlib*)window;
|
||||
|
||||
return win->xwin;
|
||||
}
|
||||
315
libsst-wm/Xlib/SST_WMOpenGL_Xlib.c
Normal file
315
libsst-wm/Xlib/SST_WMOpenGL_Xlib.c
Normal file
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
SST_WMOpenGL_Xlib.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 1/13/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
OpenGL context creation on X Windows
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
#include <SST/SST_WMOpenGL.h>
|
||||
#include "XlibPrivate.h"
|
||||
#include "GLXPrivate.h"
|
||||
#include "APIPrivate.h"
|
||||
|
||||
/*
|
||||
NOTE: We don't include <GL/gl.h> because it may not exist! Many embedded Linux
|
||||
systems now ship with OpenGL|ES only, and because of that, they don't have
|
||||
headers for full OpenGL. This API supports both, so we can't assume any OpenGL
|
||||
headers (either regular or "ES") exist.
|
||||
*/
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static SST_OpenGLContext Xlib_CreateOpenGLContext(SST_DisplayTarget target, SST_WMOpenGLType apiType, const SST_OpenGLContextAttributes* attribs, SST_OpenGLContextAttributes* selectedAttribsReturn)
|
||||
{
|
||||
SST_DisplayTarget_Xlib* displayTarget = (SST_DisplayTarget_Xlib*)target;
|
||||
SST_OpenGLContext glctx;
|
||||
Bool usingGLX = True;
|
||||
Display* display = displayTarget->display;
|
||||
|
||||
/* If using GL|ES, only EGL will do */
|
||||
if(apiType == SSTGL_OPENGL_ES)
|
||||
usingGLX = False;
|
||||
else /* We can use either GLX or EGL to create a full GL context */
|
||||
{
|
||||
/* Not loaded -> fail */
|
||||
if(!isGLXLoaded())
|
||||
usingGLX = False;
|
||||
|
||||
/* The client has GLX libraries, but does the server support it? */
|
||||
if(!isGLXSupported(display))
|
||||
usingGLX = False;
|
||||
|
||||
/* GLX isn't supported */
|
||||
if(usingGLX == False)
|
||||
{
|
||||
/* TODO: try EGL */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
if(usingGLX)
|
||||
{
|
||||
glctx = GLXCreateOpenGLContext(displayTarget, apiType, attribs, selectedAttribsReturn);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* TODO: Add EGL path */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return glctx;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static SST_OpenGLContext Xlib_CreateSlaveOpenGLContext(SST_OpenGLContext masterGLContext)
|
||||
{
|
||||
SST_OpenGLContext_Xlib* master = (SST_OpenGLContext_Xlib*)masterGLContext;
|
||||
SST_OpenGLContext_Xlib* slave;
|
||||
|
||||
#if 0
|
||||
HWND hInvisWnd;
|
||||
FindMonitorInfo fmi;
|
||||
HDC hDC = NULL;
|
||||
HGLRC hGLRC = NULL;
|
||||
BOOL ok;
|
||||
const WGLFunctions* wgl = &master->wgl;
|
||||
|
||||
/* Since the slave context merely needs to be on *a* screen controlled by the display target, just use the first one */
|
||||
findMonitor(&master->displayTarget->devs[0], &fmi);
|
||||
if(!fmi.foundIt)
|
||||
return NULL;
|
||||
|
||||
/* Make 1x1 hidden window that doesn't appear in the titlebar and has no borders */
|
||||
hInvisWnd = CreateWindowExA(WS_EX_TOOLWINDOW, SST_WINCLASS, "(temp)", WS_POPUP, fmi.left, fmi.top, 1, 1, NULL, NULL, GetModuleHandleA(NULL), NULL);
|
||||
if(hInvisWnd == NULL)
|
||||
return NULL;
|
||||
ShowWindow(hInvisWnd, SW_HIDE);
|
||||
|
||||
/* Allocate context structure */
|
||||
slave = HeapAlloc(GetProcessHeap(), 0, sizeof(SST_OpenGLContext_Win32));
|
||||
if(slave == NULL)
|
||||
{
|
||||
DestroyWindow(hInvisWnd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ok = FALSE;
|
||||
hDC = GetDC(hInvisWnd);
|
||||
|
||||
/* If master context was done using legacy functions... */
|
||||
if(master->isLegacy)
|
||||
{
|
||||
PIXELFORMATDESCRIPTOR pfd;
|
||||
|
||||
/* Get the PFD for this pixel foramt */
|
||||
DescribePixelFormat(hDC, master->pixelFormat, sizeof(pfd), &pfd);
|
||||
|
||||
/* Set it */
|
||||
if(SetPixelFormat(hDC, master->pixelFormat, &pfd))
|
||||
{
|
||||
hGLRC = wgl->CreateContext(hDC);
|
||||
if(hGLRC != NULL)
|
||||
{
|
||||
if(wgl->ShareLists(master->context, hGLRC))
|
||||
ok = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else /* Modern OpenGL functions */
|
||||
{
|
||||
if(SetPixelFormat(hDC, master->pixelFormat, NULL))
|
||||
{
|
||||
HGLRC oldRC;
|
||||
HDC oldDC;
|
||||
|
||||
oldDC = wgl->GetCurrentDC();
|
||||
oldRC = wgl->GetCurrentContext();
|
||||
|
||||
/* Bind master context so we can call wgl extension functions. Note that we're using
|
||||
the invisible window's HDC. This should work because we just set the pixel format to be
|
||||
identical to the master context, meaning they should be compatible */
|
||||
if(wgl->MakeCurrent(hDC, master->context))
|
||||
{
|
||||
int attrs[16];
|
||||
int* ptr = attrs;
|
||||
int ctxFlags;
|
||||
|
||||
if(master->debugEnabled)
|
||||
ctxFlags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
|
||||
|
||||
ptr = addAttr(ptr, WGL_CONTEXT_MAJOR_VERSION_ARB, master->ctxVersion[0]);
|
||||
ptr = addAttr(ptr, WGL_CONTEXT_MINOR_VERSION_ARB, master->ctxVersion[1]);
|
||||
ptr = addAttr(ptr, WGL_CONTEXT_LAYER_PLANE_ARB, 0);
|
||||
|
||||
/* If WGL_ARB_create_context_profile is supported, add a profile mask */
|
||||
if(wgl->supportsProfiles)
|
||||
ptr = addAttr(ptr, WGL_CONTEXT_PROFILE_MASK_ARB, (master->legacyEnabled ? WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB : WGL_CONTEXT_CORE_PROFILE_BIT_ARB));
|
||||
|
||||
/* Legacy-free? */
|
||||
if(!master->legacyEnabled)
|
||||
ctxFlags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
|
||||
|
||||
/* Debug mode? */
|
||||
if(master->debugEnabled)
|
||||
ctxFlags |= WGL_CONTEXT_DEBUG_BIT_ARB;
|
||||
|
||||
ptr = addAttr(ptr, WGL_CONTEXT_FLAGS_ARB, ctxFlags);
|
||||
*ptr = 0;
|
||||
|
||||
/* Create the new context, sharing with the master context */
|
||||
hGLRC = wgl->CreateContextAttribsARB(hDC, master->context, attrs);
|
||||
if(hGLRC != NULL)
|
||||
ok = TRUE;
|
||||
}
|
||||
|
||||
/* Restore old context */
|
||||
wgl->MakeCurrent(oldDC, oldRC);
|
||||
}
|
||||
}
|
||||
|
||||
/* Done with the DC */
|
||||
if(hDC)
|
||||
ReleaseDC(hInvisWnd, hDC);
|
||||
|
||||
/* Did we succeed in making the slave context? */
|
||||
if(ok)
|
||||
{
|
||||
/* Set up slave context info */
|
||||
slave->context = hGLRC;
|
||||
slave->displayTarget = master->displayTarget;
|
||||
slave->hDCActive = NULL;
|
||||
slave->hSlaveWnd = hInvisWnd;
|
||||
slave->isLegacy = master->isLegacy;
|
||||
slave->opengl32 = LoadLibraryA("opengl32.dll"); /* Need to increase ref count for opengl32.dll */
|
||||
slave->pixelFormat = master->pixelFormat;
|
||||
slave->wgl = master->wgl; /* TODO: should be safe, right? context dependent, but same device/GL impl... */
|
||||
slave->ctxVersion[0] = master->ctxVersion[0];
|
||||
slave->ctxVersion[1] = master->ctxVersion[1];
|
||||
slave->legacyEnabled = master->legacyEnabled;
|
||||
slave->debugEnabled = master->debugEnabled;
|
||||
}
|
||||
else /* Failure, clean up */
|
||||
{
|
||||
if(hGLRC)
|
||||
master->wgl.DeleteContext(hGLRC);
|
||||
|
||||
DestroyWindow(hInvisWnd);
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, slave);
|
||||
slave = NULL;
|
||||
}
|
||||
#endif
|
||||
return slave;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void Xlib_SwapOpenGLBuffers(SST_OpenGLContext ctx)
|
||||
{
|
||||
SST_OpenGLContext_Xlib* glctx = (SST_OpenGLContext_Xlib*)ctx;
|
||||
|
||||
if(glctx->glxcontext)
|
||||
glX.SwapBuffers(glctx->displayTarget->display, glctx->win);
|
||||
else
|
||||
{
|
||||
/* TODO: eglSwapBuffers() */
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static int Xlib_BindOpenGLContext(SST_OpenGLContext ctx, SST_Window window)
|
||||
{
|
||||
SST_OpenGLContext_Xlib* glctx = (SST_OpenGLContext_Xlib*)ctx;
|
||||
SST_Window_Xlib* win = (SST_Window_Xlib*)window;
|
||||
|
||||
/* Unbinding a context from a thread */
|
||||
if(ctx == NULL)
|
||||
{
|
||||
|
||||
/* GLX: Unbind context */
|
||||
if(glctx->glxcontext)
|
||||
{
|
||||
glX.MakeContextCurrent(glctx->displayTarget->display, None, None, NULL);
|
||||
|
||||
glctx->win = None;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* TODO: EGL implementation */
|
||||
}
|
||||
|
||||
/* OK */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* GLX*/
|
||||
if(glctx->glxcontext)
|
||||
{
|
||||
|
||||
/* Binding master context to a window */
|
||||
if(win != NULL)
|
||||
{
|
||||
if(glX.MakeContextCurrent(glctx->displayTarget->display, win->xwin, win->xwin, glctx->glxcontext))
|
||||
{
|
||||
glctx->win = win->xwin;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Failed to bind */
|
||||
return 0;
|
||||
}
|
||||
else /* Bind slave context */
|
||||
{
|
||||
/* TODO: bind to a slave's pbuffer, I guess? */
|
||||
}
|
||||
}
|
||||
else /* Otherwise EGL */
|
||||
{
|
||||
/* TODO: EGL */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void Xlib_DestroyOpenGLContext(SST_OpenGLContext ctx)
|
||||
{
|
||||
SST_OpenGLContext_Xlib* glctx = (SST_OpenGLContext_Xlib*)ctx;
|
||||
|
||||
#if 0
|
||||
if(glctx->hSlaveWnd)
|
||||
DestroyWindow(glctx->hSlaveWnd);
|
||||
#endif
|
||||
|
||||
/* Destroy the OpenGL context */
|
||||
glX.DestroyContext(glctx->displayTarget->display, glctx->glxcontext);
|
||||
|
||||
/* Free memory used by our GL context */
|
||||
free(glctx);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
const struct SST_WM_OpenGLFuncs Xlib_OpenGLFuncs = {
|
||||
Xlib_CreateOpenGLContext,
|
||||
Xlib_CreateSlaveOpenGLContext,
|
||||
Xlib_SwapOpenGLBuffers,
|
||||
Xlib_BindOpenGLContext,
|
||||
Xlib_DestroyOpenGLContext
|
||||
};
|
||||
75
libsst-wm/Xlib/SST_WMRender_Xlib.c
Normal file
75
libsst-wm/Xlib/SST_WMRender_Xlib.c
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
SST_WMRender_Xlib.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 1/8/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
Software rendering support
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#include "XlibPrivate.h"
|
||||
#include <SST/SST_WMWindow.h>
|
||||
#include "APIPrivate.h"
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
int Xlib_EnableSoftwareRendering(SST_Window window)
|
||||
{
|
||||
SST_Window_Xlib* win = (SST_Window_Xlib*)window;
|
||||
|
||||
/* TODO: Use XPutImage or XShm extension */
|
||||
(void)win;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void Xlib_DisableSoftwareRendering(SST_Window window)
|
||||
{
|
||||
SST_Window_Xlib* win = (SST_Window_Xlib*)window;
|
||||
|
||||
/* TODO */
|
||||
(void)win;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void* Xlib_LockBackbuffer(SST_Window window, size_t* pitchReturn)
|
||||
{
|
||||
SST_Window_Xlib* win = (SST_Window_Xlib*)window;
|
||||
|
||||
*pitchReturn = win->softwarePitch;
|
||||
|
||||
return win->softwareBackbuffer;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void Xlib_UnlockBackbuffer(SST_Window window)
|
||||
{
|
||||
SST_Window_Xlib* win = (SST_Window_Xlib*)window;
|
||||
|
||||
/* TODO: invalidate window rect and repaint */
|
||||
(void)win;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
struct SST_WM_RenderFuncs Xlib_RenderFuncs = {
|
||||
Xlib_EnableSoftwareRendering,
|
||||
Xlib_DisableSoftwareRendering,
|
||||
Xlib_LockBackbuffer,
|
||||
Xlib_UnlockBackbuffer
|
||||
};
|
||||
|
||||
86
libsst-wm/Xlib/SST_WMVideoMode_Xlib.c
Normal file
86
libsst-wm/Xlib/SST_WMVideoMode_Xlib.c
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
SST_WMVideoMode_Xlib.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 1/8/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
Video mode setting functions (Xlib)
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#include "XlibPrivate.h"
|
||||
#include "APIPrivate.h"
|
||||
/*
|
||||
Right now, these are essentially no-ops. Later, some real mechanism needs to be used:
|
||||
|
||||
1) [Preferred] XRandR extension
|
||||
2) XF86VideoMode extension
|
||||
|
||||
That will get good and messy then. In particular, if a set of headers isn't available for the platform,
|
||||
then it basically won't compile. Seems like I need to re-write a few definitions in-line, and of course,
|
||||
link dynamically and do proper version queries (*.so doesn't mean server actually supports it).
|
||||
*/
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static int Xlib_SetVideoModeOnScreen(SST_DisplayTarget target, size_t screenIndex, const SST_VideoMode* vmode)
|
||||
{
|
||||
SST_DisplayTarget_Xlib* displayTarget = (SST_DisplayTarget_Xlib*)target;
|
||||
Display* display = displayTarget->display;
|
||||
int xscreen;
|
||||
|
||||
/* Must be screen 0 */
|
||||
if(screenIndex != 0)
|
||||
return 0;
|
||||
|
||||
xscreen = DefaultScreen(display);
|
||||
|
||||
/* Since we aren't changing the display mode, just verify it matches */
|
||||
if(vmode->bpp != (uint32_t)DefaultDepth(display, xscreen) ||
|
||||
vmode->width != (uint32_t)DisplayWidth(display, xscreen) ||
|
||||
vmode->height != (uint32_t)DisplayHeight(display, xscreen) ||
|
||||
vmode->refreshRate != 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static int Xlib_GetVideoModeOnScreen(SST_DisplayTarget target, size_t screenIndex, SST_VideoMode* vmodeReturn)
|
||||
{
|
||||
SST_DisplayTarget_Xlib* displayTarget = (SST_DisplayTarget_Xlib*)target;
|
||||
Display* display = displayTarget->display;
|
||||
int xscreen;
|
||||
|
||||
/* Must be screen 0 */
|
||||
if(screenIndex != 0)
|
||||
return 0;
|
||||
|
||||
xscreen = DefaultScreen(display);
|
||||
vmodeReturn->bpp = (uint32_t)DefaultDepth(display, xscreen);
|
||||
vmodeReturn->width = (uint32_t)DisplayWidth(display, xscreen);
|
||||
vmodeReturn->height = (uint32_t)DisplayHeight(display, xscreen);
|
||||
vmodeReturn->refreshRate = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const struct SST_WM_VideoModeFuncs Xlib_VideoModeFuncs = {
|
||||
Xlib_SetVideoModeOnScreen,
|
||||
Xlib_GetVideoModeOnScreen
|
||||
};
|
||||
|
||||
537
libsst-wm/Xlib/SST_WMWindow_Xlib.c
Normal file
537
libsst-wm/Xlib/SST_WMWindow_Xlib.c
Normal file
@@ -0,0 +1,537 @@
|
||||
/*
|
||||
SST_WMWindow_Xlib.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 1/8/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
Window creation (Xlib)
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#include <SST/SST_WMWindow.h>
|
||||
#include "XlibPrivate.h"
|
||||
#include "XI2Private.h"
|
||||
#include "EventQueue.h"
|
||||
#include "APIPrivate.h"
|
||||
#include <stdio.h>
|
||||
|
||||
static void destroyWin(SST_Window_Xlib* win);
|
||||
|
||||
/* Extended Window Manager Hints (http://standards.freedesktop.org/wm-spec/wm-spec-latest.html) */
|
||||
static int ewmh_supported(SST_DisplayTarget_Xlib* displayTarget, SST_Window_Xlib* win);
|
||||
static void ewmh_setFullscreen(SST_Window_Xlib* win, int fullscreen);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static SST_DisplayTarget Xlib_CreateDisplayTarget(size_t adapterIndex, size_t screenIndexOrMultihead)
|
||||
{
|
||||
SST_DisplayTarget_Xlib* displayTarget;
|
||||
#ifdef HAVE_XINPUT2
|
||||
XI2Functions XI;
|
||||
#endif
|
||||
Display* display;
|
||||
|
||||
/* > 1 adapters not supported, multihead not supported */
|
||||
if(screenIndexOrMultihead != 0 || adapterIndex != 0)
|
||||
return NULL;
|
||||
|
||||
/* Open the X display */
|
||||
display = X.OpenDisplay(NULL);
|
||||
if(display == NULL)
|
||||
return NULL;
|
||||
|
||||
/* If we can open a display, then we're connected to the X server,
|
||||
so that is good enough. */
|
||||
|
||||
/* Allocate a display target structure */
|
||||
displayTarget = (SST_DisplayTarget_Xlib*)malloc(sizeof(SST_DisplayTarget_Xlib));
|
||||
if(displayTarget == NULL)
|
||||
{
|
||||
X.CloseDisplay(display);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Initialize lock for user events */
|
||||
if(pthread_mutex_init(&displayTarget->eventLock, NULL) != 0)
|
||||
{
|
||||
X.CloseDisplay(display);
|
||||
free(displayTarget);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(InitEQ(&displayTarget->eventQueue) == 0)
|
||||
{
|
||||
pthread_mutex_destroy(&displayTarget->eventLock);
|
||||
X.CloseDisplay(display);
|
||||
free(displayTarget);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(InitEQ(&displayTarget->userEventQueue) == 0)
|
||||
{
|
||||
DestroyEQ(&displayTarget->eventQueue);
|
||||
pthread_mutex_destroy(&displayTarget->eventLock);
|
||||
X.CloseDisplay(display);
|
||||
free(displayTarget);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Save fields */
|
||||
displayTarget->display = display;
|
||||
displayTarget->firstWindow = NULL;
|
||||
displayTarget->relativeMouse = 0;
|
||||
displayTarget->ewmhSupport = -1;
|
||||
displayTarget->atomWmProtocols = X.InternAtom(display, "WM_PROTOCOLS", True);
|
||||
displayTarget->atomWmDeleteWindow = X.InternAtom(display, "WM_DELETE_WINDOW", False);
|
||||
memset(displayTarget->keymapBitvector, 0, sizeof(displayTarget->keymapBitvector));
|
||||
|
||||
/* XInput2: Verify that server supports XI2 (sets */
|
||||
#ifdef HAVE_XINPUT2
|
||||
if(XI2_IsLoaded())
|
||||
XI2_IsSupportedOnConnection(displayTarget);
|
||||
#endif
|
||||
|
||||
return (SST_DisplayTarget)displayTarget;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static size_t Xlib_GetDisplayTargetScreenCount(SST_DisplayTarget target)
|
||||
{
|
||||
(void)target;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static SST_Window Xlib_CreateWindowOnScreen(SST_DisplayTarget target, size_t screenIndex, uint32_t x, uint32_t y, uint32_t width, uint32_t height, const char* title)
|
||||
{
|
||||
SST_Window_Xlib* win;
|
||||
SST_DisplayTarget_Xlib* displayTarget = (SST_DisplayTarget_Xlib*)target;
|
||||
Window xwin;
|
||||
Display* display = displayTarget->display;
|
||||
int screen = DefaultScreen(display);
|
||||
SST_WMEvent* event;
|
||||
|
||||
/* Must be on screen 0 */
|
||||
if(screenIndex != 0)
|
||||
return 0;
|
||||
|
||||
xwin = X.CreateSimpleWindow(display,
|
||||
RootWindow(display, screen),
|
||||
(int)x, (int)y,
|
||||
(int)width, (int)height,
|
||||
0, 0, /* border width/color */
|
||||
WhitePixel(display, screen)); /* background color */
|
||||
|
||||
/* Set window's WM_PROTOCOLS property */
|
||||
X.SetWMProtocols(display, xwin, &displayTarget->atomWmDeleteWindow, 1);
|
||||
|
||||
/* Set title bar text */
|
||||
X.StoreName(display, xwin, title);
|
||||
|
||||
/* Map the window to the screen */
|
||||
X.MapRaised(display, xwin);
|
||||
|
||||
/* Force the move, because some window managers just put windows wherever. Argh. */
|
||||
X.MoveWindow(display, xwin, (int)x, (int)y);
|
||||
|
||||
X.SelectInput(display, xwin, KeyPressMask| KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | ExposureMask | StructureNotifyMask);
|
||||
|
||||
/* Display it now */
|
||||
X.Flush(display);
|
||||
|
||||
/* Allocate SST window structure */
|
||||
win = (SST_Window_Xlib*)malloc(sizeof(SST_Window_Xlib));
|
||||
if(win == NULL)
|
||||
return NULL;
|
||||
|
||||
win->owner = displayTarget;
|
||||
win->next = displayTarget->firstWindow;
|
||||
win->xwin = xwin;
|
||||
win->lastX = (uint32_t)x;
|
||||
win->lastY = (uint32_t)y;
|
||||
win->lastWidth = (uint32_t)width;
|
||||
win->lastHeight = (uint32_t)height;
|
||||
win->isFullscreen = 0;
|
||||
win->softwareBackbuffer = NULL;
|
||||
win->softwareImage = NULL;
|
||||
win->softwarePitch = 0;
|
||||
|
||||
/* Link window as new root */
|
||||
displayTarget->firstWindow = win;
|
||||
|
||||
/* Add a SSTWMEVENT_CREATED event */
|
||||
event = AllocSlotInEQ(&displayTarget->eventQueue);
|
||||
if(event != NULL)
|
||||
{
|
||||
event->window = win;
|
||||
event->type = SSTWMEVENT_CREATED;
|
||||
memset(&event->details, 0, sizeof(event->details));
|
||||
}
|
||||
|
||||
return (SST_Window)win;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static SST_DisplayTarget Xlib_GetWindowDisplayTarget(SST_Window window)
|
||||
{
|
||||
SST_Window_Xlib* win = (SST_Window_Xlib*)window;
|
||||
|
||||
return win->owner;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void Xlib_SetWindowText(SST_Window window, const char* titleBar)
|
||||
{
|
||||
SST_Window_Xlib* win = (SST_Window_Xlib*)window;
|
||||
|
||||
X.StoreName(win->owner->display, win->xwin, titleBar);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void Xlib_GetWindowRect(SST_Window window, SST_Rect* rectReturn)
|
||||
{
|
||||
SST_Window_Xlib* win = (SST_Window_Xlib*)window;
|
||||
Window dummyRoot;
|
||||
int x, y;
|
||||
unsigned int w, h;
|
||||
unsigned int dummy1, dummy2;
|
||||
|
||||
X.GetGeometry(win->owner->display, win->xwin, &dummyRoot, &x, &y, &w, &h, &dummy1, &dummy2);
|
||||
|
||||
rectReturn->x = (uint32_t)x;
|
||||
rectReturn->y = (uint32_t)y;
|
||||
rectReturn->width = (uint32_t)w;
|
||||
rectReturn->height = (uint32_t)h;
|
||||
return;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void Xlib_MoveWindowOnScreen(SST_Window window, size_t screenIndex, uint32_t x, uint32_t y)
|
||||
{
|
||||
SST_Window_Xlib* win = (SST_Window_Xlib*)window;
|
||||
|
||||
/* Only allow operations on screen 0 */
|
||||
if(screenIndex != SST_SAME_SCREEN && screenIndex != 0)
|
||||
return;
|
||||
|
||||
X.MoveWindow(win->owner->display, win->xwin, (int)x, (int)y);
|
||||
X.Sync(win->owner->display, False);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void Xlib_ResizeWindow(SST_Window window, uint32_t width, uint32_t height)
|
||||
{
|
||||
SST_Window_Xlib* win = (SST_Window_Xlib*)window;
|
||||
|
||||
X.ResizeWindow(win->owner->display, win->xwin, width, height);
|
||||
X.Sync(win->owner->display, False);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void Xlib_SetWindowState(SST_Window window, SST_WMWindowState state, uint32_t param)
|
||||
{
|
||||
SST_Window_Xlib* win = (SST_Window_Xlib*)window;
|
||||
Display* display = win->owner->display;
|
||||
|
||||
switch(state)
|
||||
{
|
||||
case SSTWS_SHOWN:
|
||||
{
|
||||
/* Map or unmap the window respectively */
|
||||
if(param == 0)
|
||||
X.UnmapWindow(display, win->xwin);
|
||||
else
|
||||
X.MapWindow(display, win->xwin);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* Turn on/off resizeability */
|
||||
case SSTWS_RESIZEABLE:
|
||||
{
|
||||
/* TODO */
|
||||
break;
|
||||
}
|
||||
|
||||
case SSTWS_FULLSCREEN:
|
||||
{
|
||||
/* If we haven't yet checked for EWMH support, do so now */
|
||||
if(win->owner->ewmhSupport == -1)
|
||||
win->owner->ewmhSupport = ewmh_supported(win->owner, win);
|
||||
|
||||
/* Enabling fullscreen? */
|
||||
if(param && !win->isFullscreen)
|
||||
{
|
||||
|
||||
/* Use EWMH */
|
||||
if(win->owner->ewmhSupport != 0)
|
||||
ewmh_setFullscreen(win, 1);
|
||||
|
||||
win->isFullscreen = True;
|
||||
}
|
||||
else if(win->isFullscreen) /* Disabling fullscreen */
|
||||
{
|
||||
win->isFullscreen = False;
|
||||
|
||||
if(win->owner->ewmhSupport != 0)
|
||||
ewmh_setFullscreen(win, 0);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case SSTWS_MINIMIZED:
|
||||
{
|
||||
if(param == 0) /* Maximize */
|
||||
X.MapRaised(display, win->xwin);
|
||||
else /* Minimize */
|
||||
X.IconifyWindow(display, win->xwin, DefaultScreen(display));
|
||||
break;
|
||||
}
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void Xlib_SetDisplayTargetState(SST_DisplayTarget target, SST_WMDisplayTargetState state, uint32_t param)
|
||||
{
|
||||
SST_DisplayTarget_Xlib* displayTarget = (SST_DisplayTarget_Xlib*)target;
|
||||
switch(state)
|
||||
{
|
||||
case SSTDTS_RELMOUSE:
|
||||
{
|
||||
#ifdef HAVE_XINPUT2
|
||||
XIEventMask eventmask;
|
||||
uint8_t maskBytes[3];
|
||||
|
||||
memset(maskBytes, 0, sizeof(maskBytes));
|
||||
|
||||
eventmask.deviceid = XIAllMasterDevices;
|
||||
eventmask.mask_len = sizeof(maskBytes);
|
||||
eventmask.mask = maskBytes;
|
||||
|
||||
if(!displayTarget->xi2Support)
|
||||
{
|
||||
printf("libsst-wm: XInput2 not supported; cannot use relative mouse mode.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Disabling? */
|
||||
if(displayTarget->relativeMouse && param == 0)
|
||||
{
|
||||
displayTarget->relativeMouse = 0;
|
||||
}
|
||||
else if(!displayTarget->relativeMouse && param != 0) /* Enabling? */
|
||||
{
|
||||
printf("libsst-wm: enabling XI2 raw motion\n");
|
||||
XISetMask(maskBytes, XI_RawMotion); /* Macro invocation */
|
||||
displayTarget->relativeMouse = 1;
|
||||
}
|
||||
|
||||
if(XI.SelectEvents(displayTarget->display, DefaultRootWindow(displayTarget->display), &eventmask, 1) == Success)
|
||||
printf("libsst-wm: relative mouse is %s!\n", param?"ON":"OFF");
|
||||
else
|
||||
printf("libsst-wm: failed to change relative mouse mode - XISelectEvents() returned failure\n");
|
||||
|
||||
#else
|
||||
printf("libsst-wm: XI2 not compiled in, cannot use relative mouse mode.");
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void Xlib_DestroyWindow(SST_Window window)
|
||||
{
|
||||
SST_DisplayTarget_Xlib* displayTarget;
|
||||
SST_Window_Xlib* win = (SST_Window_Xlib*)window;
|
||||
SST_Window_Xlib* nextWin;
|
||||
|
||||
displayTarget = win->owner;
|
||||
nextWin = displayTarget->firstWindow;
|
||||
|
||||
/* Special case: root window */
|
||||
if(nextWin == win)
|
||||
{
|
||||
/* Set new root to be this->next */
|
||||
displayTarget->firstWindow = win->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
int found = 0;
|
||||
|
||||
/* Check list */
|
||||
while(nextWin)
|
||||
{
|
||||
/* Did we find the window? */
|
||||
if(nextWin->next == win)
|
||||
{
|
||||
/* Remove this window from the linked list */
|
||||
nextWin->next = win->next;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
else
|
||||
nextWin = nextWin->next;
|
||||
}
|
||||
|
||||
/* Don't destroy another display target's window */
|
||||
if(!found)
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
/* Actually destroy the window window */
|
||||
destroyWin(win);
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void Xlib_DestroyDisplayTarget(SST_DisplayTarget target)
|
||||
{
|
||||
SST_DisplayTarget_Xlib* displayTarget = (SST_DisplayTarget_Xlib*)target;
|
||||
SST_Window_Xlib* window = displayTarget->firstWindow;
|
||||
|
||||
/* Destroy all windows */
|
||||
while(window)
|
||||
{
|
||||
/* Save the next window */
|
||||
SST_Window_Xlib* next = window->next;
|
||||
|
||||
destroyWin(window);
|
||||
|
||||
/* Move to next window */
|
||||
window = next;
|
||||
}
|
||||
|
||||
DestroyEQ(&displayTarget->userEventQueue);
|
||||
DestroyEQ(&displayTarget->eventQueue);
|
||||
pthread_mutex_destroy(&displayTarget->eventLock);
|
||||
X.CloseDisplay(displayTarget->display);
|
||||
|
||||
/* Free structures */
|
||||
free(displayTarget);
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void destroyWin(SST_Window_Xlib* win)
|
||||
{
|
||||
/* TODO Destroy more */
|
||||
|
||||
X.DestroyWindow(win->owner->display, win->xwin);
|
||||
free(win);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
/* Check if extended window manager hints are supported */
|
||||
static int ewmh_supported(SST_DisplayTarget_Xlib* displayTarget, SST_Window_Xlib* win)
|
||||
{
|
||||
Atom actions;
|
||||
Atom actionFullscreen;
|
||||
Atom actualType;
|
||||
int format;
|
||||
unsigned long nrItems;
|
||||
unsigned long bytesAfterReturn;
|
||||
unsigned long i;
|
||||
Atom* propReturn;
|
||||
int foundit = 0;
|
||||
Display* display = displayTarget->display;
|
||||
|
||||
actions = X.InternAtom(display, "_NET_WM_ALLOWED_ACTIONS", False);
|
||||
actionFullscreen = X.InternAtom(display, "_NET_WM_ACTION_FULLSCREEN", False);
|
||||
|
||||
/* Get a list of atoms */
|
||||
if(X.GetWindowProperty(display, win->xwin, actions, 0, 1024, False, XA_ATOM, &actualType,
|
||||
&format,
|
||||
&nrItems,
|
||||
&bytesAfterReturn,
|
||||
(unsigned char**)&propReturn) != Success)
|
||||
{
|
||||
/* Nope */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Search through the list for the atom that matches the fullscreen atom */
|
||||
for(i=0; i<nrItems; i++)
|
||||
{
|
||||
if(propReturn[i] == actionFullscreen)
|
||||
{
|
||||
foundit = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Free atom list and return */
|
||||
X.Free(propReturn);
|
||||
|
||||
return foundit;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
/* Use extended window manager hints to set the window in/out of fullscreen mode */
|
||||
static void ewmh_setFullscreen(SST_Window_Xlib* win, int fullscreen)
|
||||
{
|
||||
XEvent event;
|
||||
Display* display = win->owner->display;
|
||||
|
||||
event.xclient.type = ClientMessage;
|
||||
event.xclient.serial = 0;
|
||||
event.xclient.send_event = True;
|
||||
event.xclient.display = display;
|
||||
event.xclient.window = win->xwin;
|
||||
event.xclient.message_type = X.InternAtom(display, "_NET_WM_STATE", False);
|
||||
event.xclient.format = 32;
|
||||
event.xclient.data.l[0] = fullscreen;
|
||||
event.xclient.data.l[1] = X.InternAtom(display, "_NET_WM_STATE_FULLSCREEN", False);
|
||||
event.xclient.data.l[2] = 0;
|
||||
event.xclient.data.l[3] = 0;
|
||||
event.xclient.data.l[4] = 0;
|
||||
|
||||
X.SendEvent(display, DefaultRootWindow(display), False, StructureNotifyMask | ResizeRedirectMask, &event);
|
||||
}
|
||||
|
||||
extern int Xlib_ShowDialogBox(SST_DisplayTarget target, SST_Window parent, const char* caption, const char* message, const char** buttons, int nrButtons);
|
||||
|
||||
const struct SST_WM_WindowFuncs Xlib_WindowFuncs = {
|
||||
Xlib_CreateDisplayTarget,
|
||||
Xlib_GetDisplayTargetScreenCount,
|
||||
Xlib_CreateWindowOnScreen,
|
||||
Xlib_GetWindowDisplayTarget,
|
||||
Xlib_SetWindowText,
|
||||
Xlib_GetWindowRect,
|
||||
Xlib_MoveWindowOnScreen,
|
||||
Xlib_ResizeWindow,
|
||||
Xlib_ShowDialogBox,
|
||||
Xlib_SetWindowState,
|
||||
Xlib_SetDisplayTargetState,
|
||||
Xlib_DestroyWindow,
|
||||
Xlib_DestroyDisplayTarget
|
||||
};
|
||||
|
||||
83
libsst-wm/Xlib/XI2Private.c
Normal file
83
libsst-wm/Xlib/XI2Private.c
Normal file
@@ -0,0 +1,83 @@
|
||||
|
||||
#ifdef HAVE_XINPUT2
|
||||
#include <dlfcn.h>
|
||||
#include "XlibPrivate.h"
|
||||
#include "XI2Private.h"
|
||||
|
||||
XI2Functions XI = { 0 };
|
||||
|
||||
void XI2_Load()
|
||||
{
|
||||
const int flags = RTLD_LAZY | RTLD_GLOBAL;
|
||||
void* XI2lib;
|
||||
|
||||
/* Try opening the correct SONAME version of libXi */
|
||||
XI2lib = dlopen("libXi.so.6", flags);
|
||||
|
||||
/* Didn't work? */
|
||||
if(XI2lib == NULL)
|
||||
{
|
||||
/* Try a super-generic version */
|
||||
XI2lib = dlopen("libXi.so", flags);
|
||||
if(XI2lib == NULL)
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
/* Resolve symbols */
|
||||
XI.SelectEvents = dlsym(XI2lib, "XISelectEvents");
|
||||
XI.QueryVersion = dlsym(XI2lib, "XIQueryVersion");
|
||||
|
||||
if(XI.SelectEvents == NULL || XI.QueryVersion == NULL)
|
||||
{
|
||||
dlclose(XI2lib);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Save handle */
|
||||
XI.XI2lib = XI2lib;
|
||||
return;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void XI2_Unload()
|
||||
{
|
||||
if(XI.XI2lib != NULL)
|
||||
dlclose(XI.XI2lib);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
int XI2_IsLoaded()
|
||||
{
|
||||
return (XI.XI2lib != NULL);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void XI2_IsSupportedOnConnection(SST_DisplayTarget_Xlib* displayTarget)
|
||||
{
|
||||
int major = 2, minor = 0;
|
||||
int dummyEvent, dummyError;
|
||||
|
||||
/* Default to NO */
|
||||
displayTarget->xi2Support = 0;
|
||||
displayTarget->xi2opcode = ~0;
|
||||
|
||||
/* Check if server has XI at all. */
|
||||
if(X.QueryExtension(displayTarget->display, "XInputExtension", &displayTarget->xi2opcode, &dummyEvent, &dummyError))
|
||||
{
|
||||
/* OK, does it support XI2? */
|
||||
XI.QueryVersion(displayTarget->display, &major, &minor);
|
||||
|
||||
/* If the version is at least 2.0, we're good */
|
||||
if(major * 100 + minor >= 200) {
|
||||
displayTarget->xi2Support = 1;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
60
libsst-wm/Xlib/XI2Private.h
Normal file
60
libsst-wm/Xlib/XI2Private.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
XI2Private.h
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 5/13/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
Private definitions and functions for XInput2 portion of Xlib driver. XI2 support
|
||||
is optional, but most systems that run a recent version of X will have it.
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
#ifndef _XI2PRIVATE_H
|
||||
#define _XI2PRIVATE_H
|
||||
|
||||
#ifdef HAVE_XINPUT2
|
||||
|
||||
#include <X11/X.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/extensions/XInput2.h>
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
typedef Status (*pf_XISelectEvents)(Display* display, Window win, XIEventMask* masks, int num_masks);
|
||||
typedef Status (*pf_XIQueryVersion)(Display *display, int *major_version_inout, int *minor_version_inout);
|
||||
|
||||
/** Structure describing XInput2 functions used */
|
||||
typedef struct XI2Functions {
|
||||
pf_XISelectEvents SelectEvents;
|
||||
pf_XIQueryVersion QueryVersion;
|
||||
void* XI2lib;
|
||||
} XI2Functions;
|
||||
|
||||
extern XI2Functions XI;
|
||||
|
||||
struct SST_DisplayTarget_Xlib;
|
||||
|
||||
/* Attempt to load XInput2 library */
|
||||
void XI2_Load();
|
||||
|
||||
/* Check if XInput2 library was successfully loaded (X server may not support it though) */
|
||||
int XI2_IsLoaded();
|
||||
|
||||
/* Unload XInput2 library */
|
||||
void XI2_Unload();
|
||||
|
||||
/* Check if the connection to the X server supports XInput2. */
|
||||
void XI2_IsSupportedOnConnection(struct SST_DisplayTarget_Xlib* displayTarget);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
76
libsst-wm/Xlib/XlibDriver.c
Normal file
76
libsst-wm/Xlib/XlibDriver.c
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
XlibDriver.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 5/14/2014
|
||||
|
||||
Purpose:
|
||||
|
||||
Xlib driver for libsst-wm
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#include "APIPrivate.h"
|
||||
#include "XlibPrivate.h"
|
||||
#include "XI2Private.h"
|
||||
#include "GLXPrivate.h"
|
||||
|
||||
extern const struct SST_WM_WindowFuncs Xlib_WindowFuncs;
|
||||
extern const struct SST_WM_EnumFuncs Xlib_EnumFuncs;
|
||||
extern const struct SST_WM_EventFuncs Xlib_EventFuncs;
|
||||
extern const struct SST_WM_OpenGLFuncs Xlib_OpenGLFuncs;
|
||||
extern const struct SST_WM_RenderFuncs Xlib_RenderFuncs;
|
||||
extern const struct SST_WM_VideoModeFuncs Xlib_VideoModeFuncs;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
int Xlib_init()
|
||||
{
|
||||
if(getenv("LIBSST_NO_XLIB"))
|
||||
return 0;
|
||||
|
||||
if(loadXlib() == 0)
|
||||
return 0;
|
||||
|
||||
#ifdef HAVE_XINPUT2
|
||||
XI2_Load(); /* may fail, but that's OK */
|
||||
#endif
|
||||
|
||||
|
||||
loadGLX();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void Xlib_shutdown()
|
||||
{
|
||||
#ifdef HAVE_XINPUT2
|
||||
XI2_Unload();
|
||||
#endif
|
||||
|
||||
unloadGLX();
|
||||
|
||||
unloadXlib();
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const struct SST_WM_Driver XlibDriver = {
|
||||
"Xlib Driver",
|
||||
Xlib_init,
|
||||
Xlib_shutdown,
|
||||
&Xlib_WindowFuncs,
|
||||
&Xlib_EnumFuncs,
|
||||
&Xlib_EventFuncs,
|
||||
&Xlib_OpenGLFuncs,
|
||||
&Xlib_RenderFuncs,
|
||||
&Xlib_VideoModeFuncs
|
||||
};
|
||||
91
libsst-wm/Xlib/XlibPrivate.c
Normal file
91
libsst-wm/Xlib/XlibPrivate.c
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
XlibPrivate.c
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 1/8/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
Private defintions and functions for Xlib implementation of libsst-wm
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#include "XlibPrivate.h"
|
||||
#include <dlfcn.h>
|
||||
|
||||
XlibFunctions X;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
int loadXlib()
|
||||
{
|
||||
const int flags = RTLD_LAZY | RTLD_GLOBAL;
|
||||
void* xlib;
|
||||
|
||||
X.xlib = NULL;
|
||||
|
||||
/* Try opening the correct SONAME version of libX11 */
|
||||
xlib = dlopen("libX11.so.6", flags);
|
||||
|
||||
/* Didn't work? */
|
||||
if(xlib == NULL)
|
||||
{
|
||||
/* Try a super-generic version */
|
||||
xlib = dlopen("libX11.so", flags);
|
||||
if(xlib == NULL)
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/* Resolve symbols */
|
||||
X.OpenDisplay = dlsym(xlib, "XOpenDisplay");
|
||||
X.CloseDisplay = dlsym(xlib, "XCloseDisplay");
|
||||
X.MoveWindow = dlsym(xlib, "XMoveWindow");
|
||||
X.ResizeWindow = dlsym(xlib, "XResizeWindow");
|
||||
X.MapRaised = dlsym(xlib, "XMapRaised");
|
||||
X.MapWindow = dlsym(xlib, "XMapWindow");
|
||||
X.UnmapWindow = dlsym(xlib, "XUnmapWindow");
|
||||
X.StoreName = dlsym(xlib, "XStoreName");
|
||||
X.DestroyWindow = dlsym(xlib, "XDestroyWindow");
|
||||
X.CreateSimpleWindow = dlsym(xlib, "XCreateSimpleWindow");
|
||||
X.GetGeometry = dlsym(xlib, "XGetGeometry");
|
||||
X.GetWindowProperty = dlsym(xlib,"XGetWindowProperty");
|
||||
X.Pending = dlsym(xlib, "XPending");
|
||||
X.NextEvent = dlsym(xlib, "XNextEvent");
|
||||
X.PeekEvent = dlsym(xlib, "XPeekEvent");
|
||||
X.SendEvent = dlsym(xlib, "XSendEvent");
|
||||
X.Flush = dlsym(xlib, "XFlush");
|
||||
X.Sync = dlsym(xlib, "XSync");
|
||||
X.InternAtom = dlsym(xlib, "XInternAtom");
|
||||
X.SetWMProtocols = dlsym(xlib, "XSetWMProtocols");
|
||||
X.IconifyWindow = dlsym(xlib, "XIconifyWindow");
|
||||
X.Free = dlsym(xlib, "XFree");
|
||||
X.SelectInput = dlsym(xlib, "XSelectInput");
|
||||
X.LookupString = dlsym(xlib, "XLookupString");
|
||||
X.QueryKeymap = dlsym(xlib, "XQueryKeymap");
|
||||
X.QueryExtension = dlsym(xlib, "XQueryExtension");
|
||||
X.GetEventData = dlsym(xlib, "XGetEventData");
|
||||
X.FreeEventData = dlsym(xlib, "XFreeEventData");
|
||||
|
||||
|
||||
/* Save handle */
|
||||
X.xlib = xlib;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void unloadXlib()
|
||||
{
|
||||
if(X.xlib != NULL)
|
||||
dlclose(X.xlib);
|
||||
}
|
||||
|
||||
186
libsst-wm/Xlib/XlibPrivate.h
Normal file
186
libsst-wm/Xlib/XlibPrivate.h
Normal file
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
XlibPrivate.h
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 1/8/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
|
||||
|
||||
License:
|
||||
|
||||
This program is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What The Fuck You Want
|
||||
To Public License, Version 2, as published by Sam Hocevar. See
|
||||
http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef _XLIBPRIVATE_H
|
||||
#define _XLIBPRIVATE_H
|
||||
|
||||
#include <X11/X.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xproto.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/keysym.h>
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include <SST/SST_WMTypes.h>
|
||||
#include "EventQueue.h"
|
||||
#include "GLXPrivate.h"
|
||||
#include "XI2Private.h"
|
||||
|
||||
#define MIN_BPP 16 /* Minimum BPP for a mode to be considered. Some embedded systems use 16-bit color to save memory, so accept those too. */
|
||||
|
||||
/* XGenericEventCookie is required for XI2, but not present on Solaris 10, so fake it*/
|
||||
#if defined(__sun) && !defined(HAVE_XINPUT2)
|
||||
typedef void XGenericEventCookie;
|
||||
#endif
|
||||
|
||||
/* Xlib C API */
|
||||
typedef Display* (*pf_XOpenDisplay)(const char* s);
|
||||
typedef void (*pf_XCloseDisplay)(Display* dpy);
|
||||
typedef int (*pf_XMoveWindow)(Display* dpy, Window w, int x, int y);
|
||||
typedef int (*pf_XResizeWindow)(Display* dpy, Window w, unsigned int x, unsigned int y);
|
||||
typedef int (*pf_XMapRaised)(Display* dpy, Window w);
|
||||
typedef int (*pf_XMapWindow)(Display* dpy, Window w);
|
||||
typedef int (*pf_XUnmapWindow)(Display* dpy, Window w);
|
||||
typedef int (*pf_XStoreName)(Display* dpy, Window w, const char* windowName);
|
||||
typedef int (*pf_XDestroyWindow)(Display* dpy, Window w);
|
||||
typedef Window (*pf_XCreateSimpleWindow)(Display*, Window parent, int x, int y, unsigned int w, unsigned int h, unsigned int borderWidth, unsigned long border, unsigned long background);
|
||||
typedef Status (*pf_XGetGeometry)(Display* display, Drawable d, Window* root_return, int* x_return, int* y_return, unsigned int* width_return, unsigned int* height_return, unsigned int* border_width_return, unsigned int* depth_return);
|
||||
typedef int (*pf_XGetWindowProperty)(Display *display, Window w, Atom property, long long_offset, long long_length, Bool _delete, Atom req_type, Atom* actual_type_return, int* actual_format_return, unsigned long* nitems_return, unsigned long* bytes_after_return, unsigned char** prop_return);
|
||||
typedef int (*pf_XPending)(Display* display);
|
||||
typedef int (*pf_XNextEvent)(Display* display, XEvent* event_return);
|
||||
typedef int (*pf_XPeekEvent)(Display* display, XEvent* event_return);
|
||||
typedef Status (*pf_XSendEvent)(Display *display, Window w, Bool propagate, long event_mask, XEvent *event_send);
|
||||
typedef int (*pf_XFlush)(Display* display);
|
||||
typedef int (*pf_XSync)(Display* display, Bool discard);
|
||||
typedef Atom (*pf_XInternAtom)(Display* display, const char* name, Bool create);
|
||||
typedef Status (*pf_XSetWMProtocols)(Display* display, Window w, Atom* protocols, int count);
|
||||
typedef Status (*pf_XIconifyWindow)(Display* display, Window w, int screen_number);
|
||||
typedef void (*pf_XFree)(void*);
|
||||
typedef int (*pf_XSelectInput)(Display* display, Window w, long event_mask);
|
||||
typedef int (*pf_XLookupString)(XKeyEvent* event_struct, char* buffer_return, int bytes_buffer, KeySym* keysym_return, XComposeStatus* status_in_out);
|
||||
typedef int (*pf_XQueryKeymap)(Display *display, char keys_return[32]);
|
||||
typedef Bool (*pf_XQueryExtension)(Display* display, const char* name, int* major_opcode_return, int* first_event_return, int* first_error_return);
|
||||
typedef Bool (*pf_XGetEventData)(Display *display, XGenericEventCookie *cookie);
|
||||
typedef void (*pf_XFreeEventData)(Display *display, XGenericEventCookie *cookie);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
typedef struct XlibFunctions
|
||||
{
|
||||
pf_XOpenDisplay OpenDisplay;
|
||||
pf_XCloseDisplay CloseDisplay;
|
||||
pf_XMoveWindow MoveWindow;
|
||||
pf_XResizeWindow ResizeWindow;
|
||||
pf_XMapRaised MapRaised;
|
||||
pf_XMapWindow MapWindow;
|
||||
pf_XUnmapWindow UnmapWindow;
|
||||
pf_XStoreName StoreName;
|
||||
pf_XDestroyWindow DestroyWindow;
|
||||
pf_XCreateSimpleWindow CreateSimpleWindow;
|
||||
pf_XGetGeometry GetGeometry;
|
||||
pf_XGetWindowProperty GetWindowProperty;
|
||||
pf_XPending Pending;
|
||||
pf_XNextEvent NextEvent;
|
||||
pf_XPeekEvent PeekEvent;
|
||||
pf_XSendEvent SendEvent;
|
||||
pf_XFlush Flush;
|
||||
pf_XSync Sync;
|
||||
pf_XInternAtom InternAtom;
|
||||
pf_XSetWMProtocols SetWMProtocols;
|
||||
pf_XIconifyWindow IconifyWindow;
|
||||
pf_XFree Free;
|
||||
pf_XSelectInput SelectInput;
|
||||
pf_XLookupString LookupString;
|
||||
pf_XQueryKeymap QueryKeymap;
|
||||
pf_XQueryExtension QueryExtension;
|
||||
pf_XGetEventData GetEventData;
|
||||
pf_XFreeEventData FreeEventData;
|
||||
|
||||
void* xlib;
|
||||
} XlibFunctions;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
typedef struct SST_GraphicsEnumerator_Xlib
|
||||
{
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint32_t bpp;
|
||||
} SST_GraphicsEnumerator_Xlib;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
struct SST_Window_Xlib;
|
||||
|
||||
typedef struct SST_DisplayTarget_Xlib
|
||||
{
|
||||
EventQueue eventQueue;
|
||||
uint8_t keymapBitvector[32]; /* Bitmap similar to XQueryKeymap() */
|
||||
pthread_mutex_t eventLock; /* Lock protecting user events, since they may be freely added by other threads */
|
||||
EventQueue userEventQueue;
|
||||
Display* display;
|
||||
struct SST_Window_Xlib* firstWindow;
|
||||
int relativeMouse; /* Is relative mouse move enabled? */
|
||||
int ewmhSupport; /* Extended WM Hints, -1: not checked, 0: not supported, else: supported */
|
||||
int xi2Support; /* XInput2 support, -1: not checked, 0: not supported, else: supported */
|
||||
int xi2opcode; /* XI2 opcode */
|
||||
Atom atomWmProtocols;
|
||||
Atom atomWmDeleteWindow;
|
||||
} SST_DisplayTarget_Xlib;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
typedef struct SST_Window_Xlib
|
||||
{
|
||||
struct SST_Window_Xlib* next;
|
||||
SST_DisplayTarget_Xlib* owner;
|
||||
Window xwin;
|
||||
int isFullscreen;
|
||||
|
||||
/* Because configure requests cover a wide variety of events,
|
||||
keep these "last" parameters to check if an event actually occured */
|
||||
int lastX, lastY;
|
||||
int lastWidth, lastHeight;
|
||||
|
||||
/* Software rendering support */
|
||||
XImage* softwareImage;
|
||||
void* softwareBackbuffer;
|
||||
uint32_t softwarePitch;
|
||||
} SST_Window_Xlib;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
typedef struct SST_OpenGLContext_Xlib
|
||||
{
|
||||
SST_DisplayTarget_Xlib* displayTarget;
|
||||
uint16_t ctxVersion[2]; /* context version major/minor */
|
||||
|
||||
|
||||
/* GLX Fields */
|
||||
int legacyEnabled; /* Did we use legacy GLX (< 1.4) context support? */
|
||||
GLXContext glxcontext;
|
||||
GLXFunctions glX;
|
||||
Window win; /* Window context is bound to */
|
||||
|
||||
/* EGL fields */
|
||||
|
||||
} SST_OpenGLContext_Xlib;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
extern XlibFunctions X;
|
||||
|
||||
int loadXlib();
|
||||
void unloadXlib();
|
||||
|
||||
#endif
|
||||
32
libsst-wm/Xlib/sources.mk
Normal file
32
libsst-wm/Xlib/sources.mk
Normal file
@@ -0,0 +1,32 @@
|
||||
# libsst-wm/Xlib/sources.mk
|
||||
# Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
# Created: 1/8/2013
|
||||
#
|
||||
# Purpose:
|
||||
#
|
||||
# List of source files for X Windows systems
|
||||
#
|
||||
# License:
|
||||
#
|
||||
# This program is free software. It comes without any warranty, to
|
||||
# the extent permitted by applicable law. You can redistribute it
|
||||
# and/or modify it under the terms of the Do What The Fuck You Want
|
||||
# To Public License, Version 2, as published by Sam Hocevar. See
|
||||
# http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
ifeq ($(findstring -DHAVE_XLIB,$(CFLAGS)),-DHAVE_XLIB)
|
||||
SRC += \
|
||||
Xlib/SST_WMDialogBox_Xlib.c \
|
||||
Xlib/SST_WMEnum_Xlib.c \
|
||||
Xlib/SST_WMEvent_Xlib.c \
|
||||
Xlib/SST_WMOpenGL_Xlib.c \
|
||||
Xlib/SST_WMNonPortable_Xlib.c \
|
||||
Xlib/SST_WMVideoMode_Xlib.c \
|
||||
Xlib/SST_WMRender_Xlib.c \
|
||||
Xlib/SST_WMWindow_Xlib.c \
|
||||
Xlib/XlibPrivate.c \
|
||||
Xlib/GLXPrivate.c \
|
||||
Xlib/XI2Private.c \
|
||||
Xlib/XlibDriver.c
|
||||
|
||||
endif
|
||||
208
libsst-wm/libsst-wm.vcxproj
Normal file
208
libsst-wm/libsst-wm.vcxproj
Normal file
@@ -0,0 +1,208 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{D5B4F387-30FB-449A-B777-356D0398C701}</ProjectGuid>
|
||||
<RootNamespace>libsstwm</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<PlatformToolset>v110</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<PlatformToolset>v110</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<PlatformToolset>v110</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<PlatformToolset>v110</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<_ProjectFileVersion>11.0.50727.1</_ProjectFileVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<OutDir>$(SolutionDir)\Lib\x86\</OutDir>
|
||||
<IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir>
|
||||
<TargetName>$(ProjectName)-debug</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<OutDir>$(SolutionDir)\Lib\x86\</OutDir>
|
||||
<IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<OutDir>$(SolutionDir)\Lib\x64\</OutDir>
|
||||
<IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir>
|
||||
<TargetName>$(ProjectName)-debug</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<OutDir>$(SolutionDir)\Lib\x64\</OutDir>
|
||||
<IntDir>$(SolutionDir)Intermediate\$(Configuration)\$(Platform)\$(ProjectName)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)Lib\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<CreateHotpatchableImage>false</CreateHotpatchableImage>
|
||||
<StringPooling>true</StringPooling>
|
||||
<ExceptionHandling>false</ExceptionHandling>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</ClCompile>
|
||||
<Lib />
|
||||
<Lib>
|
||||
<LinkTimeCodeGeneration>true</LinkTimeCodeGeneration>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)Lib\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<CreateHotpatchableImage>false</CreateHotpatchableImage>
|
||||
<StringPooling>true</StringPooling>
|
||||
<ExceptionHandling>false</ExceptionHandling>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Midl>
|
||||
<TargetEnvironment>X64</TargetEnvironment>
|
||||
</Midl>
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)Lib\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<CreateHotpatchableImage>false</CreateHotpatchableImage>
|
||||
<StringPooling>true</StringPooling>
|
||||
<ExceptionHandling>false</ExceptionHandling>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</ClCompile>
|
||||
<Lib />
|
||||
<Lib>
|
||||
<LinkTimeCodeGeneration>true</LinkTimeCodeGeneration>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Midl>
|
||||
<TargetEnvironment>X64</TargetEnvironment>
|
||||
</Midl>
|
||||
<ClCompile>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)Lib\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<CreateHotpatchableImage>false</CreateHotpatchableImage>
|
||||
<StringPooling>true</StringPooling>
|
||||
<ExceptionHandling>false</ExceptionHandling>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\Lib\Include\SST\SST_WM.h" />
|
||||
<ClInclude Include="..\Lib\Include\SST\SST_WMEnum.h" />
|
||||
<ClInclude Include="..\Lib\Include\SST\SST_WMEvent.h" />
|
||||
<ClInclude Include="..\Lib\Include\SST\SST_WMKeys.h" />
|
||||
<ClInclude Include="..\Lib\Include\SST\SST_WMNonPortable.h" />
|
||||
<ClInclude Include="..\Lib\Include\SST\SST_WMOpenGL.h" />
|
||||
<ClInclude Include="..\Lib\Include\SST\SST_WMRender.h" />
|
||||
<ClInclude Include="..\Lib\Include\SST\SST_WMTypes.h" />
|
||||
<ClInclude Include="..\Lib\Include\SST\SST_WMVideoMode.h" />
|
||||
<ClInclude Include="..\Lib\Include\SST\SST_WMWindow.h" />
|
||||
<ClInclude Include="APIPrivate.h" />
|
||||
<ClInclude Include="EventQueue.h" />
|
||||
<ClInclude Include="Win32\Win32Private.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="API.c" />
|
||||
<ClCompile Include="Win32\SST_WMDialogBox_Win32.c" />
|
||||
<ClCompile Include="Win32\SST_WMEnum_Win32.c" />
|
||||
<ClCompile Include="Win32\SST_WMEvent_Win32.c" />
|
||||
<ClCompile Include="Win32\SST_WMNonPortable_Win32.c" />
|
||||
<ClCompile Include="Win32\SST_WMOpenGL_Win32.c" />
|
||||
<ClCompile Include="Win32\SST_WMRender_Win32.c" />
|
||||
<ClCompile Include="Win32\SST_WMVideoMode_Win32.c" />
|
||||
<ClCompile Include="Win32\SST_WMWindow_Win32.c" />
|
||||
<ClCompile Include="Win32\Win32Driver.c" />
|
||||
<ClCompile Include="Win32\Win32Private.c" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
92
libsst-wm/libsst-wm.vcxproj.filters
Normal file
92
libsst-wm/libsst-wm.vcxproj.filters
Normal file
@@ -0,0 +1,92 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\Win32">
|
||||
<UniqueIdentifier>{5e667c79-5dd8-45f6-a16c-800453e72a33}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\Lib\Include\SST\SST_WM.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Lib\Include\SST\SST_WMEnum.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Lib\Include\SST\SST_WMEvent.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Lib\Include\SST\SST_WMKeys.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Lib\Include\SST\SST_WMNonPortable.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Lib\Include\SST\SST_WMOpenGL.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Lib\Include\SST\SST_WMRender.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Lib\Include\SST\SST_WMTypes.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Lib\Include\SST\SST_WMVideoMode.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Lib\Include\SST\SST_WMWindow.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="APIPrivate.h">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="EventQueue.h">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Win32\Win32Private.h">
|
||||
<Filter>Source Files\Win32</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="API.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Win32\SST_WMDialogBox_Win32.c">
|
||||
<Filter>Source Files\Win32</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Win32\SST_WMEnum_Win32.c">
|
||||
<Filter>Source Files\Win32</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Win32\SST_WMEvent_Win32.c">
|
||||
<Filter>Source Files\Win32</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Win32\SST_WMNonPortable_Win32.c">
|
||||
<Filter>Source Files\Win32</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Win32\SST_WMOpenGL_Win32.c">
|
||||
<Filter>Source Files\Win32</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Win32\SST_WMRender_Win32.c">
|
||||
<Filter>Source Files\Win32</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Win32\SST_WMVideoMode_Win32.c">
|
||||
<Filter>Source Files\Win32</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Win32\SST_WMWindow_Win32.c">
|
||||
<Filter>Source Files\Win32</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Win32\Win32Private.c">
|
||||
<Filter>Source Files\Win32</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Win32\Win32Driver.c">
|
||||
<Filter>Source Files\Win32</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
BIN
libsst-wm/obj/x86-64/release/API.o
Normal file
BIN
libsst-wm/obj/x86-64/release/API.o
Normal file
Binary file not shown.
BIN
libsst-wm/obj/x86-64/release/Xlib/GLXPrivate.o
Normal file
BIN
libsst-wm/obj/x86-64/release/Xlib/GLXPrivate.o
Normal file
Binary file not shown.
BIN
libsst-wm/obj/x86-64/release/Xlib/SST_WMDialogBox_Xlib.o
Normal file
BIN
libsst-wm/obj/x86-64/release/Xlib/SST_WMDialogBox_Xlib.o
Normal file
Binary file not shown.
BIN
libsst-wm/obj/x86-64/release/Xlib/SST_WMEnum_Xlib.o
Normal file
BIN
libsst-wm/obj/x86-64/release/Xlib/SST_WMEnum_Xlib.o
Normal file
Binary file not shown.
BIN
libsst-wm/obj/x86-64/release/Xlib/SST_WMEvent_Xlib.o
Normal file
BIN
libsst-wm/obj/x86-64/release/Xlib/SST_WMEvent_Xlib.o
Normal file
Binary file not shown.
BIN
libsst-wm/obj/x86-64/release/Xlib/SST_WMNonPortable_Xlib.o
Normal file
BIN
libsst-wm/obj/x86-64/release/Xlib/SST_WMNonPortable_Xlib.o
Normal file
Binary file not shown.
BIN
libsst-wm/obj/x86-64/release/Xlib/SST_WMOpenGL_Xlib.o
Normal file
BIN
libsst-wm/obj/x86-64/release/Xlib/SST_WMOpenGL_Xlib.o
Normal file
Binary file not shown.
BIN
libsst-wm/obj/x86-64/release/Xlib/SST_WMRender_Xlib.o
Normal file
BIN
libsst-wm/obj/x86-64/release/Xlib/SST_WMRender_Xlib.o
Normal file
Binary file not shown.
BIN
libsst-wm/obj/x86-64/release/Xlib/SST_WMVideoMode_Xlib.o
Normal file
BIN
libsst-wm/obj/x86-64/release/Xlib/SST_WMVideoMode_Xlib.o
Normal file
Binary file not shown.
BIN
libsst-wm/obj/x86-64/release/Xlib/SST_WMWindow_Xlib.o
Normal file
BIN
libsst-wm/obj/x86-64/release/Xlib/SST_WMWindow_Xlib.o
Normal file
Binary file not shown.
BIN
libsst-wm/obj/x86-64/release/Xlib/XI2Private.o
Normal file
BIN
libsst-wm/obj/x86-64/release/Xlib/XI2Private.o
Normal file
Binary file not shown.
BIN
libsst-wm/obj/x86-64/release/Xlib/XlibDriver.o
Normal file
BIN
libsst-wm/obj/x86-64/release/Xlib/XlibDriver.o
Normal file
Binary file not shown.
BIN
libsst-wm/obj/x86-64/release/Xlib/XlibPrivate.o
Normal file
BIN
libsst-wm/obj/x86-64/release/Xlib/XlibPrivate.o
Normal file
Binary file not shown.
26
libsst-wm/sources-MacOSX.mk
Normal file
26
libsst-wm/sources-MacOSX.mk
Normal file
@@ -0,0 +1,26 @@
|
||||
# libsst-wm/sources-Darwin.mk
|
||||
# Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
# Created: 11/27/2012
|
||||
#
|
||||
# Purpose:
|
||||
#
|
||||
# List of source files for MacOS X systems
|
||||
#
|
||||
# License:
|
||||
#
|
||||
# This program is free software. It comes without any warranty, to
|
||||
# the extent permitted by applicable law. You can redistribute it
|
||||
# and/or modify it under the terms of the Do What The Fuck You Want
|
||||
# To Public License, Version 2, as published by Sam Hocevar. See
|
||||
# http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
SRC := \
|
||||
SST_WMEnum_MacOSX.m #\
|
||||
#SST_WMEvent_Win32.c \
|
||||
#SST_WMNonPortable_Win32.c \
|
||||
#SST_WMOpenGL_Win32.c \
|
||||
#SST_WMRender_Win32.c \
|
||||
#SST_WMVideoMode_Win32.c \
|
||||
#SST_WMWindow_Win32.c \
|
||||
#Win32Private.c
|
||||
|
||||
24
libsst-wm/sources-RaspPi.mk
Normal file
24
libsst-wm/sources-RaspPi.mk
Normal file
@@ -0,0 +1,24 @@
|
||||
# libsst-wm/sources-RaspPi.mk
|
||||
# Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
# Created: 6/12/2013
|
||||
#
|
||||
# Purpose:
|
||||
#
|
||||
# List of source files for Raspberry Pi native port
|
||||
#
|
||||
# License:
|
||||
#
|
||||
# This program is free software. It comes without any warranty, to
|
||||
# the extent permitted by applicable law. You can redistribute it
|
||||
# and/or modify it under the terms of the Do What The Fuck You Want
|
||||
# To Public License, Version 2, as published by Sam Hocevar. See
|
||||
# http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
SRC := \
|
||||
SST_WMDialogBox_RaspPi.c \
|
||||
SST_WMEnum_RaspPi.c \
|
||||
SST_WMEvent_RaspPi.c \
|
||||
SST_WMRender_RaspPi.c \
|
||||
SST_WMWindow_RaspPi.c \
|
||||
SST_WMVideoMode_RaspPi.c
|
||||
|
||||
26
libsst-wm/sources-Win32.mk
Normal file
26
libsst-wm/sources-Win32.mk
Normal file
@@ -0,0 +1,26 @@
|
||||
# libsst-wm/sources-Win32.mk
|
||||
# Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
# Created: 11/16/2012
|
||||
#
|
||||
# Purpose:
|
||||
#
|
||||
# List of source files for Win32 systems
|
||||
#
|
||||
# License:
|
||||
#
|
||||
# This program is free software. It comes without any warranty, to
|
||||
# the extent permitted by applicable law. You can redistribute it
|
||||
# and/or modify it under the terms of the Do What The Fuck You Want
|
||||
# To Public License, Version 2, as published by Sam Hocevar. See
|
||||
# http://sam.zoy.org/wtfpl/COPYING for more details.
|
||||
|
||||
SRC := \
|
||||
SST_WMEnum_Win32.c \
|
||||
SST_WMEvent_Win32.c \
|
||||
SST_WMNonPortable_Win32.c \
|
||||
SST_WMOpenGL_Win32.c \
|
||||
SST_WMRender_Win32.c \
|
||||
SST_WMVideoMode_Win32.c \
|
||||
SST_WMWindow_Win32.c \
|
||||
Win32Private.c
|
||||
|
||||
Reference in New Issue
Block a user