Initial commit

This commit is contained in:
2026-04-03 00:22:39 -05:00
commit eca1e8c458
945 changed files with 218160 additions and 0 deletions

282
libsst-wm/API.c Normal file
View 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
View 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
View 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

View 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

View 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
View 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

View 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

View 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;
}

View 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;
}

View 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);
}

View 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);
}

View 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;
}

View 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);
}
/******************************************************************************/

View 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, &centerOn);
}
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;
}

View 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
};

View 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
};

View 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;
}

View 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(&copyFrom->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
};

View 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
};

View 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
};

View 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(&regRefCount) == 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(&regRefCount) == 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
};

View 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
};

File diff suppressed because it is too large Load Diff

View 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
View 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;
}

View 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

View 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;
}

View 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
};

View 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
};

View 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;
}

View 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
};

View 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
};

View 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
};

View 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
};

View 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

View 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

View 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
};

View 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);
}

View 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
View 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
View 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>

View 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>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View 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

View 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

View 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