Files
libsst/libsst-wm/RaspPi/SST_WMWindow_RaspPi.c
2026-04-03 00:22:39 -05:00

391 lines
8.9 KiB
C

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