From 7fe60435bce6595a9c58a9bfd8244d74b5320e96 Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Tue, 15 Jan 2013 08:46:13 +0100 Subject: Import DirectFB141_2k11R3_beta5 --- Source/DirectFB/src/core/Makefile.am | 84 + Source/DirectFB/src/core/Makefile.in | 648 +++++ Source/DirectFB/src/core/clipboard.c | 298 +++ Source/DirectFB/src/core/clipboard.h | 53 + Source/DirectFB/src/core/colorhash.c | 366 +++ Source/DirectFB/src/core/colorhash.h | 54 + Source/DirectFB/src/core/core.c | 1160 +++++++++ Source/DirectFB/src/core/core.h | 162 ++ Source/DirectFB/src/core/core_parts.c | 202 ++ Source/DirectFB/src/core/core_parts.h | 131 + Source/DirectFB/src/core/core_system.h | 141 ++ Source/DirectFB/src/core/coredefs.h | 48 + Source/DirectFB/src/core/coretypes.h | 89 + Source/DirectFB/src/core/fonts.c | 660 +++++ Source/DirectFB/src/core/fonts.h | 250 ++ Source/DirectFB/src/core/gfxcard.c | 2921 ++++++++++++++++++++++ Source/DirectFB/src/core/gfxcard.h | 470 ++++ Source/DirectFB/src/core/graphics_driver.h | 86 + Source/DirectFB/src/core/input.c | 2668 ++++++++++++++++++++ Source/DirectFB/src/core/input.h | 203 ++ Source/DirectFB/src/core/input_driver.h | 103 + Source/DirectFB/src/core/layer_context.c | 1947 ++++++++++++++ Source/DirectFB/src/core/layer_context.h | 149 ++ Source/DirectFB/src/core/layer_control.c | 589 +++++ Source/DirectFB/src/core/layer_control.h | 72 + Source/DirectFB/src/core/layer_region.c | 1129 +++++++++ Source/DirectFB/src/core/layer_region.h | 100 + Source/DirectFB/src/core/layers.c | 640 +++++ Source/DirectFB/src/core/layers.h | 359 +++ Source/DirectFB/src/core/layers_internal.h | 196 ++ Source/DirectFB/src/core/local_surface_pool.c | 313 +++ Source/DirectFB/src/core/palette.c | 317 +++ Source/DirectFB/src/core/palette.h | 106 + Source/DirectFB/src/core/prealloc_surface_pool.c | 192 ++ Source/DirectFB/src/core/screen.c | 540 ++++ Source/DirectFB/src/core/screen.h | 122 + Source/DirectFB/src/core/screens.c | 591 +++++ Source/DirectFB/src/core/screens.h | 263 ++ Source/DirectFB/src/core/screens_internal.h | 81 + Source/DirectFB/src/core/shared_surface_pool.c | 227 ++ Source/DirectFB/src/core/state.c | 416 +++ Source/DirectFB/src/core/state.h | 362 +++ Source/DirectFB/src/core/surface.c | 768 ++++++ Source/DirectFB/src/core/surface.h | 446 ++++ Source/DirectFB/src/core/surface_buffer.c | 1206 +++++++++ Source/DirectFB/src/core/surface_buffer.h | 257 ++ Source/DirectFB/src/core/surface_core.c | 214 ++ Source/DirectFB/src/core/surface_pool.c | 1263 ++++++++++ Source/DirectFB/src/core/surface_pool.h | 272 ++ Source/DirectFB/src/core/surface_pool_bridge.c | 531 ++++ Source/DirectFB/src/core/surface_pool_bridge.h | 187 ++ Source/DirectFB/src/core/system.c | 464 ++++ Source/DirectFB/src/core/system.h | 258 ++ Source/DirectFB/src/core/windows.c | 1908 ++++++++++++++ Source/DirectFB/src/core/windows.h | 316 +++ Source/DirectFB/src/core/windows_internal.h | 211 ++ Source/DirectFB/src/core/windowstack.c | 998 ++++++++ Source/DirectFB/src/core/windowstack.h | 105 + Source/DirectFB/src/core/wm.c | 1440 +++++++++++ Source/DirectFB/src/core/wm.h | 468 ++++ Source/DirectFB/src/core/wm_module.h | 274 ++ 61 files changed, 31094 insertions(+) create mode 100755 Source/DirectFB/src/core/Makefile.am create mode 100755 Source/DirectFB/src/core/Makefile.in create mode 100755 Source/DirectFB/src/core/clipboard.c create mode 100755 Source/DirectFB/src/core/clipboard.h create mode 100755 Source/DirectFB/src/core/colorhash.c create mode 100755 Source/DirectFB/src/core/colorhash.h create mode 100755 Source/DirectFB/src/core/core.c create mode 100755 Source/DirectFB/src/core/core.h create mode 100755 Source/DirectFB/src/core/core_parts.c create mode 100755 Source/DirectFB/src/core/core_parts.h create mode 100755 Source/DirectFB/src/core/core_system.h create mode 100755 Source/DirectFB/src/core/coredefs.h create mode 100755 Source/DirectFB/src/core/coretypes.h create mode 100755 Source/DirectFB/src/core/fonts.c create mode 100755 Source/DirectFB/src/core/fonts.h create mode 100755 Source/DirectFB/src/core/gfxcard.c create mode 100755 Source/DirectFB/src/core/gfxcard.h create mode 100755 Source/DirectFB/src/core/graphics_driver.h create mode 100755 Source/DirectFB/src/core/input.c create mode 100755 Source/DirectFB/src/core/input.h create mode 100755 Source/DirectFB/src/core/input_driver.h create mode 100755 Source/DirectFB/src/core/layer_context.c create mode 100755 Source/DirectFB/src/core/layer_context.h create mode 100755 Source/DirectFB/src/core/layer_control.c create mode 100755 Source/DirectFB/src/core/layer_control.h create mode 100755 Source/DirectFB/src/core/layer_region.c create mode 100755 Source/DirectFB/src/core/layer_region.h create mode 100755 Source/DirectFB/src/core/layers.c create mode 100755 Source/DirectFB/src/core/layers.h create mode 100755 Source/DirectFB/src/core/layers_internal.h create mode 100755 Source/DirectFB/src/core/local_surface_pool.c create mode 100755 Source/DirectFB/src/core/palette.c create mode 100755 Source/DirectFB/src/core/palette.h create mode 100755 Source/DirectFB/src/core/prealloc_surface_pool.c create mode 100755 Source/DirectFB/src/core/screen.c create mode 100755 Source/DirectFB/src/core/screen.h create mode 100755 Source/DirectFB/src/core/screens.c create mode 100755 Source/DirectFB/src/core/screens.h create mode 100755 Source/DirectFB/src/core/screens_internal.h create mode 100755 Source/DirectFB/src/core/shared_surface_pool.c create mode 100755 Source/DirectFB/src/core/state.c create mode 100755 Source/DirectFB/src/core/state.h create mode 100755 Source/DirectFB/src/core/surface.c create mode 100755 Source/DirectFB/src/core/surface.h create mode 100755 Source/DirectFB/src/core/surface_buffer.c create mode 100755 Source/DirectFB/src/core/surface_buffer.h create mode 100755 Source/DirectFB/src/core/surface_core.c create mode 100755 Source/DirectFB/src/core/surface_pool.c create mode 100755 Source/DirectFB/src/core/surface_pool.h create mode 100755 Source/DirectFB/src/core/surface_pool_bridge.c create mode 100755 Source/DirectFB/src/core/surface_pool_bridge.h create mode 100755 Source/DirectFB/src/core/system.c create mode 100755 Source/DirectFB/src/core/system.h create mode 100755 Source/DirectFB/src/core/windows.c create mode 100755 Source/DirectFB/src/core/windows.h create mode 100755 Source/DirectFB/src/core/windows_internal.h create mode 100755 Source/DirectFB/src/core/windowstack.c create mode 100755 Source/DirectFB/src/core/windowstack.h create mode 100755 Source/DirectFB/src/core/wm.c create mode 100755 Source/DirectFB/src/core/wm.h create mode 100755 Source/DirectFB/src/core/wm_module.h (limited to 'Source/DirectFB/src/core') diff --git a/Source/DirectFB/src/core/Makefile.am b/Source/DirectFB/src/core/Makefile.am new file mode 100755 index 0000000..e387345 --- /dev/null +++ b/Source/DirectFB/src/core/Makefile.am @@ -0,0 +1,84 @@ +## Makefile.am for DirectFB/src/core + +INCLUDES = \ + -I$(top_builddir)/include \ + -I$(top_builddir)/lib \ + -I$(top_srcdir)/include \ + -I$(top_srcdir)/lib \ + -I$(top_srcdir)/src + +AM_CPPFLAGS = \ + -DDATADIR=\"${RUNTIME_SYSROOT}@DATADIR@\" \ + -DSOPATH=\"@SOPATH@\" \ + -DMODULEDIR=\"${RUNTIME_SYSROOT}@MODULEDIR@\" \ + "-DBUILDTIME=\"`date -u "+%Y-%m-%d %H:%M"`\"" + + +internalincludedir = $(INTERNALINCLUDEDIR)/core + +internalinclude_HEADERS = \ + clipboard.h \ + colorhash.h \ + coredefs.h \ + coretypes.h \ + core_parts.h \ + core_system.h \ + core.h \ + fonts.h \ + gfxcard.h \ + graphics_driver.h \ + input.h \ + input_driver.h \ + layer_context.h \ + layer_control.h \ + layer_region.h \ + layers.h \ + layers_internal.h \ + palette.h \ + screen.h \ + screens.h \ + screens_internal.h \ + state.h \ + surface.h \ + surface_buffer.h \ + surface_pool.h \ + surface_pool_bridge.h \ + system.h \ + windows.h \ + windows_internal.h \ + windowstack.h \ + wm.h \ + wm_module.h + + +noinst_LTLIBRARIES = libdirectfb_core.la + + +libdirectfb_core_la_SOURCES = \ + clipboard.c \ + colorhash.c \ + core.c \ + core_parts.c \ + fonts.c \ + gfxcard.c \ + input.c \ + layer_context.c \ + layer_control.c \ + layer_region.c \ + layers.c \ + local_surface_pool.c \ + palette.c \ + prealloc_surface_pool.c \ + screen.c \ + screens.c \ + shared_surface_pool.c \ + state.c \ + surface.c \ + surface_buffer.c \ + surface_core.c \ + surface_pool.c \ + surface_pool_bridge.c \ + system.c \ + windows.c \ + windowstack.c \ + wm.c diff --git a/Source/DirectFB/src/core/Makefile.in b/Source/DirectFB/src/core/Makefile.in new file mode 100755 index 0000000..9955d0b --- /dev/null +++ b/Source/DirectFB/src/core/Makefile.in @@ -0,0 +1,648 @@ +# Makefile.in generated by automake 1.10.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +subdir = src/core +DIST_COMMON = $(internalinclude_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/as-ac-expand.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +libdirectfb_core_la_LIBADD = +am_libdirectfb_core_la_OBJECTS = clipboard.lo colorhash.lo core.lo \ + core_parts.lo fonts.lo gfxcard.lo input.lo layer_context.lo \ + layer_control.lo layer_region.lo layers.lo \ + local_surface_pool.lo palette.lo prealloc_surface_pool.lo \ + screen.lo screens.lo shared_surface_pool.lo state.lo \ + surface.lo surface_buffer.lo surface_core.lo surface_pool.lo \ + surface_pool_bridge.lo system.lo windows.lo windowstack.lo \ + wm.lo +libdirectfb_core_la_OBJECTS = $(am_libdirectfb_core_la_OBJECTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libdirectfb_core_la_SOURCES) +DIST_SOURCES = $(libdirectfb_core_la_SOURCES) +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +am__installdirs = "$(DESTDIR)$(internalincludedir)" +internalincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(internalinclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AS = @AS@ +ASFLAGS = @ASFLAGS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DATADIR = @DATADIR@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DFB_CFLAGS_OMIT_FRAME_POINTER = @DFB_CFLAGS_OMIT_FRAME_POINTER@ +DFB_INTERNAL_CFLAGS = @DFB_INTERNAL_CFLAGS@ +DFB_LDFLAGS = @DFB_LDFLAGS@ +DFB_SMOOTH_SCALING = @DFB_SMOOTH_SCALING@ +DIRECTFB_BINARY_AGE = @DIRECTFB_BINARY_AGE@ +DIRECTFB_CSOURCE = @DIRECTFB_CSOURCE@ +DIRECTFB_INTERFACE_AGE = @DIRECTFB_INTERFACE_AGE@ +DIRECTFB_MAJOR_VERSION = @DIRECTFB_MAJOR_VERSION@ +DIRECTFB_MICRO_VERSION = @DIRECTFB_MICRO_VERSION@ +DIRECTFB_MINOR_VERSION = @DIRECTFB_MINOR_VERSION@ +DIRECTFB_VERSION = @DIRECTFB_VERSION@ +DIRECT_BUILD_DEBUG = @DIRECT_BUILD_DEBUG@ +DIRECT_BUILD_DEBUGS = @DIRECT_BUILD_DEBUGS@ +DIRECT_BUILD_GETTID = @DIRECT_BUILD_GETTID@ +DIRECT_BUILD_NETWORK = @DIRECT_BUILD_NETWORK@ +DIRECT_BUILD_STDBOOL = @DIRECT_BUILD_STDBOOL@ +DIRECT_BUILD_TEXT = @DIRECT_BUILD_TEXT@ +DIRECT_BUILD_TRACE = @DIRECT_BUILD_TRACE@ +DSYMUTIL = @DSYMUTIL@ +DYNLIB = @DYNLIB@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +FREETYPE_CFLAGS = @FREETYPE_CFLAGS@ +FREETYPE_LIBS = @FREETYPE_LIBS@ +FREETYPE_PROVIDER = @FREETYPE_PROVIDER@ +FUSION_BUILD_KERNEL = @FUSION_BUILD_KERNEL@ +FUSION_BUILD_MULTI = @FUSION_BUILD_MULTI@ +FUSION_MESSAGE_SIZE = @FUSION_MESSAGE_SIZE@ +GIF_PROVIDER = @GIF_PROVIDER@ +GREP = @GREP@ +HAVE_LINUX = @HAVE_LINUX@ +INCLUDEDIR = @INCLUDEDIR@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTERNALINCLUDEDIR = @INTERNALINCLUDEDIR@ +JPEG_PROVIDER = @JPEG_PROVIDER@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBJPEG = @LIBJPEG@ +LIBOBJS = @LIBOBJS@ +LIBPNG = @LIBPNG@ +LIBPNG_CONFIG = @LIBPNG_CONFIG@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_AGE = @LT_AGE@ +LT_BINARY = @LT_BINARY@ +LT_CURRENT = @LT_CURRENT@ +LT_RELEASE = @LT_RELEASE@ +LT_REVISION = @LT_REVISION@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MAN2HTML = @MAN2HTML@ +MKDIR_P = @MKDIR_P@ +MODULEDIR = @MODULEDIR@ +MODULEDIRNAME = @MODULEDIRNAME@ +NMEDIT = @NMEDIT@ +OBJEXT = @OBJEXT@ +OSX_LIBS = @OSX_LIBS@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKG_CONFIG = @PKG_CONFIG@ +PNG_PROVIDER = @PNG_PROVIDER@ +RANLIB = @RANLIB@ +RUNTIME_SYSROOT = @RUNTIME_SYSROOT@ +SDL_CFLAGS = @SDL_CFLAGS@ +SDL_LIBS = @SDL_LIBS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SOPATH = @SOPATH@ +STRIP = @STRIP@ +SYSCONFDIR = @SYSCONFDIR@ +SYSFS_LIBS = @SYSFS_LIBS@ +THREADFLAGS = @THREADFLAGS@ +THREADLIB = @THREADLIB@ +TSLIB_CFLAGS = @TSLIB_CFLAGS@ +TSLIB_LIBS = @TSLIB_LIBS@ +VERSION = @VERSION@ +VNC_CFLAGS = @VNC_CFLAGS@ +VNC_CONFIG = @VNC_CONFIG@ +VNC_LIBS = @VNC_LIBS@ +X11_CFLAGS = @X11_CFLAGS@ +X11_LIBS = @X11_LIBS@ +ZLIB_LIBS = @ZLIB_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +INCLUDES = \ + -I$(top_builddir)/include \ + -I$(top_builddir)/lib \ + -I$(top_srcdir)/include \ + -I$(top_srcdir)/lib \ + -I$(top_srcdir)/src + +AM_CPPFLAGS = \ + -DDATADIR=\"${RUNTIME_SYSROOT}@DATADIR@\" \ + -DSOPATH=\"@SOPATH@\" \ + -DMODULEDIR=\"${RUNTIME_SYSROOT}@MODULEDIR@\" \ + "-DBUILDTIME=\"`date -u "+%Y-%m-%d %H:%M"`\"" + +internalincludedir = $(INTERNALINCLUDEDIR)/core +internalinclude_HEADERS = \ + clipboard.h \ + colorhash.h \ + coredefs.h \ + coretypes.h \ + core_parts.h \ + core_system.h \ + core.h \ + fonts.h \ + gfxcard.h \ + graphics_driver.h \ + input.h \ + input_driver.h \ + layer_context.h \ + layer_control.h \ + layer_region.h \ + layers.h \ + layers_internal.h \ + palette.h \ + screen.h \ + screens.h \ + screens_internal.h \ + state.h \ + surface.h \ + surface_buffer.h \ + surface_pool.h \ + surface_pool_bridge.h \ + system.h \ + windows.h \ + windows_internal.h \ + windowstack.h \ + wm.h \ + wm_module.h + +noinst_LTLIBRARIES = libdirectfb_core.la +libdirectfb_core_la_SOURCES = \ + clipboard.c \ + colorhash.c \ + core.c \ + core_parts.c \ + fonts.c \ + gfxcard.c \ + input.c \ + layer_context.c \ + layer_control.c \ + layer_region.c \ + layers.c \ + local_surface_pool.c \ + palette.c \ + prealloc_surface_pool.c \ + screen.c \ + screens.c \ + shared_surface_pool.c \ + state.c \ + surface.c \ + surface_buffer.c \ + surface_core.c \ + surface_pool.c \ + surface_pool_bridge.c \ + system.c \ + windows.c \ + windowstack.c \ + wm.c + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/core/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/core/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libdirectfb_core.la: $(libdirectfb_core_la_OBJECTS) $(libdirectfb_core_la_DEPENDENCIES) + $(LINK) $(libdirectfb_core_la_OBJECTS) $(libdirectfb_core_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/clipboard.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/colorhash.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/core.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/core_parts.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fonts.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gfxcard.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/input.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/layer_context.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/layer_control.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/layer_region.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/layers.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/local_surface_pool.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/palette.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/prealloc_surface_pool.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/screen.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/screens.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/shared_surface_pool.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/state.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/surface.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/surface_buffer.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/surface_core.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/surface_pool.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/surface_pool_bridge.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/system.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/windows.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/windowstack.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wm.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-internalincludeHEADERS: $(internalinclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(internalincludedir)" || $(MKDIR_P) "$(DESTDIR)$(internalincludedir)" + @list='$(internalinclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f=$(am__strip_dir) \ + echo " $(internalincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(internalincludedir)/$$f'"; \ + $(internalincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(internalincludedir)/$$f"; \ + done + +uninstall-internalincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(internalinclude_HEADERS)'; for p in $$list; do \ + f=$(am__strip_dir) \ + echo " rm -f '$(DESTDIR)$(internalincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(internalincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(internalincludedir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-internalincludeHEADERS + +install-dvi: install-dvi-am + +install-exec-am: + +install-html: install-html-am + +install-info: install-info-am + +install-man: + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-internalincludeHEADERS + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am \ + install-internalincludeHEADERS install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-internalincludeHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/Source/DirectFB/src/core/clipboard.c b/Source/DirectFB/src/core/clipboard.c new file mode 100755 index 0000000..53fde34 --- /dev/null +++ b/Source/DirectFB/src/core/clipboard.c @@ -0,0 +1,298 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include + +#include + +#include +#include + +#include + +#include +#include +#include + + +D_DEBUG_DOMAIN( Core_Clipboard, "Core/Clipboard", "DirectFB Clipboard Core" ); + +/**********************************************************************************************************************/ + +typedef struct { + int magic; + + FusionSkirmish lock; + char *mime_type; + void *data; + unsigned int size; + struct timeval timestamp; + + FusionSHMPoolShared *shmpool; +} DFBClipboardCoreShared; + +struct __DFB_DFBClipboardCore { + int magic; + + CoreDFB *core; + + DFBClipboardCoreShared *shared; +}; + + +DFB_CORE_PART( clipboard_core, ClipboardCore ); + +/**********************************************************************************************************************/ + +static DFBResult +dfb_clipboard_core_initialize( CoreDFB *core, + DFBClipboardCore *data, + DFBClipboardCoreShared *shared ) +{ + D_DEBUG_AT( Core_Clipboard, "dfb_clipboard_core_initialize( %p, %p, %p )\n", core, data, shared ); + + D_ASSERT( data != NULL ); + D_ASSERT( shared != NULL ); + + data->core = core; + data->shared = shared; + + shared->shmpool = dfb_core_shmpool( core ); + + fusion_skirmish_init( &shared->lock, "Clipboard Core", dfb_core_world(core) ); + + D_MAGIC_SET( data, DFBClipboardCore ); + D_MAGIC_SET( shared, DFBClipboardCoreShared ); + + return DFB_OK; +} + +static DFBResult +dfb_clipboard_core_join( CoreDFB *core, + DFBClipboardCore *data, + DFBClipboardCoreShared *shared ) +{ + D_DEBUG_AT( Core_Clipboard, "dfb_clipboard_core_join( %p, %p, %p )\n", core, data, shared ); + + D_ASSERT( data != NULL ); + D_MAGIC_ASSERT( shared, DFBClipboardCoreShared ); + + data->core = core; + data->shared = shared; + + D_MAGIC_SET( data, DFBClipboardCore ); + + return DFB_OK; +} + +static DFBResult +dfb_clipboard_core_shutdown( DFBClipboardCore *data, + bool emergency ) +{ + DFBClipboardCoreShared *shared; + + D_DEBUG_AT( Core_Clipboard, "dfb_clipboard_core_shutdown( %p, %semergency )\n", data, emergency ? "" : "no " ); + + D_MAGIC_ASSERT( data, DFBClipboardCore ); + + shared = data->shared; + + D_MAGIC_ASSERT( shared, DFBClipboardCoreShared ); + + fusion_skirmish_destroy( &shared->lock ); + + if (shared->data) + SHFREE( shared->shmpool, shared->data ); + + if (shared->mime_type) + SHFREE( shared->shmpool, shared->mime_type ); + + D_MAGIC_CLEAR( data ); + D_MAGIC_CLEAR( shared ); + + return DFB_OK; +} + +static DFBResult +dfb_clipboard_core_leave( DFBClipboardCore *data, + bool emergency ) +{ + D_DEBUG_AT( Core_Clipboard, "dfb_clipboard_core_leave( %p, %semergency )\n", data, emergency ? "" : "no " ); + + D_MAGIC_ASSERT( data, DFBClipboardCore ); + D_MAGIC_ASSERT( data->shared, DFBClipboardCoreShared ); + + D_MAGIC_CLEAR( data ); + + return DFB_OK; +} + +static DFBResult +dfb_clipboard_core_suspend( DFBClipboardCore *data ) +{ + D_DEBUG_AT( Core_Clipboard, "dfb_clipboard_core_suspend( %p )\n", data ); + + D_MAGIC_ASSERT( data, DFBClipboardCore ); + D_MAGIC_ASSERT( data->shared, DFBClipboardCoreShared ); + + return DFB_OK; +} + +static DFBResult +dfb_clipboard_core_resume( DFBClipboardCore *data ) +{ + D_DEBUG_AT( Core_Clipboard, "dfb_clipboard_core_resume( %p )\n", data ); + + D_MAGIC_ASSERT( data, DFBClipboardCore ); + D_MAGIC_ASSERT( data->shared, DFBClipboardCoreShared ); + + return DFB_OK; +} + +/**********************************************************************************************************************/ + +DFBResult +dfb_clipboard_set( DFBClipboardCore *core, + const char *mime_type, + const void *data, + unsigned int size, + struct timeval *timestamp ) +{ + DFBClipboardCoreShared *shared; + + char *new_mime; + void *new_data; + + D_MAGIC_ASSERT( core, DFBClipboardCore ); + D_ASSERT( mime_type != NULL ); + D_ASSERT( data != NULL ); + D_ASSERT( size > 0 ); + + shared = core->shared; + + D_MAGIC_ASSERT( shared, DFBClipboardCoreShared ); + + new_mime = SHSTRDUP( shared->shmpool, mime_type ); + if (!new_mime) + return D_OOSHM(); + + new_data = SHMALLOC( shared->shmpool, size ); + if (!new_data) { + SHFREE( shared->shmpool, new_mime ); + return D_OOSHM(); + } + + direct_memcpy( new_data, data, size ); + + if (fusion_skirmish_prevail( &shared->lock )) { + SHFREE( shared->shmpool, new_data ); + SHFREE( shared->shmpool, new_mime ); + return DFB_FUSION; + } + + if (shared->data) + SHFREE( shared->shmpool, shared->data ); + + if (shared->mime_type) + SHFREE( shared->shmpool, shared->mime_type ); + + shared->mime_type = new_mime; + shared->data = new_data; + shared->size = size; + + gettimeofday( &shared->timestamp, NULL ); + + if (timestamp) + *timestamp = shared->timestamp; + + fusion_skirmish_dismiss( &shared->lock ); + + return DFB_OK; +} + +DFBResult +dfb_clipboard_get( DFBClipboardCore *core, + char **mime_type, + void **data, + unsigned int *size ) +{ + DFBClipboardCoreShared *shared; + + D_MAGIC_ASSERT( core, DFBClipboardCore ); + + shared = core->shared; + + D_MAGIC_ASSERT( shared, DFBClipboardCoreShared ); + + if (fusion_skirmish_prevail( &shared->lock )) + return DFB_FUSION; + + if (!shared->mime_type || !shared->data) { + fusion_skirmish_dismiss( &shared->lock ); + return DFB_BUFFEREMPTY; + } + + if (mime_type) + *mime_type = strdup( shared->mime_type ); + + if (data) { + *data = malloc( shared->size ); + direct_memcpy( *data, shared->data, shared->size ); + } + + if (size) + *size = shared->size; + + fusion_skirmish_dismiss( &shared->lock ); + + return DFB_OK; +} + +DFBResult +dfb_clipboard_get_timestamp( DFBClipboardCore *core, + struct timeval *timestamp ) +{ + DFBClipboardCoreShared *shared; + + D_MAGIC_ASSERT( core, DFBClipboardCore ); + D_ASSERT( timestamp != NULL ); + + shared = core->shared; + + D_MAGIC_ASSERT( shared, DFBClipboardCoreShared ); + + if (fusion_skirmish_prevail( &shared->lock )) + return DFB_FUSION; + + *timestamp = shared->timestamp; + + fusion_skirmish_dismiss( &shared->lock ); + + return DFB_OK; +} + diff --git a/Source/DirectFB/src/core/clipboard.h b/Source/DirectFB/src/core/clipboard.h new file mode 100755 index 0000000..ffb9c43 --- /dev/null +++ b/Source/DirectFB/src/core/clipboard.h @@ -0,0 +1,53 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef __CORE__CLIPBOARD_H__ +#define __CORE__CLIPBOARD_H__ + +#include + +#include + + +DFBResult dfb_clipboard_set( DFBClipboardCore *core, + const char *mime_type, + const void *data, + unsigned int size, + struct timeval *timestamp ); + +DFBResult dfb_clipboard_get( DFBClipboardCore *core, + char **mime_type, + void **data, + unsigned int *size ); + + +DFBResult dfb_clipboard_get_timestamp( DFBClipboardCore *core, + struct timeval *timestamp ); + +#endif + diff --git a/Source/DirectFB/src/core/colorhash.c b/Source/DirectFB/src/core/colorhash.c new file mode 100755 index 0000000..370697d --- /dev/null +++ b/Source/DirectFB/src/core/colorhash.c @@ -0,0 +1,366 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include + + +D_DEBUG_DOMAIN( Core_ColorHash, "Core/ColorHash", "DirectFB ColorHash Core" ); + + +#define HASH_SIZE 823 + +typedef struct { + unsigned int pixel; + unsigned int index; + CorePalette *palette; +} Colorhash; + +/**********************************************************************************************************************/ + +typedef struct { + int magic; + + Colorhash *hash; + unsigned int hash_users; + FusionSkirmish hash_lock; + + FusionSHMPoolShared *shmpool; +} DFBColorHashCoreShared; + +struct __DFB_DFBColorHashCore { + int magic; + + CoreDFB *core; + + DFBColorHashCoreShared *shared; +}; + +DFB_CORE_PART( colorhash_core, ColorHashCore ); + +/**********************************************************************************************************************/ + +static DFBColorHashCore *core_colorhash; /* FIXME */ + + +static DFBResult +dfb_colorhash_core_initialize( CoreDFB *core, + DFBColorHashCore *data, + DFBColorHashCoreShared *shared ) +{ + D_DEBUG_AT( Core_ColorHash, "dfb_colorhash_core_initialize( %p, %p, %p )\n", core, data, shared ); + + D_ASSERT( data != NULL ); + D_ASSERT( shared != NULL ); + + core_colorhash = data; /* FIXME */ + + data->core = core; + data->shared = shared; + + shared->shmpool = dfb_core_shmpool( core ); + + fusion_skirmish_init( &shared->hash_lock, "Colorhash Core", dfb_core_world(core) ); + + D_MAGIC_SET( data, DFBColorHashCore ); + D_MAGIC_SET( shared, DFBColorHashCoreShared ); + + return DFB_OK; +} + +static DFBResult +dfb_colorhash_core_join( CoreDFB *core, + DFBColorHashCore *data, + DFBColorHashCoreShared *shared ) +{ + D_DEBUG_AT( Core_ColorHash, "dfb_colorhash_core_join( %p, %p, %p )\n", core, data, shared ); + + D_ASSERT( data != NULL ); + D_MAGIC_ASSERT( shared, DFBColorHashCoreShared ); + + core_colorhash = data; /* FIXME */ + + data->core = core; + data->shared = shared; + + D_MAGIC_SET( data, DFBColorHashCore ); + + return DFB_OK; +} + +static DFBResult +dfb_colorhash_core_shutdown( DFBColorHashCore *data, + bool emergency ) +{ + DFBColorHashCoreShared *shared; + + D_DEBUG_AT( Core_ColorHash, "dfb_colorhash_core_shutdown( %p, %semergency )\n", data, emergency ? "" : "no " ); + + D_MAGIC_ASSERT( data, DFBColorHashCore ); + D_MAGIC_ASSERT( data->shared, DFBColorHashCoreShared ); + + shared = data->shared; + + fusion_skirmish_destroy( &shared->hash_lock ); + + D_MAGIC_CLEAR( data ); + D_MAGIC_CLEAR( shared ); + + return DFB_OK; +} + +static DFBResult +dfb_colorhash_core_leave( DFBColorHashCore *data, + bool emergency ) +{ + DFBColorHashCoreShared *shared; + + D_DEBUG_AT( Core_ColorHash, "dfb_colorhash_core_leave( %p, %semergency )\n", data, emergency ? "" : "no " ); + + D_MAGIC_ASSERT( data, DFBColorHashCore ); + D_MAGIC_ASSERT( data->shared, DFBColorHashCoreShared ); + + shared = data->shared; + + D_MAGIC_CLEAR( data ); + + return DFB_OK; +} + +static DFBResult +dfb_colorhash_core_suspend( DFBColorHashCore *data ) +{ + DFBColorHashCoreShared *shared; + + D_DEBUG_AT( Core_ColorHash, "dfb_colorhash_core_suspend( %p )\n", data ); + + D_MAGIC_ASSERT( data, DFBColorHashCore ); + D_MAGIC_ASSERT( data->shared, DFBColorHashCoreShared ); + + shared = data->shared; + + return DFB_OK; +} + +static DFBResult +dfb_colorhash_core_resume( DFBColorHashCore *data ) +{ + DFBColorHashCoreShared *shared; + + D_DEBUG_AT( Core_ColorHash, "dfb_colorhash_core_resume( %p )\n", data ); + + D_MAGIC_ASSERT( data, DFBColorHashCore ); + D_MAGIC_ASSERT( data->shared, DFBColorHashCoreShared ); + + shared = data->shared; + + return DFB_OK; +} + +/**********************************************************************************************************************/ + +void +dfb_colorhash_attach( DFBColorHashCore *core, + CorePalette *palette ) +{ + DFBColorHashCoreShared *shared; + + D_ASSUME( core != NULL ); + + if (core) { + D_MAGIC_ASSERT( core, DFBColorHashCore ); + D_MAGIC_ASSERT( core->shared, DFBColorHashCoreShared ); + } + else + core = core_colorhash; + + shared = core->shared; + + fusion_skirmish_prevail( &shared->hash_lock ); + + if (!shared->hash) { + D_ASSERT( shared->hash_users == 0 ); + + shared->hash = SHCALLOC( shared->shmpool, HASH_SIZE, sizeof (Colorhash) ); + } + + shared->hash_users++; + + fusion_skirmish_dismiss( &shared->hash_lock ); +} + +void +dfb_colorhash_detach( DFBColorHashCore *core, + CorePalette *palette ) +{ + DFBColorHashCoreShared *shared; + + D_ASSUME( core != NULL ); + + if (core) { + D_MAGIC_ASSERT( core, DFBColorHashCore ); + D_MAGIC_ASSERT( core->shared, DFBColorHashCoreShared ); + } + else + core = core_colorhash; + + shared = core->shared; + + D_ASSERT( shared->hash_users > 0 ); + D_ASSERT( shared->hash != NULL ); + + fusion_skirmish_prevail( &shared->hash_lock ); + + shared->hash_users--; + + if (!shared->hash_users) { + /* no more users, free allocated resources */ + SHFREE( shared->shmpool, shared->hash ); + shared->hash = NULL; + } + + fusion_skirmish_dismiss( &shared->hash_lock ); +} + +unsigned int +dfb_colorhash_lookup( DFBColorHashCore *core, + CorePalette *palette, + u8 r, + u8 g, + u8 b, + u8 a ) +{ + unsigned int pixel = PIXEL_ARGB(a, r, g, b); + unsigned int index = (pixel ^ (unsigned long) palette) % HASH_SIZE; + DFBColorHashCoreShared *shared; + +// D_ASSUME( core != NULL ); + + if (core) { + D_MAGIC_ASSERT( core, DFBColorHashCore ); + D_MAGIC_ASSERT( core->shared, DFBColorHashCoreShared ); + } + else + core = core_colorhash; + + shared = core->shared; + + D_ASSERT( shared->hash != NULL ); + + fusion_skirmish_prevail( &shared->hash_lock ); + + /* try a lookup in the hash table */ + if (shared->hash[index].palette == palette && shared->hash[index].pixel == pixel) { + /* set the return value */ + index = shared->hash[index].index; + } else { /* look for the closest match */ + DFBColor *entries = palette->entries; + int min_diff = 0; + unsigned int i, min_index = 0; + + for (i = 0; i < palette->num_entries; i++) { + int diff; + + int r_diff = (int) entries[i].r - (int) r; + int g_diff = (int) entries[i].g - (int) g; + int b_diff = (int) entries[i].b - (int) b; + int a_diff = (int) entries[i].a - (int) a; + + if (a) + diff = (r_diff * r_diff + g_diff * g_diff + + b_diff * b_diff + ((a_diff * a_diff) >> 6)); + else + diff = (r_diff + g_diff + b_diff + (a_diff * a_diff)); + + if (i == 0 || diff < min_diff) { + min_diff = diff; + min_index = i; + } + + if (!diff) + break; + } + + /* store the matching entry in the hash table */ + shared->hash[index].pixel = pixel; + shared->hash[index].index = min_index; + shared->hash[index].palette = palette; + + /* set the return value */ + index = min_index; + } + + fusion_skirmish_dismiss( &shared->hash_lock ); + + return index; +} + +void +dfb_colorhash_invalidate( DFBColorHashCore *core, + CorePalette *palette ) +{ + unsigned int index = HASH_SIZE - 1; + DFBColorHashCoreShared *shared; + + D_ASSUME( core != NULL ); + + if (core) { + D_MAGIC_ASSERT( core, DFBColorHashCore ); + D_MAGIC_ASSERT( core->shared, DFBColorHashCoreShared ); + } + else + core = core_colorhash; + + shared = core->shared; + + D_ASSERT( shared->hash != NULL ); + + fusion_skirmish_prevail( &shared->hash_lock ); + + /* invalidate all entries owned by this palette */ + do { + if (shared->hash[index].palette == palette) + shared->hash[index].palette = NULL; + } while (index--); + + fusion_skirmish_dismiss( &shared->hash_lock ); +} + diff --git a/Source/DirectFB/src/core/colorhash.h b/Source/DirectFB/src/core/colorhash.h new file mode 100755 index 0000000..d321000 --- /dev/null +++ b/Source/DirectFB/src/core/colorhash.h @@ -0,0 +1,54 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef __CORE__COLORHASH_H__ +#define __CORE__COLORHASH_H__ + +#include + +#include + + +void dfb_colorhash_attach ( DFBColorHashCore *core, + CorePalette *palette ); + +void dfb_colorhash_detach ( DFBColorHashCore *core, + CorePalette *palette ); + +unsigned int dfb_colorhash_lookup ( DFBColorHashCore *core, + CorePalette *palette, + u8 r, + u8 g, + u8 b, + u8 a); + +void dfb_colorhash_invalidate( DFBColorHashCore *core, + CorePalette *palette ); + +#endif + diff --git a/Source/DirectFB/src/core/core.c b/Source/DirectFB/src/core/core.c new file mode 100755 index 0000000..ca20152 --- /dev/null +++ b/Source/DirectFB/src/core/core.c @@ -0,0 +1,1160 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +D_DEBUG_DOMAIN( DirectFB_Core, "DirectFB/Core", "DirectFB Core" ); + +/******************************************************************************/ + +extern CorePart dfb_clipboard_core; +extern CorePart dfb_colorhash_core; +extern CorePart dfb_graphics_core; +extern CorePart dfb_input_core; +extern CorePart dfb_layer_core; +extern CorePart dfb_screen_core; +extern CorePart dfb_surface_core; +extern CorePart dfb_system_core; +extern CorePart dfb_wm_core; + +static CorePart *core_parts[] = { + &dfb_clipboard_core, + &dfb_colorhash_core, + &dfb_surface_core, + &dfb_system_core, + &dfb_input_core, + &dfb_graphics_core, + &dfb_screen_core, + &dfb_layer_core, + &dfb_wm_core +}; + +void * +dfb_core_get_part( CoreDFB *core, + DFBCorePartID part_id ) +{ + switch (part_id) { + case DFCP_CLIPBOARD: + return dfb_clipboard_core.data_local; + + case DFCP_COLORHASH: + return dfb_colorhash_core.data_local; + + case DFCP_GRAPHICS: + return dfb_graphics_core.data_local; + + case DFCP_INPUT: + return dfb_input_core.data_local; + + case DFCP_LAYER: + return dfb_layer_core.data_local; + + case DFCP_SCREEN: + return dfb_screen_core.data_local; + + case DFCP_SURFACE: + return dfb_surface_core.data_local; + + case DFCP_SYSTEM: + return dfb_system_core.data_local; + + case DFCP_WM: + return dfb_wm_core.data_local; + + default: + D_BUG( "unknown core part" ); + } + + return NULL; +} + +/******************************************************************************/ + +/* + * one entry in the cleanup stack + */ +struct _CoreCleanup { + DirectLink link; + + CoreCleanupFunc func; /* the cleanup function to be called */ + void *data; /* context of the cleanup function */ + bool emergency; /* if true, cleanup is also done during + emergency shutdown (from signal hadler) */ +}; + +/******************************************************************************/ + +struct __DFB_CoreDFBShared { + int magic; + + FusionSkirmish lock; + bool active; + + FusionObjectPool *layer_context_pool; + FusionObjectPool *layer_region_pool; + FusionObjectPool *palette_pool; + FusionObjectPool *surface_pool; + FusionObjectPool *window_pool; + + FusionSHMPoolShared *shmpool; + FusionSHMPoolShared *shmpool_data; /* for raw data, e.g. surface buffers */ +}; + +struct __DFB_CoreDFB { + int magic; + + int refs; + + int fusion_id; + + FusionWorld *world; + FusionArena *arena; + + CoreDFBShared *shared; + + bool master; + bool suspended; + + DirectLink *cleanups; + + DirectThreadInitHandler *init_handler; + + DirectSignalHandler *signal_handler; + + DirectCleanupHandler *cleanup_handler; +}; + +/******************************************************************************/ + +/* + * ckecks if stack is clean, otherwise prints warning, then calls core_deinit() + */ +static void dfb_core_deinit_check( void *ctx ); + +static void dfb_core_thread_init_handler( DirectThread *thread, void *arg ); + +static void dfb_core_process_cleanups( CoreDFB *core, bool emergency ); + +static DirectSignalHandlerResult dfb_core_signal_handler( int num, + void *addr, + void *ctx ); + +/******************************************************************************/ + +static int dfb_core_arena_initialize( FusionArena *arena, + void *ctx ); +static int dfb_core_arena_shutdown ( FusionArena *arena, + void *ctx, + bool emergency ); +static int dfb_core_arena_join ( FusionArena *arena, + void *ctx ); +static int dfb_core_arena_leave ( FusionArena *arena, + void *ctx, + bool emergency ); + +/******************************************************************************/ + +#if defined(DFB_DYNAMIC_LINKING) && defined(SOPATH) +/* + * the library handle for dlopen'ing ourselves + */ +static void* dfb_lib_handle = NULL; +#endif + +/******************************************************************************/ + +static CoreDFB *core_dfb = NULL; +static pthread_mutex_t core_dfb_lock = PTHREAD_MUTEX_INITIALIZER; + +/******************************************************************************/ + +DFBResult +dfb_core_create( CoreDFB **ret_core ) +{ + int ret; +#if FUSION_BUILD_MULTI + char buf[16]; +#endif + CoreDFB *core = NULL; + CoreDFBShared *shared = NULL; + + D_ASSERT( ret_core != NULL ); + D_ASSERT( dfb_config != NULL ); + + D_DEBUG_AT( DirectFB_Core, "%s...\n", __FUNCTION__ ); + + pthread_mutex_lock( &core_dfb_lock ); + + D_ASSERT( core_dfb == NULL || core_dfb->refs > 0 ); + + if (core_dfb) { + D_MAGIC_ASSERT( core_dfb, CoreDFB ); + + core_dfb->refs++; + + *ret_core = core_dfb; + + pthread_mutex_unlock( &core_dfb_lock ); + + return DFB_OK; + } + + direct_initialize(); + + + D_INFO( "DirectFB/Core: %s Application Core. ("BUILDTIME") %s%s\n", + FUSION_BUILD_MULTI ? "Multi" : "Single", + DIRECT_BUILD_DEBUG ? "[ DEBUG ]" : "", + DIRECT_BUILD_TRACE ? "[ TRACE ]" : "" ); + + +#if defined(DFB_DYNAMIC_LINKING) && defined(SOPATH) + if (!dfb_lib_handle) +#ifdef RTLD_GLOBAL + dfb_lib_handle = dlopen(SOPATH, RTLD_GLOBAL|RTLD_LAZY); +#else + /* RTLD_GLOBAL is not defined on OpenBSD */ + dfb_lib_handle = dlopen(SOPATH, RTLD_LAZY); +#endif +#endif + + ret = dfb_system_lookup(); + if (ret) + goto error; + + + /* Allocate local core structure. */ + core = D_CALLOC( 1, sizeof(CoreDFB) ); + if (!core) { + ret = D_OOM(); + goto error; + } + + core->refs = 1; + + core->init_handler = direct_thread_add_init_handler( dfb_core_thread_init_handler, core ); + +#if FUSION_BUILD_MULTI + dfb_system_thread_init(); +#endif + + direct_find_best_memcpy(); + + D_MAGIC_SET( core, CoreDFB ); + + core_dfb = core; + + ret = fusion_enter( dfb_config->session, DIRECTFB_CORE_ABI, FER_ANY, &core->world ); + if (ret) + goto error; + + core->fusion_id = fusion_id( core->world ); + +#if FUSION_BUILD_MULTI + D_DEBUG_AT( DirectFB_Core, "world %d, fusion id %d\n", fusion_world_index(core->world), core->fusion_id ); + + snprintf( buf, sizeof(buf), "%d", fusion_world_index(core->world) ); + + setenv( "DIRECTFB_SESSION", buf, true ); +#endif + + if (dfb_config->sync) { + D_INFO( "DirectFB/Core: calling sync()...\n" ); + sync(); + } + + direct_signal_handler_add( DIRECT_SIGNAL_ANY, dfb_core_signal_handler, core, &core->signal_handler ); + + if (fusion_arena_enter( core->world, "DirectFB/Core", + dfb_core_arena_initialize, dfb_core_arena_join, + core, &core->arena, &ret ) || ret) + { + ret = ret ? ret : DFB_FUSION; + goto error; + } + + shared = core->shared; + D_MAGIC_ASSERT( shared, CoreDFBShared ); + + if (dfb_config->block_all_signals) + direct_signals_block_all(); + + if (dfb_config->deinit_check) + direct_cleanup_handler_add( dfb_core_deinit_check, NULL, &core->cleanup_handler ); + + + fusion_skirmish_prevail( &shared->lock ); + + if (!core->master) { + while (!shared->active) + fusion_skirmish_wait( &shared->lock, 0 ); + } + + fusion_skirmish_dismiss( &shared->lock ); + + + *ret_core = core; + + pthread_mutex_unlock( &core_dfb_lock ); + + D_DEBUG_AT( DirectFB_Core, "Core successfully created.\n" ); + + return DFB_OK; + + +error: + if (core) { + if (core->world) + fusion_exit( core->world, false ); + + if (core->init_handler) + direct_thread_remove_init_handler( core->init_handler ); + + if (core->signal_handler) + direct_signal_handler_remove( core->signal_handler ); + + D_MAGIC_CLEAR( core ); + + D_FREE( core ); + core_dfb = NULL; + } + + pthread_mutex_unlock( &core_dfb_lock ); + + direct_shutdown(); + + return ret; +} + +DFBResult +dfb_core_destroy( CoreDFB *core, bool emergency ) +{ + D_MAGIC_ASSERT( core, CoreDFB ); + D_ASSERT( core->refs > 0 ); + D_ASSERT( core == core_dfb ); + + D_DEBUG_AT( DirectFB_Core, "%s...\n", __FUNCTION__ ); + + if (!emergency) { + pthread_mutex_lock( &core_dfb_lock ); + + if (--core->refs) { + pthread_mutex_unlock( &core_dfb_lock ); + return DFB_OK; + } + } + + direct_signal_handler_remove( core->signal_handler ); + + if (core->cleanup_handler) + direct_cleanup_handler_remove( core->cleanup_handler ); + + if (core->master) { + if (emergency) { + fusion_kill( core->world, 0, SIGKILL, 1000 ); + } + else { + fusion_kill( core->world, 0, SIGTERM, 5000 ); + fusion_kill( core->world, 0, SIGKILL, 2000 ); + } + } + + dfb_core_process_cleanups( core, emergency ); + + while (fusion_arena_exit( core->arena, dfb_core_arena_shutdown, + core->master ? NULL : dfb_core_arena_leave, + core, emergency, NULL ) == DFB_BUSY) + { + D_ONCE( "waiting for DirectFB slaves to terminate" ); + usleep( 100000 ); + } + + fusion_exit( core->world, emergency ); + + if (!emergency) + direct_thread_remove_init_handler( core->init_handler ); + + D_MAGIC_CLEAR( core ); + + D_FREE( core ); + core_dfb = NULL; + + if (!emergency) { + pthread_mutex_unlock( &core_dfb_lock ); + + direct_shutdown(); + } + + return DFB_OK; +} + +CoreLayerContext * +dfb_core_create_layer_context( CoreDFB *core ) +{ + CoreDFBShared *shared; + + D_ASSUME( core != NULL ); + + if (!core) + core = core_dfb; + + D_MAGIC_ASSERT( core, CoreDFB ); + + shared = core->shared; + + D_MAGIC_ASSERT( shared, CoreDFBShared ); + D_ASSERT( shared->layer_context_pool != NULL ); + + return (CoreLayerContext*) fusion_object_create( shared->layer_context_pool, core->world ); +} + +CoreLayerRegion * +dfb_core_create_layer_region( CoreDFB *core ) +{ + CoreDFBShared *shared; + + D_ASSUME( core != NULL ); + + if (!core) + core = core_dfb; + + D_MAGIC_ASSERT( core, CoreDFB ); + + shared = core->shared; + + D_MAGIC_ASSERT( shared, CoreDFBShared ); + D_ASSERT( core->shared->layer_region_pool != NULL ); + + return (CoreLayerRegion*) fusion_object_create( core->shared->layer_region_pool, core->world ); +} + +CorePalette * +dfb_core_create_palette( CoreDFB *core ) +{ + CoreDFBShared *shared; + + D_ASSUME( core != NULL ); + + if (!core) + core = core_dfb; + + D_MAGIC_ASSERT( core, CoreDFB ); + + shared = core->shared; + + D_MAGIC_ASSERT( shared, CoreDFBShared ); + D_ASSERT( core->shared->palette_pool != NULL ); + + return (CorePalette*) fusion_object_create( core->shared->palette_pool, core->world ); +} + +CoreSurface * +dfb_core_create_surface( CoreDFB *core ) +{ + CoreDFBShared *shared; + + D_ASSUME( core != NULL ); + + if (!core) + core = core_dfb; + + D_MAGIC_ASSERT( core, CoreDFB ); + + shared = core->shared; + + D_MAGIC_ASSERT( shared, CoreDFBShared ); + D_ASSERT( core->shared->surface_pool != NULL ); + + return (CoreSurface*) fusion_object_create( core->shared->surface_pool, core->world ); +} + +CoreWindow * +dfb_core_create_window( CoreDFB *core ) +{ + CoreDFBShared *shared; + + D_ASSUME( core != NULL ); + + if (!core) + core = core_dfb; + + D_MAGIC_ASSERT( core, CoreDFB ); + + shared = core->shared; + + D_MAGIC_ASSERT( shared, CoreDFBShared ); + D_ASSERT( core->shared->window_pool != NULL ); + + return (CoreWindow*) fusion_object_create( core->shared->window_pool, core->world ); +} + +DirectResult +dfb_core_enum_surfaces( CoreDFB *core, + FusionObjectCallback callback, + void *ctx ) +{ + CoreDFBShared *shared; + + D_ASSERT( core != NULL || core_dfb != NULL ); + + if (!core) + core = core_dfb; + + D_MAGIC_ASSERT( core, CoreDFB ); + + shared = core->shared; + + D_MAGIC_ASSERT( shared, CoreDFBShared ); + + return fusion_object_pool_enum( shared->surface_pool, callback, ctx ); +} + +DirectResult +dfb_core_enum_layer_contexts( CoreDFB *core, + FusionObjectCallback callback, + void *ctx ) +{ + CoreDFBShared *shared; + + D_ASSERT( core != NULL || core_dfb != NULL ); + + if (!core) + core = core_dfb; + + D_MAGIC_ASSERT( core, CoreDFB ); + + shared = core->shared; + + D_MAGIC_ASSERT( shared, CoreDFBShared ); + + return fusion_object_pool_enum( shared->layer_context_pool, callback, ctx ); +} + +DirectResult +dfb_core_enum_layer_regions( CoreDFB *core, + FusionObjectCallback callback, + void *ctx ) +{ + CoreDFBShared *shared; + + D_ASSERT( core != NULL || core_dfb != NULL ); + + if (!core) + core = core_dfb; + + D_MAGIC_ASSERT( core, CoreDFB ); + + shared = core->shared; + + D_MAGIC_ASSERT( shared, CoreDFBShared ); + + return fusion_object_pool_enum( shared->layer_region_pool, callback, ctx ); +} + +bool +dfb_core_is_master( CoreDFB *core ) +{ + D_MAGIC_ASSERT( core, CoreDFB ); + + return core->master; +} + +void +dfb_core_activate( CoreDFB *core ) +{ + CoreDFBShared *shared; + + D_MAGIC_ASSERT( core, CoreDFB ); + + shared = core->shared; + D_MAGIC_ASSERT( shared, CoreDFBShared ); + + fusion_skirmish_prevail( &shared->lock ); + + shared->active = true; + + fusion_skirmish_notify( &shared->lock ); + + fusion_skirmish_dismiss( &shared->lock ); +} + +FusionWorld * +dfb_core_world( CoreDFB *core ) +{ +// D_ASSUME( core != NULL ); + + if (!core) + core = core_dfb; + + D_MAGIC_ASSERT( core, CoreDFB ); + + return core->world; +} + +FusionArena * +dfb_core_arena( CoreDFB *core ) +{ + D_ASSUME( core != NULL ); + + if (!core) + core = core_dfb; + + D_MAGIC_ASSERT( core, CoreDFB ); + + return core->arena; +} + +FusionSHMPoolShared * +dfb_core_shmpool( CoreDFB *core ) +{ + CoreDFBShared *shared; + + D_ASSUME( core != NULL ); + + if (!core) + core = core_dfb; + + D_MAGIC_ASSERT( core, CoreDFB ); + + shared = core->shared; + + D_MAGIC_ASSERT( shared, CoreDFBShared ); + + return shared->shmpool; +} + +FusionSHMPoolShared * +dfb_core_shmpool_data( CoreDFB *core ) +{ + CoreDFBShared *shared; + + D_ASSUME( core != NULL ); + + if (!core) + core = core_dfb; + + D_MAGIC_ASSERT( core, CoreDFB ); + + shared = core->shared; + + D_MAGIC_ASSERT( shared, CoreDFBShared ); + + return shared->shmpool_data; +} + +DFBResult +dfb_core_suspend( CoreDFB *core ) +{ + DFBResult ret; + + D_ASSUME( core != NULL ); + + if (!core) + core = core_dfb; + + D_MAGIC_ASSERT( core, CoreDFB ); + + if (!core->master) + return DFB_ACCESSDENIED; + + if (core->suspended) + return DFB_BUSY; + + ret = dfb_input_core.Suspend( dfb_input_core.data_local ); + if (ret) + goto error_input; + + ret = dfb_layer_core.Suspend( dfb_layer_core.data_local ); + if (ret) + goto error_layers; + + ret = dfb_screen_core.Suspend( dfb_screen_core.data_local ); + if (ret) + goto error_screens; + + ret = dfb_graphics_core.Suspend( dfb_graphics_core.data_local ); + if (ret) + goto error_graphics; + + core->suspended = true; + + return DFB_OK; + +error_graphics: + dfb_screen_core.Resume( dfb_screen_core.data_local ); +error_screens: + dfb_layer_core.Resume( dfb_layer_core.data_local ); +error_layers: + dfb_input_core.Resume( dfb_input_core.data_local ); +error_input: + return ret; +} + +DFBResult +dfb_core_resume( CoreDFB *core ) +{ + DFBResult ret; + + D_ASSUME( core != NULL ); + + if (!core) + core = core_dfb; + + D_MAGIC_ASSERT( core, CoreDFB ); + + if (!core->master) + return DFB_ACCESSDENIED; + + if (!core->suspended) + return DFB_BUSY; + + ret = dfb_graphics_core.Resume( dfb_graphics_core.data_local ); + if (ret) + goto error_graphics; + + ret = dfb_screen_core.Resume( dfb_screen_core.data_local ); + if (ret) + goto error_screens; + + ret = dfb_layer_core.Resume( dfb_layer_core.data_local ); + if (ret) + goto error_layers; + + ret = dfb_input_core.Resume( dfb_input_core.data_local ); + if (ret) + goto error_input; + + core->suspended = false; + + return DFB_OK; + +error_input: + dfb_layer_core.Suspend( dfb_layer_core.data_local ); +error_layers: + dfb_screen_core.Suspend( dfb_screen_core.data_local ); +error_screens: + dfb_graphics_core.Suspend( dfb_graphics_core.data_local ); +error_graphics: + return ret; +} + +CoreCleanup * +dfb_core_cleanup_add( CoreDFB *core, + CoreCleanupFunc func, + void *data, + bool emergency ) +{ + CoreCleanup *cleanup; + + D_ASSUME( core != NULL ); + + if (!core) + core = core_dfb; + + D_MAGIC_ASSERT( core, CoreDFB ); + + cleanup = D_CALLOC( 1, sizeof(CoreCleanup) ); + + cleanup->func = func; + cleanup->data = data; + cleanup->emergency = emergency; + + direct_list_prepend( &core->cleanups, &cleanup->link ); + + return cleanup; +} + +void +dfb_core_cleanup_remove( CoreDFB *core, + CoreCleanup *cleanup ) +{ + D_ASSUME( core != NULL ); + + if (!core) + core = core_dfb; + + D_MAGIC_ASSERT( core, CoreDFB ); + + direct_list_remove( &core->cleanups, &cleanup->link ); + + D_FREE( cleanup ); +} + +/******************************************************************************/ + +static void +dfb_core_deinit_check( void *ctx ) +{ + if (core_dfb && core_dfb->refs) { + D_WARN( "Application exited without deinitialization of DirectFB!" ); + dfb_core_destroy( core_dfb, true ); + } +} + +static void +dfb_core_thread_init_handler( DirectThread *thread, void *arg ) +{ + dfb_system_thread_init(); +} + +static void +dfb_core_process_cleanups( CoreDFB *core, bool emergency ) +{ + D_MAGIC_ASSERT( core, CoreDFB ); + + while (core->cleanups) { + CoreCleanup *cleanup = (CoreCleanup*) core->cleanups; + + core->cleanups = core->cleanups->next; + + if (cleanup->emergency || !emergency) + cleanup->func( cleanup->data, emergency ); + + D_FREE( cleanup ); + } +} + +static DirectSignalHandlerResult +dfb_core_signal_handler( int num, + void *addr, + void *ctx ) +{ + CoreDFB *core = ctx; + + D_ASSERT( core == core_dfb ); + + dfb_core_destroy( core, true ); + + return DSHR_OK; +} + +/******************************************************************************/ + +static int +dfb_core_shutdown( CoreDFB *core, bool emergency ) +{ + CoreDFBShared *shared; + + D_MAGIC_ASSERT( core, CoreDFB ); + + shared = core->shared; + + D_MAGIC_ASSERT( shared, CoreDFBShared ); + + /* Suspend input core to stop all input threads before shutting down. */ + if (dfb_input_core.initialized) + dfb_input_core.Suspend( dfb_input_core.data_local ); + + fusion_stop_dispatcher( core->world, emergency ); + + /* Destroy window objects. */ + fusion_object_pool_destroy( shared->window_pool, core->world ); + + /* Close window stacks. */ + if (dfb_wm_core.initialized) + dfb_wm_close_all_stacks( dfb_wm_core.data_local ); + + /* Destroy layer context and region objects. */ + fusion_object_pool_destroy( shared->layer_region_pool, core->world ); + fusion_object_pool_destroy( shared->layer_context_pool, core->world ); + + /* Shutdown WM core. */ + dfb_core_part_shutdown( core, &dfb_wm_core, emergency ); + + /* Shutdown layer core. */ + dfb_core_part_shutdown( core, &dfb_layer_core, emergency ); + dfb_core_part_shutdown( core, &dfb_screen_core, emergency ); + + /* Destroy surface and palette objects. */ + fusion_object_pool_destroy( shared->surface_pool, core->world ); + fusion_object_pool_destroy( shared->palette_pool, core->world ); + + /* Destroy remaining core parts. */ + dfb_core_part_shutdown( core, &dfb_graphics_core, emergency ); + dfb_core_part_shutdown( core, &dfb_surface_core, emergency ); + dfb_core_part_shutdown( core, &dfb_input_core, emergency ); + dfb_core_part_shutdown( core, &dfb_system_core, emergency ); + dfb_core_part_shutdown( core, &dfb_colorhash_core, emergency ); + dfb_core_part_shutdown( core, &dfb_clipboard_core, emergency ); + + /* Destroy shared memory pool for surface data. */ + fusion_shm_pool_destroy( core->world, shared->shmpool_data ); + + return 0; +} + +static DFBResult +dfb_core_initialize( CoreDFB *core ) +{ + int i; + DFBResult ret; + CoreDFBShared *shared; + + D_MAGIC_ASSERT( core, CoreDFB ); + + shared = core->shared; + + D_MAGIC_ASSERT( shared, CoreDFBShared ); + + ret = fusion_shm_pool_create( core->world, "DirectFB Data Pool", 0x1000000, + fusion_config->debugshm, &shared->shmpool_data ); + if (ret) + return ret; + + shared->layer_context_pool = dfb_layer_context_pool_create( core->world ); + shared->layer_region_pool = dfb_layer_region_pool_create( core->world ); + shared->palette_pool = dfb_palette_pool_create( core->world ); + shared->surface_pool = dfb_surface_pool_create( core->world ); + shared->window_pool = dfb_window_pool_create( core->world ); + + for (i=0; i=0; i--) + dfb_core_part_leave( core, core_parts[i], emergency ); + + return DFB_OK; +} + +static int +dfb_core_join( CoreDFB *core ) +{ + int i; + + D_MAGIC_ASSERT( core, CoreDFB ); + + for (i=0; iworld, "DirectFB Main Pool", 0x400000, + fusion_config->debugshm, &pool ); + if (ret) + return ret; + + /* Allocate shared structure in the new pool. */ + shared = SHCALLOC( pool, 1, sizeof(CoreDFBShared) ); + if (!shared) { + fusion_shm_pool_destroy( core->world, pool ); + return D_OOSHM(); + } + + core->shared = shared; + core->master = true; + + shared->shmpool = pool; + + D_MAGIC_SET( shared, CoreDFBShared ); + + /* Initialize. */ + ret = dfb_core_initialize( core ); + if (ret) { + D_MAGIC_CLEAR( shared ); + SHFREE( pool, shared ); + fusion_shm_pool_destroy( core->world, pool ); + return ret; + } + + fusion_skirmish_init( &shared->lock, "DirectFB Core", core->world ); + + /* Register shared data. */ + fusion_arena_add_shared_field( arena, "Core/Shared", shared ); + + return DFB_OK; +} + +static int +dfb_core_arena_shutdown( FusionArena *arena, + void *ctx, + bool emergency) +{ + DFBResult ret; + CoreDFB *core = ctx; + CoreDFBShared *shared; + FusionSHMPoolShared *pool; + + D_MAGIC_ASSERT( core, CoreDFB ); + + shared = core->shared; + + D_MAGIC_ASSERT( shared, CoreDFBShared ); + + pool = shared->shmpool; + + D_DEBUG_AT( DirectFB_Core, "Shutting down...\n" ); + + if (!core->master) { + D_WARN( "refusing shutdown in slave" ); + return dfb_core_leave( core, emergency ); + } + + /* Shutdown. */ + ret = dfb_core_shutdown( core, emergency ); + + fusion_skirmish_destroy( &shared->lock ); + + D_MAGIC_CLEAR( shared ); + + SHFREE( pool, shared ); + + fusion_shm_pool_destroy( core->world, pool ); + + return ret; +} + +static int +dfb_core_arena_join( FusionArena *arena, + void *ctx ) +{ + DFBResult ret; + CoreDFB *core = ctx; + void *field; + + D_MAGIC_ASSERT( core, CoreDFB ); + + D_DEBUG_AT( DirectFB_Core, "Joining...\n" ); + + /* Get shared data. */ + if (fusion_arena_get_shared_field( arena, "Core/Shared", &field )) + return DFB_FUSION; + + core->shared = field; + + /* Join. */ + ret = dfb_core_join( core ); + if (ret) + return ret; + + return DFB_OK; +} + +static int +dfb_core_arena_leave( FusionArena *arena, + void *ctx, + bool emergency) +{ + DFBResult ret; + CoreDFB *core = ctx; + + D_MAGIC_ASSERT( core, CoreDFB ); + + D_DEBUG_AT( DirectFB_Core, "Leaving...\n" ); + + /* Leave. */ + ret = dfb_core_leave( core, emergency ); + if (ret) + return ret; + + return DFB_OK; +} + diff --git a/Source/DirectFB/src/core/core.h b/Source/DirectFB/src/core/core.h new file mode 100755 index 0000000..7116e8c --- /dev/null +++ b/Source/DirectFB/src/core/core.h @@ -0,0 +1,162 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef __CORE_H__ +#define __CORE_H__ + +#include +#include +#include + +#include + +#include "coretypes.h" +#include "coredefs.h" + + +#define DIRECTFB_CORE_ABI 45 + + +typedef enum { + DFCP_CLIPBOARD, + DFCP_COLORHASH, + DFCP_GRAPHICS, + DFCP_INPUT, + DFCP_LAYER, + DFCP_SCREEN, + DFCP_SURFACE, + DFCP_SYSTEM, + DFCP_WM, + + _DFCP_NUM +} DFBCorePartID; + + +/* + * Cleanup function, callback of a cleanup stack entry. + */ +typedef void (*CoreCleanupFunc)(void *data, int emergency); + + + +/* + * Core initialization and deinitialization + */ +DFBResult dfb_core_create ( CoreDFB **ret_core ); + +DFBResult dfb_core_destroy ( CoreDFB *core, + bool emergency ); + +void *dfb_core_get_part( CoreDFB *core, + DFBCorePartID part_id ); + + +#define DFB_CORE(core,PART) dfb_core_get_part( core, DFCP_##PART ) + + +/* + * Object creation + */ +CoreLayerContext *dfb_core_create_layer_context( CoreDFB *core ); +CoreLayerRegion *dfb_core_create_layer_region ( CoreDFB *core ); +CorePalette *dfb_core_create_palette ( CoreDFB *core ); +CoreSurface *dfb_core_create_surface ( CoreDFB *core ); +CoreWindow *dfb_core_create_window ( CoreDFB *core ); + +/* + * Debug + */ +DirectResult dfb_core_enum_surfaces ( CoreDFB *core, + FusionObjectCallback callback, + void *ctx ); +DirectResult dfb_core_enum_layer_contexts( CoreDFB *core, + FusionObjectCallback callback, + void *ctx ); +DirectResult dfb_core_enum_layer_regions ( CoreDFB *core, + FusionObjectCallback callback, + void *ctx ); + + +/* + * Returns true if the calling process is the master fusionee, + * i.e. handles input drivers running their threads. + */ +bool dfb_core_is_master( CoreDFB *core ); + +/* + * Allows other (blocking) Fusionees to enter the DirectFB session. + */ +void dfb_core_activate( CoreDFB *core ); + +/* + * Returns the core's fusion world. + */ +FusionWorld *dfb_core_world( CoreDFB *core ); + +/* + * Returns the core arena. + */ +FusionArena *dfb_core_arena( CoreDFB *core ); + +/* + * Returns the shared memory pool of the core. + */ +FusionSHMPoolShared *dfb_core_shmpool( CoreDFB *core ); + +/* + * Returns the shared memory pool for raw data, e.g. surface buffers. + */ +FusionSHMPoolShared *dfb_core_shmpool_data( CoreDFB *core ); + +/* + * Suspends all core parts, stopping input threads, closing devices... + */ +DFBResult dfb_core_suspend( CoreDFB *core ); + +/* + * Resumes all core parts, reopening devices, starting input threads... + */ +DFBResult dfb_core_resume( CoreDFB *core ); + +/* + * Adds a function to the cleanup stack that is called during deinitialization. + * If emergency is true, the cleanup is even called by core_deinit_emergency(). + */ +CoreCleanup *dfb_core_cleanup_add( CoreDFB *core, + CoreCleanupFunc func, + void *data, + bool emergency ); + +/* + * Removes a function from the cleanup stack. + */ +void dfb_core_cleanup_remove( CoreDFB *core, + CoreCleanup *cleanup ); + +#endif + diff --git a/Source/DirectFB/src/core/core_parts.c b/Source/DirectFB/src/core/core_parts.c new file mode 100755 index 0000000..1b5f944 --- /dev/null +++ b/Source/DirectFB/src/core/core_parts.c @@ -0,0 +1,202 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include + +#include +#include + +#include + +#include +#include + +#include +#include + +#include +#include + + +D_DEBUG_DOMAIN( Core_Parts, "Core/Parts", "DirectFB Core Parts" ); + + +DFBResult +dfb_core_part_initialize( CoreDFB *core, + CorePart *core_part ) +{ + DFBResult ret; + void *local = NULL; + void *shared = NULL; + FusionSHMPoolShared *pool; + + pool = dfb_core_shmpool( core ); + + if (core_part->initialized) { + D_BUG( "%s already initialized", core_part->name ); + return DFB_BUG; + } + + D_DEBUG_AT( Core_Parts, "Going to initialize '%s' core...\n", core_part->name ); + + if (core_part->size_local) + local = D_CALLOC( 1, core_part->size_local ); + + if (core_part->size_shared) + shared = SHCALLOC( pool, 1, core_part->size_shared ); + + ret = core_part->Initialize( core, local, shared ); + if (ret) { + D_ERROR( "DirectFB/Core: Could not initialize '%s' core!\n" + " --> %s\n", core_part->name, + DirectFBErrorString( ret ) ); + + if (shared) + SHFREE( pool, shared ); + + if (local) + D_FREE( local ); + + return ret; + } + + if (shared) + fusion_arena_add_shared_field( dfb_core_arena( core ), + core_part->name, shared ); + + core_part->data_local = local; + core_part->data_shared = shared; + core_part->initialized = true; + + return DFB_OK; +} + +DFBResult +dfb_core_part_join( CoreDFB *core, + CorePart *core_part ) +{ + DFBResult ret; + void *local = NULL; + void *shared = NULL; + + if (core_part->initialized) { + D_BUG( "%s already joined", core_part->name ); + return DFB_BUG; + } + + D_DEBUG_AT( Core_Parts, "Going to join '%s' core...\n", core_part->name ); + + if (core_part->size_shared && + fusion_arena_get_shared_field( dfb_core_arena( core ), + core_part->name, &shared )) + return DFB_FUSION; + + if (core_part->size_local) + local = D_CALLOC( 1, core_part->size_local ); + + ret = core_part->Join( core, local, shared ); + if (ret) { + D_ERROR( "DirectFB/Core: Could not join '%s' core!\n" + " --> %s\n", core_part->name, + DirectFBErrorString( ret ) ); + + if (local) + D_FREE( local ); + + return ret; + } + + core_part->data_local = local; + core_part->data_shared = shared; + core_part->initialized = true; + + return DFB_OK; +} + +DFBResult +dfb_core_part_shutdown( CoreDFB *core, + CorePart *core_part, + bool emergency ) +{ + DFBResult ret; + FusionSHMPoolShared *pool; + + pool = dfb_core_shmpool( core ); + + if (!core_part->initialized) + return DFB_OK; + + D_DEBUG_AT( Core_Parts, "Going to shutdown '%s' core...\n", core_part->name ); + + ret = core_part->Shutdown( core_part->data_local, emergency ); + if (ret) + D_ERROR( "DirectFB/Core: Could not shutdown '%s' core!\n" + " --> %s\n", core_part->name, + DirectFBErrorString( ret ) ); + + if (core_part->data_shared) + SHFREE( pool, core_part->data_shared ); + + if (core_part->data_local) + D_FREE( core_part->data_local ); + + core_part->data_local = NULL; + core_part->data_shared = NULL; + core_part->initialized = false; + + return DFB_OK; +} + +DFBResult +dfb_core_part_leave( CoreDFB *core, + CorePart *core_part, + bool emergency ) +{ + DFBResult ret; + + if (!core_part->initialized) + return DFB_OK; + + D_DEBUG_AT( Core_Parts, "Going to leave '%s' core...\n", core_part->name ); + + ret = core_part->Leave( core_part->data_local, emergency ); + if (ret) + D_ERROR( "DirectFB/Core: Could not leave '%s' core!\n" + " --> %s\n", core_part->name, + DirectFBErrorString( ret ) ); + + if (core_part->data_local) + D_FREE( core_part->data_local ); + + core_part->data_local = NULL; + core_part->data_shared = NULL; + core_part->initialized = false; + + return DFB_OK; +} + diff --git a/Source/DirectFB/src/core/core_parts.h b/Source/DirectFB/src/core/core_parts.h new file mode 100755 index 0000000..31b7563 --- /dev/null +++ b/Source/DirectFB/src/core/core_parts.h @@ -0,0 +1,131 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef __CORE_PARTS_H__ +#define __CORE_PARTS_H__ + +#include +#include + +#include + +#include +#include + + +typedef DFBResult (*CoreInitialize)( CoreDFB *core, + void *data_local, + void *data_shared ); + +typedef DFBResult (*CoreJoin) ( CoreDFB *core, + void *data_local, + void *data_shared ); + +typedef DFBResult (*CoreShutdown) ( void *data_local, + bool emergency ); + +typedef DFBResult (*CoreLeave) ( void *data_local, + bool emergency ); + +typedef DFBResult (*CoreSuspend) ( void *data_local ); + +typedef DFBResult (*CoreResume) ( void *data_local ); + + +typedef struct { + const char *name; + + int size_local; + int size_shared; + + CoreInitialize Initialize; + CoreJoin Join; + CoreShutdown Shutdown; + CoreLeave Leave; + CoreSuspend Suspend; + CoreResume Resume; + + void *data_local; + void *data_shared; + + bool initialized; +} CorePart; + + +DFBResult dfb_core_part_initialize( CoreDFB *core, + CorePart *core_part ); + +DFBResult dfb_core_part_join ( CoreDFB *core, + CorePart *core_part ); + +DFBResult dfb_core_part_shutdown ( CoreDFB *core, + CorePart *core_part, + bool emergency ); + +DFBResult dfb_core_part_leave ( CoreDFB *core, + CorePart *core_part, + bool emergency ); + + +#define DFB_CORE_PART(part,Type) \ + \ +static DFBResult dfb_##part##_initialize( CoreDFB *core, \ + DFB##Type *local, \ + DFB##Type##Shared *shared ); \ + \ +static DFBResult dfb_##part##_join ( CoreDFB *core, \ + DFB##Type *local, \ + DFB##Type##Shared *shared ); \ + \ +static DFBResult dfb_##part##_shutdown ( DFB##Type *local, \ + bool emergency ); \ + \ +static DFBResult dfb_##part##_leave ( DFB##Type *local, \ + bool emergency ); \ + \ +static DFBResult dfb_##part##_suspend ( DFB##Type *local ); \ + \ +static DFBResult dfb_##part##_resume ( DFB##Type *local ); \ + \ +CorePart dfb_##part = { \ + .name = #part, \ + \ + .size_local = sizeof(DFB##Type), \ + .size_shared = sizeof(DFB##Type##Shared), \ + \ + .Initialize = (void*)dfb_##part##_initialize, \ + .Join = (void*)dfb_##part##_join, \ + .Shutdown = (void*)dfb_##part##_shutdown, \ + .Leave = (void*)dfb_##part##_leave, \ + .Suspend = (void*)dfb_##part##_suspend, \ + .Resume = (void*)dfb_##part##_resume, \ +} + + +#endif + diff --git a/Source/DirectFB/src/core/core_system.h b/Source/DirectFB/src/core/core_system.h new file mode 100755 index 0000000..dfa2abc --- /dev/null +++ b/Source/DirectFB/src/core/core_system.h @@ -0,0 +1,141 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef __DFB__CORE__CORE_SYSTEM_H__ +#define __DFB__CORE__CORE_SYSTEM_H__ + +#include + +static void +system_get_info( CoreSystemInfo *info ); + +static DFBResult +system_initialize( CoreDFB *core, void **data ); + +static DFBResult +system_join( CoreDFB *core, void **data ); + +static DFBResult +system_shutdown( bool emergency ); + +static DFBResult +system_leave( bool emergency ); + +static DFBResult +system_suspend( void ); + +static DFBResult +system_resume( void ); + +static VideoMode* +system_get_modes( void ); + +static VideoMode* +system_get_current_mode( void ); + +static DFBResult +system_thread_init( void ); + +static bool +system_input_filter( CoreInputDevice *device, + DFBInputEvent *event ); + +static volatile void* +system_map_mmio( unsigned int offset, + int length ); + +static void +system_unmap_mmio( volatile void *addr, + int length ); + +static int +system_get_accelerator( void ); + +static unsigned long +system_video_memory_physical( unsigned int offset ); + +static void* +system_video_memory_virtual( unsigned int offset ); + +static unsigned int +system_videoram_length( void ); + +static unsigned long +system_aux_memory_physical( unsigned int offset ); + +static void* +system_aux_memory_virtual( unsigned int offset ); + +static unsigned int +system_auxram_length( void ); + +static void +system_get_busid( int *ret_bus, int *ret_dev, int *ret_func ); + +static void +system_get_deviceid( unsigned int *ret_vendor_id, unsigned int *ret_device_id ); + + +static CoreSystemFuncs system_funcs = { + .GetSystemInfo = system_get_info, + .Initialize = system_initialize, + .Join = system_join, + .Shutdown = system_shutdown, + .Leave = system_leave, + .Suspend = system_suspend, + .Resume = system_resume, + .GetModes = system_get_modes, + .GetCurrentMode = system_get_current_mode, + .ThreadInit = system_thread_init, + .InputFilter = system_input_filter, + .MapMMIO = system_map_mmio, + .UnmapMMIO = system_unmap_mmio, + .GetAccelerator = system_get_accelerator, + .VideoMemoryPhysical = system_video_memory_physical, + .VideoMemoryVirtual = system_video_memory_virtual, + .VideoRamLength = system_videoram_length, + .AuxMemoryPhysical = system_aux_memory_physical, + .AuxMemoryVirtual = system_aux_memory_virtual, + .AuxRamLength = system_auxram_length, + .GetBusID = system_get_busid, + .GetDeviceID = system_get_deviceid +}; + +#define DFB_CORE_SYSTEM(shortname) \ +__attribute__((constructor)) void directfb_##shortname( void ); \ + \ +void \ +directfb_##shortname( void ) \ +{ \ + direct_modules_register( &dfb_core_systems, \ + DFB_CORE_SYSTEM_ABI_VERSION, \ + #shortname, &system_funcs ); \ +} + +#endif + diff --git a/Source/DirectFB/src/core/coredefs.h b/Source/DirectFB/src/core/coredefs.h new file mode 100755 index 0000000..3354cfa --- /dev/null +++ b/Source/DirectFB/src/core/coredefs.h @@ -0,0 +1,48 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef __CORE__COREDEFS_H__ +#define __CORE__COREDEFS_H__ + + +#ifdef PIC +#define DFB_DYNAMIC_LINKING +#endif + +#define MAX_INPUTDEVICES 64 +#define MAX_LAYERS 16 +#define MAX_SCREENS 4 + +#define MAX_INPUT_GLOBALS 8 + +#define MAX_SURFACE_BUFFERS 6 +#define MAX_SURFACE_POOLS 8 +#define MAX_SURFACE_POOL_BRIDGES 4 + +#endif + diff --git a/Source/DirectFB/src/core/coretypes.h b/Source/DirectFB/src/core/coretypes.h new file mode 100755 index 0000000..a5df62d --- /dev/null +++ b/Source/DirectFB/src/core/coretypes.h @@ -0,0 +1,89 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef __CORETYPES_H__ +#define __CORETYPES_H__ + +#include + +typedef struct __DFB_CoreDFB CoreDFB; +typedef struct __DFB_CoreDFBShared CoreDFBShared; + + +typedef struct __DFB_DFBClipboardCore DFBClipboardCore; +typedef struct __DFB_DFBColorHashCore DFBColorHashCore; +typedef struct __DFB_DFBGraphicsCore DFBGraphicsCore; +typedef struct __DFB_DFBInputCore DFBInputCore; +typedef struct __DFB_DFBLayerCore DFBLayerCore; +typedef struct __DFB_DFBScreenCore DFBScreenCore; +typedef struct __DFB_DFBSystemCore DFBSystemCore; +typedef struct __DFB_DFBWMCore DFBWMCore; + + +typedef struct __DFB_DFBGraphicsCore CoreGraphicsDevice; /* FIXME */ + + +typedef struct _CoreCleanup CoreCleanup; + +typedef struct _CoreFont CoreFont; +typedef struct _CoreGlyphData CoreGlyphData; +typedef struct _CorePalette CorePalette; + +typedef struct _CardState CardState; + + +typedef struct __DFB_CoreGraphicsSerial CoreGraphicsSerial; + +typedef struct __DFB_CoreScreen CoreScreen; + +typedef struct __DFB_CoreInputDevice CoreInputDevice; + +typedef struct __DFB_CoreLayer CoreLayer; +typedef struct __DFB_CoreLayerContext CoreLayerContext; +typedef struct __DFB_CoreLayerRegion CoreLayerRegion; +typedef struct __DFB_CoreLayerRegionConfig CoreLayerRegionConfig; + +typedef struct __DFB_CoreSurface CoreSurface; +typedef struct __DFB_CoreSurfaceAccessor CoreSurfaceAccessor; +typedef struct __DFB_CoreSurfaceAllocation CoreSurfaceAllocation; +typedef struct __DFB_CoreSurfaceBuffer CoreSurfaceBuffer; +typedef struct __DFB_CoreSurfaceBufferLock CoreSurfaceBufferLock; +typedef struct __DFB_CoreSurfacePool CoreSurfacePool; +typedef struct __DFB_CoreSurfacePoolBridge CoreSurfacePoolBridge; +typedef struct __DFB_CoreSurfacePoolTransfer CoreSurfacePoolTransfer; + +typedef struct __DFB_CoreWindow CoreWindow; +typedef struct __DFB_CoreWindowConfig CoreWindowConfig; +typedef struct __DFB_CoreWindowStack CoreWindowStack; + + +typedef unsigned int CoreSurfacePoolID; +typedef unsigned int CoreSurfacePoolBridgeID; + +#endif + diff --git a/Source/DirectFB/src/core/fonts.c b/Source/DirectFB/src/core/fonts.c new file mode 100755 index 0000000..2e6b599 --- /dev/null +++ b/Source/DirectFB/src/core/fonts.c @@ -0,0 +1,660 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include + +#include +#include + +#include + +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + + +D_DEBUG_DOMAIN( Core_Font, "Core/Font", "DirectFB Core Font" ); +D_DEBUG_DOMAIN( Core_FontSurfaces, "Core/Font/Surf", "DirectFB Core Font Surfaces" ); + +/**********************************************************************************************************************/ + +static bool free_glyphs( DirectHash *hash, + unsigned long key, + void *value, + void *ctx ); + +/**********************************************************************************************************************/ + +DFBResult +dfb_font_create( CoreDFB *core, + const DFBFontDescription *description, + const char *url, + CoreFont **ret_font ) +{ + DFBResult ret; + int i; + CoreFont *font; + + D_DEBUG_AT( Core_Font, "%s()\n", __FUNCTION__ ); + + D_ASSERT( core != NULL ); + D_ASSERT( ret_font != NULL ); + + font = D_CALLOC( 1, sizeof(CoreFont) ); + if (!font) + return D_OOM(); + + for (i=0; ilayers[i].glyph_hash ); + if (ret) { + while (i--) + direct_hash_destroy( font->layers[i].glyph_hash ); + + D_FREE( font ); + return ret; + } + } + + font->description = *description; + font->url = D_STRDUP( url ); + + font->core = core; + font->max_rows = 2; + + direct_util_recursive_pthread_mutex_init( &font->lock ); + + /* the proposed pixel_format, may be changed by the font provider */ + font->pixel_format = dfb_config->font_format ? : DSPF_A8; + + if ((font->pixel_format == DSPF_ARGB || font->pixel_format == DSPF_ARGB4444) && dfb_config->font_premult) + font->surface_caps = DSCAPS_PREMULTIPLIED; + + font->blittingflags = DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_COLORIZE; + + D_MAGIC_SET( font, CoreFont ); + + *ret_font = font; + + return DFB_OK; +} + +void +dfb_font_destroy( CoreFont *font ) +{ + int i; + + D_DEBUG_AT( Core_Font, "%s()\n", __FUNCTION__ ); + + D_MAGIC_ASSERT( font, CoreFont ); + + D_MAGIC_CLEAR( font ); + + D_FREE( font->url ); + + pthread_mutex_lock( &font->lock ); + + for (i=0; ilayers[i].glyph_hash, free_glyphs, NULL ); + + direct_hash_destroy( font->layers[i].glyph_hash ); + } + + if (font->rows) { + for (i = 0; i < font->num_rows; i++) { + CoreFontCacheRow *row = font->rows[i]; + + D_MAGIC_ASSERT( row, CoreFontCacheRow ); + + dfb_surface_unref( row->surface ); + + D_MAGIC_CLEAR( row ); + + D_FREE( row ); + } + + D_FREE( font->rows ); + } + + D_ASSERT( font->encodings != NULL || !font->last_encoding ); + + for (i=DTEID_OTHER; i<=font->last_encoding; i++) { + CoreFontEncoding *encoding = font->encodings[i]; + + D_ASSERT( encoding != NULL ); + D_ASSERT( encoding->name != NULL ); + + D_MAGIC_CLEAR( encoding ); + + D_FREE( encoding->name ); + D_FREE( encoding ); + } + + if (font->encodings) + D_FREE( font->encodings ); + + pthread_mutex_unlock( &font->lock ); + pthread_mutex_destroy( &font->lock ); + + D_FREE( font ); +} + +/**********************************************************************************************************************/ + +DFBResult +dfb_font_get_glyph_data( CoreFont *font, + unsigned int index, + unsigned int layer, + CoreGlyphData **ret_data ) +{ + DFBResult ret; + CoreGlyphData *data; + int i; + int align; + CoreFontCacheRow *row = NULL; + + D_DEBUG_AT( Core_Font, "%s()\n", __FUNCTION__ ); + + D_MAGIC_ASSERT( font, CoreFont ); + D_ASSERT( ret_data != NULL ); + + D_ASSERT( layer < D_ARRAY_SIZE(font->layers) ); + D_ASSERT( font->num_rows >= 0 ); + + if (font->num_rows) { + D_ASSERT( font->num_rows <= font->max_rows || font->max_rows < 0 ); + D_ASSERT( font->active_row >= 0 ); + D_ASSERT( font->active_row < font->num_rows ); + } + + if (index < 128 && font->layers[layer].glyph_data[index]) { + data = font->layers[layer].glyph_data[index]; + if (data->failed) + goto retry; + + *ret_data = font->layers[layer].glyph_data[index]; + return DFB_OK; + } + + data = direct_hash_lookup( font->layers[layer].glyph_hash, index ); + if (data) { + D_MAGIC_ASSERT( data, CoreGlyphData ); + + if (font->rows) { + D_ASSERT( data->row >= 0 ); + D_ASSERT( data->row < font->num_rows ); + + row = font->rows[data->row]; + + D_MAGIC_ASSERT( row, CoreFontCacheRow ); + + row->stamp = font->row_stamp++; + } + + if (data->failed) + goto retry; + + *ret_data = data; + return DFB_OK; + } + + if (!font->GetGlyphData) + return DFB_UNSUPPORTED; + + data = D_CALLOC( 1, sizeof(CoreGlyphData) ); + if (!data) + return D_OOM(); + + D_MAGIC_SET( data, CoreGlyphData ); + + data->index = index; + data->layer = layer; + +retry: + data->failed = false; + + ret = font->GetGlyphData( font, index, data ); + if (ret) { + D_DERROR( ret, "Core/Font: Could not get glyph info for index %d!\n", index ); + data->start = data->width = data->height = 0; + data->failed = true; + goto out; + } + + if (data->width < 1 || data->height < 1) { + data->start = data->width = data->height = 0; + goto out; + } + + if (font->rows) { + D_ASSERT( font->active_row >= 0 ); + D_ASSERT( font->active_row < font->num_rows ); + + row = font->rows[font->active_row]; + + D_MAGIC_ASSERT( row, CoreFontCacheRow ); + } + else { + /* Calculate row width? */ + if (font->row_width == 0) { + int width = 2048 * font->height / 64; + + if (width > 2048) + width = 2048; + + if (width < font->maxadvance) + width = font->maxadvance; + + font->row_width = (width + 7) & ~7; + } + } + + /* Need another font surface? */ + if (!row || (row->next_x + data->width > font->row_width)) { + D_ASSERT( font->max_rows != 0 ); + + /* Maximum number of rows reached? */ + if (font->num_rows == font->max_rows) { + int best_row = -1; + unsigned int best_val = 0; + + /* Check for trailing space first. */ + for (i=0; inum_rows; i++) { + row = font->rows[i]; + + D_MAGIC_ASSERT( row, CoreFontCacheRow ); + + if (row->next_x + data->width <= font->row_width) { + if (best_row == -1 || best_val < row->next_x) { + best_row = i; + best_val = row->next_x; + } + } + } + + /* Found a row with enough trailing space? */ + if (best_row != -1) { + font->active_row = best_row; + row = font->rows[best_row]; + + D_MAGIC_ASSERT( row, CoreFontCacheRow ); + + D_DEBUG_AT( Core_FontSurfaces, " -> using trailing space of row %d - %dx%d %s\n", + font->active_row, row->surface->config.size.w, row->surface->config.size.h, + dfb_pixelformat_name(row->surface->config.format) ); + } + else { + CoreGlyphData *d, *n; + + D_ASSERT( best_row == -1 ); + D_ASSERT( best_val == 0 ); + + /* Reuse the least recently used row. */ + for (i=0; inum_rows; i++) { + row = font->rows[i]; + + D_MAGIC_ASSERT( row, CoreFontCacheRow ); + + if (best_row == -1 || best_val > row->stamp) { + best_row = i; + best_val = row->stamp; + } + } + + D_ASSERT( best_row != -1 ); + + font->active_row = best_row; + row = font->rows[best_row]; + + D_MAGIC_ASSERT( row, CoreFontCacheRow ); + + D_DEBUG_AT( Core_FontSurfaces, " -> reusing row %d - %dx%d %s\n", + font->active_row, row->surface->config.size.w, row->surface->config.size.h, + dfb_pixelformat_name(row->surface->config.format) ); + + /* Kick out all glyphs. */ + direct_list_foreach_safe (d, n, row->glyphs) { + D_MAGIC_ASSERT( d, CoreGlyphData ); + D_ASSERT( d->layer < D_ARRAY_SIZE(font->layers) ); + + /*ret =*/ direct_hash_remove( font->layers[d->layer].glyph_hash, d->index ); + //FIXME: use D_ASSERT( ret == DFB_OK ); + + if (d->index < 128) + font->layers[d->layer].glyph_data[d->index] = NULL; + + D_MAGIC_CLEAR( d ); + D_FREE( d ); + } + + /* Reset row. */ + row->glyphs = NULL; + row->next_x = 0; + } + } + else { + /* Allocate new font cache row structure. */ + row = D_CALLOC( 1, sizeof(CoreFontCacheRow) ); + if (!row) { + ret = D_OOM(); + goto error; + } + + /* Create a new font surface. */ + ret = dfb_surface_create_simple( font->core, + font->row_width, + MAX( font->height + 1, 8 ), + font->pixel_format, + font->surface_caps, CSTF_FONT, + 0 /* FIXME: no shared fonts, no font id */, + NULL, &row->surface ); + if (ret) { + D_DERROR( ret, "Core/Font: Could not create font surface!\n" ); + D_FREE( row ); + goto error; + } + + D_DEBUG_AT( Core_FontSurfaces, " -> new row %d - %dx%d %s\n", font->num_rows, + row->surface->config.size.w, row->surface->config.size.h, + dfb_pixelformat_name(row->surface->config.format) ); + + D_MAGIC_SET( row, CoreFontCacheRow ); + + + /* Append to array. FIXME: Use vector to avoid realloc each time! */ + font->rows = D_REALLOC( font->rows, sizeof(void*) * (font->num_rows + 1) ); + D_ASSERT( font->rows != NULL ); + + font->rows[font->num_rows] = row; + + /* Set new row to use. */ + font->active_row = font->num_rows++; + } + } + + D_MAGIC_ASSERT( row, CoreFontCacheRow ); + D_ASSERT( font->num_rows > 0 ); + D_ASSERT( font->num_rows <= font->max_rows || font->max_rows < 0 ); + D_ASSERT( font->active_row >= 0 ); + D_ASSERT( font->active_row < font->num_rows ); + D_ASSERT( row == font->rows[font->active_row] ); + + D_DEBUG_AT( Core_FontSurfaces, " -> render %2d - %2dx%2d at %d:%03d font <%p>\n", + index, data->width, data->height, font->active_row, row->next_x, font ); + + data->row = font->active_row; + data->start = row->next_x; + data->surface = row->surface; + + align = (8 / (DFB_BYTES_PER_PIXEL( font->pixel_format ) ? : 1)) * + (DFB_PIXELFORMAT_ALIGNMENT( font->pixel_format ) + 1) - 1; + + row->next_x += (data->width + align) & ~align; + + row->stamp = font->row_stamp++; + + /* Render the glyph data into the surface. */ + ret = font->RenderGlyph( font, index, data ); + if (ret) { + data->start = data->width = data->height = 0; + data->failed = true; + goto out; + } + + dfb_gfxcard_flush_texture_cache(); + + +out: + if (!data->inserted) { + if (row) + direct_list_append( &row->glyphs, &data->link ); + + direct_hash_insert( font->layers[layer].glyph_hash, index, data ); + + if (index < 128) + font->layers[layer].glyph_data[index] = data; + + data->inserted = true; + } + + *ret_data = data; + + return DFB_OK; + + +error: + D_MAGIC_CLEAR( data ); + D_FREE( data ); + + return ret; +} + +/**********************************************************************************************************************/ + +DFBResult +dfb_font_register_encoding( CoreFont *font, + const char *name, + const CoreFontEncodingFuncs *funcs, + DFBTextEncodingID encoding_id ) +{ + CoreFontEncoding *encoding; + CoreFontEncoding **encodings; + + D_DEBUG_AT( Core_Font, "%s()\n", __FUNCTION__ ); + + D_MAGIC_ASSERT( font, CoreFont ); + D_ASSERT( encoding_id == DTEID_UTF8 || name != NULL ); + D_ASSERT( funcs != NULL ); + + if (!funcs->GetCharacterIndex) + return DFB_INVARG; + + /* Special case for default, native format. */ + if (encoding_id == DTEID_UTF8) { + font->utf8 = funcs; + + return DFB_OK; + } + + if (!funcs->DecodeText) + return DFB_INVARG; + + /* Setup new encoding information. */ + encoding = D_CALLOC( 1, sizeof(CoreFontEncoding) ); + if (!encoding) + return D_OOM(); + + encoding->encoding = font->last_encoding + 1; + encoding->funcs = funcs; + encoding->name = D_STRDUP( name ); + + if (!encoding->name) { + D_FREE( encoding ); + return D_OOM(); + } + + /* Add to array. */ + encodings = D_REALLOC( font->encodings, + (encoding->encoding + 1) * sizeof(CoreFontEncoding*) ); + if (!encodings) { + D_FREE( encoding->name ); + D_FREE( encoding ); + return D_OOM(); + } + + font->encodings = encodings; + + font->last_encoding++; + + D_ASSERT( font->last_encoding == encoding->encoding ); + + encodings[encoding->encoding] = encoding; + + D_MAGIC_SET( encoding, CoreFontEncoding ); + + return DFB_OK; +} + +DFBResult +dfb_font_decode_text( CoreFont *font, + DFBTextEncodingID encoding, + const void *text, + int length, + unsigned int *ret_indices, + int *ret_num ) +{ + int pos = 0, num = 0; + const u8 *bytes = text; + + D_DEBUG_AT( Core_Font, "%s()\n", __FUNCTION__ ); + + D_MAGIC_ASSERT( font, CoreFont ); + D_ASSERT( text != NULL ); + D_ASSERT( length >= 0 ); /* TODO: handle -1 here? */ + D_ASSERT( ret_indices != NULL ); + D_ASSERT( ret_num != NULL ); + + if (encoding != DTEID_UTF8) { + if (encoding > font->last_encoding) + return DFB_IDNOTFOUND; + + D_ASSERT( font->encodings[encoding] != NULL ); + D_ASSERT( font->encodings[encoding]->funcs != NULL ); + D_ASSERT( font->encodings[encoding]->funcs->DecodeText != NULL ); + + return font->encodings[encoding]->funcs->DecodeText( font, text, length, + ret_indices, ret_num ); + } + else if (font->utf8) { + const CoreFontEncodingFuncs *funcs = font->utf8; + + if (funcs->DecodeText) + return funcs->DecodeText( font, text, length, ret_indices, ret_num ); + + D_ASSERT( funcs->GetCharacterIndex != NULL ); + + while (pos < length) { + unsigned int c; + + if (bytes[pos] < 128) + c = bytes[pos++]; + else { + c = DIRECT_UTF8_GET_CHAR( &bytes[pos] ); + pos += DIRECT_UTF8_SKIP(bytes[pos]); + } + + if (funcs->GetCharacterIndex( font, c, &ret_indices[num] ) == DFB_OK) + num++; + } + + } + else { + while (pos < length) { + if (bytes[pos] < 128) + ret_indices[num++] = bytes[pos++]; + else { + ret_indices[num++] = DIRECT_UTF8_GET_CHAR( &bytes[pos] ); + pos += DIRECT_UTF8_SKIP(bytes[pos]); + } + } + } + + *ret_num = num; + + return DFB_OK; +} + +DFBResult +dfb_font_decode_character( CoreFont *font, + DFBTextEncodingID encoding, + u32 character, + unsigned int *ret_index ) +{ + D_DEBUG_AT( Core_Font, "%s()\n", __FUNCTION__ ); + + D_MAGIC_ASSERT( font, CoreFont ); + D_ASSERT( ret_index != NULL ); + + if (encoding > font->last_encoding) + return DFB_IDNOTFOUND; + + if (encoding != DTEID_UTF8) { + D_ASSERT( font->encodings[encoding] != NULL ); + D_ASSERT( font->encodings[encoding]->funcs != NULL ); + D_ASSERT( font->encodings[encoding]->funcs->GetCharacterIndex != NULL ); + + return font->encodings[encoding]->funcs->GetCharacterIndex( font, character, ret_index ); + } + else if (font->utf8) { + const CoreFontEncodingFuncs *funcs = font->utf8; + + D_ASSERT( funcs->GetCharacterIndex != NULL ); + + return funcs->GetCharacterIndex( font, character, ret_index ); + } + else + *ret_index = character; + + return DFB_OK; +} + +/**********************************************************************************************************************/ + +static bool +free_glyphs( DirectHash *hash, + unsigned long key, + void *value, + void *ctx ) +{ + CoreGlyphData *data = value; + + D_MAGIC_ASSERT( data, CoreGlyphData ); + + D_MAGIC_CLEAR( data ); + D_FREE( data ); + + return true; +} + diff --git a/Source/DirectFB/src/core/fonts.h b/Source/DirectFB/src/core/fonts.h new file mode 100755 index 0000000..4dc04fa --- /dev/null +++ b/Source/DirectFB/src/core/fonts.h @@ -0,0 +1,250 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef __FONTS_H__ +#define __FONTS_H__ + +#include + +#include + +#include + +#include + +#include + +/* + * glyph struct + */ +struct _CoreGlyphData { + DirectLink link; + + unsigned int index; + unsigned int layer; + unsigned int row; + + CoreSurface *surface; /* contains bitmap of glyph */ + int start; /* x offset of glyph in surface */ + int width; /* width of the glyphs bitmap */ + int height; /* height of the glyphs bitmap */ + int left; /* x offset of the glyph */ + int top; /* y offset of the glyph */ + int xadvance; /* placement of next glyph */ + int yadvance; + + bool inserted; + bool failed; + + int magic; +}; + +typedef struct { + DFBResult (* GetCharacterIndex) ( CoreFont *thiz, + unsigned int character, + unsigned int *ret_index ); + + DFBResult (* DecodeText) ( CoreFont *thiz, + const void *text, + int length, + unsigned int *ret_indices, + int *ret_num ); +} CoreFontEncodingFuncs; + +typedef struct { + DirectLink link; + + DFBTextEncodingID encoding; + char *name; + const CoreFontEncodingFuncs *funcs; + + int magic; +} CoreFontEncoding; + +typedef struct { + unsigned int stamp; + + CoreSurface *surface; + int next_x; + + DirectLink *glyphs; + + int magic; +} CoreFontCacheRow; + + +#define DFB_FONT_MAX_LAYERS 2 + +/* + * font struct + */ + +struct _CoreFont { + CoreDFB *core; + + DFBFontDescription description; /* original description used to create the font */ + char *url; + + DFBSurfaceBlittingFlags blittingflags; + DFBSurfacePixelFormat pixel_format; + DFBSurfaceCapabilities surface_caps; + int row_width; + int max_rows; + + DFBFontAttributes attributes; + + CoreFontCacheRow **rows; /* contain bitmaps of loaded glyphs */ + int num_rows; + int active_row; + unsigned int row_stamp; + + struct { + DirectHash *glyph_hash; /* infos about loaded glyphs */ + CoreGlyphData *glyph_data[128]; + } layers[DFB_FONT_MAX_LAYERS]; + + int height; /* font height */ + + int ascender; /* a positive value, the distance + from the baseline to the top */ + int descender; /* a negative value, the distance + from the baseline to the bottom */ + int maxadvance; /* width of largest character */ + + float up_unit_x; /* unit vector pointing 'up' in for */ + float up_unit_y; /* this font's rotation */ + + pthread_mutex_t lock; /* lock during access to the font */ + + const CoreFontEncodingFuncs *utf8; /* for default encoding, DTEID_UTF8 */ + CoreFontEncoding **encodings; /* for other encodings */ + DFBTextEncodingID last_encoding; /* dynamic allocation impl. helper */ + + void *impl_data; /* a pointer used by the impl. */ + + DFBResult (* GetGlyphData) ( CoreFont *thiz, + unsigned int index, + CoreGlyphData *data ); + + DFBResult (* RenderGlyph) ( CoreFont *thiz, + unsigned int index, + CoreGlyphData *data ); + + DFBResult (* GetKerning) ( CoreFont *thiz, + unsigned int prev, + unsigned int current, + int *ret_x, + int *ret_y ); + + + int magic; +}; + +/* + * allocates and initializes a new font structure + */ +DFBResult dfb_font_create( CoreDFB *core, + const DFBFontDescription *description, + const char *url, + CoreFont **ret_font ); + +/* + * destroy all data in the CoreFont struct + */ +void dfb_font_destroy( CoreFont *font ); + +/* + * lock the font before accessing it + */ +static inline void +dfb_font_lock( CoreFont *font ) +{ + D_MAGIC_ASSERT( font, CoreFont ); + + pthread_mutex_lock( &font->lock ); +} + +/* + * unlock the font after access + */ +static inline void +dfb_font_unlock( CoreFont *font ) +{ + D_MAGIC_ASSERT( font, CoreFont ); + + pthread_mutex_unlock( &font->lock ); +} + +/* + * loads glyph data from font + */ +DFBResult dfb_font_get_glyph_data( CoreFont *font, + unsigned int index, + unsigned int layer, + CoreGlyphData **glyph_data ); + + +/* + * Called by font module to register encoding implementations. + * + * The encoding can be DTEID_UTF8 or DTEID_OTHER, where in the + * latter case the actual id will be allocated dynamically. + * + * In the case of DTEID_UTF8 it's allowed to only provide + * GetCharacterIndex() and let the core do the DecodeText(), + * but that would cause a GetCharacterIndex() call per decoded + * unicode character. So implementing both is advisable. + * + * If nothing is registered for DTEID_UTF8 at all, the core will + * pass the raw unicode characters to GetGlyphInfo(), RenderGlyph() etc. + * That's the old behaviour, fully compatible with old modules. It's + * also a good choice if you want to avoid the character translation, + * having an efficient font module which is based natively on unicode + * characters. + * + * For registering an encoding as DTEID_OTHER both GetCharacterIndex() + * and DecodeText() must be provided. + */ +DFBResult dfb_font_register_encoding( CoreFont *font, + const char *name, + const CoreFontEncodingFuncs *funcs, + DFBTextEncodingID encoding ); + +DFBResult dfb_font_decode_text( CoreFont *font, + DFBTextEncodingID encoding, + const void *text, + int length, + unsigned int *ret_indices, + int *ret_num ); + +DFBResult dfb_font_decode_character( CoreFont *font, + DFBTextEncodingID encoding, + u32 character, + unsigned int *ret_index ); + +#endif diff --git a/Source/DirectFB/src/core/gfxcard.c b/Source/DirectFB/src/core/gfxcard.c new file mode 100755 index 0000000..84e725c --- /dev/null +++ b/Source/DirectFB/src/core/gfxcard.c @@ -0,0 +1,2921 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include + +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + + +D_DEBUG_DOMAIN( Core_Graphics, "Core/Graphics", "DirectFB Graphics Core" ); +D_DEBUG_DOMAIN( Core_GraphicsOps, "Core/GraphicsOps", "DirectFB Graphics Core Operations" ); +D_DEBUG_DOMAIN( Core_GfxState, "Core/GfxState", "DirectFB Graphics Core State" ); + + +DEFINE_MODULE_DIRECTORY( dfb_graphics_drivers, "gfxdrivers", DFB_GRAPHICS_DRIVER_ABI_VERSION ); + +/**********************************************************************************************************************/ + +static void dfb_gfxcard_find_driver( CoreDFB *core ); +static void dfb_gfxcard_load_driver( void ); + +static void fill_tri( DFBTriangle *tri, CardState *state, bool accelerated ); + +/**********************************************************************************************************************/ + +typedef struct { + int magic; + + /* amount of usable memory */ + unsigned int videoram_length; + unsigned int auxram_length; + unsigned int auxram_offset; + + char *module_name; + + GraphicsDriverInfo driver_info; + GraphicsDeviceInfo device_info; + void *device_data; + + FusionProperty lock; + GraphicsDeviceLockFlags lock_flags; + + /* + * Points to the current state of the graphics card. + */ + CardState *state; + FusionID holder; /* Fusion ID of state owner. */ +} DFBGraphicsCoreShared; + +struct __DFB_DFBGraphicsCore { + int magic; + + CoreDFB *core; + + DFBGraphicsCoreShared *shared; + + DirectModuleEntry *module; + const GraphicsDriverFuncs *driver_funcs; + + void *driver_data; + void *device_data; /* copy of shared->device_data */ + + CardCapabilities caps; /* local caps */ + CardLimitations limits; /* local limits */ + + GraphicsDeviceFuncs funcs; +}; + + +DFB_CORE_PART( graphics_core, GraphicsCore ); + +/**********************************************************************************************************************/ + +static CoreGraphicsDevice *card; /* FIXME */ + +/* Hook for registering additional screen(s) and layer(s) in app or lib initializing DirectFB. */ +void (*__DFB_CoreRegisterHook)( CoreDFB *core, CoreGraphicsDevice *device, void *ctx ) = NULL; +void *__DFB_CoreRegisterHookCtx = NULL; + + +/** public **/ + +static DFBResult +dfb_graphics_core_initialize( CoreDFB *core, + DFBGraphicsCore *data, + DFBGraphicsCoreShared *shared ) +{ + DFBResult ret; + int videoram_length; + int auxram_length; + FusionSHMPoolShared *pool = dfb_core_shmpool( core ); + + D_DEBUG_AT( Core_Graphics, "dfb_graphics_core_initialize( %p, %p, %p )\n", core, data, shared ); + + D_ASSERT( data != NULL ); + D_ASSERT( shared != NULL ); + + + card = data; /* FIXME */ + + data->core = core; + data->shared = shared; + + + /* fill generic driver info */ + gGetDriverInfo( &shared->driver_info ); + + /* fill generic device info */ + gGetDeviceInfo( &shared->device_info ); + + if (!shared->device_info.limits.dst_max.w) + shared->device_info.limits.dst_max.w = INT_MAX; + + if (!shared->device_info.limits.dst_max.h) + shared->device_info.limits.dst_max.h = INT_MAX; + + /* Limit video ram length */ + videoram_length = dfb_system_videoram_length(); + if (videoram_length) { + if (dfb_config->videoram_limit > 0 && + dfb_config->videoram_limit < videoram_length) + shared->videoram_length = dfb_config->videoram_limit; + else + shared->videoram_length = videoram_length; + } + + /* Limit auxiliary memory length (currently only AGP) */ + auxram_length = dfb_system_auxram_length(); + if (auxram_length) { + if (dfb_config->agpmem_limit > 0 && + dfb_config->agpmem_limit < auxram_length) + shared->auxram_length = dfb_config->agpmem_limit; + else + shared->auxram_length = auxram_length; + } + + /* Build a list of available drivers. */ + direct_modules_explore_directory( &dfb_graphics_drivers ); + + /* Load driver */ + if (dfb_system_caps() & CSCAPS_ACCELERATION) + dfb_gfxcard_find_driver( core ); + + if (data->driver_funcs) { + const GraphicsDriverFuncs *funcs = data->driver_funcs; + + data->driver_data = D_CALLOC( 1, shared->driver_info.driver_data_size ); + + card->device_data = + shared->device_data = SHCALLOC( pool, 1, shared->driver_info.device_data_size ); + + ret = funcs->InitDriver( card, &card->funcs, + card->driver_data, card->device_data, core ); + if (ret) { + SHFREE( pool, shared->device_data ); + SHFREE( pool, shared->module_name ); + D_FREE( card->driver_data ); + card = NULL; + return ret; + } + + ret = funcs->InitDevice( data, &shared->device_info, + data->driver_data, data->device_data ); + if (ret) { + funcs->CloseDriver( card, card->driver_data ); + SHFREE( pool, shared->device_data ); + SHFREE( pool, shared->module_name ); + D_FREE( card->driver_data ); + card = NULL; + return ret; + } + + if (data->funcs.EngineReset) + data->funcs.EngineReset( data->driver_data, data->device_data ); + } + + D_INFO( "DirectFB/Graphics: %s %s %d.%d (%s)\n", + shared->device_info.vendor, shared->device_info.name, + shared->driver_info.version.major, + shared->driver_info.version.minor, shared->driver_info.vendor ); + + if (dfb_config->software_only) { + if (data->funcs.CheckState) { + data->funcs.CheckState = NULL; + + D_INFO( "DirectFB/Graphics: Acceleration disabled (by 'no-hardware')\n" ); + } + } + else { + data->caps = shared->device_info.caps; + data->limits = shared->device_info.limits; + } + + fusion_property_init( &shared->lock, dfb_core_world(core) ); + + if (__DFB_CoreRegisterHook) + __DFB_CoreRegisterHook( core, card, __DFB_CoreRegisterHookCtx ); + + D_MAGIC_SET( data, DFBGraphicsCore ); + D_MAGIC_SET( shared, DFBGraphicsCoreShared ); + + return DFB_OK; +} + +static DFBResult +dfb_graphics_core_join( CoreDFB *core, + DFBGraphicsCore *data, + DFBGraphicsCoreShared *shared ) +{ + DFBResult ret; + GraphicsDriverInfo driver_info; + + D_DEBUG_AT( Core_Graphics, "dfb_graphics_core_join( %p, %p, %p )\n", core, data, shared ); + + D_ASSERT( data != NULL ); + D_MAGIC_ASSERT( shared, DFBGraphicsCoreShared ); + + card = data; /* FIXME */ + + data->core = core; + data->shared = shared; + + /* Initialize software rasterizer. */ + gGetDriverInfo( &driver_info ); + + /* Build a list of available drivers. */ + direct_modules_explore_directory( &dfb_graphics_drivers ); + + /* Load driver. */ + if (dfb_system_caps() & CSCAPS_ACCELERATION) + dfb_gfxcard_load_driver(); + + if (data->driver_funcs) { + const GraphicsDriverFuncs *funcs = data->driver_funcs; + + data->driver_data = D_CALLOC( 1, shared->driver_info.driver_data_size ); + + data->device_data = shared->device_data; + + ret = funcs->InitDriver( card, &card->funcs, + card->driver_data, card->device_data, core ); + if (ret) { + D_FREE( data->driver_data ); + data = NULL; + return ret; + } + } + else if (shared->module_name) { + D_ERROR( "DirectFB/Graphics: Could not load driver used by the running session!\n" ); + data = NULL; + return DFB_UNSUPPORTED; + } + + + D_INFO( "DirectFB/Graphics: %s %s %d.%d (%s)\n", + shared->device_info.vendor, shared->device_info.name, + shared->driver_info.version.major, + shared->driver_info.version.minor, shared->driver_info.vendor ); + + if (dfb_config->software_only) { + if (data->funcs.CheckState) { + data->funcs.CheckState = NULL; + + D_INFO( "DirectFB/Graphics: Acceleration disabled (by 'no-hardware')\n" ); + } + } + else { + data->caps = shared->device_info.caps; + data->limits = shared->device_info.limits; + } + + D_MAGIC_SET( data, DFBGraphicsCore ); + + return DFB_OK; +} + +static DFBResult +dfb_graphics_core_shutdown( DFBGraphicsCore *data, + bool emergency ) +{ + DFBGraphicsCoreShared *shared; + FusionSHMPoolShared *pool = dfb_core_shmpool( data->core ); + + D_DEBUG_AT( Core_Graphics, "dfb_graphics_core_shutdown( %p, %semergency )\n", data, emergency ? "" : "no " ); + + D_MAGIC_ASSERT( data, DFBGraphicsCore ); + D_MAGIC_ASSERT( data->shared, DFBGraphicsCoreShared ); + + shared = data->shared; + + + dfb_gfxcard_lock( GDLF_SYNC ); + + if (data->driver_funcs) { + const GraphicsDriverFuncs *funcs = data->driver_funcs; + + funcs->CloseDevice( data, data->driver_data, data->device_data ); + funcs->CloseDriver( data, data->driver_data ); + + direct_module_unref( data->module ); + + SHFREE( pool, card->device_data ); + D_FREE( card->driver_data ); + } + + fusion_property_destroy( &shared->lock ); + + if (shared->module_name) + SHFREE( pool, shared->module_name ); + + + D_MAGIC_CLEAR( data ); + D_MAGIC_CLEAR( shared ); + + return DFB_OK; +} + +static DFBResult +dfb_graphics_core_leave( DFBGraphicsCore *data, + bool emergency ) +{ + DFBGraphicsCoreShared *shared; + + D_DEBUG_AT( Core_Graphics, "dfb_graphics_core_leave( %p, %semergency )\n", data, emergency ? "" : "no " ); + + D_MAGIC_ASSERT( data, DFBGraphicsCore ); + D_MAGIC_ASSERT( data->shared, DFBGraphicsCoreShared ); + + shared = data->shared; + + if (data->driver_funcs) { + data->driver_funcs->CloseDriver( data, data->driver_data ); + + direct_module_unref( data->module ); + + D_FREE( data->driver_data ); + } + + + D_MAGIC_CLEAR( data ); + + return DFB_OK; +} + +static DFBResult +dfb_graphics_core_suspend( DFBGraphicsCore *data ) +{ + DFBGraphicsCoreShared *shared; + + D_DEBUG_AT( Core_Graphics, "dfb_graphics_core_suspend( %p )\n", data ); + + D_MAGIC_ASSERT( data, DFBGraphicsCore ); + D_MAGIC_ASSERT( data->shared, DFBGraphicsCoreShared ); + + shared = data->shared; + + dfb_gfxcard_lock( GDLF_WAIT | GDLF_SYNC | GDLF_RESET | GDLF_INVALIDATE ); + + return DFB_OK; +} + +static DFBResult +dfb_graphics_core_resume( DFBGraphicsCore *data ) +{ + DFBGraphicsCoreShared *shared; + + D_DEBUG_AT( Core_Graphics, "dfb_graphics_core_resume( %p )\n", data ); + + D_MAGIC_ASSERT( data, DFBGraphicsCore ); + D_MAGIC_ASSERT( data->shared, DFBGraphicsCoreShared ); + + shared = data->shared; + + dfb_gfxcard_unlock(); + + return DFB_OK; +} + +/**********************************************************************************************************************/ + +DFBResult +dfb_gfxcard_lock( GraphicsDeviceLockFlags flags ) +{ + DFBResult ret; + DFBGraphicsCoreShared *shared; + GraphicsDeviceFuncs *funcs; + + D_ASSERT( card != NULL ); + D_ASSERT( card->shared != NULL ); + + shared = card->shared; + funcs = &card->funcs; + + if ( ((flags & GDLF_WAIT) ? + fusion_property_purchase( &shared->lock ) : + fusion_property_lease( &shared->lock )) ) + return DFB_FAILURE; + + if ((flags & GDLF_SYNC) && funcs->EngineSync) { + ret = funcs->EngineSync( card->driver_data, card->device_data ); + if (ret) { + if (funcs->EngineReset) + funcs->EngineReset( card->driver_data, card->device_data ); + + shared->state = NULL; + + fusion_property_cede( &shared->lock ); + + return ret; + } + } + + if ((shared->lock_flags & GDLF_RESET) && funcs->EngineReset) + funcs->EngineReset( card->driver_data, card->device_data ); + + if (shared->lock_flags & GDLF_INVALIDATE) { + if (funcs->InvalidateState) + funcs->InvalidateState( card->driver_data, card->device_data ); + shared->state = NULL; + } + + shared->lock_flags = flags; + + return DFB_OK; +} + +void +dfb_gfxcard_unlock( void ) +{ + D_ASSERT( card != NULL ); + D_ASSERT( card->shared != NULL ); + + fusion_property_cede( &card->shared->lock ); +} + +void +dfb_gfxcard_holdup( void ) +{ + D_ASSERT( card != NULL ); + D_ASSERT( card->shared != NULL ); + + fusion_property_holdup( &card->shared->lock ); +} + +/* + * Signal beginning of a sequence of operations using this state. + * Any number of states can be 'drawing'. + */ +void +dfb_gfxcard_start_drawing( CoreGraphicsDevice *device, CardState *state ) +{ + D_ASSERT( device != NULL ); + D_MAGIC_ASSERT( state, CardState ); + + if (device->funcs.StartDrawing) + device->funcs.StartDrawing( device->driver_data, device->device_data, state ); +} + +/* + * Signal end of sequence, i.e. destination surface is consistent again. + */ +void +dfb_gfxcard_stop_drawing( CoreGraphicsDevice *device, CardState *state ) +{ + D_ASSERT( device != NULL ); + D_MAGIC_ASSERT( state, CardState ); + + if (device->funcs.StopDrawing) + device->funcs.StopDrawing( device->driver_data, device->device_data, state ); +} + +/* + * This function returns non zero if acceleration is available + * for the specific function using the given state. + */ +bool +dfb_gfxcard_state_check( CardState *state, DFBAccelerationMask accel ) +{ + CoreSurface *dst; + CoreSurface *src; + CoreSurfaceBuffer *dst_buffer; + CoreSurfaceBuffer *src_buffer; + + int cx2, cy2; + + D_ASSERT( card != NULL ); + D_MAGIC_ASSERT( state, CardState ); + D_MAGIC_ASSERT_IF( state->destination, CoreSurface ); + D_MAGIC_ASSERT_IF( state->source, CoreSurface ); + + D_DEBUG_AT( Core_GraphicsOps, "%s( %p, 0x%08x ) [%d,%d - %d,%d]\n", + __FUNCTION__, state, accel, DFB_REGION_VALS( &state->clip ) ); + + D_ASSERT( state->clip.x2 >= state->clip.x1 ); + D_ASSERT( state->clip.y2 >= state->clip.y1 ); + D_ASSERT( state->clip.x1 >= 0 ); + D_ASSERT( state->clip.y1 >= 0 ); + + if (DFB_BLITTING_FUNCTION(accel)) { + D_DEBUG_AT( Core_GfxState, "%s( %p, 0x%08x ) blitting %p -> %p\n", __FUNCTION__, + state, accel, state->source, state->destination ); + } + else { + D_DEBUG_AT( Core_GfxState, "%s( %p, 0x%08x ) drawing -> %p\n", __FUNCTION__, + state, accel, state->destination ); + } + + if (state->clip.x1 < 0) { + state->clip.x1 = 0; + state->modified |= SMF_CLIP; + } + + if (state->clip.y1 < 0) { + state->clip.y1 = 0; + state->modified |= SMF_CLIP; + } + + D_DEBUG_AT( Core_GfxState, " <- checked 0x%08x, accel 0x%08x, modified 0x%08x, mod_hw 0x%08x\n", + state->checked, state->accel, state->modified, state->mod_hw ); + + dst = state->destination; + src = state->source; + + /* Destination may have been destroyed. */ + if (!dst) { + D_BUG( "no destination" ); + return false; + } + + /* Source may have been destroyed. */ + if (DFB_BLITTING_FUNCTION( accel )) { + if (!src) { + D_BUG( "no source" ); + return false; + } + + /* Mask may have been destroyed. */ + if (state->blittingflags & (DSBLIT_SRC_MASK_ALPHA | DSBLIT_SRC_MASK_COLOR) && !state->source_mask) { + D_BUG( "no mask" ); + return false; + } + } + + dst_buffer = dfb_surface_get_buffer( dst, state->to ); + D_MAGIC_ASSERT( dst_buffer, CoreSurfaceBuffer ); + + D_ASSUME( state->clip.x2 < dst->config.size.w ); + D_ASSUME( state->clip.y2 < dst->config.size.h ); + + cx2 = state->destination->config.size.w - 1; + cy2 = state->destination->config.size.h - 1; + + if (state->clip.x2 > cx2) { + state->clip.x2 = cx2; + + if (state->clip.x1 > cx2) + state->clip.x1 = cx2; + + state->modified |= SMF_CLIP; + } + + if (state->clip.y2 > cy2) { + state->clip.y2 = cy2; + + if (state->clip.y1 > cy2) + state->clip.y1 = cy2; + + state->modified |= SMF_CLIP; + } + + + /* + * If there's no CheckState function there's no acceleration at all. + */ + if (!card->funcs.CheckState) + return false; + + /* + * Check if this function has been disabled temporarily. + */ + if (state->disabled & accel) + return false; + + /* If destination or blend functions have been changed... */ + if (state->modified & (SMF_DESTINATION | SMF_SRC_BLEND | SMF_DST_BLEND | SMF_RENDER_OPTIONS)) { + /* ...force rechecking for all functions. */ + state->checked = DFXL_NONE; + } + else { + /* If source/mask or blitting flags have been changed... */ + if (state->modified & (SMF_SOURCE | SMF_BLITTING_FLAGS | SMF_SOURCE_MASK | SMF_SOURCE_MASK_VALS)) { + /* ...force rechecking for all blitting functions. */ + state->checked &= ~DFXL_ALL_BLIT; + } + + /* If drawing flags have been changed... */ + if (state->modified & SMF_DRAWING_FLAGS) { + /* ...force rechecking for all drawing functions. */ + state->checked &= ~DFXL_ALL_DRAW; + } + } + + D_DEBUG_AT( Core_GfxState, " -> checked 0x%08x, accel 0x%08x, modified 0x%08x, mod_hw 0x%08x\n", + state->checked, state->accel, state->modified, state->mod_hw ); + + /* If the function needs to be checked... */ + if (!(state->checked & accel)) { + /* Unset unchecked functions. */ + state->accel &= state->checked; + + /* Call driver to (re)set the bit if the function is supported. */ + card->funcs.CheckState( card->driver_data, card->device_data, state, accel ); + + /* Add the function to 'checked functions'. */ + state->checked |= accel; + + /* Add additional functions the driver might have checked, too. */ + state->checked |= state->accel; + } + + D_DEBUG_AT( Core_GfxState, " -> checked 0x%08x, accel 0x%08x, modified 0x%08x, mod_hw 0x%08x\n", + state->checked, state->accel, state->modified, state->mod_hw ); + + /* Move modification flags to the set for drivers. */ + state->mod_hw |= state->modified; + state->modified = 0; + + /* + * If back_buffer policy is 'system only' there's no acceleration + * available. + */ + if (dst_buffer->policy == CSP_SYSTEMONLY || /* Special check required if driver does not check itself. */ + ( !(card->caps.flags & CCF_RENDEROPTS) && + (state->render_options & DSRO_MATRIX) )) + { + /* Clear 'accelerated functions'. */ + state->accel = DFXL_NONE; + state->checked = DFXL_ALL; + } + else if (DFB_BLITTING_FUNCTION( accel )) { + /* + * If the front buffer policy of the source is 'system only' + * no accelerated blitting is available. + */ + src_buffer = dfb_surface_get_buffer( src, state->from ); + + D_MAGIC_ASSERT( src_buffer, CoreSurfaceBuffer ); + + if (src_buffer->policy == CSP_SYSTEMONLY && !(card->caps.flags & CCF_READSYSMEM)) { + /* Clear 'accelerated blitting functions'. */ + state->accel &= ~DFXL_ALL_BLIT; + state->checked |= DFXL_ALL_BLIT; + } + } + + D_DEBUG_AT( Core_GfxState, " => checked 0x%08x, accel 0x%08x, modified 0x%08x, mod_hw 0x%08x\n", + state->checked, state->accel, state->modified, state->mod_hw ); + + /* Return whether the function bit is set. */ + return !!(state->accel & accel); +} + +/* + * This function returns non zero after successful locking the surface(s) + * for access by hardware. Propagate state changes to driver. + */ +static bool +dfb_gfxcard_state_acquire( CardState *state, DFBAccelerationMask accel ) +{ + DFBResult ret; + CoreSurface *dst; + CoreSurface *src; + DFBGraphicsCoreShared *shared; + CoreSurfaceAccessFlags access = CSAF_WRITE; + + D_ASSERT( card != NULL ); + D_ASSERT( card->shared != NULL ); + + D_MAGIC_ASSERT( state, CardState ); + D_MAGIC_ASSERT_IF( state->destination, CoreSurface ); + D_MAGIC_ASSERT_IF( state->source, CoreSurface ); + + dst = state->destination; + src = state->source; + shared = card->shared; + + /* find locking flags */ + if (DFB_BLITTING_FUNCTION( accel )) { + if (state->blittingflags & (DSBLIT_BLEND_ALPHACHANNEL | + DSBLIT_BLEND_COLORALPHA | + DSBLIT_DST_COLORKEY)) + access |= CSAF_READ; + } + else if (state->drawingflags & (DSDRAW_BLEND | DSDRAW_DST_COLORKEY)) + access |= CSAF_READ; + + if (DFB_BLITTING_FUNCTION(accel)) { + D_DEBUG_AT( Core_GfxState, "%s( %p, 0x%08x ) blitting %p -> %p\n", __FUNCTION__, + state, accel, state->source, state->destination ); + } + else { + D_DEBUG_AT( Core_GfxState, "%s( %p, 0x%08x ) drawing -> %p\n", __FUNCTION__, + state, accel, state->destination ); + } + + /* lock destination */ + ret = dfb_surface_lock_buffer( dst, state->to, CSAID_GPU, access, &state->dst ); + if (ret) { + D_DEBUG_AT( Core_Graphics, "Could not lock destination for GPU access!\n" ); + return false; + } + + /* if blitting... */ + if (DFB_BLITTING_FUNCTION( accel )) { + /* ...lock source for reading */ + ret = dfb_surface_lock_buffer( src, state->from, CSAID_GPU, CSAF_READ, &state->src ); + if (ret) { + D_DEBUG_AT( Core_Graphics, "Could not lock source for GPU access!\n" ); + dfb_surface_unlock_buffer( dst, &state->dst ); + return false; + } + + state->flags |= CSF_SOURCE_LOCKED; + + /* if using a mask... */ + if (state->blittingflags & (DSBLIT_SRC_MASK_ALPHA | DSBLIT_SRC_MASK_COLOR)) { + /* ...lock source mask for reading */ + ret = dfb_surface_lock_buffer( state->source_mask, state->from, CSAID_GPU, CSAF_READ, &state->src_mask ); + if (ret) { + D_DEBUG_AT( Core_Graphics, "Could not lock source mask for GPU access!\n" ); + dfb_surface_unlock_buffer( src, &state->src ); + dfb_surface_unlock_buffer( dst, &state->dst ); + return false; + } + + state->flags |= CSF_SOURCE_MASK_LOCKED; + } + } + + /* + * Make sure that state setting with subsequent command execution + * isn't done by two processes simultaneously. + * + * This will timeout if the hardware is locked by another party with + * the first argument being true (e.g. DRI). + */ + if (dfb_gfxcard_lock( GDLF_NONE )) { + D_DERROR( ret, "Core/Graphics: Could not lock GPU!\n" ); + + dfb_surface_unlock_buffer( dst, &state->dst ); + + if (state->flags & CSF_SOURCE_LOCKED) { + dfb_surface_unlock_buffer( src, &state->src ); + state->flags &= ~CSF_SOURCE_LOCKED; + } + + /* if source mask got locked this value is true */ + if (state->flags & CSF_SOURCE_MASK_LOCKED) { + dfb_surface_unlock_buffer( state->source_mask, &state->src_mask ); + + state->flags &= ~CSF_SOURCE_MASK_LOCKED; + } + + return false; + } + + /* if we are switching to another state... */ + if (state != shared->state || state->fusion_id != shared->holder) { + D_DEBUG_AT( Core_GfxState, " -> switch from %p [%lu] to %p [%lu]\n", + shared->state, shared->holder, state, state->fusion_id ); + + /* ...set all modification bits and clear 'set functions' */ + state->mod_hw |= SMF_ALL; + state->set = 0; + + shared->state = state; + shared->holder = state->fusion_id; + } + + dfb_state_update( state, state->flags & (CSF_SOURCE_LOCKED | CSF_SOURCE_MASK_LOCKED) ); + + D_DEBUG_AT( Core_GfxState, " -> mod_hw 0x%08x, modified 0x%08x\n", state->mod_hw, state->modified ); + + /* Move modification flags to the set for drivers. */ + state->mod_hw |= state->modified; + state->modified = SMF_ALL; + + /* + * If function hasn't been set or state is modified, + * call the driver function to propagate the state changes. + */ + D_DEBUG_AT( Core_GfxState, " -> mod_hw 0x%08x, set 0x%08x\n", state->mod_hw, state->set ); + if (state->mod_hw || !(state->set & accel)) { + card->funcs.SetState( card->driver_data, card->device_data, + &card->funcs, state, accel ); + + D_DEBUG_AT( Core_GfxState, " => mod_hw 0x%08x, set 0x%08x\n", state->mod_hw, state->set ); + } + + if (state->modified != SMF_ALL) + D_ONCE( "USING OLD DRIVER! *** Use 'state->mod_hw' NOT 'modified'." ); + + state->modified = 0; + + return true; +} + +/* + * Unlock destination and possibly the source. + */ +static void +dfb_gfxcard_state_release( CardState *state ) +{ + D_ASSERT( card != NULL ); + D_ASSERT( card->shared != NULL ); + D_MAGIC_ASSERT( state, CardState ); + D_ASSERT( state->destination != NULL ); + + /* start command processing if not already running */ + if (card->funcs.EmitCommands) + card->funcs.EmitCommands( card->driver_data, card->device_data ); + + /* Store the serial of the operation. */ +#if FIXME_SC_2 + if (card->funcs.GetSerial) { + card->funcs.GetSerial( card->driver_data, card->device_data, &state->serial ); + + state->destination->back_buffer->video.serial = state->serial; + } +#endif + + /* allow others to use the hardware */ + dfb_gfxcard_unlock(); + + /* destination always gets locked during acquisition */ + dfb_surface_unlock_buffer( state->destination, &state->dst ); + + /* if source got locked this value is true */ + if (state->flags & CSF_SOURCE_LOCKED) { + dfb_surface_unlock_buffer( state->source, &state->src ); + + state->flags &= ~CSF_SOURCE_LOCKED; + } + + /* if source mask got locked this value is true */ + if (state->flags & CSF_SOURCE_MASK_LOCKED) { + dfb_surface_unlock_buffer( state->source_mask, &state->src_mask ); + + state->flags &= ~CSF_SOURCE_MASK_LOCKED; + } +} + +/** DRAWING FUNCTIONS **/ + +#define DFB_TRANSFORM(x, y, m, affine) \ +do { \ + s32 _x, _y, _w; \ + if (affine) { \ + _x = ((x) * (m)[0] + (y) * (m)[1] + (m)[2] + 0x8000) >> 16; \ + _y = ((x) * (m)[3] + (y) * (m)[4] + (m)[5] + 0x8000) >> 16; \ + } \ + else { \ + _x = ((x) * (m)[0] + (y) * (m)[1] + (m)[2]); \ + _y = ((x) * (m)[3] + (y) * (m)[4] + (m)[5]); \ + _w = ((x) * (m)[6] + (y) * (m)[7] + (m)[8]); \ + if (!_w) { \ + _x = (_x < 0) ? -0x7fffffff : 0x7fffffff; \ + _y = (_y < 0) ? -0x7fffffff : 0x7fffffff; \ + } \ + else { \ + _x /= _w; \ + _y /= _w; \ + } \ + } \ + (x) = _x; \ + (y) = _y; \ +} while (0) + +void +dfb_gfxcard_fillrectangles( const DFBRectangle *rects, int num, CardState *state ) +{ + D_DEBUG_AT( Core_GraphicsOps, "%s( %p [%d], %p )\n", __FUNCTION__, rects, num, state ); + + D_ASSERT( card != NULL ); + D_ASSERT( card->shared != NULL ); + D_MAGIC_ASSERT( state, CardState ); + D_ASSERT( rects != NULL ); + D_ASSERT( num > 0 ); + + /* The state is locked during graphics operations. */ + dfb_state_lock( state ); + + /* Signal beginning of sequence of operations if not already done. */ + dfb_state_start_drawing( state, card ); + + if (!(state->render_options & DSRO_MATRIX)) { + while (num > 0) { + if (dfb_rectangle_region_intersects( rects, &state->clip )) + break; + + rects++; + num--; + } + } + + if (num > 0) { + int i = 0; + DFBRectangle rect; + + /* Check for acceleration and setup execution. */ + if (dfb_gfxcard_state_check( state, DFXL_FILLRECTANGLE ) && + dfb_gfxcard_state_acquire( state, DFXL_FILLRECTANGLE )) + { + /* + * Now everything is prepared for execution of the + * FillRectangle driver function. + */ + for (; irender_options & DSRO_MATRIX) && + !dfb_rectangle_region_intersects( &rects[i], &state->clip )) + continue; + + rect = rects[i]; + + if (rect.w > card->limits.dst_max.w || rect.h > card->limits.dst_max.h) { + dfb_clip_rectangle( &state->clip, &rect ); + + if (rect.w > card->limits.dst_max.w || rect.h > card->limits.dst_max.h) + break; + } + else if (!D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) && + !D_FLAGS_IS_SET( card->caps.clip, DFXL_FILLRECTANGLE )) + dfb_clip_rectangle( &state->clip, &rect ); + + if (!card->funcs.FillRectangle( card->driver_data, + card->device_data, &rect )) + break; + } + + /* Release after state acquisition. */ + dfb_gfxcard_state_release( state ); + } + + if (i < num) { + /* Use software fallback. */ + if (gAcquire( state, DFXL_FILLRECTANGLE )) { + if (!(state->render_options & DSRO_MATRIX)) { + for (; iclip, &rect )) + gFillRectangle( state, &rect ); + } + } + else if (state->matrix[1] == 0 && state->matrix[3] == 0) { + /* Scaled/Translated Rectangle. */ + for (; imatrix, state->affine_matrix); + DFB_TRANSFORM(x2, y2, state->matrix, state->affine_matrix); + + if (x1 < x2) { + rect.x = x1; + rect.w = x2-x1; + } else { + rect.x = x2; + rect.w = x1-x2; + } + if (y1 < y2) { + rect.y = y1; + rect.h = y2-y1; + } + else { + rect.y = y2; + rect.h = y1-y2; + } + + if (dfb_clip_rectangle( &state->clip, &rect )) + gFillRectangle( state, &rect ); + } + } + else { + /* Rotated rectangle. Split into triangles. */ + for (; imatrix, state->affine_matrix); + DFB_TRANSFORM(tri.x2, tri.y2, state->matrix, state->affine_matrix); + DFB_TRANSFORM(tri.x3, tri.y3, state->matrix, state->affine_matrix); + + dfb_sort_triangle( &tri ); + if (tri.y3 - tri.y1 > 0) + fill_tri( &tri, state, false ); + + tri.x1 = rects[i].x; tri.y1 = rects[i].y; + tri.x2 = rects[i].x+rects[i].w; tri.y2 = rects[i].y+rects[i].h; + tri.x3 = rects[i].x; tri.y3 = rects[i].y+rects[i].h; + DFB_TRANSFORM(tri.x1, tri.y1, state->matrix, state->affine_matrix); + DFB_TRANSFORM(tri.x2, tri.y2, state->matrix, state->affine_matrix); + DFB_TRANSFORM(tri.x3, tri.y3, state->matrix, state->affine_matrix); + + dfb_sort_triangle( &tri ); + if (tri.y3 - tri.y1 > 0) + fill_tri( &tri, state, false ); + } + } + + gRelease( state ); + } + } + } + + /* Unlock after execution. */ + dfb_state_unlock( state ); +} + +static void +build_clipped_rectangle_outlines( DFBRectangle *rect, + const DFBRegion *clip, + DFBRectangle *ret_outlines, + int *ret_num ) +{ + DFBEdgeFlags edges = dfb_clip_edges( clip, rect ); + int t = (edges & DFEF_TOP ? 1 : 0); + int tb = t + (edges & DFEF_BOTTOM ? 1 : 0); + int num = 0; + + DFB_RECTANGLE_ASSERT( rect ); + + D_ASSERT( ret_outlines != NULL ); + D_ASSERT( ret_num != NULL ); + + if (edges & DFEF_TOP) { + DFBRectangle *out = &ret_outlines[num++]; + + out->x = rect->x; + out->y = rect->y; + out->w = rect->w; + out->h = 1; + } + + if (rect->h > t) { + if (edges & DFEF_BOTTOM) { + DFBRectangle *out = &ret_outlines[num++]; + + out->x = rect->x; + out->y = rect->y + rect->h - 1; + out->w = rect->w; + out->h = 1; + } + + if (rect->h > tb) { + if (edges & DFEF_LEFT) { + DFBRectangle *out = &ret_outlines[num++]; + + out->x = rect->x; + out->y = rect->y + t; + out->w = 1; + out->h = rect->h - tb; + } + + if (rect->w > 1 || !(edges & DFEF_LEFT)) { + if (edges & DFEF_RIGHT) { + DFBRectangle *out = &ret_outlines[num++]; + + out->x = rect->x + rect->w - 1; + out->y = rect->y + t; + out->w = 1; + out->h = rect->h - tb; + } + } + } + } + + *ret_num = num; +} + +void dfb_gfxcard_drawrectangle( DFBRectangle *rect, CardState *state ) +{ + DFBRectangle rects[4]; + bool hw = false; + int i = 0, num = 0; + + D_ASSERT( card != NULL ); + D_ASSERT( card->shared != NULL ); + D_MAGIC_ASSERT( state, CardState ); + DFB_RECTANGLE_ASSERT( rect ); + + D_DEBUG_AT( Core_GraphicsOps, "%s( %d,%d - %dx%d, %p )\n", __FUNCTION__, DFB_RECTANGLE_VALS(rect), state ); + + /* The state is locked during graphics operations. */ + dfb_state_lock( state ); + + /* Signal beginning of sequence of operations if not already done. */ + dfb_state_start_drawing( state, card ); + + if (!dfb_rectangle_region_intersects( rect, &state->clip )) { + dfb_state_unlock( state ); + return; + } + + if (D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) || + D_FLAGS_IS_SET( card->caps.clip, DFXL_DRAWRECTANGLE ) || + !dfb_clip_needed( &state->clip, rect )) + { + if (rect->w <= card->limits.dst_max.w && rect->h <= card->limits.dst_max.h && + dfb_gfxcard_state_check( state, DFXL_DRAWRECTANGLE ) && + dfb_gfxcard_state_acquire( state, DFXL_DRAWRECTANGLE )) + { + hw = card->funcs.DrawRectangle( card->driver_data, + card->device_data, rect ); + + dfb_gfxcard_state_release( state ); + } + } + + if (!hw && !(state->render_options & DSRO_MATRIX)) { + build_clipped_rectangle_outlines( rect, &state->clip, rects, &num ); + + if (!num) { + dfb_state_unlock( state ); + return; + } + + if (dfb_gfxcard_state_check( state, DFXL_FILLRECTANGLE ) && + dfb_gfxcard_state_acquire( state, DFXL_FILLRECTANGLE )) + { + for (; ilimits.dst_max.w && rects[i].h <= card->limits.dst_max.h + && card->funcs.FillRectangle( card->driver_data, + card->device_data, &rects[i] ); + if (!hw) + break; + } + + dfb_gfxcard_state_release( state ); + } + } + + if (!hw) { + if (!(state->render_options & DSRO_MATRIX)) { + if (gAcquire( state, DFXL_FILLRECTANGLE )) { + for (; ix; y1 = rect->y; + x2 = rect->x+rect->w; y2 = rect->y; + x3 = rect->x+rect->w; y3 = rect->y+rect->h; + x4 = rect->x; y4 = rect->y+rect->h; + DFB_TRANSFORM(x1, y1, state->matrix, state->affine_matrix); + DFB_TRANSFORM(x2, y2, state->matrix, state->affine_matrix); + DFB_TRANSFORM(x3, y3, state->matrix, state->affine_matrix); + DFB_TRANSFORM(x4, y4, state->matrix, state->affine_matrix); + + line = (DFBRegion) { x1, y1, x2, y2 }; + if (dfb_clip_line( &state->clip, &line )) + gDrawLine( state, &line ); + + line = (DFBRegion) { x2, y2, x3, y3 }; + if (dfb_clip_line( &state->clip, &line )) + gDrawLine( state, &line ); + + line = (DFBRegion) { x3, y3, x4, y4 }; + if (dfb_clip_line( &state->clip, &line )) + gDrawLine( state, &line ); + + line = (DFBRegion) { x4, y4, x1, y1 }; + if (dfb_clip_line( &state->clip, &line )) + gDrawLine( state, &line ); + + gRelease( state ); + } + } + } + + dfb_state_unlock( state ); +} + +void dfb_gfxcard_drawlines( DFBRegion *lines, int num_lines, CardState *state ) +{ + int i = 0; + + D_DEBUG_AT( Core_GraphicsOps, "%s( %p [%d], %p )\n", __FUNCTION__, lines, num_lines, state ); + + D_ASSERT( card != NULL ); + D_ASSERT( card->shared != NULL ); + D_MAGIC_ASSERT( state, CardState ); + D_ASSERT( lines != NULL ); + D_ASSERT( num_lines > 0 ); + + /* The state is locked during graphics operations. */ + dfb_state_lock( state ); + + /* Signal beginning of sequence of operations if not already done. */ + dfb_state_start_drawing( state, card ); + + if (dfb_gfxcard_state_check( state, DFXL_DRAWLINE ) && + dfb_gfxcard_state_acquire( state, DFXL_DRAWLINE )) + { + for (; icaps.flags, CCF_CLIPPING ) && + !D_FLAGS_IS_SET( card->caps.clip, DFXL_DRAWLINE ) && + !dfb_clip_line( &state->clip, &lines[i] )) + continue; + + if (!card->funcs.DrawLine( card->driver_data, + card->device_data, &lines[i] )) + break; + } + + dfb_gfxcard_state_release( state ); + } + + if (i < num_lines) { + if (gAcquire( state, DFXL_DRAWLINE )) { + for (; irender_options & DSRO_MATRIX) { + DFB_TRANSFORM(lines[i].x1, lines[i].y1, state->matrix, state->affine_matrix); + DFB_TRANSFORM(lines[i].x2, lines[i].y2, state->matrix, state->affine_matrix); + } + + if (dfb_clip_line( &state->clip, &lines[i] )) + gDrawLine( state, &lines[i] ); + } + + gRelease( state ); + } + } + + dfb_state_unlock( state ); +} + +void dfb_gfxcard_fillspans( int y, DFBSpan *spans, int num_spans, CardState *state ) +{ + int i = 0; + + D_DEBUG_AT( Core_GraphicsOps, "%s( %d, %p [%d], %p )\n", __FUNCTION__, y, spans, num_spans, state ); + + D_ASSERT( card != NULL ); + D_ASSERT( card->shared != NULL ); + D_MAGIC_ASSERT( state, CardState ); + D_ASSERT( spans != NULL ); + D_ASSERT( num_spans > 0 ); + + /* The state is locked during graphics operations. */ + dfb_state_lock( state ); + + /* Signal beginning of sequence of operations if not already done. */ + dfb_state_start_drawing( state, card ); + + if (dfb_gfxcard_state_check( state, DFXL_FILLRECTANGLE ) && + dfb_gfxcard_state_acquire( state, DFXL_FILLRECTANGLE )) + { + for (; i card->limits.dst_max.w || rect.h > card->limits.dst_max.h) { + if (!dfb_clip_rectangle( &state->clip, &rect )) + continue; + + if (rect.w > card->limits.dst_max.w || rect.h > card->limits.dst_max.h) + break; + } + else if (!D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) && + !D_FLAGS_IS_SET( card->caps.clip, DFXL_FILLRECTANGLE ) && + !dfb_clip_rectangle( &state->clip, &rect )) + continue; + + if (!card->funcs.FillRectangle( card->driver_data, + card->device_data, &rect )) + break; + } + + dfb_gfxcard_state_release( state ); + } + + if (i < num_spans) { + if (gAcquire( state, DFXL_FILLRECTANGLE )) { + for (; irender_options & DSRO_MATRIX) { + if (state->matrix[1] == 0 && state->matrix[3] == 0) { + int x1, y1, x2, y2; + + x1 = rect.x; y1 = rect.y; + x2 = x1+rect.w; y2 = y1+rect.h; + DFB_TRANSFORM(x1, y1, state->matrix, state->affine_matrix); + DFB_TRANSFORM(x2, y2, state->matrix, state->affine_matrix); + + if (x1 < x2) { + rect.x = x1; + rect.w = x2-x1; + } else { + rect.x = x2; + rect.w = x1-x2; + } + if (y1 < y2) { + rect.y = y1; + rect.h = y2-y1; + } + else { + rect.y = y2; + rect.h = y1-y2; + } + + if (dfb_clip_rectangle( &state->clip, &rect )) + gFillRectangle( state, &rect ); + } + else { + DFBTriangle tri; + + tri.x1 = rect.x; tri.y1 = rect.y; + tri.x2 = rect.x+rect.w; tri.y2 = rect.y; + tri.x3 = rect.x+rect.w; tri.y3 = rect.y+rect.h; + DFB_TRANSFORM(tri.x1, tri.y1, state->matrix, state->affine_matrix); + DFB_TRANSFORM(tri.x2, tri.y2, state->matrix, state->affine_matrix); + DFB_TRANSFORM(tri.x3, tri.y3, state->matrix, state->affine_matrix); + + dfb_sort_triangle( &tri ); + if (tri.y3 - tri.y1 > 0) + fill_tri( &tri, state, false ); + + tri.x1 = rect.x; tri.y1 = rect.y; + tri.x2 = rect.x+rect.w; tri.y2 = rect.y+rect.h; + tri.x3 = rect.x; tri.y3 = rect.y+rect.h; + DFB_TRANSFORM(tri.x1, tri.y1, state->matrix, state->affine_matrix); + DFB_TRANSFORM(tri.x2, tri.y2, state->matrix, state->affine_matrix); + DFB_TRANSFORM(tri.x3, tri.y3, state->matrix, state->affine_matrix); + + dfb_sort_triangle( &tri ); + if (tri.y3 - tri.y1 > 0) + fill_tri( &tri, state, false ); + } + } + else { + if (dfb_clip_rectangle( &state->clip, &rect )) + gFillRectangle( state, &rect ); + } + } + + gRelease( state ); + } + } + + dfb_state_unlock( state ); +} + + +typedef struct { + int xi; + int xf; + int mi; + int mf; + int _2dy; +} DDA; + +#define SETUP_DDA(xs,ys,xe,ye,dda) \ + do { \ + int dx = xe - xs; \ + int dy = ye - ys; \ + dda.xi = xs; \ + if (dy != 0) { \ + dda.mi = dx / dy; \ + dda.mf = 2*(dx % dy); \ + dda.xf = -dy; \ + dda._2dy = 2 * dy; \ + if (dda.mf < 0) { \ + dda.mf += 2 * ABS(dy); \ + dda.mi--; \ + } \ + } \ + else { \ + dda.mi = 0; \ + dda.mf = 0; \ + dda.xf = 0; \ + dda._2dy = 0; \ + } \ + } while (0) + + +#define INC_DDA(dda) \ + do { \ + dda.xi += dda.mi; \ + dda.xf += dda.mf; \ + if (dda.xf > 0) { \ + dda.xi++; \ + dda.xf -= dda._2dy; \ + } \ + } while (0) + + +/** + * render a triangle using two parallel DDA's + */ +static void +fill_tri( DFBTriangle *tri, CardState *state, bool accelerated ) +{ + int y, yend; + DDA dda1 = { .xi = 0 }, dda2 = { .xi = 0 }; + int clip_x1 = state->clip.x1; + int clip_x2 = state->clip.x2; + + D_MAGIC_ASSERT( state, CardState ); + + y = tri->y1; + yend = tri->y3; + + if (yend > state->clip.y2) + yend = state->clip.y2; + + SETUP_DDA(tri->x1, tri->y1, tri->x3, tri->y3, dda1); + SETUP_DDA(tri->x1, tri->y1, tri->x2, tri->y2, dda2); + + while (y <= yend) { + DFBRectangle rect; + + if (y == tri->y2) { + if (tri->y2 == tri->y3) + return; + SETUP_DDA(tri->x2, tri->y2, tri->x3, tri->y3, dda2); + } + + rect.w = ABS(dda1.xi - dda2.xi); + rect.x = MIN(dda1.xi, dda2.xi); + + if (clip_x2 < rect.x + rect.w) + rect.w = clip_x2 - rect.x + 1; + + if (rect.w > 0) { + if (clip_x1 > rect.x) { + rect.w -= (clip_x1 - rect.x); + rect.x = clip_x1; + } + rect.y = y; + rect.h = 1; + + if (rect.w > 0 && rect.y >= state->clip.y1) { + if (accelerated) + card->funcs.FillRectangle( card->driver_data, + card->device_data, &rect ); + else + gFillRectangle( state, &rect ); + } + } + + INC_DDA(dda1); + INC_DDA(dda2); + + y++; + } +} + + +void dfb_gfxcard_filltriangles( const DFBTriangle *tris, int num, CardState *state ) +{ + bool hw = false; + int i = 0; + + D_ASSERT( card != NULL ); + D_ASSERT( card->shared != NULL ); + D_MAGIC_ASSERT( state, CardState ); + D_ASSERT( tris != NULL ); + D_ASSERT( num > 0 ); + + D_DEBUG_AT( Core_GraphicsOps, "%s( %p [%d], %p )\n", __FUNCTION__, tris, num, state ); + + /* The state is locked during graphics operations. */ + dfb_state_lock( state ); + + /* Signal beginning of sequence of operations if not already done. */ + dfb_state_start_drawing( state, card ); + + if (dfb_gfxcard_state_check( state, DFXL_FILLTRIANGLE ) && + dfb_gfxcard_state_acquire( state, DFXL_FILLTRIANGLE )) + { + if (!D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) && + !D_FLAGS_IS_SET( card->caps.clip, DFXL_FILLTRIANGLE )) + { + DFBPoint p[6]; + int n; + + for (; i < num; i++) { + /* FIXME: DSRO_MATRIX. */ + if (dfb_clip_triangle( &state->clip, &tris[i], p, &n )) { + DFBTriangle tri; + int j; + + tri.x1 = p[0].x; tri.y1 = p[0].y; + tri.x2 = p[1].x; tri.y2 = p[1].y; + tri.x3 = p[2].x; tri.y3 = p[2].y; + hw = card->funcs.FillTriangle( card->driver_data, + card->device_data, &tri ); + if (!hw) + break; + + /* FIXME: return value. */ + for (j = 3; j < n; j++) { + tri.x1 = p[0].x; tri.y1 = p[0].y; + tri.x2 = p[j-1].x; tri.y2 = p[j-1].y; + tri.x3 = p[j].x; tri.y3 = p[j].y; + card->funcs.FillTriangle( card->driver_data, + card->device_data, &tri ); + } + } + } + } + else { + for (; i < num; i++) { + DFBTriangle tri = tris[i]; + + hw = card->funcs.FillTriangle( card->driver_data, + card->device_data, &tri ); + if (!hw) + break; + } + + } + + dfb_gfxcard_state_release( state ); + } + + if (!hw && i < num) { + /* otherwise use the spanline rasterizer (fill_tri) + and fill the triangle using a rectangle for each spanline */ + + /* try hardware accelerated rectangle filling */ + if (!(card->caps.flags & CCF_NOTRIEMU) && + dfb_gfxcard_state_check( state, DFXL_FILLRECTANGLE ) && + dfb_gfxcard_state_acquire( state, DFXL_FILLRECTANGLE )) + { + for (; i < num; i++) { + DFBTriangle tri = tris[i]; + + dfb_sort_triangle( &tri ); + + if (tri.y3 - tri.y1 > 0) + fill_tri( &tri, state, true ); + } + + dfb_gfxcard_state_release( state ); + } + else if (gAcquire( state, DFXL_FILLRECTANGLE )) { + for (; i < num; i++) { + DFBTriangle tri = tris[i]; + + if (state->render_options & DSRO_MATRIX) { + DFB_TRANSFORM(tri.x1, tri.y1, state->matrix, state->affine_matrix); + DFB_TRANSFORM(tri.x2, tri.y2, state->matrix, state->affine_matrix); + DFB_TRANSFORM(tri.x3, tri.y3, state->matrix, state->affine_matrix); + } + + dfb_sort_triangle( &tri ); + + if (tri.y3 - tri.y1 > 0) + fill_tri( &tri, state, false ); + } + + gRelease( state ); + } + } + + dfb_state_unlock( state ); +} + +static void +clip_blit_rotated( DFBRectangle *srect, DFBRectangle *drect, const DFBRegion *clip, DFBSurfaceBlittingFlags flags ) +{ + DFBRegion dest = DFB_REGION_INIT_FROM_RECTANGLE( drect ); + DFBRegion clipped = dest; + + if (flags & (DSBLIT_ROTATE90 | DSBLIT_ROTATE270)) { + D_ASSERT( srect->w == drect->h ); + D_ASSERT( srect->h == drect->w ); + } + else { + D_ASSERT( srect->w == drect->w ); + D_ASSERT( srect->h == drect->h ); + } + + dfb_region_region_intersect( &clipped, clip ); + dfb_rectangle_from_region( drect, &clipped ); + + if (flags & DSBLIT_ROTATE90) { + srect->x += dest.y2 - clipped.y2; + srect->y += clipped.x1 - dest.x1; + srect->w = drect->h; + srect->h = drect->w; + + D_DEBUG_AT( Core_GraphicsOps, " => %4d,%4d-%4dx%4d -> %4d,%4d-%4dx%4d (90°)\n", + DFB_RECTANGLE_VALS(srect), DFB_RECTANGLE_VALS(drect) ); + } + else if (flags & DSBLIT_ROTATE180) { + srect->x += dest.x2 - clipped.x2; + srect->y += dest.y2 - clipped.y2; + srect->w = drect->w; + srect->h = drect->h; + + D_DEBUG_AT( Core_GraphicsOps, " => %4d,%4d-%4dx%4d -> %4d,%4d-%4dx%4d (180°)\n", + DFB_RECTANGLE_VALS(srect), DFB_RECTANGLE_VALS(drect) ); + } + else if (flags & DSBLIT_ROTATE270) { + srect->x += clipped.y1 - dest.y1; + srect->y += dest.x2 - clipped.x2; + srect->w = drect->h; + srect->h = drect->w; + + D_DEBUG_AT( Core_GraphicsOps, " => %4d,%4d-%4dx%4d -> %4d,%4d-%4dx%4d (270°)\n", + DFB_RECTANGLE_VALS(srect), DFB_RECTANGLE_VALS(drect) ); + } + else { + srect->x += clipped.x1 - dest.x1; + srect->y += clipped.y1 - dest.y1; + srect->w = drect->w; + srect->h = drect->h; + + D_DEBUG_AT( Core_GraphicsOps, " => %4d,%4d-%4dx%4d -> %4d,%4d-%4dx%4d\n", + DFB_RECTANGLE_VALS(srect), DFB_RECTANGLE_VALS(drect) ); + } +} + +void dfb_gfxcard_blit( DFBRectangle *rect, int dx, int dy, CardState *state ) +{ + bool hw = false; + DFBRectangle drect = { dx, dy, rect->w, rect->h }; + + if (state->blittingflags & (DSBLIT_ROTATE90 | DSBLIT_ROTATE270)) + D_UTIL_SWAP( drect.w, drect.h ); + + D_DEBUG_AT( Core_GraphicsOps, "%s( %4d,%4d-%4dx%4d -> %4d,%4d-%4dx%4d, %p )\n", + __FUNCTION__, DFB_RECTANGLE_VALS(rect), DFB_RECTANGLE_VALS(&drect), state ); + + D_ASSERT( card != NULL ); + D_ASSERT( card->shared != NULL ); + D_MAGIC_ASSERT( state, CardState ); + D_ASSERT( state->source != NULL ); + D_ASSERT( rect != NULL ); + D_ASSERT( rect->x >= 0 ); + D_ASSERT( rect->y >= 0 ); + D_ASSERT( rect->x < state->source->config.size.w ); + D_ASSERT( rect->y < state->source->config.size.h ); + D_ASSERT( rect->x + rect->w - 1 < state->source->config.size.w ); + D_ASSERT( rect->y + rect->h - 1 < state->source->config.size.h ); + + /* The state is locked during graphics operations. */ + dfb_state_lock( state ); + + /* Signal beginning of sequence of operations if not already done. */ + dfb_state_start_drawing( state, card ); + + if (!(state->render_options & DSRO_MATRIX) && + !dfb_clip_blit_precheck( &state->clip, drect.w, drect.h, drect.x, drect.y )) + { + /* no work at all */ + dfb_state_unlock( state ); + return; + } + + if (dfb_gfxcard_state_check( state, DFXL_BLIT ) && + dfb_gfxcard_state_acquire( state, DFXL_BLIT )) + { + if (!D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) && + !D_FLAGS_IS_SET( card->caps.clip, DFXL_BLIT )) + clip_blit_rotated( rect, &drect, &state->clip, state->blittingflags ); + + hw = card->funcs.Blit( card->driver_data, card->device_data, rect, drect.x, drect.y ); + + dfb_gfxcard_state_release( state ); + } + + if (!hw) { + if (state->render_options & DSRO_MATRIX) { + if (state->matrix[0] < 0 || state->matrix[1] != 0 || + state->matrix[3] != 0 || state->matrix[4] < 0 || + state->matrix[6] != 0 || state->matrix[7] != 0) { + D_WARN( "rotation not yet implemented" ); + dfb_state_unlock( state ); + return; + } + + if (gAcquire( state, DFXL_STRETCHBLIT )) { + DFBRectangle drect; + int x1, y1, x2, y2; + + x1 = dx; y1 = dy; + x2 = dx+rect->w; y2 = dy+rect->h; + DFB_TRANSFORM(x1, y1, state->matrix, state->affine_matrix); + DFB_TRANSFORM(x2, y2, state->matrix, state->affine_matrix); + + drect = (DFBRectangle) { x1, y1, x2-x1, y2-y1 }; + if (dfb_clip_blit_precheck( &state->clip, + drect.w, drect.h, drect.x, drect.y )) + gStretchBlit( state, rect, &drect ); + + gRelease( state ); + } + } + else { + if (gAcquire( state, DFXL_BLIT )) { + clip_blit_rotated( rect, &drect, &state->clip, state->blittingflags ); + + gBlit( state, rect, drect.x, drect.y ); + + gRelease( state ); + } + } + } + + dfb_state_unlock( state ); +} + +void dfb_gfxcard_batchblit( DFBRectangle *rects, DFBPoint *points, + int num, CardState *state ) +{ + int i = 0; + + D_DEBUG_AT( Core_GraphicsOps, "%s( %p, %p [%d], %p )\n", __FUNCTION__, rects, points, num, state ); + + D_ASSERT( card != NULL ); + D_ASSERT( card->shared != NULL ); + D_MAGIC_ASSERT( state, CardState ); + D_ASSERT( rects != NULL ); + D_ASSERT( points != NULL ); + D_ASSERT( num > 0 ); + + /* The state is locked during graphics operations. */ + dfb_state_lock( state ); + + /* Signal beginning of sequence of operations if not already done. */ + dfb_state_start_drawing( state, card ); + + if (dfb_gfxcard_state_check( state, DFXL_BLIT ) && + dfb_gfxcard_state_acquire( state, DFXL_BLIT )) + { + for (; irender_options & DSRO_MATRIX) || + dfb_clip_blit_precheck( &state->clip, + rects[i].w, rects[i].h, + points[i].x, points[i].y )) + { + if (!D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) && + !D_FLAGS_IS_SET( card->caps.clip, DFXL_BLIT )) + dfb_clip_blit( &state->clip, &rects[i], + &points[i].x, &points[i].y ); + + if (!card->funcs.Blit( card->driver_data, card->device_data, + &rects[i], points[i].x, points[i].y )) + break; + } + } + + dfb_gfxcard_state_release( state ); + } + + if (i < num) { + if (state->render_options & DSRO_MATRIX) { + if (state->matrix[0] < 0 || state->matrix[1] != 0 || + state->matrix[3] != 0 || state->matrix[4] < 0 || + state->matrix[6] != 0 || state->matrix[7] != 0) { + D_WARN( "rotation not yet implemented" ); + dfb_state_unlock( state ); + return; + } + + if (gAcquire( state, DFXL_STRETCHBLIT )) { + for (; imatrix, state->affine_matrix); + DFB_TRANSFORM(x2, y2, state->matrix, state->affine_matrix); + + drect = (DFBRectangle) { x1, y1, x2-x1, y2-y1 }; + if (dfb_clip_blit_precheck( &state->clip, + drect.w, drect.h, drect.x, drect.y )) + gStretchBlit( state, &rects[i], &drect ); + } + + gRelease( state ); + } + } + else { + if (gAcquire( state, DFXL_BLIT )) { + for (; iclip, + rects[i].w, rects[i].h, + points[i].x, points[i].y )) + { + dfb_clip_blit( &state->clip, &rects[i], + &points[i].x, &points[i].y ); + + gBlit( state, &rects[i], points[i].x, points[i].y ); + } + } + + gRelease( state ); + } + } + } + + dfb_state_unlock( state ); +} + +void dfb_gfxcard_tileblit( DFBRectangle *rect, int dx1, int dy1, int dx2, int dy2, + CardState *state ) +{ + int x, y; + int odx; + DFBRectangle srect; + DFBRegion *clip; + + D_DEBUG_AT( Core_GraphicsOps, "%s( %d,%d - %d,%d, %p )\n", __FUNCTION__, dx1, dy1, dx2, dy2, state ); + + D_ASSERT( card != NULL ); + D_ASSERT( card->shared != NULL ); + D_MAGIC_ASSERT( state, CardState ); + D_ASSERT( rect != NULL ); + + /* If called with an invalid rectangle, the algorithm goes into an + infinite loop. This should never happen but it's safer to check. */ + D_ASSERT( rect->w >= 1 ); + D_ASSERT( rect->h >= 1 ); + + /* The state is locked during graphics operations. */ + dfb_state_lock( state ); + + /* Signal beginning of sequence of operations if not already done. */ + dfb_state_start_drawing( state, card ); + + clip = &state->clip; + + /* Check if anything is drawn at all. */ + if (!(state->render_options & DSRO_MATRIX) && + !dfb_clip_blit_precheck( clip, dx2-dx1+1, dy2-dy1+1, dx1, dy1 )) { + dfb_state_unlock( state ); + return; + } + + /* Remove clipped tiles. */ + if (dx1 < clip->x1) { + int outer = clip->x1 - dx1; + + dx1 += outer - (outer % rect->w); + } + + if (dy1 < clip->y1) { + int outer = clip->y1 - dy1; + + dy1 += outer - (outer % rect->h); + } + + if (dx2 > clip->x2) { + int outer = clip->x2 - dx2; + + dx2 -= outer - (outer % rect->w); + } + + if (dy2 > clip->y2) { + int outer = clip->y2 - dy2; + + dy2 -= outer - (outer % rect->h); + } + + odx = dx1; + + if (dfb_gfxcard_state_check( state, DFXL_BLIT ) && + dfb_gfxcard_state_acquire( state, DFXL_BLIT )) { + bool hw = true; + + for (; dy1 < dy2; dy1 += rect->h) { + for (; dx1 < dx2; dx1 += rect->w) { + + if (!dfb_clip_blit_precheck( clip, rect->w, rect->h, dx1, dy1 )) + continue; + + x = dx1; + y = dy1; + srect = *rect; + + if (!D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) && + !D_FLAGS_IS_SET( card->caps.clip, DFXL_BLIT )) + dfb_clip_blit( clip, &srect, &x, &y ); + + hw = card->funcs.Blit( card->driver_data, + card->device_data, &srect, x, y ); + if (!hw) + break; + } + if (!hw) + break; + dx1 = odx; + } + + dfb_gfxcard_state_release( state ); + } + + if (dy1 < dy2) { + if (state->render_options & DSRO_MATRIX) { + if (state->matrix[0] < 0 || state->matrix[1] != 0 || + state->matrix[3] != 0 || state->matrix[4] < 0 || + state->matrix[6] != 0 || state->matrix[7] != 0) { + D_WARN( "rotation not yet implemented" ); + dfb_state_unlock( state ); + return; + } + + if (gAcquire( state, DFXL_STRETCHBLIT )) { + for (; dy1 < dy2; dy1 += rect->h) { + for (; dx1 < dx2; dx1 += rect->w) { + DFBRectangle drect; + int x1, y1, x2, y2; + + x1 = dx1; y1 = dy1; + x2 = dx1+rect->w; y2 = dy1+rect->h; + DFB_TRANSFORM(x1, y1, state->matrix, state->affine_matrix); + DFB_TRANSFORM(x2, y2, state->matrix, state->affine_matrix); + + drect = (DFBRectangle) { x1, y1, x2-x1, y2-y1 }; + if (dfb_clip_blit_precheck( &state->clip, + drect.w, drect.h, drect.x, drect.y )) + gStretchBlit( state, rect, &drect ); + } + dx1 = odx; + } + + gRelease( state ); + } + } + else { + if (gAcquire( state, DFXL_BLIT )) { + for (; dy1 < dy2; dy1 += rect->h) { + for (; dx1 < dx2; dx1 += rect->w) { + + if (!dfb_clip_blit_precheck( clip, rect->w, rect->h, dx1, dy1 )) + continue; + + x = dx1; + y = dy1; + srect = *rect; + + dfb_clip_blit( clip, &srect, &x, &y ); + + gBlit( state, &srect, x, y ); + } + dx1 = odx; + } + + gRelease( state ); + } + } + } + + dfb_state_unlock( state ); +} + +void dfb_gfxcard_stretchblit( DFBRectangle *srect, DFBRectangle *drect, + CardState *state ) +{ + bool hw = false; + + D_ASSERT( card != NULL ); + D_ASSERT( card->shared != NULL ); + D_MAGIC_ASSERT( state, CardState ); + D_ASSERT( srect != NULL ); + D_ASSERT( drect != NULL ); + + D_DEBUG_AT( Core_GraphicsOps, "%s( %d,%d - %dx%d -> %d,%d - %dx%d, %p )\n", + __FUNCTION__, DFB_RECTANGLE_VALS(srect), DFB_RECTANGLE_VALS(drect), state ); + + if (state->blittingflags & (DSBLIT_ROTATE90 | DSBLIT_ROTATE270)) { + if (srect->w == drect->h && srect->h == drect->w) { + dfb_gfxcard_blit( srect, drect->x, drect->y, state ); + return; + } + } + else { + if (srect->w == drect->w && srect->h == drect->h) { + dfb_gfxcard_blit( srect, drect->x, drect->y, state ); + return; + } + } + + /* The state is locked during graphics operations. */ + dfb_state_lock( state ); + + /* Signal beginning of sequence of operations if not already done. */ + dfb_state_start_drawing( state, card ); + + if (!(state->render_options & DSRO_MATRIX) && + !dfb_clip_blit_precheck( &state->clip, drect->w, drect->h, + drect->x, drect->y )) + { + dfb_state_unlock( state ); + return; + } + + if (dfb_gfxcard_state_check( state, DFXL_STRETCHBLIT ) && + dfb_gfxcard_state_acquire( state, DFXL_STRETCHBLIT )) + { + if (!D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) && + !D_FLAGS_IS_SET( card->caps.clip, DFXL_STRETCHBLIT )) + dfb_clip_stretchblit( &state->clip, srect, drect ); + + hw = card->funcs.StretchBlit( card->driver_data, card->device_data, srect, drect ); + + dfb_gfxcard_state_release( state ); + } + + if (!hw) { + if (state->render_options & DSRO_MATRIX) { + int x1, y1, x2, y2; + + if (state->matrix[0] < 0 || state->matrix[1] != 0 || + state->matrix[3] != 0 || state->matrix[4] < 0 || + state->matrix[6] != 0 || state->matrix[7] != 0) { + D_WARN( "rotation not yet implemented" ); + dfb_state_unlock( state ); + return; + } + + x1 = drect->x; y1 = drect->y; + x2 = x1+drect->w; y2 = y1+drect->h; + DFB_TRANSFORM(x1, y1, state->matrix, state->affine_matrix); + DFB_TRANSFORM(x2, y2, state->matrix, state->affine_matrix); + drect->x = x1; drect->y = y1; + drect->w = x2-x1; drect->h = y2-y1; + + if (!dfb_clip_blit_precheck( &state->clip, + drect->w, drect->h, drect->x, drect->y )) { + dfb_state_unlock( state ); + return; + } + } + + if (gAcquire( state, DFXL_STRETCHBLIT )) { + /* Clipping is performed in the following function. */ + gStretchBlit( state, srect, drect ); + gRelease( state ); + } + } + + dfb_state_unlock( state ); +} + +void dfb_gfxcard_texture_triangles( DFBVertex *vertices, int num, + DFBTriangleFormation formation, + CardState *state ) +{ + bool hw = false; + + D_DEBUG_AT( Core_GraphicsOps, "%s( %p [%d], %s, %p )\n", __FUNCTION__, vertices, num, + (formation == DTTF_LIST) ? "LIST" : + (formation == DTTF_STRIP) ? "STRIP" : + (formation == DTTF_FAN) ? "FAN" : "unknown formation", state ); + + D_ASSERT( card != NULL ); + D_ASSERT( card->shared != NULL ); + D_ASSERT( vertices != NULL ); + D_ASSERT( num >= 3 ); + D_MAGIC_ASSERT( state, CardState ); + + /* The state is locked during graphics operations. */ + dfb_state_lock( state ); + + /* Signal beginning of sequence of operations if not already done. */ + dfb_state_start_drawing( state, card ); + + if ((D_FLAGS_IS_SET( card->caps.flags, CCF_CLIPPING ) || D_FLAGS_IS_SET( card->caps.clip, DFXL_TEXTRIANGLES )) && + dfb_gfxcard_state_check( state, DFXL_TEXTRIANGLES ) && + dfb_gfxcard_state_acquire( state, DFXL_TEXTRIANGLES )) + { + hw = card->funcs.TextureTriangles( card->driver_data, + card->device_data, + vertices, num, formation ); + + dfb_gfxcard_state_release( state ); + } + + if (!hw) { + if (gAcquire( state, DFXL_TEXTRIANGLES )) { + //dfb_clip_stretchblit( &state->clip, srect, drect ); + //gStretchBlit( state, srect, drect ); + gRelease( state ); + } + } + + dfb_state_unlock( state ); +} + +void +dfb_gfxcard_drawstring( const u8 *text, int bytes, + DFBTextEncodingID encoding, int x, int y, + CoreFont *font, unsigned int layers, CardState *state ) +{ + unsigned int prev = 0; + unsigned int indices[bytes]; + int i, l, num; + int kern_x; + int kern_y; + CoreSurface *surface; + DFBSurfaceBlittingFlags orig_flags; + DFBSurfaceBlendFunction orig_srcblend; + DFBSurfaceBlendFunction orig_dstblend; + DFBPoint points[50]; + DFBRectangle rects[50]; + int num_blits = 0; + int ox = x; + int oy = y; + + if (encoding == DTEID_UTF8) + D_DEBUG_AT( Core_GraphicsOps, "%s( '%s' [%d], %d,%d, %p, %p )\n", + __FUNCTION__, text, bytes, x, y, font, state ); + else + D_DEBUG_AT( Core_GraphicsOps, "%s( %p [%d], %d, %d,%d, %p, %p )\n", + __FUNCTION__, text, bytes, encoding, x, y, font, state ); + + D_ASSERT( card != NULL ); + D_ASSERT( card->shared != NULL ); + D_MAGIC_ASSERT( state, CardState ); + D_ASSERT( text != NULL ); + D_ASSERT( bytes > 0 ); + D_ASSERT( font != NULL ); + + surface = state->destination; + D_MAGIC_ASSERT( surface, CoreSurface ); + + /* simple prechecks */ + if (!(state->render_options & DSRO_MATRIX) && + (x > state->clip.x2 || y > state->clip.y2 || + y + font->ascender - font->descender <= state->clip.y1)) { + return; + } + + dfb_font_lock( font ); + + /* Decode string to character indices. */ + dfb_font_decode_text( font, encoding, text, bytes, indices, &num ); + + orig_flags = state->blittingflags; + orig_srcblend = state->src_blend; + orig_dstblend = state->dst_blend; + + if (orig_flags != DSBLIT_INDEX_TRANSLATION) { + DFBSurfaceBlittingFlags flags = font->blittingflags; + + /* additional blending? */ + if ((state->drawingflags & DSDRAW_BLEND) && (state->color.a != 0xff)) + flags |= DSBLIT_BLEND_COLORALPHA; + + if (state->drawingflags & DSDRAW_DST_COLORKEY) + flags |= DSBLIT_DST_COLORKEY; + + if (state->drawingflags & DSDRAW_XOR) + flags |= DSBLIT_XOR; + + if (flags & (DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_BLEND_COLORALPHA)) { + /* Porter/Duff SRC_OVER composition */ + if ((DFB_PIXELFORMAT_HAS_ALPHA( surface->config.format ) && (surface->config.caps & DSCAPS_PREMULTIPLIED)) + || + (font->surface_caps & DSCAPS_PREMULTIPLIED)) + { + if (font->surface_caps & DSCAPS_PREMULTIPLIED) { + if (flags & DSBLIT_BLEND_COLORALPHA) + flags |= DSBLIT_SRC_PREMULTCOLOR; + } + else + flags |= DSBLIT_SRC_PREMULTIPLY; + + dfb_state_set_src_blend( state, DSBF_ONE ); + } + else + dfb_state_set_src_blend( state, DSBF_SRCALPHA ); + + dfb_state_set_dst_blend( state, DSBF_INVSRCALPHA ); + } + + dfb_state_set_blitting_flags( state, flags ); + } + + for (l=layers-1; l>=0; l--) { + x = ox; + y = oy; + + if (layers > 1) { + if (num_blits) { + dfb_gfxcard_batchblit( rects, points, num_blits, state ); + num_blits = 0; + } + + dfb_state_set_color( state, &state->colors[l] ); + } + + /* blit glyphs */ + for (i=0; i dfb_font_get_glyph_data() failed! [%s]\n", DirectFBErrorString( ret ) ); + prev = current; + continue; + } + + if (prev && font->GetKerning && font->GetKerning( font, prev, current, &kern_x, &kern_y) == DFB_OK) { + x += kern_x; + y += kern_y; + } + + if (glyph->width) { + if (glyph->surface != state->source || num_blits == D_ARRAY_SIZE(rects)) { + if (num_blits) { + dfb_gfxcard_batchblit( rects, points, num_blits, state ); + num_blits = 0; + } + + if (glyph->surface != state->source) + dfb_state_set_source( state, glyph->surface ); + } + + points[num_blits] = (DFBPoint){ x + glyph->left, y + glyph->top }; + rects[num_blits] = (DFBRectangle){ glyph->start, 0, glyph->width, glyph->height }; + + num_blits++; + } + + x += glyph->xadvance; + y += glyph->yadvance; + prev = current; + } + } + + if (num_blits) { + dfb_gfxcard_batchblit( rects, points, num_blits, state ); + num_blits = 0; + } + + dfb_font_unlock( font ); + + + if (orig_flags != DSBLIT_INDEX_TRANSLATION) { + dfb_state_set_blitting_flags( state, orig_flags ); + dfb_state_set_src_blend( state, orig_srcblend ); + dfb_state_set_dst_blend( state, orig_dstblend ); + } +} + +void dfb_gfxcard_drawglyph( CoreGlyphData **glyph, int x, int y, + CoreFont *font, unsigned int layers, CardState *state ) +{ + int l; + CoreSurface *surface; + DFBSurfaceBlittingFlags orig_flags; + DFBSurfaceBlendFunction orig_srcblend; + DFBSurfaceBlendFunction orig_dstblend; + + D_DEBUG_AT( Core_GraphicsOps, "%s( %u, %d,%d, %p, %p )\n", + __FUNCTION__, index, x, y, font, state ); + + D_ASSERT( card != NULL ); + D_ASSERT( card->shared != NULL ); + D_MAGIC_ASSERT( state, CardState ); + D_ASSERT( font != NULL ); + + surface = state->destination; + D_MAGIC_ASSERT( surface, CoreSurface ); + + orig_flags = state->blittingflags; + orig_srcblend = state->src_blend; + orig_dstblend = state->dst_blend; + + if (orig_flags != DSBLIT_INDEX_TRANSLATION) { + DFBSurfaceBlittingFlags flags = font->blittingflags; + + /* additional blending? */ + if ((state->drawingflags & DSDRAW_BLEND) && (state->color.a != 0xff)) + flags |= DSBLIT_BLEND_COLORALPHA; + + if (state->drawingflags & DSDRAW_DST_COLORKEY) + flags |= DSBLIT_DST_COLORKEY; + + if (state->drawingflags & DSDRAW_XOR) + flags |= DSBLIT_XOR; + + if (flags & (DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_BLEND_COLORALPHA)) { + /* Porter/Duff SRC_OVER composition */ + if ((DFB_PIXELFORMAT_HAS_ALPHA( surface->config.format ) && (surface->config.caps & DSCAPS_PREMULTIPLIED)) + || + (font->surface_caps & DSCAPS_PREMULTIPLIED)) + { + if (font->surface_caps & DSCAPS_PREMULTIPLIED) { + if (flags & DSBLIT_BLEND_COLORALPHA) + flags |= DSBLIT_SRC_PREMULTCOLOR; + } + else + flags |= DSBLIT_SRC_PREMULTIPLY; + + dfb_state_set_src_blend( state, DSBF_ONE ); + } + else + dfb_state_set_src_blend( state, DSBF_SRCALPHA ); + + dfb_state_set_dst_blend( state, DSBF_INVSRCALPHA ); + } + + dfb_state_set_blitting_flags( state, flags ); + } + + for (l=layers-1; l>=0; l--) { + if (layers > 1) + dfb_state_set_color( state, &state->colors[l] ); + + /* blit glyph */ + if (glyph[l]->width) { + DFBRectangle rect = { glyph[l]->start, 0, glyph[l]->width, glyph[l]->height }; + + dfb_state_set_source( state, glyph[l]->surface ); + + dfb_gfxcard_blit( &rect, x + glyph[l]->left, y + glyph[l]->top, state ); + } + } + + if (orig_flags != DSBLIT_INDEX_TRANSLATION) { + dfb_state_set_blitting_flags( state, orig_flags ); + dfb_state_set_src_blend( state, orig_srcblend ); + dfb_state_set_dst_blend( state, orig_dstblend ); + } +} + +bool dfb_gfxcard_drawstring_check_state( CoreFont *font, CardState *state ) +{ + int i; + bool result; + CoreSurface *surface; + DFBSurfaceBlittingFlags orig_flags; + DFBSurfaceBlendFunction orig_srcblend; + DFBSurfaceBlendFunction orig_dstblend; + CoreGlyphData *data = NULL; + + D_ASSERT( card != NULL ); + D_ASSERT( card->shared != NULL ); + D_MAGIC_ASSERT( state, CardState ); + D_ASSERT( font != NULL ); + + D_DEBUG_AT( Core_GfxState, "%s( %p, %p )\n", __FUNCTION__, font, state ); + + surface = state->destination; + D_MAGIC_ASSERT( surface, CoreSurface ); + + dfb_font_lock( font ); + + for (i=0; i<128; i++) { + if (dfb_font_get_glyph_data (font, i, 0, &data) == DFB_OK) + break; + } + + if (!data) { + D_DEBUG_AT( Core_GfxState, " -> No font data!\n" ); + dfb_font_unlock( font ); + return; + } + + orig_flags = state->blittingflags; + orig_srcblend = state->src_blend; + orig_dstblend = state->dst_blend; + + if (orig_flags != DSBLIT_INDEX_TRANSLATION) { + DFBSurfaceBlittingFlags flags = font->blittingflags; + + /* additional blending? */ + if ((state->drawingflags & DSDRAW_BLEND) && (state->color.a != 0xff)) + flags |= DSBLIT_BLEND_COLORALPHA; + + if (state->drawingflags & DSDRAW_DST_COLORKEY) + flags |= DSBLIT_DST_COLORKEY; + + if (state->drawingflags & DSDRAW_XOR) + flags |= DSBLIT_XOR; + + if (flags & (DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_BLEND_COLORALPHA)) { + /* Porter/Duff SRC_OVER composition */ + if ((DFB_PIXELFORMAT_HAS_ALPHA( surface->config.format ) && (surface->config.caps & DSCAPS_PREMULTIPLIED)) + || + (font->surface_caps & DSCAPS_PREMULTIPLIED)) + { + if (font->surface_caps & DSCAPS_PREMULTIPLIED) { + if (flags & DSBLIT_BLEND_COLORALPHA) + flags |= DSBLIT_SRC_PREMULTCOLOR; + } + else + flags |= DSBLIT_SRC_PREMULTIPLY; + + dfb_state_set_src_blend( state, DSBF_ONE ); + } + else + dfb_state_set_src_blend( state, DSBF_SRCALPHA ); + + dfb_state_set_dst_blend( state, DSBF_INVSRCALPHA ); + } + + dfb_state_set_blitting_flags( state, flags ); + } + + /* set the source */ + dfb_state_set_source( state, data->surface ); + + dfb_state_lock( state ); + + /* check for blitting and report */ + result = dfb_gfxcard_state_check( state, DFXL_BLIT ); + + dfb_state_unlock( state ); + + dfb_font_unlock( font ); + + if (orig_flags != DSBLIT_INDEX_TRANSLATION) { + dfb_state_set_blitting_flags( state, orig_flags ); + dfb_state_set_src_blend( state, orig_srcblend ); + dfb_state_set_dst_blend( state, orig_dstblend ); + } + + return result; +} + +DFBResult dfb_gfxcard_sync( void ) +{ + DFBResult ret; + + D_ASSUME( card != NULL ); + + if (!card) + return DFB_OK; + + ret = dfb_gfxcard_lock( GDLF_SYNC ); + if (ret) + return ret; + + dfb_gfxcard_unlock(); + + return DFB_OK; +} + +void dfb_gfxcard_invalidate_state( void ) +{ + D_ASSERT( card != NULL ); + D_ASSERT( card->shared != NULL ); + + card->shared->state = NULL; +} + +DFBResult dfb_gfxcard_wait_serial( const CoreGraphicsSerial *serial ) +{ + DFBResult ret; + + D_ASSERT( serial != NULL ); + D_ASSUME( card != NULL ); + + if (!card) + return DFB_OK; + + D_ASSERT( card->shared != NULL ); + + ret = dfb_gfxcard_lock( GDLF_NONE ); + if (ret) + return ret; + +/* FIXME_SC_2 if (card->funcs.WaitSerial) + ret = card->funcs.WaitSerial( card->driver_data, card->device_data, serial ); + else*/ if (card->funcs.EngineSync) + ret = card->funcs.EngineSync( card->driver_data, card->device_data ); + + if (ret) { + if (card->funcs.EngineReset) + card->funcs.EngineReset( card->driver_data, card->device_data ); + + card->shared->state = NULL; + } + + dfb_gfxcard_unlock(); + + return ret; +} + +void dfb_gfxcard_flush_texture_cache( void ) +{ + D_ASSUME( card != NULL ); + + if (card && card->funcs.FlushTextureCache) + card->funcs.FlushTextureCache( card->driver_data, card->device_data ); +} + +void dfb_gfxcard_flush_read_cache( void ) +{ + D_ASSUME( card != NULL ); + + if (card && card->funcs.FlushReadCache) + card->funcs.FlushReadCache( card->driver_data, card->device_data ); +} + +void dfb_gfxcard_after_set_var( void ) +{ + D_ASSUME( card != NULL ); + + if (card && card->funcs.AfterSetVar) + card->funcs.AfterSetVar( card->driver_data, card->device_data ); +} + +void dfb_gfxcard_surface_enter( CoreSurfaceBuffer *buffer, DFBSurfaceLockFlags flags ) +{ + D_ASSUME( card != NULL ); + + if (card && card->funcs.SurfaceEnter) + card->funcs.SurfaceEnter( card->driver_data, card->device_data, buffer, flags ); +} + +void dfb_gfxcard_surface_leave( CoreSurfaceBuffer *buffer ) +{ + D_ASSUME( card != NULL ); + + if (card && card->funcs.SurfaceLeave) + card->funcs.SurfaceLeave( card->driver_data, card->device_data, buffer ); +} + +DFBResult +dfb_gfxcard_adjust_heap_offset( int offset ) +{ + D_ASSERT( card != NULL ); + D_ASSERT( card->shared != NULL ); + +//FIXME_SMAN return dfb_surfacemanager_adjust_heap_offset( card->shared->surface_manager, offset ); + return DFB_OK; +} + +void +dfb_gfxcard_get_capabilities( CardCapabilities *ret_caps ) +{ + D_ASSERT( card != NULL ); + + D_ASSERT( ret_caps != NULL ); + + *ret_caps = card->caps; +} + +void +dfb_gfxcard_get_device_info( GraphicsDeviceInfo *ret_info ) +{ + D_ASSERT( card != NULL ); + D_ASSERT( card->shared != NULL ); + + D_ASSERT( ret_info != NULL ); + + *ret_info = card->shared->device_info; +} + +void +dfb_gfxcard_get_driver_info( GraphicsDriverInfo *ret_info ) +{ + D_ASSERT( card != NULL ); + D_ASSERT( card->shared != NULL ); + + D_ASSERT( ret_info != NULL ); + + *ret_info = card->shared->driver_info; +} + + +int +dfb_gfxcard_reserve_memory( CoreGraphicsDevice *device, unsigned int size ) +{ + DFBGraphicsCoreShared *shared; + + D_ASSERT( device != NULL ); + D_ASSERT( device->shared != NULL ); + + shared = device->shared; + + if (shared->device_info.limits.surface_byteoffset_alignment) { + size += shared->device_info.limits.surface_byteoffset_alignment - 1; + size -= (size % shared->device_info.limits.surface_byteoffset_alignment); + } + else + D_WARN( "no alignment specified yet?" ); + + if (shared->videoram_length < size) { + D_WARN( "not enough video memory (%u < %u)", shared->videoram_length, size ); + return -1; + } + + shared->videoram_length -= size; + + return shared->videoram_length; +} + +int +dfb_gfxcard_reserve_auxmemory( CoreGraphicsDevice *device, unsigned int size ) +{ + DFBGraphicsCoreShared *shared; + int offset; + + D_ASSERT( device != NULL ); + D_ASSERT( device->shared != NULL ); + + shared = device->shared; + + /* Reserve memory at the beginning of the aperture + * to prevent overflows on DMA buffers. */ + + offset = shared->auxram_offset; + + if (shared->auxram_length < (offset + size)) + return -1; + + shared->auxram_offset += size; + + return offset; +} + +unsigned int +dfb_gfxcard_memory_length( void ) +{ + D_ASSERT( card != NULL ); + D_ASSERT( card->shared != NULL ); + + return card->shared->videoram_length; +} + +unsigned int +dfb_gfxcard_auxmemory_length( void ) +{ + D_ASSERT( card != NULL ); + D_ASSERT( card->shared != NULL ); + + return card->shared->auxram_length; +} + +volatile void * +dfb_gfxcard_map_mmio( CoreGraphicsDevice *device, + unsigned int offset, + int length ) +{ + return dfb_system_map_mmio( offset, length ); +} + +void +dfb_gfxcard_unmap_mmio( CoreGraphicsDevice *device, + volatile void *addr, + int length ) +{ + dfb_system_unmap_mmio( addr, length ); +} + +int +dfb_gfxcard_get_accelerator( CoreGraphicsDevice *device ) +{ + return dfb_system_get_accelerator(); +} + +void +dfb_gfxcard_get_limits( CoreGraphicsDevice *device, + CardLimitations *ret_limits ) +{ + D_ASSERT( device != NULL ); + D_ASSERT( ret_limits != NULL ); + + if (!device) + device = card; + + *ret_limits = device->limits; +} + +void +dfb_gfxcard_calc_buffer_size( CoreGraphicsDevice *device, + CoreSurfaceBuffer *buffer, + int *ret_pitch, + int *ret_length ) +{ + int pitch; + int length; + CoreSurface *surface; + + D_ASSERT( device != NULL ); + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + + surface = buffer->surface; + D_MAGIC_ASSERT( surface, CoreSurface ); + + /* calculate the required length depending on limitations */ + pitch = MAX( surface->config.size.w, surface->config.min_size.w ); + + if (pitch < device->limits.surface_max_power_of_two_pixelpitch && + surface->config.size.h < device->limits.surface_max_power_of_two_height) + pitch = 1 << direct_log2( pitch ); + + if (device->limits.surface_pixelpitch_alignment > 1) { + pitch += device->limits.surface_pixelpitch_alignment - 1; + pitch -= pitch % device->limits.surface_pixelpitch_alignment; + } + + pitch = DFB_BYTES_PER_LINE( buffer->format, pitch ); + + if (pitch < device->limits.surface_max_power_of_two_bytepitch && + surface->config.size.h < device->limits.surface_max_power_of_two_height) + pitch = 1 << direct_log2( pitch ); + + if (device->limits.surface_bytepitch_alignment > 1) { + pitch += device->limits.surface_bytepitch_alignment - 1; + pitch -= pitch % device->limits.surface_bytepitch_alignment; + } + + length = DFB_PLANE_MULTIPLY( buffer->format, + MAX( surface->config.size.h, surface->config.min_size.h ) * pitch ); + + /* Add extra space for optimized routines which are now allowed to overrun, e.g. prefetching. */ + length += 16; + + if (device->limits.surface_byteoffset_alignment > 1) { + length += device->limits.surface_byteoffset_alignment - 1; + length -= length % device->limits.surface_byteoffset_alignment; + } + + if (ret_pitch) + *ret_pitch = pitch; + + if (ret_length) + *ret_length = length; +} + +unsigned long +dfb_gfxcard_memory_physical( CoreGraphicsDevice *device, + unsigned int offset ) +{ + return dfb_system_video_memory_physical( offset ); +} + +void * +dfb_gfxcard_memory_virtual( CoreGraphicsDevice *device, + unsigned int offset ) +{ + return dfb_system_video_memory_virtual( offset ); +} + +unsigned long +dfb_gfxcard_auxmemory_physical( CoreGraphicsDevice *device, + unsigned int offset ) +{ + return dfb_system_aux_memory_physical( offset ); +} + +void * +dfb_gfxcard_auxmemory_virtual( CoreGraphicsDevice *device, + unsigned int offset ) +{ + return dfb_system_aux_memory_virtual( offset ); +} + +void * +dfb_gfxcard_get_device_data( void ) +{ + D_ASSERT( card != NULL ); + D_ASSERT( card->shared != NULL ); + + return card->shared->device_data; +} + +void * +dfb_gfxcard_get_driver_data( void ) +{ + D_ASSERT( card != NULL ); + + return card->driver_data; +} + +CoreGraphicsDevice * +dfb_gfxcard_get_primary( void ) +{ + return card; +} + + +/** internal **/ + +/* + * loads/probes/unloads one driver module after another until a suitable + * driver is found and returns its symlinked functions + */ +static void dfb_gfxcard_find_driver( CoreDFB *core ) +{ + DirectLink *link; + FusionSHMPoolShared *pool = dfb_core_shmpool( core ); + + direct_list_foreach (link, dfb_graphics_drivers.entries) { + DirectModuleEntry *module = (DirectModuleEntry*) link; + + const GraphicsDriverFuncs *funcs = direct_module_ref( module ); + + if (!funcs) + continue; + + if (!card->module && funcs->Probe( card )) { + funcs->GetDriverInfo( card, &card->shared->driver_info ); + + card->module = module; + card->driver_funcs = funcs; + + card->shared->module_name = SHSTRDUP( pool, module->name ); + } + else + direct_module_unref( module ); + } +} + +/* + * loads the driver module used by the session + */ +static void dfb_gfxcard_load_driver( void ) +{ + DirectLink *link; + + if (!card->shared->module_name) + return; + + direct_list_foreach (link, dfb_graphics_drivers.entries) { + DirectModuleEntry *module = (DirectModuleEntry*) link; + + const GraphicsDriverFuncs *funcs = direct_module_ref( module ); + + if (!funcs) + continue; + + if (!card->module && + !strcmp( module->name, card->shared->module_name )) + { + card->module = module; + card->driver_funcs = funcs; + } + else + direct_module_unref( module ); + } +} + diff --git a/Source/DirectFB/src/core/gfxcard.h b/Source/DirectFB/src/core/gfxcard.h new file mode 100755 index 0000000..6e723d0 --- /dev/null +++ b/Source/DirectFB/src/core/gfxcard.h @@ -0,0 +1,470 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef __GFXCARD_H__ +#define __GFXCARD_H__ + +#include + +#include + +#include + +#include +#include + + +typedef enum { + CCF_CLIPPING = 0x00000001, + CCF_NOTRIEMU = 0x00000002, + CCF_READSYSMEM = 0x00000004, + /* CCF_WRITESYSMEM ?! */ + CCF_AUXMEMORY = 0x00000010, + CCF_RENDEROPTS = 0x00000020 +} CardCapabilitiesFlags; + +struct __DFB_CoreGraphicsSerial { + unsigned int serial; + unsigned int generation; +}; + +typedef struct { + CardCapabilitiesFlags flags; + + DFBAccelerationMask accel; + DFBSurfaceBlittingFlags blitting; + DFBSurfaceDrawingFlags drawing; + DFBAccelerationMask clip; +} CardCapabilities; + +typedef struct { + unsigned int surface_byteoffset_alignment; + unsigned int surface_pixelpitch_alignment; + unsigned int surface_bytepitch_alignment; + + unsigned int surface_max_power_of_two_pixelpitch; + unsigned int surface_max_power_of_two_bytepitch; + unsigned int surface_max_power_of_two_height; + + DFBDimension dst_min; + DFBDimension dst_max; + DFBDimension src_min; + DFBDimension src_max; +} CardLimitations; + +DECLARE_MODULE_DIRECTORY( dfb_graphics_drivers ); + +/* + * Increase this number when changes result in binary incompatibility! + */ +#define DFB_GRAPHICS_DRIVER_ABI_VERSION 34 + +#define DFB_GRAPHICS_DRIVER_INFO_NAME_LENGTH 40 +#define DFB_GRAPHICS_DRIVER_INFO_VENDOR_LENGTH 60 +#define DFB_GRAPHICS_DRIVER_INFO_URL_LENGTH 100 +#define DFB_GRAPHICS_DRIVER_INFO_LICENSE_LENGTH 40 + +#define DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH 48 +#define DFB_GRAPHICS_DEVICE_INFO_VENDOR_LENGTH 64 + + +typedef struct { + int major; /* major version */ + int minor; /* minor version */ +} GraphicsDriverVersion; /* major.minor, e.g. 0.1 */ + +typedef struct { + GraphicsDriverVersion version; + + char name[DFB_GRAPHICS_DRIVER_INFO_NAME_LENGTH]; + /* Name of driver, e.g. 'Matrox Driver' */ + + char vendor[DFB_GRAPHICS_DRIVER_INFO_VENDOR_LENGTH]; + /* Vendor (or author) of the driver, + e.g. 'directfb.org' or 'Denis Oliver Kropp' */ + + char url[DFB_GRAPHICS_DRIVER_INFO_URL_LENGTH]; + /* URL for driver updates, + e.g. 'http://www.directfb.org/' */ + + char license[DFB_GRAPHICS_DRIVER_INFO_LICENSE_LENGTH]; + /* License, e.g. 'LGPL' or 'proprietary' */ + + unsigned int driver_data_size; + unsigned int device_data_size; +} GraphicsDriverInfo; + +typedef struct { + char name[DFB_GRAPHICS_DEVICE_INFO_NAME_LENGTH]; + /* Device name, e.g. 'G400' */ + + char vendor[DFB_GRAPHICS_DEVICE_INFO_VENDOR_LENGTH]; + /* Vendor of the device, + e.g. 'Matrox' or 'ATI' */ + + /* hardware acceleration capabilities */ + CardCapabilities caps; + + /* hardware limitations */ + CardLimitations limits; +} GraphicsDeviceInfo; + +typedef struct _GraphicsDeviceFuncs { + /* + * function that is called after variable screeninfo is changed + * (used for buggy fbdev drivers, that reinitialize something when + * calling FBIO_PUT_VSCREENINFO) + */ + void (*AfterSetVar)( void *driver_data, void *device_data ); + + /* + * Called after driver->InitDevice() and during dfb_gfxcard_unlock( true ). + * The driver should do the one time initialization of the engine, + * e.g. writing some registers that are supposed to have a fixed value. + * + * This happens after mode switching or after returning from + * OpenGL state (e.g. DRI driver). + */ + void (*EngineReset)( void *driver_data, void *device_data ); + + /* + * Makes sure that graphics hardware has finished all operations. + * + * This method is called before the CPU accesses a surface' buffer + * that had been written to by the hardware after this method has been + * called the last time. + * + * It's also called before entering the OpenGL state (e.g. DRI driver). + */ + DFBResult (*EngineSync)( void *driver_data, void *device_data ); + + /* + * Called during dfb_gfxcard_lock() to notify the driver that + * the current rendering state is no longer valid. + */ + void (*InvalidateState)( void *driver_data, void *device_data ); + + /* + * after the video memory has been written to by the CPU (e.g. modification + * of a texture) make sure the accelerator won't use cached texture data + */ + void (*FlushTextureCache)( void *driver_data, void *device_data ); + + /* + * After the video memory has been written to by the accelerator + * make sure the CPU won't read back cached data. + */ + void (*FlushReadCache)( void *driver_data, void *device_data ); + + /* + * Called before a software access to a video surface buffer. + */ + void (*SurfaceEnter)( void *driver_data, void *device_data, + CoreSurfaceBuffer *buffer, DFBSurfaceLockFlags flags ); + + /* + * Called after a software access to a video surface buffer. + */ + void (*SurfaceLeave)( void *driver_data, void *device_data, CoreSurfaceBuffer *buffer ); + + /* + * Return the serial of the last (queued) operation. + * + * The serial is used to wait for finishing a specific graphics + * operation instead of the whole engine being idle. + */ + void (*GetSerial)( void *driver_data, void *device_data, CoreGraphicsSerial *serial ); + + /* + * Makes sure that graphics hardware has finished the specified operation. + */ + DFBResult (*WaitSerial)( void *driver_data, void *device_data, const CoreGraphicsSerial *serial ); + + /* + * emit any buffered commands, i.e. trigger processing + */ + void (*EmitCommands) ( void *driver_data, void *device_data ); + + /* + * Check if the function 'accel' can be accelerated with the 'state'. + * If that's true, the function sets the 'accel' bit in 'state->accel'. + * Otherwise the function just returns, no need to clear the bit. + */ + void (*CheckState)( void *driver_data, void *device_data, + CardState *state, DFBAccelerationMask accel ); + + /* + * Program card for execution of the function 'accel' with the 'state'. + * 'state->modified' contains information about changed entries. + * This function has to set at least 'accel' in 'state->set'. + * The driver should remember 'state->modified' and clear it. + * The driver may modify 'funcs' depending on 'state' settings. + */ + void (*SetState) ( void *driver_data, void *device_data, + struct _GraphicsDeviceFuncs *funcs, + CardState *state, DFBAccelerationMask accel ); + + /* + * drawing functions + */ + bool (*FillRectangle) ( void *driver_data, void *device_data, + DFBRectangle *rect ); + + bool (*DrawRectangle) ( void *driver_data, void *device_data, + DFBRectangle *rect ); + + bool (*DrawLine) ( void *driver_data, void *device_data, + DFBRegion *line ); + + bool (*FillTriangle) ( void *driver_data, void *device_data, + DFBTriangle *tri ); + + /* + * blitting functions + */ + bool (*Blit) ( void *driver_data, void *device_data, + DFBRectangle *rect, int dx, int dy ); + + bool (*StretchBlit) ( void *driver_data, void *device_data, + DFBRectangle *srect, DFBRectangle *drect ); + + bool (*TextureTriangles)( void *driver_data, void *device_data, + DFBVertex *vertices, int num, + DFBTriangleFormation formation ); + + /* + * Signal beginning of a sequence of operations using this state. + * Any number of states can be 'drawing'. + */ + void (*StartDrawing)( void *driver_data, void *device_data, CardState *state ); + + /* + * Signal end of sequence, i.e. destination surface is consistent again. + */ + void (*StopDrawing)( void *driver_data, void *device_data, CardState *state ); +} GraphicsDeviceFuncs; + +typedef struct { + int (*Probe) (CoreGraphicsDevice *device); + void (*GetDriverInfo) (CoreGraphicsDevice *device, + GraphicsDriverInfo *driver_info); + + DFBResult (*InitDriver) (CoreGraphicsDevice *device, + GraphicsDeviceFuncs *funcs, + void *driver_data, + void *device_data, + CoreDFB *core); + + DFBResult (*InitDevice) (CoreGraphicsDevice *device, + GraphicsDeviceInfo *device_info, + void *driver_data, + void *device_data); + + void (*CloseDevice) (CoreGraphicsDevice *device, + void *driver_data, + void *device_data); + void (*CloseDriver) (CoreGraphicsDevice *device, + void *driver_data); +} GraphicsDriverFuncs; + +typedef enum { + GDLF_NONE = 0x00000000, + + GDLF_WAIT = 0x00000001, + GDLF_SYNC = 0x00000002, + GDLF_INVALIDATE = 0x00000004, + GDLF_RESET = 0x00000008 +} GraphicsDeviceLockFlags; + +DFBResult dfb_gfxcard_lock( GraphicsDeviceLockFlags flags ); +void dfb_gfxcard_unlock( void ); +void dfb_gfxcard_holdup( void ); + +bool dfb_gfxcard_state_check( CardState *state, DFBAccelerationMask accel ); + +/* + * Signal beginning of a sequence of operations using this state. + * Any number of states can be 'drawing'. + */ +void dfb_gfxcard_start_drawing( CoreGraphicsDevice *device, + CardState *state ); + +/* + * Signal end of sequence, i.e. destination surface is consistent again. + */ +void dfb_gfxcard_stop_drawing ( CoreGraphicsDevice *device, + CardState *state ); + +/* + * drawing functions, lock source and destination surfaces, + * handle clipping and drawing method (hardware/software) + */ +void dfb_gfxcard_fillrectangles ( const DFBRectangle *rects, + int num, + CardState *state ); + +void dfb_gfxcard_drawrectangle ( DFBRectangle *rect, + CardState *state ); + +void dfb_gfxcard_drawlines ( DFBRegion *lines, + int num_lines, + CardState *state ); + +void dfb_gfxcard_fillspans ( int y, + DFBSpan *spans, + int num_spans, + CardState *state ); + +void dfb_gfxcard_filltriangles ( const DFBTriangle *tris, + int num, + CardState *state ); + +void dfb_gfxcard_blit ( DFBRectangle *rect, + int dx, + int dy, + CardState *state ); + +void dfb_gfxcard_batchblit ( DFBRectangle *rects, + DFBPoint *points, + int num, + CardState *state ); + +void dfb_gfxcard_tileblit ( DFBRectangle *rect, + int dx1, + int dy1, + int dx2, + int dy2, + CardState *state ); + +void dfb_gfxcard_stretchblit ( DFBRectangle *srect, + DFBRectangle *drect, + CardState *state ); + +void dfb_gfxcard_texture_triangles ( DFBVertex *vertices, + int num, + DFBTriangleFormation formation, + CardState *state ); + +void dfb_gfxcard_drawstring ( const u8 *text, + int bytes, + DFBTextEncodingID encoding, + int x, + int y, + CoreFont *font, + unsigned int layers, + CardState *state ); + +void dfb_gfxcard_drawglyph ( CoreGlyphData **glyph, + int x, + int y, + CoreFont *font, + unsigned int layers, + CardState *state ); + +bool dfb_gfxcard_drawstring_check_state ( CoreFont *font, + CardState *state ); + +DFBResult dfb_gfxcard_sync( void ); +void dfb_gfxcard_invalidate_state( void ); +DFBResult dfb_gfxcard_wait_serial( const CoreGraphicsSerial *serial ); +void dfb_gfxcard_flush_texture_cache( void ); +void dfb_gfxcard_flush_read_cache( void ); +void dfb_gfxcard_after_set_var( void ); +void dfb_gfxcard_surface_enter( CoreSurfaceBuffer *buffer, DFBSurfaceLockFlags flags ); +void dfb_gfxcard_surface_leave( CoreSurfaceBuffer *buffer ); + +DFBResult dfb_gfxcard_adjust_heap_offset( int offset ); + +void dfb_gfxcard_get_capabilities ( CardCapabilities *ret_caps ); +void dfb_gfxcard_get_device_info ( GraphicsDeviceInfo *ret_info ); +void dfb_gfxcard_get_driver_info ( GraphicsDriverInfo *ret_info ); + +int dfb_gfxcard_reserve_memory ( CoreGraphicsDevice *device, + unsigned int size ); +int dfb_gfxcard_reserve_auxmemory ( CoreGraphicsDevice *device, + unsigned int size ); + +unsigned int dfb_gfxcard_memory_length ( void ); +unsigned int dfb_gfxcard_auxmemory_length ( void ); + +void *dfb_gfxcard_get_device_data ( void ); +void *dfb_gfxcard_get_driver_data ( void ); + +CoreGraphicsDevice *dfb_gfxcard_get_primary ( void ); + +/* + * Graphics drivers call this function to get access to MMIO regions. + * + * device: Graphics device to map + * offset: Offset from MMIO base (default offset is 0) + * length: Length of mapped region (-1 uses default length) + * + * Returns the virtual address or NULL if mapping failed. + */ +volatile void *dfb_gfxcard_map_mmio( CoreGraphicsDevice *device, + unsigned int offset, + int length ); + +/* + * Graphics drivers call this function to unmap MMIO regions. + * + * addr: Virtual address returned by gfxcard_map_mmio + * length: Length of mapped region (-1 uses default length) + */ +void dfb_gfxcard_unmap_mmio( CoreGraphicsDevice *device, + volatile void *addr, + int length ); + +int dfb_gfxcard_get_accelerator( CoreGraphicsDevice *device ); + +void dfb_gfxcard_get_limits( CoreGraphicsDevice *device, + CardLimitations *ret_limits ); + +void dfb_gfxcard_calc_buffer_size( CoreGraphicsDevice *device, + CoreSurfaceBuffer *buffer, + int *ret_pitch, + int *ret_length ); + +unsigned long dfb_gfxcard_memory_physical ( CoreGraphicsDevice *device, + unsigned int offset ); +void *dfb_gfxcard_memory_virtual ( CoreGraphicsDevice *device, + unsigned int offset ); + +unsigned long dfb_gfxcard_auxmemory_physical( CoreGraphicsDevice *device, + unsigned int offset ); +void *dfb_gfxcard_auxmemory_virtual ( CoreGraphicsDevice *device, + unsigned int offset ); + + +/* Hook for registering additional screen(s) and layer(s) in app or lib initializing DirectFB. */ +extern void (*__DFB_CoreRegisterHook)( CoreDFB *core, CoreGraphicsDevice *device, void *ctx ); +extern void *__DFB_CoreRegisterHookCtx; + + +#endif + diff --git a/Source/DirectFB/src/core/graphics_driver.h b/Source/DirectFB/src/core/graphics_driver.h new file mode 100755 index 0000000..de03234 --- /dev/null +++ b/Source/DirectFB/src/core/graphics_driver.h @@ -0,0 +1,86 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef __GRAPHICS_DRIVER_H__ +#define __GRAPHICS_DRIVER_H__ + +#include + +#include + + +static int +driver_probe( CoreGraphicsDevice *device ); + +static void +driver_get_info( CoreGraphicsDevice *device, + GraphicsDriverInfo *info ); + +static DFBResult +driver_init_driver( CoreGraphicsDevice *device, + GraphicsDeviceFuncs *funcs, + void *driver_data, + void *device_data, + CoreDFB *core ); + +static DFBResult +driver_init_device( CoreGraphicsDevice *device, + GraphicsDeviceInfo *device_info, + void *driver_data, + void *device_data ); + +static void +driver_close_device( CoreGraphicsDevice *device, + void *driver_data, + void *device_data ); + +static void +driver_close_driver( CoreGraphicsDevice *device, + void *driver_data ); + +static GraphicsDriverFuncs driver_funcs = { + .Probe = driver_probe, + .GetDriverInfo = driver_get_info, + .InitDriver = driver_init_driver, + .InitDevice = driver_init_device, + .CloseDevice = driver_close_device, + .CloseDriver = driver_close_driver +}; + +#define DFB_GRAPHICS_DRIVER(shortname) \ +__attribute__((constructor)) void directfb_##shortname( void ); \ + \ +void \ +directfb_##shortname( void ) \ +{ \ + direct_modules_register( &dfb_graphics_drivers, \ + DFB_GRAPHICS_DRIVER_ABI_VERSION, \ + #shortname, &driver_funcs ); \ +} + +#endif diff --git a/Source/DirectFB/src/core/input.c b/Source/DirectFB/src/core/input.c new file mode 100755 index 0000000..c8eee18 --- /dev/null +++ b/Source/DirectFB/src/core/input.c @@ -0,0 +1,2668 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + + +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + + +D_DEBUG_DOMAIN( Core_Input, "Core/Input", "DirectFB Input Core" ); +D_DEBUG_DOMAIN( Core_InputEvt, "Core/Input/Evt", "DirectFB Input Core Events & Dispatch" ); + + +DEFINE_MODULE_DIRECTORY( dfb_input_modules, "inputdrivers", DFB_INPUT_DRIVER_ABI_VERSION ); + +/**********************************************************************************************************************/ + +typedef enum { + CICC_RESCAN_DEVICES +} CoreInputCoreCommand; + +typedef enum { + CIDC_RELOAD_KEYMAP, + CIDC_SET_SENSITIVITY +} CoreInputDeviceCommand; + + +typedef struct { + DirectLink link; + + int magic; + + DirectModuleEntry *module; + + const InputDriverFuncs *funcs; + + InputDriverInfo info; + + int nr_devices; +} InputDriver; + +typedef struct { + int min_keycode; + int max_keycode; + int num_entries; + DFBInputDeviceKeymapEntry *entries; +} InputDeviceKeymap; + +typedef struct { + int magic; + + DFBInputDeviceID id; /* unique device id */ + + int num; + + InputDeviceInfo device_info; + + InputDeviceKeymap keymap; + + DFBInputDeviceModifierMask modifiers_l; + DFBInputDeviceModifierMask modifiers_r; + DFBInputDeviceLockState locks; + DFBInputDeviceButtonMask buttons; + + DFBInputDeviceKeyIdentifier last_key; /* last key pressed */ + DFBInputDeviceKeySymbol last_symbol; /* last symbol pressed */ + bool first_press; /* first press of key */ + + FusionReactor *reactor; /* event dispatcher */ + FusionSkirmish lock; + + FusionCall call; /* driver call via master */ + + unsigned int axis_num; + DFBInputDeviceAxisInfo *axis_info; + + + DFBInputDeviceState state; +} InputDeviceShared; + +struct __DFB_CoreInputDevice { + int magic; + + InputDeviceShared *shared; + + InputDriver *driver; + void *driver_data; + + CoreDFB *core; +}; + +/**********************************************************************************************************************/ + +typedef struct { + int magic; + + int num; + InputDeviceShared *devices[MAX_INPUTDEVICES]; + + FusionCall call; + FusionReactor *reactor; +} DFBInputCoreShared; + +struct __DFB_DFBInputCore { + int magic; + + CoreDFB *core; + + DFBInputCoreShared *shared; + + DirectLink *drivers; + + int num; + CoreInputDevice *devices[MAX_INPUTDEVICES]; + + Reaction reaction; +}; + + +DFB_CORE_PART( input_core, InputCore ); + +/**********************************************************************************************************************/ + +typedef struct { + DFBInputDeviceKeySymbol target; + DFBInputDeviceKeySymbol result; +} DeadKeyCombo; + +typedef struct { + DFBInputDeviceKeySymbol deadkey; + const DeadKeyCombo *combos; +} DeadKeyMap; + +/**********************************************************************************************************************/ + +static const DeadKeyCombo combos_grave[] = { + { DIKS_SPACE, (unsigned char) '`' }, + { DIKS_SMALL_A, (unsigned char) 'à' }, + { DIKS_SMALL_E, (unsigned char) 'è' }, + { DIKS_SMALL_I, (unsigned char) 'ì' }, + { DIKS_SMALL_O, (unsigned char) 'ò' }, + { DIKS_SMALL_U, (unsigned char) 'ù' }, + { DIKS_CAPITAL_A, (unsigned char) 'À' }, + { DIKS_CAPITAL_E, (unsigned char) 'È' }, + { DIKS_CAPITAL_I, (unsigned char) 'Ì' }, + { DIKS_CAPITAL_O, (unsigned char) 'Ò' }, + { DIKS_CAPITAL_U, (unsigned char) 'Ù' }, + { 0, 0 } +}; + +static const DeadKeyCombo combos_acute[] = { + { DIKS_SPACE, (unsigned char) '\'' }, + { DIKS_SMALL_A, (unsigned char) 'á' }, + { DIKS_SMALL_E, (unsigned char) 'é' }, + { DIKS_SMALL_I, (unsigned char) 'í' }, + { DIKS_SMALL_O, (unsigned char) 'ó' }, + { DIKS_SMALL_U, (unsigned char) 'ú' }, + { DIKS_SMALL_Y, (unsigned char) 'ý' }, + { DIKS_CAPITAL_A, (unsigned char) 'Á' }, + { DIKS_CAPITAL_E, (unsigned char) 'É' }, + { DIKS_CAPITAL_I, (unsigned char) 'Í' }, + { DIKS_CAPITAL_O, (unsigned char) 'Ó' }, + { DIKS_CAPITAL_U, (unsigned char) 'Ú' }, + { DIKS_CAPITAL_Y, (unsigned char) 'Ý' }, + { 0, 0 } +}; + +static const DeadKeyCombo combos_circumflex[] = { + { DIKS_SPACE, (unsigned char) '^' }, + { DIKS_SMALL_A, (unsigned char) 'â' }, + { DIKS_SMALL_E, (unsigned char) 'ê' }, + { DIKS_SMALL_I, (unsigned char) 'î' }, + { DIKS_SMALL_O, (unsigned char) 'ô' }, + { DIKS_SMALL_U, (unsigned char) 'û' }, + { DIKS_CAPITAL_A, (unsigned char) 'Â' }, + { DIKS_CAPITAL_E, (unsigned char) 'Ê' }, + { DIKS_CAPITAL_I, (unsigned char) 'Î' }, + { DIKS_CAPITAL_O, (unsigned char) 'Ô' }, + { DIKS_CAPITAL_U, (unsigned char) 'Û' }, + { 0, 0 } +}; + +static const DeadKeyCombo combos_diaeresis[] = { + { DIKS_SPACE, (unsigned char) '¨' }, + { DIKS_SMALL_A, (unsigned char) 'ä' }, + { DIKS_SMALL_E, (unsigned char) 'ë' }, + { DIKS_SMALL_I, (unsigned char) 'ï' }, + { DIKS_SMALL_O, (unsigned char) 'ö' }, + { DIKS_SMALL_U, (unsigned char) 'ü' }, + { DIKS_CAPITAL_A, (unsigned char) 'Ä' }, + { DIKS_CAPITAL_E, (unsigned char) 'Ë' }, + { DIKS_CAPITAL_I, (unsigned char) 'Ï' }, + { DIKS_CAPITAL_O, (unsigned char) 'Ö' }, + { DIKS_CAPITAL_U, (unsigned char) 'Ü' }, + { 0, 0 } +}; + +static const DeadKeyCombo combos_tilde[] = { + { DIKS_SPACE, (unsigned char) '~' }, + { DIKS_SMALL_A, (unsigned char) 'ã' }, + { DIKS_SMALL_N, (unsigned char) 'ñ' }, + { DIKS_SMALL_O, (unsigned char) 'õ' }, + { DIKS_CAPITAL_A, (unsigned char) 'Ã' }, + { DIKS_CAPITAL_N, (unsigned char) 'Ñ' }, + { DIKS_CAPITAL_O, (unsigned char) 'Õ' }, + { 0, 0 } +}; + +static const DeadKeyMap deadkey_maps[] = { + { DIKS_DEAD_GRAVE, combos_grave }, + { DIKS_DEAD_ACUTE, combos_acute }, + { DIKS_DEAD_CIRCUMFLEX, combos_circumflex }, + { DIKS_DEAD_DIAERESIS, combos_diaeresis }, + { DIKS_DEAD_TILDE, combos_tilde } +}; + +/* define a lookup table to go from key IDs to names. + * This is used to look up the names provided in a loaded key table */ +/* this table is roughly 4Kb in size */ +DirectFBKeySymbolNames(KeySymbolNames); +DirectFBKeyIdentifierNames(KeyIdentifierNames); + +/**********************************************************************************************************************/ + +static void init_drivers ( CoreDFB *core ); +static DFBResult rescan_devices( CoreDFB *core ); + +static void allocate_device_keymap( CoreDFB *core, CoreInputDevice *device ); + +static DFBInputDeviceKeymapEntry *get_keymap_entry( CoreInputDevice *device, + int code ); + +static DFBResult set_keymap_entry( CoreInputDevice *device, + int code, + DFBInputDeviceKeymapEntry *entry ); + +static DFBResult load_keymap( CoreInputDevice *device, + char *filename ); + +static DFBInputDeviceKeySymbol lookup_keysymbol( char *symbolname ); +static DFBInputDeviceKeyIdentifier lookup_keyidentifier( char *identifiername ); + +/**********************************************************************************************************************/ + +static bool lookup_from_table( CoreInputDevice *device, + DFBInputEvent *event, + DFBInputEventFlags lookup ); + +static void fixup_key_event ( CoreInputDevice *device, + DFBInputEvent *event ); + +static void fixup_mouse_event( CoreInputDevice *device, + DFBInputEvent *event ); + +static void flush_keys ( CoreInputDevice *device ); + +static bool core_input_filter( CoreInputDevice *device, + DFBInputEvent *event ); + +/**********************************************************************************************************************/ + +static DFBInputDeviceKeyIdentifier symbol_to_id( DFBInputDeviceKeySymbol symbol ); + +static DFBInputDeviceKeySymbol id_to_symbol( DFBInputDeviceKeyIdentifier id, + DFBInputDeviceModifierMask modifiers, + DFBInputDeviceLockState locks ); + +/**********************************************************************************************************************/ + +static ReactionFunc dfb_input_globals[MAX_INPUT_GLOBALS+1] = { +/* 0 */ _dfb_windowstack_inputdevice_listener, + NULL +}; + +DFBResult +dfb_input_add_global( ReactionFunc func, + int *ret_index ) +{ + int i; + + D_DEBUG_AT( Core_Input, "%s( %p, %p )\n", __FUNCTION__, func, ret_index ); + + D_ASSERT( func != NULL ); + D_ASSERT( ret_index != NULL ); + + for (i=0; i index %d\n", i ); + + *ret_index = i; + + return DFB_OK; + } + } + + return DFB_LIMITEXCEEDED; +} + +DFBResult +dfb_input_set_global( ReactionFunc func, + int index ) +{ + D_DEBUG_AT( Core_Input, "%s( %p, %d )\n", __FUNCTION__, func, index ); + + D_ASSERT( func != NULL ); + D_ASSERT( index >= 0 ); + D_ASSERT( index < MAX_INPUT_GLOBALS ); + + D_ASSUME( dfb_input_globals[index] == NULL ); + + dfb_input_globals[index] = func; + + return DFB_OK; +} + +/**********************************************************************************************************************/ + +static DFBInputCore *core_local; /* FIXME */ +static DFBInputCoreShared *core_input; /* FIXME */ + +/**********************************************************************************************************************/ + +static FusionCallHandlerResult +core_input_call_handler( int caller, /* fusion id of the caller */ + int call_arg, /* optional call parameter */ + void *call_ptr, /* optional call parameter */ + void *ctx, /* optional handler context */ + unsigned int serial, + int *ret_val ) +{ + CoreDFB *core = ctx; + + D_DEBUG_AT( Core_Input, "%s( %p )\n", __FUNCTION__, core ); + + switch (call_arg) { + case CICC_RESCAN_DEVICES: + *ret_val = rescan_devices( core ); + break; + + default: + D_BUG( "unknown command %d", call_arg ); + *ret_val = DFB_BUG; + } + + return FCHR_RETURN; +} + +/**********************************************************************************************************************/ + +static DFBResult +dfb_input_core_initialize( CoreDFB *core, + DFBInputCore *data, + DFBInputCoreShared *shared ) +{ + D_DEBUG_AT( Core_Input, "dfb_input_core_initialize( %p, %p, %p )\n", core, data, shared ); + + D_ASSERT( data != NULL ); + D_ASSERT( shared != NULL ); + + core_local = data; /* FIXME */ + core_input = shared; /* FIXME */ + + data->core = core; + data->shared = shared; + + + fusion_call_init( &core_input->call, core_input_call_handler, core, dfb_core_world( core ) ); + + core_input->reactor = fusion_reactor_new( sizeof(CoreInputCoreNotification), "Input Core", dfb_core_world( core ) ); + + fusion_reactor_direct( core_input->reactor, false ); + + direct_modules_explore_directory( &dfb_input_modules ); + + init_drivers( core ); + rescan_devices( core ); + + D_MAGIC_SET( data, DFBInputCore ); + D_MAGIC_SET( shared, DFBInputCoreShared ); + + return DFB_OK; +} + +static DFBResult +rejoin_devices( CoreDFB *core ) +{ + int i; + + D_DEBUG_AT( Core_Input, "%s( %p )\n", __FUNCTION__, core ); + + D_ASSERT( core != NULL ); + D_MAGIC_ASSERT( core_local, DFBInputCore ); + D_ASSERT( core_input != NULL ); + + for (i=core_local->num; inum; i++) { + CoreInputDevice *device; + + D_DEBUG_AT( Core_Input, " -> adding %d (%s)\n", + core_input->devices[i]->id, + core_input->devices[i]->device_info.desc.name ); + + device = D_CALLOC( 1, sizeof(CoreInputDevice) ); + if (!device) { + D_OOM(); + continue; + } + + device->shared = core_input->devices[i]; + + D_MAGIC_SET( device, CoreInputDevice ); + + /* add it to the list */ + core_local->devices[core_local->num++] = device; + } + + return DFB_OK; +} + +static ReactionResult +core_input_core_reaction( const void *msg_data, + void *ctx ) +{ + const CoreInputCoreNotification *notification = msg_data; + CoreDFB *core = ctx; + + if (notification->flags & CICNF_NEW_DEVICE) + rejoin_devices( core ); + + return RS_OK; +} + +static DFBResult +dfb_input_core_join( CoreDFB *core, + DFBInputCore *data, + DFBInputCoreShared *shared ) +{ + D_DEBUG_AT( Core_Input, "dfb_input_core_join( %p, %p, %p )\n", core, data, shared ); + + D_ASSERT( data != NULL ); + D_MAGIC_ASSERT( shared, DFBInputCoreShared ); + + core_local = data; /* FIXME */ + core_input = shared; /* FIXME */ + + data->core = core; + data->shared = shared; + + D_MAGIC_SET( data, DFBInputCore ); + + + rejoin_devices( core ); + + fusion_reactor_attach( core_input->reactor, core_input_core_reaction, core, &core_local->reaction ); + + return DFB_OK; +} + +static DFBResult +dfb_input_core_shutdown( DFBInputCore *data, + bool emergency ) +{ + int i; + DFBInputCoreShared *shared; + FusionSHMPoolShared *pool = dfb_core_shmpool( data->core ); + + D_DEBUG_AT( Core_Input, "dfb_input_core_shutdown( %p, %semergency )\n", data, emergency ? "" : "no " ); + + D_MAGIC_ASSERT( data, DFBInputCore ); + D_MAGIC_ASSERT( data->shared, DFBInputCoreShared ); + + shared = data->shared; + + + for (i=0; inum; i++) { + CoreInputDevice *device = data->devices[i]; + InputDriver *driver; + InputDeviceShared *devshared; + + D_MAGIC_ASSERT( device, CoreInputDevice ); + + driver = device->driver; + D_ASSERT( driver != NULL ); + + devshared = device->shared; + D_ASSERT( devshared != NULL ); + + fusion_call_destroy( &devshared->call ); + fusion_skirmish_destroy( &devshared->lock ); + + if (device->driver_data != NULL) { + void *driver_data; + + D_ASSERT( driver->funcs != NULL ); + D_ASSERT( driver->funcs->CloseDevice != NULL ); + + D_DEBUG_AT( Core_Input, " -> closing '%s' (%d) %d.%d (%s)\n", + devshared->device_info.desc.name, devshared->num + 1, + driver->info.version.major, + driver->info.version.minor, driver->info.vendor ); + + driver_data = device->driver_data; + device->driver_data = NULL; + driver->funcs->CloseDevice( driver_data ); + } + + if (!--driver->nr_devices) { + direct_module_unref( driver->module ); + D_FREE( driver ); + } + + fusion_reactor_free( devshared->reactor ); + + if (devshared->keymap.entries) + SHFREE( pool, devshared->keymap.entries ); + + if (devshared->axis_info) + SHFREE( pool, devshared->axis_info ); + + SHFREE( pool, devshared ); + + D_MAGIC_CLEAR( device ); + + D_FREE( device ); + } + + D_MAGIC_CLEAR( data ); + D_MAGIC_CLEAR( shared ); + + return DFB_OK; +} + +static DFBResult +dfb_input_core_leave( DFBInputCore *data, + bool emergency ) +{ + int i; + DFBInputCoreShared *shared; + + D_DEBUG_AT( Core_Input, "dfb_input_core_leave( %p, %semergency )\n", data, emergency ? "" : "no " ); + + D_MAGIC_ASSERT( data, DFBInputCore ); + D_MAGIC_ASSERT( data->shared, DFBInputCoreShared ); + + shared = data->shared; + + + for (i=0; inum; i++) { + CoreInputDevice *device = data->devices[i]; + + D_MAGIC_ASSERT( device, CoreInputDevice ); + + D_FREE( device ); + } + + + D_MAGIC_CLEAR( data ); + + return DFB_OK; +} + +static DFBResult +dfb_input_core_suspend( DFBInputCore *data ) +{ + int i; + DFBInputCoreShared *shared; + + D_DEBUG_AT( Core_Input, "dfb_input_core_suspend( %p )\n", data ); + + D_MAGIC_ASSERT( data, DFBInputCore ); + D_MAGIC_ASSERT( data->shared, DFBInputCoreShared ); + + shared = data->shared; + + D_DEBUG_AT( Core_Input, " -> suspending...\n" ); + + for (i=0; inum; i++) { + CoreInputDevice *device = data->devices[i]; + InputDriver *driver; + InputDeviceShared *devshared; + + D_MAGIC_ASSERT( device, CoreInputDevice ); + + driver = device->driver; + D_ASSERT( driver != NULL ); + + devshared = device->shared; + D_ASSERT( devshared != NULL ); + + if (device->driver_data != NULL) { + void *driver_data; + + D_ASSERT( driver->funcs != NULL ); + D_ASSERT( driver->funcs->CloseDevice != NULL ); + + D_DEBUG_AT( Core_Input, " -> closing '%s' (%d) %d.%d (%s)\n", + devshared->device_info.desc.name, devshared->num + 1, + driver->info.version.major, + driver->info.version.minor, driver->info.vendor ); + + driver_data = device->driver_data; + device->driver_data = NULL; + driver->funcs->CloseDevice( driver_data ); + } + + flush_keys( device ); + } + + D_DEBUG_AT( Core_Input, " -> suspended.\n" ); + + return DFB_OK; +} + +static DFBResult +dfb_input_core_resume( DFBInputCore *data ) +{ + DFBInputCoreShared *shared; + DFBResult ret; + int i; + + D_DEBUG_AT( Core_Input, "dfb_input_core_resume( %p )\n", data ); + + D_MAGIC_ASSERT( data, DFBInputCore ); + D_MAGIC_ASSERT( data->shared, DFBInputCoreShared ); + + shared = data->shared; + + D_DEBUG_AT( Core_Input, " -> resuming...\n" ); + + for (i=0; inum; i++) { + CoreInputDevice *device = data->devices[i]; + + D_MAGIC_ASSERT( device, CoreInputDevice ); + + D_DEBUG_AT( Core_Input, " -> reopening '%s' (%d) %d.%d (%s)\n", + device->shared->device_info.desc.name, device->shared->num + 1, + device->driver->info.version.major, + device->driver->info.version.minor, + device->driver->info.vendor ); + + D_ASSERT( device->driver_data == NULL ); + + ret = device->driver->funcs->OpenDevice( device, device->shared->num, + &device->shared->device_info, + &device->driver_data ); + if (ret) { + D_DERROR( ret, "DirectFB/Input: Failed reopening device " + "during resume (%s)!\n", device->shared->device_info.desc.name ); + device->driver_data = NULL; + } + } + + D_DEBUG_AT( Core_Input, " -> resumed.\n" ); + + return DFB_OK; +} + +void +dfb_input_enumerate_devices( InputDeviceCallback callback, + void *ctx, + DFBInputDeviceCapabilities caps ) +{ + int i; + + D_ASSERT( core_input != NULL ); + + for (i=0; inum; i++) { + CoreInputDevice *device = core_local->devices[i]; + + DFBInputDeviceCapabilities dev_caps; + + D_MAGIC_ASSERT( device, CoreInputDevice ); + D_ASSERT( device->shared != NULL ); + + dev_caps = device->shared->device_info.desc.caps; + + /* Always match if unclassified */ + if (!dev_caps) + dev_caps = DICAPS_ALL; + + if ((dev_caps & caps) && callback( device, ctx ) == DFENUM_CANCEL) + break; + } +} + +DirectResult +dfb_input_attach( CoreInputDevice *device, + ReactionFunc func, + void *ctx, + Reaction *reaction ) +{ + D_DEBUG_AT( Core_Input, "%s( %p, %p, %p, %p )\n", __FUNCTION__, device, func, ctx, reaction ); + + D_MAGIC_ASSERT( device, CoreInputDevice ); + + D_ASSERT( core_input != NULL ); + D_ASSERT( device != NULL ); + D_ASSERT( device->shared != NULL ); + + return fusion_reactor_attach( device->shared->reactor, func, ctx, reaction ); +} + +DirectResult +dfb_input_detach( CoreInputDevice *device, + Reaction *reaction ) +{ + D_DEBUG_AT( Core_Input, "%s( %p, %p )\n", __FUNCTION__, device, reaction ); + + D_MAGIC_ASSERT( device, CoreInputDevice ); + + D_ASSERT( core_input != NULL ); + D_ASSERT( device != NULL ); + D_ASSERT( device->shared != NULL ); + + return fusion_reactor_detach( device->shared->reactor, reaction ); +} + +DirectResult +dfb_input_attach_global( CoreInputDevice *device, + int index, + void *ctx, + GlobalReaction *reaction ) +{ + D_DEBUG_AT( Core_Input, "%s( %p, %d, %p, %p )\n", __FUNCTION__, device, index, ctx, reaction ); + + D_MAGIC_ASSERT( device, CoreInputDevice ); + + D_ASSERT( core_input != NULL ); + D_ASSERT( device != NULL ); + D_ASSERT( device->shared != NULL ); + + return fusion_reactor_attach_global( device->shared->reactor, index, ctx, reaction ); +} + +DirectResult +dfb_input_detach_global( CoreInputDevice *device, + GlobalReaction *reaction ) +{ + D_DEBUG_AT( Core_Input, "%s( %p, %p )\n", __FUNCTION__, device, reaction ); + + D_MAGIC_ASSERT( device, CoreInputDevice ); + + D_ASSERT( core_input != NULL ); + D_ASSERT( device != NULL ); + D_ASSERT( device->shared != NULL ); + + return fusion_reactor_detach_global( device->shared->reactor, reaction ); +} + +const char * +dfb_input_event_type_name( DFBInputEventType type ) +{ + switch (type) { + case DIET_UNKNOWN: + return "UNKNOWN"; + + case DIET_KEYPRESS: + return "KEYPRESS"; + + case DIET_KEYRELEASE: + return "KEYRELEASE"; + + case DIET_BUTTONPRESS: + return "BUTTONPRESS"; + + case DIET_BUTTONRELEASE: + return "BUTTONRELEASE"; + + case DIET_AXISMOTION: + return "AXISMOTION"; + + default: + break; + } + + return ""; +} + +void +dfb_input_dispatch( CoreInputDevice *device, DFBInputEvent *event ) +{ + D_DEBUG_AT( Core_Input, "%s( %p, %p )\n", __FUNCTION__, device, event ); + + D_MAGIC_ASSERT( device, CoreInputDevice ); + + D_ASSERT( core_input != NULL ); + D_ASSERT( device != NULL ); + D_ASSERT( event != NULL ); + + D_ASSUME( device->shared != NULL ); + + /* + * 0. Sanity checks & debugging... + */ + if (!device->shared) { + D_DEBUG_AT( Core_Input, " -> No shared data!\n" ); + return; + } + + D_ASSUME( device->shared->reactor != NULL ); + + if (!device->shared->reactor) { + D_DEBUG_AT( Core_Input, " -> No reactor!\n" ); + return; + } + + D_DEBUG_AT( Core_InputEvt, " -> (%02x) %s%s%s\n", event->type, + dfb_input_event_type_name( event->type ), + (event->flags & DIEF_FOLLOW) ? " [FOLLOW]" : "", + (event->flags & DIEF_REPEAT) ? " [REPEAT]" : "" ); + +#if D_DEBUG_ENABLED + if (event->flags & DIEF_TIMESTAMP) + D_DEBUG_AT( Core_InputEvt, " -> TIMESTAMP %lu.%06lu\n", event->timestamp.tv_sec, event->timestamp.tv_usec ); + if (event->flags & DIEF_AXISABS) + D_DEBUG_AT( Core_InputEvt, " -> AXISABS %d at %d\n", event->axis, event->axisabs ); + if (event->flags & DIEF_AXISREL) + D_DEBUG_AT( Core_InputEvt, " -> AXISREL %d by %d\n", event->axis, event->axisrel ); + if (event->flags & DIEF_KEYCODE) + D_DEBUG_AT( Core_InputEvt, " -> KEYCODE %d\n", event->key_code ); + if (event->flags & DIEF_KEYID) + D_DEBUG_AT( Core_InputEvt, " -> KEYID 0x%04x\n", event->key_id ); + if (event->flags & DIEF_KEYSYMBOL) + D_DEBUG_AT( Core_InputEvt, " -> KEYSYMBOL 0x%04x\n", event->key_symbol ); + if (event->flags & DIEF_MODIFIERS) + D_DEBUG_AT( Core_InputEvt, " -> MODIFIERS 0x%04x\n", event->modifiers ); + if (event->flags & DIEF_LOCKS) + D_DEBUG_AT( Core_InputEvt, " -> LOCKS 0x%04x\n", event->locks ); + if (event->flags & DIEF_BUTTONS) + D_DEBUG_AT( Core_InputEvt, " -> BUTTONS 0x%04x\n", event->buttons ); + if (event->flags & DIEF_GLOBAL) + D_DEBUG_AT( Core_InputEvt, " -> GLOBAL\n" ); +#endif + + /* + * 1. Fixup event... + */ + event->clazz = DFEC_INPUT; + event->device_id = device->shared->id; + + if (!(event->flags & DIEF_TIMESTAMP)) { + gettimeofday( &event->timestamp, NULL ); + event->flags |= DIEF_TIMESTAMP; + } + + switch (event->type) { + case DIET_BUTTONPRESS: + case DIET_BUTTONRELEASE: + D_DEBUG_AT( Core_InputEvt, " -> BUTTON 0x%04x\n", event->button ); + + if (dfb_config->lefty) { + if (event->button == DIBI_LEFT) + event->button = DIBI_RIGHT; + else if (event->button == DIBI_RIGHT) + event->button = DIBI_LEFT; + + D_DEBUG_AT( Core_InputEvt, " -> lefty! => 0x%04x <=\n", event->button ); + } + /* fallthru */ + + case DIET_AXISMOTION: + fixup_mouse_event( device, event ); + break; + + case DIET_KEYPRESS: + case DIET_KEYRELEASE: + if (dfb_config->capslock_meta) { + if (device->shared->keymap.num_entries && (event->flags & DIEF_KEYCODE)) + lookup_from_table( device, event, (DIEF_KEYID | + DIEF_KEYSYMBOL) & ~event->flags ); + + if (event->key_id == DIKI_CAPS_LOCK || event->key_symbol == DIKS_CAPS_LOCK) { + event->flags |= DIEF_KEYID | DIEF_KEYSYMBOL; + event->key_code = -1; + event->key_id = DIKI_META_L; + event->key_symbol = DIKS_META; + } + } + + fixup_key_event( device, event ); + break; + + default: + ; + } + +#if D_DEBUG_ENABLED + if (event->flags & DIEF_TIMESTAMP) + D_DEBUG_AT( Core_InputEvt, " => TIMESTAMP %lu.%06lu\n", event->timestamp.tv_sec, event->timestamp.tv_usec ); + if (event->flags & DIEF_AXISABS) + D_DEBUG_AT( Core_InputEvt, " => AXISABS %d at %d\n", event->axis, event->axisabs ); + if (event->flags & DIEF_AXISREL) + D_DEBUG_AT( Core_InputEvt, " => AXISREL %d by %d\n", event->axis, event->axisrel ); + if (event->flags & DIEF_KEYCODE) + D_DEBUG_AT( Core_InputEvt, " => KEYCODE %d\n", event->key_code ); + if (event->flags & DIEF_KEYID) + D_DEBUG_AT( Core_InputEvt, " => KEYID 0x%04x\n", event->key_id ); + if (event->flags & DIEF_KEYSYMBOL) + D_DEBUG_AT( Core_InputEvt, " => KEYSYMBOL 0x%04x\n", event->key_symbol ); + if (event->flags & DIEF_MODIFIERS) + D_DEBUG_AT( Core_InputEvt, " => MODIFIERS 0x%04x\n", event->modifiers ); + if (event->flags & DIEF_LOCKS) + D_DEBUG_AT( Core_InputEvt, " => LOCKS 0x%04x\n", event->locks ); + if (event->flags & DIEF_BUTTONS) + D_DEBUG_AT( Core_InputEvt, " => BUTTONS 0x%04x\n", event->buttons ); + if (event->flags & DIEF_GLOBAL) + D_DEBUG_AT( Core_InputEvt, " => GLOBAL\n" ); +#endif + + if (core_input_filter( device, event )) + D_DEBUG_AT( Core_InputEvt, " ****>> FILTERED\n" ); + else + fusion_reactor_dispatch( device->shared->reactor, event, true, dfb_input_globals ); +} + +DFBInputDeviceID +dfb_input_device_id( const CoreInputDevice *device ) +{ + D_MAGIC_ASSERT( device, CoreInputDevice ); + + D_ASSERT( core_input != NULL ); + D_ASSERT( device != NULL ); + D_ASSERT( device->shared != NULL ); + + return device->shared->id; +} + +CoreInputDevice * +dfb_input_device_at( DFBInputDeviceID id ) +{ + int i; + + D_ASSERT( core_input != NULL ); + + for (i=0; inum; i++) { + CoreInputDevice *device = core_local->devices[i]; + + D_MAGIC_ASSERT( device, CoreInputDevice ); + + if (device->shared->id == id) + return device; + } + + return NULL; +} + +void +dfb_input_device_description( const CoreInputDevice *device, + DFBInputDeviceDescription *desc ) +{ + D_MAGIC_ASSERT( device, CoreInputDevice ); + + D_ASSERT( core_input != NULL ); + D_ASSERT( device != NULL ); + D_ASSERT( device->shared != NULL ); + + *desc = device->shared->device_info.desc; +} + +DFBResult +dfb_input_device_get_keymap_entry( CoreInputDevice *device, + int keycode, + DFBInputDeviceKeymapEntry *entry ) +{ + DFBInputDeviceKeymapEntry *keymap_entry; + + D_MAGIC_ASSERT( device, CoreInputDevice ); + + D_ASSERT( core_input != NULL ); + D_ASSERT( device != NULL ); + D_ASSERT( entry != NULL ); + + keymap_entry = get_keymap_entry( device, keycode ); + if (!keymap_entry) + return DFB_FAILURE; + + *entry = *keymap_entry; + + return DFB_OK; +} + +DFBResult +dfb_input_device_set_keymap_entry( CoreInputDevice *device, + int keycode, + DFBInputDeviceKeymapEntry *entry ) +{ + D_MAGIC_ASSERT( device, CoreInputDevice ); + + D_ASSERT( core_input != NULL ); + D_ASSERT( device != NULL ); + D_ASSERT( entry != NULL ); + + return set_keymap_entry( device, keycode, entry ); +} + +DFBResult +dfb_input_device_load_keymap ( CoreInputDevice *device, + char *filename ) +{ + D_MAGIC_ASSERT( device, CoreInputDevice ); + + D_ASSERT( core_input != NULL ); + D_ASSERT( device != NULL ); + D_ASSERT( filename != NULL ); + + return load_keymap( device, filename ); +} + +DFBResult +dfb_input_device_reload_keymap( CoreInputDevice *device ) +{ + int ret; + InputDeviceShared *shared; + + D_MAGIC_ASSERT( device, CoreInputDevice ); + + shared = device->shared; + + D_ASSERT( shared != NULL ); + + D_INFO( "DirectFB/Input: Reloading keymap for '%s' [0x%02x]...\n", + shared->device_info.desc.name, shared->id ); + + if (fusion_call_execute( &shared->call, FCEF_NONE, CIDC_RELOAD_KEYMAP, NULL, &ret )) + return DFB_FUSION; + + return ret; +} + +DFBResult +dfb_input_device_set_sensitivity( CoreInputDevice *device, + int sensitivity ) +{ + int ret; + InputDeviceShared *shared; + + D_MAGIC_ASSERT( device, CoreInputDevice ); + + shared = device->shared; + D_ASSERT( shared != NULL ); + + if (fusion_call_execute( &shared->call, FCEF_NONE, CIDC_SET_SENSITIVITY, (void*)(long)sensitivity, &ret )) + return DFB_FUSION; + + return ret; +} + +DFBResult +dfb_input_rescan_devices( CoreDFB *core ) +{ + int ret; + + D_DEBUG_AT( Core_Input, "%s( %p )\n", __FUNCTION__, core ); + + D_ASSERT( core_input != NULL ); + + if (fusion_call_execute( &core_input->call, FCEF_NODIRECT, CICC_RESCAN_DEVICES, NULL, &ret )) + return DFB_FUSION; + + return ret; +} + +DFBResult +dfb_input_device_disconnected( CoreInputDevice *device ) +{ + D_DEBUG_AT( Core_Input, "%s( %p )\n", __FUNCTION__, device ); + + D_MAGIC_ASSERT( device, CoreInputDevice ); + + D_ASSERT( device->shared != NULL ); + + D_ASSUME( !(device->shared->state.flags & DISTATE_DISCONNECTED) ); + + device->shared->state.flags |= DISTATE_DISCONNECTED; + + return DFB_OK; +} + +DFBResult +dfb_input_device_reconnected( CoreInputDevice *device ) +{ + D_DEBUG_AT( Core_Input, "%s( %p )\n", __FUNCTION__, device ); + + D_MAGIC_ASSERT( device, CoreInputDevice ); + + D_ASSERT( device->shared != NULL ); + + D_ASSUME( device->shared->state.flags & DISTATE_DISCONNECTED ); + + device->shared->state.flags &= ~DISTATE_DISCONNECTED; + + return DFB_OK; +} + +DFBResult +dfb_input_device_get_state( const CoreInputDevice *device, + DFBInputDeviceState *ret_state ) +{ + D_DEBUG_AT( Core_Input, "%s( %p )\n", __FUNCTION__, device ); + + D_MAGIC_ASSERT( device, CoreInputDevice ); + + D_ASSERT( device->shared != NULL ); + + *ret_state = device->shared->state; + + return DFB_OK; +} + +DFBResult +dfb_input_core_attach( CoreDFB *core, + ReactionFunc func, + void *ctx, + Reaction *reaction ) +{ + D_DEBUG_AT( Core_Input, "%s( %p )\n", __FUNCTION__, core ); + + D_ASSERT( core_input != NULL ); + + return fusion_reactor_attach( core_input->reactor, func, ctx, reaction ); +} + +DFBResult +dfb_input_core_detach( CoreDFB *core, + Reaction *reaction ) +{ + D_DEBUG_AT( Core_Input, "%s( %p )\n", __FUNCTION__, core ); + + D_ASSERT( core_input != NULL ); + + return fusion_reactor_detach( core_input->reactor, reaction ); +} + +/** internal **/ + +static void +input_add_device( CoreInputDevice *device ) +{ + CoreInputCoreNotification notification; + + D_DEBUG_AT( Core_Input, "%s( %p )\n", __FUNCTION__, device ); + + D_MAGIC_ASSERT( device, CoreInputDevice ); + + D_ASSERT( core_input != NULL ); + D_ASSERT( device != NULL ); + D_ASSERT( device->shared != NULL ); + + if (core_input->num == MAX_INPUTDEVICES) { + D_ERROR( "DirectFB/Input: Maximum number of devices reached!\n" ); + return; + } + + core_local->devices[ core_local->num++ ] = device; + + core_input->devices[ core_input->num++ ] = device->shared; + + notification.flags = CICNF_NEW_DEVICE; + notification.device_id = device->shared->id; + + fusion_reactor_dispatch( core_input->reactor, ¬ification, true, NULL ); +} + +static void +allocate_device_keymap( CoreDFB *core, CoreInputDevice *device ) +{ + int i; + DFBInputDeviceKeymapEntry *entries; + FusionSHMPoolShared *pool = dfb_core_shmpool( core ); + InputDeviceShared *shared = device->shared; + DFBInputDeviceDescription *desc = &shared->device_info.desc; + int num_entries = desc->max_keycode - + desc->min_keycode + 1; + + D_DEBUG_AT( Core_Input, "%s( %p, %p )\n", __FUNCTION__, core, device ); + + D_MAGIC_ASSERT( device, CoreInputDevice ); + + D_ASSERT( core_input != NULL ); + + entries = SHCALLOC( pool, num_entries, sizeof(DFBInputDeviceKeymapEntry) ); + if (!entries) { + D_OOSHM(); + return; + } + + /* write -1 indicating entry is not fetched yet from driver */ + for (i=0; ikeymap.min_keycode = desc->min_keycode; + shared->keymap.max_keycode = desc->max_keycode; + shared->keymap.num_entries = num_entries; + shared->keymap.entries = entries; + +#if FUSION_BUILD_MULTI + /* we need to fetch the whole map, otherwise a slave would try to */ + for (i=desc->min_keycode; i<=desc->max_keycode; i++) + get_keymap_entry( device, i ); +#endif +} + +static int +make_id( DFBInputDeviceID prefered ) +{ + int i; + + D_DEBUG_AT( Core_Input, "%s( 0x%02x )\n", __FUNCTION__, prefered ); + + D_ASSERT( core_input != NULL ); + + for (i=0; inum; i++) { + CoreInputDevice *device = core_local->devices[i]; + + D_MAGIC_ASSERT( device, CoreInputDevice ); + + if (device->shared->id == prefered) + return make_id( (prefered < DIDID_ANY) ? DIDID_ANY : (prefered + 1) ); + } + + return prefered; +} + +static DFBResult +reload_keymap( CoreInputDevice *device ) +{ + int i; + InputDeviceShared *shared; + + D_DEBUG_AT( Core_Input, "%s( %p )\n", __FUNCTION__, device ); + + D_MAGIC_ASSERT( device, CoreInputDevice ); + + shared = device->shared; + + D_ASSERT( shared != NULL ); + + if (shared->device_info.desc.min_keycode < 0 || + shared->device_info.desc.max_keycode < 0) + return DFB_UNSUPPORTED; + + /* write -1 indicating entry is not fetched yet from driver */ + for (i=0; ikeymap.num_entries; i++) + shared->keymap.entries[i].code = -1; + + /* fetch the whole map */ + for (i=shared->keymap.min_keycode; i<=shared->keymap.max_keycode; i++) + get_keymap_entry( device, i ); + + D_INFO( "DirectFB/Input: Reloaded keymap for '%s' [0x%02x]\n", + shared->device_info.desc.name, shared->id ); + + return DFB_OK; +} + +static DFBResult +set_sensitivity( CoreInputDevice *device, + int sensitivity ) +{ + InputDriver *driver; + + D_DEBUG_AT( Core_Input, "%s( %p, %d )\n", __FUNCTION__, device, sensitivity ); + + D_MAGIC_ASSERT( device, CoreInputDevice ); + + driver = device->driver; + D_ASSERT( driver != NULL ); + + if (!driver->funcs->SetSensitivity) + return DFB_UNSUPPORTED; + + return driver->funcs->SetSensitivity( device, device->driver_data, sensitivity ); +} + +static FusionCallHandlerResult +input_device_call_handler( int caller, /* fusion id of the caller */ + int call_arg, /* optional call parameter */ + void *call_ptr, /* optional call parameter */ + void *ctx, /* optional handler context */ + unsigned int serial, + int *ret_val ) +{ + CoreInputDeviceCommand command = call_arg; + CoreInputDevice *device = ctx; + + D_DEBUG_AT( Core_Input, "%s( %d, %d, %p, %p )\n", __FUNCTION__, caller, call_arg, call_ptr, ctx ); + + D_MAGIC_ASSERT( device, CoreInputDevice ); + + switch (command) { + case CIDC_RELOAD_KEYMAP: + *ret_val = reload_keymap( device ); + break; + + case CIDC_SET_SENSITIVITY: + *ret_val = set_sensitivity( device, (long) call_ptr ); + break; + + default: + D_BUG( "unknown Core Input Device Command '%d'", command ); + *ret_val = DFB_BUG; + } + + return FCHR_RETURN; +} + +static DFBResult +init_axes( CoreInputDevice *device ) +{ + int i, num; + DFBResult ret; + InputDeviceShared *shared; + const InputDriverFuncs *funcs; + + D_DEBUG_AT( Core_Input, "%s( %p )\n", __FUNCTION__, device ); + + D_MAGIC_ASSERT( device, CoreInputDevice ); + D_ASSERT( device->driver != NULL ); + + funcs = device->driver->funcs; + D_ASSERT( funcs != NULL ); + + shared = device->shared; + D_ASSERT( shared != NULL ); + + if (shared->device_info.desc.max_axis < 0) + return DFB_OK; + + num = shared->device_info.desc.max_axis + 1; + + shared->axis_info = SHCALLOC( dfb_core_shmpool(device->core), num, sizeof(DFBInputDeviceAxisInfo) ); + if (!shared->axis_info) + return D_OOSHM(); + + shared->axis_num = num; + + if (funcs->GetAxisInfo) { + for (i=0; iGetAxisInfo( device, device->driver_data, i, &shared->axis_info[i] ); + if (ret) + D_DERROR( ret, "Core/Input: GetAxisInfo() failed for '%s' [%d] on axis %d!\n", + shared->device_info.desc.name, shared->id, i ); + } + } + + return DFB_OK; +} + +static void +init_drivers( CoreDFB *core ) +{ + DirectLink *next; + DirectModuleEntry *module; + + D_DEBUG_AT( Core_Input, "%s( %p )\n", __FUNCTION__, core ); + + D_ASSERT( core_input != NULL ); + + direct_list_foreach_safe (module, next, dfb_input_modules.entries) { + InputDriver *driver; + const InputDriverFuncs *funcs; + + funcs = direct_module_ref( module ); + if (!funcs) + continue; + + driver = D_CALLOC( 1, sizeof(InputDriver) ); + if (!driver) { + D_OOM(); + direct_module_unref( module ); + continue; + } + + D_ASSERT( funcs->GetDriverInfo != NULL ); + + funcs->GetDriverInfo( &driver->info ); + + driver->module = module; + driver->funcs = funcs; + + direct_list_prepend( &core_local->drivers, &driver->link ); + } +} + +static DFBResult +rescan_devices( CoreDFB *core ) +{ + InputDriver *driver; + FusionSHMPoolShared *pool = dfb_core_shmpool( core ); + + D_DEBUG_AT( Core_Input, "%s( %p )\n", __FUNCTION__, core ); + + D_ASSERT( core_input != NULL ); + + direct_list_foreach (driver, core_local->drivers) { + int i, num; + const InputDriverFuncs *funcs = driver->funcs; + + D_DEBUG_AT( Core_Input, " -> probing '%s'...\n", driver->info.name ); + + num = funcs->GetAvailable(); + + D_DEBUG_AT( Core_Input, " -> %d available device(s) provided by '%s'.\n", num, driver->info.name ); + + + for (i=driver->nr_devices; icore = core; + + memset( &device_info, 0, sizeof(InputDeviceInfo) ); + + device_info.desc.min_keycode = -1; + device_info.desc.max_keycode = -1; + + D_MAGIC_SET( device, CoreInputDevice ); + + if (funcs->OpenDevice( device, i, &device_info, &driver_data )) { + SHFREE( pool, shared ); + D_MAGIC_CLEAR( device ); + D_FREE( device ); + continue; + } + + D_DEBUG_AT( Core_Input, " -> opened '%s' (%d) %d.%d (%s)\n", + device_info.desc.name, i + 1, driver->info.version.major, + driver->info.version.minor, driver->info.vendor ); + + if (num > 1) + snprintf( buf, sizeof(buf), "%s (%d)", device_info.desc.name, i+1 ); + else + snprintf( buf, sizeof(buf), "%s", device_info.desc.name ); + + /* init skirmish */ + fusion_skirmish_init( &shared->lock, buf, dfb_core_world(core) ); + + /* create reactor */ + shared->reactor = fusion_reactor_new( sizeof(DFBInputEvent), buf, dfb_core_world(core) ); + + fusion_reactor_set_lock( shared->reactor, &shared->lock ); + + /* init call */ + fusion_call_init( &shared->call, input_device_call_handler, device, dfb_core_world(core) ); + + /* initialize shared data */ + shared->id = make_id(device_info.prefered_id); + shared->num = i; + shared->device_info = device_info; + shared->last_key = DIKI_UNKNOWN; + shared->first_press = true; + + /* initialize local data */ + device->shared = shared; + device->driver = driver; + device->driver_data = driver_data; + + D_INFO( "DirectFB/Input: %s %d.%d (%s)\n", + buf, driver->info.version.major, + driver->info.version.minor, driver->info.vendor ); + + if (device_info.desc.min_keycode > device_info.desc.max_keycode) { + D_BUG("min_keycode > max_keycode"); + device_info.desc.min_keycode = -1; + device_info.desc.max_keycode = -1; + } + else if (device_info.desc.min_keycode >= 0 && + device_info.desc.max_keycode >= 0) + allocate_device_keymap( core, device ); + + init_axes( device ); + + /* add it to the list */ + input_add_device( device ); + } + + driver->nr_devices = num; + } + + return DFB_OK; +} + +static DFBInputDeviceKeymapEntry * +get_keymap_entry( CoreInputDevice *device, + int code ) +{ + InputDeviceKeymap *map; + DFBInputDeviceKeymapEntry *entry; + + D_MAGIC_ASSERT( device, CoreInputDevice ); + + D_ASSERT( core_input != NULL ); + D_ASSERT( device != NULL ); + D_ASSERT( device->shared != NULL ); + + map = &device->shared->keymap; + + /* safety check */ + if (code < map->min_keycode || code > map->max_keycode) + return NULL; + + /* point to right array index */ + entry = &map->entries[code - map->min_keycode]; + + /* need to initialize? */ + if (entry->code != code) { + DFBResult ret; + InputDriver *driver = device->driver; + + if (!driver) { + D_BUG("seem to be a slave with an empty keymap"); + return NULL; + } + + /* write keycode to entry */ + entry->code = code; + + /* fetch entry from driver */ + ret = driver->funcs->GetKeymapEntry( device, + device->driver_data, entry ); + if (ret) + return NULL; + + /* drivers may leave this blank */ + if (entry->identifier == DIKI_UNKNOWN) + entry->identifier = symbol_to_id( entry->symbols[DIKSI_BASE] ); + + if (entry->symbols[DIKSI_BASE_SHIFT] == DIKS_NULL) + entry->symbols[DIKSI_BASE_SHIFT] = entry->symbols[DIKSI_BASE]; + + if (entry->symbols[DIKSI_ALT] == DIKS_NULL) + entry->symbols[DIKSI_ALT] = entry->symbols[DIKSI_BASE]; + + if (entry->symbols[DIKSI_ALT_SHIFT] == DIKS_NULL) + entry->symbols[DIKSI_ALT_SHIFT] = entry->symbols[DIKSI_ALT]; + } + + return entry; +} + +/* replace a single keymap entry with the code-entry pair */ +static DFBResult +set_keymap_entry( CoreInputDevice *device, + int code, + DFBInputDeviceKeymapEntry *entry ) +{ + InputDeviceKeymap *map; + + D_ASSERT( device->shared != NULL ); + D_ASSERT( device->shared->keymap.entries != NULL ); + + map = &device->shared->keymap; + + /* sanity check */ + if (code < map->min_keycode || code > map->max_keycode) + return DFB_FAILURE; + + /* copy the entry to the map */ + map->entries[code - map->min_keycode] = *entry; + + return DFB_OK; +} + +/* replace the complete current keymap with a keymap from a file. + * the minimum-maximum keycodes of the driver are to be respected. + */ +static DFBResult +load_keymap( CoreInputDevice *device, + char *filename ) +{ + DFBResult ret = DFB_OK; + InputDeviceKeymap *map = 0; + FILE *file = 0; + DFBInputDeviceLockState lockstate = 0; + + D_ASSERT( device->shared != NULL ); + D_ASSERT( device->shared->keymap.entries != NULL ); + + map = &device->shared->keymap; + + /* open the file */ + file = fopen( filename, "r" ); + if( !file ) + { + return errno2result( errno ); + } + + /* read the file, line by line, and consume the mentioned scancodes */ + while(1) + { + int i; + int dummy; + char buffer[201]; + int keycode; + char diki[201]; + char diks[4][201]; + char *b; + + DFBInputDeviceKeymapEntry entry = { .code = 0 }; + + b = fgets( buffer, 200, file ); + if( !b ) { + if( feof(file) ) { + fclose(file); + return DFB_OK; + } + fclose(file); + return errno2result(errno); + } + + /* comment or empty line */ + if( buffer[0]=='#' || strcmp(buffer,"\n")==0 ) + continue; + + /* check for lock state change */ + if( !strncmp(buffer,"capslock:",9) ) { lockstate |= DILS_CAPS; continue; } + if( !strncmp(buffer,":capslock",9) ) { lockstate &= ~DILS_CAPS; continue; } + if( !strncmp(buffer,"numlock:",8) ) { lockstate |= DILS_NUM; continue; } + if( !strncmp(buffer,":numlock",8) ) { lockstate &= ~DILS_NUM; continue; } + + i = sscanf( buffer, " keycode %i = %s = %s %s %s %s %i\n", + &keycode, diki, diks[0], diks[1], diks[2], diks[3], &dummy ); + + if( i < 3 || i > 6 ) { + /* we want 1 to 4 key symbols */ + D_INFO( "DirectFB/Input: skipped erroneous input line %s\n", buffer ); + continue; + } + + if( keycode > map->max_keycode || keycode < map->min_keycode ) { + D_INFO( "DirectFB/Input: skipped keycode %d out of range\n", keycode ); + continue; + } + + entry.code = keycode; + entry.locks = lockstate; + entry.identifier = lookup_keyidentifier( diki ); + + switch( i ) { + case 6: entry.symbols[3] = lookup_keysymbol( diks[3] ); + case 5: entry.symbols[2] = lookup_keysymbol( diks[2] ); + case 4: entry.symbols[1] = lookup_keysymbol( diks[1] ); + case 3: entry.symbols[0] = lookup_keysymbol( diks[0] ); + + /* fall through */ + } + + switch( i ) { + case 3: entry.symbols[1] = entry.symbols[0]; + case 4: entry.symbols[2] = entry.symbols[0]; + case 5: entry.symbols[3] = entry.symbols[1]; + + /* fall through */ + } + + ret = set_keymap_entry( device, keycode, &entry ); + if( ret ) + return ret; + } +} + +static DFBInputDeviceKeySymbol lookup_keysymbol( char *symbolname ) +{ + int i; + + /* we want uppercase */ + for( i=0; i= 'a' && symbolname[i] <= 'z' ) + symbolname[i] = symbolname[i] - 'a' + 'A'; + + for( i=0; i < sizeof (KeySymbolNames) / sizeof (KeySymbolNames[0]); i++ ) { + if( strcmp( symbolname, KeySymbolNames[i].name ) == 0 ) + return KeySymbolNames[i].symbol; + } + + /* not found, maybe starting with 0x for raw conversion. + * We are already at uppercase. + */ + if( symbolname[0]=='0' && symbolname[1]=='X' ) { + int code=0; + symbolname+=2; + while(*symbolname) { + if( *symbolname >= '0' && *symbolname <= '9' ) { + code = code*16 + *symbolname - '0'; + } else if( *symbolname >= 'A' && *symbolname <= 'F' ) { + code = code*16 + *symbolname - 'A' + 10; + } else { + /* invalid character */ + return DIKS_NULL; + } + symbolname++; + } + return code; + } + + return DIKS_NULL; +} + +static DFBInputDeviceKeyIdentifier lookup_keyidentifier( char *identifiername ) +{ + int i; + + /* we want uppercase */ + for( i=0; i= 'a' && identifiername[i] <= 'z' ) + identifiername[i] = identifiername[i] - 'a' + 'A'; + + for( i=0; i < sizeof (KeyIdentifierNames) / sizeof (KeyIdentifierNames[0]); i++ ) { + if( strcmp( identifiername, KeyIdentifierNames[i].name ) == 0 ) + return KeyIdentifierNames[i].identifier; + } + + return DIKI_UNKNOWN; +} + +static bool +lookup_from_table( CoreInputDevice *device, + DFBInputEvent *event, + DFBInputEventFlags lookup ) +{ + DFBInputDeviceKeymapEntry *entry; + + D_MAGIC_ASSERT( device, CoreInputDevice ); + + D_ASSERT( core_input != NULL ); + D_ASSERT( device != NULL ); + D_ASSERT( device->shared != NULL ); + D_ASSERT( event != NULL ); + + /* fetch the entry from the keymap, possibly calling the driver */ + entry = get_keymap_entry( device, event->key_code ); + if (!entry) + return false; + + /* lookup identifier */ + if (lookup & DIEF_KEYID) + event->key_id = entry->identifier; + + /* lookup symbol */ + if (lookup & DIEF_KEYSYMBOL) { + DFBInputDeviceKeymapSymbolIndex index = + (event->modifiers & DIMM_ALTGR) ? DIKSI_ALT : DIKSI_BASE; + + if (!(event->modifiers & DIMM_SHIFT) ^ !(entry->locks & event->locks)) + index++; + + /* don't modify modifiers */ + if (DFB_KEY_TYPE( entry->symbols[DIKSI_BASE] ) == DIKT_MODIFIER) + event->key_symbol = entry->symbols[DIKSI_BASE]; + else + event->key_symbol = entry->symbols[index]; + } + + return true; +} + +static int +find_key_code_by_id( CoreInputDevice *device, + DFBInputDeviceKeyIdentifier id ) +{ + int i; + InputDeviceKeymap *map; + + D_MAGIC_ASSERT( device, CoreInputDevice ); + + D_ASSERT( core_input != NULL ); + D_ASSERT( device != NULL ); + D_ASSERT( device->shared != NULL ); + + map = &device->shared->keymap; + + for (i=0; inum_entries; i++) { + DFBInputDeviceKeymapEntry *entry = &map->entries[i]; + + if (entry->identifier == id) + return entry->code; + } + + return -1; +} + +static int +find_key_code_by_symbol( CoreInputDevice *device, + DFBInputDeviceKeySymbol symbol ) +{ + int i; + InputDeviceKeymap *map; + + D_MAGIC_ASSERT( device, CoreInputDevice ); + + D_ASSERT( core_input != NULL ); + D_ASSERT( device != NULL ); + D_ASSERT( device->shared != NULL ); + + map = &device->shared->keymap; + + for (i=0; inum_entries; i++) { + int n; + DFBInputDeviceKeymapEntry *entry = &map->entries[i]; + + for (n=0; n<=DIKSI_LAST; n++) + if (entry->symbols[n] == symbol) + return entry->code; + } + + return -1; +} + +#define FIXUP_KEY_FIELDS (DIEF_MODIFIERS | DIEF_LOCKS | \ + DIEF_KEYCODE | DIEF_KEYID | DIEF_KEYSYMBOL) + +/* + * Fill partially missing values for key_code, key_id and key_symbol by + * translating those that are set. Fix modifiers/locks before if not set. + * + * + * There are five valid constellations that give reasonable values. + * (not counting the constellation where everything is set) + * + * Device has no translation table + * 1. key_id is set, key_symbol not + * -> key_code defaults to -1, key_symbol from key_id (up-translation) + * 2. key_symbol is set, key_id not + * -> key_code defaults to -1, key_id from key_symbol (down-translation) + * + * Device has a translation table + * 3. key_code is set + * -> look up key_id and/or key_symbol (key_code being the index) + * 4. key_id is set + * -> look up key_code and possibly key_symbol (key_id being searched for) + * 5. key_symbol is set + * -> look up key_code and key_id (key_symbol being searched for) + * + * Fields remaining will be set to the default, e.g. key_code to -1. + */ +static void +fixup_key_event( CoreInputDevice *device, DFBInputEvent *event ) +{ + int i; + DFBInputEventFlags valid = event->flags & FIXUP_KEY_FIELDS; + DFBInputEventFlags missing = valid ^ FIXUP_KEY_FIELDS; + InputDeviceShared *shared = device->shared; + + D_MAGIC_ASSERT( device, CoreInputDevice ); + + /* Add missing flags */ + event->flags |= missing; + + /* + * Use cached values for modifiers/locks if they are missing. + */ + if (missing & DIEF_MODIFIERS) + event->modifiers = shared->modifiers_l | shared->modifiers_r; + + if (missing & DIEF_LOCKS) + event->locks = shared->locks; + + /* + * With translation table + */ + if (device->shared->keymap.num_entries) { + if (valid & DIEF_KEYCODE) { + lookup_from_table( device, event, missing ); + + missing &= ~(DIEF_KEYID | DIEF_KEYSYMBOL); + } + else if (valid & DIEF_KEYID) { + event->key_code = find_key_code_by_id( device, event->key_id ); + + if (event->key_code != -1) { + lookup_from_table( device, event, missing ); + + missing &= ~(DIEF_KEYCODE | DIEF_KEYSYMBOL); + } + else if (missing & DIEF_KEYSYMBOL) { + event->key_symbol = id_to_symbol( event->key_id, + event->modifiers, + event->locks ); + missing &= ~DIEF_KEYSYMBOL; + } + } + else if (valid & DIEF_KEYSYMBOL) { + event->key_code = find_key_code_by_symbol( device, + event->key_symbol ); + + if (event->key_code != -1) { + lookup_from_table( device, event, missing ); + + missing &= ~(DIEF_KEYCODE | DIEF_KEYID); + } + else { + event->key_symbol = symbol_to_id( event->key_symbol ); + missing &= ~DIEF_KEYSYMBOL; + } + } + } + else { + /* + * Without translation table + */ + if (valid & DIEF_KEYID) { + if (missing & DIEF_KEYSYMBOL) { + event->key_symbol = id_to_symbol( event->key_id, + event->modifiers, + event->locks ); + missing &= ~DIEF_KEYSYMBOL; + } + } + else if (valid & DIEF_KEYSYMBOL) { + event->key_id = symbol_to_id( event->key_symbol ); + missing &= ~DIEF_KEYID; + } + } + + /* + * Clear remaining fields. + */ + if (missing & DIEF_KEYCODE) + event->key_code = -1; + + if (missing & DIEF_KEYID) + event->key_id = DIKI_UNKNOWN; + + if (missing & DIEF_KEYSYMBOL) + event->key_symbol = DIKS_NULL; + + /* + * Update cached values for modifiers. + */ + if (DFB_KEY_TYPE(event->key_symbol) == DIKT_MODIFIER) { + if (event->type == DIET_KEYPRESS) { + switch (event->key_id) { + case DIKI_SHIFT_L: + shared->modifiers_l |= DIMM_SHIFT; + break; + case DIKI_SHIFT_R: + shared->modifiers_r |= DIMM_SHIFT; + break; + case DIKI_CONTROL_L: + shared->modifiers_l |= DIMM_CONTROL; + break; + case DIKI_CONTROL_R: + shared->modifiers_r |= DIMM_CONTROL; + break; + case DIKI_ALT_L: + shared->modifiers_l |= DIMM_ALT; + break; + case DIKI_ALT_R: + shared->modifiers_r |= (event->key_symbol == DIKS_ALTGR) ? DIMM_ALTGR : DIMM_ALT; + break; + case DIKI_META_L: + shared->modifiers_l |= DIMM_META; + break; + case DIKI_META_R: + shared->modifiers_r |= DIMM_META; + break; + case DIKI_SUPER_L: + shared->modifiers_l |= DIMM_SUPER; + break; + case DIKI_SUPER_R: + shared->modifiers_r |= DIMM_SUPER; + break; + case DIKI_HYPER_L: + shared->modifiers_l |= DIMM_HYPER; + break; + case DIKI_HYPER_R: + shared->modifiers_r |= DIMM_HYPER; + break; + default: + ; + } + } + else { + switch (event->key_id) { + case DIKI_SHIFT_L: + shared->modifiers_l &= ~DIMM_SHIFT; + break; + case DIKI_SHIFT_R: + shared->modifiers_r &= ~DIMM_SHIFT; + break; + case DIKI_CONTROL_L: + shared->modifiers_l &= ~DIMM_CONTROL; + break; + case DIKI_CONTROL_R: + shared->modifiers_r &= ~DIMM_CONTROL; + break; + case DIKI_ALT_L: + shared->modifiers_l &= ~DIMM_ALT; + break; + case DIKI_ALT_R: + shared->modifiers_r &= (event->key_symbol == DIKS_ALTGR) ? ~DIMM_ALTGR : ~DIMM_ALT; + break; + case DIKI_META_L: + shared->modifiers_l &= ~DIMM_META; + break; + case DIKI_META_R: + shared->modifiers_r &= ~DIMM_META; + break; + case DIKI_SUPER_L: + shared->modifiers_l &= ~DIMM_SUPER; + break; + case DIKI_SUPER_R: + shared->modifiers_r &= ~DIMM_SUPER; + break; + case DIKI_HYPER_L: + shared->modifiers_l &= ~DIMM_HYPER; + break; + case DIKI_HYPER_R: + shared->modifiers_r &= ~DIMM_HYPER; + break; + default: + ; + } + } + + /* write back to event */ + if (missing & DIEF_MODIFIERS) + event->modifiers = shared->modifiers_l | shared->modifiers_r; + } + + /* + * Update cached values for locks. + */ + if (event->type == DIET_KEYPRESS) { + + /* When we receive a new key press, toggle lock flags */ + if (shared->first_press || shared->last_key != event->key_id) { + switch (event->key_id) { + case DIKI_CAPS_LOCK: + shared->locks ^= DILS_CAPS; + break; + case DIKI_NUM_LOCK: + shared->locks ^= DILS_NUM; + break; + case DIKI_SCROLL_LOCK: + shared->locks ^= DILS_SCROLL; + break; + default: + ; + } + } + + /* write back to event */ + if (missing & DIEF_LOCKS) + event->locks = shared->locks; + + /* store last pressed key */ + shared->last_key = event->key_id; + shared->first_press = false; + } + else if (event->type == DIET_KEYRELEASE) { + + shared->first_press = true; + } + + /* Handle dead keys. */ + if (DFB_KEY_TYPE(shared->last_symbol) == DIKT_DEAD) { + for (i=0; ideadkey == shared->last_symbol) { + for (i=0; map->combos[i].target; i++) { + if (map->combos[i].target == event->key_symbol) { + event->key_symbol = map->combos[i].result; + break; + } + } + break; + } + } + + if (event->type == DIET_KEYRELEASE && + DFB_KEY_TYPE(event->key_symbol) != DIKT_MODIFIER) + shared->last_symbol = event->key_symbol; + } + else + shared->last_symbol = event->key_symbol; +} + +static void +fixup_mouse_event( CoreInputDevice *device, DFBInputEvent *event ) +{ + InputDeviceShared *shared = device->shared; + + D_MAGIC_ASSERT( device, CoreInputDevice ); + + if (event->flags & DIEF_BUTTONS) { + shared->buttons = event->buttons; + } + else { + switch (event->type) { + case DIET_BUTTONPRESS: + shared->buttons |= (1 << event->button); + break; + case DIET_BUTTONRELEASE: + shared->buttons &= ~(1 << event->button); + break; + default: + ; + } + + /* Add missing flag */ + event->flags |= DIEF_BUTTONS; + + event->buttons = shared->buttons; + } + + switch (event->type) { + case DIET_AXISMOTION: + if ((event->flags & DIEF_AXISABS) && event->axis >= 0 && event->axis < shared->axis_num) { + if (!(event->flags & DIEF_MIN) && (shared->axis_info[event->axis].flags & DIAIF_ABS_MIN)) { + event->min = shared->axis_info[event->axis].abs_min; + + event->flags |= DIEF_MIN; + } + + if (!(event->flags & DIEF_MAX) && (shared->axis_info[event->axis].flags & DIAIF_ABS_MAX)) { + event->max = shared->axis_info[event->axis].abs_max; + + event->flags |= DIEF_MAX; + } + } + break; + + default: + break; + } +} + +static DFBInputDeviceKeyIdentifier +symbol_to_id( DFBInputDeviceKeySymbol symbol ) +{ + if (symbol >= 'a' && symbol <= 'z') + return DIKI_A + symbol - 'a'; + + if (symbol >= 'A' && symbol <= 'Z') + return DIKI_A + symbol - 'A'; + + if (symbol >= '0' && symbol <= '9') + return DIKI_0 + symbol - '0'; + + if (symbol >= DIKS_F1 && symbol <= DIKS_F12) + return DIKI_F1 + symbol - DIKS_F1; + + switch (symbol) { + case DIKS_ESCAPE: + return DIKI_ESCAPE; + + case DIKS_CURSOR_LEFT: + return DIKI_LEFT; + + case DIKS_CURSOR_RIGHT: + return DIKI_RIGHT; + + case DIKS_CURSOR_UP: + return DIKI_UP; + + case DIKS_CURSOR_DOWN: + return DIKI_DOWN; + + case DIKS_ALTGR: + return DIKI_ALT_R; + + case DIKS_CONTROL: + return DIKI_CONTROL_L; + + case DIKS_SHIFT: + return DIKI_SHIFT_L; + + case DIKS_ALT: + return DIKI_ALT_L; + + case DIKS_META: + return DIKI_META_L; + + case DIKS_SUPER: + return DIKI_SUPER_L; + + case DIKS_HYPER: + return DIKI_HYPER_L; + + case DIKS_TAB: + return DIKI_TAB; + + case DIKS_ENTER: + return DIKI_ENTER; + + case DIKS_SPACE: + return DIKI_SPACE; + + case DIKS_BACKSPACE: + return DIKI_BACKSPACE; + + case DIKS_INSERT: + return DIKI_INSERT; + + case DIKS_DELETE: + return DIKI_DELETE; + + case DIKS_HOME: + return DIKI_HOME; + + case DIKS_END: + return DIKI_END; + + case DIKS_PAGE_UP: + return DIKI_PAGE_UP; + + case DIKS_PAGE_DOWN: + return DIKI_PAGE_DOWN; + + case DIKS_CAPS_LOCK: + return DIKI_CAPS_LOCK; + + case DIKS_NUM_LOCK: + return DIKI_NUM_LOCK; + + case DIKS_SCROLL_LOCK: + return DIKI_SCROLL_LOCK; + + case DIKS_PRINT: + return DIKI_PRINT; + + case DIKS_PAUSE: + return DIKI_PAUSE; + + case DIKS_BACKSLASH: + return DIKI_BACKSLASH; + + case DIKS_PERIOD: + return DIKI_PERIOD; + + case DIKS_COMMA: + return DIKI_COMMA; + + default: + ; + } + + return DIKI_UNKNOWN; +} + +static DFBInputDeviceKeySymbol +id_to_symbol( DFBInputDeviceKeyIdentifier id, + DFBInputDeviceModifierMask modifiers, + DFBInputDeviceLockState locks ) +{ + bool shift = !(modifiers & DIMM_SHIFT) ^ !(locks & DILS_CAPS); + + if (id >= DIKI_A && id <= DIKI_Z) + return (shift ? DIKS_CAPITAL_A : DIKS_SMALL_A) + id - DIKI_A; + + if (id >= DIKI_0 && id <= DIKI_9) + return DIKS_0 + id - DIKI_0; + + if (id >= DIKI_KP_0 && id <= DIKI_KP_9) + return DIKS_0 + id - DIKI_KP_0; + + if (id >= DIKI_F1 && id <= DIKI_F12) + return DIKS_F1 + id - DIKI_F1; + + switch (id) { + case DIKI_ESCAPE: + return DIKS_ESCAPE; + + case DIKI_LEFT: + return DIKS_CURSOR_LEFT; + + case DIKI_RIGHT: + return DIKS_CURSOR_RIGHT; + + case DIKI_UP: + return DIKS_CURSOR_UP; + + case DIKI_DOWN: + return DIKS_CURSOR_DOWN; + + case DIKI_CONTROL_L: + case DIKI_CONTROL_R: + return DIKS_CONTROL; + + case DIKI_SHIFT_L: + case DIKI_SHIFT_R: + return DIKS_SHIFT; + + case DIKI_ALT_L: + case DIKI_ALT_R: + return DIKS_ALT; + + case DIKI_META_L: + case DIKI_META_R: + return DIKS_META; + + case DIKI_SUPER_L: + case DIKI_SUPER_R: + return DIKS_SUPER; + + case DIKI_HYPER_L: + case DIKI_HYPER_R: + return DIKS_HYPER; + + case DIKI_TAB: + return DIKS_TAB; + + case DIKI_ENTER: + return DIKS_ENTER; + + case DIKI_SPACE: + return DIKS_SPACE; + + case DIKI_BACKSPACE: + return DIKS_BACKSPACE; + + case DIKI_INSERT: + return DIKS_INSERT; + + case DIKI_DELETE: + return DIKS_DELETE; + + case DIKI_HOME: + return DIKS_HOME; + + case DIKI_END: + return DIKS_END; + + case DIKI_PAGE_UP: + return DIKS_PAGE_UP; + + case DIKI_PAGE_DOWN: + return DIKS_PAGE_DOWN; + + case DIKI_CAPS_LOCK: + return DIKS_CAPS_LOCK; + + case DIKI_NUM_LOCK: + return DIKS_NUM_LOCK; + + case DIKI_SCROLL_LOCK: + return DIKS_SCROLL_LOCK; + + case DIKI_PRINT: + return DIKS_PRINT; + + case DIKI_PAUSE: + return DIKS_PAUSE; + + case DIKI_KP_DIV: + return DIKS_SLASH; + + case DIKI_KP_MULT: + return DIKS_ASTERISK; + + case DIKI_KP_MINUS: + return DIKS_MINUS_SIGN; + + case DIKI_KP_PLUS: + return DIKS_PLUS_SIGN; + + case DIKI_KP_ENTER: + return DIKS_ENTER; + + case DIKI_KP_SPACE: + return DIKS_SPACE; + + case DIKI_KP_TAB: + return DIKS_TAB; + + case DIKI_KP_EQUAL: + return DIKS_EQUALS_SIGN; + + case DIKI_KP_DECIMAL: + return DIKS_PERIOD; + + case DIKI_KP_SEPARATOR: + return DIKS_COMMA; + + case DIKI_BACKSLASH: + return DIKS_BACKSLASH; + + case DIKI_EQUALS_SIGN: + return DIKS_EQUALS_SIGN; + + case DIKI_LESS_SIGN: + return DIKS_LESS_THAN_SIGN; + + case DIKI_MINUS_SIGN: + return DIKS_MINUS_SIGN; + + case DIKI_PERIOD: + return DIKS_PERIOD; + + case DIKI_QUOTE_LEFT: + case DIKI_QUOTE_RIGHT: + return DIKS_QUOTATION; + + case DIKI_SEMICOLON: + return DIKS_SEMICOLON; + + case DIKI_SLASH: + return DIKS_SLASH; + + default: + ; + } + + return DIKS_NULL; +} + +static void +release_key( CoreInputDevice *device, DFBInputDeviceKeyIdentifier id ) +{ + DFBInputEvent evt; + + D_MAGIC_ASSERT( device, CoreInputDevice ); + + evt.type = DIET_KEYRELEASE; + + if (DFB_KEY_TYPE(id) == DIKT_IDENTIFIER) { + evt.flags = DIEF_KEYID; + evt.key_id = id; + } + else { + evt.flags = DIEF_KEYSYMBOL; + evt.key_symbol = id; + } + + dfb_input_dispatch( device, &evt ); +} + +static void +flush_keys( CoreInputDevice *device ) +{ + D_MAGIC_ASSERT( device, CoreInputDevice ); + + if (device->shared->modifiers_l) { + if (device->shared->modifiers_l & DIMM_ALT) + release_key( device, DIKI_ALT_L ); + + if (device->shared->modifiers_l & DIMM_CONTROL) + release_key( device, DIKI_CONTROL_L ); + + if (device->shared->modifiers_l & DIMM_HYPER) + release_key( device, DIKI_HYPER_L ); + + if (device->shared->modifiers_l & DIMM_META) + release_key( device, DIKI_META_L ); + + if (device->shared->modifiers_l & DIMM_SHIFT) + release_key( device, DIKI_SHIFT_L ); + + if (device->shared->modifiers_l & DIMM_SUPER) + release_key( device, DIKI_SUPER_L ); + } + + if (device->shared->modifiers_r) { + if (device->shared->modifiers_r & DIMM_ALTGR) + release_key( device, DIKS_ALTGR ); + + if (device->shared->modifiers_r & DIMM_ALT) + release_key( device, DIKI_ALT_R ); + + if (device->shared->modifiers_r & DIMM_CONTROL) + release_key( device, DIKI_CONTROL_R ); + + if (device->shared->modifiers_r & DIMM_HYPER) + release_key( device, DIKI_HYPER_R ); + + if (device->shared->modifiers_r & DIMM_META) + release_key( device, DIKI_META_R ); + + if (device->shared->modifiers_r & DIMM_SHIFT) + release_key( device, DIKI_SHIFT_R ); + + if (device->shared->modifiers_r & DIMM_SUPER) + release_key( device, DIKI_SUPER_R ); + } +} + +static void +dump_primary_layer_surface( CoreDFB *core ) +{ + CoreLayer *layer = dfb_layer_at( DLID_PRIMARY ); + CoreLayerContext *context; + + /* Get the currently active context. */ + if (dfb_layer_get_active_context( layer, &context ) == DFB_OK) { + CoreLayerRegion *region; + + /* Get the first region. */ + if (dfb_layer_context_get_primary_region( context, + false, ®ion ) == DFB_OK) + { + CoreSurface *surface; + + /* Lock the region to avoid tearing due to concurrent updates. */ + dfb_layer_region_lock( region ); + + /* Get the surface of the region. */ + if (dfb_layer_region_get_surface( region, &surface ) == DFB_OK) { + /* Dump the surface contents. */ + dfb_surface_dump_buffer( surface, CSBR_FRONT, dfb_config->screenshot_dir, "dfb" ); + + /* Release the surface. */ + dfb_surface_unref( surface ); + } + + /* Unlock the region. */ + dfb_layer_region_unlock( region ); + + /* Release the region. */ + dfb_layer_region_unref( region ); + } + + /* Release the context. */ + dfb_layer_context_unref( context ); + } +} + +static bool +core_input_filter( CoreInputDevice *device, DFBInputEvent *event ) +{ + D_MAGIC_ASSERT( device, CoreInputDevice ); + + if (dfb_system_input_filter( device, event )) + return true; + + if (event->type == DIET_KEYPRESS) { + switch (event->key_symbol) { + case DIKS_PRINT: + if (!event->modifiers && dfb_config->screenshot_dir) { + dump_primary_layer_surface( device->core ); + return true; + } + break; + + case DIKS_BACKSPACE: + if (event->modifiers == DIMM_META) + direct_trace_print_stacks(); + + break; + + case DIKS_ESCAPE: + if (event->modifiers == DIMM_META) { +#if FUSION_BUILD_MULTI + DFBResult ret; + CoreLayer *layer = dfb_layer_at( DLID_PRIMARY ); + CoreLayerContext *context; + + /* Get primary (shared) context. */ + ret = dfb_layer_get_primary_context( layer, + false, &context ); + if (ret) + return false; + + /* Activate the context. */ + dfb_layer_activate_context( layer, context ); + + /* Release the context. */ + dfb_layer_context_unref( context ); + +#else + kill( 0, SIGINT ); +#endif + + return true; + } + break; + + default: + break; + } + } + + return false; +} + diff --git a/Source/DirectFB/src/core/input.h b/Source/DirectFB/src/core/input.h new file mode 100755 index 0000000..0e21e2c --- /dev/null +++ b/Source/DirectFB/src/core/input.h @@ -0,0 +1,203 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef __INPUT_H__ +#define __INPUT_H__ + +#include +#include + +#include + +#include + +#include + + + +DECLARE_MODULE_DIRECTORY( dfb_input_modules ); + + +/* + * Increase this number when changes result in binary incompatibility! + */ +#define DFB_INPUT_DRIVER_ABI_VERSION 7 + +#define DFB_INPUT_DRIVER_INFO_NAME_LENGTH 48 +#define DFB_INPUT_DRIVER_INFO_VENDOR_LENGTH 64 + + +typedef struct { + int major; /* major version */ + int minor; /* minor version */ +} InputDriverVersion; /* major.minor, e.g. 0.1 */ + +typedef struct { + InputDriverVersion version; + + char name[DFB_INPUT_DRIVER_INFO_NAME_LENGTH]; + /* Name of driver, + e.g. 'Serial Mouse Driver' */ + + char vendor[DFB_INPUT_DRIVER_INFO_VENDOR_LENGTH]; + /* Vendor (or author) of the driver, + e.g. 'directfb.org' or 'Sven Neumann' */ +} InputDriverInfo; + +typedef struct { + unsigned int prefered_id; /* Prefered predefined input device id, + e.g. DIDID_MOUSE */ + + DFBInputDeviceDescription desc; /* Capabilities, type, etc. */ + DFBInputDeviceState state; +} InputDeviceInfo; + +typedef struct { + int (*GetAvailable) (void); + void (*GetDriverInfo) (InputDriverInfo *driver_info); + DFBResult (*OpenDevice) (CoreInputDevice *device, + unsigned int number, + InputDeviceInfo *device_info, + void **driver_data); + DFBResult (*GetKeymapEntry) (CoreInputDevice *device, + void *driver_data, + DFBInputDeviceKeymapEntry *entry); + void (*CloseDevice) (void *driver_data); + + DFBResult (*GetAxisInfo) (CoreInputDevice *device, + void *driver_data, + DFBInputDeviceAxisIdentifier axis, + DFBInputDeviceAxisInfo *ret_info); + + DFBResult (*SetSensitivity) (CoreInputDevice *device, + void *driver_data, + int sensitivity ); +} InputDriverFuncs; + + +typedef DFBEnumerationResult (*InputDeviceCallback) (CoreInputDevice *device, + void *ctx); + +void dfb_input_enumerate_devices( InputDeviceCallback callback, + void *ctx, + DFBInputDeviceCapabilities caps ); + + +DirectResult dfb_input_attach ( CoreInputDevice *device, + ReactionFunc func, + void *ctx, + Reaction *reaction ); + +DirectResult dfb_input_detach ( CoreInputDevice *device, + Reaction *reaction ); + +DirectResult dfb_input_attach_global( CoreInputDevice *device, + int index, + void *ctx, + GlobalReaction *reaction ); + +DirectResult dfb_input_detach_global( CoreInputDevice *device, + GlobalReaction *reaction ); + + +DFBResult dfb_input_add_global ( ReactionFunc func, + int *ret_index ); + +DFBResult dfb_input_set_global ( ReactionFunc func, + int index ); + + +void dfb_input_dispatch ( CoreInputDevice *device, + DFBInputEvent *event ); + + + +void dfb_input_device_description( const CoreInputDevice *device, + DFBInputDeviceDescription *desc ); + +DFBInputDeviceID dfb_input_device_id ( const CoreInputDevice *device ); + +CoreInputDevice *dfb_input_device_at ( DFBInputDeviceID id ); + + + +DFBResult dfb_input_device_get_keymap_entry( CoreInputDevice *device, + int keycode, + DFBInputDeviceKeymapEntry *entry ); + +DFBResult dfb_input_device_set_keymap_entry( CoreInputDevice *device, + int keycode, + DFBInputDeviceKeymapEntry *entry ); + +DFBResult dfb_input_device_load_keymap ( CoreInputDevice *device, + char *filename ); + +DFBResult dfb_input_device_reload_keymap ( CoreInputDevice *device ); + +DFBResult dfb_input_device_set_sensitivity( CoreInputDevice *device, + int sensitivity ); + +DFBResult dfb_input_rescan_devices( CoreDFB *core ); + +DFBResult dfb_input_device_disconnected( CoreInputDevice *device ); +DFBResult dfb_input_device_reconnected ( CoreInputDevice *device ); + +DFBResult dfb_input_device_get_state( const CoreInputDevice *device, + DFBInputDeviceState *ret_state ); + + + +typedef enum { + CICNF_NONE = 0x00000000, + + CICNF_NEW_DEVICE = 0x00000001, + + CICNF_ALL = 0x00000001, +} CoreInputCoreNotificationFlags; + +typedef struct { + CoreInputCoreNotificationFlags flags; + + DFBInputDeviceID device_id; +} CoreInputCoreNotification; + + +DFBResult dfb_input_core_attach( CoreDFB *core, + ReactionFunc func, + void *ctx, + Reaction *reaction ); + +DFBResult dfb_input_core_detach( CoreDFB *core, + Reaction *reaction ); +/* global reactions */ + +typedef enum { + DFB_WINDOWSTACK_INPUTDEVICE_LISTENER +} DFB_INPUT_GLOBALS; + +#endif diff --git a/Source/DirectFB/src/core/input_driver.h b/Source/DirectFB/src/core/input_driver.h new file mode 100755 index 0000000..41c4e0e --- /dev/null +++ b/Source/DirectFB/src/core/input_driver.h @@ -0,0 +1,103 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef __INPUT_DRIVER_H__ +#define __INPUT_DRIVER_H__ + +#include + + +static int +driver_get_available( void ); + +static void +driver_get_info( InputDriverInfo *info ); + +static DFBResult +driver_open_device( CoreInputDevice *device, + unsigned int number, + InputDeviceInfo *info, + void **driver_data ); + +static DFBResult +driver_get_keymap_entry( CoreInputDevice *device, + void *driver_data, + DFBInputDeviceKeymapEntry *entry ); + +#ifdef DFB_INPUTDRIVER_HAS_AXIS_INFO +static DFBResult +driver_get_axis_info( CoreInputDevice *device, + void *driver_data, + DFBInputDeviceAxisIdentifier axis, + DFBInputDeviceAxisInfo *ret_info ); +#endif + +static void +driver_close_device( void *driver_data ); + +#ifdef DFB_INPUTDRIVER_HAS_SENSITIVITY +static DFBResult +driver_set_sensitivity( CoreInputDevice *device, + void *driver_data, + int sensitivity ); +#endif + +static const InputDriverFuncs driver_funcs = { + .GetAvailable = driver_get_available, + .GetDriverInfo = driver_get_info, + .OpenDevice = driver_open_device, + .GetKeymapEntry = driver_get_keymap_entry, + .CloseDevice = driver_close_device, + +#ifdef DFB_INPUTDRIVER_HAS_AXIS_INFO + .GetAxisInfo = driver_get_axis_info, +#endif + +#ifdef DFB_INPUTDRIVER_HAS_SENSITIVITY + .SetSensitivity = driver_set_sensitivity, +#endif +}; + +#define DFB_INPUT_DRIVER(shortname) \ +__attribute__((constructor)) void directfb_##shortname##_ctor( void ); \ +__attribute__((destructor)) void directfb_##shortname##_dtor( void ); \ + \ +void \ +directfb_##shortname##_ctor( void ) \ +{ \ + direct_modules_register( &dfb_input_modules, DFB_INPUT_DRIVER_ABI_VERSION, \ + #shortname, &driver_funcs ); \ +} \ + \ +void \ +directfb_##shortname##_dtor( void ) \ +{ \ + direct_modules_unregister( &dfb_input_modules, #shortname ); \ +} + +#endif diff --git a/Source/DirectFB/src/core/layer_context.c b/Source/DirectFB/src/core/layer_context.c new file mode 100755 index 0000000..1dcccc8 --- /dev/null +++ b/Source/DirectFB/src/core/layer_context.c @@ -0,0 +1,1947 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include + +#include +#include + +#include + +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + + +D_DEBUG_DOMAIN( Core_LayerContext, "Core/LayerContext", "DirectFB Display Layer Context" ); + +/**********************************************************************************************************************/ + +static void init_region_config ( CoreLayerContext *context, + CoreLayerRegionConfig *config ); + +static void build_updated_config( CoreLayer *layer, + CoreLayerContext *context, + const DFBDisplayLayerConfig *update, + CoreLayerRegionConfig *ret_config, + CoreLayerRegionConfigFlags *ret_flags ); + +static DFBResult allocate_surface ( CoreLayer *layer, + CoreLayerRegion *region, + CoreLayerRegionConfig *config ); + +static DFBResult reallocate_surface ( CoreLayer *layer, + CoreLayerRegion *region, + CoreLayerRegionConfig *config ); + +static DFBResult deallocate_surface ( CoreLayer *layer, + CoreLayerRegion *region ); + +static void screen_rectangle ( CoreLayerContext *context, + const DFBLocation *location, + DFBRectangle *rect ); + +/**********************************************************************************************************************/ + +static void +context_destructor( FusionObject *object, bool zombie, void *ctx ) +{ + CoreLayerContext *context = (CoreLayerContext*) object; + CoreLayer *layer = dfb_layer_at( context->layer_id ); + CoreLayerShared *shared = layer->shared; + + (void) shared; + + D_DEBUG_AT( Core_LayerContext, "*~ destroying context %p (%s, %sactive%s)\n", + context, shared->description.name, context->active ? "" : "in", + zombie ? " - ZOMBIE" : ""); + + D_MAGIC_ASSERT( context, CoreLayerContext ); + + /* Remove the context from the layer's context stack. */ + dfb_layer_remove_context( layer, context ); + + /* + * Detach input devices before taking the context lock to prevent a + * deadlock between windowstack destruction and input event processing. + */ + if (context->stack) + dfb_windowstack_detach_devices( context->stack ); + + dfb_layer_context_lock( context ); + + /* Destroy the window stack. */ + if (context->stack) { + dfb_windowstack_destroy( context->stack ); + context->stack = NULL; + } + + /* Destroy the region vector. */ + fusion_vector_destroy( &context->regions ); + + /* Deinitialize the lock. */ + fusion_skirmish_destroy( &context->lock ); + + /* Free clip regions. */ + if (context->primary.config.clips) + SHFREE( context->shmpool, context->primary.config.clips ); + + D_MAGIC_CLEAR( context ); + + /* Destroy the object. */ + fusion_object_destroy( object ); +} + +/**********************************************************************************************************************/ + +FusionObjectPool * +dfb_layer_context_pool_create( const FusionWorld *world ) +{ + return fusion_object_pool_create( "Layer Context Pool", + sizeof(CoreLayerContext), + sizeof(CoreLayerContextNotification), + context_destructor, NULL, world ); +} + +/**********************************************************************************************************************/ + +static void +update_stack_geometry( CoreLayerContext *context ) +{ + DFBDimension size; + int rotation; + CoreLayerRegion *region; + CoreSurface *surface; + + D_MAGIC_ASSERT( context, CoreLayerContext ); + + rotation = context->rotation; + + switch (rotation) { + default: + D_BUG( "invalid rotation %d", rotation ); + case 0: + case 180: + size.w = context->config.width; + size.h = context->config.height; + break; + + case 90: + case 270: + size.w = context->config.height; + size.h = context->config.width; + break; + } + + region = context->primary.region; + if (region) { + surface = region->surface; + if (surface) { + D_MAGIC_ASSERT( surface, CoreSurface ); + + rotation -= surface->rotation; + if (rotation < 0) + rotation += 360; + } + } + + dfb_windowstack_resize( context->stack, size.w, size.h, rotation ); +} + +DFBResult +dfb_layer_context_init( CoreLayerContext *context, + CoreLayer *layer ) +{ + CoreLayerShared *shared; + + D_ASSERT( context != NULL ); + D_ASSERT( layer != NULL ); + D_ASSERT( layer->shared != NULL ); + + shared = layer->shared; + + D_DEBUG_AT( Core_LayerContext, "%s( %p, %p [%s] )\n", __FUNCTION__, context, layer, shared->description.name ); + + context->shmpool = shared->shmpool; + + /* Initialize the lock. */ + if (fusion_skirmish_init( &context->lock, "Layer Context", dfb_core_world(layer->core) )) { + fusion_object_destroy( &context->object ); + return DFB_FUSION; + } + + /* Initialize the region vector. */ + fusion_vector_init( &context->regions, 4, context->shmpool ); + + /* Store layer ID, default configuration and default color adjustment. */ + context->layer_id = shared->layer_id; + context->config = shared->default_config; + context->adjustment = shared->default_adjustment; + context->rotation = dfb_config->layers[dfb_layer_id_translated(layer)].rotate; + + /* Initialize screen location. */ + context->screen.location.x = 0.0f; + context->screen.location.y = 0.0f; + context->screen.location.w = 1.0f; + context->screen.location.h = 1.0f; + + if (D_FLAGS_IS_SET( shared->description.caps, DLCAPS_SCREEN_LOCATION )) + context->screen.mode = CLLM_LOCATION; + else if (D_FLAGS_IS_SET( shared->description.caps, DLCAPS_SCREEN_POSITION )) + context->screen.mode = CLLM_CENTER; + + /* Change global reaction lock. */ + fusion_object_set_lock( &context->object, &context->lock ); + + D_MAGIC_SET( context, CoreLayerContext ); + + /* Initialize the primary region's configuration. */ + init_region_config( context, &context->primary.config ); + + /* Activate the object. */ + fusion_object_activate( &context->object ); + + + dfb_layer_context_lock( context ); + + /* Create the window stack. */ + context->stack = dfb_windowstack_create( context ); + if (!context->stack) { + dfb_layer_context_unlock( context ); + dfb_layer_context_unref( context ); + return D_OOSHM(); + } + + /* Tell the window stack about its size. */ + update_stack_geometry( context ); + + dfb_layer_context_unlock( context ); + + return DFB_OK; +} + +DFBResult +dfb_layer_context_activate( CoreLayerContext *context ) +{ + DFBResult ret; + int index; + CoreLayer *layer; + CoreLayerRegion *region; + + D_DEBUG_AT( Core_LayerContext, "%s( %p )\n", __FUNCTION__, context ); + + D_MAGIC_ASSERT( context, CoreLayerContext ); + + layer = dfb_layer_at( context->layer_id ); + + D_ASSERT( layer != NULL ); + D_ASSERT( layer->funcs != NULL ); + + /* Lock the context. */ + if (dfb_layer_context_lock( context )) + return DFB_FUSION; + + D_ASSUME( !context->active ); + + if (context->active) { + dfb_layer_context_unlock( context ); + return DFB_OK; + } + + /* Iterate through all regions. */ + fusion_vector_foreach (region, index, context->regions) { + /* Activate each region. */ + if (dfb_layer_region_activate( region )) + D_WARN( "could not activate region!" ); + + if (region->surface && region->surface->num_buffers == 0) { + D_ASSERT( region->surface_lock.buffer == NULL ); + + ret = reallocate_surface( layer, region, ®ion->config ); + if (ret) + D_DERROR( ret, "Core/Layers: Reallocation of layer surface failed!\n" ); + } + } + + context->active = true; + + /* set new adjustment */ + if (layer->funcs->SetColorAdjustment) + layer->funcs->SetColorAdjustment( layer, layer->driver_data, + layer->layer_data, &context->adjustment ); + + /* Resume window stack. */ + if (context->stack) { + CoreWindowStack *stack = context->stack; + + D_MAGIC_ASSERT( stack, CoreWindowStack ); + + if (stack->flags & CWSF_INITIALIZED) + dfb_wm_set_active( stack, true ); + } + + /* Unlock the context. */ + dfb_layer_context_unlock( context ); + + return DFB_OK; +} + +DFBResult +dfb_layer_context_deactivate( CoreLayerContext *context ) +{ + int index; + CoreLayerRegion *region; + + D_MAGIC_ASSERT( context, CoreLayerContext ); + + /* Lock the context. */ + if (dfb_layer_context_lock( context )) + return DFB_FUSION; + + D_DEBUG_AT( Core_LayerContext, "%s( %p )\n", __FUNCTION__, context ); + + D_ASSUME( context->active ); + + if (!context->active) { + dfb_layer_context_unlock( context ); + return DFB_OK; + } + + /* Iterate through all regions. */ + fusion_vector_foreach (region, index, context->regions) { + /* Deactivate each region. */ + dfb_layer_region_deactivate( region ); + } + + context->active = false; + + /* Suspend window stack. */ + if (context->stack) { + CoreWindowStack *stack = context->stack; + + D_MAGIC_ASSERT( stack, CoreWindowStack ); + + if (stack->flags & CWSF_ACTIVATED) + dfb_wm_set_active( stack, false ); + } + + /* Unlock the context. */ + dfb_layer_context_unlock( context ); + + return DFB_OK; +} + +DFBResult +dfb_layer_context_add_region( CoreLayerContext *context, + CoreLayerRegion *region ) +{ + D_DEBUG_AT( Core_LayerContext, "%s( %p, %p )\n", __FUNCTION__, context, region ); + + D_MAGIC_ASSERT( context, CoreLayerContext ); + D_ASSERT( region != NULL ); + + /* Lock the context. */ + if (dfb_layer_context_lock( context )) + return DFB_FUSION; + + D_ASSUME( ! fusion_vector_contains( &context->regions, region ) ); + + if (fusion_vector_contains( &context->regions, region )) { + dfb_layer_context_unlock( context ); + return DFB_OK; + } + + /* Add region to vector. */ + if (fusion_vector_add( &context->regions, region )) { + dfb_layer_context_unlock( context ); + return DFB_FUSION; + } + + /* Inherit state from context. */ + if (context->active) + region->state |= CLRSF_ACTIVE; + + /* Unlock the context. */ + dfb_layer_context_unlock( context ); + + return DFB_OK; +} + +DFBResult +dfb_layer_context_remove_region( CoreLayerContext *context, + CoreLayerRegion *region ) +{ + int index; + + D_MAGIC_ASSERT( context, CoreLayerContext ); + D_ASSERT( region != NULL ); + + /* Lock the context. */ + if (dfb_layer_context_lock( context )) + return DFB_FUSION; + + D_ASSUME( fusion_vector_contains( &context->regions, region ) ); + + /* Lookup region. */ + index = fusion_vector_index_of( &context->regions, region ); + if (index < 0) { + dfb_layer_context_unlock( context ); + return DFB_OK; + } + + /* Remove region from vector. */ + fusion_vector_remove( &context->regions, index ); + + /* Check if the primary region is removed. */ + if (region == context->primary.region) + context->primary.region = NULL; + + /* Unlock the context. */ + dfb_layer_context_unlock( context ); + + return DFB_OK; +} + +DFBResult +dfb_layer_context_get_primary_region( CoreLayerContext *context, + bool create, + CoreLayerRegion **ret_region ) +{ + DFBResult ret = DFB_OK; + + D_DEBUG_AT( Core_LayerContext, "%s( %p, %screate )\n", __FUNCTION__, context, create ? "" : "DON'T " ); + + D_MAGIC_ASSERT( context, CoreLayerContext ); + D_ASSERT( ret_region != NULL ); + + /* Lock the context. */ + if (dfb_layer_context_lock( context )) + return DFB_FUSION; + +restart: + while (context->primary.region) { + /* Increase the primary region's reference counter. */ + ret = dfb_layer_region_ref( context->primary.region ); + if (ret == DFB_OK) + break; + + dfb_layer_context_unlock( context ); + + if (ret == DFB_LOCKED) { + //sched_yield(); + usleep( 10000 ); + + if (dfb_layer_context_lock( context )) + return DFB_FUSION; + } + else + return DFB_FUSION; + } + + if (!context->primary.region) { + if (create) { + CoreLayerRegion *region; + + /* Unlock the context. */ + dfb_layer_context_unlock( context ); + + /* Create the primary region. */ + ret = dfb_layer_region_create( context, ®ion ); + if (ret) { + D_ERROR( "DirectFB/core/layers: Could not create primary region!\n" ); + return ret; + } + + /* Lock the context again. */ + if (dfb_layer_context_lock( context )) { + dfb_layer_region_unref( region ); + return DFB_FUSION; + } + + /* Check for race. */ + if (context->primary.region) { + dfb_layer_region_unref( region ); + goto restart; + } + + /* Set the region configuration. */ + ret = dfb_layer_region_set_configuration( region, + &context->primary.config, + CLRCF_ALL ); + if (ret) { + D_DERROR( ret, "DirectFB/core/layers: " + "Could not set primary region config!\n" ); + dfb_layer_region_unref( region ); + dfb_layer_context_unlock( context ); + return ret; + } + + /* Remember the primary region. */ + context->primary.region = region; + + /* Allocate surface, enable region etc. */ + ret = dfb_layer_context_set_configuration( context, &context->config ); + if (ret) { + D_DERROR( ret, "DirectFB/core/layers: " + "Could not set layer context config!\n" ); + context->primary.region = NULL; + dfb_layer_region_unref( region ); + dfb_layer_context_unlock( context ); + return ret; + } + } + else { + dfb_layer_context_unlock( context ); + return DFB_TEMPUNAVAIL; + } + } + + /* Return region. */ + *ret_region = context->primary.region; + + /* Unlock the context. */ + dfb_layer_context_unlock( context ); + + return DFB_OK; +} + +/* + * configuration management + */ +DFBResult +dfb_layer_context_test_configuration( CoreLayerContext *context, + const DFBDisplayLayerConfig *config, + DFBDisplayLayerConfigFlags *ret_failed ) +{ + DFBResult ret = DFB_OK; + CoreLayer *layer; + CoreLayerRegionConfig region_config; + CoreLayerRegionConfigFlags failed; + const DisplayLayerFuncs *funcs; + + D_DEBUG_AT( Core_LayerContext, "%s( %p, %p, %p )\n", __FUNCTION__, context, config, ret_failed ); + + D_MAGIC_ASSERT( context, CoreLayerContext ); + D_ASSERT( config != NULL ); + + /* Lock the context. */ + if (dfb_layer_context_lock( context )) + return DFB_FUSION; + + layer = dfb_layer_at( context->layer_id ); + + D_ASSERT( layer != NULL ); + D_ASSERT( layer->shared != NULL ); + D_ASSERT( layer->funcs != NULL ); + D_ASSERT( layer->funcs->TestRegion != NULL ); + + funcs = layer->funcs; + + /* Build a new region configuration with the changes. */ + build_updated_config( layer, context, config, ®ion_config, NULL ); + + /* Unlock the context. */ + dfb_layer_context_unlock( context ); + + + /* Test the region configuration. */ + if (region_config.buffermode == DLBM_WINDOWS) { + if (! D_FLAGS_IS_SET( layer->shared->description.caps, DLCAPS_WINDOWS )) { + failed = CLRCF_BUFFERMODE; + ret = DFB_UNSUPPORTED; + } + } + else { + /* Let the driver examine the modified configuration. */ + ret = funcs->TestRegion( layer, layer->driver_data, layer->layer_data, + ®ion_config, &failed ); + } + + /* Return flags for failing entries. */ + if (ret_failed) { + DFBDisplayLayerConfigFlags flags = DLCONF_NONE; + + /* Translate flags. */ + if (ret != DFB_OK) { + if (failed & CLRCF_WIDTH) + flags |= DLCONF_WIDTH; + + if (failed & CLRCF_HEIGHT) + flags |= DLCONF_HEIGHT; + + if (failed & CLRCF_FORMAT) + flags |= DLCONF_PIXELFORMAT; + + if (failed & CLRCF_BUFFERMODE) + flags |= DLCONF_BUFFERMODE; + + if (failed & CLRCF_OPTIONS) + flags |= DLCONF_OPTIONS; + + if (failed & CLRCF_SOURCE_ID) + flags |= DLCONF_SOURCE; + + if (failed & CLRCF_SURFACE_CAPS) + flags |= DLCONF_SURFACE_CAPS; + } + + *ret_failed = flags; + } + + return ret; +} + +DFBResult +dfb_layer_context_set_configuration( CoreLayerContext *context, + const DFBDisplayLayerConfig *config ) +{ + int i; + DFBResult ret; + CoreLayer *layer; + CoreLayerShared *shared; + CoreLayerRegionConfig region_config; + CoreLayerRegionConfigFlags flags; + const DisplayLayerFuncs *funcs; + + D_DEBUG_AT( Core_LayerContext, "%s( %p, %p )\n", __FUNCTION__, context, config ); + + D_MAGIC_ASSERT( context, CoreLayerContext ); + D_ASSERT( config != NULL ); + + /* Lock the context. */ + if (dfb_layer_context_lock( context )) + return DFB_FUSION; + + layer = dfb_layer_at( context->layer_id ); + + D_ASSERT( layer != NULL ); + D_ASSERT( layer->shared != NULL ); + D_ASSERT( layer->funcs != NULL ); + D_ASSERT( layer->funcs->TestRegion != NULL ); + + shared = layer->shared; + funcs = layer->funcs; + + /* Build a new region configuration with the changes. */ + build_updated_config( layer, context, config, ®ion_config, &flags ); + + /* Test the region configuration first. */ + if (region_config.buffermode == DLBM_WINDOWS) { + if (! D_FLAGS_IS_SET( shared->description.caps, DLCAPS_WINDOWS )) { + dfb_layer_context_unlock( context ); + return DFB_UNSUPPORTED; + } + } + else { + ret = funcs->TestRegion( layer, layer->driver_data, layer->layer_data, + ®ion_config, NULL ); + if (ret) { + dfb_layer_context_unlock( context ); + return ret; + } + } + + /* Set the region configuration. */ + if (context->primary.region) { + CoreLayerRegion *region = context->primary.region; + + /* Add local reference. */ + if (dfb_layer_region_ref( region )) { + dfb_layer_context_unlock( context ); + return DFB_FUSION; + } + + /* Lock the region. */ + if (dfb_layer_region_lock( region )) { + dfb_layer_region_unref( region ); + dfb_layer_context_unlock( context ); + return DFB_FUSION; + } + + /* Normal buffer mode? */ + if (region_config.buffermode != DLBM_WINDOWS) { + bool surface = shared->description.caps & DLCAPS_SURFACE; + CoreLayerRegionStateFlags configured = region->state & CLRSF_CONFIGURED; + + if (shared->description.caps & DLCAPS_SOURCES) { + for (i=0; idescription.sources; i++) { + if (shared->sources[i].description.source_id == region_config.source_id) + break; + } + + D_ASSERT( i < shared->description.sources ); + + surface = shared->sources[i].description.caps & DDLSCAPS_SURFACE; + } + + D_FLAGS_CLEAR( region->state, CLRSF_CONFIGURED ); + + /* Unlock the region surface */ + if (region->surface) { + if (D_FLAGS_IS_SET( region->state, CLRSF_REALIZED )) { + if (!D_FLAGS_IS_SET( region->state, CLRSF_FROZEN )) + D_ASSUME( region->surface_lock.buffer != NULL ); + + if (region->surface_lock.buffer) + dfb_surface_unlock_buffer( region->surface, ®ion->surface_lock ); + } + } + + /* (Re)allocate the region's surface. */ + if (surface) { + flags |= CLRCF_SURFACE | CLRCF_PALETTE; + + if (region->surface) { + ret = reallocate_surface( layer, region, ®ion_config ); + if (ret) + D_DERROR( ret, "Core/Layers: Reallocation of layer surface failed!\n" ); + } + else { + ret = allocate_surface( layer, region, ®ion_config ); + if (ret) + D_DERROR( ret, "Core/Layers: Allocation of layer surface failed!\n" ); + } + + if (ret) { + dfb_layer_region_unlock( region ); + dfb_layer_region_unref( region ); + dfb_layer_context_unlock( context ); + return ret; + } + } + else if (region->surface) + deallocate_surface( layer, region ); + + region->state |= configured; + + /* Set the new region configuration. */ + dfb_layer_region_set_configuration( region, ®ion_config, flags ); + + /* Enable the primary region. */ + if (! D_FLAGS_IS_SET( region->state, CLRSF_ENABLED )) + dfb_layer_region_enable( region ); + } + else { + /* Disable and deallocate the primary region. */ + if (D_FLAGS_IS_SET( region->state, CLRSF_ENABLED )) { + dfb_layer_region_disable( region ); + + if (region->surface) + deallocate_surface( layer, region ); + } + } + + /* Unlock the region and give up the local reference. */ + dfb_layer_region_unlock( region ); + dfb_layer_region_unref( region ); + } + + /* Remember new region config. */ + context->primary.config = region_config; + + /* + * Write back modified entries. + */ + if (config->flags & DLCONF_WIDTH) + context->config.width = config->width; + + if (config->flags & DLCONF_HEIGHT) + context->config.height = config->height; + + if (config->flags & DLCONF_PIXELFORMAT) + context->config.pixelformat = config->pixelformat; + + if (config->flags & DLCONF_BUFFERMODE) + context->config.buffermode = config->buffermode; + + if (config->flags & DLCONF_OPTIONS) + context->config.options = config->options; + + if (config->flags & DLCONF_SOURCE) + context->config.source = config->source; + + if (config->flags & DLCONF_SURFACE_CAPS) + context->config.surface_caps = config->surface_caps; + + /* Update the window stack. */ + if (context->stack) { + CoreWindowStack *stack = context->stack; + + /* Update hardware flag. */ + stack->hw_mode = (region_config.buffermode == DLBM_WINDOWS); + + /* Tell the windowing core about the new size. */ + if (config->flags & (DLCONF_WIDTH | DLCONF_HEIGHT | + DLCONF_PIXELFORMAT | DLCONF_BUFFERMODE | DLCONF_SURFACE_CAPS)) + { + update_stack_geometry( context ); + + /* FIXME: call only if really needed */ + dfb_windowstack_repaint_all( stack ); + } + } + + /* Unlock the context. */ + dfb_layer_context_unlock( context ); + + return DFB_OK; +} + +DFBResult +dfb_layer_context_get_configuration( CoreLayerContext *context, + DFBDisplayLayerConfig *config ) +{ + D_DEBUG_AT( Core_LayerContext, "%s( %p, %p )\n", __FUNCTION__, context, config ); + + D_MAGIC_ASSERT( context, CoreLayerContext ); + D_ASSERT( config != NULL ); + + *config = context->config; + + return DFB_OK; +} + +static DFBResult +update_primary_region_config( CoreLayerContext *context, + CoreLayerRegionConfig *config, + CoreLayerRegionConfigFlags flags ) +{ + DFBResult ret = DFB_OK; + + D_DEBUG_AT( Core_LayerContext, "%s( %p, %p, 0x%08x )\n", __FUNCTION__, context, config, flags ); + + D_MAGIC_ASSERT( context, CoreLayerContext ); + D_ASSERT( config != NULL ); + + if (context->primary.region) { + /* Set the new configuration. */ + ret = dfb_layer_region_set_configuration( context->primary.region, config, flags ); + } + else { + CoreLayer *layer = dfb_layer_at( context->layer_id ); + + D_ASSERT( layer->funcs != NULL ); + D_ASSERT( layer->funcs->TestRegion != NULL ); + + /* Just test the new configuration. */ + ret = layer->funcs->TestRegion( layer, layer->driver_data, + layer->layer_data, config, NULL ); + } + + if (ret) + return ret; + + /* Remember the configuration. */ + context->primary.config = *config; + + return DFB_OK; +} + +DFBResult +dfb_layer_context_set_src_colorkey( CoreLayerContext *context, + u8 r, u8 g, u8 b, int index ) +{ + DFBResult ret; + CoreLayerRegionConfig config; + + D_DEBUG_AT( Core_LayerContext, "%s( %p, %02x %02x %02x - %d )\n", __FUNCTION__, context, r, g, b, index ); + + D_MAGIC_ASSERT( context, CoreLayerContext ); + + /* Lock the context. */ + if (dfb_layer_context_lock( context )) + return DFB_FUSION; + + /* Take the current configuration. */ + config = context->primary.config; + + /* Change the color key. */ + config.src_key.r = r; + config.src_key.g = g; + config.src_key.b = b; + + if (index >= 0) + config.src_key.index = index & 0xff; + + /* Try to set the new configuration. */ + ret = update_primary_region_config( context, &config, CLRCF_SRCKEY ); + + /* Unlock the context. */ + dfb_layer_context_unlock( context ); + + return ret; +} + +DFBResult +dfb_layer_context_set_dst_colorkey( CoreLayerContext *context, + u8 r, u8 g, u8 b, int index ) +{ + DFBResult ret; + CoreLayerRegionConfig config; + + D_DEBUG_AT( Core_LayerContext, "%s( %p, %02x %02x %02x - %d )\n", __FUNCTION__, context, r, g, b, index ); + + D_MAGIC_ASSERT( context, CoreLayerContext ); + + /* Lock the context. */ + if (dfb_layer_context_lock( context )) + return DFB_FUSION; + + /* Take the current configuration. */ + config = context->primary.config; + + /* Change the color key. */ + config.dst_key.r = r; + config.dst_key.g = g; + config.dst_key.b = b; + + if (index >= 0) + config.dst_key.index = index & 0xff; + + /* Try to set the new configuration. */ + ret = update_primary_region_config( context, &config, CLRCF_DSTKEY ); + + /* Unlock the context. */ + dfb_layer_context_unlock( context ); + + return ret; +} + +DFBResult +dfb_layer_context_set_sourcerectangle( CoreLayerContext *context, + const DFBRectangle *source ) +{ + DFBResult ret; + CoreLayerRegionConfig config; + CoreLayerRegionConfigFlags flags; + CoreLayer *layer; + + D_DEBUG_AT( Core_LayerContext, "%s( %p, %p )\n", __FUNCTION__, context, source ); + + D_MAGIC_ASSERT( context, CoreLayerContext ); + D_ASSERT( source != NULL ); + + /* Lock the context. */ + if (dfb_layer_context_lock( context )) + return DFB_FUSION; + + /* Take the current configuration. */ + config = context->primary.config; + + /* Do nothing if the source rectangle didn't change. */ + if (DFB_RECTANGLE_EQUAL( config.source, *source )) { + dfb_layer_context_unlock( context ); + return DFB_OK; + } + + /* Check if the new source rectangle is valid. */ + if (source->x < 0 || source->y < 0 || + source->x + source->w > config.width || + source->y + source->h > config.height) { + dfb_layer_context_unlock( context ); + return DFB_INVAREA; + } + + /* Change the source rectangle. */ + config.source = *source; + + flags = CLRCF_SOURCE; + layer = dfb_layer_at( context->layer_id ); + + /* If the display layer does not support scaling and the destination + rectangle size is not the same as the source, change it to match. The + origin is left alone to allow the driver to handle it. */ + if ( !D_FLAGS_IS_SET( layer->shared->description.caps, DLCAPS_SCREEN_SIZE ) && + ( config.dest.w != config.source.w || + config.dest.h != config.source.h ) ) + { + config.dest.w = config.source.w; + config.dest.h = config.source.h; + + flags |= CLRCF_DEST; + } + + /* Try to set the new configuration. */ + ret = update_primary_region_config( context, &config, flags ); + + /* Unlock the context. */ + dfb_layer_context_unlock( context ); + + return ret; +} + +DFBResult +dfb_layer_context_set_screenlocation( CoreLayerContext *context, + const DFBLocation *location ) +{ + DFBResult ret; + CoreLayerRegionConfig config; + + D_DEBUG_AT( Core_LayerContext, "%s( %p, %p )\n", __FUNCTION__, context, location ); + + D_MAGIC_ASSERT( context, CoreLayerContext ); + D_ASSERT( location != NULL ); + + /* Lock the context. */ + if (dfb_layer_context_lock( context )) + return DFB_FUSION; + + /* Do nothing if the location didn't change. */ +/* if (context->screen.mode == CLLM_LOCATION && + DFB_LOCATION_EQUAL( context->screen.location, *location )) + { + dfb_layer_context_unlock( context ); + return DFB_OK; + }*/ + + /* Take the current configuration. */ + config = context->primary.config; + + /* Calculate new absolute screen coordinates. */ + screen_rectangle( context, location, &config.dest ); + + /* Try to set the new configuration. */ + ret = update_primary_region_config( context, &config, CLRCF_DEST ); + if (ret == DFB_OK) { + context->screen.location = *location; + context->screen.rectangle = config.dest; + context->screen.mode = CLLM_LOCATION; + } + + /* Unlock the context. */ + dfb_layer_context_unlock( context ); + + return ret; +} + +DFBResult +dfb_layer_context_set_screenrectangle( CoreLayerContext *context, + const DFBRectangle *rectangle ) +{ + DFBResult ret; + CoreLayerRegionConfig config; + + D_DEBUG_AT( Core_LayerContext, "%s( %p, %p )\n", __FUNCTION__, context, rectangle ); + + D_MAGIC_ASSERT( context, CoreLayerContext ); + + DFB_RECTANGLE_ASSERT( rectangle ); + + /* Lock the context. */ + if (dfb_layer_context_lock( context )) + return DFB_FUSION; + + /* Do nothing if the location didn't change. */ +/* if (context->screen.mode == CLLM_RECTANGLE && + DFB_RECTANGLE_EQUAL( context->screen.rectangle, *rectangle )) + { + dfb_layer_context_unlock( context ); + return DFB_OK; + }*/ + + /* Take the current configuration. */ + config = context->primary.config; + + /* Use supplied absolute screen coordinates. */ + config.dest = *rectangle; + + /* Try to set the new configuration. */ + ret = update_primary_region_config( context, &config, CLRCF_DEST ); + if (ret == DFB_OK) { + context->screen.rectangle = config.dest; + context->screen.mode = CLLM_RECTANGLE; + } + + /* Unlock the context. */ + dfb_layer_context_unlock( context ); + + return ret; +} + +DFBResult +dfb_layer_context_set_screenposition( CoreLayerContext *context, + int x, + int y ) +{ + DFBResult ret; + CoreLayerRegionConfig config; + + D_DEBUG_AT( Core_LayerContext, "%s( %p, %4d,%4d )\n", __FUNCTION__, context, x, y ); + + D_MAGIC_ASSERT( context, CoreLayerContext ); + + /* Lock the context. */ + if (dfb_layer_context_lock( context )) + return DFB_FUSION; + + /* Do nothing if the location didn't change. */ + if (context->primary.config.dest.x == x && context->primary.config.dest.y == y) { + dfb_layer_context_unlock( context ); + return DFB_OK; + } + + /* Take the current configuration. */ + config = context->primary.config; + + /* Set new absolute screen coordinates. */ + config.dest.x = x; + config.dest.y = y; + + /* Try to set the new configuration. */ + ret = update_primary_region_config( context, &config, CLRCF_DEST ); + if (ret == DFB_OK) { + context->screen.rectangle = config.dest; + context->screen.mode = CLLM_POSITION; + } + + /* Unlock the context. */ + dfb_layer_context_unlock( context ); + + return ret; +} + +DFBResult +dfb_layer_context_set_opacity( CoreLayerContext *context, + u8 opacity ) +{ + DFBResult ret; + CoreLayerRegionConfig config; + + D_DEBUG_AT( Core_LayerContext, "%s( %p, %u )\n", __FUNCTION__, context, opacity ); + + D_MAGIC_ASSERT( context, CoreLayerContext ); + + /* Lock the context. */ + if (dfb_layer_context_lock( context )) + return DFB_FUSION; + + /* Do nothing if the opacity didn't change. */ + if (context->primary.config.opacity == opacity) { + dfb_layer_context_unlock( context ); + return DFB_OK; + } + + /* Take the current configuration. */ + config = context->primary.config; + + /* Change the opacity. */ + config.opacity = opacity; + + /* Try to set the new configuration. */ + ret = update_primary_region_config( context, &config, CLRCF_OPACITY ); + if (ret == DFB_OK) + context->primary.config.opacity = opacity; + + /* Unlock the context. */ + dfb_layer_context_unlock( context ); + + return ret; +} + +DFBResult +dfb_layer_context_set_rotation( CoreLayerContext *context, + int rotation ) +{ + D_DEBUG_AT( Core_LayerContext, "%s( %p, %d )\n", __FUNCTION__, context, rotation ); + + D_MAGIC_ASSERT( context, CoreLayerContext ); + + /* Lock the context. */ + if (dfb_layer_context_lock( context )) + return DFB_FUSION; + + /* Do nothing if the rotation didn't change. */ + if (context->rotation != rotation) { + context->rotation = rotation; + + update_stack_geometry( context ); + + dfb_windowstack_repaint_all( context->stack ); + } + + /* Unlock the context. */ + dfb_layer_context_unlock( context ); + + return DFB_OK; +} + +DFBResult +dfb_layer_context_set_coloradjustment( CoreLayerContext *context, + const DFBColorAdjustment *adjustment ) +{ + DFBResult ret; + DFBColorAdjustment adj; + CoreLayer *layer; + + D_DEBUG_AT( Core_LayerContext, "%s( %p, %p )\n", __FUNCTION__, context, adjustment ); + + D_MAGIC_ASSERT( context, CoreLayerContext ); + D_ASSERT( adjustment != NULL ); + + layer = dfb_layer_at( context->layer_id ); + + D_ASSERT( layer != NULL ); + D_ASSERT( layer->funcs != NULL ); + + adj = context->adjustment; + + if (!layer->funcs->SetColorAdjustment) + return DFB_UNSUPPORTED; + + /* if flags are set that are not in the default adjustment */ + if (adjustment->flags & ~context->adjustment.flags) + return DFB_UNSUPPORTED; + + /* take over changed values */ + if (adjustment->flags & DCAF_BRIGHTNESS) adj.brightness = adjustment->brightness; + if (adjustment->flags & DCAF_CONTRAST) adj.contrast = adjustment->contrast; + if (adjustment->flags & DCAF_HUE) adj.hue = adjustment->hue; + if (adjustment->flags & DCAF_SATURATION) adj.saturation = adjustment->saturation; + + /* set new adjustment */ + ret = layer->funcs->SetColorAdjustment( layer, layer->driver_data, + layer->layer_data, &adj ); + if (ret) + return ret; + + /* keep new adjustment */ + context->adjustment = adj; + + return DFB_OK; +} + +DFBResult +dfb_layer_context_get_coloradjustment( CoreLayerContext *context, + DFBColorAdjustment *ret_adjustment ) +{ + D_DEBUG_AT( Core_LayerContext, "%s( %p, %p )\n", __FUNCTION__, context, ret_adjustment ); + + D_MAGIC_ASSERT( context, CoreLayerContext ); + D_ASSERT( ret_adjustment != NULL ); + + *ret_adjustment = context->adjustment; + + return DFB_OK; +} + +DFBResult +dfb_layer_context_set_field_parity( CoreLayerContext *context, + int field ) +{ + DFBResult ret; + CoreLayerRegionConfig config; + + D_DEBUG_AT( Core_LayerContext, "%s( %p, %d )\n", __FUNCTION__, context, field ); + + D_MAGIC_ASSERT( context, CoreLayerContext ); + + /* Lock the context. */ + if (dfb_layer_context_lock( context )) + return DFB_FUSION; + + /* Do nothing if the parity didn't change. */ + if (context->primary.config.parity == field) { + dfb_layer_context_unlock( context ); + return DFB_OK; + } + + /* Take the current configuration. */ + config = context->primary.config; + + /* Change the parity. */ + config.parity = field; + + /* Try to set the new configuration. */ + ret = update_primary_region_config( context, &config, CLRCF_PARITY ); + + /* Unlock the context. */ + dfb_layer_context_unlock( context ); + + return ret; +} + +DFBResult +dfb_layer_context_set_clip_regions( CoreLayerContext *context, + const DFBRegion *regions, + int num_regions, + DFBBoolean positive ) +{ + DFBResult ret; + CoreLayerRegionConfig config; + DFBRegion *clips; + DFBRegion *old_clips; + + D_DEBUG_AT( Core_LayerContext, "%s( %p, %p [%d], %s )\n", __FUNCTION__, + context, regions, num_regions, positive ? "positive" : "negative" ); + + D_MAGIC_ASSERT( context, CoreLayerContext ); + + clips = SHMALLOC( context->shmpool, sizeof(DFBRegion) * num_regions ); + if (!clips) + return D_OOSHM(); + + direct_memcpy( clips, regions, sizeof(DFBRegion) * num_regions ); + + /* Lock the context. */ + if (dfb_layer_context_lock( context )) { + SHFREE( context->shmpool, clips ); + return DFB_FUSION; + } + + /* Take the current configuration. */ + config = context->primary.config; + + /* Remember for freeing later on. */ + old_clips = config.clips; + + /* Change the clip regions. */ + config.clips = clips; + config.num_clips = num_regions; + config.positive = positive; + + /* Try to set the new configuration. */ + ret = update_primary_region_config( context, &config, CLRCF_CLIPS ); + + /* Unlock the context. */ + dfb_layer_context_unlock( context ); + + if (ret) + SHFREE( context->shmpool, clips ); + else if (old_clips) + SHFREE( context->shmpool, old_clips ); + + return ret; +} + +DFBResult +dfb_layer_context_create_window( CoreDFB *core, + CoreLayerContext *context, + const DFBWindowDescription *desc, + CoreWindow **ret_window ) +{ + DFBResult ret; + CoreWindow *window; + CoreWindowStack *stack; + CoreLayer *layer; + + D_DEBUG_AT( Core_LayerContext, "%s( %p, %p, %p, %p )\n", __FUNCTION__, core, context, desc, ret_window ); + + D_MAGIC_ASSERT( context, CoreLayerContext ); + D_ASSERT( context->stack != NULL ); + D_ASSERT( desc != NULL ); + D_ASSERT( ret_window != NULL ); + + layer = dfb_layer_at( context->layer_id ); + + D_ASSERT( layer != NULL ); + D_ASSERT( layer->funcs != NULL ); + + if (dfb_layer_context_lock( context )) + return DFB_FUSION; + + stack = context->stack; + + if (!stack->cursor.set) { + ret = dfb_windowstack_cursor_enable( core, stack, true ); + if (ret) { + dfb_layer_context_unlock( context ); + return ret; + } + } + + ret = dfb_window_create( stack, desc, &window ); + if (ret) { + dfb_layer_context_unlock( context ); + return ret; + } + + *ret_window = window; + + dfb_layer_context_unlock( context ); + + return DFB_OK; +} + +CoreWindow * +dfb_layer_context_find_window( CoreLayerContext *context, DFBWindowID id ) +{ + CoreWindowStack *stack; + CoreWindow *window; + + D_DEBUG_AT( Core_LayerContext, "%s( %p, %u )\n", __FUNCTION__, context, id ); + + D_MAGIC_ASSERT( context, CoreLayerContext ); + D_ASSERT( context->stack != NULL ); + + stack = context->stack; + + if (dfb_layer_context_lock( context )) + return NULL; + + if (dfb_wm_window_lookup( stack, id, &window ) || dfb_window_ref( window )) + window = NULL; + + dfb_layer_context_unlock( context ); + + return window; +} + +CoreWindowStack * +dfb_layer_context_windowstack( const CoreLayerContext *context ) +{ + D_MAGIC_ASSERT( context, CoreLayerContext ); + + return context->stack; +} + +bool +dfb_layer_context_active( const CoreLayerContext *context ) +{ + D_MAGIC_ASSERT( context, CoreLayerContext ); + + return context->active; +} + +DirectResult +dfb_layer_context_lock( CoreLayerContext *context ) +{ + DFBResult ret; + + D_DEBUG_AT( Core_LayerContext, "%s( %p )\n", __FUNCTION__, context ); + + D_MAGIC_ASSERT( context, CoreLayerContext ); + + ret = fusion_skirmish_prevail( &context->lock ); + if (ret == DFB_OK) { + int locked; + + ret = fusion_skirmish_lock_count( &context->lock, &locked ); + if (ret == DFB_OK) + D_DEBUG_AT( Core_LayerContext, " -> locked %dx now\n", locked ); + } + + return ret; +} + +DirectResult +dfb_layer_context_unlock( CoreLayerContext *context ) +{ + D_DEBUG_AT( Core_LayerContext, "%s( %p )\n", __FUNCTION__, context ); + + D_MAGIC_ASSERT( context, CoreLayerContext ); + + return fusion_skirmish_dismiss( &context->lock ); +} + +/**************************************************************************************************/ + +/* + * region config construction + */ +static void +init_region_config( CoreLayerContext *context, + CoreLayerRegionConfig *config ) +{ + D_DEBUG_AT( Core_LayerContext, "%s( %p, %p )\n", __FUNCTION__, context, config ); + + D_MAGIC_ASSERT( context, CoreLayerContext ); + D_ASSERT( config != NULL ); + + memset( config, 0, sizeof(CoreLayerRegionConfig) ); + + /* Initialize values from layer config. */ + config->width = context->config.width; + config->height = context->config.height; + config->format = context->config.pixelformat; + config->buffermode = context->config.buffermode; + config->options = context->config.options; + config->source_id = context->config.source; + config->surface_caps = context->config.surface_caps; + + /* Initialize source rectangle. */ + config->source.x = 0; + config->source.y = 0; + config->source.w = config->width; + config->source.h = config->height; + + /* Initialize screen rectangle. */ + screen_rectangle( context, &context->screen.location, &config->dest ); + + /* Set default opacity. */ + config->opacity = 0xff; + + /* Set default alpha ramp. */ + config->alpha_ramp[0] = 0x00; + config->alpha_ramp[1] = 0x55; + config->alpha_ramp[2] = 0xaa; + config->alpha_ramp[3] = 0xff; +} + +static void +build_updated_config( CoreLayer *layer, + CoreLayerContext *context, + const DFBDisplayLayerConfig *update, + CoreLayerRegionConfig *ret_config, + CoreLayerRegionConfigFlags *ret_flags ) +{ + CoreLayerRegionConfigFlags flags = CLRCF_NONE; + + D_DEBUG_AT( Core_LayerContext, "%s( %p, %p, %p, %p, %p )\n", + __FUNCTION__, layer, context, update, ret_config, ret_flags ); + + D_ASSERT( layer != NULL ); + D_MAGIC_ASSERT( context, CoreLayerContext ); + D_ASSERT( update != NULL ); + D_ASSERT( ret_config != NULL ); + + /* Get the current region configuration. */ + *ret_config = context->primary.config; + + /* Change width. */ + if (update->flags & DLCONF_WIDTH) { + flags |= CLRCF_WIDTH; + ret_config->width = update->width; + } + + /* Change height. */ + if (update->flags & DLCONF_HEIGHT) { + flags |= CLRCF_HEIGHT; + ret_config->height = update->height; + } + + /* Update source and destination rectangle. */ + if (update->flags & (DLCONF_WIDTH | DLCONF_HEIGHT)) { + int width, height; + DFBResult ret; + + flags |= CLRCF_SOURCE | CLRCF_DEST; + + ret_config->source.x = 0; + ret_config->source.y = 0; + ret_config->source.w = ret_config->width; + ret_config->source.h = ret_config->height; + + switch (context->screen.mode) { + case CLLM_CENTER: + ret = dfb_screen_get_layer_dimension( layer->screen, layer, &width, &height ); + if( ret == DFB_OK ) { + ret_config->dest.x = (width - ret_config->width) / 2; + ret_config->dest.y = (height - ret_config->height) / 2; + } + /* fall through */ + + case CLLM_POSITION: + ret_config->dest.w = ret_config->width; + ret_config->dest.h = ret_config->height; + break; + + case CLLM_LOCATION: + case CLLM_RECTANGLE: + D_ASSERT( layer->shared != NULL ); + + /* If the display layer does not support scaling and the + destination rectangle size is not the same as the + source rectangle, change it to match. The origin is + left alone to allow the driver to handle it. */ + if ( !D_FLAGS_IS_SET( layer->shared->description.caps, DLCAPS_SCREEN_SIZE ) + && ( ret_config->dest.w != ret_config->source.w || + ret_config->dest.h != ret_config->source.h ) ) + { + ret_config->dest.w = ret_config->width; + ret_config->dest.h = ret_config->height; + } + break; + + default: + D_BREAK( "invalid layout mode" ); + } + } + + /* Change pixel format. */ + if (update->flags & DLCONF_PIXELFORMAT) { + flags |= CLRCF_FORMAT; + ret_config->format = update->pixelformat; + } + + /* Change buffer mode. */ + if (update->flags & DLCONF_BUFFERMODE) { + flags |= CLRCF_BUFFERMODE; + ret_config->buffermode = update->buffermode; + } + + /* Change options. */ + if (update->flags & DLCONF_OPTIONS) { + flags |= CLRCF_OPTIONS; + ret_config->options = update->options; + } + + /* Change source id. */ + if (update->flags & DLCONF_SOURCE) { + flags |= CLRCF_SOURCE_ID; + ret_config->source_id = update->source; + } + + /* Change surface caps. */ + if (update->flags & DLCONF_SURFACE_CAPS) { + flags |= CLRCF_SURFACE_CAPS; + ret_config->surface_caps = update->surface_caps; + } + + /* Return translated flags. */ + if (ret_flags) + *ret_flags = flags; +} + +/* + * region surface (re/de)allocation + */ +static DFBResult +allocate_surface( CoreLayer *layer, + CoreLayerRegion *region, + CoreLayerRegionConfig *config ) +{ + DFBResult ret; + const DisplayLayerFuncs *funcs; + CoreLayerContext *context; + CoreSurface *surface = NULL; + DFBSurfaceCapabilities caps = DSCAPS_VIDEOONLY; + CoreSurfaceTypeFlags type = CSTF_LAYER; + CoreSurfaceConfig scon; + + D_DEBUG_AT( Core_LayerContext, "%s( %p, %p, %p )\n", __FUNCTION__, layer, region, config ); + + D_ASSERT( layer != NULL ); + D_ASSERT( layer->shared != NULL ); + D_ASSERT( layer->funcs != NULL ); + D_ASSERT( region != NULL ); + D_ASSERT( region->surface == NULL ); + D_ASSERT( config != NULL ); + D_ASSERT( config->buffermode != DLBM_WINDOWS ); + + context = region->context; + D_MAGIC_ASSERT( context, CoreLayerContext ); + + funcs = layer->funcs; + + /* + * Create a new surface for the region. + * Drivers may provide their own surface creation (unusual). + */ + if (funcs->AllocateSurface) { + /* Let the driver create the surface. */ + ret = funcs->AllocateSurface( layer, layer->driver_data, + layer->layer_data, region->region_data, + config, &surface ); + if (ret) { + D_ERROR( "DirectFB/core/layers: AllocateSurface() failed!\n" ); + return ret; + } + } + else { + CoreLayerShared *shared = layer->shared; + + /* Choose surface capabilities depending on the buffer mode. */ + switch (config->buffermode) { + case DLBM_FRONTONLY: + break; + + case DLBM_BACKVIDEO: + case DLBM_BACKSYSTEM: + caps |= DSCAPS_DOUBLE; + break; + + case DLBM_TRIPLE: + caps |= DSCAPS_TRIPLE; + break; + + default: + D_BUG("unknown buffermode"); + break; + } + + if (context->rotation == 90 || context->rotation == 270) + caps |= DSCAPS_ROTATED; + + /* FIXME: remove this? */ + if (config->options & DLOP_DEINTERLACING) + caps |= DSCAPS_INTERLACED; + + /* Add available surface capabilities. */ + caps |= config->surface_caps & (DSCAPS_INTERLACED | + DSCAPS_SEPARATED | + DSCAPS_PREMULTIPLIED); + + scon.flags = CSCONF_SIZE | CSCONF_FORMAT | CSCONF_CAPS; + scon.size.w = config->width; + scon.size.h = config->height; + scon.format = config->format; + scon.caps = caps; + + if (shared->contexts.primary == region->context) + type |= CSTF_SHARED; + + /* Use the default surface creation. */ + ret = dfb_surface_create( layer->core, &scon, type, shared->layer_id, NULL, &surface ); + if (ret) { + D_DERROR( ret, "Core/layers: Surface creation failed!\n" ); + return ret; + } + + if (config->buffermode == DLBM_BACKSYSTEM) + surface->buffers[1]->policy = CSP_SYSTEMONLY; + } + + if (surface->config.caps & DSCAPS_ROTATED) + surface->rotation = context->rotation; + else + surface->rotation = (context->rotation == 180) ? 180 : 0; + + /* Tell the region about its new surface (adds a global reference). */ + ret = dfb_layer_region_set_surface( region, surface ); + + /* Remove local reference of dfb_surface_create(). */ + dfb_surface_unref( surface ); + + return ret; +} + +static DFBResult +reallocate_surface( CoreLayer *layer, + CoreLayerRegion *region, + CoreLayerRegionConfig *config ) +{ + DFBResult ret; + const DisplayLayerFuncs *funcs; + CoreLayerContext *context; + CoreSurface *surface; + CoreSurfaceConfig sconfig; + + D_DEBUG_AT( Core_LayerContext, "%s( %p, %p, %p )\n", __FUNCTION__, layer, region, config ); + + D_ASSERT( layer != NULL ); + D_ASSERT( layer->funcs != NULL ); + D_ASSERT( region != NULL ); + D_ASSERT( region->surface != NULL ); + D_ASSERT( config != NULL ); + D_ASSERT( config->buffermode != DLBM_WINDOWS ); + + context = region->context; + D_MAGIC_ASSERT( context, CoreLayerContext ); + + funcs = layer->funcs; + surface = region->surface; + + if (funcs->ReallocateSurface) + return funcs->ReallocateSurface( layer, layer->driver_data, + layer->layer_data, + region->region_data, + config, surface ); + + sconfig.flags = CSCONF_SIZE | CSCONF_FORMAT | CSCONF_CAPS; + + sconfig.caps = surface->config.caps & ~(DSCAPS_FLIPPING | DSCAPS_INTERLACED | + DSCAPS_SEPARATED | DSCAPS_PREMULTIPLIED | DSCAPS_ROTATED); + + switch (config->buffermode) { + case DLBM_TRIPLE: + sconfig.caps |= DSCAPS_TRIPLE; + break; + + case DLBM_BACKVIDEO: + case DLBM_BACKSYSTEM: + sconfig.caps |= DSCAPS_DOUBLE; + break; + + case DLBM_FRONTONLY: + break; + + default: + D_BUG("unknown buffermode"); + return DFB_BUG; + } + + if (context->rotation == 90 || context->rotation == 270) + sconfig.caps |= DSCAPS_ROTATED; + + /* Add available surface capabilities. */ + sconfig.caps |= config->surface_caps & (DSCAPS_INTERLACED | + DSCAPS_SEPARATED | + DSCAPS_PREMULTIPLIED); + + if (config->options & DLOP_DEINTERLACING) + sconfig.caps |= DSCAPS_INTERLACED; + + sconfig.size.w = config->width; + sconfig.size.h = config->height; + sconfig.format = config->format; + + ret = dfb_surface_lock( surface ); + if (ret) + return ret; + + ret = dfb_surface_reconfig( surface, &sconfig ); + if (ret) { + dfb_surface_unlock( surface ); + return ret; + } + + if (DFB_PIXELFORMAT_IS_INDEXED(surface->config.format) && !surface->palette) { + ret = dfb_surface_init_palette( layer->core, surface ); + if (ret) + D_DERROR( ret, "Core/Layers: Could not initialize palette while switching to indexed mode!\n" ); + } + + switch (config->buffermode) { + case DLBM_TRIPLE: + case DLBM_BACKVIDEO: + surface->buffers[1]->policy = CSP_VIDEOONLY; + break; + + case DLBM_BACKSYSTEM: + surface->buffers[1]->policy = CSP_SYSTEMONLY; + break; + + case DLBM_FRONTONLY: + break; + + default: + D_BUG("unknown buffermode"); + return DFB_BUG; + } + + if (surface->config.caps & DSCAPS_ROTATED) + surface->rotation = context->rotation; + else + surface->rotation = (context->rotation == 180) ? 180 : 0; + + dfb_surface_unlock( surface ); + + return DFB_OK; +} + +static DFBResult +deallocate_surface( CoreLayer *layer, CoreLayerRegion *region ) +{ + DFBResult ret; + const DisplayLayerFuncs *funcs; + CoreSurface *surface; + + D_DEBUG_AT( Core_LayerContext, "%s( %p, %p )\n", __FUNCTION__, layer, region ); + + D_ASSERT( layer != NULL ); + D_ASSERT( layer->funcs != NULL ); + D_ASSERT( region != NULL ); + + D_ASSUME( region->surface != NULL ); + + funcs = layer->funcs; + surface = region->surface; + + if (surface) { + /* Special deallocation by the driver. */ + if (funcs->DeallocateSurface) { + ret = funcs->DeallocateSurface( layer, layer->driver_data, + layer->layer_data, + region->region_data, surface ); + if (ret) + return ret; + } + + /* Detach the global listener. */ + dfb_surface_detach_global( surface, ®ion->surface_reaction ); + + /* Unlink from structure. */ + dfb_surface_unlink( ®ion->surface ); + } + + return DFB_OK; +} + +static void +screen_rectangle( CoreLayerContext *context, + const DFBLocation *location, + DFBRectangle *rect ) +{ + DFBResult ret; + int width; + int height; + CoreLayer *layer; + + D_DEBUG_AT( Core_LayerContext, "%s( %p, %p, %p )\n", __FUNCTION__, context, location, rect ); + + D_MAGIC_ASSERT( context, CoreLayerContext ); + D_ASSERT( location != NULL ); + D_ASSERT( rect != NULL ); + + D_DEBUG_AT( Core_LayerContext, " <- %4.2f,%4.2f-%4.2f,%4.2f\n", + location->x, location->y, location->w, location->h ); + + layer = dfb_layer_at( context->layer_id ); + D_ASSERT( layer != NULL ); + D_ASSERT( layer->screen != NULL ); + + ret = dfb_screen_get_layer_dimension( layer->screen, layer, &width, &height ); + if (ret) { + D_WARN( "could not determine mixer/screen dimension of layer %d", context->layer_id ); + + rect->x = location->x * 720; + rect->y = location->y * 576; + rect->w = location->w * 720; + rect->h = location->h * 576; + } + else { + rect->x = location->x * width; + rect->y = location->y * height; + rect->w = location->w * width; + rect->h = location->h * height; + } + + D_DEBUG_AT( Core_LayerContext, " => %4d,%4d-%4d,%4d\n", DFB_RECTANGLE_VALS(rect) ); +} + diff --git a/Source/DirectFB/src/core/layer_context.h b/Source/DirectFB/src/core/layer_context.h new file mode 100755 index 0000000..ab9d2fb --- /dev/null +++ b/Source/DirectFB/src/core/layer_context.h @@ -0,0 +1,149 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef __CORE__LAYER_CONTEXT_H__ +#define __CORE__LAYER_CONTEXT_H__ + +#include + +#include +#include + +typedef enum { + CLCNF_ACTIVATED = 0x00000001, + CLCNF_DEACTIVATED = 0x00000002 +} CoreLayerContextNotificationFlags; + +typedef struct { + CoreLayerContextNotificationFlags flags; + CoreLayerContext *context; +} CoreLayerContextNotification; + +/* + * Creates a pool of layer context objects. + */ +FusionObjectPool *dfb_layer_context_pool_create( const FusionWorld *world ); + +/* + * Generates dfb_layer_context_ref(), dfb_layer_context_attach() etc. + */ +FUSION_OBJECT_METHODS( CoreLayerContext, dfb_layer_context ) + + +DFBResult dfb_layer_context_init( CoreLayerContext *context, + CoreLayer *layer ); + +DFBResult dfb_layer_context_get_primary_region( CoreLayerContext *context, + bool create, + CoreLayerRegion **ret_region ); + +/* + * configuration testing/setting/getting + */ +DFBResult dfb_layer_context_test_configuration ( CoreLayerContext *context, + const DFBDisplayLayerConfig *config, + DFBDisplayLayerConfigFlags *ret_failed ); + +DFBResult dfb_layer_context_set_configuration ( CoreLayerContext *context, + const DFBDisplayLayerConfig *config ); + +DFBResult dfb_layer_context_get_configuration ( CoreLayerContext *context, + DFBDisplayLayerConfig *ret_config ); + + +/* + * configuration details + */ +DFBResult dfb_layer_context_set_src_colorkey ( CoreLayerContext *context, + u8 r, + u8 g, + u8 b, + int index ); + +DFBResult dfb_layer_context_set_dst_colorkey ( CoreLayerContext *context, + u8 r, + u8 g, + u8 b, + int index ); + +DFBResult dfb_layer_context_set_sourcerectangle( CoreLayerContext *context, + const DFBRectangle *source ); + +DFBResult dfb_layer_context_set_screenlocation ( CoreLayerContext *context, + const DFBLocation *location ); + +DFBResult dfb_layer_context_set_screenrectangle( CoreLayerContext *context, + const DFBRectangle *rectangle ); + +DFBResult dfb_layer_context_set_screenposition ( CoreLayerContext *context, + int x, + int y ); + +DFBResult dfb_layer_context_set_opacity ( CoreLayerContext *context, + u8 opacity ); + +DFBResult dfb_layer_context_set_rotation ( CoreLayerContext *context, + int rotation ); + +DFBResult dfb_layer_context_set_coloradjustment( CoreLayerContext *context, + const DFBColorAdjustment *adjustment ); + +DFBResult dfb_layer_context_get_coloradjustment( CoreLayerContext *context, + DFBColorAdjustment *ret_adjustment ); + +DFBResult dfb_layer_context_set_field_parity ( CoreLayerContext *context, + int field ); + +DFBResult dfb_layer_context_set_clip_regions ( CoreLayerContext *context, + const DFBRegion *regions, + int num_regions, + DFBBoolean positive ); + + +/* + * window control + */ +DFBResult dfb_layer_context_create_window( CoreDFB *core, + CoreLayerContext *context, + const DFBWindowDescription *desc, + CoreWindow **ret_window ); + +CoreWindow *dfb_layer_context_find_window( CoreLayerContext *context, + DFBWindowID id ); + +CoreWindowStack *dfb_layer_context_windowstack( const CoreLayerContext *context ); + +bool dfb_layer_context_active ( const CoreLayerContext *context ); + +/* + * Locking + */ +DirectResult dfb_layer_context_lock ( CoreLayerContext *context ); +DirectResult dfb_layer_context_unlock( CoreLayerContext *context ); + +#endif diff --git a/Source/DirectFB/src/core/layer_control.c b/Source/DirectFB/src/core/layer_control.c new file mode 100755 index 0000000..b190cc5 --- /dev/null +++ b/Source/DirectFB/src/core/layer_control.c @@ -0,0 +1,589 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include + +#include + + +D_DEBUG_DOMAIN( Core_Layers, "Core/Layers", "DirectFB Display Layer Core" ); + +/** public **/ + +DFBResult +dfb_layer_suspend( CoreLayer *layer ) +{ + CoreLayerShared *shared; + CoreLayerContexts *contexts; + + D_ASSERT( layer != NULL ); + D_ASSERT( layer->shared != NULL ); + + shared = layer->shared; + contexts = &shared->contexts; + + /* Lock the layer. */ + if (fusion_skirmish_prevail( &shared->lock )) + return DFB_FUSION; + + D_ASSUME( !shared->suspended ); + + if (shared->suspended) { + fusion_skirmish_dismiss( &shared->lock ); + return DFB_OK; + } + + /* Deactivate current context. */ + if (contexts->active >= 0) { + DFBResult ret; + CoreLayerContext *current = fusion_vector_at( &contexts->stack, + contexts->active ); + + ret = dfb_layer_context_deactivate( current ); + if (ret) { + D_ERROR("DirectFB/Core/layer: " + "Could not deactivate current context of '%s'! (%s)\n", + shared->description.name, DirectFBErrorString( ret )); + } + } + + shared->suspended = true; + + /* Unlock the layer. */ + fusion_skirmish_dismiss( &shared->lock ); + + return DFB_OK; +} + +DFBResult +dfb_layer_resume( CoreLayer *layer ) +{ + CoreLayerShared *shared; + CoreLayerContexts *contexts; + + D_ASSERT( layer != NULL ); + D_ASSERT( layer->shared != NULL ); + + shared = layer->shared; + contexts = &shared->contexts; + + /* Lock the layer. */ + if (fusion_skirmish_prevail( &shared->lock )) + return DFB_FUSION; + + D_ASSUME( shared->suspended ); + + if (!shared->suspended) { + fusion_skirmish_dismiss( &shared->lock ); + return DFB_OK; + } + + /* (Re)Activate current context. */ + if (contexts->active >= 0) { + DFBResult ret; + CoreLayerContext *current = fusion_vector_at( &contexts->stack, + contexts->active ); + + ret = dfb_layer_context_activate( current ); + if (ret) { + D_ERROR("DirectFB/Core/layer: " + "Could not activate current context of '%s'! (%s)\n", + shared->description.name, DirectFBErrorString( ret )); + } + } + + shared->suspended = false; + + /* Unlock the layer. */ + fusion_skirmish_dismiss( &shared->lock ); + + return DFB_OK; +} + +DFBResult +dfb_layer_create_context( CoreLayer *layer, + CoreLayerContext **ret_context ) +{ + DFBResult ret; + CoreLayerShared *shared; + CoreLayerContexts *contexts; + CoreLayerContext *context = NULL; + + D_ASSERT( layer != NULL ); + D_ASSERT( layer->shared != NULL ); + D_ASSERT( ret_context != NULL ); + + shared = layer->shared; + contexts = &shared->contexts; + + D_DEBUG_AT( Core_Layers, "%s (%s)\n", __FUNCTION__, shared->description.name ); + + /* Create the object. */ + context = dfb_core_create_layer_context( layer->core ); + if (!context) + return DFB_FUSION; + + /* Lock the layer. */ + if (fusion_skirmish_prevail( &shared->lock )) { + fusion_object_destroy( &context->object ); + return DFB_FUSION; + } + + /* Initialize the new context. */ + ret = dfb_layer_context_init( context, layer ); + if (ret) { + fusion_skirmish_dismiss( &shared->lock ); + return ret; + } + + /* Add it to the context stack. */ + if (fusion_vector_add( &contexts->stack, context )) { + dfb_layer_context_unref( context ); + fusion_skirmish_dismiss( &shared->lock ); + return DFB_FUSION; + } + + /* Unlock the layer. */ + fusion_skirmish_dismiss( &shared->lock ); + + /* Return the context. */ + *ret_context = context; + + return DFB_OK; +} + +DFBResult +dfb_layer_get_active_context( CoreLayer *layer, + CoreLayerContext **ret_context ) +{ + CoreLayerShared *shared; + CoreLayerContexts *contexts; + CoreLayerContext *context; + + D_ASSERT( layer != NULL ); + D_ASSERT( layer->shared != NULL ); + D_ASSERT( ret_context != NULL ); + + shared = layer->shared; + contexts = &shared->contexts; + + D_DEBUG_AT( Core_Layers, "%s (%s)\n", __FUNCTION__, shared->description.name ); + + /* Lock the layer. */ + if (fusion_skirmish_prevail( &shared->lock )) + return DFB_FUSION; + + /* Check for active context. */ + if (contexts->active < 0) { + fusion_skirmish_dismiss( &shared->lock ); + return DFB_NOCONTEXT; + } + + /* Fetch active context. */ + context = fusion_vector_at( &contexts->stack, contexts->active ); + + /* Increase the context's reference counter. */ + if (dfb_layer_context_ref( context )) { + fusion_skirmish_dismiss( &shared->lock ); + return DFB_FUSION; + } + + D_DEBUG_AT( Core_Layers, " => %p [%4dx%4d %8s]\n", context, + context->config.width, context->config.height, + dfb_pixelformat_name( context->config.pixelformat ) ); + + /* Return the context. */ + *ret_context = context; + + /* Unlock the layer. */ + fusion_skirmish_dismiss( &shared->lock ); + + return DFB_OK; +} + +DFBResult +dfb_layer_get_primary_context( CoreLayer *layer, + bool activate, + CoreLayerContext **ret_context ) +{ + DFBResult ret; + CoreLayerShared *shared; + CoreLayerContexts *contexts; + + D_ASSERT( layer != NULL ); + D_ASSERT( layer->shared != NULL ); + D_ASSERT( ret_context != NULL ); + + shared = layer->shared; + contexts = &shared->contexts; + + /* Lock the layer. */ + if (fusion_skirmish_prevail( &shared->lock )) + return DFB_FUSION; + + D_DEBUG_AT( Core_Layers, "%s (%s, %sactivate) <- active: %d\n", + __FUNCTION__, shared->description.name, + activate ? "" : "don't ", contexts->active ); + + /* Check for primary context. */ + if (contexts->primary) { + /* Increase the context's reference counter. */ + if (dfb_layer_context_ref( contexts->primary )) { + fusion_skirmish_dismiss( &shared->lock ); + return DFB_FUSION; + } + } + else { + CoreLayerContext *primary; + + /* Unlock the layer. */ + fusion_skirmish_dismiss( &shared->lock ); + + /* Create the primary (shared) context. */ + ret = dfb_layer_create_context( layer, &primary ); + if (ret) + return ret; + + /* Lock the layer again. */ + if (fusion_skirmish_prevail( &shared->lock )) { + dfb_layer_context_unref( primary ); + return DFB_FUSION; + } + + /* Check if there was a race. */ + if (contexts->primary) { + /* Throw away ours, the other was faster. */ + dfb_layer_context_unref( primary ); + + /* Increase the context's reference counter. */ + if (dfb_layer_context_ref( contexts->primary )) { + fusion_skirmish_dismiss( &shared->lock ); + return DFB_FUSION; + } + } + else + contexts->primary = primary; + } + + /* Activate if no context is active? */ + if (contexts->active < 0 && activate) { + ret = dfb_layer_activate_context( layer, contexts->primary ); + if (ret) { + dfb_layer_context_unref( contexts->primary ); + fusion_skirmish_dismiss( &shared->lock ); + return ret; + } + } + + /* Return the context. */ + *ret_context = contexts->primary; + + /* Unlock the layer. */ + fusion_skirmish_dismiss( &shared->lock ); + + return DFB_OK; +} + +DFBResult +dfb_layer_activate_context( CoreLayer *layer, + CoreLayerContext *context ) +{ + DFBResult ret = DFB_OK; + int index; + CoreLayerShared *shared; + CoreLayerContexts *ctxs; + + D_ASSERT( layer != NULL ); + D_ASSERT( layer->shared != NULL ); + D_ASSERT( context != NULL ); + + shared = layer->shared; + ctxs = &shared->contexts; + + /* Lock the layer. */ + if (fusion_skirmish_prevail( &shared->lock )) + return DFB_FUSION; + + D_DEBUG_AT( Core_Layers, "%s (%s, %p)\n", __FUNCTION__, shared->description.name, context ); + + D_ASSERT( fusion_vector_contains( &ctxs->stack, context ) ); + + /* Lookup the context in the context stack. */ + index = fusion_vector_index_of( &ctxs->stack, context ); + + /* Lock the context. */ + if (dfb_layer_context_lock( context )) { + fusion_skirmish_dismiss( &shared->lock ); + return DFB_FUSION; + } + + /* Need to activate? */ + if (ctxs->active != index) { + DFBResult ret; + + /* Another context currently active? */ + if (ctxs->active >= 0) { + CoreLayerContext *current = fusion_vector_at( &ctxs->stack, + ctxs->active ); + + /* Deactivate current context. */ + if (!shared->suspended) { + ret = dfb_layer_context_deactivate( current ); + if (ret) + goto error; + } + + /* No active context. */ + ctxs->active = -1; + } + + /* Activate context now. */ + if (!shared->suspended) { + ret = dfb_layer_context_activate( context ); + if (ret) + goto error; + } + + ctxs->active = index; + } + + /* Unlock the context. */ + dfb_layer_context_unlock( context ); + + /* Unlock the layer. */ + fusion_skirmish_dismiss( &shared->lock ); + + return DFB_OK; + +error: + dfb_layer_context_unlock( context ); + + fusion_skirmish_dismiss( &shared->lock ); + + return ret; +} + +DFBResult +dfb_layer_remove_context( CoreLayer *layer, + CoreLayerContext *context ) +{ + int index; + CoreLayerShared *shared; + CoreLayerContexts *ctxs; + + D_ASSERT( layer != NULL ); + D_ASSERT( layer->shared != NULL ); + D_ASSERT( context != NULL ); + + shared = layer->shared; + ctxs = &shared->contexts; + + /* Lock the layer. */ + if (fusion_skirmish_prevail( &shared->lock )) + return DFB_FUSION; + + D_DEBUG_AT( Core_Layers, "%s (%s, %p)\n", __FUNCTION__, shared->description.name, context ); + + D_ASSUME( fusion_vector_contains( &ctxs->stack, context ) ); + + /* Lookup the context in the context stack. */ + index = fusion_vector_index_of( &ctxs->stack, context ); + if (index < 0) { + fusion_skirmish_dismiss( &shared->lock ); + return DFB_OK; + } + + /* Lock the context. */ + if (dfb_layer_context_lock( context )) { + fusion_skirmish_dismiss( &shared->lock ); + return DFB_FUSION; + } + + /* Remove context from context stack. */ + fusion_vector_remove( &ctxs->stack, index ); + + /* Check if the primary context is removed. */ + if (context == ctxs->primary) + ctxs->primary = NULL; + + /* Need to deactivate? */ + if (ctxs->active == index) { + /* Deactivate the context. */ + if (!shared->suspended) + dfb_layer_context_deactivate( context ); + + /* There's no active context anymore. */ + ctxs->active = -1; + + if (ctxs->primary) + D_ASSERT( fusion_vector_contains( &ctxs->stack, ctxs->primary ) ); + + if (fusion_vector_has_elements( &ctxs->stack )) { + CoreLayerContext *ctx; + + /* Activate most recent context. */ + index = fusion_vector_size( &ctxs->stack ) - 1; + ctx = fusion_vector_at( &ctxs->stack, index ); + + if (shared->suspended || dfb_layer_context_activate( ctx ) == DFB_OK) + ctxs->active = index; + } + } + else if (ctxs->active > index) { + /* Adjust index of active context due to the removed context. */ + ctxs->active--; + } + + /* Unlock the context. */ + dfb_layer_context_unlock( context ); + + /* Unlock the layer. */ + fusion_skirmish_dismiss( &shared->lock ); + + return DFB_OK; +} + +DFBResult +dfb_layer_get_current_output_field( CoreLayer *layer, int *field ) +{ + DFBResult ret; + + D_ASSERT( layer != NULL ); + D_ASSERT( layer->funcs != NULL ); + D_ASSERT( field != NULL ); + + if (!layer->funcs->GetCurrentOutputField) + return DFB_UNSUPPORTED; + + ret = layer->funcs->GetCurrentOutputField( layer, layer->driver_data, + layer->layer_data, field ); + if (ret) + return ret; + + return DFB_OK; +} + +DFBResult +dfb_layer_get_level( CoreLayer *layer, int *ret_level ) +{ + const DisplayLayerFuncs *funcs; + + D_ASSERT( layer != NULL ); + D_ASSERT( layer->funcs != NULL ); + D_ASSERT( ret_level != NULL ); + + funcs = layer->funcs; + + if (!funcs->GetLevel) + return DFB_UNSUPPORTED; + + return funcs->GetLevel( layer, layer->driver_data, + layer->layer_data, ret_level ); +} + +DFBResult +dfb_layer_set_level( CoreLayer *layer, int level ) +{ + const DisplayLayerFuncs *funcs; + + D_ASSERT( layer != NULL ); + D_ASSERT( layer->funcs != NULL ); + + funcs = layer->funcs; + + if (!funcs->SetLevel) + return DFB_UNSUPPORTED; + + return funcs->SetLevel( layer, layer->driver_data, + layer->layer_data, level ); +} + +DFBResult +dfb_layer_wait_vsync( CoreLayer *layer ) +{ + D_ASSERT( layer != NULL ); + D_ASSERT( layer->screen != NULL ); + + return dfb_screen_wait_vsync( layer->screen ); +} + +DFBResult +dfb_layer_get_source_info( CoreLayer *layer, + int source, + DFBDisplayLayerSourceDescription *ret_desc ) +{ + D_ASSERT( layer != NULL ); + D_ASSERT( layer->shared != NULL ); + D_ASSERT( source >= 0 ); + D_ASSERT( source < layer->shared->description.sources ); + D_ASSERT( ret_desc != NULL ); + + *ret_desc = layer->shared->sources[source].description; + + return DFB_OK; +} + diff --git a/Source/DirectFB/src/core/layer_control.h b/Source/DirectFB/src/core/layer_control.h new file mode 100755 index 0000000..51b7ae2 --- /dev/null +++ b/Source/DirectFB/src/core/layer_control.h @@ -0,0 +1,72 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef __CORE__LAYER_CONTROL_H__ +#define __CORE__LAYER_CONTROL_H__ + +#include + +#include + + +DFBResult dfb_layer_create_context ( CoreLayer *layer, + CoreLayerContext **ret_context ); + +DFBResult dfb_layer_get_active_context ( CoreLayer *layer, + CoreLayerContext **ret_context ); + +DFBResult dfb_layer_get_primary_context ( CoreLayer *layer, + bool activate, + CoreLayerContext **ret_context ); + +DFBResult dfb_layer_activate_context ( CoreLayer *layer, + CoreLayerContext *context ); + +DFBResult dfb_layer_remove_context ( CoreLayer *layer, + CoreLayerContext *context ); + +DFBResult dfb_layer_suspend ( CoreLayer *layer ); +DFBResult dfb_layer_resume ( CoreLayer *layer ); + + +DFBResult dfb_layer_get_current_output_field( CoreLayer *layer, + int *field ); + +DFBResult dfb_layer_get_level ( CoreLayer *layer, + int *ret_level ); + +DFBResult dfb_layer_set_level ( CoreLayer *layer, + int level ); + +DFBResult dfb_layer_wait_vsync ( CoreLayer *layer ); + +DFBResult dfb_layer_get_source_info ( CoreLayer *layer, + int source, + DFBDisplayLayerSourceDescription *ret_desc ); + +#endif diff --git a/Source/DirectFB/src/core/layer_region.c b/Source/DirectFB/src/core/layer_region.c new file mode 100755 index 0000000..b96e742 --- /dev/null +++ b/Source/DirectFB/src/core/layer_region.c @@ -0,0 +1,1129 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include + +#include + +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + + +D_DEBUG_DOMAIN( Core_Layers, "Core/Layers", "DirectFB Display Layer Core" ); + + +static DFBResult region_buffer_lock( CoreLayerRegion *region, + CoreSurface *surface, + CoreSurfaceBufferRole role ); + +static DFBResult set_region ( CoreLayerRegion *region, + CoreLayerRegionConfig *config, + CoreLayerRegionConfigFlags flags, + CoreSurface *surface ); + +static DFBResult realize_region ( CoreLayerRegion *region ); + +static DFBResult unrealize_region( CoreLayerRegion *region ); + +/******************************************************************************/ + +static void +region_destructor( FusionObject *object, bool zombie, void *ctx ) +{ + CoreLayerRegion *region = (CoreLayerRegion*) object; + CoreLayerContext *context = region->context; + CoreLayer *layer = dfb_layer_at( context->layer_id ); + CoreLayerShared *shared = layer->shared; + + D_DEBUG_AT( Core_Layers, "destroying region %p (%s, %dx%d, " + "%s, %s, %s, %s%s)\n", region, shared->description.name, + region->config.width, region->config.height, + D_FLAGS_IS_SET( region->state, + CLRSF_CONFIGURED ) ? "configured" : "unconfigured", + D_FLAGS_IS_SET( region->state, + CLRSF_ENABLED ) ? "enabled" : "disabled", + D_FLAGS_IS_SET( region->state, + CLRSF_ACTIVE ) ? "active" : "inactive", + D_FLAGS_IS_SET( region->state, + CLRSF_REALIZED ) ? "realized" : "not realized", + zombie ? " - ZOMBIE" : "" ); + + /* Hide region etc. */ + if (D_FLAGS_IS_SET( region->state, CLRSF_ENABLED )) + dfb_layer_region_disable( region ); + + /* Remove the region from the context. */ + dfb_layer_context_remove_region( region->context, region ); + + /* Throw away its surface. */ + if (region->surface) { + /* Detach the global listener. */ + dfb_surface_detach_global( region->surface, + ®ion->surface_reaction ); + + /* Unlink from structure. */ + dfb_surface_unlink( ®ion->surface ); + } + + /* Unlink the context from the structure. */ + dfb_layer_context_unlink( ®ion->context ); + + /* Free driver's region data. */ + if (region->region_data) + SHFREE( shared->shmpool, region->region_data ); + + /* Deinitialize the lock. */ + fusion_skirmish_destroy( ®ion->lock ); + + /* Destroy the object. */ + fusion_object_destroy( object ); +} + +/******************************************************************************/ + +FusionObjectPool * +dfb_layer_region_pool_create( const FusionWorld *world ) +{ + return fusion_object_pool_create( "Layer Region Pool", + sizeof(CoreLayerRegion), + sizeof(CoreLayerRegionNotification), + region_destructor, NULL, world ); +} + +/******************************************************************************/ + +DFBResult +dfb_layer_region_create( CoreLayerContext *context, + CoreLayerRegion **ret_region ) +{ + CoreLayer *layer; + CoreLayerRegion *region; + + D_ASSERT( context != NULL ); + D_ASSERT( ret_region != NULL ); + + layer = dfb_layer_at( context->layer_id ); + + /* Create the object. */ + region = dfb_core_create_layer_region( layer->core ); + if (!region) + return DFB_FUSION; + + /* Link the context into the structure. */ + if (dfb_layer_context_link( ®ion->context, context )) { + fusion_object_destroy( ®ion->object ); + return DFB_FUSION; + } + + /* Initialize the lock. */ + if (fusion_skirmish_init( ®ion->lock, "Layer Region", dfb_core_world(layer->core) )) { + dfb_layer_context_unlink( ®ion->context ); + fusion_object_destroy( ®ion->object ); + return DFB_FUSION; + } + + /* Change global reaction lock. */ + fusion_object_set_lock( ®ion->object, ®ion->lock ); + + region->state = CLRSF_FROZEN; + + /* Activate the object. */ + fusion_object_activate( ®ion->object ); + + /* Add the region to the context. */ + dfb_layer_context_add_region( context, region ); + + /* Return the new region. */ + *ret_region = region; + + return DFB_OK; +} + +DFBResult +dfb_layer_region_activate( CoreLayerRegion *region ) +{ + DFBResult ret; + + D_ASSERT( region != NULL ); + + /* Lock the region. */ + if (dfb_layer_region_lock( region )) + return DFB_FUSION; + + D_ASSUME( ! D_FLAGS_IS_SET( region->state, CLRSF_ACTIVE ) ); + + if (D_FLAGS_IS_SET( region->state, CLRSF_ACTIVE )) { + dfb_layer_region_unlock( region ); + return DFB_OK; + } + + /* Realize the region if it's enabled. */ + if (D_FLAGS_IS_SET( region->state, CLRSF_ENABLED )) { + ret = realize_region( region ); + if (ret) { + dfb_layer_region_unlock( region ); + return ret; + } + } + + /* Update the region's state. */ + D_FLAGS_SET( region->state, CLRSF_ACTIVE ); + + /* Unlock the region. */ + dfb_layer_region_unlock( region ); + + return DFB_OK; +} + +DFBResult +dfb_layer_region_deactivate( CoreLayerRegion *region ) +{ + DFBResult ret; + + D_ASSERT( region != NULL ); + + /* Lock the region. */ + if (dfb_layer_region_lock( region )) + return DFB_FUSION; + + D_ASSUME( D_FLAGS_IS_SET( region->state, CLRSF_ACTIVE ) ); + + if (! D_FLAGS_IS_SET( region->state, CLRSF_ACTIVE )) { + dfb_layer_region_unlock( region ); + return DFB_OK; + } + + /* Unrealize the region? */ + if (D_FLAGS_IS_SET( region->state, CLRSF_REALIZED )) { + ret = unrealize_region( region ); + if (ret) + return ret; + } + + /* Update the region's state. */ + D_FLAGS_CLEAR( region->state, CLRSF_ACTIVE ); + + /* Unlock the region. */ + dfb_layer_region_unlock( region ); + + return DFB_OK; +} + +DFBResult +dfb_layer_region_enable( CoreLayerRegion *region ) +{ + DFBResult ret; + + D_ASSERT( region != NULL ); + D_ASSERT( region->context != NULL ); + + /* Lock the region. */ + if (dfb_layer_region_lock( region )) + return DFB_FUSION; + + D_ASSUME( ! D_FLAGS_IS_SET( region->state, CLRSF_ENABLED ) ); + + if (D_FLAGS_IS_SET( region->state, CLRSF_ENABLED )) { + dfb_layer_region_unlock( region ); + return DFB_OK; + } + + /* Realize the region if it's active. */ + if (D_FLAGS_IS_SET( region->state, CLRSF_ACTIVE )) { + ret = realize_region( region ); + if (ret) { + dfb_layer_region_unlock( region ); + return ret; + } + } + + /* Update the region's state. */ + D_FLAGS_SET( region->state, CLRSF_ENABLED ); + + /* Unlock the region. */ + dfb_layer_region_unlock( region ); + + return DFB_OK; +} + +DFBResult +dfb_layer_region_disable( CoreLayerRegion *region ) +{ + DFBResult ret; + + D_ASSERT( region != NULL ); + + /* Lock the region. */ + if (dfb_layer_region_lock( region )) + return DFB_FUSION; + + D_ASSUME( D_FLAGS_IS_SET( region->state, CLRSF_ENABLED ) ); + + if (! D_FLAGS_IS_SET( region->state, CLRSF_ENABLED )) { + dfb_layer_region_unlock( region ); + return DFB_OK; + } + + /* Unrealize the region? */ + if (D_FLAGS_IS_SET( region->state, CLRSF_REALIZED )) { + ret = unrealize_region( region ); + if (ret) + return ret; + } + + /* Update the region's state. */ + D_FLAGS_CLEAR( region->state, CLRSF_ENABLED ); + + /* Unlock the region. */ + dfb_layer_region_unlock( region ); + + return DFB_OK; +} + +DFBResult +dfb_layer_region_set_surface( CoreLayerRegion *region, + CoreSurface *surface ) +{ + DFBResult ret; + + D_ASSERT( region != NULL ); + D_ASSERT( surface != NULL ); + + /* Lock the region. */ + if (dfb_layer_region_lock( region )) + return DFB_FUSION; + + if (region->surface != surface) { + /* Setup hardware for the new surface if the region is realized. */ + if (D_FLAGS_IS_SET( region->state, CLRSF_REALIZED )) { + ret = set_region( region, ®ion->config, CLRCF_SURFACE | CLRCF_PALETTE, surface ); + if (ret) { + dfb_layer_region_unlock( region ); + return ret; + } + } + + /* Throw away the old surface. */ + if (region->surface) { + /* Detach the global listener. */ + dfb_surface_detach_global( region->surface, + ®ion->surface_reaction ); + + /* Unlink surface from structure. */ + dfb_surface_unlink( ®ion->surface ); + } + + /* Take the new surface. */ + if (surface) { + /* Link surface into structure. */ + if (dfb_surface_link( ®ion->surface, surface )) { + D_WARN( "region lost it's surface" ); + dfb_layer_region_unlock( region ); + return DFB_FUSION; + } + + /* Attach the global listener. */ + dfb_surface_attach_global( region->surface, + DFB_LAYER_REGION_SURFACE_LISTENER, + region, ®ion->surface_reaction ); + } + } + + /* Unlock the region. */ + dfb_layer_region_unlock( region ); + + return DFB_OK; +} + +DFBResult +dfb_layer_region_get_surface( CoreLayerRegion *region, + CoreSurface **ret_surface ) +{ + D_ASSERT( region != NULL ); + D_ASSERT( ret_surface != NULL ); + + /* Lock the region. */ + if (dfb_layer_region_lock( region )) + return DFB_FUSION; + + D_ASSUME( region->surface != NULL ); + + /* Check for NULL surface. */ + if (!region->surface) { + dfb_layer_region_unlock( region ); + return DFB_UNSUPPORTED; + } + + /* Increase the surface's reference counter. */ + if (dfb_surface_ref( region->surface )) { + dfb_layer_region_unlock( region ); + return DFB_FUSION; + } + + /* Return the surface. */ + *ret_surface = region->surface; + + /* Unlock the region. */ + dfb_layer_region_unlock( region ); + + return DFB_OK; +} + +DFBResult +dfb_layer_region_flip_update( CoreLayerRegion *region, + const DFBRegion *update, + DFBSurfaceFlipFlags flags ) +{ + DFBResult ret = DFB_OK; + DFBRegion unrotated; + DFBRegion rotated; + CoreLayer *layer; + CoreLayerContext *context; + CoreSurface *surface; + const DisplayLayerFuncs *funcs; + + if (update) + D_DEBUG_AT( Core_Layers, + "dfb_layer_region_flip_update( %p, %p, 0x%08x ) <- [%d, %d - %dx%d]\n", + region, update, flags, DFB_RECTANGLE_VALS_FROM_REGION( update ) ); + else + D_DEBUG_AT( Core_Layers, + "dfb_layer_region_flip_update( %p, %p, 0x%08x )\n", region, update, flags ); + + + D_ASSERT( region != NULL ); + D_ASSERT( region->context != NULL ); + + /* Lock the region. */ + if (dfb_layer_region_lock( region )) + return DFB_FUSION; + + D_ASSUME( region->surface != NULL ); + + /* Check for NULL surface. */ + if (!region->surface) { + D_DEBUG_AT( Core_Layers, " -> No surface => no update!\n" ); + dfb_layer_region_unlock( region ); + return DFB_UNSUPPORTED; + } + + context = region->context; + surface = region->surface; + layer = dfb_layer_at( context->layer_id ); + + D_ASSERT( layer->funcs != NULL ); + + funcs = layer->funcs; + + /* Unfreeze region? */ + if (D_FLAGS_IS_SET( region->state, CLRSF_FROZEN )) { + D_FLAGS_CLEAR( region->state, CLRSF_FROZEN ); + + if (D_FLAGS_IS_SET( region->state, CLRSF_REALIZED )) { + ret = set_region( region, ®ion->config, CLRCF_ALL, surface ); + if (ret) + D_DERROR( ret, "Core/LayerRegion: set_region() in dfb_layer_region_flip_update() failed!\n" ); + } + else if (D_FLAGS_ARE_SET( region->state, CLRSF_ENABLED | CLRSF_ACTIVE )) { + ret = realize_region( region ); + if (ret) + D_DERROR( ret, "Core/LayerRegion: realize_region() in dfb_layer_region_flip_update() failed!\n" ); + } + + if (ret) { + dfb_layer_region_unlock( region ); + return ret; + } + } + + /* Depending on the buffer mode... */ + switch (region->config.buffermode) { + case DLBM_TRIPLE: + case DLBM_BACKVIDEO: + /* Check if simply swapping the buffers is possible... */ + if (!(flags & DSFLIP_BLIT) && !surface->rotation && + (!update || (update->x1 == 0 && + update->y1 == 0 && + update->x2 == surface->config.size.w - 1 && + update->y2 == surface->config.size.h - 1))) + { + D_DEBUG_AT( Core_Layers, " -> Going to swap buffers...\n" ); + + /* Use the driver's routine if the region is realized. */ + if (D_FLAGS_IS_SET( region->state, CLRSF_REALIZED )) { + D_ASSUME( funcs->FlipRegion != NULL ); + + ret = region_buffer_lock( region, surface, CSBR_BACK ); + if (ret) { + dfb_layer_region_unlock( region ); + return ret; + } + + D_DEBUG_AT( Core_Layers, " -> Flipping region using driver...\n" ); + + if (funcs->FlipRegion) + ret = funcs->FlipRegion( layer, + layer->driver_data, + layer->layer_data, + region->region_data, + surface, flags, ®ion->surface_lock ); + + dfb_surface_unlock( surface ); + } + else { + D_DEBUG_AT( Core_Layers, " -> Flipping region not using driver...\n" ); + + /* Just do the hardware independent work. */ + dfb_surface_lock( surface ); + dfb_surface_flip( surface, false ); + dfb_surface_unlock( surface ); + } + break; + } + + /* fall through */ + + case DLBM_BACKSYSTEM: + D_DEBUG_AT( Core_Layers, " -> Going to copy portion...\n" ); + + if ((flags & DSFLIP_WAITFORSYNC) == DSFLIP_WAITFORSYNC) { + D_DEBUG_AT( Core_Layers, " -> Waiting for VSync...\n" ); + + dfb_layer_wait_vsync( layer ); + } + + D_DEBUG_AT( Core_Layers, " -> Copying content from back to front buffer...\n" ); + + /* ...or copy updated contents from back to front buffer. */ + dfb_back_to_front_copy_rotation( surface, update, surface->rotation ); + + if ((flags & DSFLIP_WAITFORSYNC) == DSFLIP_WAIT) { + D_DEBUG_AT( Core_Layers, " -> Waiting for VSync...\n" ); + + dfb_layer_wait_vsync( layer ); + } + + /* fall through */ + + case DLBM_FRONTONLY: + /* Tell the driver about the update if the region is realized. */ + if (funcs->UpdateRegion && D_FLAGS_IS_SET( region->state, CLRSF_REALIZED )) { + if (surface) { + CoreSurfaceAllocation *allocation; + + allocation = region->surface_lock.allocation; + D_ASSERT( allocation != NULL ); + + /* If hardware has written or is writing... */ + if (allocation->accessed[CSAID_GPU] & CSAF_WRITE) { + D_DEBUG_AT( Core_Layers, " -> Waiting for pending writes...\n" ); + + /* ...wait for the operation to finish. */ + if (!(flags & DSFLIP_PIPELINE)) + dfb_gfxcard_sync(); /* TODO: wait for serial instead */ + + allocation->accessed[CSAID_GPU] &= ~CSAF_WRITE; + } + + dfb_surface_lock( surface ); + dfb_surface_allocation_update( allocation, CSAF_READ ); + dfb_surface_unlock( surface ); + } + + D_DEBUG_AT( Core_Layers, " -> Notifying driver about updated content...\n" ); + + if( !update ) { + unrotated = DFB_REGION_INIT_FROM_RECTANGLE_VALS( 0, 0, + region->config.width, region->config.height ); + update = &unrotated; + } + dfb_region_from_rotated( &rotated, update, &surface->config.size, surface->rotation ); + + ret = funcs->UpdateRegion( layer, + layer->driver_data, + layer->layer_data, + region->region_data, + surface, &rotated, ®ion->surface_lock ); + } + break; + + default: + D_BUG("unknown buffer mode"); + ret = DFB_BUG; + } + + D_DEBUG_AT( Core_Layers, " -> done.\n" ); + + /* Unlock the region. */ + dfb_layer_region_unlock( region ); + + return ret; +} + +DFBResult +dfb_layer_region_set_configuration( CoreLayerRegion *region, + CoreLayerRegionConfig *config, + CoreLayerRegionConfigFlags flags ) +{ + DFBResult ret; + CoreLayer *layer; + const DisplayLayerFuncs *funcs; + CoreLayerRegionConfig new_config; + + D_ASSERT( region != NULL ); + D_ASSERT( region->context != NULL ); + D_ASSERT( config != NULL ); + D_ASSERT( config->buffermode != DLBM_WINDOWS ); + D_ASSERT( (flags == CLRCF_ALL) || (region->state & CLRSF_CONFIGURED) ); + + D_ASSUME( flags != CLRCF_NONE ); + D_ASSUME( ! (flags & ~CLRCF_ALL) ); + + layer = dfb_layer_at( region->context->layer_id ); + + D_ASSERT( layer != NULL ); + D_ASSERT( layer->funcs != NULL ); + D_ASSERT( layer->funcs->TestRegion != NULL ); + + funcs = layer->funcs; + + /* Lock the region. */ + if (dfb_layer_region_lock( region )) + return DFB_FUSION; + + /* Full configuration supplied? */ + if (flags == CLRCF_ALL) { + new_config = *config; + } + else { + /* Use the current configuration. */ + new_config = region->config; + + /* Update each modified entry. */ + if (flags & CLRCF_WIDTH) + new_config.width = config->width; + + if (flags & CLRCF_HEIGHT) + new_config.height = config->height; + + if (flags & CLRCF_FORMAT) + new_config.format = config->format; + + if (flags & CLRCF_SURFACE_CAPS) + new_config.surface_caps = config->surface_caps; + + if (flags & CLRCF_BUFFERMODE) + new_config.buffermode = config->buffermode; + + if (flags & CLRCF_OPTIONS) + new_config.options = config->options; + + if (flags & CLRCF_SOURCE_ID) + new_config.source_id = config->source_id; + + if (flags & CLRCF_SOURCE) + new_config.source = config->source; + + if (flags & CLRCF_DEST) + new_config.dest = config->dest; + + if (flags & CLRCF_OPACITY) + new_config.opacity = config->opacity; + + if (flags & CLRCF_ALPHA_RAMP) { + new_config.alpha_ramp[0] = config->alpha_ramp[0]; + new_config.alpha_ramp[1] = config->alpha_ramp[1]; + new_config.alpha_ramp[2] = config->alpha_ramp[2]; + new_config.alpha_ramp[3] = config->alpha_ramp[3]; + } + + if (flags & CLRCF_SRCKEY) + new_config.src_key = config->src_key; + + if (flags & CLRCF_DSTKEY) + new_config.dst_key = config->dst_key; + + if (flags & CLRCF_PARITY) + new_config.parity = config->parity; + + if (flags & CLRCF_CLIPS) { + new_config.clips = config->clips; + new_config.num_clips = config->num_clips; + new_config.positive = config->positive; + } + } + + /* Check if the new configuration is supported. */ + ret = funcs->TestRegion( layer, layer->driver_data, layer->layer_data, + &new_config, NULL ); + if (ret) { + dfb_layer_region_unlock( region ); + return ret; + } + + /* Check if the region should be frozen, thus requiring to apply changes explicitly. */ + if (flags & CLRCF_FREEZE) + region->state |= CLRSF_FROZEN; + + /* Propagate new configuration to the driver if the region is realized. */ + if (D_FLAGS_IS_SET( region->state, CLRSF_REALIZED )) { + ret = set_region( region, &new_config, flags, region->surface ); + if (ret) { + dfb_layer_region_unlock( region ); + return ret; + } + } + + /* Update the region's current configuration. */ + region->config = new_config; + + /* Update the region's state. */ + D_FLAGS_SET( region->state, CLRSF_CONFIGURED ); + + /* Unlock the region. */ + dfb_layer_region_unlock( region ); + + return DFB_OK; +} + +DFBResult +dfb_layer_region_get_configuration( CoreLayerRegion *region, + CoreLayerRegionConfig *config ) +{ + D_ASSERT( region != NULL ); + D_ASSERT( config != NULL ); + + D_ASSERT( D_FLAGS_IS_SET( region->state, CLRSF_CONFIGURED ) ); + + /* Lock the region. */ + if (dfb_layer_region_lock( region )) + return DFB_FUSION; + + /* Return the current configuration. */ + *config = region->config; + + /* Unlock the region. */ + dfb_layer_region_unlock( region ); + + return DFB_OK; +} + +DirectResult +dfb_layer_region_lock( CoreLayerRegion *region ) +{ + D_ASSERT( region != NULL ); + + return fusion_skirmish_prevail( ®ion->lock ); +} + +DirectResult +dfb_layer_region_unlock( CoreLayerRegion *region ) +{ + D_ASSERT( region != NULL ); + + return fusion_skirmish_dismiss( ®ion->lock ); +} + +/******************************************************************************/ + +/* + * listen to the layer's surface + */ +ReactionResult +_dfb_layer_region_surface_listener( const void *msg_data, void *ctx ) +{ + CoreSurfaceNotificationFlags flags; + CoreSurface *surface; + CoreLayer *layer; + CoreLayerShared *shared; + const DisplayLayerFuncs *funcs; + const CoreSurfaceNotification *notification = msg_data; + CoreLayerRegion *region = ctx; + + D_ASSERT( notification != NULL ); + D_ASSERT( region != NULL ); + D_ASSERT( region->context != NULL ); + + D_DEBUG_AT( Core_Layers, "_dfb_layer_region_surface_listener( %p, %p ) <- 0x%08x\n", + notification, region, notification->flags ); + + D_ASSERT( notification->surface != NULL ); + + D_ASSUME( notification->surface == region->surface ); + + if (notification->surface != region->surface) + return RS_OK; + + layer = dfb_layer_at( region->context->layer_id ); + + D_ASSERT( layer != NULL ); + D_ASSERT( layer->funcs != NULL ); + D_ASSERT( layer->funcs->SetRegion != NULL ); + D_ASSERT( layer->shared != NULL ); + + funcs = layer->funcs; + shared = layer->shared; + + flags = notification->flags; + surface = notification->surface; + + if (flags & CSNF_DESTROY) { + D_WARN( "layer region surface destroyed" ); + region->surface = NULL; + return RS_REMOVE; + } + + if (dfb_layer_region_lock( region )) + return RS_OK; + + if (D_FLAGS_ARE_SET( region->state, CLRSF_REALIZED | CLRSF_CONFIGURED ) && + !D_FLAGS_IS_SET( region->state, CLRSF_FROZEN )) + { + if (D_FLAGS_IS_SET( flags, CSNF_PALETTE_CHANGE | CSNF_PALETTE_UPDATE )) { + if (surface->palette) + funcs->SetRegion( layer, + layer->driver_data, layer->layer_data, + region->region_data, ®ion->config, + CLRCF_PALETTE, surface, surface->palette, + ®ion->surface_lock ); + } + + if ((flags & CSNF_FIELD) && funcs->SetInputField) + funcs->SetInputField( layer, + layer->driver_data, layer->layer_data, + region->region_data, surface->field ); + + if ((flags & CSNF_ALPHA_RAMP) && (shared->description.caps & DLCAPS_ALPHA_RAMP)) { + region->config.alpha_ramp[0] = surface->alpha_ramp[0]; + region->config.alpha_ramp[1] = surface->alpha_ramp[1]; + region->config.alpha_ramp[2] = surface->alpha_ramp[2]; + region->config.alpha_ramp[3] = surface->alpha_ramp[3]; + + funcs->SetRegion( layer, + layer->driver_data, layer->layer_data, + region->region_data, ®ion->config, + CLRCF_ALPHA_RAMP, surface, surface->palette, + ®ion->surface_lock ); + } + } + + dfb_layer_region_unlock( region ); + + return RS_OK; +} + +/******************************************************************************/ + +static DFBResult +region_buffer_lock( CoreLayerRegion *region, + CoreSurface *surface, + CoreSurfaceBufferRole role ) +{ + DFBResult ret; + CoreSurfaceBuffer *buffer; + CoreSurfaceAllocation *allocation; + CoreLayerContext *context; + + D_ASSERT( region != NULL ); + D_MAGIC_ASSERT( surface, CoreSurface ); + + context = region->context; + D_MAGIC_ASSERT( context, CoreLayerContext ); + + /* First unlock any previously locked buffer. */ + if (region->surface_lock.buffer) { + D_MAGIC_ASSERT( region->surface_lock.buffer, CoreSurfaceBuffer ); + + dfb_surface_unlock_buffer( region->surface_lock.buffer->surface, ®ion->surface_lock ); + } + + if (dfb_surface_lock( surface )) + return DFB_FUSION; + + buffer = dfb_surface_get_buffer( surface, role ); + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + + /* Lock the surface buffer. */ + ret = dfb_surface_buffer_lock( buffer, CSAID_LAYER0 + context->layer_id, CSAF_READ, ®ion->surface_lock ); + if (ret) { + D_DERROR( ret, "Core/LayerRegion: Could not lock region surface for SetRegion()!\n" ); + dfb_surface_unlock( surface ); + return ret; + } + + allocation = region->surface_lock.allocation; + D_ASSERT( allocation != NULL ); + + /* If hardware has written or is writing... */ + if (allocation->accessed[CSAID_GPU] & CSAF_WRITE) { + D_DEBUG_AT( Core_Layers, " -> Waiting for pending writes...\n" ); + + /* ...wait for the operation to finish. */ + dfb_gfxcard_sync(); /* TODO: wait for serial instead */ + + allocation->accessed[CSAID_GPU] &= ~CSAF_WRITE; + } + + /* surface is unlocked by caller */ + + return DFB_OK; +} + +static DFBResult +set_region( CoreLayerRegion *region, + CoreLayerRegionConfig *config, + CoreLayerRegionConfigFlags flags, + CoreSurface *surface ) +{ + DFBResult ret; + CoreLayer *layer; + CoreLayerShared *shared; + const DisplayLayerFuncs *funcs; + + D_DEBUG_AT( Core_Layers, "%s( %p, %p, 0x%08x, %p )\n", __FUNCTION__, region, config, flags, surface ); + + DFB_CORE_LAYER_REGION_CONFIG_DEBUG_AT( Core_Layers, config ); + + D_DEBUG_AT( Core_Layers, " -> state 0x%08x\n", region->state ); + + D_ASSERT( region != NULL ); + D_ASSERT( region->context != NULL ); + D_ASSERT( config != NULL ); + D_ASSERT( config->buffermode != DLBM_WINDOWS ); + + D_ASSERT( D_FLAGS_IS_SET( region->state, CLRSF_REALIZED ) ); + + layer = dfb_layer_at( region->context->layer_id ); + + D_ASSERT( layer != NULL ); + D_ASSERT( layer->shared != NULL ); + D_ASSERT( layer->funcs != NULL ); + D_ASSERT( layer->funcs->SetRegion != NULL ); + + if (region->state & CLRSF_FROZEN) { + D_DEBUG_AT( Core_Layers, " -> FROZEN!\n" ); + return DFB_OK; + } + + shared = layer->shared; + funcs = layer->funcs; + + if (surface) { + if (flags & (CLRCF_SURFACE | CLRCF_WIDTH | CLRCF_HEIGHT | CLRCF_FORMAT)) { + ret = region_buffer_lock( region, surface, CSBR_FRONT ); + if (ret) + return ret; + + dfb_surface_unlock( surface ); + } + + D_ASSERT( region->surface_lock.buffer != NULL ); + } + else if (region->surface_lock.buffer) { + D_MAGIC_ASSERT( region->surface_lock.buffer, CoreSurfaceBuffer ); + + dfb_surface_unlock_buffer( region->surface_lock.buffer->surface, ®ion->surface_lock ); + } + + D_DEBUG_AT( Core_Layers, " => setting region of '%s'\n", shared->description.name ); + + /* Setup hardware. */ + return funcs->SetRegion( layer, layer->driver_data, layer->layer_data, + region->region_data, config, flags, + surface, surface ? surface->palette : NULL, ®ion->surface_lock ); +} + +static DFBResult +realize_region( CoreLayerRegion *region ) +{ + DFBResult ret; + CoreLayer *layer; + CoreLayerShared *shared; + const DisplayLayerFuncs *funcs; + + D_DEBUG_AT( Core_Layers, "%s( %p )\n", __FUNCTION__, region ); + + D_ASSERT( region != NULL ); + + DFB_CORE_LAYER_REGION_CONFIG_DEBUG_AT( Core_Layers, ®ion->config ); + + D_DEBUG_AT( Core_Layers, " -> state 0x%08x\n", region->state ); + + D_ASSERT( region->context != NULL ); + D_ASSERT( D_FLAGS_IS_SET( region->state, CLRSF_CONFIGURED ) ); + D_ASSERT( ! D_FLAGS_IS_SET( region->state, CLRSF_REALIZED ) ); + + layer = dfb_layer_at( region->context->layer_id ); + + D_ASSERT( layer != NULL ); + D_ASSERT( layer->shared != NULL ); + D_ASSERT( layer->funcs != NULL ); + + shared = layer->shared; + funcs = layer->funcs; + + D_ASSERT( ! fusion_vector_contains( &shared->added_regions, region ) ); + + if (region->state & CLRSF_FROZEN) { + D_DEBUG_AT( Core_Layers, " -> FROZEN!\n" ); + return DFB_OK; + } + + /* Allocate the driver's region data. */ + if (funcs->RegionDataSize) { + int size = funcs->RegionDataSize(); + + if (size > 0) { + region->region_data = SHCALLOC( shared->shmpool, 1, size ); + if (!region->region_data) + return D_OOSHM(); + } + } + + D_DEBUG_AT( Core_Layers, " => adding region to '%s'\n", shared->description.name ); + + /* Add the region to the driver. */ + if (funcs->AddRegion) { + ret = funcs->AddRegion( layer, + layer->driver_data, layer->layer_data, + region->region_data, ®ion->config ); + if (ret) { + D_DERROR( ret, "Core/Layers: Could not add region!\n" ); + + if (region->region_data) { + SHFREE( shared->shmpool, region->region_data ); + region->region_data = NULL; + } + + return ret; + } + } + + /* Add the region to the 'added' list. */ + fusion_vector_add( &shared->added_regions, region ); + + /* Update the region's state. */ + D_FLAGS_SET( region->state, CLRSF_REALIZED ); + + /* Initially setup hardware. */ + ret = set_region( region, ®ion->config, CLRCF_ALL, region->surface ); + if (ret) { + unrealize_region( region ); + return ret; + } + + return DFB_OK; +} + +static DFBResult +unrealize_region( CoreLayerRegion *region ) +{ + DFBResult ret; + int index; + CoreLayer *layer; + CoreLayerShared *shared; + const DisplayLayerFuncs *funcs; + + D_DEBUG_AT( Core_Layers, "%s( %p )\n", __FUNCTION__, region ); + + D_ASSERT( region != NULL ); + + DFB_CORE_LAYER_REGION_CONFIG_DEBUG_AT( Core_Layers, ®ion->config ); + + D_DEBUG_AT( Core_Layers, " -> state 0x%08x\n", region->state ); + + D_ASSERT( region->context != NULL ); + D_ASSERT( D_FLAGS_IS_SET( region->state, CLRSF_REALIZED ) ); + + layer = dfb_layer_at( region->context->layer_id ); + + D_ASSERT( layer != NULL ); + D_ASSERT( layer->shared != NULL ); + D_ASSERT( layer->funcs != NULL ); + + shared = layer->shared; + funcs = layer->funcs; + + D_ASSERT( fusion_vector_contains( &shared->added_regions, region ) ); + + index = fusion_vector_index_of( &shared->added_regions, region ); + + D_DEBUG_AT( Core_Layers, " => removing region from '%s'\n", shared->description.name ); + + /* Remove the region from hardware and driver. */ + if (funcs->RemoveRegion) { + ret = funcs->RemoveRegion( layer, layer->driver_data, + layer->layer_data, region->region_data ); + if (ret) { + D_DERROR( ret, "Core/Layers: Could not remove region!\n" ); + return ret; + } + } + + /* Remove the region from the 'added' list. */ + fusion_vector_remove( &shared->added_regions, index ); + + /* Deallocate the driver's region data. */ + if (region->region_data) { + SHFREE( shared->shmpool, region->region_data ); + region->region_data = NULL; + } + + /* Update the region's state. */ + D_FLAGS_CLEAR( region->state, CLRSF_REALIZED ); + D_FLAGS_SET( region->state, CLRSF_FROZEN ); + + if (region->surface && region->surface_lock.buffer) { + dfb_surface_unlock_buffer( region->surface, ®ion->surface_lock ); + // PR brg36mgr#147044: [550r3cr1][CRASH][UI]set crashes when going through settings assistant + // This is because the YUV layer buffer is allocated in memory recuperated from the video flow + // and is only valid in the JPEG usecase. + // When the application destroys its window (on leaving the usecase),the layer buffer must + // also be removed. + dfb_surface_destroy_buffers( region->surface ); + } + + return DFB_OK; +} + diff --git a/Source/DirectFB/src/core/layer_region.h b/Source/DirectFB/src/core/layer_region.h new file mode 100755 index 0000000..29221a9 --- /dev/null +++ b/Source/DirectFB/src/core/layer_region.h @@ -0,0 +1,100 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef __CORE__LAYER_REGION_H__ +#define __CORE__LAYER_REGION_H__ + +#include + +#include +#include + +#include + + +typedef enum { + CLRNF_NONE = 0x00000000 +} CoreLayerRegionNotificationFlags; + +typedef struct { + CoreLayerRegionNotificationFlags flags; + CoreLayerRegion *region; +} CoreLayerRegionNotification; + +/* + * Creates a pool of layer region objects. + */ +FusionObjectPool *dfb_layer_region_pool_create( const FusionWorld *world ); + +/* + * Generates dfb_layer_region_ref(), dfb_layer_region_attach() etc. + */ +FUSION_OBJECT_METHODS( CoreLayerRegion, dfb_layer_region ) + + +DFBResult dfb_layer_region_create ( CoreLayerContext *context, + CoreLayerRegion **ret_region ); + +DFBResult dfb_layer_region_activate ( CoreLayerRegion *region ); + +DFBResult dfb_layer_region_deactivate ( CoreLayerRegion *region ); + +DFBResult dfb_layer_region_enable ( CoreLayerRegion *region ); + +DFBResult dfb_layer_region_disable ( CoreLayerRegion *region ); + +DFBResult dfb_layer_region_set_surface ( CoreLayerRegion *region, + CoreSurface *surface ); + +DFBResult dfb_layer_region_get_surface ( CoreLayerRegion *region, + CoreSurface **ret_surface ); + +DFBResult dfb_layer_region_flip_update ( CoreLayerRegion *region, + const DFBRegion *update, + DFBSurfaceFlipFlags flags ); + + +/* + * Configuration + */ +DFBResult dfb_layer_region_set_configuration( CoreLayerRegion *region, + CoreLayerRegionConfig *config, + CoreLayerRegionConfigFlags flags ); + +DFBResult dfb_layer_region_get_configuration( CoreLayerRegion *region, + CoreLayerRegionConfig *config ); + + +/* + * Locking + */ +DirectResult dfb_layer_region_lock ( CoreLayerRegion *region ); +DirectResult dfb_layer_region_unlock( CoreLayerRegion *region ); + +#endif + diff --git a/Source/DirectFB/src/core/layers.c b/Source/DirectFB/src/core/layers.c new file mode 100755 index 0000000..29c0de8 --- /dev/null +++ b/Source/DirectFB/src/core/layers.c @@ -0,0 +1,640 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + + +D_DEBUG_DOMAIN( Core_Layer, "Core/Layer", "DirectFB Display Layer Core" ); + +/**********************************************************************************************************************/ + +typedef struct { + int magic; + + int num; + CoreLayerShared *layers[MAX_LAYERS]; +} DFBLayerCoreShared; + +struct __DFB_DFBLayerCore { + int magic; + + CoreDFB *core; + + DFBLayerCoreShared *shared; +}; + + +DFB_CORE_PART( layer_core, LayerCore ); + +/**********************************************************************************************************************/ + +static int dfb_num_layers; +static CoreLayer *dfb_layers[MAX_LAYERS]; + +/** FIXME: Add proper error paths! **/ + +static DFBResult +dfb_layer_core_initialize( CoreDFB *core, + DFBLayerCore *data, + DFBLayerCoreShared *shared ) +{ + int i; + DFBResult ret; + FusionSHMPoolShared *pool; + + D_DEBUG_AT( Core_Layer, "dfb_layer_core_initialize( %p, %p, %p )\n", core, data, shared ); + + D_ASSERT( data != NULL ); + D_ASSERT( shared != NULL ); + + data->core = core; + data->shared = shared; + + + pool = dfb_core_shmpool( core ); + + /* Initialize all registered layers. */ + for (i=0; ifuncs; + + /* Allocate shared data. */ + lshared = SHCALLOC( pool, 1, sizeof(CoreLayerShared) ); + + /* Assign ID (zero based index). */ + lshared->layer_id = i; + lshared->shmpool = pool; + + snprintf( buf, sizeof(buf), "Display Layer %d", i ); + + /* Initialize the lock. */ + ret = fusion_skirmish_init( &lshared->lock, buf, dfb_core_world(core) ); + if (ret) + return ret; + + /* Allocate driver's layer data. */ + if (funcs->LayerDataSize) { + int size = funcs->LayerDataSize(); + + if (size > 0) { + lshared->layer_data = SHCALLOC( pool, 1, size ); + if (!lshared->layer_data) + return D_OOSHM(); + } + } + + /* Initialize the layer, get the layer description, + the default configuration and default color adjustment. */ + ret = funcs->InitLayer( layer, + layer->driver_data, + lshared->layer_data, + &lshared->description, + &lshared->default_config, + &lshared->default_adjustment ); + if (ret) { + D_DERROR( ret, "DirectFB/Core/layers: " + "Failed to initialize layer %d!\n", lshared->layer_id ); + return ret; + } + + if (lshared->description.caps & DLCAPS_SOURCES) { + int n; + + lshared->sources = SHCALLOC( pool, lshared->description.sources, sizeof(CoreLayerSource) ); + if (!lshared->sources) + return D_OOSHM(); + + for (n=0; ndescription.sources; n++) { + CoreLayerSource *source = &lshared->sources[n]; + + source->index = n; + + ret = funcs->InitSource( layer, layer->driver_data, + lshared->layer_data, n, &source->description ); + if (ret) { + D_DERROR( ret, "DirectFB/Core/layers: Failed to initialize source %d " + "of layer %d!\n", n, lshared->layer_id ); + return ret; + } + } + } + + if (D_FLAGS_IS_SET( lshared->description.caps, DLCAPS_SCREEN_LOCATION )) + D_FLAGS_SET( lshared->description.caps, DLCAPS_SCREEN_POSITION | DLCAPS_SCREEN_SIZE ); + + if (D_FLAGS_ARE_SET( lshared->description.caps, + DLCAPS_SCREEN_POSITION | DLCAPS_SCREEN_SIZE )) + D_FLAGS_SET( lshared->description.caps, DLCAPS_SCREEN_LOCATION ); + + /* Initialize the vector for the contexts. */ + fusion_vector_init( &lshared->contexts.stack, 4, pool ); + + /* Initialize the vector for realized (added) regions. */ + fusion_vector_init( &lshared->added_regions, 4, pool ); + + /* No active context by default. */ + lshared->contexts.active = -1; + + /* Store layer data. */ + layer->layer_data = lshared->layer_data; + + /* Store pointer to shared data and core. */ + layer->shared = lshared; + layer->core = core; + + /* Add the layer to the shared list. */ + shared->layers[ shared->num++ ] = lshared; + } + + + D_MAGIC_SET( data, DFBLayerCore ); + D_MAGIC_SET( shared, DFBLayerCoreShared ); + + return DFB_OK; +} + +static DFBResult +dfb_layer_core_join( CoreDFB *core, + DFBLayerCore *data, + DFBLayerCoreShared *shared ) +{ + int i; + + D_DEBUG_AT( Core_Layer, "dfb_layer_core_join( %p, %p, %p )\n", core, data, shared ); + + D_ASSERT( data != NULL ); + D_MAGIC_ASSERT( shared, DFBLayerCoreShared ); + + data->core = core; + data->shared = shared; + + + if (dfb_num_layers != shared->num) { + D_ERROR("DirectFB/core/layers: Number of layers does not match!\n"); + return DFB_BUG; + } + + for (i=0; ilayers[i]; + + /* make a copy for faster access */ + layer->layer_data = lshared->layer_data; + + /* store pointer to shared data and core */ + layer->shared = lshared; + layer->core = core; + } + + + D_MAGIC_SET( data, DFBLayerCore ); + + return DFB_OK; +} + +static DFBResult +dfb_layer_core_shutdown( DFBLayerCore *data, + bool emergency ) +{ + int i; + DFBResult ret; + DFBLayerCoreShared *shared; + + D_DEBUG_AT( Core_Layer, "dfb_layer_core_shutdown( %p, %semergency )\n", data, emergency ? "" : "no " ); + + D_MAGIC_ASSERT( data, DFBLayerCore ); + D_MAGIC_ASSERT( data->shared, DFBLayerCoreShared ); + + shared = data->shared; + + + /* Begin with the most recently added layer. */ + for (i=dfb_num_layers-1; i>=0; i--) { + CoreLayer *layer = dfb_layers[i]; + CoreLayerShared *shared = layer->shared; + const DisplayLayerFuncs *funcs = layer->funcs; + + D_ASSUME( emergency || fusion_vector_is_empty( &shared->added_regions ) ); + + /* Remove all regions during emergency shutdown. */ + if (emergency && funcs->RemoveRegion) { + int n; + CoreLayerRegion *region; + + fusion_vector_foreach( region, n, shared->added_regions ) { + D_DEBUG_AT( Core_Layer, "Removing region (%d, %d - %dx%d) from '%s'.\n", + DFB_RECTANGLE_VALS( ®ion->config.dest ), + shared->description.name ); + + ret = funcs->RemoveRegion( layer, layer->driver_data, + layer->layer_data, region->region_data ); + if (ret) + D_DERROR( ret, "Core/Layers: Could not remove region!\n" ); + } + } + + /* Deinitialize the lock. */ + fusion_skirmish_destroy( &shared->lock ); + + /* Deinitialize the state for window stack repaints. */ + dfb_state_destroy( &layer->state ); + + /* Deinitialize the vector for the contexts. */ + fusion_vector_destroy( &shared->contexts.stack ); + + /* Deinitialize the vector for the realized (added) regions. */ + fusion_vector_destroy( &shared->added_regions ); + + /* Free the driver's layer data. */ + if (shared->layer_data) + SHFREE( shared->shmpool, shared->layer_data ); + + /* Free the shared layer data. */ + SHFREE( shared->shmpool, shared ); + + /* Free the local layer data. */ + D_FREE( layer ); + } + + dfb_num_layers = 0; + + + D_MAGIC_CLEAR( data ); + D_MAGIC_CLEAR( shared ); + + return DFB_OK; +} + +static DFBResult +dfb_layer_core_leave( DFBLayerCore *data, + bool emergency ) +{ + int i; + DFBLayerCoreShared *shared; + + D_DEBUG_AT( Core_Layer, "dfb_layer_core_leave( %p, %semergency )\n", data, emergency ? "" : "no " ); + + D_MAGIC_ASSERT( data, DFBLayerCore ); + D_MAGIC_ASSERT( data->shared, DFBLayerCoreShared ); + + shared = data->shared; + + + /* Deinitialize all local stuff. */ + for (i=0; istate ); + + /* Free local layer data. */ + D_FREE( layer ); + } + + dfb_num_layers = 0; + + + D_MAGIC_CLEAR( data ); + + return DFB_OK; +} + +static DFBResult +dfb_layer_core_suspend( DFBLayerCore *data ) +{ + int i; + DFBLayerCoreShared *shared; + + D_DEBUG_AT( Core_Layer, "dfb_layer_core_suspend( %p )\n", data ); + + D_MAGIC_ASSERT( data, DFBLayerCore ); + D_MAGIC_ASSERT( data->shared, DFBLayerCoreShared ); + + shared = data->shared; + + for (i=dfb_num_layers-1; i>=0; i--) + dfb_layer_suspend( dfb_layers[i] ); + + return DFB_OK; +} + +static DFBResult +dfb_layer_core_resume( DFBLayerCore *data ) +{ + int i; + DFBLayerCoreShared *shared; + + D_DEBUG_AT( Core_Layer, "dfb_layer_core_resume( %p )\n", data ); + + D_MAGIC_ASSERT( data, DFBLayerCore ); + D_MAGIC_ASSERT( data->shared, DFBLayerCoreShared ); + + shared = data->shared; + + for (i=0; idevice = screen->device; + layer->screen = screen; + layer->driver_data = driver_data; + layer->funcs = funcs; + + /* Initialize the state for window stack repaints */ + dfb_state_init( &layer->state, NULL ); + + /* add it to the local list */ + dfb_layers[dfb_num_layers++] = layer; + + return layer; +} + +typedef void (*AnyFunc)( void ); + +CoreLayer * +dfb_layers_hook_primary( CoreGraphicsDevice *device, + void *driver_data, + DisplayLayerFuncs *funcs, + DisplayLayerFuncs *primary_funcs, + void **primary_driver_data ) +{ + int i; + int entries; + CoreLayer *primary = dfb_layers[0]; + + D_ASSERT( primary != NULL ); + D_ASSERT( device != NULL ); + D_ASSERT( funcs != NULL ); + + /* copy content of original function table */ + if (primary_funcs) + direct_memcpy( primary_funcs, primary->funcs, sizeof(DisplayLayerFuncs) ); + + /* copy pointer to original driver data */ + if (primary_driver_data) + *primary_driver_data = primary->driver_data; + + /* replace all entries in the old table that aren't NULL in the new one */ + entries = sizeof(DisplayLayerFuncs) / sizeof(void(*)( void )); + for (i=0; ifuncs; + + if (newfuncs[i]) + oldfuncs[i] = newfuncs[i]; + } + + /* replace device and driver data pointer */ + primary->device = device; + primary->driver_data = driver_data; + + return primary; +} + +CoreLayer * +dfb_layers_replace_primary( CoreGraphicsDevice *device, + void *driver_data, + DisplayLayerFuncs *funcs ) +{ + CoreLayer *primary = dfb_layers[0]; + + D_ASSERT( primary != NULL ); + D_ASSERT( device != NULL ); + D_ASSERT( funcs != NULL ); + + /* replace device, function table and driver data pointer */ + primary->device = device; + primary->funcs = funcs; + primary->driver_data = driver_data; + + return primary; +} + +void +dfb_layers_enumerate( DisplayLayerCallback callback, + void *ctx ) +{ + int i; + + D_ASSERT( callback != NULL ); + + for (i=0; i= 0); + D_ASSERT( id < dfb_num_layers); + + return dfb_layers[id]; +} + +CoreLayer * +dfb_layer_at_translated( DFBDisplayLayerID id ) +{ + D_ASSERT( id >= 0); + D_ASSERT( id < dfb_num_layers); + D_ASSERT( dfb_config != NULL ); + + if (dfb_config->primary_layer > 0 && + dfb_config->primary_layer < dfb_num_layers) + { + if (id == DLID_PRIMARY) + return dfb_layer_at( dfb_config->primary_layer ); + + if (id == dfb_config->primary_layer) + return dfb_layer_at( DLID_PRIMARY ); + } + + return dfb_layer_at( id ); +} + +void +dfb_layer_get_description( const CoreLayer *layer, + DFBDisplayLayerDescription *desc ) +{ + D_ASSERT( layer != NULL ); + D_ASSERT( layer->shared != NULL ); + D_ASSERT( desc != NULL ); + + *desc = layer->shared->description; +} + +CoreScreen * +dfb_layer_screen( const CoreLayer *layer ) +{ + D_ASSERT( layer != NULL ); + + return layer->screen; +} + +CardState * +dfb_layer_state( CoreLayer *layer ) +{ + D_ASSERT( layer != NULL ); + + return &layer->state; +} + +DFBDisplayLayerID +dfb_layer_id( const CoreLayer *layer ) +{ + D_ASSERT( layer != NULL ); + D_ASSERT( layer->shared != NULL ); + + return layer->shared->layer_id; +} + +DFBDisplayLayerID +dfb_layer_id_translated( const CoreLayer *layer ) +{ + CoreLayerShared *shared; + + D_ASSERT( layer != NULL ); + D_ASSERT( layer->shared != NULL ); + D_ASSERT( dfb_config != NULL ); + + shared = layer->shared; + + if (dfb_config->primary_layer > 0 && + dfb_config->primary_layer < dfb_num_layers) + { + if (shared->layer_id == DLID_PRIMARY) + return dfb_config->primary_layer; + + if (shared->layer_id == dfb_config->primary_layer) + return DLID_PRIMARY; + } + + return shared->layer_id; +} + +DFBSurfacePixelFormat +dfb_primary_layer_pixelformat( void ) +{ + CoreLayerShared *shared; + CoreLayerContext *context; + CoreLayer *layer = dfb_layer_at_translated(DLID_PRIMARY); + DFBSurfacePixelFormat format = DSPF_UNKNOWN; + + D_ASSERT( layer != NULL ); + D_ASSERT( layer->shared != NULL ); + + shared = layer->shared; + + /* If no context is active, return the default format. */ + if (dfb_layer_get_active_context( layer, &context ) != DFB_OK) + return shared->default_config.pixelformat; + + /* Use the format from the current configuration. */ + format = context->config.pixelformat; + + /* Decrease the context's reference counter. */ + dfb_layer_context_unref( context ); + + return format; +} + diff --git a/Source/DirectFB/src/core/layers.h b/Source/DirectFB/src/core/layers.h new file mode 100755 index 0000000..68a1d9e --- /dev/null +++ b/Source/DirectFB/src/core/layers.h @@ -0,0 +1,359 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef __CORE__LAYERS_H__ +#define __CORE__LAYERS_H__ + +#include + +#include + +#include +#include + + +struct __DFB_CoreLayerRegionConfig { + int width; /* width of the source in pixels */ + int height; /* height of the source in pixels */ + DFBSurfacePixelFormat format; /* pixel format of the source surface */ + DFBSurfaceCapabilities surface_caps; /* capabilities of the source surface */ + DFBDisplayLayerBufferMode buffermode; /* surface buffer configuration */ + + DFBDisplayLayerOptions options; /* various configuration options */ + + DFBDisplayLayerSourceID source_id; /* selected source */ + + DFBRectangle source; /* viewport within source (input) */ + DFBRectangle dest; /* viewport on screen (output) */ + + u8 opacity; /* global region alpha */ + + DFBColorKey src_key; /* source color key */ + DFBColorKey dst_key; /* destination color key */ + + int parity; /* field parity (for interlaced) */ + + u8 alpha_ramp[4]; /* alpha values for 1 or 2 bit lookup */ + + DFBRegion *clips; /* clip regions */ + int num_clips; /* number of clip regions */ + DFBBoolean positive; /* show or cut out regions */ +}; + +#if D_DEBUG_ENABLED +#define DFB_CORE_LAYER_REGION_CONFIG_DEBUG_AT( domain, config ) \ + do { \ + const CoreLayerRegionConfig *_config = config; \ + \ + D_DEBUG_AT( domain, " -> size %dx%d\n", _config->width, _config->height ); \ + D_DEBUG_AT( domain, " -> format %s\n", dfb_pixelformat_name( _config->format ) ); \ + D_DEBUG_AT( domain, " -> surf caps 0x%08x\n", _config->surface_caps ); \ + D_DEBUG_AT( domain, " -> buffermode %d\n", _config->buffermode ); \ + D_DEBUG_AT( domain, " -> options 0x%08x\n", _config->options ); \ + D_DEBUG_AT( domain, " -> source %d,%d-%dx%d\n", DFB_RECTANGLE_VALS(&_config->source) ); \ + D_DEBUG_AT( domain, " -> dest %d,%d-%dx%d\n", DFB_RECTANGLE_VALS(&_config->dest) ); \ + D_DEBUG_AT( domain, " -> opacity %d\n", _config->opacity ); \ + D_DEBUG_AT( domain, " -> src_key %02x%02x%02x (index %d)\n", DFB_COLORKEY_VALS(&_config->src_key) ); \ + D_DEBUG_AT( domain, " -> dst_key %02x%02x%02x (index %d)\n", DFB_COLORKEY_VALS(&_config->dst_key) ); \ + } while (0) +#else +#define DFB_CORE_LAYER_REGION_CONFIG_DEBUG_AT( domain, config ) \ + do { \ + } while (0) +#endif + +typedef enum { + CLRCF_NONE = 0x00000000, + + CLRCF_WIDTH = 0x00000001, + CLRCF_HEIGHT = 0x00000002, + CLRCF_FORMAT = 0x00000004, + CLRCF_SURFACE_CAPS = 0x00000008, + + CLRCF_BUFFERMODE = 0x00000010, + CLRCF_OPTIONS = 0x00000020, + CLRCF_SOURCE_ID = 0x00000040, + + CLRCF_SOURCE = 0x00000100, + CLRCF_DEST = 0x00000200, + CLRCF_CLIPS = 0x00000400, + + CLRCF_OPACITY = 0x00001000, + CLRCF_ALPHA_RAMP = 0x00002000, + + CLRCF_SRCKEY = 0x00010000, + CLRCF_DSTKEY = 0x00020000, + + CLRCF_PARITY = 0x00100000, + + CLRCF_SURFACE = 0x10000000, + CLRCF_PALETTE = 0x20000000, + + CLRCF_FREEZE = 0x80000000, + + CLRCF_ALL = 0xB013377F +} CoreLayerRegionConfigFlags; + +typedef struct { + /** Driver Control **/ + + /* + * Return size of layer data (shared memory). + */ + int (*LayerDataSize) ( void ); + + /* + * Return size of region data (shared memory). + */ + int (*RegionDataSize)( void ); + + /* + * Called once by the master to initialize layer data and reset hardware. + * Return layer description, default configuration and color adjustment. + */ + DFBResult (*InitLayer) ( CoreLayer *layer, + void *driver_data, + void *layer_data, + DFBDisplayLayerDescription *description, + DFBDisplayLayerConfig *config, + DFBColorAdjustment *adjustment ); + + /* + * Called once by the master for each source. + * Driver fills description. + */ + DFBResult (*InitSource) ( CoreLayer *layer, + void *driver_data, + void *layer_data, + int source, + DFBDisplayLayerSourceDescription *description ); + + + /** Layer Control **/ + + /* + * Return the currently displayed field (interlaced only). + */ + DFBResult (*GetCurrentOutputField)( CoreLayer *layer, + void *driver_data, + void *layer_data, + int *field ); + + /* + * Return the z position of the layer. + */ + DFBResult (*GetLevel) ( CoreLayer *layer, + void *driver_data, + void *layer_data, + int *level ); + + /* + * Move the layer below or on top of others (z position). + */ + DFBResult (*SetLevel) ( CoreLayer *layer, + void *driver_data, + void *layer_data, + int level ); + + + /** Configuration **/ + + /* + * Adjust brightness, contrast, saturation etc. + */ + DFBResult (*SetColorAdjustment) ( CoreLayer *layer, + void *driver_data, + void *layer_data, + DFBColorAdjustment *adjustment ); + + + /** Region Control **/ + + /* + * Check all parameters and return if this region is supported. + */ + DFBResult (*TestRegion) ( CoreLayer *layer, + void *driver_data, + void *layer_data, + CoreLayerRegionConfig *config, + CoreLayerRegionConfigFlags *failed ); + + /* + * Add a new region to the layer, but don't program hardware, yet. + */ + DFBResult (*AddRegion) ( CoreLayer *layer, + void *driver_data, + void *layer_data, + void *region_data, + CoreLayerRegionConfig *config ); + + /* + * Setup hardware, called once after AddRegion() or when parameters + * have changed. Surface and palette are only set if updated or new. + */ + DFBResult (*SetRegion) ( CoreLayer *layer, + void *driver_data, + void *layer_data, + void *region_data, + CoreLayerRegionConfig *config, + CoreLayerRegionConfigFlags updated, + CoreSurface *surface, + CorePalette *palette, + CoreSurfaceBufferLock *lock ); + + /* + * Remove a region from the layer. + */ + DFBResult (*RemoveRegion) ( CoreLayer *layer, + void *driver_data, + void *layer_data, + void *region_data ); + + /* + * Flip the surface of the region. + */ + DFBResult (*FlipRegion) ( CoreLayer *layer, + void *driver_data, + void *layer_data, + void *region_data, + CoreSurface *surface, + DFBSurfaceFlipFlags flags, + CoreSurfaceBufferLock *lock ); + + /* + * Indicate updates to the front buffer content. + */ + DFBResult (*UpdateRegion) ( CoreLayer *layer, + void *driver_data, + void *layer_data, + void *region_data, + CoreSurface *surface, + const DFBRegion *update, + CoreSurfaceBufferLock *lock ); + + /* + * Control hardware deinterlacing. + */ + DFBResult (*SetInputField)( CoreLayer *layer, + void *driver_data, + void *layer_data, + void *region_data, + int field ); + + + /** Override defaults. Subject to change. **/ + + /* + * Allocate the surface of the region. + */ + DFBResult (*AllocateSurface) ( CoreLayer *layer, + void *driver_data, + void *layer_data, + void *region_data, + CoreLayerRegionConfig *config, + CoreSurface **ret_surface ); + + /* + * Reallocate the surface of the region. + */ + DFBResult (*ReallocateSurface)( CoreLayer *layer, + void *driver_data, + void *layer_data, + void *region_data, + CoreLayerRegionConfig *config, + CoreSurface *surface ); + + /* + * Deallocate the surface of the region. + */ + DFBResult (*DeallocateSurface)( CoreLayer *layer, + void *driver_data, + void *layer_data, + void *region_data, + CoreSurface *surface ); +} DisplayLayerFuncs; + + +/* + * Add a layer to a graphics device by pointing to a table + * containing driver functions. The supplied driver data + * will be passed to these functions. + */ +CoreLayer *dfb_layers_register( CoreScreen *screen, + void *driver_data, + const DisplayLayerFuncs *funcs ); + +/* + * Replace functions of the primary layer implementation by passing + * an alternative driver function table. All non-NULL functions in the new + * table replace the functions in the original function table. + * The original function table is written to 'primary_funcs' before to allow + * drivers to use existing functionality from the original implementation. + */ +CoreLayer *dfb_layers_hook_primary( CoreGraphicsDevice *device, + void *driver_data, + DisplayLayerFuncs *funcs, + DisplayLayerFuncs *primary_funcs, + void **primary_driver_data ); + +/* + * Replace functions of the primary layer implementation completely by passing + * an alternative driver function table. + */ +CoreLayer *dfb_layers_replace_primary( CoreGraphicsDevice *device, + void *driver_data, + DisplayLayerFuncs *funcs ); + +typedef DFBEnumerationResult (*DisplayLayerCallback) (CoreLayer *layer, + void *ctx); + +void dfb_layers_enumerate( DisplayLayerCallback callback, + void *ctx ); + + +int dfb_layer_num( void ); + +CoreLayer *dfb_layer_at( DFBDisplayLayerID id ); + +CoreLayer *dfb_layer_at_translated( DFBDisplayLayerID id ); + + +void dfb_layer_get_description( const CoreLayer *layer, + DFBDisplayLayerDescription *desc ); + +CoreScreen *dfb_layer_screen( const CoreLayer *layer ); + +CardState *dfb_layer_state( CoreLayer *layer ); + +DFBDisplayLayerID dfb_layer_id( const CoreLayer *layer ); + +DFBDisplayLayerID dfb_layer_id_translated( const CoreLayer *layer ); + +DFBSurfacePixelFormat dfb_primary_layer_pixelformat( void ); + +#endif diff --git a/Source/DirectFB/src/core/layers_internal.h b/Source/DirectFB/src/core/layers_internal.h new file mode 100755 index 0000000..c546a33 --- /dev/null +++ b/Source/DirectFB/src/core/layers_internal.h @@ -0,0 +1,196 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef __CORE__LAYERS_INTERNAL_H__ +#define __CORE__LAYERS_INTERNAL_H__ + +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + +typedef struct { + FusionVector stack; + int active; + + CoreLayerContext *primary; +} CoreLayerContexts; + +typedef struct { + int index; + DFBDisplayLayerSourceDescription description; +} CoreLayerSource; + +typedef struct { + DFBDisplayLayerID layer_id; + + DFBDisplayLayerDescription description; + DFBDisplayLayerConfig default_config; + DFBColorAdjustment default_adjustment; + + CoreLayerSource *sources; + + void *layer_data; + + FusionSkirmish lock; + + CoreLayerContexts contexts; + + bool suspended; + + FusionVector added_regions; + + FusionSHMPoolShared *shmpool; +} CoreLayerShared; + +struct __DFB_CoreLayer { + CoreLayerShared *shared; + + CoreDFB *core; + + CoreGraphicsDevice *device; + + CoreScreen *screen; + + void *driver_data; + void *layer_data; /* copy of shared->layer_data */ + + const DisplayLayerFuncs *funcs; + + CardState state; +}; + +typedef enum { + CLLM_LOCATION, /* Keep normalized area. */ + CLLM_CENTER, /* Center layer after resizing destination area. */ + CLLM_POSITION, /* Keep pixel position, but resize area. */ + CLLM_RECTANGLE /* Keep pixel based area. */ +} CoreLayerLayoutMode; + +struct __DFB_CoreLayerContext { + FusionObject object; + + int magic; + + DFBDisplayLayerID layer_id; + + FusionSkirmish lock; + + bool active; /* Is this the active context? */ + + DFBDisplayLayerConfig config; /* Current layer configuration. */ + int rotation; + + FusionVector regions; /* All regions created within + this context. */ + + struct { + CoreLayerRegion *region; /* Region of layer config if buffer + mode is not DLBM_WINDOWS. */ + CoreLayerRegionConfig config; /* Region config used to implement + layer config and settings. */ + } primary; + + struct { + DFBLocation location; /* Normalized screen location. */ + DFBRectangle rectangle; /* Pixel based position and size. */ + + CoreLayerLayoutMode mode; /* ...and how resizing influences them. */ + } screen; + + DFBColorAdjustment adjustment; /* Color adjustment of the layer.*/ + + CoreWindowStack *stack; /* Every layer has its own + windowstack as every layer has + its own pixel buffer. */ + + FusionSHMPoolShared *shmpool; +}; + +typedef enum { + CLRSF_NONE = 0x00000000, + + CLRSF_CONFIGURED = 0x00000001, + CLRSF_ENABLED = 0x00000002, + CLRSF_ACTIVE = 0x00000004, + CLRSF_REALIZED = 0x00000008, + + CLRSF_FROZEN = 0x00000010, + + CLRSF_ALL = 0x0000001F +} CoreLayerRegionStateFlags; + +struct __DFB_CoreLayerRegion { + FusionObject object; + + CoreLayerContext *context; + + FusionSkirmish lock; + + CoreLayerRegionStateFlags state; + + CoreLayerRegionConfig config; + + CoreSurface *surface; + CoreSurfaceBufferLock surface_lock; + GlobalReaction surface_reaction; + + void *region_data; +}; + + +/* Called at the end of dfb_layer_region_create(). */ +DFBResult dfb_layer_context_add_region( CoreLayerContext *context, + CoreLayerRegion *region ); + +/* Called early in the region_destructor(). */ +DFBResult dfb_layer_context_remove_region( CoreLayerContext *context, + CoreLayerRegion *region ); + +/* Called by dfb_layer_activate_context(), + dfb_layer_remove_context() and dfb_layer_resume(). */ +DFBResult dfb_layer_context_activate ( CoreLayerContext *context ); + +/* Called by dfb_layer_deactivate_context(), + dfb_layer_remove_context() and dfb_layer_suspend(). */ +DFBResult dfb_layer_context_deactivate( CoreLayerContext *context ); + +/* global reactions */ +ReactionResult _dfb_layer_region_surface_listener( const void *msg_data, + void *ctx ); + +#endif + diff --git a/Source/DirectFB/src/core/local_surface_pool.c b/Source/DirectFB/src/core/local_surface_pool.c new file mode 100755 index 0000000..8da06de --- /dev/null +++ b/Source/DirectFB/src/core/local_surface_pool.c @@ -0,0 +1,313 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include + +#include +#include + +#include + +#include +#include + + +/**********************************************************************************************************************/ + +typedef struct { +} LocalPoolData; + +typedef struct { + FusionCall call; +} LocalPoolLocalData; + +typedef struct { + int magic; + + void *addr; + int pitch; + int size; + + FusionCall call; + FusionID fid; +} LocalAllocationData; + +/**********************************************************************************************************************/ + +static FusionCallHandlerResult +local_surface_pool_call_handler( int caller, + int call_arg, + void *call_ptr, + void *ctx, + unsigned int serial, + int *ret_val ) +{ + D_FREE( call_ptr ); + + *ret_val = 0; + + return FCHR_RETURN; +} + +/**********************************************************************************************************************/ + +static int +localPoolDataSize( void ) +{ + return sizeof(LocalPoolData); +} + +static int +localPoolLocalDataSize( void ) +{ + return sizeof(LocalPoolLocalData); +} + +static int +localAllocationDataSize( void ) +{ + return sizeof(LocalAllocationData); +} + +static DFBResult +localInitPool( CoreDFB *core, + CoreSurfacePool *pool, + void *pool_data, + void *pool_local, + void *system_data, + CoreSurfacePoolDescription *ret_desc ) +{ + LocalPoolLocalData *local = pool_local; + + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + D_ASSERT( pool_local != NULL ); + D_ASSERT( ret_desc != NULL ); + + ret_desc->caps = CSPCAPS_NONE; + ret_desc->access[CSAID_CPU] = CSAF_READ | CSAF_WRITE; + ret_desc->types = CSTF_FONT | CSTF_INTERNAL; + ret_desc->priority = CSPP_PREFERED; + + snprintf( ret_desc->name, DFB_SURFACE_POOL_DESC_NAME_LENGTH, "System Memory" ); + + fusion_call_init( &local->call, local_surface_pool_call_handler, local, dfb_core_world(core) ); + + return DFB_OK; +} + +static DFBResult +localJoinPool( CoreDFB *core, + CoreSurfacePool *pool, + void *pool_data, + void *pool_local, + void *system_data ) +{ + LocalPoolLocalData *local = pool_local; + + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + D_ASSERT( pool_local != NULL ); + + return fusion_call_init( &local->call, local_surface_pool_call_handler, local, dfb_core_world(core) ); +} + +static DFBResult +localDestroyPool( CoreSurfacePool *pool, + void *pool_data, + void *pool_local ) +{ + CoreSurfaceAllocation *allocation; + LocalPoolLocalData *local = pool_local; + LocalAllocationData *data; + FusionID fid; + + DFBResult res; + int i; + + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + D_ASSERT( pool_local != NULL ); + + res = fusion_call_destroy( &local->call ); + fid = fusion_id( dfb_core_world(NULL) ); + + /* remove the local allocations */ + fusion_vector_foreach (allocation, i, pool->allocs) { + data = allocation->data; + if( data->fid == fid ) + D_FREE( data->addr ); + } + + return res; +} + +static DFBResult +localLeavePool( CoreSurfacePool *pool, + void *pool_data, + void *pool_local ) +{ + CoreSurfaceAllocation *allocation; + LocalPoolLocalData *local = pool_local; + LocalAllocationData *data; + FusionID fid; + + DFBResult res; + int i; + + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + D_ASSERT( pool_local != NULL ); + + res = fusion_call_destroy( &local->call ); + fid = fusion_id( dfb_core_world(NULL) ); + + /* remove the local allocations */ + fusion_vector_foreach (allocation, i, pool->allocs) { + data = allocation->data; + if( data->fid == fid ) + D_FREE( data->addr ); + } + + return res; +} + +static DFBResult +localAllocateBuffer( CoreSurfacePool *pool, + void *pool_data, + void *pool_local, + CoreSurfaceBuffer *buffer, + CoreSurfaceAllocation *allocation, + void *alloc_data ) +{ + CoreSurface *surface; + LocalPoolLocalData *local = pool_local; + LocalAllocationData *alloc = alloc_data; + + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + D_ASSERT( alloc != NULL ); + + surface = buffer->surface; + D_MAGIC_ASSERT( surface, CoreSurface ); + + dfb_surface_calc_buffer_size( surface, 8, 0, &alloc->pitch, &alloc->size ); + + alloc->addr = D_MALLOC( alloc->size ); + if (!alloc->addr) + return D_OOM(); + + alloc->call = local->call; + alloc->fid = fusion_id( dfb_core_world(NULL) ); + + D_MAGIC_SET( alloc, LocalAllocationData ); + + allocation->flags = CSALF_VOLATILE; + allocation->size = alloc->size; + + return DFB_OK; +} + +static DFBResult +localDeallocateBuffer( CoreSurfacePool *pool, + void *pool_data, + void *pool_local, + CoreSurfaceBuffer *buffer, + CoreSurfaceAllocation *allocation, + void *alloc_data ) +{ + DFBResult ret; + LocalAllocationData *alloc = alloc_data; + + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + D_MAGIC_ASSERT( alloc, LocalAllocationData ); + + ret = fusion_call_execute( &alloc->call, FCEF_ONEWAY, 0, alloc->addr, NULL ); +// if (ret) +// D_DERROR( ret, "SurfPool/Local: Could not call buffer owner to free it there!\n" ); + + D_MAGIC_CLEAR( alloc ); + + return DFB_OK; +} + +static DFBResult +localLock( CoreSurfacePool *pool, + void *pool_data, + void *pool_local, + CoreSurfaceAllocation *allocation, + void *alloc_data, + CoreSurfaceBufferLock *lock ) +{ + LocalAllocationData *alloc = alloc_data; + + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); + D_MAGIC_ASSERT( lock, CoreSurfaceBufferLock ); + D_MAGIC_ASSERT( alloc, LocalAllocationData ); + + lock->addr = alloc->addr; + lock->pitch = alloc->pitch; + + return DFB_OK; +} + +static DFBResult +localUnlock( CoreSurfacePool *pool, + void *pool_data, + void *pool_local, + CoreSurfaceAllocation *allocation, + void *alloc_data, + CoreSurfaceBufferLock *lock ) +{ + LocalAllocationData *alloc = alloc_data; + + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); + D_MAGIC_ASSERT( lock, CoreSurfaceBufferLock ); + D_MAGIC_ASSERT( alloc, LocalAllocationData ); + + (void) alloc; + + return DFB_OK; +} + +const SurfacePoolFuncs localSurfacePoolFuncs = { + .PoolDataSize = localPoolDataSize, + .PoolLocalDataSize = localPoolLocalDataSize, + .AllocationDataSize = localAllocationDataSize, + + .InitPool = localInitPool, + .JoinPool = localJoinPool, + .DestroyPool = localDestroyPool, + .LeavePool = localLeavePool, + + .AllocateBuffer = localAllocateBuffer, + .DeallocateBuffer = localDeallocateBuffer, + + .Lock = localLock, + .Unlock = localUnlock, +}; + diff --git a/Source/DirectFB/src/core/palette.c b/Source/DirectFB/src/core/palette.c new file mode 100755 index 0000000..3d66a54 --- /dev/null +++ b/Source/DirectFB/src/core/palette.c @@ -0,0 +1,317 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include + +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include + +D_DEBUG_DOMAIN( Core_Palette, "Core/Palette", "DirectFB Palette Core" ); + +/**********************************************************************************************************************/ + +static const u8 lookup3to8[] = { 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff }; +static const u8 lookup2to8[] = { 0x00, 0x55, 0xaa, 0xff }; + +static const ReactionFunc dfb_palette_globals[] = { +/* 0 */ _dfb_surface_palette_listener, + NULL +}; + +/**********************************************************************************************************************/ + +static void palette_destructor( FusionObject *object, bool zombie, void *ctx ) +{ + CorePaletteNotification notification; + CorePalette *palette = (CorePalette*) object; + + D_MAGIC_ASSERT( palette, CorePalette ); + + D_DEBUG_AT( Core_Palette, "destroying %p (%d)%s\n", palette, + palette->num_entries, zombie ? " (ZOMBIE)" : ""); + + D_ASSERT( palette->entries != NULL ); + D_ASSERT( palette->entries_yuv != NULL ); + + notification.flags = CPNF_DESTROY; + notification.palette = palette; + + dfb_palette_dispatch( palette, ¬ification, dfb_palette_globals ); + + if (palette->hash_attached) { + dfb_colorhash_invalidate( NULL, palette ); + dfb_colorhash_detach( NULL, palette ); + } + + SHFREE( palette->shmpool, palette->entries_yuv ); + SHFREE( palette->shmpool, palette->entries ); + + D_MAGIC_CLEAR( palette ); + + fusion_object_destroy( object ); +} + +FusionObjectPool * +dfb_palette_pool_create( const FusionWorld *world ) +{ + FusionObjectPool *pool; + + pool = fusion_object_pool_create( "Palette Pool", + sizeof(CorePalette), + sizeof(CorePaletteNotification), + palette_destructor, NULL, world ); + + return pool; +} + +/**********************************************************************************************************************/ + +DFBResult +dfb_palette_create( CoreDFB *core, + unsigned int size, + CorePalette **ret_palette ) +{ + CorePalette *palette; + + D_DEBUG_AT( Core_Palette, "%s( %d )\n", __FUNCTION__, size ); + + D_ASSERT( ret_palette ); + + palette = dfb_core_create_palette( core ); + if (!palette) + return DFB_FUSION; + + palette->shmpool = dfb_core_shmpool( core ); + + if (size) { + palette->entries = SHCALLOC( palette->shmpool, size, sizeof(DFBColor) ); + if (!palette->entries) { + fusion_object_destroy( &palette->object ); + return D_OOSHM(); + } + + palette->entries_yuv = SHCALLOC( palette->shmpool, size, sizeof(DFBColorYUV) ); + if (!palette->entries_yuv) { + SHFREE( palette->shmpool, palette->entries ); + fusion_object_destroy( &palette->object ); + return D_OOSHM(); + } + } + + palette->num_entries = size; + + /* reset cache */ + palette->search_cache.index = -1; + + D_MAGIC_SET( palette, CorePalette ); + + /* activate object */ + fusion_object_activate( &palette->object ); + + /* return the new palette */ + *ret_palette = palette; + + D_DEBUG_AT( Core_Palette, " -> %p\n", palette ); + + return DFB_OK; +} + +void +dfb_palette_generate_rgb332_map( CorePalette *palette ) +{ + unsigned int i; + + D_DEBUG_AT( Core_Palette, "%s( %p )\n", __FUNCTION__, palette ); + + D_MAGIC_ASSERT( palette, CorePalette ); + + if (!palette->num_entries) + return; + + for (i=0; inum_entries; i++) { + palette->entries[i].a = i ? 0xff : 0x00; + palette->entries[i].r = lookup3to8[ (i & 0xE0) >> 5 ]; + palette->entries[i].g = lookup3to8[ (i & 0x1C) >> 2 ]; + palette->entries[i].b = lookup2to8[ (i & 0x03) ]; + + palette->entries_yuv[i].a = palette->entries[i].a; + + RGB_TO_YCBCR( palette->entries[i].r, palette->entries[i].g, palette->entries[i].b, + palette->entries_yuv[i].y, palette->entries_yuv[i].u, palette->entries_yuv[i].v ); + } + + dfb_palette_update( palette, 0, palette->num_entries - 1 ); +} + +void +dfb_palette_generate_rgb121_map( CorePalette *palette ) +{ + unsigned int i; + + D_DEBUG_AT( Core_Palette, "%s( %p )\n", __FUNCTION__, palette ); + + D_MAGIC_ASSERT( palette, CorePalette ); + + if (!palette->num_entries) + return; + + for (i=0; inum_entries; i++) { + palette->entries[i].a = i ? 0xff : 0x00; + palette->entries[i].r = (i & 0x8) ? 0xff : 0x00; + palette->entries[i].g = lookup2to8[ (i & 0x6) >> 1 ]; + palette->entries[i].b = (i & 0x1) ? 0xff : 0x00; + + palette->entries_yuv[i].a = palette->entries[i].a; + + RGB_TO_YCBCR( palette->entries[i].r, palette->entries[i].g, palette->entries[i].b, + palette->entries_yuv[i].y, palette->entries_yuv[i].u, palette->entries_yuv[i].v ); + } + + dfb_palette_update( palette, 0, palette->num_entries - 1 ); +} + +unsigned int +dfb_palette_search( CorePalette *palette, + u8 r, + u8 g, + u8 b, + u8 a ) +{ + unsigned int index; + + D_MAGIC_ASSERT( palette, CorePalette ); + + /* check local cache first */ + if (palette->search_cache.index != -1 && + palette->search_cache.color.a == a && + palette->search_cache.color.r == r && + palette->search_cache.color.g == g && + palette->search_cache.color.b == b) + return palette->search_cache.index; + + /* check the global color hash table, returns the closest match */ + if (!palette->hash_attached) { + dfb_colorhash_attach( NULL, palette ); + palette->hash_attached = true; + } + + index = dfb_colorhash_lookup( NULL, palette, r, g, b, a ); + + /* write into local cache */ + palette->search_cache.index = index; + palette->search_cache.color.a = a; + palette->search_cache.color.r = r; + palette->search_cache.color.g = g; + palette->search_cache.color.b = b; + + return index; +} + +void +dfb_palette_update( CorePalette *palette, int first, int last ) +{ + CorePaletteNotification notification; + + D_DEBUG_AT( Core_Palette, "%s( %p, %d, %d )\n", __FUNCTION__, palette, first, last ); + + D_MAGIC_ASSERT( palette, CorePalette ); + D_ASSERT( first >= 0 ); + D_ASSERT( first < palette->num_entries ); + D_ASSERT( last >= 0 ); + D_ASSERT( last < palette->num_entries ); + D_ASSERT( first <= last ); + + notification.flags = CPNF_ENTRIES; + notification.palette = palette; + notification.first = first; + notification.last = last; + + /* reset cache */ + if (palette->search_cache.index >= first && + palette->search_cache.index <= last) + palette->search_cache.index = -1; + + /* invalidate entries in colorhash */ + if (palette->hash_attached) + dfb_colorhash_invalidate( NULL, palette ); + + /* post message about palette update */ + dfb_palette_dispatch( palette, ¬ification, dfb_palette_globals ); +} + +bool +dfb_palette_equal( CorePalette *palette1, CorePalette *palette2 ) +{ + u32 *entries1; + u32 *entries2; + int i; + + D_DEBUG_AT( Core_Palette, "%s( %p, %p )\n", __FUNCTION__, palette1, palette2 ); + + D_ASSERT( palette1 != NULL ); + D_ASSERT( palette2 != NULL ); + + if (palette1 == palette2) { + D_DEBUG_AT( Core_Palette, " -> SAME\n" ); + return true; + } + + if (palette1->num_entries != palette2->num_entries) { + D_DEBUG_AT( Core_Palette, " -> NOT EQUAL (%d/%d)\n", palette1->num_entries, palette2->num_entries ); + return false; + } + + entries1 = (u32*)palette1->entries; + entries2 = (u32*)palette2->entries; + + for (i = 0; i < palette1->num_entries; i++) { + if (entries1[i] != entries2[i]) { + D_DEBUG_AT( Core_Palette, " -> NOT EQUAL (%d)\n", i ); + return false; + } + } + + D_DEBUG_AT( Core_Palette, " -> EQUAL\n" ); + + return true; +} + diff --git a/Source/DirectFB/src/core/palette.h b/Source/DirectFB/src/core/palette.h new file mode 100755 index 0000000..10886be --- /dev/null +++ b/Source/DirectFB/src/core/palette.h @@ -0,0 +1,106 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef __PALETTE_H__ +#define __PALETTE_H__ + +#include +#include +#include + +struct _CorePalette { + FusionObject object; + int magic; + + unsigned int num_entries; + DFBColor *entries; + DFBColorYUV *entries_yuv; + + struct { + int index; + DFBColor color; + } search_cache; + + bool hash_attached; + + FusionSHMPoolShared *shmpool; +}; + +typedef enum { + CPNF_ENTRIES = 0x00000001, + CPNF_DESTROY = 0x00000002 +} CorePaletteNotificationFlags; + +typedef struct { + CorePaletteNotificationFlags flags; + CorePalette *palette; + int first; + int last; +} CorePaletteNotification; + + +DFBResult dfb_palette_create ( CoreDFB *core, + unsigned int size, + CorePalette **ret_palette ); + +void dfb_palette_generate_rgb332_map( CorePalette *palette ); +void dfb_palette_generate_rgb121_map( CorePalette *palette ); + +unsigned int dfb_palette_search ( CorePalette *palette, + u8 r, + u8 g, + u8 b, + u8 a ); + +void dfb_palette_update ( CorePalette *palette, + int first, + int last ); + +bool dfb_palette_equal ( CorePalette *palette1, + CorePalette *palette2 ); + + +/* + * Creates a pool of palette objects. + */ +FusionObjectPool *dfb_palette_pool_create( const FusionWorld *world ); + +/* + * Generates dfb_palette_ref(), dfb_palette_attach() etc. + */ +FUSION_OBJECT_METHODS( CorePalette, dfb_palette ) + + +/* global reactions */ + +typedef enum { + DFB_SURFACE_PALETTE_LISTENER +} DFB_PALETTE_GLOBALS; + +#endif + diff --git a/Source/DirectFB/src/core/prealloc_surface_pool.c b/Source/DirectFB/src/core/prealloc_surface_pool.c new file mode 100755 index 0000000..f7d9051 --- /dev/null +++ b/Source/DirectFB/src/core/prealloc_surface_pool.c @@ -0,0 +1,192 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include + +#include + +#include +#include +#include + +#include +#include + +typedef struct { + void *addr; + int pitch; +} PreallocAllocationData; + +/**********************************************************************************************************************/ + +static int +preallocAllocationDataSize( void ) +{ + return sizeof(PreallocAllocationData); +} + +static DFBResult +preallocInitPool( CoreDFB *core, + CoreSurfacePool *pool, + void *pool_data, + void *pool_local, + void *system_data, + CoreSurfacePoolDescription *ret_desc ) +{ + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + D_ASSERT( ret_desc != NULL ); + + ret_desc->caps = CSPCAPS_NONE; + ret_desc->access[CSAID_CPU] = CSAF_READ | CSAF_WRITE; + ret_desc->types = CSTF_PREALLOCATED | CSTF_INTERNAL; + ret_desc->priority = CSPP_DEFAULT; + + snprintf( ret_desc->name, DFB_SURFACE_POOL_DESC_NAME_LENGTH, "Preallocated Memory" ); + + return DFB_OK; +} + +static DFBResult +preallocTestConfig( CoreSurfacePool *pool, + void *pool_data, + void *pool_local, + CoreSurfaceBuffer *buffer, + const CoreSurfaceConfig *config ) +{ + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + D_ASSERT( config != NULL ); + + return (config->flags & CSCONF_PREALLOCATED) ? DFB_OK : DFB_UNSUPPORTED; +} + +static DFBResult +preallocAllocateBuffer( CoreSurfacePool *pool, + void *pool_data, + void *pool_local, + CoreSurfaceBuffer *buffer, + CoreSurfaceAllocation *allocation, + void *alloc_data ) +{ + int index; + CoreSurface *surface; + PreallocAllocationData *alloc = alloc_data; + + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + + surface = buffer->surface; + D_MAGIC_ASSERT( surface, CoreSurface ); + + for (index=0; indexbuffers[index] == buffer) + break; + } + + if (index == MAX_SURFACE_BUFFERS) + return DFB_BUG; + + if (!(surface->config.flags & CSCONF_PREALLOCATED)) + return DFB_BUG; + + if (!surface->config.preallocated[index].addr || + surface->config.preallocated[index].pitch < DFB_BYTES_PER_LINE(surface->config.format, + surface->config.size.w)) + return DFB_INVARG; + + alloc->addr = surface->config.preallocated[index].addr; + alloc->pitch = surface->config.preallocated[index].pitch; + + allocation->flags = CSALF_PREALLOCATED | CSALF_VOLATILE; + allocation->size = surface->config.preallocated[index].pitch * + DFB_PLANE_MULTIPLY( surface->config.format, surface->config.size.h ); + + return DFB_OK; +} + +static DFBResult +preallocDeallocateBuffer( CoreSurfacePool *pool, + void *pool_data, + void *pool_local, + CoreSurfaceBuffer *buffer, + CoreSurfaceAllocation *allocation, + void *alloc_data ) +{ + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); + + return DFB_OK; +} + +static DFBResult +preallocLock( CoreSurfacePool *pool, + void *pool_data, + void *pool_local, + CoreSurfaceAllocation *allocation, + void *alloc_data, + CoreSurfaceBufferLock *lock ) +{ + PreallocAllocationData *alloc = alloc_data; + + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); + D_MAGIC_ASSERT( lock, CoreSurfaceBufferLock ); + + lock->addr = alloc->addr; + lock->pitch = alloc->pitch; + + return DFB_OK; +} + +static DFBResult +preallocUnlock( CoreSurfacePool *pool, + void *pool_data, + void *pool_local, + CoreSurfaceAllocation *allocation, + void *alloc_data, + CoreSurfaceBufferLock *lock ) +{ + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); + D_MAGIC_ASSERT( lock, CoreSurfaceBufferLock ); + + return DFB_OK; +} + +const SurfacePoolFuncs preallocSurfacePoolFuncs = { + .AllocationDataSize = preallocAllocationDataSize, + .InitPool = preallocInitPool, + + .TestConfig = preallocTestConfig, + + .AllocateBuffer = preallocAllocateBuffer, + .DeallocateBuffer = preallocDeallocateBuffer, + + .Lock = preallocLock, + .Unlock = preallocUnlock, +}; + diff --git a/Source/DirectFB/src/core/screen.c b/Source/DirectFB/src/core/screen.c new file mode 100755 index 0000000..4b233e0 --- /dev/null +++ b/Source/DirectFB/src/core/screen.c @@ -0,0 +1,540 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include + +#include + +#include + +#include +#include +#include + + +DFBResult +dfb_screen_get_info( CoreScreen *screen, + DFBScreenID *ret_id, + DFBScreenDescription *ret_desc ) +{ + CoreScreenShared *shared; + + D_ASSERT( screen != NULL ); + D_ASSERT( screen->shared != NULL ); + + shared = screen->shared; + + if (ret_id) + *ret_id = shared->screen_id; + + if (ret_desc) + *ret_desc = shared->description; + + return DFB_OK; +} + +DFBResult +dfb_screen_suspend( CoreScreen *screen ) +{ + D_ASSERT( screen != NULL ); + + return DFB_OK; +} + +DFBResult +dfb_screen_resume( CoreScreen *screen ) +{ + D_ASSERT( screen != NULL ); + + return DFB_OK; +} + +DFBResult +dfb_screen_set_powermode( CoreScreen *screen, + DFBScreenPowerMode mode ) +{ + ScreenFuncs *funcs; + + D_ASSERT( screen != NULL ); + D_ASSERT( screen->funcs != NULL ); + + funcs = screen->funcs; + + if (funcs->SetPowerMode) + return funcs->SetPowerMode( screen, + screen->driver_data, + screen->screen_data, + mode ); + + return DFB_UNSUPPORTED; +} + +DFBResult +dfb_screen_wait_vsync( CoreScreen *screen ) +{ + ScreenFuncs *funcs; + + D_ASSERT( screen != NULL ); + D_ASSERT( screen->funcs != NULL ); + + funcs = screen->funcs; + + if (funcs->WaitVSync) + return funcs->WaitVSync( screen, + screen->driver_data, screen->screen_data ); + + return DFB_UNSUPPORTED; +} + + +/*********************************** Mixers ***********************************/ + +DFBResult +dfb_screen_get_mixer_info( CoreScreen *screen, + int mixer, + DFBScreenMixerDescription *ret_desc ) +{ + D_ASSERT( screen != NULL ); + D_ASSERT( screen->shared != NULL ); + D_ASSERT( mixer >= 0 ); + D_ASSERT( mixer < screen->shared->description.mixers ); + D_ASSERT( ret_desc != NULL ); + + /* Return mixer description. */ + *ret_desc = screen->shared->mixers[mixer].description; + + return DFB_OK; +} + +DFBResult +dfb_screen_get_mixer_config( CoreScreen *screen, + int mixer, + DFBScreenMixerConfig *ret_config ) +{ + D_ASSERT( screen != NULL ); + D_ASSERT( screen->shared != NULL ); + D_ASSERT( mixer >= 0 ); + D_ASSERT( mixer < screen->shared->description.mixers ); + D_ASSERT( ret_config != NULL ); + + /* Return current mixer configuration. */ + *ret_config = screen->shared->mixers[mixer].configuration; + + return DFB_OK; +} + +DFBResult +dfb_screen_test_mixer_config( CoreScreen *screen, + int mixer, + const DFBScreenMixerConfig *config, + DFBScreenMixerConfigFlags *ret_failed ) +{ + DFBResult ret; + DFBScreenMixerConfigFlags failed = DSMCONF_NONE; + + D_ASSERT( screen != NULL ); + D_ASSERT( screen->shared != NULL ); + D_ASSERT( screen->funcs != NULL ); + D_ASSERT( screen->funcs->TestMixerConfig != NULL ); + D_ASSERT( mixer >= 0 ); + D_ASSERT( mixer < screen->shared->description.mixers ); + D_ASSERT( config != NULL ); + D_ASSERT( config->flags == screen->shared->mixers[mixer].configuration.flags ); + + /* Test the mixer configuration. */ + ret = screen->funcs->TestMixerConfig( screen, + screen->driver_data, + screen->screen_data, + mixer, config, &failed ); + + D_ASSUME( (ret == DFB_OK && !failed) || (ret != DFB_OK) ); + + if (ret_failed) + *ret_failed = failed; + + return ret; +} + +DFBResult +dfb_screen_set_mixer_config( CoreScreen *screen, + int mixer, + const DFBScreenMixerConfig *config ) +{ + DFBResult ret; + DFBScreenMixerConfigFlags failed = DSOCONF_NONE; + + D_ASSERT( screen != NULL ); + D_ASSERT( screen->shared != NULL ); + D_ASSERT( screen->funcs != NULL ); + D_ASSERT( screen->funcs->TestMixerConfig != NULL ); + D_ASSERT( screen->funcs->SetMixerConfig != NULL ); + D_ASSERT( mixer >= 0 ); + D_ASSERT( mixer < screen->shared->description.mixers ); + D_ASSERT( config != NULL ); + D_ASSERT( config->flags == screen->shared->mixers[mixer].configuration.flags ); + + /* Test configuration first. */ + ret = screen->funcs->TestMixerConfig( screen, + screen->driver_data, + screen->screen_data, + mixer, config, &failed ); + + D_ASSUME( (ret == DFB_OK && !failed) || (ret != DFB_OK && failed) ); + + if (ret) + return ret; + + /* Set configuration afterwards. */ + ret = screen->funcs->SetMixerConfig( screen, + screen->driver_data, + screen->screen_data, + mixer, config ); + if (ret) + return ret; + + /* Store current configuration. */ + screen->shared->mixers[mixer].configuration = *config; + + return DFB_OK; +} + + +/********************************** Encoders **********************************/ + +DFBResult +dfb_screen_get_encoder_info( CoreScreen *screen, + int encoder, + DFBScreenEncoderDescription *ret_desc ) +{ + D_ASSERT( screen != NULL ); + D_ASSERT( screen->shared != NULL ); + D_ASSERT( encoder >= 0 ); + D_ASSERT( encoder < screen->shared->description.encoders ); + D_ASSERT( ret_desc != NULL ); + + /* Return encoder description. */ + *ret_desc = screen->shared->encoders[encoder].description; + + return DFB_OK; +} + +DFBResult +dfb_screen_get_encoder_config( CoreScreen *screen, + int encoder, + DFBScreenEncoderConfig *ret_config ) +{ + D_ASSERT( screen != NULL ); + D_ASSERT( screen->shared != NULL ); + D_ASSERT( encoder >= 0 ); + D_ASSERT( encoder < screen->shared->description.encoders ); + D_ASSERT( ret_config != NULL ); + + /* Return current encoder configuration. */ + *ret_config = screen->shared->encoders[encoder].configuration; + + return DFB_OK; +} + +DFBResult +dfb_screen_test_encoder_config( CoreScreen *screen, + int encoder, + const DFBScreenEncoderConfig *config, + DFBScreenEncoderConfigFlags *ret_failed ) +{ + DFBResult ret; + DFBScreenEncoderConfigFlags failed = DSECONF_NONE; + + D_ASSERT( screen != NULL ); + D_ASSERT( screen->shared != NULL ); + D_ASSERT( screen->funcs != NULL ); + D_ASSERT( screen->funcs->TestEncoderConfig != NULL ); + D_ASSERT( encoder >= 0 ); + D_ASSERT( encoder < screen->shared->description.encoders ); + D_ASSERT( config != NULL ); + D_ASSERT( config->flags == screen->shared->encoders[encoder].configuration.flags ); + + /* Test the encoder configuration. */ + ret = screen->funcs->TestEncoderConfig( screen, + screen->driver_data, + screen->screen_data, + encoder, config, &failed ); + + D_ASSUME( (ret == DFB_OK && !failed) || (ret != DFB_OK && failed) ); + + if (ret_failed) + *ret_failed = failed; + + return ret; +} + +DFBResult +dfb_screen_set_encoder_config( CoreScreen *screen, + int encoder, + const DFBScreenEncoderConfig *config ) +{ + DFBResult ret; + DFBScreenEncoderConfigFlags failed = DSECONF_NONE; + + D_ASSERT( screen != NULL ); + D_ASSERT( screen->shared != NULL ); + D_ASSERT( screen->funcs != NULL ); + D_ASSERT( screen->funcs->TestEncoderConfig != NULL ); + D_ASSERT( screen->funcs->SetEncoderConfig != NULL ); + D_ASSERT( encoder >= 0 ); + D_ASSERT( encoder < screen->shared->description.encoders ); + D_ASSERT( config != NULL ); + D_ASSERT( config->flags == screen->shared->encoders[encoder].configuration.flags ); + + /* Test configuration first. */ + ret = screen->funcs->TestEncoderConfig( screen, + screen->driver_data, + screen->screen_data, + encoder, config, &failed ); + + D_ASSUME( (ret == DFB_OK && !failed) || (ret != DFB_OK && failed) ); + + if (ret) + return ret; + + /* Set configuration afterwards. */ + ret = screen->funcs->SetEncoderConfig( screen, + screen->driver_data, + screen->screen_data, + encoder, config ); + if (ret) + return ret; + + /* Store current configuration. */ + screen->shared->encoders[encoder].configuration = *config; + + return DFB_OK; +} + + +/********************************** Outputs ***********************************/ + +DFBResult +dfb_screen_get_output_info( CoreScreen *screen, + int output, + DFBScreenOutputDescription *ret_desc ) +{ + D_ASSERT( screen != NULL ); + D_ASSERT( screen->shared != NULL ); + D_ASSERT( output >= 0 ); + D_ASSERT( output < screen->shared->description.outputs ); + D_ASSERT( ret_desc != NULL ); + + /* Return output description. */ + *ret_desc = screen->shared->outputs[output].description; + + return DFB_OK; +} + +DFBResult +dfb_screen_get_output_config( CoreScreen *screen, + int output, + DFBScreenOutputConfig *ret_config ) +{ + D_ASSERT( screen != NULL ); + D_ASSERT( screen->shared != NULL ); + D_ASSERT( output >= 0 ); + D_ASSERT( output < screen->shared->description.outputs ); + D_ASSERT( ret_config != NULL ); + + /* Return current output configuration. */ + *ret_config = screen->shared->outputs[output].configuration; + + return DFB_OK; +} + +DFBResult +dfb_screen_test_output_config( CoreScreen *screen, + int output, + const DFBScreenOutputConfig *config, + DFBScreenOutputConfigFlags *ret_failed ) +{ + DFBResult ret; + DFBScreenOutputConfigFlags failed = DSOCONF_NONE; + + D_ASSERT( screen != NULL ); + D_ASSERT( screen->shared != NULL ); + D_ASSERT( screen->funcs != NULL ); + D_ASSERT( screen->funcs->TestOutputConfig != NULL ); + D_ASSERT( output >= 0 ); + D_ASSERT( output < screen->shared->description.outputs ); + D_ASSERT( config != NULL ); + D_ASSERT( config->flags == screen->shared->outputs[output].configuration.flags ); + + /* Test the output configuration. */ + ret = screen->funcs->TestOutputConfig( screen, + screen->driver_data, + screen->screen_data, + output, config, &failed ); + + D_ASSUME( (ret == DFB_OK && !failed) || (ret != DFB_OK && failed) ); + + if (ret_failed) + *ret_failed = failed; + + return ret; +} + +DFBResult +dfb_screen_set_output_config( CoreScreen *screen, + int output, + const DFBScreenOutputConfig *config ) +{ + DFBResult ret; + DFBScreenOutputConfigFlags failed = DSOCONF_NONE; + + D_ASSERT( screen != NULL ); + D_ASSERT( screen->shared != NULL ); + D_ASSERT( screen->funcs != NULL ); + D_ASSERT( screen->funcs->TestOutputConfig != NULL ); + D_ASSERT( screen->funcs->SetOutputConfig != NULL ); + D_ASSERT( output >= 0 ); + D_ASSERT( output < screen->shared->description.outputs ); + D_ASSERT( config != NULL ); + D_ASSERT( config->flags == screen->shared->outputs[output].configuration.flags ); + + /* Test configuration first. */ + ret = screen->funcs->TestOutputConfig( screen, + screen->driver_data, + screen->screen_data, + output, config, &failed ); + + D_ASSUME( (ret == DFB_OK && !failed) || (ret != DFB_OK && failed) ); + + if (ret) + return ret; + + /* Set configuration afterwards. */ + ret = screen->funcs->SetOutputConfig( screen, + screen->driver_data, + screen->screen_data, + output, config ); + if (ret) + return ret; + + /* Store current configuration. */ + screen->shared->outputs[output].configuration = *config; + + return DFB_OK; +} + +DFBResult +dfb_screen_get_screen_size( CoreScreen *screen, + int *ret_width, + int *ret_height ) +{ + D_ASSERT( screen != NULL ); + D_ASSERT( screen->funcs != NULL ); + D_ASSERT( screen->funcs->GetScreenSize != NULL ); + D_ASSERT( ret_width != NULL ); + D_ASSERT( ret_height != NULL ); + + return screen->funcs->GetScreenSize( screen, + screen->driver_data, screen->screen_data, + ret_width, ret_height ); +} + +DFBResult +dfb_screen_get_layer_dimension( CoreScreen *screen, + CoreLayer *layer, + int *ret_width, + int *ret_height ) +{ + int i; + DFBResult ret = DFB_UNSUPPORTED; + CoreScreenShared *shared; + ScreenFuncs *funcs; + + D_ASSERT( screen != NULL ); + D_ASSERT( screen->shared != NULL ); + D_ASSERT( screen->funcs != NULL ); + D_ASSERT( layer != NULL ); + D_ASSERT( ret_width != NULL ); + D_ASSERT( ret_height != NULL ); + + shared = screen->shared; + funcs = screen->funcs; + + if (funcs->GetMixerState) { + for (i=0; idescription.mixers; i++) { + const DFBScreenMixerConfig *config = &shared->mixers[i].configuration; + + if ((config->flags & DSMCONF_LAYERS) && + DFB_DISPLAYLAYER_IDS_HAVE( config->layers, dfb_layer_id(layer) )) + { + CoreMixerState state; + + ret = funcs->GetMixerState( screen, screen->driver_data, screen->screen_data, i, &state ); + if (ret == DFB_OK) { + if (state.flags & CMSF_DIMENSION) { + *ret_width = state.dimension.w; + *ret_height = state.dimension.h; + + return DFB_OK; + } + + ret = DFB_UNSUPPORTED; + } + } + } + + for (i=0; idescription.mixers; i++) { + const DFBScreenMixerDescription *desc = &shared->mixers[i].description; + + if ((desc->caps & DSMCAPS_SUB_LAYERS) && + DFB_DISPLAYLAYER_IDS_HAVE( desc->sub_layers, dfb_layer_id(layer) )) + { + CoreMixerState state; + + ret = funcs->GetMixerState( screen, screen->driver_data, screen->screen_data, i, &state ); + if (ret == DFB_OK) { + if (state.flags & CMSF_DIMENSION) { + *ret_width = state.dimension.w; + *ret_height = state.dimension.h; + + return DFB_OK; + } + + ret = DFB_UNSUPPORTED; + } + } + } + } + + if (funcs->GetScreenSize) + ret = funcs->GetScreenSize( screen, + screen->driver_data, screen->screen_data, + ret_width, ret_height ); + + return ret; +} + diff --git a/Source/DirectFB/src/core/screen.h b/Source/DirectFB/src/core/screen.h new file mode 100755 index 0000000..b5491f4 --- /dev/null +++ b/Source/DirectFB/src/core/screen.h @@ -0,0 +1,122 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef __DFB__CORE__SCREEN_H__ +#define __DFB__CORE__SCREEN_H__ + +#include + +DFBResult dfb_screen_get_info ( CoreScreen *screen, + DFBScreenID *ret_id, + DFBScreenDescription *ret_desc ); + + +/* Misc */ + +DFBResult dfb_screen_suspend ( CoreScreen *screen ); +DFBResult dfb_screen_resume ( CoreScreen *screen ); + +DFBResult dfb_screen_set_powermode ( CoreScreen *screen, + DFBScreenPowerMode mode ); + +DFBResult dfb_screen_wait_vsync ( CoreScreen *screen ); + + +/* Mixers */ + +DFBResult dfb_screen_get_mixer_info ( CoreScreen *screen, + int mixer, + DFBScreenMixerDescription *ret_desc ); + +DFBResult dfb_screen_get_mixer_config ( CoreScreen *screen, + int mixer, + DFBScreenMixerConfig *ret_config ); + +DFBResult dfb_screen_test_mixer_config( CoreScreen *screen, + int mixer, + const DFBScreenMixerConfig *config, + DFBScreenMixerConfigFlags *ret_failed ); + +DFBResult dfb_screen_set_mixer_config ( CoreScreen *screen, + int mixer, + const DFBScreenMixerConfig *config ); + + +/* Encoders */ + +DFBResult dfb_screen_get_encoder_info ( CoreScreen *screen, + int encoder, + DFBScreenEncoderDescription *ret_desc ); + +DFBResult dfb_screen_get_encoder_config ( CoreScreen *screen, + int encoder, + DFBScreenEncoderConfig *ret_config ); + +DFBResult dfb_screen_test_encoder_config( CoreScreen *screen, + int encoder, + const DFBScreenEncoderConfig *config, + DFBScreenEncoderConfigFlags *ret_failed ); + +DFBResult dfb_screen_set_encoder_config ( CoreScreen *screen, + int encoder, + const DFBScreenEncoderConfig *config ); + + +/* Outputs */ + +DFBResult dfb_screen_get_output_info ( CoreScreen *screen, + int output, + DFBScreenOutputDescription *ret_desc ); + +DFBResult dfb_screen_get_output_config ( CoreScreen *screen, + int output, + DFBScreenOutputConfig *ret_config ); + +DFBResult dfb_screen_test_output_config( CoreScreen *screen, + int output, + const DFBScreenOutputConfig *config, + DFBScreenOutputConfigFlags *ret_failed ); + +DFBResult dfb_screen_set_output_config ( CoreScreen *screen, + int output, + const DFBScreenOutputConfig *config ); + + +/* Screen configuration */ + +DFBResult dfb_screen_get_screen_size ( CoreScreen *screen, + int *ret_width, + int *ret_height ); + +DFBResult dfb_screen_get_layer_dimension( CoreScreen *screen, + CoreLayer *layer, + int *ret_width, + int *ret_height ); + +#endif + diff --git a/Source/DirectFB/src/core/screens.c b/Source/DirectFB/src/core/screens.c new file mode 100755 index 0000000..708f5e8 --- /dev/null +++ b/Source/DirectFB/src/core/screens.c @@ -0,0 +1,591 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include + +#include + +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include + +#include + +#include + + +D_DEBUG_DOMAIN( Core_Screen, "Core/Screen", "DirectFB Screen Core" ); + +/**********************************************************************************************************************/ + +typedef struct { + int magic; + + + int num; + CoreScreenShared *screens[MAX_SCREENS]; +} DFBScreenCoreShared; + +struct __DFB_DFBScreenCore { + int magic; + + CoreDFB *core; + + DFBScreenCoreShared *shared; +}; + + +DFB_CORE_PART( screen_core, ScreenCore ); + +/**********************************************************************************************************************/ + +static DFBScreenCoreShared *core_screens = NULL; /* FIXME */ + +static int num_screens = 0; /* FIXME */ +static CoreScreen *screens[MAX_SCREENS] = { NULL }; /* FIXME */ + + +static DFBResult +dfb_screen_core_initialize( CoreDFB *core, + DFBScreenCore *data, + DFBScreenCoreShared *shared ) +{ + int i; + DFBResult ret; + FusionSHMPoolShared *pool; + + D_DEBUG_AT( Core_Screen, "dfb_screen_core_initialize( %p, %p, %p )\n", core, data, shared ); + + D_ASSERT( data != NULL ); + D_ASSERT( shared != NULL ); + + data->core = core; + data->shared = shared; + + core_screens = shared; /* FIXME */ + + pool = dfb_core_shmpool( core ); + + /* Initialize all registered screens. */ + for (i=0; ifuncs; + DFBScreenDescription desc = { .caps = DSCCAPS_NONE }; + + /* Allocate shared data. */ + sshared = SHCALLOC( pool, 1, sizeof(CoreScreenShared) ); + + /* Assign ID (zero based index). */ + sshared->screen_id = i; + + snprintf( buf, sizeof(buf), "Screen %d", i ); + + /* Initialize the lock. */ + if (fusion_skirmish_init( &sshared->lock, buf, dfb_core_world(core) )) { + SHFREE( pool, sshared ); + return DFB_FUSION; + } + + /* Allocate driver's screen data. */ + if (funcs->ScreenDataSize) { + int size = funcs->ScreenDataSize(); + + if (size > 0) { + sshared->screen_data = SHCALLOC( pool, 1, size ); + if (!sshared->screen_data) { + fusion_skirmish_destroy( &sshared->lock ); + SHFREE( pool, sshared ); + return D_OOSHM(); + } + } + } + + /* Initialize the screen and get the screen description. */ + ret = funcs->InitScreen( screen, + screen->device, + screen->driver_data, + sshared->screen_data, + &desc ); + if (ret) { + D_ERROR("DirectFB/Core/screens: " + "Failed to initialize screen %d!\n", sshared->screen_id); + + fusion_skirmish_destroy( &sshared->lock ); + + if (sshared->screen_data) + SHFREE( pool, sshared->screen_data ); + + SHFREE( pool, sshared ); + + return ret; + } + + D_ASSUME( desc.mixers > 0 || !(desc.caps & DSCCAPS_MIXERS) ); + D_ASSUME( desc.mixers == 0 || (desc.caps & DSCCAPS_MIXERS) ); + + D_ASSUME( desc.encoders > 0 || !(desc.caps & DSCCAPS_ENCODERS) ); + D_ASSUME( desc.encoders == 0 || (desc.caps & DSCCAPS_ENCODERS) ); + + D_ASSUME( desc.outputs > 0 || !(desc.caps & DSCCAPS_OUTPUTS) ); + D_ASSUME( desc.outputs == 0 || (desc.caps & DSCCAPS_OUTPUTS) ); + + D_ASSERT( desc.mixers >= 0 ); + D_ASSERT( desc.mixers <= 32 ); + D_ASSERT( desc.encoders >= 0 ); + D_ASSERT( desc.encoders <= 32 ); + D_ASSERT( desc.outputs >= 0 ); + D_ASSERT( desc.outputs <= 32 ); + + /* Store description in sshared memory. */ + sshared->description = desc; + + /* Initialize mixers. */ + if (sshared->description.mixers) { + int i; + + D_ASSERT( funcs->InitMixer != NULL ); + D_ASSERT( funcs->SetMixerConfig != NULL ); + + sshared->mixers = SHCALLOC( pool, sshared->description.mixers, + sizeof(CoreScreenMixer) ); + for (i=0; idescription.mixers; i++) { + funcs->InitMixer( screen, + screen->driver_data, + sshared->screen_data, i, + &sshared->mixers[i].description, + &sshared->mixers[i].configuration ); + funcs->SetMixerConfig( screen, + screen->driver_data, + sshared->screen_data, i, + &sshared->mixers[i].configuration ); + } + } + + /* Initialize encoders. */ + if (sshared->description.encoders) { + int i; + + D_ASSERT( funcs->InitEncoder != NULL ); + D_ASSERT( funcs->SetEncoderConfig != NULL ); + + sshared->encoders = SHCALLOC( pool, sshared->description.encoders, + sizeof(CoreScreenEncoder) ); + for (i=0; idescription.encoders; i++) { + funcs->InitEncoder( screen, + screen->driver_data, + sshared->screen_data, i, + &sshared->encoders[i].description, + &sshared->encoders[i].configuration ); + funcs->SetEncoderConfig( screen, + screen->driver_data, + sshared->screen_data, i, + &sshared->encoders[i].configuration ); + } + } + + /* Initialize outputs. */ + if (sshared->description.outputs) { + int i; + + D_ASSERT( funcs->InitOutput != NULL ); + D_ASSERT( funcs->SetOutputConfig != NULL ); + + sshared->outputs = SHCALLOC( pool, sshared->description.outputs, + sizeof(CoreScreenOutput) ); + for (i=0; idescription.outputs; i++) { + funcs->InitOutput( screen, + screen->driver_data, + sshared->screen_data, i, + &sshared->outputs[i].description, + &sshared->outputs[i].configuration ); + funcs->SetOutputConfig( screen, + screen->driver_data, + sshared->screen_data, i, + &sshared->outputs[i].configuration ); + } + } + + /* Make a copy for faster access. */ + screen->screen_data = sshared->screen_data; + + /* Store pointer to sshared data and core. */ + screen->shared = sshared; + screen->core = core; + + /* Add the screen to the sshared list. */ + core_screens->screens[ core_screens->num++ ] = sshared; + } + + + D_MAGIC_SET( data, DFBScreenCore ); + D_MAGIC_SET( shared, DFBScreenCoreShared ); + + return DFB_OK; +} + +static DFBResult +dfb_screen_core_join( CoreDFB *core, + DFBScreenCore *data, + DFBScreenCoreShared *shared ) +{ + int i; + + D_DEBUG_AT( Core_Screen, "dfb_screen_core_join( %p, %p, %p )\n", core, data, shared ); + + D_ASSERT( data != NULL ); + D_MAGIC_ASSERT( shared, DFBScreenCoreShared ); + + data->core = core; + data->shared = shared; + + core_screens = shared; /* FIXME */ + + if (num_screens != core_screens->num) { + D_ERROR("DirectFB/core/screens: Number of screens does not match!\n"); + return DFB_BUG; + } + + for (i=0; iscreens[i]; + + /* Make a copy for faster access. */ + screen->screen_data = shared->screen_data; + + /* Store pointer to shared data and core. */ + screen->shared = shared; + screen->core = core; + } + + + D_MAGIC_SET( data, DFBScreenCore ); + + return DFB_OK; +} + +static DFBResult +dfb_screen_core_shutdown( DFBScreenCore *data, + bool emergency ) +{ + int i; + FusionSHMPoolShared *pool; + DFBScreenCoreShared *shared; + + D_DEBUG_AT( Core_Screen, "dfb_screen_core_shutdown( %p, %semergency )\n", data, emergency ? "" : "no " ); + + D_MAGIC_ASSERT( data, DFBScreenCore ); + D_MAGIC_ASSERT( data->shared, DFBScreenCoreShared ); + + shared = data->shared; + + pool = dfb_core_shmpool( data->core ); + + /* Begin with the most recently added screen. */ + for (i=num_screens-1; i>=0; i--) { + CoreScreen *screen = screens[i]; + CoreScreenShared *shared = screen->shared; + + /* Deinitialize the lock. */ + fusion_skirmish_destroy( &shared->lock ); + + /* Free the driver's screen data. */ + if (shared->screen_data) + SHFREE( pool, shared->screen_data ); + + /* Free mixer data. */ + if (shared->mixers) + SHFREE( pool, shared->mixers ); + + /* Free encoder data. */ + if (shared->encoders) + SHFREE( pool, shared->encoders ); + + /* Free output data. */ + if (shared->outputs) + SHFREE( pool, shared->outputs ); + + /* Free the shared screen data. */ + SHFREE( pool, shared ); + + /* Free the local screen data. */ + D_FREE( screen ); + } + + core_screens = NULL; + num_screens = 0; + + + D_MAGIC_CLEAR( data ); + D_MAGIC_CLEAR( shared ); + + return DFB_OK; +} + +static DFBResult +dfb_screen_core_leave( DFBScreenCore *data, + bool emergency ) +{ + int i; + DFBScreenCoreShared *shared; + + D_DEBUG_AT( Core_Screen, "dfb_screen_core_leave( %p, %semergency )\n", data, emergency ? "" : "no " ); + + D_MAGIC_ASSERT( data, DFBScreenCore ); + D_MAGIC_ASSERT( data->shared, DFBScreenCoreShared ); + + shared = data->shared; + + + /* Deinitialize all local stuff only. */ + for (i=0; ishared, DFBScreenCoreShared ); + + shared = data->shared; + + for (i=num_screens-1; i>=0; i--) + dfb_screen_suspend( screens[i] ); + + return DFB_OK; +} + +static DFBResult +dfb_screen_core_resume( DFBScreenCore *data ) +{ + int i; + DFBScreenCoreShared *shared; + + D_DEBUG_AT( Core_Screen, "dfb_screen_core_resume( %p )\n", data ); + + D_MAGIC_ASSERT( data, DFBScreenCore ); + D_MAGIC_ASSERT( data->shared, DFBScreenCoreShared ); + + shared = data->shared; + + for (i=0; idevice = device; + screen->driver_data = driver_data; + screen->funcs = funcs; + + /* add it to the local list */ + screens[num_screens++] = screen; + + return screen; +} + +typedef void (*AnyFunc)( void ); + +CoreScreen * +dfb_screens_hook_primary( CoreGraphicsDevice *device, + void *driver_data, + ScreenFuncs *funcs, + ScreenFuncs *primary_funcs, + void **primary_driver_data ) +{ + int i; + int entries; + CoreScreen *primary = screens[0]; + + D_ASSERT( primary != NULL ); + D_ASSERT( device != NULL ); + D_ASSERT( funcs != NULL ); + + /* copy content of original function table */ + if (primary_funcs) + direct_memcpy( primary_funcs, primary->funcs, sizeof(ScreenFuncs) ); + + /* copy pointer to original driver data */ + if (primary_driver_data) + *primary_driver_data = primary->driver_data; + + /* replace all entries in the old table that aren't NULL in the new one */ + entries = sizeof(ScreenFuncs) / sizeof(void(*)( void )); + for (i=0; ifuncs; + + if (newfuncs[i]) + oldfuncs[i] = newfuncs[i]; + } + + /* replace device and driver data pointer */ + primary->device = device; + primary->driver_data = driver_data; + + return primary; +} + +CoreScreen * +dfb_screens_register_primary( CoreGraphicsDevice *device, + void *driver_data, + ScreenFuncs *funcs ) +{ + CoreScreen *primary = screens[0]; + + D_ASSERT( primary != NULL ); + D_ASSERT( funcs != NULL ); + D_ASSERT( num_screens > 0 ); + + /* replace device, function table and driver data pointer */ + primary->device = device; + primary->funcs = funcs; + primary->driver_data = driver_data; + + return primary; +} + +void +dfb_screens_enumerate( CoreScreenCallback callback, + void *ctx ) +{ + int i; + + D_ASSERT( core_screens != NULL ); + D_ASSERT( callback != NULL ); + + for (i=0; i= 0); + D_ASSERT( screen_id < num_screens); + + return screens[screen_id]; +} + +CoreScreen * +dfb_screens_at_translated( DFBScreenID screen_id ) +{ + CoreScreen *primary; + + D_ASSERT( screen_id >= 0); + D_ASSERT( screen_id < num_screens); + + if (dfb_config->primary_layer > 0) { + primary = dfb_layer_screen( dfb_layer_at_translated( DLID_PRIMARY ) ); + + if (screen_id == DSCID_PRIMARY) + return primary; + + if (screen_id == primary->shared->screen_id) + return dfb_screens_at( DSCID_PRIMARY ); + } + + return dfb_screens_at( screen_id ); +} + +DFBScreenID +dfb_screen_id_translated( CoreScreen *screen ) +{ + CoreScreenShared *shared; + CoreScreen *primary; + + D_ASSERT( screen != NULL ); + D_ASSERT( screen->shared != NULL ); + + shared = screen->shared; + + if (dfb_config->primary_layer > 0) { + primary = dfb_layer_screen( dfb_layer_at_translated( DLID_PRIMARY ) ); + + if (shared->screen_id == DSCID_PRIMARY) + return primary->shared->screen_id; + + if (shared->screen_id == primary->shared->screen_id) + return DSCID_PRIMARY; + } + + return shared->screen_id; +} + diff --git a/Source/DirectFB/src/core/screens.h b/Source/DirectFB/src/core/screens.h new file mode 100755 index 0000000..1ebaa4e --- /dev/null +++ b/Source/DirectFB/src/core/screens.h @@ -0,0 +1,263 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef __DFB__CORE__SCREENS_H__ +#define __DFB__CORE__SCREENS_H__ + +#include + +#include + + +typedef DFBEnumerationResult (*CoreScreenCallback) (CoreScreen *screen, + void *ctx); + +typedef enum { + CMSF_NONE = 0x00000000, /* none of these */ + + CMSF_DIMENSION = 0x00000001, /* dimension is set */ + + CMSF_ALL = 0x00000001, /* all of these */ +} CoreMixerStateFlags; + +typedef struct { + CoreMixerStateFlags flags; + + DFBDimension dimension; +} CoreMixerState; + +typedef struct { + /** Driver Control **/ + + /* + * Return size of screen data (shared memory). + */ + int (*ScreenDataSize)(void); + + /* + * Called once by the master to initialize screen data and reset hardware. + * Driver has to fill the screen description. + */ + DFBResult (*InitScreen) ( CoreScreen *screen, + CoreGraphicsDevice *device, + void *driver_data, + void *screen_data, + DFBScreenDescription *description ); + + /* + * Called once by the master for each mixer. + * Driver fills description and default config. + */ + DFBResult (*InitMixer) ( CoreScreen *screen, + void *driver_data, + void *screen_data, + int mixer, + DFBScreenMixerDescription *description, + DFBScreenMixerConfig *config ); + + /* + * Called once by the master for each encoder. + * Driver fills description and default config. + */ + DFBResult (*InitEncoder) ( CoreScreen *screen, + void *driver_data, + void *screen_data, + int encoder, + DFBScreenEncoderDescription *description, + DFBScreenEncoderConfig *config ); + + /* + * Called once by the master for each output. + * Driver fills description and default config. + */ + DFBResult (*InitOutput) ( CoreScreen *screen, + void *driver_data, + void *screen_data, + int output, + DFBScreenOutputDescription *description, + DFBScreenOutputConfig *config ); + + + /** Power management **/ + + /* + * Switch between "on", "standby", "suspend" and "off". + */ + DFBResult (*SetPowerMode) ( CoreScreen *screen, + void *driver_data, + void *screen_data, + DFBScreenPowerMode mode ); + + + /** Synchronization **/ + + /* + * Wait for the vertical retrace. + */ + DFBResult (*WaitVSync) ( CoreScreen *screen, + void *driver_data, + void *screen_data ); + + + /** Mixer configuration **/ + + /* + * Test if configuration is supported. Store failing fields in 'failed'. + */ + DFBResult (*TestMixerConfig)( CoreScreen *screen, + void *driver_data, + void *screen_data, + int mixer, + const DFBScreenMixerConfig *config, + DFBScreenMixerConfigFlags *failed ); + + /* + * Set new configuration. + */ + DFBResult (*SetMixerConfig) ( CoreScreen *screen, + void *driver_data, + void *screen_data, + int mixer, + const DFBScreenMixerConfig *config ); + + + /** Encoder configuration **/ + + /* + * Test if configuration is supported. Store failing fields in 'failed'. + */ + DFBResult (*TestEncoderConfig)( CoreScreen *screen, + void *driver_data, + void *screen_data, + int encoder, + const DFBScreenEncoderConfig *config, + DFBScreenEncoderConfigFlags *failed ); + + /* + * Set new configuration. + */ + DFBResult (*SetEncoderConfig) ( CoreScreen *screen, + void *driver_data, + void *screen_data, + int encoder, + const DFBScreenEncoderConfig *config ); + + + /** Output configuration **/ + + /* + * Test if configuration is supported. Store failing fields in 'failed'. + */ + DFBResult (*TestOutputConfig)( CoreScreen *screen, + void *driver_data, + void *screen_data, + int output, + const DFBScreenOutputConfig *config, + DFBScreenOutputConfigFlags *failed ); + + /* + * Set new configuration. + */ + DFBResult (*SetOutputConfig) ( CoreScreen *screen, + void *driver_data, + void *screen_data, + int output, + const DFBScreenOutputConfig *config ); + + + /** Screen configuration **/ + + /* + * Return the screen size, e.g. as a basis for positioning a layer. + * + * This function might be replaced soon. + */ + DFBResult (*GetScreenSize) ( CoreScreen *screen, + void *driver_data, + void *screen_data, + int *ret_width, + int *ret_height ); + + + /** States **/ + + DFBResult (*GetMixerState) ( CoreScreen *screen, + void *driver_data, + void *screen_data, + int mixer, + CoreMixerState *ret_state ); +} ScreenFuncs; + + +/* + * Add a screen to a graphics device by pointing to a table containing + * driver functions. The driver data will be passed to these functions. + */ +CoreScreen *dfb_screens_register( CoreGraphicsDevice *device, + void *driver_data, + ScreenFuncs *funcs ); + +/* + * Replace functions of the primary screen implementation by passing + * an alternative driver function table. All non-NULL functions in the new + * table replace the functions in the original function table. + * The original function table is written to 'primary_funcs' before to allow + * drivers to use existing functionality from the original implementation. + */ +CoreScreen *dfb_screens_hook_primary( CoreGraphicsDevice *device, + void *driver_data, + ScreenFuncs *funcs, + ScreenFuncs *primary_funcs, + void **primary_driver_data ); + +/* + * Replace the default implementation for the primary screen. + */ +CoreScreen *dfb_screens_register_primary( CoreGraphicsDevice *device, + void *driver_data, + ScreenFuncs *funcs ); + +/* + * Enumerate all registered screens by invoking the callback for each screen. + */ +void dfb_screens_enumerate( CoreScreenCallback callback, + void *ctx ); + +/* + * Returns the screen with the specified ID. + */ +CoreScreen *dfb_screens_at( DFBScreenID screen_id ); + +CoreScreen *dfb_screens_at_translated( DFBScreenID screen_id ); + +/* + * Return the (translated) ID of the specified screen. + */ +DFBScreenID dfb_screen_id_translated( CoreScreen *screen ); + +#endif diff --git a/Source/DirectFB/src/core/screens_internal.h b/Source/DirectFB/src/core/screens_internal.h new file mode 100755 index 0000000..361b571 --- /dev/null +++ b/Source/DirectFB/src/core/screens_internal.h @@ -0,0 +1,81 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef __DFB__CORE__SCREENS_INTERNAL_H__ +#define __DFB__CORE__SCREENS_INTERNAL_H__ + +#include + +#include + +#include +#include + +typedef struct { + DFBScreenMixerDescription description; + DFBScreenMixerConfig configuration; +} CoreScreenMixer; + +typedef struct { + DFBScreenEncoderDescription description; + DFBScreenEncoderConfig configuration; +} CoreScreenEncoder; + +typedef struct { + DFBScreenOutputDescription description; + DFBScreenOutputConfig configuration; +} CoreScreenOutput; + +typedef struct { + FusionSkirmish lock; + + DFBScreenID screen_id; + + DFBScreenDescription description; + + CoreScreenMixer *mixers; + CoreScreenEncoder *encoders; + CoreScreenOutput *outputs; + + void *screen_data; +} CoreScreenShared; + +struct __DFB_CoreScreen { + CoreScreenShared *shared; + + CoreDFB *core; + CoreGraphicsDevice *device; + + ScreenFuncs *funcs; + + void *driver_data; + void *screen_data; /* copy of shared->screen_data */ +}; + +#endif + diff --git a/Source/DirectFB/src/core/shared_surface_pool.c b/Source/DirectFB/src/core/shared_surface_pool.c new file mode 100755 index 0000000..5199a84 --- /dev/null +++ b/Source/DirectFB/src/core/shared_surface_pool.c @@ -0,0 +1,227 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include + +#include + +#include +#include +#include + +#include +#include + +#include + +/**********************************************************************************************************************/ + +typedef struct { + FusionSHMPoolShared *shmpool; +} SharedPoolData; + +typedef struct { + CoreDFB *core; + FusionWorld *world; +} SharedPoolLocalData; + +typedef struct { + void *addr; + int pitch; + int size; +} SharedAllocationData; + +/**********************************************************************************************************************/ + +static int +sharedPoolDataSize( void ) +{ + return sizeof(SharedPoolData); +} + +static int +sharedPoolLocalDataSize( void ) +{ + return sizeof(SharedPoolLocalData); +} + +static int +sharedAllocationDataSize( void ) +{ + return sizeof(SharedAllocationData); +} + +static DFBResult +sharedInitPool( CoreDFB *core, + CoreSurfacePool *pool, + void *pool_data, + void *pool_local, + void *system_data, + CoreSurfacePoolDescription *ret_desc ) +{ + DFBResult ret; + SharedPoolData *data = pool_data; + SharedPoolLocalData *local = pool_local; + + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + D_ASSERT( ret_desc != NULL ); + + local->core = core; + local->world = dfb_core_world( core ); + + ret = fusion_shm_pool_create( local->world, "Surface Memory Pool", dfb_config->surface_shmpool_size, + fusion_config->debugshm, &data->shmpool ); + if (ret) + return ret; + + ret_desc->caps = CSPCAPS_NONE; + ret_desc->access[CSAID_CPU] = CSAF_READ | CSAF_WRITE | CSAF_SHARED; + ret_desc->access[CSAID_LAYER0] = CSAF_READ | CSAF_SHARED; + ret_desc->access[CSAID_LAYER1] = CSAF_READ | CSAF_SHARED; + ret_desc->types = CSTF_LAYER | CSTF_WINDOW | CSTF_CURSOR | CSTF_FONT | CSTF_SHARED | CSTF_INTERNAL; + ret_desc->priority = CSPP_DEFAULT; + + snprintf( ret_desc->name, DFB_SURFACE_POOL_DESC_NAME_LENGTH, "Shared Memory" ); + + return DFB_OK; +} + +static DFBResult +sharedDestroyPool( CoreSurfacePool *pool, + void *pool_data, + void *pool_local ) +{ + SharedPoolData *data = pool_data; + SharedPoolLocalData *local = pool_local; + + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + + fusion_shm_pool_destroy( local->world, data->shmpool ); + + return DFB_OK; +} + +static DFBResult +sharedAllocateBuffer( CoreSurfacePool *pool, + void *pool_data, + void *pool_local, + CoreSurfaceBuffer *buffer, + CoreSurfaceAllocation *allocation, + void *alloc_data ) +{ + CoreSurface *surface; + SharedPoolData *data = pool_data; + SharedAllocationData *alloc = alloc_data; + + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + + surface = buffer->surface; + + D_MAGIC_ASSERT( surface, CoreSurface ); + + dfb_surface_calc_buffer_size( surface, 8, 0, &alloc->pitch, &alloc->size ); + + alloc->addr = SHMALLOC( data->shmpool, alloc->size ); + if (!alloc->addr) + return D_OOSHM(); + + allocation->flags = CSALF_VOLATILE; + allocation->size = alloc->size; + + return DFB_OK; +} + +static DFBResult +sharedDeallocateBuffer( CoreSurfacePool *pool, + void *pool_data, + void *pool_local, + CoreSurfaceBuffer *buffer, + CoreSurfaceAllocation *allocation, + void *alloc_data ) +{ + SharedPoolData *data = pool_data; + SharedAllocationData *alloc = alloc_data; + + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + + SHFREE( data->shmpool, alloc->addr ); + + return DFB_OK; +} + +static DFBResult +sharedLock( CoreSurfacePool *pool, + void *pool_data, + void *pool_local, + CoreSurfaceAllocation *allocation, + void *alloc_data, + CoreSurfaceBufferLock *lock ) +{ + SharedAllocationData *alloc = alloc_data; + + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); + D_MAGIC_ASSERT( lock, CoreSurfaceBufferLock ); + + lock->addr = alloc->addr; + lock->pitch = alloc->pitch; + + return DFB_OK; +} + +static DFBResult +sharedUnlock( CoreSurfacePool *pool, + void *pool_data, + void *pool_local, + CoreSurfaceAllocation *allocation, + void *alloc_data, + CoreSurfaceBufferLock *lock ) +{ + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); + D_MAGIC_ASSERT( lock, CoreSurfaceBufferLock ); + + return DFB_OK; +} + +const SurfacePoolFuncs sharedSurfacePoolFuncs = { + .PoolDataSize = sharedPoolDataSize, + .PoolLocalDataSize = sharedPoolLocalDataSize, + .AllocationDataSize = sharedAllocationDataSize, + .InitPool = sharedInitPool, + .DestroyPool = sharedDestroyPool, + + .AllocateBuffer = sharedAllocateBuffer, + .DeallocateBuffer = sharedDeallocateBuffer, + + .Lock = sharedLock, + .Unlock = sharedUnlock, +}; + diff --git a/Source/DirectFB/src/core/state.c b/Source/DirectFB/src/core/state.c new file mode 100755 index 0000000..8ae97e0 --- /dev/null +++ b/Source/DirectFB/src/core/state.c @@ -0,0 +1,416 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include + +#include + +#include + +#include +#include + +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + + +static inline void +validate_clip( CardState *state, + int xmax, + int ymax, + bool warn ) +{ + D_MAGIC_ASSERT( state, CardState ); + DFB_REGION_ASSERT( &state->clip ); + + D_ASSERT( xmax >= 0 ); + D_ASSERT( ymax >= 0 ); + D_ASSERT( state->clip.x1 <= state->clip.x2 ); + D_ASSERT( state->clip.y1 <= state->clip.y2 ); + + if (state->clip.x1 <= xmax && + state->clip.y1 <= ymax && + state->clip.x2 <= xmax && + state->clip.y2 <= ymax) + return; + + if (warn) + D_WARN( "Clip %d,%d-%dx%d invalid, adjusting to fit %dx%d", + DFB_RECTANGLE_VALS_FROM_REGION( &state->clip ), xmax+1, ymax+1 ); + + if (state->clip.x1 > xmax) + state->clip.x1 = xmax; + + if (state->clip.y1 > ymax) + state->clip.y1 = ymax; + + if (state->clip.x2 > xmax) + state->clip.x2 = xmax; + + if (state->clip.y2 > ymax) + state->clip.y2 = ymax; + + state->modified |= SMF_CLIP; +} + +int +dfb_state_init( CardState *state, CoreDFB *core ) +{ + D_ASSERT( state != NULL ); + + memset( state, 0, sizeof(CardState) ); + + state->core = core; + state->fusion_id = fusion_id( dfb_core_world(core) ); + state->modified = SMF_ALL; + state->src_blend = DSBF_SRCALPHA; + state->dst_blend = DSBF_INVSRCALPHA; + state->render_options = dfb_config->render_options; + + state->matrix[0] = 0x10000; + state->matrix[1] = 0x00000; + state->matrix[2] = 0x00000; + state->matrix[3] = 0x00000; + state->matrix[4] = 0x10000; + state->matrix[5] = 0x00000; + state->matrix[6] = 0x00000; + state->matrix[7] = 0x00000; + state->matrix[8] = 0x10000; + state->affine_matrix = DFB_TRUE; + + state->from = CSBR_FRONT; + state->to = CSBR_BACK; + + direct_util_recursive_pthread_mutex_init( &state->lock ); + + direct_serial_init( &state->dst_serial ); + direct_serial_init( &state->src_serial ); + direct_serial_init( &state->src_mask_serial ); + + D_MAGIC_SET( state, CardState ); + + return 0; +} + +void +dfb_state_destroy( CardState *state ) +{ + D_MAGIC_ASSERT( state, CardState ); + + D_ASSUME( !(state->flags & CSF_DRAWING) ); + + D_ASSERT( state->destination == NULL ); + D_ASSERT( state->source == NULL ); + D_ASSERT( state->source_mask == NULL ); + + D_MAGIC_CLEAR( state ); + + direct_serial_deinit( &state->dst_serial ); + direct_serial_deinit( &state->src_serial ); + direct_serial_deinit( &state->src_mask_serial ); + + if (state->gfxs) { + GenefxState *gfxs = state->gfxs; + + if (gfxs->ABstart) + D_FREE( gfxs->ABstart ); + + D_FREE( gfxs ); + } + + if (state->num_translation) { + D_ASSERT( state->index_translation != NULL ); + + D_FREE( state->index_translation ); + } + else + D_ASSERT( state->index_translation == NULL ); + + pthread_mutex_destroy( &state->lock ); +} + +DFBResult +dfb_state_set_destination( CardState *state, CoreSurface *destination ) +{ + D_MAGIC_ASSERT( state, CardState ); + + dfb_state_lock( state ); + + D_ASSUME( !(state->flags & CSF_DRAWING) ); + + if (state->destination != destination) { + if (destination) { + if (dfb_surface_ref( destination )) { + D_WARN( "could not ref() destination" ); + dfb_state_unlock( state ); + return DFB_DEAD; + } + + validate_clip( state, destination->config.size.w - 1, destination->config.size.h - 1, false ); + } + + if (state->destination) { + D_ASSERT( D_FLAGS_IS_SET( state->flags, CSF_DESTINATION ) ); + dfb_surface_unref( state->destination ); + } + + state->destination = destination; + state->modified |= SMF_DESTINATION; + + if (destination) { + direct_serial_copy( &state->dst_serial, &destination->serial ); + + D_FLAGS_SET( state->flags, CSF_DESTINATION ); + } + else + D_FLAGS_CLEAR( state->flags, CSF_DESTINATION ); + } + + dfb_state_unlock( state ); + + return DFB_OK; +} + +DFBResult +dfb_state_set_source( CardState *state, CoreSurface *source ) +{ + D_MAGIC_ASSERT( state, CardState ); + + dfb_state_lock( state ); + + if (state->source != source) { + if (source && dfb_surface_ref( source )) { + D_WARN( "could not ref() source" ); + dfb_state_unlock( state ); + return DFB_DEAD; + } + + if (state->source) { + D_ASSERT( D_FLAGS_IS_SET( state->flags, CSF_SOURCE ) ); + dfb_surface_unref( state->source ); + } + + state->source = source; + state->modified |= SMF_SOURCE; + + if (source) { + direct_serial_copy( &state->src_serial, &source->serial ); + + D_FLAGS_SET( state->flags, CSF_SOURCE ); + } + else + D_FLAGS_CLEAR( state->flags, CSF_SOURCE ); + } + + dfb_state_unlock( state ); + + return DFB_OK; +} + +DFBResult +dfb_state_set_source_mask( CardState *state, CoreSurface *source_mask ) +{ + D_MAGIC_ASSERT( state, CardState ); + + dfb_state_lock( state ); + + if (state->source_mask != source_mask) { + if (source_mask && dfb_surface_ref( source_mask )) { + D_WARN( "could not ref() source mask" ); + dfb_state_unlock( state ); + return DFB_DEAD; + } + + if (state->source_mask) { + D_ASSERT( D_FLAGS_IS_SET( state->flags, CSF_SOURCE_MASK ) ); + dfb_surface_unref( state->source_mask ); + } + + state->source_mask = source_mask; + state->modified |= SMF_SOURCE_MASK; + + if (source_mask) { + direct_serial_copy( &state->src_mask_serial, &source_mask->serial ); + + D_FLAGS_SET( state->flags, CSF_SOURCE_MASK ); + } + else + D_FLAGS_CLEAR( state->flags, CSF_SOURCE_MASK ); + } + + dfb_state_unlock( state ); + + return DFB_OK; +} + +void +dfb_state_update( CardState *state, bool update_sources ) +{ + CoreSurface *destination; + + D_MAGIC_ASSERT( state, CardState ); + DFB_REGION_ASSERT( &state->clip ); + + destination = state->destination; + + if (D_FLAGS_IS_SET( state->flags, CSF_DESTINATION )) { + + D_ASSERT( destination != NULL ); + + if (direct_serial_update( &state->dst_serial, &destination->serial )) { + validate_clip( state, destination->config.size.w - 1, destination->config.size.h - 1, true ); + + state->modified |= SMF_DESTINATION; + } + } + else if (destination) + validate_clip( state, destination->config.size.w - 1, destination->config.size.h - 1, true ); + + if (update_sources && D_FLAGS_IS_SET( state->flags, CSF_SOURCE )) { + CoreSurface *source = state->source; + + D_ASSERT( source != NULL ); + + if (direct_serial_update( &state->src_serial, &source->serial )) + state->modified |= SMF_SOURCE; + } + + if (update_sources && D_FLAGS_IS_SET( state->flags, CSF_SOURCE_MASK )) { + CoreSurface *source_mask = state->source_mask; + + D_ASSERT( source_mask != NULL ); + + if (direct_serial_update( &state->src_mask_serial, &source_mask->serial )) + state->modified |= SMF_SOURCE_MASK; + } +} + +DFBResult +dfb_state_set_index_translation( CardState *state, + const int *indices, + int num_indices ) +{ + D_MAGIC_ASSERT( state, CardState ); + + D_ASSERT( indices != NULL || num_indices == 0 ); + + dfb_state_lock( state ); + + if (state->num_translation != num_indices) { + int *new_trans = D_REALLOC( state->index_translation, + num_indices * sizeof(int) ); + + D_ASSERT( num_indices || new_trans == NULL ); + + if (num_indices && !new_trans) { + dfb_state_unlock( state ); + return D_OOM(); + } + + state->index_translation = new_trans; + state->num_translation = num_indices; + } + + if (num_indices) + direct_memcpy( state->index_translation, indices, num_indices * sizeof(int) ); + + state->modified |= SMF_INDEX_TRANSLATION; + + dfb_state_unlock( state ); + + return DFB_OK; +} + +void +dfb_state_set_matrix( CardState *state, + const s32 *matrix ) +{ + D_MAGIC_ASSERT( state, CardState ); + + D_ASSERT( matrix != NULL ); + + if (memcmp( state->matrix, matrix, sizeof(state->matrix) )) { + direct_memcpy( state->matrix, matrix, sizeof(state->matrix) ); + + state->affine_matrix = (matrix[6] == 0x00000 && + matrix[7] == 0x00000 && + matrix[8] == 0x10000); + + state->modified |= SMF_MATRIX; + } +} + +void +dfb_state_set_color_or_index( CardState *state, + const DFBColor *color, + int index ) +{ + CoreSurface *destination; + CorePalette *palette = NULL; + + D_MAGIC_ASSERT( state, CardState ); + D_ASSERT( color != NULL ); + + destination = state->destination; + if (destination) + palette = destination->palette; + + if (index < 0) { + D_ASSERT( color != NULL ); + + if (palette) + dfb_state_set_color_index( state, dfb_palette_search( palette, + color->r, color->g, + color->b, color->a ) ); + + dfb_state_set_color( state, color ); + } + else { + dfb_state_set_color_index( state, index ); + + if (palette) { + D_ASSERT( palette->num_entries > 0 ); + D_ASSUME( palette->num_entries > index ); + + dfb_state_set_color( state, &palette->entries[index % palette->num_entries] ); + } + } +} + diff --git a/Source/DirectFB/src/core/state.h b/Source/DirectFB/src/core/state.h new file mode 100755 index 0000000..7eb7667 --- /dev/null +++ b/Source/DirectFB/src/core/state.h @@ -0,0 +1,362 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef __CORE__STATE_H__ +#define __CORE__STATE_H__ + +#include + +#include + +#include + +#include + +#include +#include +#include +#include + +#include + +#include +#include + + +typedef enum { + SMF_DRAWING_FLAGS = 0x00000001, + SMF_BLITTING_FLAGS = 0x00000002, + SMF_CLIP = 0x00000004, + SMF_COLOR = 0x00000008, + SMF_SRC_BLEND = 0x00000010, + SMF_DST_BLEND = 0x00000020, + SMF_SRC_COLORKEY = 0x00000040, + SMF_DST_COLORKEY = 0x00000080, + + SMF_DESTINATION = 0x00000100, + SMF_SOURCE = 0x00000200, + SMF_SOURCE_MASK = 0x00000400, + SMF_SOURCE_MASK_VALS = 0x00000800, + + SMF_INDEX_TRANSLATION = 0x00001000, + SMF_COLORKEY = 0x00002000, + + SMF_RENDER_OPTIONS = 0x00010000, + SMF_MATRIX = 0x00020000, + + SMF_ALL = 0x00033FFF +} StateModificationFlags; + +typedef enum { + CSF_NONE = 0x00000000, + + CSF_DESTINATION = 0x00000001, /* destination is set using dfb_state_set_destination() */ + CSF_SOURCE = 0x00000002, /* source is set using dfb_state_set_source() */ + CSF_SOURCE_MASK = 0x00000008, /* source mask is set using dfb_state_set_source_mask() */ + + CSF_SOURCE_LOCKED = 0x00000010, /* source surface is locked */ + CSF_SOURCE_MASK_LOCKED = 0x00000020, /* source mask surface is locked */ + + CSF_DRAWING = 0x00010000, /* something has been rendered with this state, + this is cleared by flushing the state, e.g. upon flip */ + + CSF_ALL = 0x0001003B +} CardStateFlags; + +struct _CardState { + int magic; + + CoreDFB *core; + CoreGraphicsDevice *device; + FusionID fusion_id; + + pthread_mutex_t lock; /* lock for state handling */ + + CardStateFlags flags; + + StateModificationFlags modified; /* indicate which fields have been + modified, these flags will be + cleared by the gfx drivers */ + StateModificationFlags mod_hw; + + /* values forming the state for graphics operations */ + + DFBSurfaceDrawingFlags drawingflags; /* drawing flags */ + DFBSurfaceBlittingFlags blittingflags; /* blitting flags */ + + DFBRegion clip; /* clipping rectangle */ + DFBColor color; /* color for drawing or modulation */ + unsigned int color_index; /* index to color in palette */ + DFBSurfaceBlendFunction src_blend; /* blend function for source */ + DFBSurfaceBlendFunction dst_blend; /* blend function for destination */ + u32 src_colorkey; /* colorkey for source */ + u32 dst_colorkey; /* colorkey for destination */ + + CoreSurface *destination; /* destination surface */ + CoreSurface *source; /* source surface */ + + DirectSerial dst_serial; /* last destination surface serial */ + DirectSerial src_serial; /* last source surface serial */ + + int *index_translation; + int num_translation; + + /* hardware abstraction and state handling helpers */ + + DFBAccelerationMask accel; /* remember checked commands if they are accelerated */ + DFBAccelerationMask checked; /* commands for which a state has been checked */ + DFBAccelerationMask set; /* commands for which a state is valid */ + DFBAccelerationMask disabled; /* commands which are disabled temporarily */ + + CoreGraphicsSerial serial; /* hardware serial of the last operation */ + + /* from/to buffers */ + + CoreSurfaceBufferRole from; /* usually CSBR_FRONT */ + CoreSurfaceBufferRole to; /* usually CSBR_BACK */ + + /* read/write locks during operation */ + + CoreSurfaceBufferLock dst; + CoreSurfaceBufferLock src; + + /* software driver */ + + GenefxState *gfxs; + + + /* extended state */ + + DFBSurfaceRenderOptions render_options; + + DFBColorKey colorkey; /* key for color key protection */ + + s32 matrix[9]; /* transformation matrix for DSRO_MATRIX (fixed 16.16) */ + DFBBoolean affine_matrix; + + CoreSurface *source_mask; /* source mask surface */ + CoreSurfaceBufferLock src_mask; /* source mask surface lock */ + DirectSerial src_mask_serial; /* last source mask surface serial */ + DFBPoint src_mask_offset; /* relative or absolute coordinates */ + DFBSurfaceMaskFlags src_mask_flags; /* controls coordinate mode and more */ + + DFBColor colors[DFB_COLOR_IDS_MAX]; /* colors for drawing or modulation */ + unsigned int color_indices[DFB_COLOR_IDS_MAX]; /* indices to colors in palette */ +}; + +int dfb_state_init( CardState *state, CoreDFB *core ); +void dfb_state_destroy( CardState *state ); + +DFBResult dfb_state_set_destination( CardState *state, CoreSurface *destination ); +DFBResult dfb_state_set_source( CardState *state, CoreSurface *source ); +DFBResult dfb_state_set_source_mask( CardState *state, CoreSurface *source_mask ); + +void dfb_state_update( CardState *state, bool update_source ); + +DFBResult dfb_state_set_index_translation( CardState *state, + const int *indices, + int num_indices ); + +void dfb_state_set_matrix( CardState *state, + const s32 *matrix ); + +static inline void +dfb_state_get_serial( const CardState *state, CoreGraphicsSerial *ret_serial ) +{ + D_ASSERT( state != NULL ); + D_ASSERT( ret_serial != NULL ); + + *ret_serial = state->serial; +} + +static inline void +dfb_state_lock( CardState *state ) +{ + D_MAGIC_ASSERT( state, CardState ); + + DFB_REGION_ASSERT( &state->clip ); + + pthread_mutex_lock( &state->lock ); +} + +static inline void +dfb_state_start_drawing( CardState *state, CoreGraphicsDevice *device ) +{ + D_MAGIC_ASSERT( state, CardState ); + D_ASSERT( device != NULL ); + D_ASSERT( state->destination != NULL ); + + if (dfb_config->startstop) { + if (state->flags & CSF_DRAWING) + D_ASSERT( state->device == device ); + else { + dfb_gfxcard_start_drawing( device, state ); + + state->flags = (CardStateFlags)(state->flags | CSF_DRAWING); + state->device = device; + } + } +} + +static inline void +dfb_state_stop_drawing( CardState *state ) +{ + D_MAGIC_ASSERT( state, CardState ); + D_ASSERT( state->destination != NULL ); + + if (dfb_config->startstop) { + if (state->flags & CSF_DRAWING) { + D_ASSERT( state->device != NULL ); + + dfb_gfxcard_stop_drawing( state->device, state ); + + state->flags = (CardStateFlags)(state->flags & ~CSF_DRAWING); + state->device = NULL; + } + else + D_ASSERT( state->device == NULL ); + } +} + +static inline void +dfb_state_unlock( CardState *state ) +{ + D_MAGIC_ASSERT( state, CardState ); + + DFB_REGION_ASSERT( &state->clip ); + + pthread_mutex_unlock( &state->lock ); +} + + +#define _dfb_state_set_checked(member,flag,state,value) \ +do { \ + D_MAGIC_ASSERT( state, CardState ); \ + \ + if ((value) != (state)->member) { \ + (state)->member = (value); \ + (state)->modified |= SMF_##flag; \ + } \ +} while (0) + + +#define dfb_state_set_blitting_flags(state,flags) _dfb_state_set_checked( blittingflags, \ + BLITTING_FLAGS, \ + state, flags ) + +#define dfb_state_set_drawing_flags(state,flags) _dfb_state_set_checked( drawingflags, \ + DRAWING_FLAGS, \ + state, flags ) + +#define dfb_state_set_color_index(state,index) _dfb_state_set_checked( color_index, \ + COLOR, \ + state, index ) + +#define dfb_state_set_src_blend(state,blend) _dfb_state_set_checked( src_blend, \ + SRC_BLEND, \ + state, blend ) + +#define dfb_state_set_dst_blend(state,blend) _dfb_state_set_checked( dst_blend, \ + DST_BLEND, \ + state, blend ) + +#define dfb_state_set_src_colorkey(state,key) _dfb_state_set_checked( src_colorkey, \ + SRC_COLORKEY, \ + state, key ) + +#define dfb_state_set_dst_colorkey(state,key) _dfb_state_set_checked( dst_colorkey, \ + DST_COLORKEY, \ + state, key ) + +#define dfb_state_set_render_options(state,opts) _dfb_state_set_checked( render_options, \ + RENDER_OPTIONS, \ + state, opts ) + +static inline void dfb_state_set_clip( CardState *state, const DFBRegion *clip ) +{ + D_MAGIC_ASSERT( state, CardState ); + DFB_REGION_ASSERT( clip ); + + if (! DFB_REGION_EQUAL( state->clip, *clip )) { + state->clip = *clip; + state->modified = (StateModificationFlags)( state->modified | SMF_CLIP ); + } +} + +static inline void dfb_state_set_color( CardState *state, const DFBColor *color ) +{ + D_MAGIC_ASSERT( state, CardState ); + D_ASSERT( color != NULL ); + + if (! DFB_COLOR_EQUAL( state->color, *color )) { + state->color = *color; + state->modified = (StateModificationFlags)( state->modified | SMF_COLOR ); + } +} + +static inline void dfb_state_set_colorkey( CardState *state, const DFBColorKey *key ) +{ + D_MAGIC_ASSERT( state, CardState ); + D_ASSERT( key != NULL ); + + if (! DFB_COLORKEY_EQUAL( state->colorkey, *key )) { + state->colorkey = *key; + state->modified = (StateModificationFlags)( state->modified | SMF_COLOR ); + } +} + +static inline void dfb_state_set_source_mask_vals( CardState *state, + const DFBPoint *offset, + DFBSurfaceMaskFlags flags ) +{ + D_MAGIC_ASSERT( state, CardState ); + D_ASSERT( offset != NULL ); + D_FLAGS_ASSERT( flags, DSMF_ALL ); + + if (! DFB_POINT_EQUAL( state->src_mask_offset, *offset ) || state->src_mask_flags != flags) { + state->src_mask_offset = *offset; + state->src_mask_flags = flags; + + state->modified = (StateModificationFlags)( state->modified | SMF_SOURCE_MASK_VALS ); + } +} + +/* + * Multifunctional color configuration function. + * + * Always tries to set both color and index. + * + * If color index is -1, color is used and searched in palette of destination surface if present. + * If color index is valid the color is looked up in palette if present. + */ +void dfb_state_set_color_or_index( CardState *state, + const DFBColor *color, + int index ); + +#endif + diff --git a/Source/DirectFB/src/core/surface.c b/Source/DirectFB/src/core/surface.c new file mode 100755 index 0000000..7b8e4fc --- /dev/null +++ b/Source/DirectFB/src/core/surface.c @@ -0,0 +1,768 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include + +#include + +#include +#include +#include + +#include +#include + +#include + + +D_DEBUG_DOMAIN( Core_Surface, "Core/Surface", "DirectFB Core Surface" ); + +/**********************************************************************************************************************/ + +static const ReactionFunc dfb_surface_globals[] = { +/* 0 */ _dfb_layer_region_surface_listener, +/* 1 */ _dfb_windowstack_background_image_listener, + NULL +}; + +static void +surface_destructor( FusionObject *object, bool zombie, void *ctx ) +{ + int i; + CoreSurface *surface = (CoreSurface*) object; + + D_MAGIC_ASSERT( surface, CoreSurface ); + + D_DEBUG_AT( Core_Surface, "destroying %p (%dx%d%s)\n", surface, + surface->config.size.w, surface->config.size.h, zombie ? " ZOMBIE" : ""); + + dfb_surface_lock( surface ); + + surface->state |= CSSF_DESTROYED; + + /* announce surface destruction */ + dfb_surface_notify( surface, CSNF_DESTROY ); + + /* unlink palette */ + if (surface->palette) { + dfb_palette_detach_global( surface->palette, &surface->palette_reaction ); + dfb_palette_unlink( &surface->palette ); + } + + /* destroy buffers */ + for (i=0; ibuffers[i]) + dfb_surface_buffer_destroy( surface->buffers[i] ); + } + + direct_serial_deinit( &surface->serial ); + + dfb_surface_unlock( surface ); + + fusion_skirmish_destroy( &surface->lock ); + + D_MAGIC_CLEAR( surface ); + + fusion_object_destroy( object ); +} + +FusionObjectPool * +dfb_surface_pool_create( const FusionWorld *world ) +{ + FusionObjectPool *pool; + + pool = fusion_object_pool_create( "Surface Pool", + sizeof(CoreSurface), + sizeof(CoreSurfaceNotification), + surface_destructor, NULL, world ); + + return pool; +} + +/**********************************************************************************************************************/ + +DFBResult +dfb_surface_create( CoreDFB *core, + const CoreSurfaceConfig *config, + CoreSurfaceTypeFlags type, + unsigned long resource_id, + CorePalette *palette, + CoreSurface **ret_surface ) +{ + DFBResult ret = DFB_BUG; + int i; + int buffers; + CoreSurface *surface; + char buf[64]; + + D_ASSERT( core != NULL ); + D_FLAGS_ASSERT( type, CSTF_ALL ); + D_MAGIC_ASSERT_IF( palette, CorePalette ); + D_ASSERT( ret_surface != NULL ); + + D_DEBUG_AT( Core_Surface, "dfb_surface_create( %p, %p, %p )\n", core, config, ret_surface ); + + surface = dfb_core_create_surface( core ); + if (!surface) + return DFB_FUSION; + + if (config) { + D_FLAGS_ASSERT( config->flags, CSCONF_ALL ); + + surface->config.flags = config->flags; + + if (config->flags & CSCONF_SIZE) { + D_DEBUG_AT( Core_Surface, " -> %dx%d\n", config->size.w, config->size.h ); + + surface->config.size = config->size; + } + + if (config->flags & CSCONF_FORMAT) { + D_DEBUG_AT( Core_Surface, " -> %s\n", dfb_pixelformat_name( config->format ) ); + + surface->config.format = config->format; + } + + if (config->flags & CSCONF_CAPS) { + D_DEBUG_AT( Core_Surface, " -> caps 0x%08x\n", config->caps ); + + if (config->caps & DSCAPS_ROTATED) + D_UNIMPLEMENTED(); + + surface->config.caps = config->caps & ~DSCAPS_ROTATED; + } + + if (config->flags & CSCONF_PREALLOCATED) { + D_DEBUG_AT( Core_Surface, " -> prealloc %p [%d]\n", + config->preallocated[0].addr, + config->preallocated[0].pitch ); + + direct_memcpy( surface->config.preallocated, config->preallocated, sizeof(config->preallocated) ); + + type |= CSTF_PREALLOCATED; + } + } + + if (surface->config.caps & DSCAPS_SYSTEMONLY) + surface->type = (type & ~CSTF_EXTERNAL) | CSTF_INTERNAL; + else if (surface->config.caps & DSCAPS_VIDEOONLY) + surface->type = (type & ~CSTF_INTERNAL) | CSTF_EXTERNAL; + else + surface->type = type & ~(CSTF_INTERNAL | CSTF_EXTERNAL); + + if (surface->config.caps & DSCAPS_SHARED) + surface->type |= CSTF_SHARED; + + surface->resource_id = resource_id; + + if (surface->config.caps & DSCAPS_TRIPLE) + buffers = 3; + else if (surface->config.caps & DSCAPS_DOUBLE) + buffers = 2; + else { + buffers = 1; + + surface->config.caps &= ~DSCAPS_ROTATED; + } + + surface->notifications = CSNF_ALL & ~CSNF_FLIP; + + surface->alpha_ramp[0] = 0x00; + surface->alpha_ramp[1] = 0x55; + surface->alpha_ramp[2] = 0xaa; + surface->alpha_ramp[3] = 0xff; + + + if (surface->config.caps & DSCAPS_STATIC_ALLOC) + surface->config.min_size = surface->config.size; + + surface->shmpool = dfb_core_shmpool( core ); + + direct_serial_init( &surface->serial ); + + snprintf( buf, sizeof(buf), "Surface %dx%d %s", surface->config.size.w, + surface->config.size.h, dfb_pixelformat_name(surface->config.format) ); + + fusion_ref_set_name( &surface->object.ref, buf ); + + fusion_skirmish_init( &surface->lock, buf, dfb_core_world(core) ); + + fusion_object_set_lock( &surface->object, &surface->lock ); + + D_MAGIC_SET( surface, CoreSurface ); + + + if (dfb_config->warn.flags & DCWF_CREATE_SURFACE && + dfb_config->warn.create_surface.min_size.w <= surface->config.size.w && + dfb_config->warn.create_surface.min_size.h <= surface->config.size.h) + D_WARN( "create-surface %4dx%4d %6s, buffers %d, caps 0x%08x, type 0x%08x", + surface->config.size.w, surface->config.size.h, dfb_pixelformat_name(surface->config.format), + buffers, surface->config.caps, surface->type ); + + + if (palette) { + dfb_surface_set_palette( surface, palette ); + } + else if (DFB_PIXELFORMAT_IS_INDEXED( surface->config.format )) { + ret = dfb_surface_init_palette( core, surface ); + if (ret) + goto error; + } + + /* Create the Surface Buffers. */ + for (i=0; ibuffers[surface->num_buffers++] = buffer; + + switch (i) { + case 0: + surface->buffer_indices[CSBR_FRONT] = i; + case 1: + surface->buffer_indices[CSBR_BACK] = i; + case 2: + surface->buffer_indices[CSBR_IDLE] = i; + } + } + + fusion_object_activate( &surface->object ); + + *ret_surface = surface; + + return DFB_OK; + +error: + D_MAGIC_CLEAR( surface ); + + for (i=0; ibuffers[i]) + dfb_surface_buffer_destroy( surface->buffers[i] ); + } + + fusion_skirmish_destroy( &surface->lock ); + + direct_serial_deinit( &surface->serial ); + + fusion_object_destroy( &surface->object ); + + return ret; +} + +DFBResult +dfb_surface_create_simple ( CoreDFB *core, + int width, + int height, + DFBSurfacePixelFormat format, + DFBSurfaceCapabilities caps, + CoreSurfaceTypeFlags type, + unsigned long resource_id, + CorePalette *palette, + CoreSurface **ret_surface ) +{ + CoreSurfaceConfig config; + + D_DEBUG_AT( Core_Surface, "%s( %p, %dx%d %s, %p )\n", __FUNCTION__, core, width, height, + dfb_pixelformat_name( format ), ret_surface ); + + D_ASSERT( core != NULL ); + D_ASSERT( ret_surface != NULL ); + + config.flags = CSCONF_SIZE | CSCONF_FORMAT | CSCONF_CAPS; + config.size.w = width; + config.size.h = height; + config.format = format; + config.caps = caps; + + return dfb_surface_create( core, &config, type, resource_id, palette, ret_surface ); +} + +DFBResult +dfb_surface_init_palette( CoreDFB *core, + CoreSurface *surface ) +{ + DFBResult ret; + CorePalette *palette; + + ret = dfb_palette_create( core, + 1 << DFB_COLOR_BITS_PER_PIXEL( surface->config.format ), + &palette ); + if (ret) { + D_DERROR( ret, "Core/Surface: Error creating palette!\n" ); + return ret; + } + + switch (surface->config.format) { + case DSPF_LUT8: + dfb_palette_generate_rgb332_map( palette ); + break; + + case DSPF_ALUT44: + dfb_palette_generate_rgb121_map( palette ); + break; + + default: + break; + } + + dfb_surface_set_palette( surface, palette ); + + dfb_palette_unref( palette ); + + return DFB_OK; +} + + +DFBResult +dfb_surface_notify( CoreSurface *surface, + CoreSurfaceNotificationFlags flags) +{ + CoreSurfaceNotification notification; + + D_MAGIC_ASSERT( surface, CoreSurface ); + FUSION_SKIRMISH_ASSERT( &surface->lock ); + D_FLAGS_ASSERT( flags, CSNF_ALL ); + + direct_serial_increase( &surface->serial ); + + if (!(surface->state & CSSF_DESTROYED)) { + if (!(surface->notifications & flags)) + return DFB_OK; + } + + notification.flags = flags; + notification.surface = surface; + + return dfb_surface_dispatch( surface, ¬ification, dfb_surface_globals ); +} + +DFBResult +dfb_surface_flip( CoreSurface *surface, bool swap ) +{ + unsigned int back, front; + + D_MAGIC_ASSERT( surface, CoreSurface ); + + FUSION_SKIRMISH_ASSERT( &surface->lock ); + + back = (surface->flips + CSBR_BACK) % surface->num_buffers; + front = (surface->flips + CSBR_FRONT) % surface->num_buffers; + + D_ASSERT( surface->buffer_indices[back] < surface->num_buffers ); + D_ASSERT( surface->buffer_indices[front] < surface->num_buffers ); + + if (surface->buffers[surface->buffer_indices[back]]->policy != + surface->buffers[surface->buffer_indices[front]]->policy || (surface->config.caps & DSCAPS_ROTATED)) + return DFB_UNSUPPORTED; + + if (swap) { + int tmp = surface->buffer_indices[back]; + surface->buffer_indices[back] = surface->buffer_indices[front]; + surface->buffer_indices[front] = tmp; + } + else + surface->flips++; + + dfb_surface_notify( surface, CSNF_FLIP ); + + return DFB_OK; +} + +DFBResult +dfb_surface_reconfig( CoreSurface *surface, + const CoreSurfaceConfig *config ) +{ + int i, buffers; + DFBResult ret; + + D_DEBUG_AT( Core_Surface, "%s( %p, %dx%d %s -> %dx%d %s )\n", __FUNCTION__, surface, + surface->config.size.w, surface->config.size.h, dfb_pixelformat_name( surface->config.format ), + (config->flags & CSCONF_SIZE) ? config->size.w : surface->config.size.w, + (config->flags & CSCONF_SIZE) ? config->size.h : surface->config.size.h, + (config->flags & CSCONF_FORMAT) ? dfb_pixelformat_name( config->format ) : + dfb_pixelformat_name( surface->config.format ) ); + + D_MAGIC_ASSERT( surface, CoreSurface ); + D_ASSERT( config != NULL ); + + if (surface->type & CSTF_PREALLOCATED) + return DFB_UNSUPPORTED; + + if (config->flags & CSCONF_PREALLOCATED) + return DFB_UNSUPPORTED; + + if (fusion_skirmish_prevail( &surface->lock )) + return DFB_FUSION; + + if ( (config->flags == CSCONF_SIZE || + ((config->flags == (CSCONF_SIZE | CSCONF_FORMAT)) && (config->format == surface->config.format))) && + config->size.w <= surface->config.min_size.w && + config->size.h <= surface->config.min_size.h) + { + surface->config.size = config->size; + + fusion_skirmish_dismiss( &surface->lock ); + return DFB_OK; + } + +#if 1 + /* Precheck the Surface Buffers. */ + for (i=0; inum_buffers; i++) { + if (surface->buffers[i]->locked) { + D_DEBUG_AT( Core_Surface, " -> surface is locked, cannot reconfigure!\n" ); + + fusion_skirmish_dismiss( &surface->lock ); + return DFB_LOCKED; + } + } +#endif + + /* Destroy the Surface Buffers. */ + for (i=0; inum_buffers; i++) { + dfb_surface_buffer_destroy( surface->buffers[i] ); + surface->buffers[i] = NULL; + } + + surface->num_buffers = 0; + + if (config->flags & CSCONF_SIZE) + surface->config.size = config->size; + + if (config->flags & CSCONF_FORMAT) + surface->config.format = config->format; + + if (config->flags & CSCONF_CAPS) { + if (config->caps & DSCAPS_ROTATED) + D_UNIMPLEMENTED(); + + surface->config.caps = config->caps & ~DSCAPS_ROTATED; + } + + if (surface->config.caps & DSCAPS_SYSTEMONLY) + surface->type = (surface->type & ~CSTF_EXTERNAL) | CSTF_INTERNAL; + else if (surface->config.caps & DSCAPS_VIDEOONLY) + surface->type = (surface->type & ~CSTF_INTERNAL) | CSTF_EXTERNAL; + else + surface->type = surface->type & ~(CSTF_INTERNAL | CSTF_EXTERNAL); + + if (surface->config.caps & DSCAPS_TRIPLE) + buffers = 3; + else if (surface->config.caps & DSCAPS_DOUBLE) + buffers = 2; + else { + buffers = 1; + + surface->config.caps &= ~DSCAPS_ROTATED; + } + + /* Recreate the Surface Buffers. */ + for (i=0; ibuffers[surface->num_buffers++] = buffer; + + switch (i) { + case 0: + surface->buffer_indices[CSBR_FRONT] = i; + case 1: + surface->buffer_indices[CSBR_BACK] = i; + case 2: + surface->buffer_indices[CSBR_IDLE] = i; + } + } + + dfb_surface_notify( surface, CSNF_SIZEFORMAT ); + + fusion_skirmish_dismiss( &surface->lock ); + + return DFB_OK; + +error: + D_UNIMPLEMENTED(); + + fusion_skirmish_dismiss( &surface->lock ); + + return ret; +} + +DFBResult +dfb_surface_destroy_buffers( CoreSurface *surface ) +{ + int i; + + D_MAGIC_ASSERT( surface, CoreSurface ); + + if (surface->type & CSTF_PREALLOCATED) + return DFB_UNSUPPORTED; + + if (fusion_skirmish_prevail( &surface->lock )) + return DFB_FUSION; + + /* Destroy the Surface Buffers. */ + for (i=0; inum_buffers; i++) { + dfb_surface_buffer_destroy( surface->buffers[i] ); + surface->buffers[i] = NULL; + } + + surface->num_buffers = 0; + + fusion_skirmish_dismiss( &surface->lock ); + + return DFB_OK; +} + +DFBResult +dfb_surface_lock_buffer( CoreSurface *surface, + CoreSurfaceBufferRole role, + CoreSurfaceAccessorID accessor, + CoreSurfaceAccessFlags access, + CoreSurfaceBufferLock *ret_lock ) +{ + DFBResult ret; + CoreSurfaceBuffer *buffer; + + D_MAGIC_ASSERT( surface, CoreSurface ); + + if (fusion_skirmish_prevail( &surface->lock )) + return DFB_FUSION; + + buffer = dfb_surface_get_buffer( surface, role ); + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + + ret = dfb_surface_buffer_lock( buffer, accessor, access, ret_lock ); + + fusion_skirmish_dismiss( &surface->lock ); + + return ret; +} + +DFBResult +dfb_surface_unlock_buffer( CoreSurface *surface, + CoreSurfaceBufferLock *lock ) +{ + DFBResult ret; + + D_MAGIC_ASSERT( surface, CoreSurface ); + + if (fusion_skirmish_prevail( &surface->lock )) + return DFB_FUSION; + + ret = dfb_surface_buffer_unlock( lock ); + + fusion_skirmish_dismiss( &surface->lock ); + + return ret; +} + +DFBResult +dfb_surface_read_buffer( CoreSurface *surface, + CoreSurfaceBufferRole role, + void *destination, + int pitch, + const DFBRectangle *rect ) +{ + DFBResult ret; + CoreSurfaceBuffer *buffer; + + D_MAGIC_ASSERT( surface, CoreSurface ); + D_ASSERT( destination != NULL ); + D_ASSERT( pitch > 0 ); + DFB_RECTANGLE_ASSERT_IF( rect ); + + if (fusion_skirmish_prevail( &surface->lock )) + return DFB_FUSION; + + buffer = dfb_surface_get_buffer( surface, role ); + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + + ret = dfb_surface_buffer_read( buffer, destination, pitch, rect ); + + fusion_skirmish_dismiss( &surface->lock ); + + return ret; +} + +DFBResult +dfb_surface_write_buffer( CoreSurface *surface, + CoreSurfaceBufferRole role, + const void *source, + int pitch, + const DFBRectangle *rect ) +{ + DFBResult ret; + CoreSurfaceBuffer *buffer; + + D_MAGIC_ASSERT( surface, CoreSurface ); + D_ASSERT( source != NULL ); + D_ASSERT( pitch > 0 ); + DFB_RECTANGLE_ASSERT_IF( rect ); + + if (fusion_skirmish_prevail( &surface->lock )) + return DFB_FUSION; + + buffer = dfb_surface_get_buffer( surface, role ); + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + + ret = dfb_surface_buffer_write( buffer, source, pitch, rect ); + + fusion_skirmish_dismiss( &surface->lock ); + + return ret; +} + +DFBResult +dfb_surface_dump_buffer( CoreSurface *surface, + CoreSurfaceBufferRole role, + const char *path, + const char *prefix ) +{ + DFBResult ret; + CoreSurfaceBuffer *buffer; + + D_MAGIC_ASSERT( surface, CoreSurface ); + D_ASSERT( path != NULL ); + D_ASSERT( prefix != NULL ); + + if (fusion_skirmish_prevail( &surface->lock )) + return DFB_FUSION; + + buffer = dfb_surface_get_buffer( surface, role ); + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + + ret = dfb_surface_buffer_dump( buffer, path, prefix ); + + fusion_skirmish_dismiss( &surface->lock ); + + return ret; +} + +DFBResult +dfb_surface_set_palette( CoreSurface *surface, + CorePalette *palette ) +{ + D_MAGIC_ASSERT( surface, CoreSurface ); + D_MAGIC_ASSERT_IF( palette, CorePalette ); + + if (fusion_skirmish_prevail( &surface->lock )) + return DFB_FUSION; + + if (surface->palette != palette) { + if (surface->palette) { + dfb_palette_detach_global( surface->palette, &surface->palette_reaction ); + dfb_palette_unlink( &surface->palette ); + } + + if (palette) { + dfb_palette_link( &surface->palette, palette ); + dfb_palette_attach_global( palette, DFB_SURFACE_PALETTE_LISTENER, + surface, &surface->palette_reaction ); + } + + dfb_surface_notify( surface, CSNF_PALETTE_CHANGE ); + } + + fusion_skirmish_dismiss( &surface->lock ); + + return DFB_OK; +} + +DFBResult +dfb_surface_set_field( CoreSurface *surface, + int field ) +{ + D_MAGIC_ASSERT( surface, CoreSurface ); + + if (fusion_skirmish_prevail( &surface->lock )) + return DFB_FUSION; + + surface->field = field; + + dfb_surface_notify( surface, CSNF_FIELD ); + + fusion_skirmish_dismiss( &surface->lock ); + + return DFB_OK; +} + +DFBResult +dfb_surface_set_alpha_ramp( CoreSurface *surface, + u8 a0, + u8 a1, + u8 a2, + u8 a3 ) +{ + D_MAGIC_ASSERT( surface, CoreSurface ); + + if (fusion_skirmish_prevail( &surface->lock )) + return DFB_FUSION; + + surface->alpha_ramp[0] = a0; + surface->alpha_ramp[1] = a1; + surface->alpha_ramp[2] = a2; + surface->alpha_ramp[3] = a3; + + dfb_surface_notify( surface, CSNF_ALPHA_RAMP ); + + fusion_skirmish_dismiss( &surface->lock ); + + return DFB_OK; +} + +ReactionResult +_dfb_surface_palette_listener( const void *msg_data, + void *ctx ) +{ + const CorePaletteNotification *notification = msg_data; + CoreSurface *surface = ctx; + + if (notification->flags & CPNF_DESTROY) + return RS_REMOVE; + + if (notification->flags & CPNF_ENTRIES) { + if (fusion_skirmish_prevail( &surface->lock )) + return RS_OK; + + dfb_surface_notify( surface, CSNF_PALETTE_UPDATE ); + + fusion_skirmish_dismiss( &surface->lock ); + } + + return RS_OK; +} + diff --git a/Source/DirectFB/src/core/surface.h b/Source/DirectFB/src/core/surface.h new file mode 100755 index 0000000..1d2d452 --- /dev/null +++ b/Source/DirectFB/src/core/surface.h @@ -0,0 +1,446 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef __CORE__SURFACE_H__ +#define __CORE__SURFACE_H__ + +#include + +#include +#include +#include + +#include +#include + +#include +#include + + +typedef enum { + CSNF_NONE = 0x00000000, + + CSNF_SIZEFORMAT = 0x00000001, /* width, height, format */ + CSNF_SYSTEM = 0x00000002, /* system instance information */ + CSNF_VIDEO = 0x00000004, /* video instance information */ + CSNF_DESTROY = 0x00000008, /* surface is about to be destroyed */ + CSNF_FLIP = 0x00000010, /* surface buffer pointer swapped */ + CSNF_FIELD = 0x00000020, /* active (displayed) field switched */ + CSNF_PALETTE_CHANGE = 0x00000040, /* another palette has been set */ + CSNF_PALETTE_UPDATE = 0x00000080, /* current palette has been altered */ + CSNF_ALPHA_RAMP = 0x00000100, /* alpha ramp was modified */ + + CSNF_ALL = 0x000001FF +} CoreSurfaceNotificationFlags; + +typedef struct { + CoreSurfaceNotificationFlags flags; + CoreSurface *surface; +} CoreSurfaceNotification; + + +typedef enum { + CSCONF_NONE = 0x00000000, + + CSCONF_SIZE = 0x00000001, + CSCONF_FORMAT = 0x00000002, + CSCONF_CAPS = 0x00000004, + + CSCONF_PREALLOCATED = 0x00000010, + + CSCONF_ALL = 0x00000017 +} CoreSurfaceConfigFlags; + +typedef enum { + CSTF_NONE = 0x00000000, + + CSTF_LAYER = 0x00000001, /* surface for layer */ + CSTF_WINDOW = 0x00000002, /* surface for window */ + CSTF_CURSOR = 0x00000004, /* surface for cursor */ + CSTF_FONT = 0x00000008, /* surface for font */ + + CSTF_SHARED = 0x00000010, /* accessable by other processes */ + + CSTF_INTERNAL = 0x00000100, /* system memory */ + CSTF_EXTERNAL = 0x00000200, /* video memory */ + + CSTF_PREALLOCATED = 0x00000400, /* preallocated memory */ + + CSTF_ALL = 0x0000071F +} CoreSurfaceTypeFlags; + +typedef struct { + CoreSurfaceConfigFlags flags; + + DFBDimension size; + DFBSurfacePixelFormat format; + DFBSurfaceCapabilities caps; + + struct { + void *addr; + int pitch; + } preallocated[MAX_SURFACE_BUFFERS]; + + DFBDimension min_size; +} CoreSurfaceConfig; + +typedef enum { + CSP_SYSTEMONLY = 0x00000000, /* never try to swap + into video memory */ + CSP_VIDEOLOW = 0x00000001, /* try to store in video memory, + low priority */ + CSP_VIDEOHIGH = 0x00000002, /* try to store in video memory, + high priority */ + CSP_VIDEOONLY = 0x00000003 /* always and only + store in video memory */ +} CoreSurfacePolicy; + +typedef enum { + CSAF_NONE = 0x00000000, + + CSAF_READ = 0x00000001, /* accessor may read */ + CSAF_WRITE = 0x00000002, /* accessor may write */ + + CSAF_SHARED = 0x00000010, /* other processes can read/write at the same time (shared mapping) */ + + CSAF_ALL = 0x00000013 +} CoreSurfaceAccessFlags; + +typedef enum { + CSAID_NONE = 0x00000000, /* none or unknown accessor */ + + CSAID_CPU = 0x00000001, /* local processor, where DirectFB is running on, could be app or sw fallback */ + + CSAID_GPU = 0x00000002, /* primary accelerator, as in traditional 'gfxcard' core (ACCEL0) */ + + CSAID_ACCEL0 = 0x00000002, /* accelerators, decoders etc. (CSAID_ACCEL0 + accel_id<0-5>) */ + CSAID_ACCEL1 = 0x00000003, + CSAID_ACCEL2 = 0x00000004, + CSAID_ACCEL3 = 0x00000005, + CSAID_ACCEL4 = 0x00000006, + CSAID_ACCEL5 = 0x00000007, + + CSAID_LAYER0 = 0x00000008, /* display layers, registered by layer core (CSAID_LAYER0 + layer_id<0-7>) */ + CSAID_LAYER1 = 0x00000009, + CSAID_LAYER2 = 0x0000000a, + CSAID_LAYER3 = 0x0000000b, + CSAID_LAYER4 = 0x0000000c, + CSAID_LAYER5 = 0x0000000d, + CSAID_LAYER6 = 0x0000000e, + CSAID_LAYER7 = 0x0000000f, + + _CSAID_NUM = 0x00000010, /* number of statically assigned IDs for usage in static arrays */ + + CSAID_ANY = 0x00000100, /* any other accessor needs to be registered using IDs starting from here */ +} CoreSurfaceAccessorID; + +typedef enum { + CSBR_FRONT = 0, + CSBR_BACK = 1, + CSBR_IDLE = 2 +} CoreSurfaceBufferRole; + +typedef enum { + CSSF_NONE = 0x00000000, + + CSSF_DESTROYED = 0x00000001, /* surface is being or has been destroyed */ + + CSSF_ALL = 0x00000001 +} CoreSurfaceStateFlags; + +struct __DFB_CoreSurface +{ + FusionObject object; + int magic; + + FusionSkirmish lock; + + CoreSurfaceStateFlags state; + + CoreSurfaceConfig config; + CoreSurfaceTypeFlags type; + unsigned long resource_id; /* layer id, window id, or user specified */ + + int rotation; + + CoreSurfaceNotificationFlags notifications; + + DirectSerial serial; + + int field; + u8 alpha_ramp[4]; + + CoreSurfaceBuffer *buffers[MAX_SURFACE_BUFFERS]; + int num_buffers; + + int buffer_indices[MAX_SURFACE_BUFFERS]; + + unsigned int flips; + + CorePalette *palette; + GlobalReaction palette_reaction; + + FusionSHMPoolShared *shmpool; +}; + + +/* + * Creates a pool of surface objects. + */ +FusionObjectPool *dfb_surface_pool_create( const FusionWorld *world ); + +/* + * Generates dfb_surface_ref(), dfb_surface_attach() etc. + */ +FUSION_OBJECT_METHODS( CoreSurface, dfb_surface ) + + +DFBResult dfb_surface_create ( CoreDFB *core, + const CoreSurfaceConfig *config, + CoreSurfaceTypeFlags type, + unsigned long resource_id, + CorePalette *palette, + CoreSurface **ret_surface ); + +DFBResult dfb_surface_create_simple ( CoreDFB *core, + int width, + int height, + DFBSurfacePixelFormat format, + DFBSurfaceCapabilities caps, + CoreSurfaceTypeFlags type, + unsigned long resource_id, + CorePalette *palette, + CoreSurface **ret_surface ); + +DFBResult dfb_surface_init_palette ( CoreDFB *core, + CoreSurface *surface ); + +DFBResult dfb_surface_notify ( CoreSurface *surface, + CoreSurfaceNotificationFlags flags); + +DFBResult dfb_surface_flip ( CoreSurface *surface, + bool swap ); + +DFBResult dfb_surface_reconfig ( CoreSurface *surface, + const CoreSurfaceConfig *config ); + +DFBResult dfb_surface_destroy_buffers( CoreSurface *surface ); + +DFBResult dfb_surface_lock_buffer ( CoreSurface *surface, + CoreSurfaceBufferRole role, + CoreSurfaceAccessorID accessor, + CoreSurfaceAccessFlags access, + CoreSurfaceBufferLock *ret_lock ); + +DFBResult dfb_surface_unlock_buffer ( CoreSurface *surface, + CoreSurfaceBufferLock *lock ); + +DFBResult dfb_surface_read_buffer ( CoreSurface *surface, + CoreSurfaceBufferRole role, + void *destination, + int pitch, + const DFBRectangle *rect ); + +DFBResult dfb_surface_write_buffer ( CoreSurface *surface, + CoreSurfaceBufferRole role, + const void *source, + int pitch, + const DFBRectangle *rect ); + +DFBResult dfb_surface_dump_buffer ( CoreSurface *surface, + CoreSurfaceBufferRole role, + const char *path, + const char *prefix ); + +DFBResult dfb_surface_set_palette ( CoreSurface *surface, + CorePalette *palette ); + +DFBResult dfb_surface_set_field ( CoreSurface *surface, + int field ); + +DFBResult dfb_surface_set_alpha_ramp( CoreSurface *surface, + u8 a0, + u8 a1, + u8 a2, + u8 a3 ); + + +static inline DirectResult +dfb_surface_lock( CoreSurface *surface ) +{ + D_MAGIC_ASSERT( surface, CoreSurface ); + + return fusion_skirmish_prevail( &surface->lock ); +} + +static inline DirectResult +dfb_surface_trylock( CoreSurface *surface ) +{ + D_MAGIC_ASSERT( surface, CoreSurface ); + + return fusion_skirmish_swoop( &surface->lock ); +} + +static inline DirectResult +dfb_surface_unlock( CoreSurface *surface ) +{ + D_MAGIC_ASSERT( surface, CoreSurface ); + + return fusion_skirmish_dismiss( &surface->lock ); +} + +static inline CoreSurfaceBuffer * +dfb_surface_get_buffer( CoreSurface *surface, + CoreSurfaceBufferRole role ) +{ + D_MAGIC_ASSERT( surface, CoreSurface ); + D_ASSERT( role == CSBR_FRONT || role == CSBR_BACK || role == CSBR_IDLE ); + + D_ASSERT( surface->num_buffers > 0 ); + + return surface->buffers[ surface->buffer_indices[(surface->flips + role) % surface->num_buffers] ]; +} + +static inline void * +dfb_surface_data_offset( const CoreSurface *surface, + void *data, + int pitch, + int x, + int y ) +{ + D_ASSERT( surface != NULL ); + D_ASSERT( data != NULL ); + D_ASSERT( pitch > 0 ); + D_ASSERT( x >= 0 ); + D_ASSERT( x < surface->config.size.w ); + D_ASSERT( y >= 0 ); + D_ASSERT( y < surface->config.size.h ); + + if (surface->config.caps & DSCAPS_SEPARATED) { + if (y & 1) + y += surface->config.size.h; + + y >>= 1; + } + + return (u8*)data + pitch * y + DFB_BYTES_PER_LINE( surface->config.format, x ); +} + +static inline void +dfb_surface_calc_buffer_size( CoreSurface *surface, + int byte_align, + int pixel_align, + int *ret_pitch, + int *ret_size ) +{ + DFBSurfacePixelFormat format; + int width; + int pitch; + + D_MAGIC_ASSERT( surface, CoreSurface ); + + format = surface->config.format; + + width = direct_util_align( surface->config.size.w, pixel_align ); + pitch = direct_util_align( DFB_BYTES_PER_LINE( format, width ), byte_align ); + + if (ret_pitch) + *ret_pitch = pitch; + + if (ret_size) + *ret_size = pitch * DFB_PLANE_MULTIPLY( format, surface->config.size.h ); +} + +static inline void +dfb_surface_caps_apply_policy( CoreSurfacePolicy policy, + DFBSurfaceCapabilities *caps ) +{ + switch (policy) { + case CSP_SYSTEMONLY: + *caps = (DFBSurfaceCapabilities)((*caps & ~DSCAPS_VIDEOONLY) | DSCAPS_SYSTEMONLY); + break; + + case CSP_VIDEOONLY: + *caps = (DFBSurfaceCapabilities)((*caps & ~DSCAPS_SYSTEMONLY) | DSCAPS_VIDEOONLY); + break; + + default: + *caps = (DFBSurfaceCapabilities)(*caps & ~(DSCAPS_SYSTEMONLY | DSCAPS_VIDEOONLY)); + break; + } +} + +static inline DFBResult +dfb_surface_resize( CoreSurface *surface, + int width, + int height ) +{ + CoreSurfaceConfig config; + + D_MAGIC_ASSERT( surface, CoreSurface ); + D_ASSERT( width > 0 ); + D_ASSERT( height > 0 ); + + config.flags = CSCONF_SIZE; + config.size.w = width; + config.size.h = height; + + return dfb_surface_reconfig( surface, &config ); +} + +static inline DFBResult +dfb_surface_reformat( CoreSurface *surface, + int width, + int height, + DFBSurfacePixelFormat format ) +{ + CoreSurfaceConfig config; + + D_MAGIC_ASSERT( surface, CoreSurface ); + D_ASSERT( width > 0 ); + D_ASSERT( height > 0 ); + + config.flags = (CoreSurfaceConfigFlags)(CSCONF_SIZE | CSCONF_FORMAT); + config.size.w = width; + config.size.h = height; + config.format = format; + + return dfb_surface_reconfig( surface, &config ); +} + +/* global reactions */ +ReactionResult _dfb_surface_palette_listener( const void *msg_data, + void *ctx ); + +typedef enum { + DFB_LAYER_REGION_SURFACE_LISTENER, + DFB_WINDOWSTACK_BACKGROUND_IMAGE_LISTENER +} DFB_SURFACE_GLOBALS; + +#endif + diff --git a/Source/DirectFB/src/core/surface_buffer.c b/Source/DirectFB/src/core/surface_buffer.c new file mode 100755 index 0000000..da477df --- /dev/null +++ b/Source/DirectFB/src/core/surface_buffer.c @@ -0,0 +1,1206 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +//#define DIRECT_ENABLE_DEBUG + +#include + +#include + +#include +#include +#include +#include + +#ifdef USE_ZLIB +#include +#endif + +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include + +static const u8 lookup3to8[] = { 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff }; +static const u8 lookup2to8[] = { 0x00, 0x55, 0xaa, 0xff }; + + +D_DEBUG_DOMAIN( Core_SurfBuffer, "Core/SurfBuffer", "DirectFB Core Surface Buffer" ); + +/**********************************************************************************************************************/ + +DFBResult +dfb_surface_buffer_new( CoreSurface *surface, + CoreSurfaceBufferFlags flags, + CoreSurfaceBuffer **ret_buffer ) +{ + CoreSurfaceBuffer *buffer; + + D_MAGIC_ASSERT( surface, CoreSurface ); + D_FLAGS_ASSERT( flags, CSBF_ALL ); + D_ASSERT( ret_buffer != NULL ); + +#if DIRECT_BUILD_DEBUG + D_DEBUG_AT( Core_SurfBuffer, "dfb_surface_buffer_new( %s )\n", dfb_pixelformat_name( surface->config.format ) ); + + if (flags & CSBF_STICKED) + D_DEBUG_AT( Core_SurfBuffer, " -> STICKED\n" ); +#endif + + buffer = SHCALLOC( surface->shmpool, 1, sizeof(CoreSurfaceBuffer) ); + if (!buffer) + return D_OOSHM(); + + direct_serial_init( &buffer->serial ); + direct_serial_increase( &buffer->serial ); + + buffer->surface = surface; + buffer->flags = flags; + buffer->format = surface->config.format; + + if (surface->config.caps & DSCAPS_VIDEOONLY) + buffer->policy = CSP_VIDEOONLY; + else if (surface->config.caps & DSCAPS_SYSTEMONLY) + buffer->policy = CSP_SYSTEMONLY; + else + buffer->policy = CSP_VIDEOLOW; + + fusion_vector_init( &buffer->allocs, 2, surface->shmpool ); + + D_MAGIC_SET( buffer, CoreSurfaceBuffer ); + + *ret_buffer = buffer; + + return DFB_OK; +} + +DFBResult +dfb_surface_buffer_destroy( CoreSurfaceBuffer *buffer ) +{ + CoreSurface *surface; + CoreSurfaceAllocation *allocation; + int i; + + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + + surface = buffer->surface; + D_MAGIC_ASSERT( surface, CoreSurface ); + FUSION_SKIRMISH_ASSERT( &surface->lock ); + + D_DEBUG_AT( Core_SurfBuffer, "dfb_surface_buffer_destroy( %p [%dx%d] )\n", + buffer, surface->config.size.w, surface->config.size.h ); + + fusion_vector_foreach_reverse (allocation, i, buffer->allocs) + dfb_surface_pool_deallocate( allocation->pool, allocation ); + + fusion_vector_destroy( &buffer->allocs ); + + direct_serial_deinit( &buffer->serial ); + + D_MAGIC_CLEAR( buffer ); + + SHFREE( surface->shmpool, buffer ); + + return DFB_OK; +} + +static CoreSurfaceAllocation * +find_allocation( CoreSurfaceBuffer *buffer, + CoreSurfaceAccessorID accessor, + CoreSurfaceAccessFlags flags, + bool lock ) +{ + int i; + CoreSurfaceAllocation *alloc; + CoreSurfaceAllocation *uptodate = NULL; + CoreSurfaceAllocation *outdated = NULL; + + /* Prefer allocations which are up to date. */ + fusion_vector_foreach (alloc, i, buffer->allocs) { + if (direct_serial_check( &alloc->serial, &buffer->serial )) { + /* Return immediately if up to date allocation has required flags. */ + if (D_FLAGS_ARE_SET( alloc->access[accessor], flags )) + return alloc; + + /* Remember up to date allocation in case none has supported flags. */ + uptodate = alloc; + } + else if (D_FLAGS_ARE_SET( alloc->access[accessor], flags )) { + /* Remember outdated allocation which has supported flags though. */ + outdated = alloc; + } + } + + /* In case of a lock the flags are mandatory and the outdated allocation has to be used... */ + if (lock) + return outdated; + + /* ...otherwise we can still prefer the up to date allocation for Read/Write()! */ + return uptodate ?: outdated; +} + +DFBResult +dfb_surface_buffer_lock( CoreSurfaceBuffer *buffer, + CoreSurfaceAccessorID accessor, + CoreSurfaceAccessFlags access, + CoreSurfaceBufferLock *lock ) +{ + DFBResult ret; + CoreSurface *surface; + CoreSurfaceAllocation *allocation = NULL; + bool allocated = false; + + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + D_FLAGS_ASSERT( access, CSAF_ALL ); + D_ASSERT( lock != NULL ); + + surface = buffer->surface; + D_MAGIC_ASSERT( surface, CoreSurface ); + + FUSION_SKIRMISH_ASSERT( &surface->lock ); + + D_ASSERT( accessor >= CSAID_CPU ); + D_ASSUME( accessor < _CSAID_NUM ); + if (accessor >= CSAID_ANY) { + D_UNIMPLEMENTED(); + return DFB_UNIMPLEMENTED; + } + + if (accessor < 0 || accessor >= _CSAID_NUM) + return DFB_INVARG; + +#if DIRECT_BUILD_DEBUG + D_DEBUG_AT( Core_SurfBuffer, "dfb_surface_buffer_lock( %p, 0x%02x, %p ) <- %dx%d %s [%d]\n", buffer, access, lock, + surface->config.size.w, surface->config.size.h, dfb_pixelformat_name(buffer->format), + dfb_surface_buffer_index(buffer) ); + + switch (accessor) { + case CSAID_CPU: + D_DEBUG_AT( Core_SurfBuffer, " -> CPU %s%s\n", + (access & CSAF_READ) ? "READ" : "", (access & CSAF_WRITE) ? "WRITE" : "" ); + break; + + case CSAID_GPU: + D_DEBUG_AT( Core_SurfBuffer, " -> GPU %s%s\n", + (access & CSAF_READ) ? "READ" : "", (access & CSAF_WRITE) ? "WRITE" : "" ); + break; + + case CSAID_LAYER0: + case CSAID_LAYER1: + case CSAID_LAYER2: + case CSAID_LAYER3: + case CSAID_LAYER4: + case CSAID_LAYER5: + case CSAID_LAYER6: + case CSAID_LAYER7: + D_DEBUG_AT( Core_SurfBuffer, " -> LAYER %d %s%s\n", accessor - CSAID_LAYER0, + (access & CSAF_READ) ? "READ" : "", (access & CSAF_WRITE) ? "WRITE" : "" ); + break; + + default: + D_DEBUG_AT( Core_SurfBuffer, " -> other\n" ); + break; + } + + if (access & CSAF_SHARED) + D_DEBUG_AT( Core_SurfBuffer, " -> SHARED\n" ); +#endif + + /* Look for allocation with proper access. */ + allocation = find_allocation( buffer, accessor, access, true ); + if (!allocation) { + /* If no allocation exists, create one. */ + ret = dfb_surface_pools_allocate( buffer, accessor, access, &allocation ); + if (ret) { + D_DERROR( ret, "Core/SurfBuffer: Buffer allocation failed!\n" ); + return ret; + } + + allocated = true; + } + + CORE_SURFACE_ALLOCATION_ASSERT( allocation ); + + /* Synchronize with other allocations. */ + ret = dfb_surface_allocation_update( allocation, access ); + if (ret) { + /* Destroy if newly created. */ + if (allocated) + dfb_surface_pool_deallocate( allocation->pool, allocation ); + return ret; + } + + /* Lock the allocation. */ + dfb_surface_buffer_lock_init( lock, accessor, access ); + + ret = dfb_surface_pool_lock( allocation->pool, allocation, lock ); + if (ret) { + D_DERROR( ret, "Core/SurfBuffer: Locking allocation failed! [%s]\n", + allocation->pool->desc.name ); + dfb_surface_buffer_lock_deinit( lock ); + + /* Destroy if newly created. */ + if (allocated) + dfb_surface_pool_deallocate( allocation->pool, allocation ); + + return ret; + } + +#if 1 + /* + * Manage access interlocks. + * + * SOON FIXME: Clearing flags only when not locked yet. Otherwise nested GPU/CPU locks are a problem. + */ + /* Software read/write access... */ + if (accessor == CSAID_CPU) { + /* If hardware has written or is writing... */ + if (allocation->accessed[CSAID_GPU] & CSAF_WRITE) { + /* ...wait for the operation to finish. */ + dfb_gfxcard_sync(); /* TODO: wait for serial instead */ + + /* Software read access after hardware write requires flush of the (bus) read cache. */ + dfb_gfxcard_flush_read_cache(); + + if (!buffer->locked) { + /* ...clear hardware write access. */ + allocation->accessed[CSAID_GPU] &= ~CSAF_WRITE; + + /* ...clear hardware read access (to avoid syncing twice). */ + allocation->accessed[CSAID_GPU] &= ~CSAF_READ; + } + } + + /* Software write access... */ + if (access & CSAF_WRITE) { + /* ...if hardware has (to) read... */ + if (allocation->accessed[CSAID_GPU] & CSAF_READ) { + /* ...wait for the operation to finish. */ + dfb_gfxcard_sync(); /* TODO: wait for serial instead */ + + /* ...clear hardware read access. */ + if (!buffer->locked) + allocation->accessed[CSAID_GPU] &= ~CSAF_READ; + } + } + } + + /* Hardware read access... */ + if (accessor == CSAID_GPU && access & CSAF_READ) { + /* ...if software has written before... */ + if (allocation->accessed[CSAID_CPU] & CSAF_WRITE) { + /* ...flush texture cache. */ + dfb_gfxcard_flush_texture_cache(); + + /* ...clear software write access. */ + if (!buffer->locked) + allocation->accessed[CSAID_CPU] &= ~CSAF_WRITE; + } + } + + if (! D_FLAGS_ARE_SET( allocation->accessed[accessor], access )) { + /* FIXME: surface_enter */ + } +#endif + + /* Collect... */ + allocation->accessed[accessor] |= access; + +#if 1 + /* FIXME: don't use weak counter */ + buffer->locked++; + + D_DEBUG_AT( Core_SurfBuffer, " -> locked %dx now\n", buffer->locked ); +#endif + + return DFB_OK; +} + +DFBResult +dfb_surface_buffer_unlock( CoreSurfaceBufferLock *lock ) +{ + DFBResult ret; + CoreSurfacePool *pool; + CoreSurfaceBuffer *buffer; + CoreSurfaceAllocation *allocation; + + D_DEBUG_AT( Core_SurfBuffer, "dfb_surface_buffer_unlock( %p )\n", lock ); + + D_MAGIC_ASSERT( lock, CoreSurfaceBufferLock ); + + D_MAGIC_ASSERT( lock->buffer, CoreSurfaceBuffer ); + D_MAGIC_ASSERT( lock->buffer->surface, CoreSurface ); + + FUSION_SKIRMISH_ASSERT( &lock->buffer->surface->lock ); + + allocation = lock->allocation; + CORE_SURFACE_ALLOCATION_ASSERT( allocation ); + + buffer = lock->buffer; + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + + pool = allocation->pool; + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + + /* + * FIXME: This should fail with a nested GPU Lock during a CPU Lock and/or vice versa? + */ +// D_ASSUME( D_FLAGS_ARE_SET( allocation->accessed, lock->access ) ); + + ret = dfb_surface_pool_unlock( pool, lock->allocation, lock ); + if (ret) { + D_DERROR( ret, "Core/SurfBuffer: Unlocking allocation failed! [%s]\n", pool->desc.name ); + return ret; + } + +#if 1 + buffer->locked--; +#endif + + dfb_surface_buffer_lock_reset( lock ); + + dfb_surface_buffer_lock_deinit( lock ); + + return DFB_OK; +} + +DFBResult +dfb_surface_buffer_read( CoreSurfaceBuffer *buffer, + void *destination, + int pitch, + const DFBRectangle *prect ) +{ + DFBResult ret; + int y; + int bytes; + DFBRectangle rect; + CoreSurface *surface; + CoreSurfaceAllocation *allocation = NULL; + bool allocated = false; + DFBSurfacePixelFormat format; + + D_DEBUG_AT( Core_SurfBuffer, "%s( %p, %p [%d] )\n", __FUNCTION__, buffer, destination, pitch ); + + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + D_ASSERT( destination != NULL ); + D_ASSERT( pitch > 0 ); + DFB_RECTANGLE_ASSERT_IF( prect ); + + surface = buffer->surface; + D_MAGIC_ASSERT( surface, CoreSurface ); + + FUSION_SKIRMISH_ASSERT( &surface->lock ); + + /* Determine area. */ + rect.x = 0; + rect.y = 0; + rect.w = surface->config.size.w; + rect.h = surface->config.size.h; + + if (prect && (!dfb_rectangle_intersect( &rect, prect ) || !DFB_RECTANGLE_EQUAL( rect, *prect ))) + return DFB_INVAREA; + + /* Calculate bytes per read line. */ + format = surface->config.format; + bytes = DFB_BYTES_PER_LINE( format, rect.w ); + + D_DEBUG_AT( Core_SurfBuffer, " -> %d,%d - %dx%d (%s)\n", DFB_RECTANGLE_VALS(&rect), + dfb_pixelformat_name( format ) ); + + /* If no allocations exists, simply clear the destination. */ + if (fusion_vector_is_empty( &buffer->allocs )) { + for (y=0; ywritten && direct_serial_check( &buffer->written->serial, &buffer->serial )) + allocation = buffer->written; + else { + /* ...otherwise look for allocation with CPU access. */ + allocation = find_allocation( buffer, CSAID_CPU, CSAF_READ, false ); + if (!allocation) { + /* If no allocation exists, create one. */ + ret = dfb_surface_pools_allocate( buffer, CSAID_CPU, CSAF_READ, &allocation ); + if (ret) { + D_DERROR( ret, "Core/SurfBuffer: Buffer allocation failed!\n" ); + return ret; + } + + allocated = true; + } + } + + CORE_SURFACE_ALLOCATION_ASSERT( allocation ); + + /* Synchronize with other allocations. */ + ret = dfb_surface_allocation_update( allocation, CSAF_READ ); + if (ret) { + /* Destroy if newly created. */ + if (allocated) + dfb_surface_pool_deallocate( allocation->pool, allocation ); + return ret; + } + + /* Try reading from allocation directly... */ + ret = dfb_surface_pool_read( allocation->pool, allocation, destination, pitch, &rect ); + if (ret) { + /* ...otherwise use fallback method via locking if possible. */ + if (allocation->access[CSAID_CPU] & CSAF_READ) { + CoreSurfaceBufferLock lock; + + /* Lock the allocation. */ + dfb_surface_buffer_lock_init( &lock, CSAID_CPU, CSAF_READ ); + + ret = dfb_surface_pool_lock( allocation->pool, allocation, &lock ); + if (ret) { + D_DERROR( ret, "Core/SurfBuffer: Locking allocation failed! [%s]\n", + allocation->pool->desc.name ); + dfb_surface_buffer_lock_deinit( &lock ); + return ret; + } + + /* Move to start of read. */ + lock.addr += DFB_BYTES_PER_LINE( format, rect.x ) + rect.y * lock.pitch; + + /* Copy the data. */ + for (y=0; ypool, allocation, &lock ); + if (ret) + D_DERROR( ret, "Core/SurfBuffer: Unlocking allocation failed! [%s]\n", allocation->pool->desc.name ); + + dfb_surface_buffer_lock_deinit( &lock ); + } + } + + return ret; +} + +DFBResult +dfb_surface_buffer_write( CoreSurfaceBuffer *buffer, + const void *source, + int pitch, + const DFBRectangle *prect ) +{ + DFBResult ret; + DFBRectangle rect; + CoreSurface *surface; + CoreSurfaceAllocation *allocation = NULL; + bool allocated = false; + + D_DEBUG_AT( Core_SurfBuffer, "%s( %p, %p [%d] )\n", __FUNCTION__, buffer, source, pitch ); + + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + D_ASSERT( pitch > 0 || source == NULL ); + DFB_RECTANGLE_ASSERT_IF( prect ); + + surface = buffer->surface; + D_MAGIC_ASSERT( surface, CoreSurface ); + + FUSION_SKIRMISH_ASSERT( &surface->lock ); + + /* Determine area. */ + rect.x = 0; + rect.y = 0; + rect.w = surface->config.size.w; + rect.h = surface->config.size.h; + + if (prect && (!dfb_rectangle_intersect( &rect, prect ) || !DFB_RECTANGLE_EQUAL( rect, *prect ))) + return DFB_INVAREA; + + D_DEBUG_AT( Core_SurfBuffer, " -> %d,%d - %dx%d (%s)\n", DFB_RECTANGLE_VALS(&rect), + dfb_pixelformat_name( surface->config.format ) ); + + /* Use last read allocation if it's up to date... */ + if (buffer->read && direct_serial_check( &buffer->read->serial, &buffer->serial )) + allocation = buffer->read; + else { + /* ...otherwise look for allocation with CPU access. */ + allocation = find_allocation( buffer, CSAID_CPU, CSAF_WRITE, false ); + if (!allocation) { + /* If no allocation exists, create one. */ + ret = dfb_surface_pools_allocate( buffer, CSAID_CPU, CSAF_WRITE, &allocation ); + if (ret) { + D_DERROR( ret, "Core/SurfBuffer: Buffer allocation failed!\n" ); + return ret; + } + + allocated = true; + } + } + + CORE_SURFACE_ALLOCATION_ASSERT( allocation ); + + /* Synchronize with other allocations. */ + ret = dfb_surface_allocation_update( allocation, CSAF_WRITE ); + if (ret) { + /* Destroy if newly created. */ + if (allocated) + dfb_surface_pool_deallocate( allocation->pool, allocation ); + return ret; + } + + /* Try writing to allocation directly... */ + ret = source ? dfb_surface_pool_write( allocation->pool, allocation, source, pitch, &rect ) : DFB_UNSUPPORTED; + if (ret) { + /* ...otherwise use fallback method via locking if possible. */ + if (allocation->access[CSAID_CPU] & CSAF_WRITE) { + int y; + int bytes; + DFBSurfacePixelFormat format; + CoreSurfaceBufferLock lock; + + /* Calculate bytes per written line. */ + format = surface->config.format; + bytes = DFB_BYTES_PER_LINE( format, rect.w ); + + /* Lock the allocation. */ + dfb_surface_buffer_lock_init( &lock, CSAID_CPU, CSAF_WRITE ); + + ret = dfb_surface_pool_lock( allocation->pool, allocation, &lock ); + if (ret) { + D_DERROR( ret, "Core/SurfBuffer: Locking allocation failed! [%s]\n", + allocation->pool->desc.name ); + dfb_surface_buffer_lock_deinit( &lock ); + return ret; + } + + /* Move to start of write. */ + lock.addr += DFB_BYTES_PER_LINE( format, rect.x ) + rect.y * lock.pitch; + + /* Copy the data. */ + for (y=0; ypool, allocation, &lock ); + if (ret) + D_DERROR( ret, "Core/SurfBuffer: Unlocking allocation failed! [%s]\n", allocation->pool->desc.name ); + + dfb_surface_buffer_lock_deinit( &lock ); + } + } + + return ret; +} + +DFBResult +dfb_surface_buffer_dump( CoreSurfaceBuffer *buffer, + const char *directory, + const char *prefix ) +{ + DFBResult ret; + int num = -1; + int fd_p = -1; + int fd_g = -1; + int i, n; + int len = (directory ? strlen(directory) : 0) + (prefix ? strlen(prefix) : 0) + 40; + char filename[len]; + char head[30]; + bool rgb = false; + bool alpha = false; +#ifdef USE_ZLIB + gzFile gz_p = NULL, gz_g = NULL; + static const char *gz_ext = ".gz"; +#else + static const char *gz_ext = ""; +#endif + CoreSurface *surface; + CorePalette *palette = NULL; + CoreSurfaceBufferLock lock; + + D_DEBUG_AT( Core_SurfBuffer, "%s( %p, %p, %p )\n", __FUNCTION__, buffer, directory, prefix ); + + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + D_ASSERT( directory != NULL ); + + surface = buffer->surface; + D_MAGIC_ASSERT( surface, CoreSurface ); + + FUSION_SKIRMISH_ASSERT( &surface->lock ); + + /* Check pixel format. */ + switch (buffer->format) { + case DSPF_LUT8: + palette = surface->palette; + + if (!palette) { + D_BUG( "no palette" ); + return DFB_BUG; + } + + if (dfb_palette_ref( palette )) + return DFB_FUSION; + + rgb = true; + + /* fall through */ + + case DSPF_A8: + alpha = true; + break; + + case DSPF_ARGB: + case DSPF_ARGB1555: + case DSPF_ARGB2554: + case DSPF_ARGB4444: + case DSPF_AiRGB: + alpha = true; + + /* fall through */ + + case DSPF_RGB332: + case DSPF_RGB16: + case DSPF_RGB24: + case DSPF_RGB32: + case DSPF_YUY2: + case DSPF_UYVY: + case DSPF_NV16: + case DSPF_RGB444: + case DSPF_RGB555: + case DSPF_BGR555: + rgb = true; + break; + + + default: + D_ERROR( "DirectFB/core/surfaces: surface dump for format " + "'%s' is not implemented!\n", + dfb_pixelformat_name( buffer->format ) ); + return DFB_UNSUPPORTED; + } + + /* Lock the surface buffer, get the data pointer and pitch. */ + ret = dfb_surface_buffer_lock( buffer, CSAID_CPU, CSAF_READ, &lock ); + if (ret) { + if (palette) + dfb_palette_unref( palette ); + return ret; + } + + if (prefix) { + /* Find the lowest unused index. */ + while (++num < 10000) { + snprintf( filename, len, "%s/%s_%04d.ppm%s", + directory, prefix, num, gz_ext ); + + if (access( filename, F_OK ) != 0) { + snprintf( filename, len, "%s/%s_%04d.pgm%s", + directory, prefix, num, gz_ext ); + + if (access( filename, F_OK ) != 0) + break; + } + } + + if (num == 10000) { + D_ERROR( "DirectFB/core/surfaces: " + "couldn't find an unused index for surface dump!\n" ); + dfb_surface_buffer_unlock( &lock ); + if (palette) + dfb_palette_unref( palette ); + return DFB_FAILURE; + } + } + + /* Create a file with the found index. */ + if (rgb) { + if (prefix) + snprintf( filename, len, "%s/%s_%04d.ppm%s", directory, prefix, num, gz_ext ); + else + snprintf( filename, len, "%s.ppm%s", directory, gz_ext ); + + fd_p = open( filename, O_EXCL | O_CREAT | O_WRONLY, 0644 ); + if (fd_p < 0) { + D_PERROR("DirectFB/core/surfaces: " + "could not open %s!\n", filename); + dfb_surface_buffer_unlock( &lock ); + if (palette) + dfb_palette_unref( palette ); + return DFB_IO; + } + } + + /* Create a graymap for the alpha channel using the found index. */ + if (alpha) { + if (prefix) + snprintf( filename, len, "%s/%s_%04d.pgm%s", directory, prefix, num, gz_ext ); + else + snprintf( filename, len, "%s.pgm%s", directory, gz_ext ); + + fd_g = open( filename, O_EXCL | O_CREAT | O_WRONLY, 0644 ); + if (fd_g < 0) { + D_PERROR("DirectFB/core/surfaces: " + "could not open %s!\n", filename); + + dfb_surface_buffer_unlock( &lock ); + if (palette) + dfb_palette_unref( palette ); + + if (rgb) { + close( fd_p ); + snprintf( filename, len, "%s/%s_%04d.ppm%s", + directory, prefix, num, gz_ext ); + unlink( filename ); + } + + return DFB_IO; + } + } + +#ifdef USE_ZLIB + if (rgb) + gz_p = gzdopen( fd_p, "wb" ); + + if (alpha) + gz_g = gzdopen( fd_g, "wb" ); +#endif + + if (rgb) { + /* Write the pixmap header. */ + snprintf( head, 30, + "P6\n%d %d\n255\n", surface->config.size.w, surface->config.size.h ); +#ifdef USE_ZLIB + gzwrite( gz_p, head, strlen(head) ); +#else + write( fd_p, head, strlen(head) ); +#endif + } + + /* Write the graymap header. */ + if (alpha) { + snprintf( head, 30, + "P5\n%d %d\n255\n", surface->config.size.w, surface->config.size.h ); +#ifdef USE_ZLIB + gzwrite( gz_g, head, strlen(head) ); +#else + write( fd_g, head, strlen(head) ); +#endif + } + + /* Write the pixmap (and graymap) data. */ + for (i=0; iconfig.size.h; i++) { + int n3; + + /* Prepare one row. */ + u8 *src8 = dfb_surface_data_offset( surface, lock.addr, lock.pitch, 0, i ); + + /* Write color buffer to pixmap file. */ + if (rgb) { + u8 buf_p[surface->config.size.w * 3]; + + if (buffer->format == DSPF_LUT8) { + for (n=0, n3=0; nconfig.size.w; n++, n3+=3) { + buf_p[n3+0] = palette->entries[src8[n]].r; + buf_p[n3+1] = palette->entries[src8[n]].g; + buf_p[n3+2] = palette->entries[src8[n]].b; + } + } + else + dfb_convert_to_rgb24( buffer->format, src8, lock.pitch, surface->config.size.h, + buf_p, surface->config.size.w * 3, surface->config.size.w, 1 ); +#ifdef USE_ZLIB + gzwrite( gz_p, buf_p, surface->config.size.w * 3 ); +#else + write( fd_p, buf_p, surface->config.size.w * 3 ); +#endif + } + + /* Write alpha buffer to graymap file. */ + if (alpha) { + u8 buf_g[surface->config.size.w]; + + if (buffer->format == DSPF_LUT8) { + for (n=0; nconfig.size.w; n++) + buf_g[n] = palette->entries[src8[n]].a; + } + else + dfb_convert_to_a8( buffer->format, src8, lock.pitch, surface->config.size.h, + buf_g, surface->config.size.w, surface->config.size.w, 1 ); +#ifdef USE_ZLIB + gzwrite( gz_g, buf_g, surface->config.size.w ); +#else + write( fd_g, buf_g, surface->config.size.w ); +#endif + } + } + + /* Unlock the surface buffer. */ + dfb_surface_buffer_unlock( &lock ); + + /* Release the palette. */ + if (palette) + dfb_palette_unref( palette ); + +#ifdef USE_ZLIB + if (rgb) + gzclose( gz_p ); + + if (alpha) + gzclose( gz_g ); +#endif + + /* Close pixmap file. */ + if (rgb) + close( fd_p ); + + /* Close graymap file. */ + if (alpha) + close( fd_g ); + + return DFB_OK; +} + +/**********************************************************************************************************************/ + +static void +transfer_buffer( CoreSurfaceBuffer *buffer, + const void *src, + void *dst, + int srcpitch, + int dstpitch ) +{ + int i; + CoreSurface *surface; + + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + + surface = buffer->surface; + D_MAGIC_ASSERT( surface, CoreSurface ); + + D_DEBUG_AT( Core_SurfBuffer, "%s( %p, %p [%d] -> %p [%d] ) * %d\n", + __FUNCTION__, buffer, src, srcpitch, dst, dstpitch, surface->config.size.h ); + + D_ASSERT( src != NULL ); + D_ASSERT( dst != NULL ); + D_ASSERT( srcpitch > 0 ); + D_ASSERT( dstpitch > 0 ); + + D_ASSERT( srcpitch >= DFB_BYTES_PER_LINE( buffer->format, surface->config.size.w ) ); + D_ASSERT( dstpitch >= DFB_BYTES_PER_LINE( buffer->format, surface->config.size.w ) ); + + for (i=0; iconfig.size.h; i++) { + direct_memcpy( dst, src, DFB_BYTES_PER_LINE( buffer->format, surface->config.size.w ) ); + + src += srcpitch; + dst += dstpitch; + } + + switch (buffer->format) { + case DSPF_YV12: + case DSPF_I420: + for (i=0; iconfig.size.h; i++) { + direct_memcpy( dst, src, + DFB_BYTES_PER_LINE( buffer->format, surface->config.size.w / 2 ) ); + src += srcpitch / 2; + dst += dstpitch / 2; + } + break; + + case DSPF_NV12: + case DSPF_NV21: + for (i=0; iconfig.size.h/2; i++) { + direct_memcpy( dst, src, + DFB_BYTES_PER_LINE( buffer->format, surface->config.size.w ) ); + src += srcpitch; + dst += dstpitch; + } + break; + + case DSPF_NV16: + for (i=0; iconfig.size.h; i++) { + direct_memcpy( dst, src, + DFB_BYTES_PER_LINE( buffer->format, surface->config.size.w ) ); + src += srcpitch; + dst += dstpitch; + } + break; + + default: + break; + } +} + +static DFBResult +allocation_update_copy( CoreSurfaceAllocation *allocation, + CoreSurfaceAllocation *source ) +{ + DFBResult ret; + CoreSurfaceBufferLock src; + CoreSurfaceBufferLock dst; + CoreSurfaceBuffer *buffer; + + D_DEBUG_AT( Core_SurfBuffer, "%s()\n", __FUNCTION__ ); + + D_ASSERT( allocation != source ); + + D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); + D_MAGIC_ASSERT( source, CoreSurfaceAllocation ); + + D_ASSERT( source->buffer == allocation->buffer ); + + buffer = allocation->buffer; + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + + /* Lock the source allocation. */ + dfb_surface_buffer_lock_init( &src, CSAID_CPU, CSAF_READ ); + + ret = dfb_surface_pool_lock( source->pool, source, &src ); + if (ret) { + D_DERROR( ret, "Core/SurfBuffer: Could not lock source for transfer!\n" ); + dfb_surface_buffer_lock_deinit( &src ); + return ret; + } + + /* Lock the destination allocation. */ + dfb_surface_buffer_lock_init( &dst, CSAID_CPU, CSAF_WRITE ); + + ret = dfb_surface_pool_lock( allocation->pool, allocation, &dst ); + if (ret) { + D_DERROR( ret, "Core/SurfBuffer: Could not lock destination for transfer!\n" ); + dfb_surface_pool_unlock( source->pool, source, &src ); + return ret; + } + + transfer_buffer( buffer, src.addr, dst.addr, src.pitch, dst.pitch ); + + dfb_surface_pool_unlock( allocation->pool, allocation, &dst ); + dfb_surface_pool_unlock( source->pool, source, &src ); + + dfb_surface_buffer_lock_deinit( &dst ); + dfb_surface_buffer_lock_deinit( &src ); + + return DFB_OK; +} + +static DFBResult +allocation_update_write( CoreSurfaceAllocation *allocation, + CoreSurfaceAllocation *source ) +{ + DFBResult ret; + CoreSurfaceBufferLock src; + CoreSurfaceBuffer *buffer; + + D_DEBUG_AT( Core_SurfBuffer, "%s()\n", __FUNCTION__ ); + + D_ASSERT( allocation != source ); + + D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); + D_MAGIC_ASSERT( source, CoreSurfaceAllocation ); + + D_ASSERT( source->buffer == allocation->buffer ); + + buffer = allocation->buffer; + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + + /* Lock the source allocation. */ + dfb_surface_buffer_lock_init( &src, CSAID_CPU, CSAF_READ ); + + ret = dfb_surface_pool_lock( source->pool, source, &src ); + if (ret) { + D_DERROR( ret, "Core/SurfBuffer: Could not lock source for transfer!\n" ); + dfb_surface_buffer_lock_deinit( &src ); + return ret; + } + + /* Write to the destination allocation. */ + ret = dfb_surface_pool_write( allocation->pool, allocation, src.addr, src.pitch, NULL ); + if (ret) + D_DERROR( ret, "Core/SurfBuffer: Could not write from destination allocation!\n" ); + + dfb_surface_pool_unlock( source->pool, source, &src ); + + dfb_surface_buffer_lock_deinit( &src ); + + return ret; +} + +static DFBResult +allocation_update_read( CoreSurfaceAllocation *allocation, + CoreSurfaceAllocation *source ) +{ + DFBResult ret; + CoreSurfaceBufferLock dst; + CoreSurfaceBuffer *buffer; + + D_DEBUG_AT( Core_SurfBuffer, "%s()\n", __FUNCTION__ ); + + D_ASSERT( allocation != source ); + + D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); + D_MAGIC_ASSERT( source, CoreSurfaceAllocation ); + + D_ASSERT( source->buffer == allocation->buffer ); + + buffer = allocation->buffer; + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + + /* Lock the destination allocation. */ + dfb_surface_buffer_lock_init( &dst, CSAID_CPU, CSAF_WRITE ); + + ret = dfb_surface_pool_lock( allocation->pool, allocation, &dst ); + if (ret) { + D_DERROR( ret, "Core/SurfBuffer: Could not lock destination for transfer!\n" ); + dfb_surface_buffer_lock_deinit( &dst ); + return ret; + } + + /* Read from the source allocation. */ + ret = dfb_surface_pool_read( source->pool, source, dst.addr, dst.pitch, NULL ); + if (ret) + D_DERROR( ret, "Core/SurfBuffer: Could not read from source allocation!\n" ); + + dfb_surface_pool_unlock( allocation->pool, allocation, &dst ); + + dfb_surface_buffer_lock_deinit( &dst ); + + return ret; +} + +DFBResult +dfb_surface_allocation_update( CoreSurfaceAllocation *allocation, + CoreSurfaceAccessFlags access ) +{ + DFBResult ret; + int i; + CoreSurfaceAllocation *alloc; + CoreSurfaceBuffer *buffer; + + D_DEBUG_AT( Core_SurfBuffer, "%s()\n", __FUNCTION__ ); + + D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); + D_FLAGS_ASSERT( access, CSAF_ALL ); + + buffer = allocation->buffer; + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + + if (direct_serial_update( &allocation->serial, &buffer->serial ) && buffer->written) { + CoreSurfaceAllocation *source = buffer->written; + + D_ASSUME( allocation != source ); + + D_DEBUG_AT( Core_SurfBuffer, " -> updating allocation...\n" ); + + D_MAGIC_ASSERT( source, CoreSurfaceAllocation ); + D_ASSERT( source->buffer == allocation->buffer ); + + ret = dfb_surface_pool_bridges_transfer( buffer, source, allocation, NULL, 0 ); + if (ret) { + if ((source->access[CSAID_CPU] & CSAF_READ) && (allocation->access[CSAID_CPU] & CSAF_WRITE)) + ret = allocation_update_copy( allocation, source ); + else if (source->access[CSAID_CPU] & CSAF_READ) + ret = allocation_update_write( allocation, source ); + else if (allocation->access[CSAID_CPU] & CSAF_WRITE) + ret = allocation_update_read( allocation, source ); + else { + D_UNIMPLEMENTED(); + ret = DFB_UNSUPPORTED; + } + } + + if (ret) { + D_DERROR( ret, "Core/SurfaceBuffer: Updating allocation failed!\n" ); + return ret; + } + } + + if (access & CSAF_WRITE) { + D_DEBUG_AT( Core_SurfBuffer, " -> increasing serial...\n" ); + + direct_serial_increase( &buffer->serial ); + + direct_serial_copy( &allocation->serial, &buffer->serial ); + + buffer->written = allocation; + buffer->read = NULL; + + /* Zap volatile allocations (freed when no longer up to date). */ + fusion_vector_foreach (alloc, i, buffer->allocs) { + D_MAGIC_ASSERT( alloc, CoreSurfaceAllocation ); + + if (alloc != allocation && (alloc->flags & CSALF_VOLATILE)) { + dfb_surface_pool_deallocate( alloc->pool, alloc ); + i--; + } + } + } + else + buffer->read = allocation; + + /* Zap all other allocations? */ + if (dfb_config->thrifty_surface_buffers) { + buffer->written = buffer->read = allocation; + + fusion_vector_foreach (alloc, i, buffer->allocs) { + D_MAGIC_ASSERT( alloc, CoreSurfaceAllocation ); + + /* Don't zap preallocated which would not really free up memory, but just loose the handle. */ + if (alloc != allocation && !(alloc->flags & (CSALF_PREALLOCATED | CSALF_MUCKOUT))) { + dfb_surface_pool_deallocate( alloc->pool, alloc ); + i--; + } + } + } + + return DFB_OK; +} + diff --git a/Source/DirectFB/src/core/surface_buffer.h b/Source/DirectFB/src/core/surface_buffer.h new file mode 100755 index 0000000..4acf65a --- /dev/null +++ b/Source/DirectFB/src/core/surface_buffer.h @@ -0,0 +1,257 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef __CORE__SURFACE_BUFFER_H__ +#define __CORE__SURFACE_BUFFER_H__ + +#include +#include + +#include + +#include + +#include + + +/* + * Configuration and State flags of a Surface Buffer + */ +typedef enum { + CSBF_NONE = 0x00000000, /* None of these. */ + + CSBF_STICKED = 0x00000001, /* Sticked to one Surface Pool, e.g. system only. */ + + CSBF_ALL = 0x00000001 /* All of these. */ +} CoreSurfaceBufferFlags; + +/* + * Configuration and State flags of a Surface Buffer Allocation + */ +typedef enum { + CSALF_NONE = 0x00000000, /* None of these. */ + + CSALF_ONEFORALL = 0x00000001, /* Only one allocation in pool for all buffers. */ + CSALF_VOLATILE = 0x00000002, /* Allocation should be freed when no longer up to date. */ + CSALF_PREALLOCATED = 0x00000004, /* Preallocated memory, don't zap when "thrifty-surface-buffers" is active. */ + + CSALF_MUCKOUT = 0x00001000, /* Indicates surface pool being in the progress of mucking out this and possibly + other allocations to have enough space for a new allocation to be made. */ + + CSALF_ALL = 0x00001007 /* All of these. */ +} CoreSurfaceAllocationFlags; + +/* + * An Allocation of a Surface Buffer + */ +struct __DFB_CoreSurfaceAllocation { + int magic; + + DirectSerial serial; /* Equals serial of buffer if content is up to date. */ + + CoreSurfaceBuffer *buffer; /* Surface Buffer owning this allocation. */ + CoreSurface *surface; /* Surface owning the Buffer of this allocation. */ + CoreSurfacePool *pool; /* Surface Pool providing the allocation. */ + void *data; /* Pool's private data for this allocation. */ + int size; /* Amount of data used by this allocation. */ + unsigned long offset; /* Offset within address range of pool if contiguous. */ + + CoreSurfaceAllocationFlags flags; /* Pool can return CSALF_ONEFORALL upon allocation of first buffer. */ + + const CoreSurfaceAccessFlags *access; /* Possible access flags (pointer to pool description). */ + CoreSurfaceAccessFlags accessed[_CSAID_NUM]; /* Access since last synchronization. */ +}; + +#define CORE_SURFACE_ALLOCATION_ASSERT(alloc) \ + do { \ + D_MAGIC_ASSERT( alloc, CoreSurfaceAllocation ); \ + D_ASSUME( (alloc)->size > 0 ); \ + D_ASSERT( (alloc)->size >= 0 ); \ + D_ASSERT( (alloc)->offset + (alloc)->size <= ((alloc)->pool->desc.size ?:~0UL) ); \ + D_FLAGS_ASSERT( (alloc)->access[CSAID_CPU], CSAF_ALL ); \ + D_FLAGS_ASSERT( (alloc)->access[CSAID_GPU], CSAF_ALL ); \ + D_FLAGS_ASSERT( (alloc)->flags, CSALF_ALL ); \ + D_FLAGS_ASSERT( (alloc)->accessed[CSAID_CPU], CSAF_ALL ); \ + D_FLAGS_ASSERT( (alloc)->accessed[CSAID_GPU], CSAF_ALL ); \ + } while (0) + +/* + * A Lock on a Surface Buffer + */ +struct __DFB_CoreSurfaceBufferLock { + int magic; /* Must be valid before calling dfb_surface_pool_lock() */ + + CoreSurfaceAccessorID accessor; /* " */ + CoreSurfaceAccessFlags access; /* " */ + + CoreSurfaceBuffer *buffer; /* Set by dfb_surface_pool_lock() */ + CoreSurfaceAllocation *allocation; /* " */ + + void *addr; /* " */ + unsigned long phys; /* " */ + unsigned long offset; /* " */ + unsigned int pitch; /* " */ + + void *handle; /* " */ +}; + +static inline void +dfb_surface_buffer_lock_reset( CoreSurfaceBufferLock *lock ) +{ + D_MAGIC_ASSERT( lock, CoreSurfaceBufferLock ); + + lock->buffer = NULL; + lock->allocation = NULL; + lock->addr = NULL; + lock->phys = 0; + lock->offset = ~0; + lock->pitch = 0; + lock->handle = NULL; +} + +static inline void +dfb_surface_buffer_lock_init( CoreSurfaceBufferLock *lock, CoreSurfaceAccessorID accessor, CoreSurfaceAccessFlags access ) +{ + D_MAGIC_SET( lock, CoreSurfaceBufferLock ); + + lock->accessor = accessor; + lock->access = access; + + dfb_surface_buffer_lock_reset( lock ); +} + +static inline void +dfb_surface_buffer_lock_deinit( CoreSurfaceBufferLock *lock ) +{ + D_MAGIC_ASSERT( lock, CoreSurfaceBufferLock ); + + lock->accessor = CSAID_NONE; + lock->access = CSAF_NONE; + + D_MAGIC_CLEAR( lock ); +} + +#define CORE_SURFACE_BUFFER_LOCK_ASSERT(lock) \ + do { \ + D_MAGIC_ASSERT( lock, CoreSurfaceBufferLock ); \ + D_FLAGS_ASSERT( (lock)->access, CSAF_ALL ); \ + if ((lock)->buffer) { \ + D_ASSERT( (lock)->allocation != NULL ); \ + D_ASSERT( (lock)->buffer == (lock)->allocation->buffer ); \ + D_ASSUME( (lock)->addr != NULL || (lock)->phys != 0 || (lock)->offset != ~0 || (lock)->handle != NULL );\ + D_ASSUME( (lock)->offset == (lock)->allocation->offset || (lock)->offset == ~0 ); \ + D_ASSERT( (lock)->pitch > 0 || ((lock)->addr == NULL && (lock)->phys == 0) ); \ + } \ + else { \ + D_ASSERT( (lock)->allocation == NULL ); \ + D_ASSERT( (lock)->addr == NULL ); \ + D_ASSERT( (lock)->phys == 0 ); \ + D_ASSERT( (lock)->offset == ~0 ); \ + D_ASSERT( (lock)->pitch == 0 ); \ + D_ASSERT( (lock)->handle == NULL ); \ + } \ + } while (0) + +/* + * A Surface Buffer of a Surface + */ +struct __DFB_CoreSurfaceBuffer { + int magic; + + DirectSerial serial; /* Increased when content is written. */ + CoreSurfaceAllocation *written; /* Allocation with the last write access. */ + CoreSurfaceAllocation *read; /* Allocation with the last read access. */ + + CoreSurface *surface; /* Surface owning this Surface Buffer. */ + CoreSurfacePolicy policy; + + CoreSurfaceBufferFlags flags; /* Configuration and State flags. */ + DFBSurfacePixelFormat format; /* Pixel format of buffer data. */ + + FusionVector allocs; /* Allocations within Surface Pools. */ + +#if 1 + unsigned int locked; /* Lock count. FIXME: Add fail safe cleanup! */ +#endif +}; + + +DFBResult dfb_surface_buffer_new ( CoreSurface *surface, + CoreSurfaceBufferFlags flags, + CoreSurfaceBuffer **ret_buffer ); + +DFBResult dfb_surface_buffer_destroy( CoreSurfaceBuffer *buffer ); + + +DFBResult dfb_surface_buffer_lock ( CoreSurfaceBuffer *buffer, + CoreSurfaceAccessorID accessor, + CoreSurfaceAccessFlags access, + CoreSurfaceBufferLock *ret_lock ); + +DFBResult dfb_surface_buffer_unlock ( CoreSurfaceBufferLock *lock ); + +DFBResult dfb_surface_buffer_read ( CoreSurfaceBuffer *buffer, + void *destination, + int pitch, + const DFBRectangle *rect ); + +DFBResult dfb_surface_buffer_write ( CoreSurfaceBuffer *buffer, + const void *source, + int pitch, + const DFBRectangle *rect ); + +DFBResult dfb_surface_buffer_dump ( CoreSurfaceBuffer *buffer, + const char *directory, + const char *prefix ); + +static inline int +dfb_surface_buffer_index( CoreSurfaceBuffer *buffer ) +{ + int index; + CoreSurface *surface; + + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + + surface = buffer->surface; + D_MAGIC_ASSERT( surface, CoreSurface ); + + for (index=0; indexbuffers[index] == buffer) + return index; + } + + D_ASSERT( index, + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include + +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include + + +extern SurfacePoolFuncs localSurfacePoolFuncs; +extern SurfacePoolFuncs sharedSurfacePoolFuncs; +extern SurfacePoolFuncs preallocSurfacePoolFuncs; + + + +D_DEBUG_DOMAIN( Core_Surface, "Core/SurfaceCore", "DirectFB Surface Core" ); + +/**********************************************************************************************************************/ + +typedef struct { + int magic; + + CoreSurfacePool *local_pool; + CoreSurfacePool *shared_pool; + CoreSurfacePool *prealloc_pool; +} DFBSurfaceCoreShared; + +typedef struct { + int magic; + + CoreDFB *core; + + DFBSurfaceCoreShared *shared; +} DFBSurfaceCore; + + +DFB_CORE_PART( surface_core, SurfaceCore ); + +/**********************************************************************************************************************/ + +static DFBResult +dfb_surface_core_initialize( CoreDFB *core, + DFBSurfaceCore *data, + DFBSurfaceCoreShared *shared ) +{ + DFBResult ret; + + D_DEBUG_AT( Core_Surface, "dfb_surface_core_initialize( %p, %p, %p )\n", core, data, shared ); + + D_ASSERT( data != NULL ); + D_ASSERT( shared != NULL ); + + data->core = core; + data->shared = shared; + + ret = dfb_surface_pool_initialize( core, &sharedSurfacePoolFuncs, &shared->shared_pool ); + if (ret) { + D_DERROR( ret, "Core/Surface: Could not register 'shared' surface pool!\n" ); + return ret; + } + + ret = dfb_surface_pool_initialize( core, &localSurfacePoolFuncs, &shared->local_pool ); + if (ret) { + D_DERROR( ret, "Core/Surface: Could not register 'local' surface pool!\n" ); + dfb_surface_pool_destroy( shared->shared_pool ); + return ret; + } + + ret = dfb_surface_pool_initialize( core, &preallocSurfacePoolFuncs, &shared->prealloc_pool ); + if (ret) { + D_DERROR( ret, "Core/Surface: Could not register 'prealloc' surface pool!\n" ); + dfb_surface_pool_destroy( shared->local_pool ); + dfb_surface_pool_destroy( shared->shared_pool ); + return ret; + } + + D_MAGIC_SET( data, DFBSurfaceCore ); + D_MAGIC_SET( shared, DFBSurfaceCoreShared ); + + return DFB_OK; +} + +static DFBResult +dfb_surface_core_join( CoreDFB *core, + DFBSurfaceCore *data, + DFBSurfaceCoreShared *shared ) +{ + D_DEBUG_AT( Core_Surface, "dfb_surface_core_join( %p, %p, %p )\n", core, data, shared ); + + D_ASSERT( data != NULL ); + D_MAGIC_ASSERT( shared, DFBSurfaceCoreShared ); + + data->core = core; + data->shared = shared; + + dfb_surface_pool_join( core, shared->shared_pool, &sharedSurfacePoolFuncs ); + dfb_surface_pool_join( core, shared->local_pool, &localSurfacePoolFuncs ); + dfb_surface_pool_join( core, shared->prealloc_pool, &preallocSurfacePoolFuncs ); + + D_MAGIC_SET( data, DFBSurfaceCore ); + + return DFB_OK; +} + +static DFBResult +dfb_surface_core_shutdown( DFBSurfaceCore *data, + bool emergency ) +{ + DFBSurfaceCoreShared *shared; + + D_DEBUG_AT( Core_Surface, "dfb_surface_core_shutdown( %p, %semergency )\n", data, emergency ? "" : "no " ); + + D_MAGIC_ASSERT( data, DFBSurfaceCore ); + D_MAGIC_ASSERT( data->shared, DFBSurfaceCoreShared ); + + shared = data->shared; + + dfb_surface_pool_destroy( shared->prealloc_pool ); + dfb_surface_pool_destroy( shared->local_pool ); + dfb_surface_pool_destroy( shared->shared_pool ); + + D_MAGIC_CLEAR( data ); + D_MAGIC_CLEAR( shared ); + + return DFB_OK; +} + +static DFBResult +dfb_surface_core_leave( DFBSurfaceCore *data, + bool emergency ) +{ + DFBSurfaceCoreShared *shared; + + D_DEBUG_AT( Core_Surface, "dfb_surface_core_leave( %p, %semergency )\n", data, emergency ? "" : "no " ); + + D_MAGIC_ASSERT( data, DFBSurfaceCore ); + D_MAGIC_ASSERT( data->shared, DFBSurfaceCoreShared ); + + shared = data->shared; + + dfb_surface_pool_leave( shared->shared_pool ); + dfb_surface_pool_leave( shared->local_pool ); + dfb_surface_pool_leave( shared->prealloc_pool ); + + D_MAGIC_CLEAR( data ); + + return DFB_OK; +} + +static DFBResult +dfb_surface_core_suspend( DFBSurfaceCore *data ) +{ + DFBSurfaceCoreShared *shared; + + D_DEBUG_AT( Core_Surface, "dfb_surface_core_suspend( %p )\n", data ); + + D_MAGIC_ASSERT( data, DFBSurfaceCore ); + D_MAGIC_ASSERT( data->shared, DFBSurfaceCoreShared ); + + shared = data->shared; + + return DFB_OK; +} + +static DFBResult +dfb_surface_core_resume( DFBSurfaceCore *data ) +{ + DFBSurfaceCoreShared *shared; + + D_DEBUG_AT( Core_Surface, "dfb_surface_core_resume( %p )\n", data ); + + D_MAGIC_ASSERT( data, DFBSurfaceCore ); + D_MAGIC_ASSERT( data->shared, DFBSurfaceCoreShared ); + + shared = data->shared; + + return DFB_OK; +} + diff --git a/Source/DirectFB/src/core/surface_pool.c b/Source/DirectFB/src/core/surface_pool.c new file mode 100755 index 0000000..0518df2 --- /dev/null +++ b/Source/DirectFB/src/core/surface_pool.c @@ -0,0 +1,1263 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include +#include + +#include +#include + +#include + +#include +#include + +#include +#include +#include + +#include + +#include + + +D_DEBUG_DOMAIN( Core_SurfacePool, "Core/SurfacePool", "DirectFB Core Surface Pool" ); +D_DEBUG_DOMAIN( Core_SurfPoolLock, "Core/SurfPoolLock", "DirectFB Core Surface Pool Lock" ); + +/**********************************************************************************************************************/ + +static const SurfacePoolFuncs *pool_funcs[MAX_SURFACE_POOLS]; +static void *pool_locals[MAX_SURFACE_POOLS]; +static int pool_count; +static CoreSurfacePool *pool_array[MAX_SURFACE_POOLS]; +static unsigned int pool_order[MAX_SURFACE_POOLS]; + +/**********************************************************************************************************************/ + +static inline const SurfacePoolFuncs * +get_funcs( const CoreSurfacePool *pool ) +{ + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + + D_ASSERT( pool->pool_id >= 0 ); + D_ASSERT( pool->pool_id < MAX_SURFACE_POOLS ); + D_ASSERT( pool_funcs[pool->pool_id] != NULL ); + + /* Return function table of the pool. */ + return pool_funcs[pool->pool_id]; +} + +static inline void * +get_local( const CoreSurfacePool *pool ) +{ + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + + D_ASSERT( pool->pool_id >= 0 ); + D_ASSERT( pool->pool_id < MAX_SURFACE_POOLS ); + + /* Return local data of the pool. */ + return pool_locals[pool->pool_id]; +} + +/**********************************************************************************************************************/ + +static DFBResult init_pool( CoreDFB *core, + CoreSurfacePool *pool, + const SurfacePoolFuncs *funcs ); + +/**********************************************************************************************************************/ + +static void insert_pool_local( CoreSurfacePool *pool ); +static void remove_pool_local( CoreSurfacePoolID pool_id ); + +/**********************************************************************************************************************/ + +static void remove_allocation( CoreSurfacePool *pool, + CoreSurfaceBuffer *buffer, + CoreSurfaceAllocation *allocation ); + +static DFBResult backup_allocation( CoreSurfacePool *pool, + CoreSurfaceBuffer *buffer, + CoreSurfaceAllocation *allocation ); + +/**********************************************************************************************************************/ + +DFBResult +dfb_surface_pool_initialize( CoreDFB *core, + const SurfacePoolFuncs *funcs, + CoreSurfacePool **ret_pool ) +{ + DFBResult ret; + CoreSurfacePool *pool; + FusionSHMPoolShared *shmpool; + + D_DEBUG_AT( Core_SurfacePool, "%s( %p )\n", __FUNCTION__, funcs ); + + D_ASSERT( core != NULL ); + D_ASSERT( funcs != NULL ); + D_ASSERT( ret_pool != NULL ); + + /* Check against pool limit. */ + if (pool_count == MAX_SURFACE_POOLS) { + D_ERROR( "Core/SurfacePool: Maximum number of pools (%d) reached!\n", MAX_SURFACE_POOLS ); + return DFB_LIMITEXCEEDED; + } + + D_ASSERT( pool_funcs[pool_count] == NULL ); + + shmpool = dfb_core_shmpool( core ); + + /* Allocate pool structure. */ + pool = SHCALLOC( shmpool, 1, sizeof(CoreSurfacePool) ); + if (!pool) + return D_OOSHM(); + + /* Assign a pool ID. */ + pool->pool_id = pool_count++; + + /* Remember shared memory pool. */ + pool->shmpool = shmpool; + + /* Set function table of the pool. */ + pool_funcs[pool->pool_id] = funcs; + + /* Add to global pool list. */ + pool_array[pool->pool_id] = pool; + + D_MAGIC_SET( pool, CoreSurfacePool ); + + ret = init_pool( core, pool, funcs ); + if (ret) { + pool_funcs[pool->pool_id] = NULL; + pool_array[pool->pool_id] = NULL; + pool_count--; + D_MAGIC_CLEAR( pool ); + SHFREE( shmpool, pool ); + return ret; + } + + /* Set default backup pool being the shared memory surface pool */ + if (!pool->backup && pool_count > 1) + pool->backup = pool_array[0]; + + /* Insert new pool into priority order */ + insert_pool_local( pool ); + + /* Return the new pool. */ + *ret_pool = pool; + + return DFB_OK; +} + +DFBResult +dfb_surface_pool_join( CoreDFB *core, + CoreSurfacePool *pool, + const SurfacePoolFuncs *funcs ) +{ + DFBResult ret; + + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + + D_DEBUG_AT( Core_SurfacePool, "%s( %p [%d], %p )\n", __FUNCTION__, pool, pool->pool_id, funcs ); + + D_ASSERT( core != NULL ); + D_ASSERT( funcs != NULL ); + + D_ASSERT( pool->pool_id < MAX_SURFACE_POOLS ); + D_ASSERT( pool->pool_id == pool_count ); + D_ASSERT( pool_funcs[pool->pool_id] == NULL ); + + /* Enforce same order as initialization to be used during join. */ + if (pool->pool_id != pool_count) { + D_ERROR( "Core/SurfacePool: Wrong order of joining pools, got %d, should be %d!\n", + pool->pool_id, pool_count ); + return DFB_BUG; + } + + /* Allocate local pool data. */ + if (pool->pool_local_data_size && + !(pool_locals[pool->pool_id] = D_CALLOC( 1, pool->pool_local_data_size ))) + return D_OOM(); + + /* Set function table of the pool. */ + pool_funcs[pool->pool_id] = funcs; + + /* Add to global pool list. */ + pool_array[pool->pool_id] = pool; + + /* Adjust pool count. */ + if (pool_count < pool->pool_id + 1) + pool_count = pool->pool_id + 1; + + funcs = get_funcs( pool ); + + if (funcs->JoinPool) { + ret = funcs->JoinPool( core, pool, pool->data, get_local(pool), dfb_system_data() ); + if (ret) { + D_DERROR( ret, "Core/SurfacePool: Joining '%s' failed!\n", pool->desc.name ); + + if (pool_locals[pool->pool_id]) { + D_FREE( pool_locals[pool->pool_id] ); + pool_locals[pool->pool_id] = NULL; + } + + pool_count--; + + return ret; + } + } + + /* Insert new pool into priority order */ + insert_pool_local( pool ); + + return DFB_OK; +} + +DFBResult +dfb_surface_pool_destroy( CoreSurfacePool *pool ) +{ + CoreSurfacePoolID pool_id; + const SurfacePoolFuncs *funcs; + + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + + pool_id = pool->pool_id; + + D_DEBUG_AT( Core_SurfacePool, "%s( %p, '%s' [%d] )\n", __FUNCTION__, pool, pool->desc.name, pool_id ); + + D_ASSERT( pool->pool_id >= 0 ); + D_ASSERT( pool_id < MAX_SURFACE_POOLS ); + D_ASSERT( pool_array[pool_id] == pool ); + + funcs = get_funcs( pool ); + + if (funcs->DestroyPool) + funcs->DestroyPool( pool, pool->data, get_local(pool) ); + + /* Free shared pool data. */ + if (pool->data) + SHFREE( pool->shmpool, pool->data ); + + /* Free local pool data and remove from lists */ + remove_pool_local( pool_id ); + + fusion_skirmish_destroy( &pool->lock ); + + fusion_vector_destroy( &pool->allocs ); + + D_MAGIC_CLEAR( pool ); + + SHFREE( pool->shmpool, pool ); + + return DFB_OK; +} + +DFBResult +dfb_surface_pool_leave( CoreSurfacePool *pool ) +{ + CoreSurfacePoolID pool_id; + const SurfacePoolFuncs *funcs; + + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + + pool_id = pool->pool_id; + + D_DEBUG_AT( Core_SurfacePool, "%s( %p, '%s' [%d] )\n", __FUNCTION__, pool, pool->desc.name, pool_id ); + + D_ASSERT( pool->pool_id >= 0 ); + D_ASSERT( pool_id < MAX_SURFACE_POOLS ); + D_ASSERT( pool_array[pool_id] == pool ); + + funcs = get_funcs( pool ); + + if (funcs->LeavePool) + funcs->LeavePool( pool, pool->data, get_local(pool) ); + + /* Free local pool data and remove from lists */ + remove_pool_local( pool_id ); + + return DFB_OK; +} + +/**********************************************************************************************************************/ + +DFBResult +dfb_surface_pools_negotiate( CoreSurfaceBuffer *buffer, + CoreSurfaceAccessorID accessor, + CoreSurfaceAccessFlags access, + CoreSurfacePool **ret_pools, + unsigned int max_pools, + unsigned int *ret_num ) +{ + DFBResult ret; + int i; + unsigned int num = 0; + CoreSurface *surface; + CoreSurfaceTypeFlags type; + unsigned int free_count = 0; + CoreSurfacePool *free_pools[pool_count]; + unsigned int oom_count = 0; + CoreSurfacePool *oom_pools[pool_count]; + + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + + D_DEBUG_AT( Core_SurfacePool, "%s( %p [%s], 0x%02x, 0x%02x, max %d )\n", __FUNCTION__, + buffer, dfb_pixelformat_name( buffer->format ), accessor, access, max_pools ); + + D_ASSERT( ret_pools != NULL ); + D_ASSERT( max_pools > 0 ); + D_ASSERT( ret_num != NULL ); + + surface = buffer->surface; + D_MAGIC_ASSERT( surface, CoreSurface ); + FUSION_SKIRMISH_ASSERT( &surface->lock ); + + D_ASSERT( accessor >= CSAID_CPU ); + D_ASSUME( accessor < _CSAID_NUM ); + if (accessor >= CSAID_ANY) { + D_UNIMPLEMENTED(); + return DFB_UNIMPLEMENTED; + } + + if (accessor < 0 || accessor >= _CSAID_NUM) + return DFB_INVARG; + + type = surface->type & ~(CSTF_INTERNAL | CSTF_EXTERNAL); + + switch (buffer->policy) { + case CSP_SYSTEMONLY: + type |= CSTF_INTERNAL; + break; + + case CSP_VIDEOONLY: + type |= CSTF_EXTERNAL; + break; + + default: + break; + } + + D_DEBUG_AT( Core_SurfacePool, " -> 0x%02x 0x%03x required\n", access, type ); + + for (i=0; i= 0 ); + D_ASSERT( pool_order[i] < pool_count ); + + pool = pool_array[pool_order[i]]; + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + + if (D_FLAGS_ARE_SET( pool->desc.access[accessor], access ) && + D_FLAGS_ARE_SET( pool->desc.types, type )) + { + const SurfacePoolFuncs *funcs; + + D_DEBUG_AT( Core_SurfacePool, " -> [%d] 0x%02x 0x%03x (%d) [%s]\n", pool->pool_id, + pool->desc.caps, pool->desc.types, pool->desc.priority, pool->desc.name ); + + funcs = get_funcs( pool ); + + ret = funcs->TestConfig ? funcs->TestConfig( pool, pool->data, get_local(pool), + buffer, &surface->config ) : DFB_OK; + switch (ret) { + case DFB_OK: + D_DEBUG_AT( Core_SurfacePool, " => OK\n" ); + free_pools[free_count++] = pool; + break; + + case DFB_NOVIDEOMEMORY: + D_DEBUG_AT( Core_SurfacePool, " => OUT OF MEMORY\n" ); + oom_pools[oom_count++] = pool; + break; + + default: + continue; + } + } + } + + D_DEBUG_AT( Core_SurfacePool, " => %d pools available\n", free_count ); + D_DEBUG_AT( Core_SurfacePool, " => %d pools out of memory\n", oom_count ); + + for (i=0; isurface; + D_MAGIC_ASSERT( surface, CoreSurface ); + FUSION_SKIRMISH_ASSERT( &surface->lock ); + + D_DEBUG_AT( Core_SurfacePool, "%s( %p, 0x%x )\n", __FUNCTION__, buffer, access ); + + D_DEBUG_AT( Core_SurfacePool, " -> %dx%d %s - %s%s%s%s%s%s%s%s\n", + surface->config.size.w, surface->config.size.h, + dfb_pixelformat_name( surface->config.format ), + (surface->type & CSTF_SHARED) ? "SHARED" : "PRIVATE", + (surface->type & CSTF_LAYER) ? " LAYER" : "", + (surface->type & CSTF_WINDOW) ? " WINDOW" : "", + (surface->type & CSTF_CURSOR) ? " CURSOR" : "", + (surface->type & CSTF_FONT) ? " FONT" : "", + (surface->type & CSTF_INTERNAL) ? " INTERNAL" : "", + (surface->type & CSTF_EXTERNAL) ? " EXTERNAL" : "", + (surface->type & CSTF_PREALLOCATED) ? " PREALLOCATED" : "" ); + + D_ASSERT( accessor >= CSAID_CPU ); + D_ASSUME( accessor < _CSAID_NUM ); + if (accessor >= CSAID_ANY) { + D_UNIMPLEMENTED(); + return DFB_UNIMPLEMENTED; + } + + if (accessor < 0 || accessor >= _CSAID_NUM) + return DFB_INVARG; + + /* Build a list of possible pools being free or out of memory */ + ret = dfb_surface_pools_negotiate( buffer, accessor, access, pools, pool_count, &num_pools ); + if (ret && ret != DFB_NOVIDEOMEMORY) { + D_DEBUG_AT( Core_SurfacePool, " -> NEGOTIATION FAILED! (%s)\n", DirectFBErrorString( ret ) ); + return ret; + } + + /* Try to do the allocation in one of the pools */ + for (i=0; i Allocation in '%s' failed!\n", pool->desc.name ); + + /* ...forget about the pool for now */ + pools[i] = NULL; + } + } + + /* Check if none of the pools could do the allocation */ + if (!allocation) { + /* Try to find a pool with "older" allocations to muck out */ + for (i=0; i FAILED!\n" ); + return DFB_FAILURE; + } + + CORE_SURFACE_ALLOCATION_ASSERT( allocation ); + + D_DEBUG_AT( Core_SurfacePool, " -> %p\n", allocation ); + + *ret_allocation = allocation; + + return DFB_OK; +} + +/**********************************************************************************************************************/ + +DFBResult +dfb_surface_pool_allocate( CoreSurfacePool *pool, + CoreSurfaceBuffer *buffer, + CoreSurfaceAllocation **ret_allocation ) +{ + DFBResult ret; + int i; + CoreSurface *surface; + CoreSurfaceAllocation *allocation = NULL; + const SurfacePoolFuncs *funcs; + + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + + D_DEBUG_AT( Core_SurfacePool, "%s( %p [%d], %p )\n", __FUNCTION__, pool, pool->pool_id, buffer ); + + D_ASSERT( ret_allocation != NULL ); + + surface = buffer->surface; + D_MAGIC_ASSERT( surface, CoreSurface ); + FUSION_SKIRMISH_ASSERT( &surface->lock ); + + funcs = get_funcs( pool ); + + D_ASSERT( funcs->AllocateBuffer != NULL ); + + allocation = SHCALLOC( pool->shmpool, 1, sizeof(CoreSurfaceAllocation) ); + if (!allocation) + return D_OOSHM(); + + allocation->buffer = buffer; + allocation->surface = surface; + allocation->pool = pool; + allocation->access = pool->desc.access; + + if (pool->alloc_data_size) { + allocation->data = SHCALLOC( pool->shmpool, 1, pool->alloc_data_size ); + if (!allocation->data) { + ret = D_OOSHM(); + goto error; + } + } + + D_MAGIC_SET( allocation, CoreSurfaceAllocation ); + + if (fusion_skirmish_prevail( &pool->lock )) { + ret = DFB_FUSION; + goto error; + } + + if (dfb_config->warn.flags & DCWF_ALLOCATE_BUFFER && + dfb_config->warn.allocate_buffer.min_size.w <= surface->config.size.w && + dfb_config->warn.allocate_buffer.min_size.h <= surface->config.size.h) + D_WARN( "allocate-buffer %4dx%4d %6s, surface-caps 0x%08x", + surface->config.size.w, surface->config.size.h, dfb_pixelformat_name(buffer->format), + surface->config.caps ); + + ret = funcs->AllocateBuffer( pool, pool->data, get_local(pool), buffer, allocation, allocation->data ); + if (ret) { + D_DEBUG_AT( Core_SurfacePool, " -> %s\n", DirectFBErrorString( ret ) ); + D_MAGIC_CLEAR( allocation ); + fusion_skirmish_dismiss( &pool->lock ); + goto error; + } + + D_MAGIC_ASSERT( allocation, CoreSurfaceAllocation ); + + if (allocation->flags & CSALF_ONEFORALL) { + for (i=0; inum_buffers; i++) { + buffer = surface->buffers[i]; + + D_ASSUME( fusion_vector_is_empty( &buffer->allocs ) ); + + D_DEBUG_AT( Core_SurfacePool, " -> %p (%d)\n", allocation, i ); + fusion_vector_add( &buffer->allocs, allocation ); + fusion_vector_add( &pool->allocs, allocation ); + } + } + else { + D_DEBUG_AT( Core_SurfacePool, " -> %p\n", allocation ); + fusion_vector_add( &buffer->allocs, allocation ); + fusion_vector_add( &pool->allocs, allocation ); + } + + direct_serial_init( &allocation->serial ); + + fusion_skirmish_dismiss( &pool->lock ); + + CORE_SURFACE_ALLOCATION_ASSERT( allocation ); + + *ret_allocation = allocation; + + return DFB_OK; + +error: + if (allocation->data) + SHFREE( pool->shmpool, allocation->data ); + + SHFREE( pool->shmpool, allocation ); + + return ret; +} + +DFBResult +dfb_surface_pool_deallocate( CoreSurfacePool *pool, + CoreSurfaceAllocation *allocation ) +{ + DFBResult ret; + int i; + const SurfacePoolFuncs *funcs; + CoreSurfaceBuffer *buffer; + CoreSurface *surface; + + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + CORE_SURFACE_ALLOCATION_ASSERT( allocation ); + + D_DEBUG_AT( Core_SurfacePool, "%s( %p [%d], %p )\n", __FUNCTION__, pool, pool->pool_id, allocation ); + + D_ASSERT( pool == allocation->pool ); + + buffer = allocation->buffer; + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + + surface = buffer->surface; + D_MAGIC_ASSERT( surface, CoreSurface ); + FUSION_SKIRMISH_ASSERT( &surface->lock ); + + funcs = get_funcs( pool ); + + D_ASSERT( funcs->DeallocateBuffer != NULL ); + + if (fusion_skirmish_prevail( &pool->lock )) + return DFB_FUSION; + + ret = funcs->DeallocateBuffer( pool, pool->data, get_local(pool), allocation->buffer, allocation, allocation->data ); + if (ret) { + D_DERROR( ret, "Core/SurfacePool: Could not deallocate buffer!\n" ); + fusion_skirmish_dismiss( &pool->lock ); + return ret; + } + + if (allocation->flags & CSALF_ONEFORALL) { + for (i=0; inum_buffers; i++) + remove_allocation( pool, surface->buffers[i], allocation ); + } + else + remove_allocation( pool, buffer, allocation ); + + fusion_skirmish_dismiss( &pool->lock ); + + if (allocation->data) + SHFREE( pool->shmpool, allocation->data ); + + direct_serial_deinit( &allocation->serial ); + + D_MAGIC_CLEAR( allocation ); + + SHFREE( pool->shmpool, allocation ); + + return DFB_OK; +} + +DFBResult +dfb_surface_pool_displace( CoreSurfacePool *pool, + CoreSurfaceBuffer *buffer, + CoreSurfaceAllocation **ret_allocation ) +{ + DFBResult ret, ret_lock = DFB_OK; + int i, retries = 3; + CoreSurface *surface; + CoreSurfaceAllocation *allocation; + const SurfacePoolFuncs *funcs; + + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + + D_DEBUG_AT( Core_SurfacePool, "%s( %p [%d], %p )\n", __FUNCTION__, pool, pool->pool_id, buffer ); + + D_ASSERT( ret_allocation != NULL ); + + surface = buffer->surface; + D_MAGIC_ASSERT( surface, CoreSurface ); + FUSION_SKIRMISH_ASSERT( &surface->lock ); + + funcs = get_funcs( pool ); + + if (fusion_skirmish_prevail( &pool->lock )) + return DFB_FUSION; + + /* Check for integrated method to muck out "older" allocations for a new one */ + if (funcs->MuckOut) { + ret = funcs->MuckOut( pool, pool->data, get_local(pool), buffer ); + if (ret) { + fusion_skirmish_dismiss( &pool->lock ); + return ret; + } + } + else { + /* Or take the generic approach via allocation list */ + D_UNIMPLEMENTED(); + } + + /* FIXME: Solve potential dead lock, until then do a few retries... */ +fixme_retry: + fusion_vector_foreach (allocation, i, pool->allocs) { + CORE_SURFACE_ALLOCATION_ASSERT( allocation ); + + if (allocation->flags & CSALF_MUCKOUT) { + CoreSurface *alloc_surface; + CoreSurfaceBuffer *alloc_buffer; + + alloc_buffer = allocation->buffer; + D_MAGIC_ASSERT( alloc_buffer, CoreSurfaceBuffer ); + + alloc_surface = alloc_buffer->surface; + D_MAGIC_ASSERT( alloc_surface, CoreSurface ); + + D_DEBUG_AT( Core_SurfacePool, " <= %p %5dk, %lu\n", + allocation, allocation->size / 1024, allocation->offset ); + + /* FIXME: Solve potential dead lock, until then only try to lock... */ + ret = dfb_surface_trylock( alloc_surface ); + if (ret) { + D_WARN( "could not lock surface (%s)", DirectFBErrorString(ret) ); + ret_lock = ret; + continue; + } + + /* Ensure mucked out allocation is backed up in another pool */ + ret = backup_allocation( pool, buffer, allocation ); + if (ret) { + D_WARN( "could not backup allocation (%s)", DirectFBErrorString(ret) ); + dfb_surface_unlock( alloc_surface ); + goto error_cleanup; + } + + /* Deallocate mucked out allocation */ + dfb_surface_pool_deallocate( pool, allocation ); + i--; + + dfb_surface_unlock( alloc_surface ); + } + } + + /* FIXME: Solve potential dead lock, until then do a few retries... */ + if (ret_lock) { + if (retries--) + goto fixme_retry; + + ret = DFB_LOCKED; + + goto error_cleanup; + } + else + ret = dfb_surface_pool_allocate( pool, buffer, ret_allocation ); + + fusion_skirmish_dismiss( &pool->lock ); + + return ret; + + +error_cleanup: + fusion_vector_foreach (allocation, i, pool->allocs) { + CORE_SURFACE_ALLOCATION_ASSERT( allocation ); + + if (allocation->flags & CSALF_MUCKOUT) + allocation->flags &= ~CSALF_MUCKOUT; + } + + fusion_skirmish_dismiss( &pool->lock ); + + return ret; +} + +DFBResult +dfb_surface_pool_lock( CoreSurfacePool *pool, + CoreSurfaceAllocation *allocation, + CoreSurfaceBufferLock *lock ) +{ + DFBResult ret; + const SurfacePoolFuncs *funcs; + + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + + D_DEBUG_AT( Core_SurfPoolLock, "%s( %p [%d], %p )\n", __FUNCTION__, pool, pool->pool_id, allocation ); + + CORE_SURFACE_ALLOCATION_ASSERT( allocation ); + CORE_SURFACE_BUFFER_LOCK_ASSERT( lock ); + D_ASSERT( lock->buffer == NULL ); + + D_ASSERT( pool == allocation->pool ); + + funcs = get_funcs( pool ); + + D_ASSERT( funcs->Lock != NULL ); + + lock->allocation = allocation; + lock->buffer = allocation->buffer; + + ret = funcs->Lock( pool, pool->data, get_local(pool), allocation, allocation->data, lock ); + if (ret) { + D_DERROR( ret, "Core/SurfacePool: Could not lock allocation!\n" ); + dfb_surface_buffer_lock_reset( lock ); + return ret; + } + + CORE_SURFACE_BUFFER_LOCK_ASSERT( lock ); + D_ASSERT( lock->buffer != NULL ); + + return DFB_OK; +} + +DFBResult +dfb_surface_pool_unlock( CoreSurfacePool *pool, + CoreSurfaceAllocation *allocation, + CoreSurfaceBufferLock *lock ) +{ + DFBResult ret; + const SurfacePoolFuncs *funcs; + + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + + D_DEBUG_AT( Core_SurfPoolLock, "%s( %p [%d], %p )\n", __FUNCTION__, pool, pool->pool_id, allocation ); + + CORE_SURFACE_ALLOCATION_ASSERT( allocation ); + CORE_SURFACE_BUFFER_LOCK_ASSERT( lock ); + D_ASSERT( lock->buffer != NULL ); + + D_ASSERT( pool == allocation->pool ); + + funcs = get_funcs( pool ); + + D_ASSERT( funcs->Unlock != NULL ); + + ret = funcs->Unlock( pool, pool->data, get_local(pool), allocation, allocation->data, lock ); + if (ret) { + D_DERROR( ret, "Core/SurfacePool: Could not unlock allocation!\n" ); + return ret; + } + + CORE_SURFACE_BUFFER_LOCK_ASSERT( lock ); + D_ASSERT( lock->buffer != NULL ); + + dfb_surface_buffer_lock_reset( lock ); + + return DFB_OK; +} + +DFBResult +dfb_surface_pool_read( CoreSurfacePool *pool, + CoreSurfaceAllocation *allocation, + void *data, + int pitch, + const DFBRectangle *rect ) +{ + DFBResult ret; + const SurfacePoolFuncs *funcs; + CoreSurface *surface; + DFBRectangle area; + + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + + D_DEBUG_AT( Core_SurfPoolLock, "%s( %p [%d], %p )\n", __FUNCTION__, pool, pool->pool_id, allocation ); + + CORE_SURFACE_ALLOCATION_ASSERT( allocation ); + D_ASSERT( data != NULL ); + D_ASSERT( pitch >= 0 ); + DFB_RECTANGLE_ASSERT_IF( rect ); + + D_ASSERT( pool == allocation->pool ); + + funcs = get_funcs( pool ); + D_ASSERT( funcs != NULL ); + + if (!funcs->Read) + return DFB_UNSUPPORTED; + + surface = allocation->surface; + D_MAGIC_ASSERT( surface, CoreSurface ); + + area.x = 0; + area.y = 0; + area.w = surface->config.size.w; + area.h = surface->config.size.h; + + if (rect && !dfb_rectangle_intersect( &area, rect )) + return DFB_INVAREA; + + ret = funcs->Read( pool, pool->data, get_local(pool), allocation, allocation->data, data, pitch, &area ); + if (ret) + D_DERROR( ret, "Core/SurfacePool: Could not read from allocation!\n" ); + + return ret; +} + +DFBResult +dfb_surface_pool_write( CoreSurfacePool *pool, + CoreSurfaceAllocation *allocation, + const void *data, + int pitch, + const DFBRectangle *rect ) +{ + DFBResult ret; + const SurfacePoolFuncs *funcs; + CoreSurface *surface; + DFBRectangle area; + + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + + D_DEBUG_AT( Core_SurfPoolLock, "%s( %p [%d], %p )\n", __FUNCTION__, pool, pool->pool_id, allocation ); + + CORE_SURFACE_ALLOCATION_ASSERT( allocation ); + D_ASSERT( data != NULL ); + D_ASSERT( pitch >= 0 ); + DFB_RECTANGLE_ASSERT_IF( rect ); + + D_ASSERT( pool == allocation->pool ); + + funcs = get_funcs( pool ); + D_ASSERT( funcs != NULL ); + + if (!funcs->Write) + return DFB_UNSUPPORTED; + + surface = allocation->surface; + D_MAGIC_ASSERT( surface, CoreSurface ); + + area.x = 0; + area.y = 0; + area.w = surface->config.size.w; + area.h = surface->config.size.h; + + if (rect && !dfb_rectangle_intersect( &area, rect )) + return DFB_INVAREA; + + ret = funcs->Write( pool, pool->data, get_local(pool), allocation, allocation->data, data, pitch, &area ); + if (ret) + D_DERROR( ret, "Core/SurfacePool: Could not write to allocation!\n" ); + + return ret; +} + +DFBResult +dfb_surface_pool_enumerate ( CoreSurfacePool *pool, + CoreSurfaceAllocCallback callback, + void *ctx ) +{ + int i; + CoreSurfaceAllocation *allocation; + + D_DEBUG_AT( Core_SurfacePool, "%s( %p, %p, %p )\n", __FUNCTION__, pool, callback, ctx ); + + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + D_ASSERT( callback != NULL ); + + fusion_vector_foreach (allocation, i, pool->allocs) { + if (callback( allocation, ctx ) == DFENUM_CANCEL) + break; + } + + return DFB_OK; +} + +/**********************************************************************************************************************/ + +static DFBResult +init_pool( CoreDFB *core, + CoreSurfacePool *pool, + const SurfacePoolFuncs *funcs ) +{ + DFBResult ret; + + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + D_ASSERT( funcs != NULL ); + D_ASSERT( funcs->InitPool != NULL ); + + D_DEBUG_AT( Core_SurfacePool, "%s( %p, %p )\n", __FUNCTION__, pool, funcs ); + + if (funcs->PoolDataSize) + pool->pool_data_size = funcs->PoolDataSize(); + + if (funcs->PoolLocalDataSize) + pool->pool_local_data_size = funcs->PoolLocalDataSize(); + + if (funcs->AllocationDataSize) + pool->alloc_data_size = funcs->AllocationDataSize(); + + /* Allocate shared pool data. */ + if (pool->pool_data_size) { + pool->data = SHCALLOC( pool->shmpool, 1, pool->pool_data_size ); + if (!pool->data) + return D_OOSHM(); + } + + /* Allocate local pool data. */ + if (pool->pool_local_data_size && + !(pool_locals[pool->pool_id] = D_CALLOC( 1, pool->pool_local_data_size ))) + { + SHFREE( pool->shmpool, pool->data ); + return D_OOM(); + } + + fusion_vector_init( &pool->allocs, 4, pool->shmpool ); + + ret = funcs->InitPool( core, pool, pool->data, get_local(pool), dfb_system_data(), &pool->desc ); + if (ret) { + D_DERROR( ret, "Core/SurfacePool: Initializing '%s' failed!\n", pool->desc.name ); + + if (pool_locals[pool->pool_id]) { + D_FREE( pool_locals[pool->pool_id] ); + pool_locals[pool->pool_id] = NULL; + } + if (pool->data) { + SHFREE( pool->shmpool, pool->data ); + pool->data = NULL; + } + return ret; + } + + fusion_skirmish_init( &pool->lock, pool->desc.name, dfb_core_world(core) ); + + return DFB_OK; +} + +static void +insert_pool_local( CoreSurfacePool *pool ) +{ + int i, n; + + for (i=0; i= 0 ); + D_ASSERT( pool_order[i] < pool_count-1 ); + + D_MAGIC_ASSERT( pool_array[pool_order[i]], CoreSurfacePool ); + + if (pool_array[pool_order[i]]->desc.priority < pool->desc.priority) + break; + } + + for (n=pool_count-1; n>i; n--) { + D_ASSERT( pool_order[n-1] >= 0 ); + D_ASSERT( pool_order[n-1] < pool_count-1 ); + + D_MAGIC_ASSERT( pool_array[pool_order[n-1]], CoreSurfacePool ); + + pool_order[n] = pool_order[n-1]; + } + + pool_order[n] = pool_count - 1; + +#if D_DEBUG_ENABLED + for (i=0; i [%d] %p - '%s' [%d] (%d), %p\n", + (i == n) ? '=' : '-', i, pool_array[pool_order[i]], pool_array[pool_order[i]]->desc.name, + pool_array[pool_order[i]]->pool_id, pool_array[pool_order[i]]->desc.priority, + pool_funcs[pool_order[i]] ); + D_ASSERT( pool_order[i] == pool_array[pool_order[i]]->pool_id ); + } +#endif +} + +static void +remove_pool_local( CoreSurfacePoolID pool_id ) +{ + int i; + + /* Free local pool data. */ + if (pool_locals[pool_id]) { + D_FREE( pool_locals[pool_id] ); + pool_locals[pool_id] = NULL; + } + + /* Erase entries of the pool. */ + pool_array[pool_id] = NULL; + pool_funcs[pool_id] = NULL; + + while (pool_count > 0 && !pool_array[pool_count-1]) { + pool_count--; + + for (i=0; isurface, CoreSurface ); + FUSION_SKIRMISH_ASSERT( &buffer->surface->lock ); + FUSION_SKIRMISH_ASSERT( &pool->lock ); + D_ASSERT( pool == allocation->pool ); + + /* Lookup indices within vectors */ + index_buffer = fusion_vector_index_of( &buffer->allocs, allocation ); + index_pool = fusion_vector_index_of( &pool->allocs, allocation ); + + D_ASSERT( index_buffer >= 0 ); + D_ASSERT( index_pool >= 0 ); + + /* Remove allocation from buffer and pool */ + fusion_vector_remove( &buffer->allocs, index_buffer ); + fusion_vector_remove( &pool->allocs, index_pool ); + + /* Update 'written' allocation pointer of buffer */ + if (buffer->written == allocation) { + /* Reset pointer first */ + buffer->written = NULL; + + /* Iterate through remaining allocations */ + fusion_vector_foreach (allocation, index_buffer, buffer->allocs) { + CORE_SURFACE_ALLOCATION_ASSERT( allocation ); + + /* Check if allocation is up to date and set it as 'written' allocation */ + if (direct_serial_check( &allocation->serial, &buffer->serial )) { + buffer->written = allocation; + break; + } + } + } + + /* Reset 'read' allocation pointer of buffer */ + if (buffer->read == allocation) + buffer->read = NULL; +} + +static DFBResult +backup_allocation( CoreSurfacePool *pool, + CoreSurfaceBuffer *buffer, + CoreSurfaceAllocation *allocation ) +{ + DFBResult ret = DFB_OK; + int i; + CoreSurfaceAllocation *backup = NULL; + + D_DEBUG_AT( Core_SurfacePool, "%s( %p, %p )\n", __FUNCTION__, pool, allocation ); + + D_MAGIC_ASSERT( pool, CoreSurfacePool ); + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + CORE_SURFACE_ALLOCATION_ASSERT( allocation ); + D_MAGIC_ASSERT( buffer->surface, CoreSurface ); + FUSION_SKIRMISH_ASSERT( &buffer->surface->lock ); + FUSION_SKIRMISH_ASSERT( &pool->lock ); + D_ASSERT( pool == allocation->pool ); + + /* Check if allocation is the only up to date (requiring a backup) */ + if (direct_serial_check( &allocation->serial, &buffer->serial )) { + CoreSurfacePool *backup_pool = pool->backup; + + /* First check if any of the existing allocations is up to date */ + fusion_vector_foreach (backup, i, buffer->allocs) { + D_MAGIC_ASSERT( backup, CoreSurfaceAllocation ); + D_MAGIC_ASSERT( backup->pool, CoreSurfacePool ); + + if (backup->pool != pool && direct_serial_check( &backup->serial, &buffer->serial )) { + D_DEBUG_AT( Core_SurfacePool, " -> up to date in '%s'\n", backup->pool->desc.name ); + return DFB_OK; + } + } + + /* Try to update one of the existing allocations */ + fusion_vector_foreach (backup, i, buffer->allocs) { + D_MAGIC_ASSERT( backup, CoreSurfaceAllocation ); + D_MAGIC_ASSERT( backup->pool, CoreSurfacePool ); + + if (backup->pool != pool && dfb_surface_allocation_update( backup, CSAF_NONE ) == DFB_OK) { + D_DEBUG_AT( Core_SurfacePool, " -> updated in '%s'\n", backup->pool->desc.name ); + return DFB_OK; + } + } + + /* Try the designated backup pool and theirs if failing */ + while (backup_pool) { + D_MAGIC_ASSERT( backup_pool, CoreSurfacePool ); + + D_DEBUG_AT( Core_SurfacePool, " -> allocating in '%s'\n", backup_pool->desc.name ); + + /* Allocate in backup pool */ + ret = dfb_surface_pool_allocate( backup_pool, buffer, &backup ); + if (ret == DFB_OK) { + /* Update new allocation */ + ret = dfb_surface_allocation_update( backup, CSAF_NONE ); + if (ret) { + D_DEBUG_AT( Core_SurfacePool, " -> update failed! (%s)\n", DirectFBErrorString(ret) ); + dfb_surface_pool_deallocate( backup_pool, backup ); + backup = NULL; + } + else + return DFB_OK; + } + else + D_DEBUG_AT( Core_SurfacePool, " -> allocation failed! (%s)\n", DirectFBErrorString(ret) ); + + backup_pool = backup_pool->backup; + } + } + else + D_DEBUG_AT( Core_SurfacePool, " -> not up to date anyhow\n" ); + + return ret; +} + diff --git a/Source/DirectFB/src/core/surface_pool.h b/Source/DirectFB/src/core/surface_pool.h new file mode 100755 index 0000000..fc049e0 --- /dev/null +++ b/Source/DirectFB/src/core/surface_pool.h @@ -0,0 +1,272 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef __CORE__SURFACE_POOL_H__ +#define __CORE__SURFACE_POOL_H__ + +#include + +#include + +#include +#include + + +typedef enum { + CSPCAPS_NONE = 0x00000000, + + CSPCAPS_PHYSICAL = 0x00000001, /* pool provides physical address to buffer */ + CSPCAPS_VIRTUAL = 0x00000002, /* pool provides virtual address to buffer */ + + CSPCAPS_ALL = 0x00000003 +} CoreSurfacePoolCapabilities; + +typedef enum { + CSPP_DEFAULT, + CSPP_PREFERED, + CSPP_ULTIMATE +} CoreSurfacePoolPriority; + +/* + * Increase this number when changes result in binary incompatibility! + */ +#define DFB_SURFACE_POOL_ABI_VERSION 1 + +#define DFB_SURFACE_POOL_DESC_NAME_LENGTH 44 + + +typedef struct { + CoreSurfacePoolCapabilities caps; + CoreSurfaceAccessFlags access[_CSAID_NUM]; + CoreSurfaceTypeFlags types; + CoreSurfacePoolPriority priority; + char name[DFB_SURFACE_POOL_DESC_NAME_LENGTH]; + unsigned long size; +} CoreSurfacePoolDescription; + + +typedef struct { + int (*PoolDataSize)( void ); + int (*PoolLocalDataSize)( void ); + int (*AllocationDataSize)( void ); + + /* + * Pool init/destroy + */ + DFBResult (*InitPool) ( CoreDFB *core, + CoreSurfacePool *pool, + void *pool_data, + void *pool_local, + void *system_data, + CoreSurfacePoolDescription *ret_desc ); + + DFBResult (*JoinPool) ( CoreDFB *core, + CoreSurfacePool *pool, + void *pool_data, + void *pool_local, + void *system_data ); + + DFBResult (*DestroyPool)( CoreSurfacePool *pool, + void *pool_data, + void *pool_local ); + + DFBResult (*LeavePool) ( CoreSurfacePool *pool, + void *pool_data, + void *pool_local ); + + + + DFBResult (*TestConfig) ( CoreSurfacePool *pool, + void *pool_data, + void *pool_local, + CoreSurfaceBuffer *buffer, + const CoreSurfaceConfig *config ); + /* + * Buffer management + */ + DFBResult (*AllocateBuffer) ( CoreSurfacePool *pool, + void *pool_data, + void *pool_local, + CoreSurfaceBuffer *buffer, + CoreSurfaceAllocation *allocation, + void *alloc_data ); + + DFBResult (*DeallocateBuffer)( CoreSurfacePool *pool, + void *pool_data, + void *pool_local, + CoreSurfaceBuffer *buffer, + CoreSurfaceAllocation *allocation, + void *alloc_data ); + + /* + * Locking + */ + DFBResult (*Lock) ( CoreSurfacePool *pool, + void *pool_data, + void *pool_local, + CoreSurfaceAllocation *allocation, + void *alloc_data, + CoreSurfaceBufferLock *lock ); + + DFBResult (*Unlock)( CoreSurfacePool *pool, + void *pool_data, + void *pool_local, + CoreSurfaceAllocation *allocation, + void *alloc_data, + CoreSurfaceBufferLock *lock ); + + /* + * Read/write + */ + DFBResult (*Read) ( CoreSurfacePool *pool, + void *pool_data, + void *pool_local, + CoreSurfaceAllocation *allocation, + void *alloc_data, + void *destination, + int pitch, + const DFBRectangle *rect ); + + DFBResult (*Write) ( CoreSurfacePool *pool, + void *pool_data, + void *pool_local, + CoreSurfaceAllocation *allocation, + void *alloc_data, + const void *source, + int pitch, + const DFBRectangle *rect ); + + /* + * Muck out + */ + DFBResult (*MuckOut) ( CoreSurfacePool *pool, + void *pool_data, + void *pool_local, + CoreSurfaceBuffer *buffer ); +} SurfacePoolFuncs; + + +struct __DFB_CoreSurfacePool { + int magic; + + FusionSkirmish lock; + + CoreSurfacePoolID pool_id; + + CoreSurfacePoolDescription desc; + + int pool_data_size; + int pool_local_data_size; + int alloc_data_size; + + void *data; + + FusionVector allocs; + + FusionSHMPoolShared *shmpool; + + CoreSurfacePool *backup; +}; + + +typedef DFBEnumerationResult (*CoreSurfacePoolCallback)( CoreSurfacePool *pool, + void *ctx ); + +typedef DFBEnumerationResult (*CoreSurfaceAllocCallback)( CoreSurfaceAllocation *allocation, + void *ctx ); + + + +DFBResult dfb_surface_pools_negotiate( CoreSurfaceBuffer *buffer, + CoreSurfaceAccessorID accessor, + CoreSurfaceAccessFlags access, + CoreSurfacePool **ret_pools, + unsigned int max_pools, + unsigned int *ret_num ); + +DFBResult dfb_surface_pools_enumerate( CoreSurfacePoolCallback callback, + void *ctx ); + +DFBResult dfb_surface_pools_allocate ( CoreSurfaceBuffer *buffer, + CoreSurfaceAccessorID accessor, + CoreSurfaceAccessFlags access, + CoreSurfaceAllocation **ret_allocation ); + + +DFBResult dfb_surface_pool_initialize( CoreDFB *core, + const SurfacePoolFuncs *funcs, + CoreSurfacePool **ret_pool ); + +DFBResult dfb_surface_pool_join ( CoreDFB *core, + CoreSurfacePool *pool, + const SurfacePoolFuncs *funcs ); + +DFBResult dfb_surface_pool_destroy ( CoreSurfacePool *pool ); + +DFBResult dfb_surface_pool_leave ( CoreSurfacePool *pool ); + + + +DFBResult dfb_surface_pool_allocate ( CoreSurfacePool *pool, + CoreSurfaceBuffer *buffer, + CoreSurfaceAllocation **ret_allocation ); + +DFBResult dfb_surface_pool_deallocate( CoreSurfacePool *pool, + CoreSurfaceAllocation *allocation ); + +DFBResult dfb_surface_pool_displace ( CoreSurfacePool *pool, + CoreSurfaceBuffer *buffer, + CoreSurfaceAllocation **ret_allocation ); + +DFBResult dfb_surface_pool_lock ( CoreSurfacePool *pool, + CoreSurfaceAllocation *allocation, + CoreSurfaceBufferLock *lock ); + +DFBResult dfb_surface_pool_unlock ( CoreSurfacePool *pool, + CoreSurfaceAllocation *allocation, + CoreSurfaceBufferLock *lock ); + +DFBResult dfb_surface_pool_read ( CoreSurfacePool *pool, + CoreSurfaceAllocation *allocation, + void *data, + int pitch, + const DFBRectangle *rect ); + +DFBResult dfb_surface_pool_write ( CoreSurfacePool *pool, + CoreSurfaceAllocation *allocation, + const void *data, + int pitch, + const DFBRectangle *rect ); + +DFBResult dfb_surface_pool_enumerate ( CoreSurfacePool *pool, + CoreSurfaceAllocCallback callback, + void *ctx ); + + +#endif + diff --git a/Source/DirectFB/src/core/surface_pool_bridge.c b/Source/DirectFB/src/core/surface_pool_bridge.c new file mode 100755 index 0000000..244ca2d --- /dev/null +++ b/Source/DirectFB/src/core/surface_pool_bridge.c @@ -0,0 +1,531 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +//#define DIRECT_ENABLE_DEBUG + +#include + +#include +#include + +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include + +#include + +#include + + +D_DEBUG_DOMAIN( Core_SurfPoolBridge, "Core/SurfPoolBridge", "DirectFB Core Surface Pool Bridge" ); + +/**********************************************************************************************************************/ + +static const SurfacePoolBridgeFuncs *bridge_funcs[MAX_SURFACE_POOL_BRIDGES]; +static void *bridge_locals[MAX_SURFACE_POOL_BRIDGES]; +static int bridge_count; +static CoreSurfacePoolBridge *bridge_array[MAX_SURFACE_POOL_BRIDGES]; + +/**********************************************************************************************************************/ + +static inline const SurfacePoolBridgeFuncs * +get_funcs( const CoreSurfacePoolBridge *bridge ) +{ + D_MAGIC_ASSERT( bridge, CoreSurfacePoolBridge ); + + D_ASSERT( bridge->bridge_id >= 0 ); + D_ASSERT( bridge->bridge_id < MAX_SURFACE_POOL_BRIDGES ); + D_ASSERT( bridge_funcs[bridge->bridge_id] != NULL ); + + /* Return function table of the bridge. */ + return bridge_funcs[bridge->bridge_id]; +} + +static inline void * +get_local( const CoreSurfacePoolBridge *bridge ) +{ + D_MAGIC_ASSERT( bridge, CoreSurfacePoolBridge ); + + D_ASSERT( bridge->bridge_id >= 0 ); + D_ASSERT( bridge->bridge_id < MAX_SURFACE_POOL_BRIDGES ); + + /* Return local data of the bridge. */ + return bridge_locals[bridge->bridge_id]; +} + +/**********************************************************************************************************************/ + +static DFBResult init_bridge( CoreDFB *core, + CoreSurfacePoolBridge *bridge, + const SurfacePoolBridgeFuncs *funcs, + void *context ); + +/**********************************************************************************************************************/ + +DFBResult +dfb_surface_pool_bridge_initialize( CoreDFB *core, + const SurfacePoolBridgeFuncs *funcs, + void *context, + CoreSurfacePoolBridge **ret_bridge ) +{ + DFBResult ret; + CoreSurfacePoolBridge *bridge; + FusionSHMPoolShared *shmpool; + + D_DEBUG_AT( Core_SurfPoolBridge, "%s( %p, %p )\n", __FUNCTION__, funcs, context ); + + D_ASSERT( core != NULL ); + D_ASSERT( funcs != NULL ); + D_ASSERT( ret_bridge != NULL ); + + /* Check against bridge limit. */ + if (bridge_count == MAX_SURFACE_POOL_BRIDGES) { + D_ERROR( "Core/SurfacePoolBridge: Maximum number of bridges (%d) reached!\n", MAX_SURFACE_POOL_BRIDGES ); + return DFB_LIMITEXCEEDED; + } + + D_ASSERT( bridge_funcs[bridge_count] == NULL ); + + shmpool = dfb_core_shmpool( core ); + + /* Allocate bridge structure. */ + bridge = SHCALLOC( shmpool, 1, sizeof(CoreSurfacePoolBridge) ); + if (!bridge) + return D_OOSHM(); + + /* Assign a bridge ID. */ + bridge->bridge_id = bridge_count++; + + /* Remember shared memory pool. */ + bridge->shmpool = shmpool; + + /* Set function table of the bridge. */ + bridge_funcs[bridge->bridge_id] = funcs; + + /* Add to global bridge list. */ + bridge_array[bridge->bridge_id] = bridge; + + D_MAGIC_SET( bridge, CoreSurfacePoolBridge ); + + ret = init_bridge( core, bridge, funcs, context ); + if (ret) { + bridge_count--; + D_MAGIC_CLEAR( bridge ); + SHFREE( shmpool, bridge ); + return ret; + } + + /* Return the new bridge. */ + *ret_bridge = bridge; + + return DFB_OK; +} + +DFBResult +dfb_surface_pool_bridge_join( CoreDFB *core, + CoreSurfacePoolBridge *bridge, + const SurfacePoolBridgeFuncs *funcs, + void *context ) +{ + DFBResult ret; + + D_MAGIC_ASSERT( bridge, CoreSurfacePoolBridge ); + + D_DEBUG_AT( Core_SurfPoolBridge, "%s( %p [%d], %p, %p )\n", __FUNCTION__, bridge, bridge->bridge_id, funcs, context ); + + D_ASSERT( core != NULL ); + D_ASSERT( funcs != NULL ); + + D_ASSERT( bridge->bridge_id < MAX_SURFACE_POOL_BRIDGES ); + D_ASSERT( bridge->bridge_id == bridge_count ); + D_ASSERT( bridge_funcs[bridge->bridge_id] == NULL ); + + /* Enforce same order as initialization to be used during join. */ + if (bridge->bridge_id != bridge_count) { + D_ERROR( "Core/SurfacePoolBridge: Wrong order of joining bridges, got %d, should be %d!\n", + bridge->bridge_id, bridge_count ); + return DFB_BUG; + } + + /* Allocate local bridge data. */ + if (bridge->bridge_local_data_size && + !(bridge_locals[bridge->bridge_id] = D_CALLOC( 1, bridge->bridge_local_data_size ))) + return D_OOM(); + + /* Set function table of the bridge. */ + bridge_funcs[bridge->bridge_id] = funcs; + + /* Add to global bridge list. */ + bridge_array[bridge->bridge_id] = bridge; + + /* Adjust bridge count. */ + if (bridge_count < bridge->bridge_id + 1) + bridge_count = bridge->bridge_id + 1; + + funcs = get_funcs( bridge ); + + if (funcs->JoinPoolBridge) { + ret = funcs->JoinPoolBridge( core, bridge, bridge->data, get_local(bridge), context ); + if (ret) { + D_DERROR( ret, "Core/SurfacePoolBridge: Joining '%s' failed!\n", bridge->desc.name ); + + if (bridge_locals[bridge->bridge_id]) { + D_FREE( bridge_locals[bridge->bridge_id] ); + bridge_locals[bridge->bridge_id] = NULL; + } + + bridge_array[bridge->bridge_id] = NULL; + bridge_funcs[bridge->bridge_id] = NULL; + + bridge_count--; + + return ret; + } + } + + return DFB_OK; +} + +DFBResult +dfb_surface_pool_bridge_destroy( CoreSurfacePoolBridge *bridge ) +{ + CoreSurfacePoolBridgeID bridge_id; + const SurfacePoolBridgeFuncs *funcs; + + D_MAGIC_ASSERT( bridge, CoreSurfacePoolBridge ); + + bridge_id = bridge->bridge_id; + + D_DEBUG_AT( Core_SurfPoolBridge, "%s( %p, '%s' [%d] )\n", __FUNCTION__, bridge, bridge->desc.name, bridge_id ); + + D_ASSERT( bridge->bridge_id >= 0 ); + D_ASSERT( bridge_id < MAX_SURFACE_POOL_BRIDGES ); + D_ASSERT( bridge_array[bridge_id] == bridge ); + + funcs = get_funcs( bridge ); + + if (funcs->DestroyPoolBridge) + funcs->DestroyPoolBridge( bridge, bridge->data, get_local(bridge) ); + + /* Free shared bridge data. */ + if (bridge->data) + SHFREE( bridge->shmpool, bridge->data ); + + /* Free local bridge data. */ + if (bridge_locals[bridge_id]) + D_FREE( bridge_locals[bridge_id] ); + + /* Remove from arrays. */ + bridge_array[bridge_id] = NULL; + bridge_funcs[bridge_id] = NULL; + bridge_locals[bridge_id] = NULL; + + fusion_skirmish_destroy( &bridge->lock ); + + D_MAGIC_CLEAR( bridge ); + + SHFREE( bridge->shmpool, bridge ); + + return DFB_OK; +} + +DFBResult +dfb_surface_pool_bridge_leave( CoreSurfacePoolBridge *bridge ) +{ + CoreSurfacePoolBridgeID bridge_id; + const SurfacePoolBridgeFuncs *funcs; + + D_MAGIC_ASSERT( bridge, CoreSurfacePoolBridge ); + + bridge_id = bridge->bridge_id; + + D_DEBUG_AT( Core_SurfPoolBridge, "%s( %p, '%s' [%d] )\n", __FUNCTION__, bridge, bridge->desc.name, bridge_id ); + + D_ASSERT( bridge->bridge_id >= 0 ); + D_ASSERT( bridge_id < MAX_SURFACE_POOL_BRIDGES ); + D_ASSERT( bridge_array[bridge_id] == bridge ); + + funcs = get_funcs( bridge ); + + if (funcs->LeavePoolBridge) + funcs->LeavePoolBridge( bridge, bridge->data, get_local(bridge) ); + + /* Free local bridge data. */ + if (bridge_locals[bridge_id]) + D_FREE( bridge_locals[bridge_id] ); + + /* Remove from arrays. */ + bridge_array[bridge_id] = NULL; + bridge_funcs[bridge_id] = NULL; + bridge_locals[bridge_id] = NULL; + + return DFB_OK; +} + +/**********************************************************************************************************************/ + +DFBResult +dfb_surface_pool_bridges_enumerate( CoreSurfacePoolBridgeCallback callback, + void *ctx ) +{ + int i; + + D_ASSERT( callback != NULL ); + + D_DEBUG_AT( Core_SurfPoolBridge, "%s( %p, %p )\n", __FUNCTION__, callback, ctx ); + + for (i=0; i 0 ); + D_ASSERT( ret_transfer != NULL ); + + alloc_size = sizeof(CoreSurfacePoolTransfer) + num_rects * sizeof(DFBRectangle) + bridge->transfer_data_size; + + transfer = SHCALLOC( bridge->shmpool, 1, alloc_size ); + if (!transfer) + return D_OOSHM(); + + transfer->bridge = bridge; + transfer->buffer = buffer; + transfer->from = from; + transfer->to = to; + + transfer->rects = (DFBRectangle*)(transfer + 1); + + if (bridge->transfer_data_size) + transfer->data = transfer->rects + num_rects; + + transfer->num_rects = num_rects; + + direct_memcpy( transfer->rects, rects, num_rects * sizeof(DFBRectangle) ); + + D_MAGIC_SET( transfer, CoreSurfacePoolTransfer ); + + *ret_transfer = transfer; + + return DFB_OK; +} + +static void +deallocate_transfer( CoreSurfacePoolTransfer *transfer ) +{ + CoreSurfacePoolBridge *bridge; + + D_MAGIC_ASSERT( transfer, CoreSurfacePoolTransfer ); + + bridge = transfer->bridge; + D_MAGIC_ASSERT( bridge, CoreSurfacePoolBridge ); + + D_MAGIC_CLEAR( transfer ); + + SHFREE( bridge->shmpool, transfer ); +} + +DFBResult +dfb_surface_pool_bridges_transfer( CoreSurfaceBuffer *buffer, + CoreSurfaceAllocation *from, + CoreSurfaceAllocation *to, + const DFBRectangle *rects, + unsigned int num_rects ) +{ + DFBResult ret; + int i; + DFBRectangle rect; + CoreSurface *surface; + CoreSurfacePoolBridge *bridge = NULL; + const SurfacePoolBridgeFuncs *funcs; + CoreSurfacePoolTransfer *transfer; + + D_MAGIC_ASSERT( buffer, CoreSurfaceBuffer ); + CORE_SURFACE_ALLOCATION_ASSERT( from ); + CORE_SURFACE_ALLOCATION_ASSERT( to ); + D_ASSERT( rects != NULL || num_rects == 0 ); + D_ASSERT( num_rects > 0 || rects == NULL ); + + D_DEBUG_AT( Core_SurfPoolBridge, "%s( %p [%s], %p -> %p, %d rects )\n", __FUNCTION__, + buffer, dfb_pixelformat_name( buffer->format ), from, to, num_rects ); + + surface = buffer->surface; + D_MAGIC_ASSERT( surface, CoreSurface ); + FUSION_SKIRMISH_ASSERT( &surface->lock ); + + if (!rects) { + rect.x = rect.y = 0; + rect.w = surface->config.size.w; + rect.h = surface->config.size.h; + + rects = ▭ + num_rects = 1; + } + + for (i=0; iCheckTransfer != NULL ); + + ret = funcs->CheckTransfer( bridge, bridge->data, get_local(bridge), buffer, from, to ); + if (ret) + bridge = NULL; + else + break; + } + + if (!bridge) + return DFB_UNSUPPORTED; + + D_DEBUG_AT( Core_SurfPoolBridge, " -> using '%s'\n", bridge->desc.name ); + + ret = allocate_transfer( bridge, buffer, from, to, rects, num_rects, &transfer ); + if (ret) + return ret; + + D_ASSERT( funcs->StartTransfer != NULL ); + + D_DEBUG_AT( Core_SurfPoolBridge, " -> start...\n" ); + + ret = funcs->StartTransfer( bridge, bridge->data, get_local(bridge), transfer, transfer->data ); + if (ret) + D_DERROR( ret, "Core/SurfacePoolBridge: Starting transfer via '%s' failed!\n", bridge->desc.name ); + else if (funcs->FinishTransfer) { + D_DEBUG_AT( Core_SurfPoolBridge, " -> finish...\n" ); + + ret = funcs->FinishTransfer( bridge, bridge->data, get_local(bridge), transfer, transfer->data ); + if (ret) + D_DERROR( ret, "Core/SurfacePoolBridge: Finishing transfer via '%s' failed!\n", bridge->desc.name ); + } + + D_DEBUG_AT( Core_SurfPoolBridge, " => %s\n", DirectResultString(ret) ); + + deallocate_transfer( transfer ); + + return ret; +} + +/**********************************************************************************************************************/ + +static DFBResult +init_bridge( CoreDFB *core, + CoreSurfacePoolBridge *bridge, + const SurfacePoolBridgeFuncs *funcs, + void *context ) +{ + DFBResult ret; + + D_MAGIC_ASSERT( bridge, CoreSurfacePoolBridge ); + D_ASSERT( funcs != NULL ); + D_ASSERT( funcs->InitPoolBridge != NULL ); + + D_DEBUG_AT( Core_SurfPoolBridge, "%s( %p, %p )\n", __FUNCTION__, bridge, funcs ); + + if (funcs->PoolBridgeDataSize) + bridge->bridge_data_size = funcs->PoolBridgeDataSize(); + + if (funcs->PoolBridgeLocalDataSize) + bridge->bridge_local_data_size = funcs->PoolBridgeLocalDataSize(); + + if (funcs->PoolTransferDataSize) + bridge->transfer_data_size = funcs->PoolTransferDataSize(); + + /* Allocate shared bridge data. */ + if (bridge->bridge_data_size) { + bridge->data = SHCALLOC( bridge->shmpool, 1, bridge->bridge_data_size ); + if (!bridge->data) + return D_OOSHM(); + } + + /* Allocate local bridge data. */ + if (bridge->bridge_local_data_size && + !(bridge_locals[bridge->bridge_id] = D_CALLOC( 1, bridge->bridge_local_data_size ))) + { + SHFREE( bridge->shmpool, bridge->data ); + return D_OOM(); + } + + ret = funcs->InitPoolBridge( core, bridge, bridge->data, get_local(bridge), context, &bridge->desc ); + if (ret) { + D_DERROR( ret, "Core/SurfacePoolBridge: Initializing '%s' failed!\n", bridge->desc.name ); + + if (bridge_locals[bridge->bridge_id]) { + D_FREE( bridge_locals[bridge->bridge_id] ); + bridge_locals[bridge->bridge_id] = NULL; + } + + if (bridge->data) { + SHFREE( bridge->shmpool, bridge->data ); + bridge->data = NULL; + } + + bridge_array[bridge->bridge_id] = NULL; + bridge_funcs[bridge->bridge_id] = NULL; + + return ret; + } + + fusion_skirmish_init( &bridge->lock, bridge->desc.name, dfb_core_world(core) ); + + return DFB_OK; +} + diff --git a/Source/DirectFB/src/core/surface_pool_bridge.h b/Source/DirectFB/src/core/surface_pool_bridge.h new file mode 100755 index 0000000..8fb6dda --- /dev/null +++ b/Source/DirectFB/src/core/surface_pool_bridge.h @@ -0,0 +1,187 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef __CORE__SURFACE_POOL_BRIDGE_H__ +#define __CORE__SURFACE_POOL_BRIDGE_H__ + +#include + +#include + +#include +#include + + +typedef enum { + CSPBCAPS_NONE = 0x00000000, + + CSPBCAPS_ALL = 0x00000000 +} CoreSurfacePoolBridgeCapabilities; + +/* + * Increase this number when changes result in binary incompatibility! + */ +#define DFB_SURFACE_POOL_BRIDGE_ABI_VERSION 1 + +#define DFB_SURFACE_POOL_BRIDGE_DESC_NAME_LENGTH 44 + + +typedef struct { + CoreSurfacePoolBridgeCapabilities caps; + char name[DFB_SURFACE_POOL_BRIDGE_DESC_NAME_LENGTH]; +} CoreSurfacePoolBridgeDescription; + + +typedef struct { + int (*PoolBridgeDataSize)( void ); + int (*PoolBridgeLocalDataSize)( void ); + + int (*PoolTransferDataSize)( void ); + + /* + * Bridge init/destroy + */ + DFBResult (*InitPoolBridge) ( CoreDFB *core, + CoreSurfacePoolBridge *bridge, + void *bridge_data, + void *bridge_local, + void *context, + CoreSurfacePoolBridgeDescription *ret_desc ); + + DFBResult (*JoinPoolBridge) ( CoreDFB *core, + CoreSurfacePoolBridge *bridge, + void *bridge_data, + void *bridge_local, + void *context ); + + DFBResult (*DestroyPoolBridge)( CoreSurfacePoolBridge *bridge, + void *bridge_data, + void *bridge_local ); + + DFBResult (*LeavePoolBridge) ( CoreSurfacePoolBridge *bridge, + void *bridge_data, + void *bridge_local ); + + + /* + * Probe + */ + DFBResult (*CheckTransfer) ( CoreSurfacePoolBridge *bridge, + void *bridge_data, + void *bridge_local, + CoreSurfaceBuffer *buffer, + CoreSurfaceAllocation *from, + CoreSurfaceAllocation *to ); + + /* + * Transfer + */ + DFBResult (*StartTransfer) ( CoreSurfacePoolBridge *bridge, + void *bridge_data, + void *bridge_local, + CoreSurfacePoolTransfer *transfer, + void *transfer_data ); + + DFBResult (*FinishTransfer) ( CoreSurfacePoolBridge *bridge, + void *bridge_data, + void *bridge_local, + CoreSurfacePoolTransfer *transfer, + void *transfer_data ); +} SurfacePoolBridgeFuncs; + + +struct __DFB_CoreSurfacePoolBridge { + int magic; + + FusionSkirmish lock; + + CoreSurfacePoolBridgeID bridge_id; + + CoreSurfacePoolBridgeDescription desc; + + int bridge_data_size; + int bridge_local_data_size; + int transfer_data_size; + + void *data; + + FusionSHMPoolShared *shmpool; + + DirectLink *transfers; +}; + +struct __DFB_CoreSurfacePoolTransfer { + DirectLink link; + + int magic; + + CoreSurfacePoolBridge *bridge; + + CoreSurfaceBuffer *buffer; + CoreSurfaceAllocation *from; + CoreSurfaceAllocation *to; + + DFBRectangle *rects; + unsigned int num_rects; + + void *data; +}; + + +typedef DFBEnumerationResult (*CoreSurfacePoolBridgeCallback)( CoreSurfacePoolBridge *bridge, + void *ctx ); + + + +DFBResult dfb_surface_pool_bridges_enumerate( CoreSurfacePoolBridgeCallback callback, + void *ctx ); + +DFBResult dfb_surface_pool_bridges_transfer ( CoreSurfaceBuffer *buffer, + CoreSurfaceAllocation *from, + CoreSurfaceAllocation *to, + const DFBRectangle *rects, + unsigned int num_rects ); + + +DFBResult dfb_surface_pool_bridge_initialize( CoreDFB *core, + const SurfacePoolBridgeFuncs *funcs, + void *context, + CoreSurfacePoolBridge **ret_bridge ); + +DFBResult dfb_surface_pool_bridge_join ( CoreDFB *core, + CoreSurfacePoolBridge *pool, + const SurfacePoolBridgeFuncs *funcs, + void *context ); + +DFBResult dfb_surface_pool_bridge_destroy ( CoreSurfacePoolBridge *bridge ); + +DFBResult dfb_surface_pool_bridge_leave ( CoreSurfacePoolBridge *bridge ); + + +#endif + diff --git a/Source/DirectFB/src/core/system.c b/Source/DirectFB/src/core/system.c new file mode 100755 index 0000000..6a78eb0 --- /dev/null +++ b/Source/DirectFB/src/core/system.c @@ -0,0 +1,464 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include + +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include + +DEFINE_MODULE_DIRECTORY( dfb_core_systems, "systems", DFB_CORE_SYSTEM_ABI_VERSION ); + + +D_DEBUG_DOMAIN( Core_System, "Core/System", "DirectFB System Core" ); + +/**********************************************************************************************************************/ + +typedef struct { + int magic; + + CoreSystemInfo system_info; +} DFBSystemCoreShared; + +struct __DFB_DFBSystemCore { + int magic; + + CoreDFB *core; + + DFBSystemCoreShared *shared; +}; + + +DFB_CORE_PART( system_core, SystemCore ); + +/**********************************************************************************************************************/ + +static DFBSystemCoreShared *system_field = NULL; /* FIXME */ + +static DirectModuleEntry *system_module = NULL; /* FIXME */ +static const CoreSystemFuncs *system_funcs = NULL; /* FIXME */ +static CoreSystemInfo system_info; /* FIXME */ +static void *system_data = NULL; /* FIXME */ + +/**********************************************************************************************************************/ + +static DFBResult +dfb_system_core_initialize( CoreDFB *core, + DFBSystemCore *data, + DFBSystemCoreShared *shared ) +{ + DFBResult ret; + + D_DEBUG_AT( Core_System, "dfb_system_core_initialize( %p, %p, %p )\n", core, data, shared ); + + D_ASSERT( data != NULL ); + D_ASSERT( shared != NULL ); + + data->core = core; + data->shared = shared; + + + system_field = shared; /* FIXME */ + + system_field->system_info = system_info; + + ret = system_funcs->Initialize( core, &system_data ); + if (ret) + return ret; + + + D_MAGIC_SET( data, DFBSystemCore ); + D_MAGIC_SET( shared, DFBSystemCoreShared ); + + return DFB_OK; +} + +static DFBResult +dfb_system_core_join( CoreDFB *core, + DFBSystemCore *data, + DFBSystemCoreShared *shared ) +{ + DFBResult ret; + + D_DEBUG_AT( Core_System, "dfb_system_core_join( %p, %p, %p )\n", core, data, shared ); + + D_ASSERT( data != NULL ); + D_MAGIC_ASSERT( shared, DFBSystemCoreShared ); + + data->core = core; + data->shared = shared; + + + system_field = shared; /* FIXME */ + + if (system_field->system_info.type != system_info.type || + strcmp( system_field->system_info.name, system_info.name )) + { + D_ERROR( "DirectFB/core/system: " + "running system '%s' doesn't match system '%s'!\n", + system_field->system_info.name, system_info.name ); + + system_field = NULL; + + return DFB_UNSUPPORTED; + } + + if (system_field->system_info.version.major != system_info.version.major || + system_field->system_info.version.minor != system_info.version.minor) + { + D_ERROR( "DirectFB/core/system: running system version '%d.%d' " + "doesn't match version '%d.%d'!\n", + system_field->system_info.version.major, + system_field->system_info.version.minor, + system_info.version.major, + system_info.version.minor ); + + system_field = NULL; + + return DFB_UNSUPPORTED; + } + + ret = system_funcs->Join( core, &system_data ); + if (ret) + return ret; + + + D_MAGIC_SET( data, DFBSystemCore ); + + return DFB_OK; +} + +static DFBResult +dfb_system_core_shutdown( DFBSystemCore *data, + bool emergency ) +{ + DFBResult ret; + DFBSystemCoreShared *shared; + + D_DEBUG_AT( Core_System, "dfb_system_core_shutdown( %p, %semergency )\n", data, emergency ? "" : "no " ); + + D_MAGIC_ASSERT( data, DFBSystemCore ); + D_MAGIC_ASSERT( data->shared, DFBSystemCoreShared ); + + shared = data->shared; + + + ret = system_funcs->Shutdown( emergency ); + + direct_module_unref( system_module ); + + system_module = NULL; + system_funcs = NULL; + system_field = NULL; + system_data = NULL; + + + D_MAGIC_CLEAR( data ); + D_MAGIC_CLEAR( shared ); + + return ret; +} + +static DFBResult +dfb_system_core_leave( DFBSystemCore *data, + bool emergency ) +{ + DFBResult ret; + DFBSystemCoreShared *shared; + + D_DEBUG_AT( Core_System, "dfb_system_core_leave( %p, %semergency )\n", data, emergency ? "" : "no " ); + + D_MAGIC_ASSERT( data, DFBSystemCore ); + D_MAGIC_ASSERT( data->shared, DFBSystemCoreShared ); + + shared = data->shared; + + + ret = system_funcs->Leave( emergency ); + + direct_module_unref( system_module ); + + system_module = NULL; + system_funcs = NULL; + system_field = NULL; + system_data = NULL; + + + D_MAGIC_CLEAR( data ); + + return ret; +} + +static DFBResult +dfb_system_core_suspend( DFBSystemCore *data ) +{ + DFBSystemCoreShared *shared; + + D_DEBUG_AT( Core_System, "dfb_system_core_suspend( %p )\n", data ); + + D_MAGIC_ASSERT( data, DFBSystemCore ); + D_MAGIC_ASSERT( data->shared, DFBSystemCoreShared ); + + shared = data->shared; + + return system_funcs->Suspend(); +} + +static DFBResult +dfb_system_core_resume( DFBSystemCore *data ) +{ + DFBSystemCoreShared *shared; + + D_DEBUG_AT( Core_System, "dfb_system_core_resume( %p )\n", data ); + + D_MAGIC_ASSERT( data, DFBSystemCore ); + D_MAGIC_ASSERT( data->shared, DFBSystemCoreShared ); + + shared = data->shared; + + return system_funcs->Resume(); +} + +/**********************************************************************************************************************/ + +DFBResult +dfb_system_lookup( void ) +{ + DirectLink *l; + + direct_modules_explore_directory( &dfb_core_systems ); + + direct_list_foreach( l, dfb_core_systems.entries ) { + DirectModuleEntry *module = (DirectModuleEntry*) l; + const CoreSystemFuncs *funcs; + + funcs = direct_module_ref( module ); + if (!funcs) + continue; + + if (!system_module || (!dfb_config->system || + !strcasecmp( dfb_config->system, module->name ))) + { + if (system_module) + direct_module_unref( system_module ); + + system_module = module; + system_funcs = funcs; + + funcs->GetSystemInfo( &system_info ); + } + else + direct_module_unref( module ); + } + + if (!system_module) { + D_ERROR("DirectFB/core/system: No system found!\n"); + + return DFB_NOIMPL; + } + + return DFB_OK; +} + +CoreSystemType +dfb_system_type( void ) +{ + return system_info.type; +} + +CoreSystemCapabilities +dfb_system_caps( void ) +{ + return system_info.caps; +} + +void * +dfb_system_data( void ) +{ + return system_data; +} + +volatile void * +dfb_system_map_mmio( unsigned int offset, + int length ) +{ + D_ASSERT( system_funcs != NULL ); + + return system_funcs->MapMMIO( offset, length ); +} + +void +dfb_system_unmap_mmio( volatile void *addr, + int length ) +{ + D_ASSERT( system_funcs != NULL ); + + system_funcs->UnmapMMIO( addr, length ); +} + +int +dfb_system_get_accelerator( void ) +{ + D_ASSERT( system_funcs != NULL ); + + return system_funcs->GetAccelerator(); +} + +VideoMode * +dfb_system_modes( void ) +{ + D_ASSERT( system_funcs != NULL ); + + return system_funcs->GetModes(); +} + +VideoMode * +dfb_system_current_mode( void ) +{ + D_ASSERT( system_funcs != NULL ); + + return system_funcs->GetCurrentMode(); +} + +DFBResult +dfb_system_thread_init( void ) +{ + D_ASSERT( system_funcs != NULL ); + + return system_funcs->ThreadInit(); +} + +bool +dfb_system_input_filter( CoreInputDevice *device, + DFBInputEvent *event ) +{ + D_ASSERT( system_funcs != NULL ); + + return system_funcs->InputFilter( device, event ); +} + +unsigned long +dfb_system_video_memory_physical( unsigned int offset ) +{ + D_ASSERT( system_funcs != NULL ); + + return system_funcs->VideoMemoryPhysical( offset ); +} + +void * +dfb_system_video_memory_virtual( unsigned int offset ) +{ + D_ASSERT( system_funcs != NULL ); + + return system_funcs->VideoMemoryVirtual( offset ); +} + +unsigned int +dfb_system_videoram_length( void ) +{ + D_ASSERT( system_funcs != NULL ); + + return system_funcs->VideoRamLength(); +} + +unsigned long +dfb_system_aux_memory_physical( unsigned int offset ) +{ + D_ASSERT( system_funcs != NULL ); + + return system_funcs->AuxMemoryPhysical( offset ); +} + +void * +dfb_system_aux_memory_virtual( unsigned int offset ) +{ + D_ASSERT( system_funcs != NULL ); + + return system_funcs->AuxMemoryVirtual( offset ); +} + +unsigned int +dfb_system_auxram_length( void ) +{ + D_ASSERT( system_funcs != NULL ); + + return system_funcs->AuxRamLength(); +} + +void +dfb_system_get_busid( int *ret_bus, int *ret_dev, int *ret_func ) +{ + int bus = -1, dev = -1, func = -1; + + D_ASSERT( system_funcs != NULL ); + + system_funcs->GetBusID( &bus, &dev, &func ); + + if (ret_bus) + *ret_bus = bus; + if (ret_dev) + *ret_dev = dev; + if (ret_func) + *ret_func = func; +} + +void +dfb_system_get_deviceid( unsigned int *ret_vendor_id, + unsigned int *ret_device_id ) +{ + unsigned int vendor_id = 0, device_id = 0; + + D_ASSERT( system_funcs != NULL ); + + system_funcs->GetDeviceID( &vendor_id, &device_id ); + + if (ret_vendor_id) + *ret_vendor_id = vendor_id; + if (ret_device_id) + *ret_device_id = device_id; +} + diff --git a/Source/DirectFB/src/core/system.h b/Source/DirectFB/src/core/system.h new file mode 100755 index 0000000..f6d4df1 --- /dev/null +++ b/Source/DirectFB/src/core/system.h @@ -0,0 +1,258 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef __DFB__CORE__SYSTEM_H__ +#define __DFB__CORE__SYSTEM_H__ + +#include + +#include + +#include + +#include + +typedef enum { + CORE_ANY, + CORE_FBDEV, + CORE_X11, + CORE_OSX, + CORE_SDL, + CORE_VNC, + CORE_DEVMEM, + CORE_TI_CMEM +} CoreSystemType; + +typedef enum { + CSCAPS_NONE = 0x00000000, /* None of these. */ + + CSCAPS_ACCELERATION = 0x00000001, /* HW acceleration supported, so probe graphics drivers. */ + + CSCAPS_ALL = 0x00000001 /* All of these. */ +} CoreSystemCapabilities; + +/* + * hold information of a Videomode read from /etc/fb.modes + * (to be replaced by DirectFB's own config system) + */ +typedef struct _VideoMode { + int xres; + int yres; + int bpp; + + int priority; + + int pixclock; + int left_margin; + int right_margin; + int upper_margin; + int lower_margin; + int hsync_len; + int vsync_len; + int hsync_high; + int vsync_high; + int csync_high; + + int laced; + int doubled; + + int sync_on_green; + int external_sync; + int broadcast; + + struct _VideoMode *next; +} VideoMode; + +DECLARE_MODULE_DIRECTORY( dfb_core_systems ); + +/* + * Increase this number when changes result in binary incompatibility! + */ +#define DFB_CORE_SYSTEM_ABI_VERSION 9 + +#define DFB_CORE_SYSTEM_INFO_NAME_LENGTH 60 +#define DFB_CORE_SYSTEM_INFO_VENDOR_LENGTH 80 +#define DFB_CORE_SYSTEM_INFO_URL_LENGTH 120 +#define DFB_CORE_SYSTEM_INFO_LICENSE_LENGTH 40 + + +typedef struct { + int major; /* major version */ + int minor; /* minor version */ +} CoreSystemVersion; /* major.minor, e.g. 0.1 */ + +typedef struct { + CoreSystemVersion version; + + CoreSystemType type; + CoreSystemCapabilities caps; + + char name[DFB_CORE_SYSTEM_INFO_NAME_LENGTH]; + /* Name of system, e.g. 'FBDev' */ + + char vendor[DFB_CORE_SYSTEM_INFO_VENDOR_LENGTH]; + /* Vendor (or author) of the driver, + e.g. 'directfb.org' or 'Denis Oliver Kropp' */ + + char url[DFB_CORE_SYSTEM_INFO_URL_LENGTH]; + /* URL for driver updates, + e.g. 'http://www.directfb.org/' */ + + char license[DFB_CORE_SYSTEM_INFO_LICENSE_LENGTH]; + /* License, e.g. 'LGPL' or 'proprietary' */ +} CoreSystemInfo; + +typedef struct { + void (*GetSystemInfo)( CoreSystemInfo *info ); + + DFBResult (*Initialize)( CoreDFB *core, void **data ); + DFBResult (*Join)( CoreDFB *core, void **data ); + + DFBResult (*Shutdown)( bool emergency ); + DFBResult (*Leave)( bool emergency ); + + DFBResult (*Suspend)( void ); + DFBResult (*Resume)( void ); + + VideoMode* (*GetModes)( void ); + VideoMode* (*GetCurrentMode)( void ); + + /* + * Called at the beginning of a new thread. + */ + DFBResult (*ThreadInit)( void ); + + /* + * Called upon incoming input events. + * Return true to drop the event, e.g. after doing special handling of it. + */ + bool (*InputFilter)( CoreInputDevice *device, DFBInputEvent *event ); + + /* + * Graphics drivers call this function to get access to MMIO regions. + * + * device: Graphics device to map + * offset: Offset from MMIO base (default offset is 0) + * length: Length of mapped region (-1 uses default length) + * + * Returns the virtual address or NULL if mapping failed. + */ + volatile void* (*MapMMIO)( unsigned int offset, + int length ); + + /* + * Graphics drivers call this function to unmap MMIO regions. + * + * addr: Virtual address returned by gfxcard_map_mmio + * length: Length of mapped region (-1 uses default length) + */ + void (*UnmapMMIO)( volatile void *addr, + int length ); + + int (*GetAccelerator)( void ); + + unsigned long (*VideoMemoryPhysical)( unsigned int offset ); + void* (*VideoMemoryVirtual)( unsigned int offset ); + + unsigned int (*VideoRamLength)( void ); + + unsigned long (*AuxMemoryPhysical)( unsigned int offset ); + void* (*AuxMemoryVirtual)( unsigned int offset ); + + unsigned int (*AuxRamLength)( void ); + + void (*GetBusID)( int *ret_bus, int *ret_dev, int *ret_func ); + void (*GetDeviceID)( unsigned int *ret_vendor_id, + unsigned int *ret_device_id ); +} CoreSystemFuncs; + + + +DFBResult +dfb_system_lookup( void ); + +CoreSystemType +dfb_system_type( void ); + +CoreSystemCapabilities +dfb_system_caps( void ); + +void * +dfb_system_data( void ); + +volatile void * +dfb_system_map_mmio( unsigned int offset, + int length ); + +void +dfb_system_unmap_mmio( volatile void *addr, + int length ); + +int +dfb_system_get_accelerator( void ); + +VideoMode * +dfb_system_modes( void ); + +VideoMode * +dfb_system_current_mode( void ); + +DFBResult +dfb_system_thread_init( void ); + +bool +dfb_system_input_filter( CoreInputDevice *device, + DFBInputEvent *event ); + +unsigned long +dfb_system_video_memory_physical( unsigned int offset ); + +void * +dfb_system_video_memory_virtual( unsigned int offset ); + +unsigned int +dfb_system_videoram_length( void ); + +unsigned long +dfb_system_aux_memory_physical( unsigned int offset ); + +void * +dfb_system_aux_memory_virtual( unsigned int offset ); + +unsigned int +dfb_system_auxram_length( void ); + +void +dfb_system_get_busid( int *ret_bus, int *ret_dev, int *ret_func ); + +void +dfb_system_get_deviceid( unsigned int *ret_vendor_id, + unsigned int *ret_device_id ); + +#endif + diff --git a/Source/DirectFB/src/core/windows.c b/Source/DirectFB/src/core/windows.c new file mode 100755 index 0000000..6d60925 --- /dev/null +++ b/Source/DirectFB/src/core/windows.c @@ -0,0 +1,1908 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include + +#include +#include +#include +#include + + +#include + +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + + +D_DEBUG_DOMAIN( Core_Windows, "Core/Windows", "DirectFB Window Core" ); + + +typedef struct { + DirectLink link; + + DFBInputDeviceID id; + GlobalReaction reaction; +} StackDevice; + +/**************************************************************************************************/ + +static bool +core_window_filter( CoreWindow *window, const DFBWindowEvent *event ); + +/**************************************************************************************************/ + +static const ReactionFunc dfb_window_globals[] = { + NULL +}; + +/**************************************************************************************************/ + +/* + * Window destructor. + */ +static void +window_destructor( FusionObject *object, bool zombie, void *ctx ) +{ + CoreWindow *window = (CoreWindow*) object; + CoreWindowStack *stack = window->stack; + + D_DEBUG_AT( Core_Windows, "destroying %p (%d,%d - %dx%d%s)\n", window, + DFB_RECTANGLE_VALS( &window->config.bounds ), zombie ? " ZOMBIE" : ""); + + D_ASSUME( window->stack != NULL ); + + if (!stack) { + fusion_object_destroy( object ); + return; + } + + dfb_windowstack_lock( stack ); + + dfb_window_destroy( window ); + + + if (window->cursor.surface) + dfb_surface_unlink( &window->cursor.surface ); + + if (window->caps & DWCAPS_SUBWINDOW) { + int index; + CoreWindow *toplevel; + + toplevel = window->toplevel; + D_ASSERT( toplevel != NULL ); + + index = fusion_vector_index_of( &toplevel->subwindows, window ); + D_ASSERT( index >= 0 ); + + fusion_vector_remove( &toplevel->subwindows, index ); + + dfb_window_unlink( &window->toplevel ); + } + else { + D_ASSERT( fusion_vector_size(&window->subwindows) == 0 ); + + fusion_vector_destroy( &window->subwindows ); + } + + dfb_windowstack_unlock( stack ); + + + /* Unlink the primary region of the context. */ + if (window->primary_region) + dfb_layer_region_unlink( &window->primary_region ); + + D_MAGIC_CLEAR( window ); + + fusion_object_destroy( object ); +} + +FusionObjectPool * +dfb_window_pool_create( const FusionWorld *world ) +{ + return fusion_object_pool_create( "Window Pool", + sizeof(CoreWindow), + sizeof(DFBWindowEvent), + window_destructor, NULL, world ); +} + +/**************************************************************************************************/ + +static DFBResult +create_region( CoreDFB *core, + CoreLayerContext *context, + CoreWindow *window, + DFBSurfacePixelFormat format, + DFBSurfaceCapabilities surface_caps, + CoreLayerRegion **ret_region, + CoreSurface **ret_surface ) +{ + DFBResult ret; + CoreLayerRegionConfig config; + CoreLayerRegion *region; + CoreSurface *surface; + CoreSurfaceConfig scon; + + D_ASSERT( core != NULL ); + D_ASSERT( context != NULL ); + D_ASSERT( window != NULL ); + D_ASSERT( ret_region != NULL ); + D_ASSERT( ret_surface != NULL ); + + memset( &config, 0, sizeof(CoreLayerRegionConfig) ); + + config.width = window->config.bounds.w; + config.height = window->config.bounds.h; + config.format = format; + config.options = context->config.options & DLOP_FLICKER_FILTERING; + config.source = (DFBRectangle) { 0, 0, config.width, config.height }; + config.dest = window->config.bounds; + config.opacity = 0; + config.alpha_ramp[0] = 0x00; + config.alpha_ramp[1] = 0x55; + config.alpha_ramp[2] = 0xaa; + config.alpha_ramp[3] = 0xff; + + if (surface_caps & DSCAPS_DOUBLE) + config.buffermode = DLBM_BACKVIDEO; + else if (surface_caps & DSCAPS_TRIPLE) + config.buffermode = DLBM_TRIPLE; + else + config.buffermode = DLBM_FRONTONLY; + + if (((context->config.options & DLOP_ALPHACHANNEL) || + (window->config.options & DWOP_ALPHACHANNEL)) && DFB_PIXELFORMAT_HAS_ALPHA(format)) + config.options |= DLOP_ALPHACHANNEL; + + config.options |= DLOP_OPACITY; + + config.surface_caps = surface_caps & (DSCAPS_INTERLACED | + DSCAPS_SEPARATED | + DSCAPS_PREMULTIPLIED); + + ret = dfb_layer_region_create( context, ®ion ); + if (ret) + return ret; + + + do { + ret = dfb_layer_region_set_configuration( region, &config, CLRCF_ALL ); + if (ret) { + if (config.options & DLOP_OPACITY) + config.options &= ~DLOP_OPACITY; + else if (config.options & DLOP_ALPHACHANNEL) + config.options = (config.options & ~DLOP_ALPHACHANNEL) | DLOP_OPACITY; + else { + D_DERROR( ret, "DirectFB/Core/Windows: Unable to set region configuration!\n" ); + dfb_layer_region_unref( region ); + return ret; + } + } + } while (ret); + + scon.flags = CSCONF_SIZE | CSCONF_FORMAT | CSCONF_CAPS; + scon.size.w = config.width; + scon.size.h = config.height; + scon.format = format; + scon.caps = surface_caps | DSCAPS_VIDEOONLY; + + ret = dfb_surface_create( core, &scon, CSTF_SHARED | CSTF_LAYER, context->layer_id, NULL, &surface ); + if (ret) { + dfb_layer_region_unref( region ); + return ret; + } + + ret = dfb_layer_region_set_surface( region, surface ); + if (ret) { + dfb_surface_unref( surface ); + dfb_layer_region_unref( region ); + return ret; + } + + ret = dfb_layer_region_enable( region ); + if (ret) { + dfb_surface_unref( surface ); + dfb_layer_region_unref( region ); + return ret; + } + + *ret_region = region; + *ret_surface = surface; + + return DFB_OK; +} + +static DFBResult +init_subwindow( CoreWindow *window, + CoreWindowStack *stack, + DFBWindowID toplevel_id ) +{ + DFBResult ret; + CoreWindow *toplevel; + + /* Lookup top level window */ + ret = dfb_wm_window_lookup( stack, toplevel_id, &toplevel ); + if (ret) + return ret; + + /* Make sure chosen top level window is not a sub window */ + if (toplevel->caps & DWCAPS_SUBWINDOW) { + D_ASSERT( toplevel->toplevel != NULL ); + D_ASSERT( toplevel->toplevel_id != 0 ); + + return DFB_INVARG; + } + else { + D_ASSERT( toplevel->toplevel == NULL ); + D_ASSERT( toplevel->toplevel_id == 0 ); + } + + /* Link top level window into sub window structure */ + ret = dfb_window_link( &window->toplevel, toplevel ); + if (ret) + return ret; + + /* Add window to sub window list of top level window */ + ret = fusion_vector_add( &toplevel->subwindows, window ); + if (ret) { + dfb_window_unlink( &window->toplevel ); + return ret; + } + + return DFB_OK; +} + +DFBResult +dfb_window_create( CoreWindowStack *stack, + const DFBWindowDescription *desc, + CoreWindow **ret_window ) +{ + DFBResult ret; + CoreSurface *surface; + CoreSurfacePolicy surface_policy = CSP_SYSTEMONLY; + CoreLayer *layer; + CoreLayerContext *context; + CoreWindow *window; + CardCapabilities card_caps; + CoreWindowConfig config; + DFBWindowCapabilities caps; + DFBSurfaceCapabilities surface_caps; + DFBSurfacePixelFormat pixelformat; + DFBWindowID toplevel_id; + + D_DEBUG_AT( Core_Windows, "%s( %p )\n", __FUNCTION__, stack ); + + D_ASSERT( stack != NULL ); + D_ASSERT( stack->context != NULL ); + D_ASSERT( desc != NULL ); + D_ASSERT( desc->width > 0 ); + D_ASSERT( desc->height > 0 ); + D_ASSERT( ret_window != NULL ); + + if (desc->width > 4096 || desc->height > 4096) + return DFB_LIMITEXCEEDED; + + /* Lock the window stack. */ + if (dfb_windowstack_lock( stack )) + return DFB_FUSION; + + context = stack->context; + layer = dfb_layer_at( context->layer_id ); + + + caps = desc->caps; + pixelformat = desc->pixelformat; + surface_caps = desc->surface_caps & (DSCAPS_INTERLACED | DSCAPS_SEPARATED | + DSCAPS_PREMULTIPLIED | DSCAPS_DEPTH | + DSCAPS_STATIC_ALLOC | DSCAPS_SYSTEMONLY | + DSCAPS_VIDEOONLY); + toplevel_id = (desc->flags & DWDESC_TOPLEVEL_ID) ? desc->toplevel_id : 0; + + if (toplevel_id != 0) + caps |= DWCAPS_SUBWINDOW; + else + caps &= ~DWCAPS_SUBWINDOW; + + + if (!dfb_config->translucent_windows) { + caps &= ~DWCAPS_ALPHACHANNEL; + + /*if (DFB_PIXELFORMAT_HAS_ALPHA(pixelformat)) + pixelformat = DSPF_UNKNOWN;*/ + } + + /* Choose pixel format. */ + if (caps & DWCAPS_ALPHACHANNEL) { + if (pixelformat == DSPF_UNKNOWN) { + if (context->config.flags & DLCONF_PIXELFORMAT) + pixelformat = context->config.pixelformat; + + if (! DFB_PIXELFORMAT_HAS_ALPHA(pixelformat)) + pixelformat = DSPF_ARGB; + } + else if (! DFB_PIXELFORMAT_HAS_ALPHA(pixelformat)) { + dfb_windowstack_unlock( stack ); + return DFB_INVARG; + } + } + else if (pixelformat == DSPF_UNKNOWN) { + if (context->config.flags & DLCONF_PIXELFORMAT) + pixelformat = context->config.pixelformat; + else { + D_WARN( "layer config has no pixel format, using RGB16" ); + + pixelformat = DSPF_RGB16; + } + } + + /* Choose window surface policy */ + if ((surface_caps & DSCAPS_VIDEOONLY) || + (context->config.buffermode == DLBM_WINDOWS)) + { + surface_policy = CSP_VIDEOONLY; + } + else if (!(surface_caps & DSCAPS_SYSTEMONLY) && + context->config.buffermode != DLBM_BACKSYSTEM) + { + if (dfb_config->window_policy != -1) { + /* Use the explicitly specified policy. */ + surface_policy = dfb_config->window_policy; + } + else { + /* Examine the hardware capabilities. */ + dfb_gfxcard_get_capabilities( &card_caps ); + + if (card_caps.accel & DFXL_BLIT) { + if ((card_caps.blitting & DSBLIT_BLEND_ALPHACHANNEL) || + !(caps & DWCAPS_ALPHACHANNEL)) + surface_policy = CSP_VIDEOHIGH; + } + } + } + + dfb_surface_caps_apply_policy( surface_policy, &surface_caps ); + + if (caps & DWCAPS_DOUBLEBUFFER) + surface_caps |= DSCAPS_DOUBLE; + + + memset( &config, 0, sizeof(CoreWindowConfig) ); + + config.bounds.x = desc->posx; + config.bounds.y = desc->posy; + config.bounds.w = desc->width; + config.bounds.h = desc->height; + config.stacking = (desc->flags & DWDESC_STACKING) ? desc->stacking : DWSC_MIDDLE; + + config.events = DWET_ALL; + + /* Auto enable blending for ARGB only, not indexed. */ + if ((caps & DWCAPS_ALPHACHANNEL) && + DFB_PIXELFORMAT_HAS_ALPHA (pixelformat) && + !DFB_PIXELFORMAT_IS_INDEXED(pixelformat)) + config.options |= DWOP_ALPHACHANNEL; + + /* Override automatic settings. */ + if (desc->flags & DWDESC_OPTIONS) + config.options = desc->options; + + /* Create the window object. */ + window = dfb_core_create_window( layer->core ); + + window->id = ++stack->id_pool; + window->caps = caps; + window->stack = stack; + window->config = config; + window->config.association = (desc->flags & DWDESC_PARENT) ? desc->parent_id : 0; + window->config.cursor_flags = dfb_config->default_cursor_flags; + + /* Set toplevel window ID (new sub window feature) */ + window->toplevel_id = toplevel_id; + + if (desc->flags & DWDESC_RESOURCE_ID) + window->resource_id = desc->resource_id; + + D_MAGIC_SET( window, CoreWindow ); + + ret = dfb_wm_preconfigure_window( stack, window ); + if(ret) { + D_MAGIC_CLEAR( window ); + fusion_object_destroy( &window->object ); + dfb_windowstack_unlock( stack ); + return ret; + } + + /* wm may have changed values */ + config = window->config; + caps = window->caps; + + /* Initialize sub window... */ + if (caps & DWCAPS_SUBWINDOW) { + ret = init_subwindow( window, stack, toplevel_id ); + if (ret) { + D_MAGIC_CLEAR( window ); + fusion_object_destroy( &window->object ); + dfb_windowstack_unlock( stack ); + return ret; + } + } + else { + /* ...or initialize top level window */ + fusion_vector_init( &window->subwindows, 3, stack->shmpool ); + + /* In case WM forbids sub window request, clear the toplevel window ID */ + window->toplevel_id = 0; + } + + if (dfb_config->warn.flags & DCWF_CREATE_WINDOW) + D_WARN( "create-window %4dx%4d %6s, caps 0x%08x, surface-caps 0x%08x, ID %u", + window->config.bounds.w, window->config.bounds.h, dfb_pixelformat_name(pixelformat), + window->caps, surface_caps, window->id ); + + /* Create the window's surface using the layer's palette if possible. */ + if (! (caps & (DWCAPS_INPUTONLY | DWCAPS_COLOR))) { + if (context->config.buffermode == DLBM_WINDOWS) { + CoreLayerRegion *region = NULL; + + /* Create a region for the window. */ + ret = create_region( layer->core, context, window, + pixelformat, surface_caps, ®ion, &surface ); + if (ret) { + D_MAGIC_CLEAR( window ); + fusion_object_destroy( &window->object ); + dfb_windowstack_unlock( stack ); + return ret; + } + + /* Link the region into the window structure. */ + dfb_layer_region_link( &window->region, region ); + dfb_layer_region_unref( region ); + + /* Link the surface into the window structure. */ + dfb_surface_link( &window->surface, surface ); + dfb_surface_unref( surface ); + } + else { + CoreLayerRegion *region; + + /* Get the primary region of the layer context. */ + ret = dfb_layer_context_get_primary_region( context, true, ®ion ); + if (ret) { + D_MAGIC_CLEAR( window ); + fusion_object_destroy( &window->object ); + dfb_windowstack_unlock( stack ); + return ret; + } + + /* Link the primary region into the window structure. */ + dfb_layer_region_link( &window->primary_region, region ); + dfb_layer_region_unref( region ); + + D_DEBUG_AT( Core_Windows, " -> %dx%d %s %s\n", + window->config.bounds.w, window->config.bounds.h, + dfb_pixelformat_name(pixelformat), + (surface_policy == CSP_VIDEOONLY) ? + "VIDEOONLY" : + ((surface_policy == CSP_SYSTEMONLY) ? + "SYSTEM ONLY" : + "AUTO VIDEO") ); + + /* Give the WM a chance to provide its own surface. */ + if (!window->surface) { + /* Create the surface for the window. */ + ret = dfb_surface_create_simple( layer->core, config.bounds.w, config.bounds.h, + pixelformat, surface_caps, CSTF_SHARED | CSTF_WINDOW, + (desc->flags & DWDESC_RESOURCE_ID) ? + desc->resource_id : window->id, + region->surface ? + region->surface->palette : NULL, &surface ); + if (ret) { + D_DERROR( ret, "Core/Windows: Failed to create window surface!\n" ); + D_MAGIC_CLEAR( window ); + dfb_layer_region_unlink( &window->primary_region ); + fusion_object_destroy( &window->object ); + dfb_windowstack_unlock( stack ); + return ret; + } + + /* Link the surface into the window structure. */ + dfb_surface_link( &window->surface, surface ); + dfb_surface_unref( surface ); + } + } + } + else + D_DEBUG_AT( Core_Windows, " -> %dx%d - INPUT ONLY!\n", + window->config.bounds.w, window->config.bounds.h ); + + D_DEBUG_AT( Core_Windows, " -> %p\n", window ); + + /* Pass the new window to the window manager. */ + ret = dfb_wm_add_window( stack, window ); + if (ret) { + D_DERROR( ret, "Core/Windows: Failed to add window to manager!\n" ); + + D_MAGIC_CLEAR( window ); + + if (window->surface) + dfb_surface_unlink( &window->surface ); + + if (window->primary_region) + dfb_layer_region_unlink( &window->primary_region ); + + if (window->region) + dfb_layer_region_unlink( &window->region ); + + fusion_object_destroy( &window->object ); + dfb_windowstack_unlock( stack ); + return ret; + } + + /* Indicate that initialization is complete. */ + D_FLAGS_SET( window->flags, CWF_INITIALIZED ); + + /* Increase number of windows. */ + stack->num++; + + /* Finally activate the object. */ + fusion_object_activate( &window->object ); + + fusion_reactor_direct( window->object.reactor, true ); + + /* Unlock the window stack. */ + dfb_windowstack_unlock( stack ); + + /* Return the new window. */ + *ret_window = window; + + return DFB_OK;; +} + +void +dfb_window_destroy( CoreWindow *window ) +{ + int i; + DFBWindowEvent evt; + CoreWindowStack *stack; + BoundWindow *bound, *next; + CoreWindow *subwindow; + + D_MAGIC_ASSERT( window, CoreWindow ); + D_ASSERT( DFB_WINDOW_INITIALIZED( window ) ); + + D_DEBUG_AT( Core_Windows, "dfb_window_destroy (%p) [%4d,%4d - %4dx%4d]\n", + window, DFB_RECTANGLE_VALS( &window->config.bounds ) ); + + D_ASSUME( window->stack != NULL ); + + stack = window->stack; + if (!stack) + return; + + /* Lock the window stack. */ + if (dfb_windowstack_lock( stack )) + return; + + /* Destroy sub windows first. */ + fusion_vector_foreach_reverse (subwindow, i, window->subwindows) { + D_ASSERT( subwindow != NULL ); + D_ASSERT( DFB_WINDOW_INITIALIZED( subwindow ) ); + + dfb_window_destroy( subwindow ); + } + + /* Avoid multiple destructions. */ + if (DFB_WINDOW_DESTROYED( window )) { + D_DEBUG_AT( Core_Windows, "%p already destroyed.\n", window ); + dfb_windowstack_unlock( stack ); + return; + } + + /* Unbind bound windows. */ + direct_list_foreach_safe (bound, next, window->bound_windows) { + direct_list_remove( &window->bound_windows, &bound->link ); + + bound->window->boundto = NULL; + + SHFREE( stack->shmpool, bound ); + } + + /* Unbind this window. */ + if (window->boundto) + dfb_window_unbind( window->boundto, window ); + + /* Make sure the window is no longer visible. */ + dfb_window_set_opacity( window, 0 ); + + /* Stop managing the window. */ + dfb_wm_remove_window( stack, window ); + + /* Indicate destruction. */ + D_FLAGS_SET( window->flags, CWF_DESTROYED ); + + /* Hardware allocated? */ + if (window->region) { + /* Disable region (removing it from hardware). */ + dfb_layer_region_disable( window->region ); + + /* Unlink from structure. */ + dfb_layer_region_unlink( &window->region ); + } + + /* Unlink the window's surface. */ + if (window->surface) { + dfb_surface_unlink( &window->surface ); + } + + /* Decrease number of windows. */ + stack->num--; + + /* Unlock the window stack. */ + dfb_windowstack_unlock( stack ); + + + /* Notify listeners. */ + evt.type = DWET_DESTROYED; + dfb_window_post_event( window, &evt ); +} + +DFBResult +dfb_window_change_stacking( CoreWindow *window, + DFBWindowStackingClass stacking ) +{ + DFBResult ret; + CoreWindowStack *stack; + CoreWindowConfig config; + + D_MAGIC_ASSERT( window, CoreWindow ); + D_ASSERT( window->stack != NULL ); + + stack = window->stack; + + /* Lock the window stack. */ + if (dfb_windowstack_lock( stack )) + return DFB_FUSION; + + /* Never call WM after destroying the window. */ + if (DFB_WINDOW_DESTROYED( window )) { + dfb_windowstack_unlock( stack ); + return DFB_DESTROYED; + } + + config.stacking = stacking; + + /* Let the window manager do its work. */ + ret = dfb_wm_set_window_config( window, &config, CWCF_STACKING ); + + /* Unlock the window stack. */ + dfb_windowstack_unlock( stack ); + + return ret; +} + +DFBResult +dfb_window_raise( CoreWindow *window ) +{ + DFBResult ret; + CoreWindowStack *stack; + + D_MAGIC_ASSERT( window, CoreWindow ); + D_ASSERT( window->stack != NULL ); + + stack = window->stack; + + /* Lock the window stack. */ + if (dfb_windowstack_lock( stack )) + return DFB_FUSION; + + /* Never call WM after destroying the window. */ + if (DFB_WINDOW_DESTROYED( window )) { + dfb_windowstack_unlock( stack ); + return DFB_DESTROYED; + } + + /* Let the window manager do its work. */ + ret = dfb_wm_restack_window( window, window, 1 ); + + /* Unlock the window stack. */ + dfb_windowstack_unlock( stack ); + + return ret; +} + +DFBResult +dfb_window_lower( CoreWindow *window ) +{ + DFBResult ret; + CoreWindowStack *stack; + + D_MAGIC_ASSERT( window, CoreWindow ); + D_ASSERT( window->stack != NULL ); + + stack = window->stack; + + /* Lock the window stack. */ + if (dfb_windowstack_lock( stack )) + return DFB_FUSION; + + /* Never call WM after destroying the window. */ + if (DFB_WINDOW_DESTROYED( window )) { + dfb_windowstack_unlock( stack ); + return DFB_DESTROYED; + } + + /* Let the window manager do its work. */ + ret = dfb_wm_restack_window( window, window, -1 ); + + /* Unlock the window stack. */ + dfb_windowstack_unlock( stack ); + + return ret; +} + +DFBResult +dfb_window_raisetotop( CoreWindow *window ) +{ + DFBResult ret; + CoreWindowStack *stack; + + D_MAGIC_ASSERT( window, CoreWindow ); + D_ASSERT( window->stack != NULL ); + + stack = window->stack; + + /* Lock the window stack. */ + if (dfb_windowstack_lock( stack )) + return DFB_FUSION; + + /* Never call WM after destroying the window. */ + if (DFB_WINDOW_DESTROYED( window )) { + dfb_windowstack_unlock( stack ); + return DFB_DESTROYED; + } + + /* Let the window manager do its work. */ + ret = dfb_wm_restack_window( window, NULL, 1 ); + + /* Unlock the window stack. */ + dfb_windowstack_unlock( stack ); + + return ret; +} + +DFBResult +dfb_window_lowertobottom( CoreWindow *window ) +{ + DFBResult ret; + CoreWindowStack *stack; + + D_MAGIC_ASSERT( window, CoreWindow ); + D_ASSERT( window->stack != NULL ); + + stack = window->stack; + + /* Lock the window stack. */ + if (dfb_windowstack_lock( stack )) + return DFB_FUSION; + + /* Never call WM after destroying the window. */ + if (DFB_WINDOW_DESTROYED( window )) { + dfb_windowstack_unlock( stack ); + return DFB_DESTROYED; + } + + /* Let the window manager do its work. */ + ret = dfb_wm_restack_window( window, NULL, 0 ); + + /* Unlock the window stack. */ + dfb_windowstack_unlock( stack ); + + return ret; +} + +DFBResult +dfb_window_putatop( CoreWindow *window, + CoreWindow *lower ) +{ + DFBResult ret; + CoreWindowStack *stack; + + D_MAGIC_ASSERT( window, CoreWindow ); + D_ASSERT( window->stack != NULL ); + + stack = window->stack; + + /* Lock the window stack. */ + if (dfb_windowstack_lock( stack )) + return DFB_FUSION; + + /* Never call WM after destroying the window. */ + if (DFB_WINDOW_DESTROYED( window )) { + dfb_windowstack_unlock( stack ); + return DFB_DESTROYED; + } + + /* Let the window manager do its work. */ + ret = dfb_wm_restack_window( window, lower, 1 ); + + /* Unlock the window stack. */ + dfb_windowstack_unlock( stack ); + + return ret; +} + +DFBResult +dfb_window_putbelow( CoreWindow *window, + CoreWindow *upper ) +{ + DFBResult ret; + CoreWindowStack *stack; + + D_MAGIC_ASSERT( window, CoreWindow ); + D_ASSERT( window->stack != NULL ); + + stack = window->stack; + + /* Lock the window stack. */ + if (dfb_windowstack_lock( stack )) + return DFB_FUSION; + + /* Never call WM after destroying the window. */ + if (DFB_WINDOW_DESTROYED( window )) { + dfb_windowstack_unlock( stack ); + return DFB_DESTROYED; + } + + /* Let the window manager do its work. */ + ret = dfb_wm_restack_window( window, upper, -1 ); + + /* Unlock the window stack. */ + dfb_windowstack_unlock( stack ); + + return ret; +} + +DFBResult +dfb_window_set_config( CoreWindow *window, + const CoreWindowConfig *config, + CoreWindowConfigFlags flags ) +{ + DFBResult ret; + CoreWindowStack *stack = window->stack; + + D_MAGIC_ASSERT( window, CoreWindow ); + + /* Lock the window stack. */ + if (dfb_windowstack_lock( stack )) + return DFB_FUSION; + + /* Never call WM after destroying the window. */ + if (DFB_WINDOW_DESTROYED( window )) { + dfb_windowstack_unlock( stack ); + return DFB_DESTROYED; + } + + ret = dfb_wm_set_window_config( window, config, flags ); + + /* Unlock the window stack. */ + dfb_windowstack_unlock( stack ); + + return ret; +} + +DFBResult +dfb_window_set_cursor_shape( CoreWindow *window, + CoreSurface *surface, + unsigned int hot_x, + unsigned int hot_y ) +{ + DFBResult ret = DFB_OK; + CoreWindowStack *stack = window->stack; + + D_MAGIC_ASSERT( window, CoreWindow ); + + /* Lock the window stack. */ + if (dfb_windowstack_lock( stack )) + return DFB_FUSION; + + /* Never call WM after destroying the window. */ + if (DFB_WINDOW_DESTROYED( window )) { + dfb_windowstack_unlock( stack ); + return DFB_DESTROYED; + } + + window->cursor.hot_x = hot_x; + window->cursor.hot_y = hot_y; + + if (window->cursor.surface) + dfb_surface_unlink( &window->cursor.surface ); + + if (surface) { + ret = dfb_surface_link( &window->cursor.surface, surface ); + if (ret == DFB_OK) { + if (window->flags & CWF_FOCUSED) + dfb_windowstack_cursor_set_shape( stack, surface, hot_x, hot_y ); + } + } + + /* Unlock the window stack. */ + dfb_windowstack_unlock( stack ); + + return ret; +} + +static DFBResult +move_window( CoreWindow *window, + int x, + int y ) +{ + DFBResult ret; + CoreWindowConfig config; + BoundWindow *bound; + + D_MAGIC_ASSERT( window, CoreWindow ); + + config.bounds.x = x; + config.bounds.y = y; + + ret = dfb_wm_set_window_config( window, &config, CWCF_POSITION ); + if (ret) + return ret; + + direct_list_foreach (bound, window->bound_windows) { + move_window( bound->window, + window->config.bounds.x + bound->x, + window->config.bounds.y + bound->y ); + } + + return DFB_OK; +} + +DFBResult +dfb_window_move( CoreWindow *window, + int x, + int y, + bool relative ) +{ + DFBResult ret; + CoreWindowStack *stack = window->stack; + + D_MAGIC_ASSERT( window, CoreWindow ); + + /* Lock the window stack. */ + if (dfb_windowstack_lock( stack )) + return DFB_FUSION; + + /* Never call WM after destroying the window. */ + if (DFB_WINDOW_DESTROYED( window )) { + dfb_windowstack_unlock( stack ); + return DFB_DESTROYED; + } + + if (window->boundto) { + dfb_windowstack_unlock( stack ); + return DFB_UNSUPPORTED; + } + + if (relative) { + x += window->config.bounds.x; + y += window->config.bounds.y; + } + + if (x == window->config.bounds.x && y == window->config.bounds.y) { + dfb_windowstack_unlock( stack ); + return DFB_OK; + } + + ret = move_window( window, x, y ); + + /* Unlock the window stack. */ + dfb_windowstack_unlock( stack ); + + return ret; +} + +DFBResult +dfb_window_set_bounds( CoreWindow *window, + int x, + int y, + int width, + int height ) +{ + DFBResult ret; + CoreWindowConfig config; + CoreWindowStack *stack = window->stack; + int old_x; + int old_y; + + D_MAGIC_ASSERT( window, CoreWindow ); + + /* Lock the window stack. */ + if (dfb_windowstack_lock( stack )) + return DFB_FUSION; + + /* Never call WM after destroying the window. */ + if (DFB_WINDOW_DESTROYED( window )) { + dfb_windowstack_unlock( stack ); + return DFB_DESTROYED; + } + + old_x = window->config.bounds.x; + old_y = window->config.bounds.y; + + if (window->boundto) { + if (old_x != x || old_y != y) { + dfb_windowstack_unlock( stack ); + return DFB_UNSUPPORTED; + } + } + + config.bounds.x = x; + config.bounds.y = y; + config.bounds.w = width; + config.bounds.h = height; + + if (window->config.bounds.x == x && + window->config.bounds.y == y && + window->config.bounds.w == width && + window->config.bounds.h == height) + { + dfb_windowstack_unlock( stack ); + return DFB_OK; + } + + ret = dfb_wm_set_window_config( window, &config, CWCF_POSITION | CWCF_SIZE ); + if (ret) { + dfb_windowstack_unlock( stack ); + return ret; + } + + if (old_x != x || old_y != y) { + BoundWindow *bound; + + direct_list_foreach (bound, window->bound_windows) { + move_window( bound->window, + window->config.bounds.x + bound->x, + window->config.bounds.y + bound->y ); + } + } + + /* Unlock the window stack. */ + dfb_windowstack_unlock( stack ); + + return DFB_OK; +} + +DFBResult +dfb_window_resize( CoreWindow *window, + int width, + int height ) +{ + DFBResult ret; + CoreWindowConfig config; + CoreWindowStack *stack = window->stack; + + D_MAGIC_ASSERT( window, CoreWindow ); + + D_DEBUG_AT( Core_Windows, "dfb_window_resize (%p) [%4d,%4d - %4dx%4d -> %dx%d]\n", + window, DFB_RECTANGLE_VALS( &window->config.bounds ), width, height ); + + D_ASSERT( width > 0 ); + D_ASSERT( height > 0 ); + + if (width > 4096 || height > 4096) + return DFB_LIMITEXCEEDED; + + /* Lock the window stack. */ + if (dfb_windowstack_lock( stack )) + return DFB_FUSION; + + /* Never call WM after destroying the window. */ + if (DFB_WINDOW_DESTROYED( window )) { + dfb_windowstack_unlock( stack ); + return DFB_DESTROYED; + } + + if (window->config.bounds.w == width && window->config.bounds.h == height) { + dfb_windowstack_unlock( stack ); + return DFB_OK; + } + + config.bounds.w = width; + config.bounds.h = height; + + ret = dfb_wm_set_window_config( window, &config, CWCF_SIZE ); + + /* Unlock the window stack. */ + dfb_windowstack_unlock( stack ); + + return ret; +} + +DFBResult +dfb_window_bind( CoreWindow *window, + CoreWindow *source, + int x, + int y ) +{ + DFBResult ret; + CoreWindowStack *stack = window->stack; + BoundWindow *bound; + + D_MAGIC_ASSERT( window, CoreWindow ); + + if (window == source) + return DFB_UNSUPPORTED; + + /* Lock the window stack. */ + if (dfb_windowstack_lock( stack )) + return DFB_FUSION; + + /* Never call WM after destroying the window. */ + if (DFB_WINDOW_DESTROYED( window )) { + dfb_windowstack_unlock( stack ); + return DFB_DESTROYED; + } + + if (DFB_WINDOW_DESTROYED( source )) { + dfb_windowstack_unlock( stack ); + return DFB_DESTROYED; + } + + bound = SHCALLOC( stack->shmpool, 1, sizeof(BoundWindow) ); + if (!bound) { + dfb_windowstack_unlock( stack ); + return DFB_NOSHAREDMEMORY; + } + + if (source->boundto) + dfb_window_unbind( source->boundto, source ); + + ret = move_window( source, + window->config.bounds.x + x, + window->config.bounds.y + y ); + if (ret) { + SHFREE( stack->shmpool, bound ); + dfb_windowstack_unlock( stack ); + return ret; + } + + bound->window = source; + bound->x = x; + bound->y = y; + + direct_list_append( &window->bound_windows, &bound->link ); + + source->boundto = window; + + dfb_windowstack_unlock( stack ); + + return DFB_OK; +} + +DFBResult +dfb_window_unbind( CoreWindow *window, + CoreWindow *source ) +{ + CoreWindowStack *stack = window->stack; + BoundWindow *bound; + + D_MAGIC_ASSERT( window, CoreWindow ); + + /* Lock the window stack. */ + if (dfb_windowstack_lock( stack )) + return DFB_FUSION; + + /* Never call WM after destroying the window. */ + if (DFB_WINDOW_DESTROYED( window )) { + dfb_windowstack_unlock( stack ); + return DFB_DESTROYED; + } + + if (DFB_WINDOW_DESTROYED( source )) { + dfb_windowstack_unlock( stack ); + return DFB_DESTROYED; + } + + if (source->boundto != window) { + dfb_windowstack_unlock( stack ); + return DFB_UNSUPPORTED; + } + + direct_list_foreach (bound, window->bound_windows) { + if (bound->window == source) { + direct_list_remove( &window->bound_windows, &bound->link ); + + bound->window->boundto = NULL; + + SHFREE( stack->shmpool, bound ); + + break; + } + } + + if (!bound) + D_BUG( "window not found" ); + + dfb_windowstack_unlock( stack ); + + return bound ? DFB_OK : DFB_ITEMNOTFOUND; +} + +/* + * sets the source color key + */ +DFBResult +dfb_window_set_color( CoreWindow *window, + DFBColor color ) +{ + DFBResult ret; + DFBColor cc; + CoreWindowConfig config; + CoreWindowStack *stack = window->stack; + + D_MAGIC_ASSERT( window, CoreWindow ); + + /* Lock the window stack. */ + if (dfb_windowstack_lock( stack )) + return DFB_FUSION; + + /* Never call WM after destroying the window. */ + if (DFB_WINDOW_DESTROYED( window )) { + dfb_windowstack_unlock( stack ); + return DFB_DESTROYED; + } + + cc = window->config.color; + if ( (cc.a==color.a) && (cc.r==color.r) && (cc.g==color.g) && (cc.b==color.b) ) { + dfb_windowstack_unlock( stack ); + return DFB_OK; + } + + config.color = color; + + ret = dfb_wm_set_window_config( window, &config, CWCF_COLOR ); + + /* Unlock the window stack. */ + dfb_windowstack_unlock( stack ); + + return ret; +} + +DFBResult +dfb_window_set_colorkey( CoreWindow *window, + u32 color_key ) +{ + DFBResult ret; + CoreWindowConfig config; + CoreWindowStack *stack = window->stack; + + D_MAGIC_ASSERT( window, CoreWindow ); + + /* Lock the window stack. */ + if (dfb_windowstack_lock( stack )) + return DFB_FUSION; + + /* Never call WM after destroying the window. */ + if (DFB_WINDOW_DESTROYED( window )) { + dfb_windowstack_unlock( stack ); + return DFB_DESTROYED; + } + + if (window->config.color_key == color_key) { + dfb_windowstack_unlock( stack ); + return DFB_OK; + } + + config.color_key = color_key; + + ret = dfb_wm_set_window_config( window, &config, CWCF_COLOR_KEY ); + + /* Unlock the window stack. */ + dfb_windowstack_unlock( stack ); + + return ret; +} + +DFBResult +dfb_window_set_opacity( CoreWindow *window, + u8 opacity ) +{ + DFBResult ret; + CoreWindowConfig config; + CoreWindowStack *stack = window->stack; + + D_MAGIC_ASSERT( window, CoreWindow ); + + /* Lock the window stack. */ + if (dfb_windowstack_lock( stack )) + return DFB_FUSION; + + /* Never call WM after destroying the window. */ + if (DFB_WINDOW_DESTROYED( window )) { + dfb_windowstack_unlock( stack ); + return DFB_DESTROYED; + } + + if (window->config.opacity == opacity) { + dfb_windowstack_unlock( stack ); + return DFB_OK; + } + + config.opacity = opacity; + + ret = dfb_wm_set_window_config( window, &config, CWCF_OPACITY ); + + /* Unlock the window stack. */ + dfb_windowstack_unlock( stack ); + + return ret; +} + +DFBResult +dfb_window_change_options( CoreWindow *window, + DFBWindowOptions disable, + DFBWindowOptions enable ) +{ + DFBResult ret; + CoreWindowConfig config; + CoreWindowStack *stack = window->stack; + + D_MAGIC_ASSERT( window, CoreWindow ); + + D_ASSUME( disable | enable ); + + if (!disable && !enable) + return DFB_OK; + + /* Lock the window stack. */ + if (dfb_windowstack_lock( stack )) + return DFB_FUSION; + + /* Never call WM after destroying the window. */ + if (DFB_WINDOW_DESTROYED( window )) { + dfb_windowstack_unlock( stack ); + return DFB_DESTROYED; + } + + config.options = (window->config.options & ~disable) | enable; + + ret = dfb_wm_set_window_config( window, &config, CWCF_OPTIONS ); + + /* Unlock the window stack. */ + dfb_windowstack_unlock( stack ); + + return ret; +} + +DFBResult +dfb_window_set_opaque( CoreWindow *window, + const DFBRegion *region ) +{ + DFBResult ret; + CoreWindowConfig config; + CoreWindowStack *stack = window->stack; + + D_MAGIC_ASSERT( window, CoreWindow ); + + DFB_REGION_ASSERT_IF( region ); + + /* Lock the window stack. */ + if (dfb_windowstack_lock( stack )) + return DFB_FUSION; + + /* Never call WM after destroying the window. */ + if (DFB_WINDOW_DESTROYED( window )) { + dfb_windowstack_unlock( stack ); + return DFB_DESTROYED; + } + + config.opaque.x1 = 0; + config.opaque.y1 = 0; + config.opaque.x2 = window->config.bounds.w - 1; + config.opaque.y2 = window->config.bounds.h - 1; + + if (region && !dfb_region_region_intersect( &config.opaque, region )) + ret = DFB_INVAREA; + else + ret = dfb_wm_set_window_config( window, &config, CWCF_OPAQUE ); + + /* Unlock the window stack. */ + dfb_windowstack_unlock( stack ); + + return ret; +} + +DFBResult +dfb_window_change_events( CoreWindow *window, + DFBWindowEventType disable, + DFBWindowEventType enable ) +{ + DFBResult ret; + CoreWindowConfig config; + CoreWindowStack *stack = window->stack; + + D_MAGIC_ASSERT( window, CoreWindow ); + + D_ASSUME( disable | enable ); + + if (!disable && !enable) + return DFB_OK; + + /* Lock the window stack. */ + if (dfb_windowstack_lock( stack )) + return DFB_FUSION; + + /* Never call WM after destroying the window. */ + if (DFB_WINDOW_DESTROYED( window )) { + dfb_windowstack_unlock( stack ); + return DFB_DESTROYED; + } + + config.events = (window->config.events & ~disable) | enable; + + ret = dfb_wm_set_window_config( window, &config, CWCF_EVENTS ); + + /* Unlock the window stack. */ + dfb_windowstack_unlock( stack ); + + return ret; +} + +DFBResult +dfb_window_set_key_selection( CoreWindow *window, + DFBWindowKeySelection selection, + const DFBInputDeviceKeySymbol *keys, + unsigned int num_keys ) +{ + DFBResult ret; + CoreWindowConfig config; + CoreWindowStack *stack = window->stack; + + D_MAGIC_ASSERT( window, CoreWindow ); + + D_ASSERT( selection == DWKS_ALL || selection == DWKS_NONE || selection == DWKS_LIST ); + D_ASSERT( keys != NULL || selection != DWKS_LIST ); + D_ASSERT( num_keys > 0 || selection != DWKS_LIST ); + + /* Lock the window stack. */ + if (dfb_windowstack_lock( stack )) + return DFB_FUSION; + + /* Never call WM after destroying the window. */ + if (DFB_WINDOW_DESTROYED( window )) { + dfb_windowstack_unlock( stack ); + return DFB_DESTROYED; + } + + config.key_selection = selection; + config.keys = (DFBInputDeviceKeySymbol*) keys; /* FIXME */ + config.num_keys = num_keys; + + ret = dfb_wm_set_window_config( window, &config, CWCF_KEY_SELECTION ); + + /* Unlock the window stack. */ + dfb_windowstack_unlock( stack ); + + return ret; +} + +DFBResult +dfb_window_change_grab( CoreWindow *window, + CoreWMGrabTarget target, + bool grab ) +{ + DFBResult ret; + CoreWMGrab wmgrab; + CoreWindowStack *stack; + + D_MAGIC_ASSERT( window, CoreWindow ); + + stack = window->stack; + + /* Lock the window stack. */ + if (dfb_windowstack_lock( stack )) + return DFB_FUSION; + + /* Never call WM after destroying the window. */ + if (DFB_WINDOW_DESTROYED( window )) { + dfb_windowstack_unlock( stack ); + return DFB_DESTROYED; + } + + wmgrab.target = target; + + if (grab) + ret = dfb_wm_grab( window, &wmgrab ); + else + ret = dfb_wm_ungrab( window, &wmgrab ); + + /* Unlock the window stack. */ + dfb_windowstack_unlock( stack ); + + return ret; +} + +DFBResult +dfb_window_grab_key( CoreWindow *window, + DFBInputDeviceKeySymbol symbol, + DFBInputDeviceModifierMask modifiers ) +{ + DFBResult ret; + CoreWMGrab grab; + CoreWindowStack *stack = window->stack; + + D_MAGIC_ASSERT( window, CoreWindow ); + + /* Lock the window stack. */ + if (dfb_windowstack_lock( stack )) + return DFB_FUSION; + + /* Never call WM after destroying the window. */ + if (DFB_WINDOW_DESTROYED( window )) { + dfb_windowstack_unlock( stack ); + return DFB_DESTROYED; + } + + grab.target = CWMGT_KEY; + grab.symbol = symbol; + grab.modifiers = modifiers; + + ret = dfb_wm_grab( window, &grab ); + + /* Unlock the window stack. */ + dfb_windowstack_unlock( stack ); + + return ret; +} + +DFBResult +dfb_window_ungrab_key( CoreWindow *window, + DFBInputDeviceKeySymbol symbol, + DFBInputDeviceModifierMask modifiers ) +{ + DFBResult ret; + CoreWMGrab grab; + CoreWindowStack *stack = window->stack; + + D_MAGIC_ASSERT( window, CoreWindow ); + + /* Lock the window stack. */ + if (dfb_windowstack_lock( stack )) + return DFB_FUSION; + + /* Never call WM after destroying the window. */ + if (DFB_WINDOW_DESTROYED( window )) { + dfb_windowstack_unlock( stack ); + return DFB_DESTROYED; + } + + grab.target = CWMGT_KEY; + grab.symbol = symbol; + grab.modifiers = modifiers; + + ret = dfb_wm_ungrab( window, &grab ); + + /* Unlock the window stack. */ + dfb_windowstack_unlock( stack ); + + return ret; +} + +DFBResult +dfb_window_repaint( CoreWindow *window, + const DFBRegion *region, + DFBSurfaceFlipFlags flags ) +{ + DFBResult ret; + CoreWindowStack *stack = window->stack; + + D_MAGIC_ASSERT( window, CoreWindow ); + D_ASSERT( window->stack != NULL ); + + DFB_REGION_ASSERT_IF( region ); + + /* Lock the window stack. */ + if (dfb_windowstack_lock( stack )) + return DFB_FUSION; + + /* Never call WM after destroying the window. */ + if (DFB_WINDOW_DESTROYED( window )) { + dfb_windowstack_unlock( stack ); + return DFB_DESTROYED; + } + + ret = dfb_wm_update_window( window, region, flags ); + + /* Unlock the window stack. */ + dfb_windowstack_unlock( stack ); + + return ret; +} + +const char * +dfb_window_event_type_name( DFBWindowEventType type ) +{ + switch (type) { + case DWET_POSITION: + return "POSITION"; + + case DWET_SIZE: + return "SIZE"; + + case DWET_CLOSE: + return "CLOSE"; + + case DWET_DESTROYED: + return "DESTROYED"; + + case DWET_GOTFOCUS: + return "GOTFOCUS"; + + case DWET_LOSTFOCUS: + return "LOSTFOCUS"; + + case DWET_KEYDOWN: + return "KEYDOWN"; + + case DWET_KEYUP: + return "KEYUP"; + + case DWET_BUTTONDOWN: + return "BUTTONDOWN"; + + case DWET_BUTTONUP: + return "BUTTONUP"; + + case DWET_MOTION: + return "MOTION"; + + case DWET_ENTER: + return "ENTER"; + + case DWET_LEAVE: + return "LEAVE"; + + case DWET_WHEEL: + return "WHEEL"; + + case DWET_POSITION_SIZE: + return "POSITION_SIZE"; + + default: + break; + } + + return ""; +} + +void +dfb_window_post_event( CoreWindow *window, + DFBWindowEvent *event ) +{ + D_MAGIC_ASSERT( window, CoreWindow ); + D_ASSERT( event != NULL ); + + D_ASSUME( !DFB_WINDOW_DESTROYED( window ) || event->type == DWET_DESTROYED ); + + if (! (event->type & window->config.events)) + return; + + gettimeofday( &event->timestamp, NULL ); + + event->clazz = DFEC_WINDOW; + event->window_id = window->id; + + D_ASSUME( window->stack != NULL ); +/* + if (window->stack) { + CoreWindowStack *stack = window->stack; + + event->cx = stack->cursor.x; + event->cy = stack->cursor.y; + } +*/ + if (!core_window_filter( window, event )) + dfb_window_dispatch( window, event, dfb_window_globals ); +} + +DFBResult +dfb_window_send_configuration( CoreWindow *window ) +{ + DFBWindowEvent event; + + D_MAGIC_ASSERT( window, CoreWindow ); + + D_ASSUME( !DFB_WINDOW_DESTROYED( window ) ); + + event.type = DWET_POSITION_SIZE; + event.x = window->config.bounds.x; + event.y = window->config.bounds.y; + event.w = window->config.bounds.w; + event.h = window->config.bounds.h; + + dfb_window_post_event( window, &event ); + + return DFB_OK; +} + +DFBResult +dfb_window_request_focus( CoreWindow *window ) +{ + DFBResult ret; + CoreWindowStack *stack = window->stack; + + D_MAGIC_ASSERT( window, CoreWindow ); + + /* Lock the window stack. */ + if (dfb_windowstack_lock( stack )) + return DFB_FUSION; + + /* Never call WM after destroying the window. */ + if (DFB_WINDOW_DESTROYED( window )) { + dfb_windowstack_unlock( stack ); + return DFB_DESTROYED; + } + + ret = dfb_wm_request_focus( window ); + + /* Unlock the window stack. */ + dfb_windowstack_unlock( stack ); + + return ret; +} + +DFBWindowID +dfb_window_id( const CoreWindow *window ) +{ + D_MAGIC_ASSERT( window, CoreWindow ); + + return window->id; +} + +/* + * Returns window surface. + * For windows with DWCAPS_COLOR this returns 0. + */ +CoreSurface * +dfb_window_surface( const CoreWindow *window ) +{ + D_MAGIC_ASSERT( window, CoreWindow ); + + return window->surface; +} + +/******************************************************************************/ + +static bool +core_window_filter( CoreWindow *window, const DFBWindowEvent *event ) +{ + D_MAGIC_ASSERT( window, CoreWindow ); + + switch (event->type) { + case DWET_GOTFOCUS: + D_FLAGS_SET( window->flags, CWF_FOCUSED ); + break; + + case DWET_LOSTFOCUS: + D_FLAGS_CLEAR( window->flags, CWF_FOCUSED ); + break; + + case DWET_ENTER: + D_FLAGS_SET( window->flags, CWF_ENTERED ); + break; + + case DWET_LEAVE: + D_FLAGS_CLEAR( window->flags, CWF_ENTERED ); + break; + + default: + break; + } + + return false; +} + +DFBResult +dfb_window_set_rotation( CoreWindow *window, + int rotation ) +{ + DFBResult ret = DFB_OK; + CoreWindowStack *stack = window->stack; + + D_MAGIC_ASSERT( window, CoreWindow ); + + stack = window->stack; + D_MAGIC_ASSERT( stack, CoreWindowStack ); + + /* Lock the window stack. */ + if (dfb_windowstack_lock( stack )) + return DFB_FUSION; + + /* Never call WM after destroying the window. */ + if (DFB_WINDOW_DESTROYED( window )) { + dfb_windowstack_unlock( stack ); + return DFB_DESTROYED; + } + + /* Do nothing if the rotation didn't change. */ + if (window->config.rotation != rotation) { + CoreWindowConfig config; + + switch (rotation) { + case 0: + case 90: + case 180: + case 270: + config.rotation = rotation; + + dfb_wm_set_window_config( window, &config, CWCF_ROTATION ); + break; + + default: + ret = DFB_UNSUPPORTED; + } + } + + /* Unlock the window stack. */ + dfb_windowstack_unlock( stack ); + + return ret; +} + diff --git a/Source/DirectFB/src/core/windows.h b/Source/DirectFB/src/core/windows.h new file mode 100755 index 0000000..4b9e2a4 --- /dev/null +++ b/Source/DirectFB/src/core/windows.h @@ -0,0 +1,316 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef __WINDOWS_H__ +#define __WINDOWS_H__ + +#include +#include + +#include +#include + +#include + +typedef enum { + CWMGT_KEYBOARD, + CWMGT_POINTER, + CWMGT_KEY, + CWMGT_UNSELECTED_KEYS, +} CoreWMGrabTarget; + + +#define CoreWindowConfigFlags DFBWindowConfigFlags + +#define CWCF_NONE DWCONF_NONE +#define CWCF_POSITION DWCONF_POSITION +#define CWCF_SIZE DWCONF_SIZE +#define CWCF_OPACITY DWCONF_OPACITY +#define CWCF_STACKING DWCONF_STACKING +#define CWCF_OPTIONS DWCONF_OPTIONS +#define CWCF_EVENTS DWCONF_EVENTS +#define CWCF_ASSOCIATION DWCONF_ASSOCIATION +#define CWCF_COLOR_KEY DWCONF_COLOR_KEY +#define CWCF_OPAQUE DWCONF_OPAQUE +#define CWCF_COLOR DWCONF_COLOR +#define CWCF_KEY_SELECTION DWCONF_KEY_SELECTION +#define CWCF_CURSOR_FLAGS DWCONF_CURSOR_FLAGS +#define CWCF_CURSOR_RESOLUTION DWCONF_CURSOR_RESOLUTION +#define CWCF_SRC_GEOMETRY DWCONF_SRC_GEOMETRY +#define CWCF_DST_GEOMETRY DWCONF_DST_GEOMETRY +#define CWCF_ROTATION DWCONF_ROTATION +#define CWCF_ALL DWCONF_ALL + + + +struct __DFB_CoreWindowConfig { + DFBRectangle bounds; /* position and size */ + int opacity; /* global alpha factor */ + DFBWindowStackingClass stacking; /* level boundaries */ + DFBWindowOptions options; /* flags for appearance/behaviour */ + DFBWindowEventType events; /* mask of enabled events */ + DFBColor color; /* color for DWCAPS_COLOR */ + u32 color_key; /* transparent pixel */ + DFBRegion opaque; /* region of the window forced to be opaque */ + + DFBWindowKeySelection key_selection; /* how to filter keys in focus */ + DFBInputDeviceKeySymbol *keys; /* list of keys for DWKS_LIST */ + unsigned int num_keys; /* number of entries in key array */ + + DFBWindowGeometry src_geometry; /* advanced source geometry */ + DFBWindowGeometry dst_geometry; /* advanced destination geometry */ + + int rotation; + + DFBWindowID association; + + DFBWindowCursorFlags cursor_flags; + DFBDimension cursor_resolution; +}; + + +#define TRANSLUCENT_WINDOW(w) ((w)->config.opacity < 0xff || \ + (w)->config.options & (DWOP_ALPHACHANNEL | DWOP_COLORKEYING)) + +#define VISIBLE_WINDOW(w) (!((w)->caps & DWCAPS_INPUTONLY) && \ + (w)->config.opacity > 0 && !DFB_WINDOW_DESTROYED((w))) + + +/* + * Creates a pool of window objects. + */ +FusionObjectPool *dfb_window_pool_create( const FusionWorld *world ); + +/* + * Generates dfb_window_ref(), dfb_window_attach() etc. + */ +FUSION_OBJECT_METHODS( CoreWindow, dfb_window ) + +/* + * creates a window on a given stack + */ +DFBResult +dfb_window_create( CoreWindowStack *stack, + const DFBWindowDescription *desc, + CoreWindow **ret_window ); + +/* + * deinitializes a window and removes it from the window stack + */ +void +dfb_window_destroy( CoreWindow *window ); + +/* + * moves a window relative to its current position + */ +DFBResult +dfb_window_move( CoreWindow *window, + int x, + int y, + bool relative ); + +/* + * set position and size + */ +DFBResult +dfb_window_set_bounds( CoreWindow *window, + int x, + int y, + int width, + int height ); + +/* + * resizes a window + */ +DFBResult +dfb_window_resize( CoreWindow *window, + int width, + int height ); + +/* + * binds a window to this window + */ +DFBResult +dfb_window_bind( CoreWindow *window, + CoreWindow *source, + int x, + int y ); + +/* + * unbinds a window from this window + */ +DFBResult +dfb_window_unbind( CoreWindow *window, + CoreWindow *source ); + +/* + * changes stacking class + */ +DFBResult +dfb_window_change_stacking( CoreWindow *window, + DFBWindowStackingClass stacking ); + +/* + * move a window up one step in window stack + */ +DFBResult +dfb_window_raise( CoreWindow *window ); + +/* + * move a window down one step in window stack + */ +DFBResult +dfb_window_lower( CoreWindow *window ); + +/* + * makes a window the first (topmost) window in the window stack + */ +DFBResult +dfb_window_raisetotop( CoreWindow *window ); + +/* + * makes a window the last (downmost) window in the window stack + */ +DFBResult +dfb_window_lowertobottom( CoreWindow *window ); + +/* + * stacks the window on top of another one + */ +DFBResult +dfb_window_putatop( CoreWindow *window, + CoreWindow *lower ); + +/* + * stacks the window below another one + */ +DFBResult +dfb_window_putbelow( CoreWindow *window, + CoreWindow *upper ); + +/* + * sets the source color key + */ +DFBResult +dfb_window_set_color( CoreWindow *window, + DFBColor color ); + +/* + * sets the source color key + */ +DFBResult +dfb_window_set_colorkey( CoreWindow *window, + u32 color_key ); + +/* + * change window configuration + */ +DFBResult +dfb_window_set_config( CoreWindow *window, + const CoreWindowConfig *config, + CoreWindowConfigFlags flags ); + +/* + * change window cursor + */ +DFBResult +dfb_window_set_cursor_shape( CoreWindow *window, + CoreSurface *surface, + unsigned int hot_x, + unsigned int hot_y ); + +/* + * sets the global alpha factor + */ +DFBResult +dfb_window_set_opacity( CoreWindow *window, + u8 opacity ); + +/* + * sets the window options + */ +DFBResult +dfb_window_change_options( CoreWindow *window, + DFBWindowOptions disable, + DFBWindowOptions enable ); + +/* + * sets the window options + */ +DFBResult +dfb_window_set_opaque( CoreWindow *window, + const DFBRegion *region ); + +/* + * manipulates the event mask + */ +DFBResult +dfb_window_change_events( CoreWindow *window, + DFBWindowEventType disable, + DFBWindowEventType enable ); + +/* + * repaints part of a window, if region is NULL the whole window is repainted + */ +DFBResult +dfb_window_repaint( CoreWindow *window, + const DFBRegion *region, + DFBSurfaceFlipFlags flags ); + +/* + * request a window to gain focus + */ +DFBResult +dfb_window_request_focus( CoreWindow *window ); + +DFBResult dfb_window_set_key_selection( CoreWindow *window, + DFBWindowKeySelection selection, + const DFBInputDeviceKeySymbol *keys, + unsigned int num_keys ); + +DFBResult dfb_window_change_grab ( CoreWindow *window, + CoreWMGrabTarget target, + bool grab ); +DFBResult dfb_window_grab_key ( CoreWindow *window, + DFBInputDeviceKeySymbol symbol, + DFBInputDeviceModifierMask modifiers ); +DFBResult dfb_window_ungrab_key ( CoreWindow *window, + DFBInputDeviceKeySymbol symbol, + DFBInputDeviceModifierMask modifiers ); + +void dfb_window_post_event( CoreWindow *window, DFBWindowEvent *event ); + +DFBResult dfb_window_send_configuration( CoreWindow *window ); + +DFBWindowID dfb_window_id( const CoreWindow *window ); + +CoreSurface *dfb_window_surface( const CoreWindow *window ); + +DFBResult +dfb_window_set_rotation( CoreWindow *window, int rotation ); +#endif diff --git a/Source/DirectFB/src/core/windows_internal.h b/Source/DirectFB/src/core/windows_internal.h new file mode 100755 index 0000000..cededef --- /dev/null +++ b/Source/DirectFB/src/core/windows_internal.h @@ -0,0 +1,211 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef __CORE__WINDOWS_INTERNAL_H__ +#define __CORE__WINDOWS_INTERNAL_H__ + +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + + +typedef enum { + CWF_NONE = 0x00000000, + + CWF_INITIALIZED = 0x00000001, + CWF_FOCUSED = 0x00000002, + CWF_ENTERED = 0x00000004, + CWF_DESTROYED = 0x00000008, + + CWF_INSERTED = 0x00000010, + + CWF_ALL = 0x0000001F +} CoreWindowFlags; + +#define DFB_WINDOW_INITIALIZED(w) ((w)->flags & CWF_INITIALIZED) +#define DFB_WINDOW_FOCUSED(w) ((w)->flags & CWF_FOCUSED) +#define DFB_WINDOW_ENTERED(w) ((w)->flags & CWF_ENTERED) +#define DFB_WINDOW_DESTROYED(w) ((w)->flags & CWF_DESTROYED) + +typedef struct { + DirectLink link; + + CoreWindow *window; + int x; + int y; +} BoundWindow; + +/* + * Core data of a window. + */ +struct __DFB_CoreWindow { + FusionObject object; + + int magic; + + DFBWindowID id; + + CoreWindowFlags flags; + + DFBWindowCapabilities caps; /* window capabilities, to enable blending etc. */ + + CoreWindowConfig config; + + CoreSurface *surface; /* backing store surface */ + GlobalReaction surface_reaction; + + CoreWindowStack *stack; /* window stack the window belongs */ + + CoreLayerRegion *primary_region; /* default region of context */ + + CoreLayerRegion *region; /* hardware allocated window */ + + void *window_data; /* private data of window manager */ + + CoreGraphicsSerial serial1; + CoreGraphicsSerial serial2; + + DirectLink *bound_windows; /* list of bound windows */ + CoreWindow *boundto; /* window to which this window is bound (window binding) */ + + DFBWindowID toplevel_id; /* in case of a sub window toplevel_id != 0 */ + CoreWindow *toplevel; /* for top level windows this will be NULL */ + FusionVector subwindows; /* list of sub windows (only valid for top level windows) */ + + CoreWindow *subfocus; /* which of the sub windows has the focus? */ + + unsigned long resource_id; + + struct { + unsigned int hot_x; + unsigned int hot_y; + CoreSurface *surface; + } cursor; +}; + +typedef enum { + CWSF_NONE = 0x00000000, + + CWSF_INITIALIZED = 0x00000001, + CWSF_ACTIVATED = 0x00000002, + + CWSF_ALL = 0x00000003 +} CoreWindowStackFlags; + +/* + * Core data of a window stack. + */ +struct __DFB_CoreWindowStack { + DirectLink link; + + int magic; + + CoreLayerContext *context; + + int width; + int height; + + int rotation; + + int rotated_width; + int rotated_height; + DFBSurfaceBlittingFlags rotated_blit; + + DFBWindowID id_pool; + + int num; + + struct { + int enabled; /* is cursor enabled ? */ + int x, y; /* cursor position */ + DFBDimension size; /* cursor shape size */ + DFBPoint hot; /* hot spot */ + CoreSurface *surface; /* shape */ + u8 opacity; /* cursor opacity */ + DFBRegion region; /* cursor is clipped by this region */ + + int numerator; /* cursor acceleration */ + int denominator; + int threshold; + + bool set; /* cursor enable/disable has + been called at least one time */ + + CoreSurfacePolicy policy; + } cursor; + + /* stores information on handling the background on exposure */ + struct { + DFBDisplayLayerBackgroundMode mode; + /* background handling mode: + don't care, solid color or image */ + + DFBColor color; /* color for solid background mode */ + int color_index; + + + CoreSurface *image; /* surface for background image mode */ + + GlobalReaction image_reaction; + } bg; + + DirectLink *devices; /* input devices attached to the stack */ + + bool hw_mode; /* recompositing is done by hardware */ + + void *stack_data; /* private data of window manager */ + + FusionSHMPoolShared *shmpool; + + CoreWindowStackFlags flags; + + Reaction input_core_reaction; +}; + + +DFBResult dfb_wm_close_all_stacks( void *data ); + + +/* global reactions */ +ReactionResult _dfb_windowstack_inputdevice_listener ( const void *msg_data, + void *ctx ); + +ReactionResult _dfb_windowstack_background_image_listener( const void *msg_data, + void *ctx ); + +#endif diff --git a/Source/DirectFB/src/core/windowstack.c b/Source/DirectFB/src/core/windowstack.c new file mode 100755 index 0000000..7a19f1c --- /dev/null +++ b/Source/DirectFB/src/core/windowstack.c @@ -0,0 +1,998 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include + +#include + +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + + +#define CURSORFILE DATADIR"/cursor.dat" + + +D_DEBUG_DOMAIN( Core_WindowStack, "Core/WindowStack", "DirectFB Core WindowStack" ); + +/**********************************************************************************************************************/ + +typedef struct { + DirectLink link; + + DFBInputDeviceID id; + Reaction reaction; +} StackDevice; + +typedef struct { + DirectLink link; + + DFBInputDeviceKeySymbol symbol; + DFBInputDeviceModifierMask modifiers; + + CoreWindow *owner; +} GrabbedKey; + +/**********************************************************************************************************************/ + +static DFBResult load_default_cursor ( CoreDFB *core, + CoreWindowStack *stack ); +static DFBResult create_cursor_surface( CoreWindowStack *stack, + int width, + int height ); + +/**********************************************************************************************************************/ + +static DFBEnumerationResult stack_attach_devices( CoreInputDevice *device, + void *ctx ); + +static ReactionResult stack_input_core_listener( const void *msg_data, + void *ctx ); + +/**********************************************************************************************************************/ + +/* + * Allocates and initializes a window stack. + */ +CoreWindowStack* +dfb_windowstack_create( CoreLayerContext *context ) +{ + DFBResult ret; + CoreWindowStack *stack; + CoreSurfacePolicy policy = CSP_SYSTEMONLY; + CoreLayer *layer; + + D_DEBUG_AT( Core_WindowStack, "%s( %p )\n", __FUNCTION__, context ); + + D_ASSERT( context != NULL ); + + layer = dfb_layer_at( context->layer_id ); + + /* Allocate window stack data (completely shared) */ + stack = (CoreWindowStack*) SHCALLOC( context->shmpool, 1, sizeof(CoreWindowStack) ); + if (!stack) { + D_OOSHM(); + return NULL; + } + + stack->shmpool = context->shmpool; + + /* Store context which we belong to. */ + stack->context = context; + + /* Set default acceleration */ + stack->cursor.numerator = 2; + stack->cursor.denominator = 1; + stack->cursor.threshold = 4; + + /* Choose cursor surface policy. */ + if (context->config.buffermode != DLBM_BACKSYSTEM) { + CardCapabilities card_caps; + + /* Use the explicitly specified policy? */ + if (dfb_config->window_policy != -1) + policy = dfb_config->window_policy; + else { + /* Examine the hardware capabilities. */ + dfb_gfxcard_get_capabilities( &card_caps ); + + if (card_caps.accel & DFXL_BLIT && card_caps.blitting & DSBLIT_BLEND_ALPHACHANNEL) + policy = CSP_VIDEOHIGH; + } + } + + stack->cursor.policy = policy; + stack->cursor.opacity = 0xFF; + + /* Set default background mode. */ + stack->bg.mode = DLBM_DONTCARE; + stack->bg.color_index = -1; + + D_MAGIC_SET( stack, CoreWindowStack ); + + /* Initialize window manager */ + ret = dfb_wm_init_stack( stack ); + if (ret) { + D_MAGIC_CLEAR( stack ); + SHFREE( context->shmpool, stack ); + return NULL; + } + + if (dfb_core_is_master( layer->core )) + dfb_input_core_attach( layer->core, stack_input_core_listener, stack, &stack->input_core_reaction ); + + /* Attach to all input devices */ + dfb_input_enumerate_devices( stack_attach_devices, stack, DICAPS_ALL ); + + D_DEBUG_AT( Core_WindowStack, " -> %p\n", stack ); + + return stack; +} + +void +dfb_windowstack_detach_devices( CoreWindowStack *stack ) +{ + DirectLink *l; + + D_DEBUG_AT( Core_WindowStack, "%s( %p )\n", __FUNCTION__, stack ); + + D_MAGIC_ASSERT( stack, CoreWindowStack ); + + /* Detach all input devices. */ + l = stack->devices; + while (l) { + DirectLink *next = l->next; + StackDevice *device = (StackDevice*) l; + + dfb_input_detach( dfb_input_device_at( device->id ), + &device->reaction ); + + SHFREE( stack->shmpool, device ); + + l = next; + } +} + +void +dfb_windowstack_destroy( CoreWindowStack *stack ) +{ + D_DEBUG_AT( Core_WindowStack, "%s( %p )\n", __FUNCTION__, stack ); + + D_MAGIC_ASSERT( stack, CoreWindowStack ); + + if (stack->input_core_reaction.func) + dfb_input_core_detach( NULL, &stack->input_core_reaction ); + + /* Unlink cursor surface. */ + if (stack->cursor.surface) + dfb_surface_unlink( &stack->cursor.surface ); + + /* Shutdown window manager? */ + if (stack->flags & CWSF_INITIALIZED) + dfb_wm_close_stack( stack ); + + /* detach listener from background surface and unlink it */ + if (stack->bg.image) { + dfb_surface_detach_global( stack->bg.image, + &stack->bg.image_reaction ); + + dfb_surface_unlink( &stack->bg.image ); + } + + /* Deallocate shared stack data. */ + if (stack->stack_data) { + SHFREE( stack->shmpool, stack->stack_data ); + stack->stack_data = NULL; + } + + D_MAGIC_CLEAR( stack ); + + /* Free stack data. */ + SHFREE( stack->shmpool, stack ); +} + +void +dfb_windowstack_resize( CoreWindowStack *stack, + int width, + int height, + int rotation ) +{ + D_DEBUG_AT( Core_WindowStack, "%s( %p, %dx%d, %d )\n", __FUNCTION__, stack, width, height, rotation ); + + D_MAGIC_ASSERT( stack, CoreWindowStack ); + + /* Lock the window stack. */ + if (dfb_windowstack_lock( stack )) + return; + + /* Store the width and height of the stack */ + stack->width = width; + stack->height = height; + stack->rotation = rotation; + + switch (stack->rotation) { + default: + D_BUG( "invalid rotation %d", stack->rotation ); + case 0: + stack->rotated_blit = DSBLIT_NOFX; + stack->rotated_width = stack->width; + stack->rotated_height = stack->height; + break; + + case 90: + stack->rotated_blit = DSBLIT_ROTATE90; + stack->rotated_width = stack->height; + stack->rotated_height = stack->width; + break; + + case 180: + stack->rotated_blit = DSBLIT_ROTATE180; + stack->rotated_width = stack->width; + stack->rotated_height = stack->height; + break; + + case 270: + stack->rotated_blit = DSBLIT_ROTATE270; + stack->rotated_width = stack->height; + stack->rotated_height = stack->width; + break; + } + + /* Setup new cursor clipping region */ + stack->cursor.region.x1 = 0; + stack->cursor.region.y1 = 0; + stack->cursor.region.x2 = width - 1; + stack->cursor.region.y2 = height - 1; + + /* Notify the window manager. */ + dfb_wm_resize_stack( stack, width, height ); + + /* Unlock the window stack. */ + dfb_windowstack_unlock( stack ); +} + +/* + * Prohibit access to the window stack data. + * Waits until stack is accessible. + */ +DirectResult +dfb_windowstack_lock( CoreWindowStack *stack ) +{ + D_MAGIC_ASSERT( stack, CoreWindowStack ); + D_ASSERT( stack->context != NULL ); + + return dfb_layer_context_lock( stack->context ); +} + +/* + * Allow access to the window stack data. + */ +DirectResult +dfb_windowstack_unlock( CoreWindowStack *stack ) +{ + D_MAGIC_ASSERT( stack, CoreWindowStack ); + D_ASSERT( stack->context != NULL ); + + return dfb_layer_context_unlock( stack->context ); +} + +DFBResult +dfb_windowstack_repaint_all( CoreWindowStack *stack ) +{ + DFBResult ret; + DFBRegion region; + + D_DEBUG_AT( Core_WindowStack, "%s( %p )\n", __FUNCTION__, stack ); + + D_MAGIC_ASSERT( stack, CoreWindowStack ); + + /* Lock the window stack. */ + if (dfb_windowstack_lock( stack )) + return DFB_FUSION; + + region.x1 = 0; + region.y1 = 0; + region.x2 = stack->rotated_width - 1; + region.y2 = stack->rotated_height - 1; + + ret = dfb_wm_update_stack( stack, ®ion, 0 ); + + /* Unlock the window stack. */ + dfb_windowstack_unlock( stack ); + + return ret; +} + +/**********************************************************************************************************************/ + +/* + * background handling + */ + +DFBResult +dfb_windowstack_set_background_mode ( CoreWindowStack *stack, + DFBDisplayLayerBackgroundMode mode ) +{ + D_DEBUG_AT( Core_WindowStack, "%s( %p, %d )\n", __FUNCTION__, stack, mode ); + + D_MAGIC_ASSERT( stack, CoreWindowStack ); + + /* Lock the window stack. */ + if (dfb_windowstack_lock( stack )) + return DFB_FUSION; + + /* nothing to do if mode is the same */ + if (mode != stack->bg.mode) { + /* for these modes a surface is required */ + if ((mode == DLBM_IMAGE || mode == DLBM_TILE) && !stack->bg.image) { + dfb_windowstack_unlock( stack ); + return DFB_MISSINGIMAGE; + } + + /* set new mode */ + stack->bg.mode = mode; + + /* force an update of the window stack */ + if (mode != DLBM_DONTCARE) + dfb_windowstack_repaint_all( stack ); + } + + /* Unlock the window stack. */ + dfb_windowstack_unlock( stack ); + + return DFB_OK; +} + +DFBResult +dfb_windowstack_set_background_image( CoreWindowStack *stack, + CoreSurface *image ) +{ + D_DEBUG_AT( Core_WindowStack, "%s( %p, %p )\n", __FUNCTION__, stack, image ); + + D_MAGIC_ASSERT( stack, CoreWindowStack ); + D_ASSERT( image != NULL ); + + if (!(image->type & CSTF_SHARED)) + return DFB_INVARG; + + /* Lock the window stack. */ + if (dfb_windowstack_lock( stack )) + return DFB_FUSION; + + /* if the surface is changed */ + if (stack->bg.image != image) { + /* detach listener from old surface and unlink it */ + if (stack->bg.image) { + dfb_surface_detach_global( stack->bg.image, + &stack->bg.image_reaction ); + + dfb_surface_unlink( &stack->bg.image ); + } + + /* link surface object */ + dfb_surface_link( &stack->bg.image, image ); + + /* attach listener to new surface */ + dfb_surface_attach_global( image, + DFB_WINDOWSTACK_BACKGROUND_IMAGE_LISTENER, + stack, &stack->bg.image_reaction ); + } + + /* force an update of the window stack */ + if (stack->bg.mode == DLBM_IMAGE || stack->bg.mode == DLBM_TILE) + dfb_windowstack_repaint_all( stack ); + + /* Unlock the window stack. */ + dfb_windowstack_unlock( stack ); + + return DFB_OK; +} + +DFBResult +dfb_windowstack_set_background_color( CoreWindowStack *stack, + const DFBColor *color ) +{ + D_ASSERT( color != NULL ); + + D_DEBUG_AT( Core_WindowStack, "%s( %p, 0x%08x )\n", __FUNCTION__, stack, + PIXEL_ARGB( color->a, color->r, color->g, color->b ) ); + + D_MAGIC_ASSERT( stack, CoreWindowStack ); + + /* Lock the window stack. */ + if (dfb_windowstack_lock( stack )) + return DFB_FUSION; + + /* do nothing if color didn't change */ + if (!DFB_COLOR_EQUAL( stack->bg.color, *color )) { + /* set new color */ + stack->bg.color = *color; + + /* force an update of the window stack */ + if (stack->bg.mode == DLBM_COLOR) + dfb_windowstack_repaint_all( stack ); + } + + /* Unlock the window stack. */ + dfb_windowstack_unlock( stack ); + + return DFB_OK; +} + +DFBResult +dfb_windowstack_set_background_color_index( CoreWindowStack *stack, + int index ) +{ + D_DEBUG_AT( Core_WindowStack, "%s( %p, %d )\n", __FUNCTION__, stack, index ); + + D_MAGIC_ASSERT( stack, CoreWindowStack ); + + /* Lock the window stack. */ + if (dfb_windowstack_lock( stack )) + return DFB_FUSION; + + /* do nothing if color didn't change */ + if (stack->bg.color_index != index) { + /* set new color index */ + stack->bg.color_index = index; + + /* force an update of the window stack */ + if (stack->bg.mode == DLBM_COLOR) + dfb_windowstack_repaint_all( stack ); + } + + /* Unlock the window stack. */ + dfb_windowstack_unlock( stack ); + + return DFB_OK; +} + +/**********************************************************************************************************************/ + +/* + * cursor control + */ + +DFBResult +dfb_windowstack_cursor_enable( CoreDFB *core, CoreWindowStack *stack, bool enable ) +{ + DFBResult ret; + + D_DEBUG_AT( Core_WindowStack, "%s( %p, %s )\n", __FUNCTION__, stack, enable ? "enable" : "disable" ); + + D_MAGIC_ASSERT( stack, CoreWindowStack ); + + /* Lock the window stack. */ + if (dfb_windowstack_lock( stack )) + return DFB_FUSION; + + stack->cursor.set = true; + + if (dfb_config->no_cursor || stack->cursor.enabled == enable) { + dfb_windowstack_unlock( stack ); + return DFB_OK; + } + + if (enable && !stack->cursor.surface) { + ret = load_default_cursor( core, stack ); + if (ret) { + dfb_windowstack_unlock( stack ); + return ret; + } + } + + /* Keep state. */ + stack->cursor.enabled = enable; + + /* Notify WM. */ + dfb_wm_update_cursor( stack, enable ? CCUF_ENABLE : CCUF_DISABLE ); + + /* Unlock the window stack. */ + dfb_windowstack_unlock( stack ); + + return DFB_OK; +} + +DFBResult +dfb_windowstack_cursor_set_opacity( CoreWindowStack *stack, u8 opacity ) +{ + D_DEBUG_AT( Core_WindowStack, "%s( %p, 0x%02x )\n", __FUNCTION__, stack, opacity ); + + D_MAGIC_ASSERT( stack, CoreWindowStack ); + + /* Lock the window stack. */ + if (dfb_windowstack_lock( stack )) + return DFB_FUSION; + + if (stack->cursor.opacity != opacity) { + /* Set new opacity. */ + stack->cursor.opacity = opacity; + + /* Notify WM. */ + if (stack->cursor.enabled) + dfb_wm_update_cursor( stack, CCUF_OPACITY ); + } + + /* Unlock the window stack. */ + dfb_windowstack_unlock( stack ); + + return DFB_OK; +} + +DFBResult +dfb_windowstack_cursor_set_shape( CoreWindowStack *stack, + CoreSurface *shape, + int hot_x, + int hot_y ) +{ + DFBResult ret; + CoreSurface *cursor; + CoreCursorUpdateFlags flags = CCUF_SHAPE; + + D_DEBUG_AT( Core_WindowStack, "%s( %p, %p, hot %d, %d ) <- size %dx%d\n", + __FUNCTION__, stack, shape, hot_x, hot_y, + shape->config.size.w, shape->config.size.h ); + + D_MAGIC_ASSERT( stack, CoreWindowStack ); + D_ASSERT( shape != NULL ); + + if (dfb_config->no_cursor) + return DFB_OK; + + /* Lock the window stack. */ + if (dfb_windowstack_lock( stack )) + return DFB_FUSION; + + cursor = stack->cursor.surface; + if (!cursor) { + D_ASSUME( !stack->cursor.enabled ); + + /* Create the a surface for the shape. */ + ret = create_cursor_surface( stack, shape->config.size.w, shape->config.size.h ); + if (ret) { + dfb_windowstack_unlock( stack ); + return ret; + } + + cursor = stack->cursor.surface; + } + else if (stack->cursor.size.w != shape->config.size.w || stack->cursor.size.h != shape->config.size.h) { + dfb_surface_unlink( &stack->cursor.surface ); + + /* Recreate the surface for the shape. */ + ret = create_cursor_surface( stack, shape->config.size.w, shape->config.size.h ); + if (ret) { + dfb_windowstack_unlock( stack ); + return ret; + } + + cursor = stack->cursor.surface; + + + stack->cursor.size.w = shape->config.size.w; + stack->cursor.size.h = shape->config.size.h; + + /* Notify about new size/shape. */ + flags |= CCUF_SIZE | CCUF_SHAPE; + } + + if (stack->cursor.hot.x != hot_x || stack->cursor.hot.y != hot_y) { + stack->cursor.hot.x = hot_x; + stack->cursor.hot.y = hot_y; + + /* Notify about new position. */ + flags |= CCUF_POSITION; + } + + /* Copy the content of the new shape. */ + dfb_gfx_copy( shape, cursor, NULL ); + + cursor->config.caps = ((cursor->config.caps & ~DSCAPS_PREMULTIPLIED) | (shape->config.caps & DSCAPS_PREMULTIPLIED)); + + /* Notify the WM. */ + if (stack->cursor.enabled) + dfb_wm_update_cursor( stack, flags ); + + /* Unlock the window stack. */ + dfb_windowstack_unlock( stack ); + + return DFB_OK; +} + +DFBResult +dfb_windowstack_cursor_warp( CoreWindowStack *stack, int x, int y ) +{ + D_DEBUG_AT( Core_WindowStack, "%s( %p, %d, %d )\n", __FUNCTION__, stack, x, y ); + + D_MAGIC_ASSERT( stack, CoreWindowStack ); + + /* Lock the window stack. */ + if (dfb_windowstack_lock( stack )) + return DFB_FUSION; + + if (x < 0) + x = 0; + else if (x > stack->width - 1) + x = stack->width - 1; + + if (y < 0) + y = 0; + else if (y > stack->height - 1) + y = stack->height - 1; + + if (stack->cursor.x != x || stack->cursor.y != y) { + stack->cursor.x = x; + stack->cursor.y = y; + + /* Notify the WM. */ + if (stack->cursor.enabled) + dfb_wm_update_cursor( stack, CCUF_POSITION ); + } + + /* Unlock the window stack. */ + dfb_windowstack_unlock( stack ); + + return DFB_OK; +} + +DFBResult +dfb_windowstack_cursor_set_acceleration( CoreWindowStack *stack, + int numerator, + int denominator, + int threshold ) +{ + D_DEBUG_AT( Core_WindowStack, "%s( %p, %d, %d, %d )\n", + __FUNCTION__, stack, numerator, denominator, threshold ); + + D_MAGIC_ASSERT( stack, CoreWindowStack ); + + /* Lock the window stack. */ + if (dfb_windowstack_lock( stack )) + return DFB_FUSION; + + stack->cursor.numerator = numerator; + stack->cursor.denominator = denominator; + stack->cursor.threshold = threshold; + + /* Unlock the window stack. */ + dfb_windowstack_unlock( stack ); + + return DFB_OK; +} + +DFBResult +dfb_windowstack_get_cursor_position( CoreWindowStack *stack, int *ret_x, int *ret_y ) +{ + D_DEBUG_AT( Core_WindowStack, "%s( %p, %p, %p )\n", __FUNCTION__, stack, ret_x, ret_y ); + + D_MAGIC_ASSERT( stack, CoreWindowStack ); + D_ASSUME( ret_x != NULL || ret_y != NULL ); + + /* Lock the window stack. */ + if (dfb_windowstack_lock( stack )) + return DFB_FUSION; + + if (ret_x) + *ret_x = stack->cursor.x; + + if (ret_y) + *ret_y = stack->cursor.y; + + /* Unlock the window stack. */ + dfb_windowstack_unlock( stack ); + + return DFB_OK; +} + +/**********************************************************************************************************************/ + +static ReactionResult +stack_input_core_listener( const void *msg_data, + void *ctx ) +{ + const CoreInputCoreNotification *notification = msg_data; + CoreWindowStack *stack = ctx; + + (void) notification; + + D_DEBUG_AT( Core_WindowStack, "%s( %p, %p, %d )\n", __FUNCTION__, msg_data, ctx, notification->device_id ); + + D_ASSERT( msg_data != NULL ); + D_MAGIC_ASSERT( stack, CoreWindowStack ); + + /* Lock the window stack. */ + if (dfb_windowstack_lock( stack )) + return RS_REMOVE; + + /* Attach to all input devices */ + dfb_input_enumerate_devices( stack_attach_devices, stack, DICAPS_ALL ); + + /* Unlock the window stack. */ + dfb_windowstack_unlock( stack ); + + return RS_OK; +} + +ReactionResult +_dfb_windowstack_inputdevice_listener( const void *msg_data, + void *ctx ) +{ + const DFBInputEvent *event = msg_data; + CoreWindowStack *stack = ctx; + + D_DEBUG_AT( Core_WindowStack, "%s( %p, %p )\n", __FUNCTION__, msg_data, ctx ); + + D_ASSERT( msg_data != NULL ); + D_MAGIC_ASSERT( stack, CoreWindowStack ); + + /* Lock the window stack. */ + if (dfb_windowstack_lock( stack )) + return RS_REMOVE; + + /* Call the window manager to dispatch the event. */ + if (dfb_layer_context_active( stack->context )) + dfb_wm_process_input( stack, event ); + + /* Unlock the window stack. */ + dfb_windowstack_unlock( stack ); + + return RS_OK; +} + +/* + * listen to the background image + */ +ReactionResult +_dfb_windowstack_background_image_listener( const void *msg_data, + void *ctx ) +{ + const CoreSurfaceNotification *notification = msg_data; + CoreWindowStack *stack = ctx; + + D_DEBUG_AT( Core_WindowStack, "%s( %p, %p )\n", __FUNCTION__, msg_data, ctx ); + + D_ASSERT( notification != NULL ); + D_MAGIC_ASSERT( stack, CoreWindowStack ); + + if (notification->flags & CSNF_DESTROY) { + if (stack->bg.image == notification->surface) { + D_ERROR( "Core/WindowStack: Surface for background vanished.\n" ); + + stack->bg.mode = DLBM_COLOR; + stack->bg.image = NULL; + + dfb_windowstack_repaint_all( stack ); + } + + return RS_REMOVE; + } + + if (notification->flags & (CSNF_FLIP | CSNF_SIZEFORMAT)) + dfb_windowstack_repaint_all( stack ); + + return RS_OK; +} + +/**********************************************************************************************************************/ + +/* + * internals + */ + +static DFBEnumerationResult +stack_attach_devices( CoreInputDevice *device, + void *ctx ) +{ + StackDevice *dev; + DFBInputDeviceID id = dfb_input_device_id( device ); + CoreWindowStack *stack = (CoreWindowStack*) ctx; + + D_MAGIC_ASSERT( stack, CoreWindowStack ); + + direct_list_foreach (dev, stack->devices) { + if (dev->id == id) + return DFENUM_OK; + } + + dev = SHCALLOC( stack->shmpool, 1, sizeof(StackDevice) ); + if (!dev) { + D_ERROR( "Core/WindowStack: Could not allocate %zu bytes\n", sizeof(StackDevice) ); + return DFENUM_CANCEL; + } + + dev->id = id; + + direct_list_prepend( &stack->devices, &dev->link ); + + dfb_input_attach( device, _dfb_windowstack_inputdevice_listener, ctx, &dev->reaction ); + + return DFENUM_OK; +} + +/* + * internal function that installs the cursor window + * and fills it with data from 'cursor.dat' + */ +static DFBResult +load_default_cursor( CoreDFB *core, CoreWindowStack *stack ) +{ + DFBResult ret; + int i; + FILE *f; + CoreSurfaceBufferLock lock; + void *data; + + D_DEBUG_AT( Core_WindowStack, "%s( %p )\n", __FUNCTION__, stack ); + + D_MAGIC_ASSERT( stack, CoreWindowStack ); + + if (!stack->cursor.surface) { + ret = create_cursor_surface( stack, 40, 40 ); + if (ret) + return ret; + } + else { + stack->cursor.hot.x = 0; + stack->cursor.hot.y = 0; + stack->cursor.size.w = 40; + stack->cursor.size.h = 40; + } + + /* lock the cursor surface */ + ret = dfb_surface_lock_buffer( stack->cursor.surface, CSBR_BACK, CSAID_CPU, CSAF_WRITE, &lock ); + if (ret) { + D_ERROR( "Core/WindowStack: cannot lock the cursor surface!\n" ); + return ret; + } + + data = lock.addr; + + /* initialize as empty cursor */ + memset( data, 0, 40 * lock.pitch ); + + /* open the file containing the cursors image data */ + f = fopen( CURSORFILE, "rb" ); + if (!f) { + ret = errno2result( errno ); + + /* ignore a missing cursor file */ + if (ret == DFB_FILENOTFOUND) + ret = DFB_OK; + else + D_PERROR( "Core/WindowStack: `" CURSORFILE "` could not be opened!\n" ); + + goto finish; + } + + /* read from file directly into the cursor window surface */ + for (i=0; i<40; i++) { + if (fread( data, MIN (40*4, lock.pitch), 1, f ) != 1) { + ret = errno2result( errno ); + + D_ERROR( "Core/WindowStack: unexpected end or read error of cursor data!\n" ); + + goto finish; + } +#ifdef WORDS_BIGENDIAN + { + int i = MIN (40, lock.pitch/4); + u32 *tmp_data = data; + + while (i--) { + *tmp_data = (*tmp_data & 0xFF000000) >> 24 | + (*tmp_data & 0x00FF0000) >> 8 | + (*tmp_data & 0x0000FF00) << 8 | + (*tmp_data & 0x000000FF) << 24; + ++tmp_data; + } + } +#endif + data += lock.pitch; + } + +finish: + if (f) + fclose( f ); + + dfb_surface_unlock_buffer( stack->cursor.surface, &lock ); + + return ret; +} + +static DFBResult +create_cursor_surface( CoreWindowStack *stack, + int width, + int height ) +{ + DFBResult ret; + CoreSurface *surface; + CoreLayer *layer; + CoreLayerContext *context; + DFBSurfaceCapabilities surface_caps = DSCAPS_NONE; + + D_DEBUG_AT( Core_WindowStack, "%s( %p, %dx%d )\n", __FUNCTION__, stack, width, height ); + + D_MAGIC_ASSERT( stack, CoreWindowStack ); + D_ASSERT( stack->cursor.surface == NULL ); + + context = stack->context; + + D_ASSERT( context != NULL ); + + layer = dfb_layer_at( context->layer_id ); + + D_ASSERT( layer != NULL ); + + stack->cursor.x = stack->width / 2; + stack->cursor.y = stack->height / 2; + stack->cursor.hot.x = 0; + stack->cursor.hot.y = 0; + stack->cursor.size.w = width; + stack->cursor.size.h = height; + + if (context->config.buffermode == DLBM_WINDOWS) + D_WARN( "cursor not yet visible with DLBM_WINDOWS" ); + + dfb_surface_caps_apply_policy( stack->cursor.policy, &surface_caps ); + + /* Create the cursor surface. */ + ret = dfb_surface_create_simple( layer->core, width, height, DSPF_ARGB, + surface_caps, CSTF_SHARED | CSTF_CURSOR, + 0, /* FIXME: no shared cursor objects, no cursor id */ + NULL, &surface ); + if (ret) { + D_ERROR( "Core/WindowStack: Failed creating a surface for software cursor!\n" ); + return ret; + } + + dfb_surface_globalize( surface ); + + stack->cursor.surface = surface; + + return DFB_OK; +} + diff --git a/Source/DirectFB/src/core/windowstack.h b/Source/DirectFB/src/core/windowstack.h new file mode 100755 index 0000000..6d7bed5 --- /dev/null +++ b/Source/DirectFB/src/core/windowstack.h @@ -0,0 +1,105 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef __CORE__WINDOWSTACK_H__ +#define __CORE__WINDOWSTACK_H__ + +#include +#include + +#include + +/* + * allocates a WindowStack, initializes it, registers it for input events + */ +CoreWindowStack *dfb_windowstack_create ( CoreLayerContext *context ); + +void dfb_windowstack_detach_devices( CoreWindowStack *stack ); + +void dfb_windowstack_destroy( CoreWindowStack *stack ); + +void dfb_windowstack_resize ( CoreWindowStack *stack, + int width, + int height, + int rotation ); + +DirectResult dfb_windowstack_lock ( CoreWindowStack *stack ); + +DirectResult dfb_windowstack_unlock ( CoreWindowStack *stack ); + +/* + * repaints all window on a window stack + */ +DFBResult dfb_windowstack_repaint_all( CoreWindowStack *stack ); + +/* + * background handling + */ +DFBResult dfb_windowstack_set_background_mode ( CoreWindowStack *stack, + DFBDisplayLayerBackgroundMode mode ); + +DFBResult dfb_windowstack_set_background_image( CoreWindowStack *stack, + CoreSurface *image ); + +DFBResult dfb_windowstack_set_background_color( CoreWindowStack *stack, + const DFBColor *color ); + +DFBResult dfb_windowstack_set_background_color_index( CoreWindowStack *stack, + int index ); + + +/* + * cursor control + */ +DFBResult dfb_windowstack_cursor_enable( CoreDFB *core, + CoreWindowStack *stack, + bool enable ); + +DFBResult dfb_windowstack_cursor_set_shape( CoreWindowStack *stack, + CoreSurface *shape, + int hot_x, + int hot_y ); + +DFBResult dfb_windowstack_cursor_set_opacity( CoreWindowStack *stack, + u8 opacity ); + +DFBResult dfb_windowstack_cursor_set_acceleration( CoreWindowStack *stack, + int numerator, + int denominator, + int threshold ); + +DFBResult dfb_windowstack_cursor_warp( CoreWindowStack *stack, + int x, + int y ); + + +DFBResult dfb_windowstack_get_cursor_position (CoreWindowStack *stack, + int *x, + int *y); + +#endif diff --git a/Source/DirectFB/src/core/wm.c b/Source/DirectFB/src/core/wm.c new file mode 100755 index 0000000..fb9148c --- /dev/null +++ b/Source/DirectFB/src/core/wm.c @@ -0,0 +1,1440 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +DEFINE_MODULE_DIRECTORY( dfb_core_wm_modules, "wm", DFB_CORE_WM_ABI_VERSION ); + + +D_DEBUG_DOMAIN( Core_WM, "Core/WM", "DirectFB WM Core" ); + +/**********************************************************************************************************************/ + +typedef struct { + int magic; + + DirectLink *stacks; + + int abi; + + char *name; + CoreWMInfo info; + void *data; + + FusionSHMPoolShared *shmpool; + + FusionReactor *reactor; +} DFBWMCoreShared; + +struct __DFB_DFBWMCore { + int magic; + + CoreDFB *core; + + DFBWMCoreShared *shared; + + + DirectModuleEntry *module; + const CoreWMFuncs *funcs; + void *data; +}; + + +DFB_CORE_PART( wm_core, WMCore ); + +/**********************************************************************************************************************/ + +static DFBResult load_module( const char *name ); + +/**********************************************************************************************************************/ + +static DFBWMCore *wm_local = NULL; /* FIXME */ +static DFBWMCoreShared *wm_shared = NULL; /* FIXME */ + + +static DFBResult +dfb_wm_core_initialize( CoreDFB *core, + DFBWMCore *data, + DFBWMCoreShared *shared ) +{ + DFBResult ret; + + D_DEBUG_AT( Core_WM, "dfb_wm_core_initialize( %p, %p, %p )\n", core, data, shared ); + + D_ASSERT( data != NULL ); + D_ASSERT( shared != NULL ); + + data->core = core; + data->shared = shared; + + + wm_local = data; /* FIXME */ + wm_shared = shared; /* FIXME */ + + wm_shared->shmpool = dfb_core_shmpool( core ); + + /* Set ABI version for the session. */ + wm_shared->abi = DFB_CORE_WM_ABI_VERSION; + + /* Load the module. */ + ret = load_module( dfb_config->wm ); + if (ret) + goto error; + + D_ASSERT( wm_local->funcs != NULL ); + D_ASSERT( wm_local->funcs->GetWMInfo != NULL ); + D_ASSERT( wm_local->funcs->Initialize != NULL ); + + /* Query module information. */ + wm_local->funcs->GetWMInfo( &wm_shared->info ); + + D_INFO( "DirectFB/Core/WM: %s %d.%d (%s)\n", + wm_shared->info.name, wm_shared->info.version.major, + wm_shared->info.version.minor, wm_shared->info.vendor ); + + ret = DFB_NOSHAREDMEMORY; + + /* Store module name in shared memory. */ + wm_shared->name = SHSTRDUP( wm_shared->shmpool, wm_local->module->name ); + if (!wm_shared->name) { + D_OOSHM(); + goto error; + } + + /* Allocate shared window manager data. */ + if (wm_shared->info.wm_shared_size) { + wm_shared->data = SHCALLOC( wm_shared->shmpool, 1, wm_shared->info.wm_shared_size ); + if (!wm_shared->data) { + D_OOSHM(); + goto error; + } + } + + ret = DFB_NOSYSTEMMEMORY; + + /* Allocate local window manager data. */ + if (wm_shared->info.wm_data_size) { + wm_local->data = D_CALLOC( 1, wm_shared->info.wm_data_size ); + if (!wm_local->data) { + D_OOM(); + goto error; + } + } + + wm_shared->reactor = fusion_reactor_new( 0, "WM", dfb_core_world(core) ); + + /* Initialize window manager. */ + ret = wm_local->funcs->Initialize( core, wm_local->data, wm_shared->data ); + if (ret) { + D_DERROR( ret, "DirectFB/Core/WM: Could not initialize window manager!\n" ); + goto error; + } + + D_MAGIC_SET( data, DFBWMCore ); + D_MAGIC_SET( shared, DFBWMCoreShared ); + + return DFB_OK; + +error: + if (wm_local->data) + D_FREE( wm_local->data ); + + if (wm_shared->data) + SHFREE( wm_shared->shmpool, wm_shared->data ); + + if (wm_shared->name) + SHFREE( wm_shared->shmpool, wm_shared->name ); + + wm_local = NULL; + wm_shared = NULL; + + return ret; +} + +static DFBResult +dfb_wm_core_join( CoreDFB *core, + DFBWMCore *data, + DFBWMCoreShared *shared ) +{ + DFBResult ret; + CoreWMInfo info; + + D_DEBUG_AT( Core_WM, "dfb_wm_core_join( %p, %p, %p )\n", core, data, shared ); + + D_ASSERT( data != NULL ); + D_MAGIC_ASSERT( shared, DFBWMCoreShared ); + + data->core = core; + data->shared = shared; + + + wm_local = data; /* FIXME */ + wm_shared = shared; /* FIXME */ + + /* Check binary version numbers. */ + if (wm_shared->abi != DFB_CORE_WM_ABI_VERSION) { + D_ERROR( "DirectFB/Core/WM: ABI version of running core instance (%d) doesn't match %d!\n", + wm_shared->abi, DFB_CORE_WM_ABI_VERSION ); + ret = DFB_VERSIONMISMATCH; + goto error; + } + + /* Load the module that is used by the running session. */ + ret = load_module( wm_shared->name ); + if (ret) + goto error; + + D_ASSERT( wm_local->funcs != NULL ); + D_ASSERT( wm_local->funcs->GetWMInfo != NULL ); + D_ASSERT( wm_local->funcs->Join != NULL ); + + /* Query module information. */ + wm_local->funcs->GetWMInfo( &info ); + + /* Check binary version numbers. */ + if (info.version.binary != wm_shared->info.version.binary) { + D_ERROR( "DirectFB/Core/WM: ABI version of running module instance (%d) doesn't match %d!\n", + wm_shared->info.version.binary, info.version.binary ); + ret = DFB_VERSIONMISMATCH; + goto error; + } + + /* Allocate window manager data. */ + if (wm_shared->info.wm_data_size) { + wm_local->data = D_CALLOC( 1, wm_shared->info.wm_data_size ); + if (!wm_local->data) { + D_WARN( "out of memory" ); + ret = DFB_NOSYSTEMMEMORY; + goto error; + } + } + + /* Join window manager. */ + ret = wm_local->funcs->Join( core, wm_local->data, wm_shared->data ); + if (ret) { + D_DERROR( ret, "DirectFB/Core/WM: Could not join window manager!\n" ); + goto error; + } + + D_MAGIC_SET( data, DFBWMCore ); + + return DFB_OK; + +error: + if (wm_local->data) + D_FREE( wm_local->data ); + + wm_local = NULL; + wm_shared = NULL; + + return ret; +} + +static DFBResult +dfb_wm_core_shutdown( DFBWMCore *data, + bool emergency ) +{ + DFBResult ret; + DFBWMCoreShared *shared; + + D_DEBUG_AT( Core_WM, "dfb_wm_core_shutdown( %p, %semergency )\n", data, emergency ? "" : "no " ); + + D_MAGIC_ASSERT( data, DFBWMCore ); + D_MAGIC_ASSERT( data->shared, DFBWMCoreShared ); + + shared = data->shared; + + D_ASSERT( wm_local != NULL ); + D_ASSERT( wm_local->funcs != NULL ); + D_ASSERT( wm_local->funcs->Shutdown != NULL ); + D_ASSERT( wm_shared != NULL ); + + fusion_reactor_destroy( wm_shared->reactor ); + + /* Shutdown window manager. */ + ret = wm_local->funcs->Shutdown( emergency, wm_local->data, wm_shared->data ); + + /* Unload the module. */ + direct_module_unref( wm_local->module ); + + /* Deallocate local window manager data. */ + if (wm_local->data) + D_FREE( wm_local->data ); + + /* Deallocate shared window manager data. */ + if (wm_shared->data) + SHFREE( wm_shared->shmpool, wm_shared->data ); + + /* Free module name in shared memory. */ + SHFREE( wm_shared->shmpool, wm_shared->name ); + + wm_local = NULL; + wm_shared = NULL; + + + D_MAGIC_CLEAR( data ); + D_MAGIC_CLEAR( shared ); + + return ret; +} + +static DFBResult +dfb_wm_core_leave( DFBWMCore *data, + bool emergency ) +{ + DFBResult ret; + DFBWMCoreShared *shared; + + D_DEBUG_AT( Core_WM, "dfb_wm_core_leave( %p, %semergency )\n", data, emergency ? "" : "no " ); + + D_MAGIC_ASSERT( data, DFBWMCore ); + D_MAGIC_ASSERT( data->shared, DFBWMCoreShared ); + + shared = data->shared; + + + D_ASSERT( wm_local != NULL ); + D_ASSERT( wm_local->funcs != NULL ); + D_ASSERT( wm_local->funcs->Leave != NULL ); + D_ASSERT( wm_shared != NULL ); + + /* Leave window manager. */ + ret = wm_local->funcs->Leave( emergency, wm_local->data, wm_shared->data ); + + /* Unload the module. */ + direct_module_unref( wm_local->module ); + + /* Deallocate local window manager data. */ + if (wm_local->data) + D_FREE( wm_local->data ); + + wm_local = NULL; + wm_shared = NULL; + + + D_MAGIC_CLEAR( data ); + + return ret; +} + +static DFBResult +dfb_wm_core_suspend( DFBWMCore *data ) +{ + DFBWMCoreShared *shared; + + D_DEBUG_AT( Core_WM, "%s( %p )\n", __FUNCTION__, data ); + + D_MAGIC_ASSERT( data, DFBWMCore ); + D_MAGIC_ASSERT( data->shared, DFBWMCoreShared ); + + shared = data->shared; + + D_ASSERT( wm_local != NULL ); + D_ASSERT( wm_local->funcs != NULL ); + D_ASSERT( wm_local->funcs->Suspend != NULL ); + D_ASSERT( wm_shared != NULL ); + + return wm_local->funcs->Suspend( wm_local->data, wm_shared->data ); +} + +static DFBResult +dfb_wm_core_resume( DFBWMCore *data ) +{ + DFBWMCoreShared *shared; + + D_DEBUG_AT( Core_WM, "%s( %p )\n", __FUNCTION__, data ); + + D_MAGIC_ASSERT( data, DFBWMCore ); + D_MAGIC_ASSERT( data->shared, DFBWMCoreShared ); + + shared = data->shared; + + D_ASSERT( wm_local != NULL ); + D_ASSERT( wm_local->funcs != NULL ); + D_ASSERT( wm_local->funcs->Resume != NULL ); + D_ASSERT( wm_shared != NULL ); + + return wm_local->funcs->Resume( wm_local->data, wm_shared->data ); +} + +DFBResult +dfb_wm_close_all_stacks( void *data ) +{ + CoreLayerContext *context; + CoreWindowStack *stack, *next; + DFBWMCore *local; + DFBWMCoreShared *shared; + + D_DEBUG_AT( Core_WM, "%s( %p )\n", __FUNCTION__, data ); + + local = data; + + D_MAGIC_ASSERT( local, DFBWMCore ); + D_ASSERT( local->funcs != NULL ); + D_ASSERT( local->funcs->CloseStack != NULL ); + + shared = local->shared; + + D_MAGIC_ASSERT( shared, DFBWMCoreShared ); + + D_DEBUG_AT( Core_WM, " -> checking %d stacks...\n", direct_list_count_elements_EXPENSIVE(shared->stacks) ); + + direct_list_foreach_safe (stack, next, shared->stacks) { + D_DEBUG_AT( Core_WM, " -> checking %p...\n", stack ); + + D_MAGIC_ASSERT( stack, CoreWindowStack ); + + context = stack->context; + D_MAGIC_ASSERT( context, CoreLayerContext ); + + D_DEBUG_AT( Core_WM, " -> ref context %p...\n", context ); + + dfb_layer_context_ref( context ); + + dfb_layer_context_lock( context ); + + if (stack->flags & CWSF_INITIALIZED) { + D_DEBUG_AT( Core_WM, " => CLOSING %p\n", stack ); + dfb_wm_close_stack( stack ); + } + + dfb_layer_context_unlock( context ); + + D_DEBUG_AT( Core_WM, " -> unref context %p...\n", context ); + + dfb_layer_context_unref( context ); + } + + return DFB_OK; +} + +/**************************************************************************************************/ + +static DFBResult +load_module( const char *name ) +{ + DirectLink *l; + + D_ASSERT( wm_local != NULL ); + + direct_modules_explore_directory( &dfb_core_wm_modules ); + + direct_list_foreach( l, dfb_core_wm_modules.entries ) { + DirectModuleEntry *module = (DirectModuleEntry*) l; + const CoreWMFuncs *funcs; + + funcs = direct_module_ref( module ); + if (!funcs) + continue; + + if (!name || !strcasecmp( name, module->name )) { + if (wm_local->module) + direct_module_unref( wm_local->module ); + + wm_local->module = module; + wm_local->funcs = funcs; + } + else + direct_module_unref( module ); + } + + if (!wm_local->module) { + if (name) + D_ERROR( "DirectFB/WM: Window manager module '%s' not found!\n", name ); + else + D_ERROR( "DirectFB/WM: No window manager module found!\n" ); + + return DFB_NOIMPL; + } + + return DFB_OK; +} + +/**************************************************************************************************/ + +static void +convert_config( DFBWindowConfig *config, + const CoreWindowConfig *from ) +{ + config->bounds = from->bounds; + config->opacity = from->opacity; + config->stacking = from->stacking; + config->options = from->options; + config->events = from->events; + config->color = from->color; + config->color_key = from->color_key; + config->opaque = from->opaque; +// config->key_selection = DWKS_ALL; // FIXME: implement +// config->keys = NULL; // FIXME: implement +// config->num_keys = 0; // FIXME: implement + config->association = from->association; + config->src_geometry = from->src_geometry; + config->dst_geometry = from->dst_geometry; + config->cursor_flags = from->cursor_flags; + config->cursor_resolution = from->cursor_resolution; +} + +static void +convert_state( DFBWindowState *state, + const CoreWindowFlags flags ) +{ + state->flags = DWSTATE_NONE; + + if (flags & CWF_INSERTED) + state->flags |= DWSTATE_INSERTED; + + if (flags & CWF_FOCUSED) + state->flags |= DWSTATE_FOCUSED; + + if (flags & CWF_ENTERED) + state->flags |= DWSTATE_ENTERED; +} + +/**************************************************************************************************/ + +typedef struct { + ReactionFunc func; + void *ctx; +} AttachContext; + +static DFBEnumerationResult +wm_window_attach_callback( CoreWindow *window, + void *ctx ) +{ + AttachContext *context = ctx; + + CoreWM_WindowAdd add; + + add.info.window_id = window->id; + add.info.caps = window->caps; + add.info.resource_id = window->resource_id; + + convert_config( &add.info.config, &window->config ); + + convert_state( &add.info.state, window->flags ); + + context->func( &add, context->ctx ); + + return DFENUM_OK; +} + +DFBResult +dfb_wm_attach( CoreDFB *core, + int channel, + ReactionFunc func, + void *ctx, + Reaction *reaction ) +{ + D_ASSERT( wm_shared != NULL ); + + if (channel == CORE_WM_WINDOW_ADD) { + CoreWindowStack *stack = (CoreWindowStack *) wm_shared->stacks; + + if (stack) { + DFBResult ret; + AttachContext context = { func, ctx }; + + dfb_windowstack_lock( stack ); + + ret = dfb_wm_enum_windows( stack, wm_window_attach_callback, &context ); + if (ret) + D_WARN( "could not enumerate windows" ); + + ret = fusion_reactor_attach_channel( wm_shared->reactor, channel, func, ctx, reaction ); + + dfb_windowstack_unlock( stack ); + + return ret; + } + } + + return fusion_reactor_attach_channel( wm_shared->reactor, channel, func, ctx, reaction ); +} + +DFBResult +dfb_wm_detach( CoreDFB *core, + Reaction *reaction ) +{ + D_ASSERT( wm_shared != NULL ); + + return fusion_reactor_detach( wm_shared->reactor, reaction ); +} + +DFBResult +dfb_wm_dispatch( CoreDFB *core, + int channel, + const void *data, + int size ) +{ + D_ASSERT( wm_shared != NULL ); + + return fusion_reactor_dispatch_channel( wm_shared->reactor, channel, data, size, true, NULL ); +} + +DFBResult +dfb_wm_dispatch_WindowAdd( CoreDFB *core, + CoreWindow *window ) +{ + CoreWM_WindowAdd add; + + add.info.window_id = window->id; + add.info.caps = window->caps; + add.info.resource_id = window->resource_id; + + convert_config( &add.info.config, &window->config ); + + convert_state( &add.info.state, window->flags ); + + return dfb_wm_dispatch( core, CORE_WM_WINDOW_ADD, &add, sizeof(add) ); +} + +DFBResult +dfb_wm_dispatch_WindowRemove( CoreDFB *core, + CoreWindow *window ) +{ + CoreWM_WindowRemove remove; + + remove.window_id = window->id; + + return dfb_wm_dispatch( core, CORE_WM_WINDOW_REMOVE, &remove, sizeof(remove) ); +} + +DFBResult +dfb_wm_dispatch_WindowConfig( CoreDFB *core, + CoreWindow *window, + DFBWindowConfigFlags flags ) +{ + CoreWM_WindowConfig config; + + config.window_id = window->id; + config.flags = flags; + + convert_config( &config.config, &window->config ); + + return dfb_wm_dispatch( core, CORE_WM_WINDOW_CONFIG, &config, sizeof(config) ); +} + +DFBResult +dfb_wm_dispatch_WindowState( CoreDFB *core, + CoreWindow *window ) +{ + CoreWM_WindowState state; + + state.window_id = window->id; + + convert_state( &state.state, window->flags ); + + return dfb_wm_dispatch( core, CORE_WM_WINDOW_STATE, &state, sizeof(state) ); +} + +DFBResult +dfb_wm_dispatch_WindowRestack( CoreDFB *core, + CoreWindow *window, + unsigned int index ) +{ + CoreWM_WindowRestack restack; + + restack.window_id = window->id; + restack.index = index; + + return dfb_wm_dispatch( core, CORE_WM_WINDOW_RESTACK, &restack, sizeof(restack) ); +} + +DFBResult +dfb_wm_dispatch_WindowFocus( CoreDFB *core, + CoreWindow *window ) +{ + CoreWM_WindowFocus focus; + + focus.window_id = window->id; + + return dfb_wm_dispatch( core, CORE_WM_WINDOW_FOCUS, &focus, sizeof(focus) ); +} + +/**************************************************************************************************/ + +void +dfb_wm_get_info( CoreWMInfo *info ) +{ + D_ASSERT( wm_shared != NULL ); + + D_ASSERT( info != NULL ); + + *info = wm_shared->info; +} + +DFBResult +dfb_wm_post_init( CoreDFB *core ) +{ + D_ASSERT( wm_local != NULL ); + D_ASSERT( wm_local->funcs != NULL ); + D_ASSERT( wm_local->funcs->Resume != NULL ); + D_ASSERT( wm_shared != NULL ); + + return wm_local->funcs->PostInit( wm_local->data, wm_shared->data ); +} + +/**************************************************************************************************/ + +DFBResult +dfb_wm_init_stack( CoreWindowStack *stack ) +{ + DFBResult ret; + + D_DEBUG_AT( Core_WM, "%s( %p )\n", __FUNCTION__, stack ); + + D_ASSERT( wm_local != NULL ); + D_ASSERT( wm_local->funcs != NULL ); + D_ASSERT( wm_local->funcs->InitStack != NULL ); + D_ASSERT( wm_shared != NULL ); + + D_MAGIC_ASSERT( stack, CoreWindowStack ); + D_ASSERT( !(stack->flags & CWSF_INITIALIZED) ); + + D_MAGIC_ASSERT( stack->context, CoreLayerContext ); + FUSION_SKIRMISH_ASSERT( &stack->context->lock ); + + /* Allocate shared stack data. */ + if (wm_shared->info.stack_data_size) { + if (stack->stack_data) + SHFREE( stack->shmpool, stack->stack_data ); + + stack->stack_data = SHCALLOC( stack->shmpool, 1, wm_shared->info.stack_data_size ); + if (!stack->stack_data) { + D_WARN( "out of (shared) memory" ); + return D_OOSHM(); + } + } + + /* Window manager specific initialization. */ + ret = wm_local->funcs->InitStack( stack, wm_local->data, stack->stack_data ); + if (ret) { + if (stack->stack_data) { + SHFREE( wm_shared->shmpool, stack->stack_data ); + stack->stack_data = NULL; + } + + return ret; + } + + stack->flags |= CWSF_INITIALIZED; + + /* Add window stack to list. */ + direct_list_append( &wm_shared->stacks, &stack->link ); + + return DFB_OK; +} + +DFBResult +dfb_wm_close_stack( CoreWindowStack *stack ) +{ + D_DEBUG_AT( Core_WM, "%s( %p )\n", __FUNCTION__, stack ); + + D_ASSERT( wm_local != NULL ); + D_ASSERT( wm_local->funcs != NULL ); + D_ASSERT( wm_local->funcs->CloseStack != NULL ); + + D_MAGIC_ASSERT( stack, CoreWindowStack ); + + D_ASSUME( stack->flags & CWSF_INITIALIZED ); + + if (!(stack->flags & CWSF_INITIALIZED)) { + D_ASSUME( !(stack->flags & CWSF_ACTIVATED) ); + return DFB_OK; + } + + D_MAGIC_ASSERT( stack->context, CoreLayerContext ); + FUSION_SKIRMISH_ASSERT( &stack->context->lock ); + + /* Deactivate before deinitialization. */ + if (stack->flags & CWSF_ACTIVATED) + dfb_wm_set_active( stack, false ); + + /* + * Clear flag and remove stack first, because + * CloseStack() may cause the stack to be destroyed! + */ + stack->flags &= ~CWSF_INITIALIZED; + + /* Remove window stack from list. */ + direct_list_remove( &wm_shared->stacks, &stack->link ); + + /* Window manager specific deinitialization. */ + return wm_local->funcs->CloseStack( stack, wm_local->data, stack->stack_data ); +} + +DFBResult +dfb_wm_set_active( CoreWindowStack *stack, + bool active ) +{ + DFBResult ret; + + D_DEBUG_AT( Core_WM, "%s( %p, %sactive )\n", __FUNCTION__, stack, active ? "" : "in" ); + + D_ASSERT( wm_local != NULL ); + D_ASSERT( wm_local->funcs != NULL ); + D_ASSERT( wm_local->funcs->SetActive != NULL ); + + D_MAGIC_ASSERT( stack, CoreWindowStack ); + D_ASSERT( stack->flags & CWSF_INITIALIZED ); + + D_MAGIC_ASSERT( stack->context, CoreLayerContext ); + FUSION_SKIRMISH_ASSERT( &stack->context->lock ); + + if (active) { + D_ASSUME( !(stack->flags & CWSF_ACTIVATED) ); + + if (stack->flags & CWSF_ACTIVATED) + return DFB_OK; + + ret = wm_local->funcs->SetActive( stack, wm_local->data, stack->stack_data, true ); + + stack->flags |= CWSF_ACTIVATED; + } + else { + D_ASSUME( stack->flags & CWSF_ACTIVATED ); + + if (!(stack->flags & CWSF_ACTIVATED)) + return DFB_OK; + + ret = wm_local->funcs->SetActive( stack, wm_local->data, stack->stack_data, false ); + + stack->flags &= ~CWSF_ACTIVATED; + } + + return ret; +} + +DFBResult +dfb_wm_resize_stack( CoreWindowStack *stack, + int width, + int height ) +{ + D_DEBUG_AT( Core_WM, "%s( %p, %dx%d )\n", __FUNCTION__, stack, width, height ); + + D_ASSERT( wm_local != NULL ); + D_ASSERT( wm_local->funcs != NULL ); + D_ASSERT( wm_local->funcs->ResizeStack != NULL ); + + D_MAGIC_ASSERT( stack, CoreWindowStack ); + D_ASSERT( stack->flags & CWSF_INITIALIZED ); + + D_MAGIC_ASSERT( stack->context, CoreLayerContext ); + FUSION_SKIRMISH_ASSERT( &stack->context->lock ); + + /* Notify window manager about the new size. */ + return wm_local->funcs->ResizeStack( stack, wm_local->data, stack->stack_data, width, height ); +} + +DFBResult +dfb_wm_process_input( CoreWindowStack *stack, + const DFBInputEvent *event ) +{ + D_DEBUG_AT( Core_WM, "%s( %p, %p )\n", __FUNCTION__, stack, event ); + + D_ASSERT( wm_local != NULL ); + D_ASSERT( wm_local->funcs != NULL ); + D_ASSERT( wm_local->funcs->ProcessInput != NULL ); + + D_MAGIC_ASSERT( stack, CoreWindowStack ); + D_ASSERT( stack->flags & CWSF_INITIALIZED ); + + D_MAGIC_ASSERT( stack->context, CoreLayerContext ); + FUSION_SKIRMISH_ASSERT( &stack->context->lock ); + + D_ASSERT( event != NULL ); + + /* Dispatch input event via window manager. */ + return wm_local->funcs->ProcessInput( stack, wm_local->data, stack->stack_data, event ); +} + +DFBResult +dfb_wm_flush_keys( CoreWindowStack *stack ) +{ + D_DEBUG_AT( Core_WM, "%s( %p )\n", __FUNCTION__, stack ); + + D_ASSERT( wm_local != NULL ); + D_ASSERT( wm_local->funcs != NULL ); + D_ASSERT( wm_local->funcs->FlushKeys != NULL ); + + D_MAGIC_ASSERT( stack, CoreWindowStack ); + D_ASSERT( stack->flags & CWSF_INITIALIZED ); + + D_MAGIC_ASSERT( stack->context, CoreLayerContext ); + FUSION_SKIRMISH_ASSERT( &stack->context->lock ); + + return wm_local->funcs->FlushKeys( stack, wm_local->data, stack->stack_data ); +} + +DFBResult +dfb_wm_window_at( CoreWindowStack *stack, + int x, + int y, + CoreWindow **ret_window ) +{ + D_DEBUG_AT( Core_WM, "%s( %p, %d,%d )\n", __FUNCTION__, stack, x, y ); + + D_ASSERT( wm_local != NULL ); + D_ASSERT( wm_local->funcs != NULL ); + D_ASSERT( wm_local->funcs->WindowAt != NULL ); + + D_MAGIC_ASSERT( stack, CoreWindowStack ); + D_ASSERT( stack->flags & CWSF_INITIALIZED ); + + D_MAGIC_ASSERT( stack->context, CoreLayerContext ); + FUSION_SKIRMISH_ASSERT( &stack->context->lock ); + + D_ASSERT( ret_window != NULL ); + + return wm_local->funcs->WindowAt( stack, wm_local->data, stack->stack_data, x, y, ret_window ); +} + +DFBResult +dfb_wm_window_lookup( CoreWindowStack *stack, + DFBWindowID window_id, + CoreWindow **ret_window ) +{ + D_DEBUG_AT( Core_WM, "%s( %p, %u )\n", __FUNCTION__, stack, window_id ); + + D_ASSERT( wm_local != NULL ); + D_ASSERT( wm_local->funcs != NULL ); + D_ASSERT( wm_local->funcs->WindowLookup != NULL ); + + D_MAGIC_ASSERT( stack, CoreWindowStack ); + D_ASSERT( stack->flags & CWSF_INITIALIZED ); + + D_MAGIC_ASSERT( stack->context, CoreLayerContext ); + FUSION_SKIRMISH_ASSERT( &stack->context->lock ); + + D_ASSERT( ret_window != NULL ); + + return wm_local->funcs->WindowLookup( stack, wm_local->data, + stack->stack_data, window_id, ret_window ); +} + +DFBResult +dfb_wm_enum_windows( CoreWindowStack *stack, + CoreWMWindowCallback callback, + void *callback_ctx ) +{ + D_DEBUG_AT( Core_WM, "%s( %p, %p, %p )\n", __FUNCTION__, stack, callback, callback_ctx ); + + D_ASSERT( wm_local != NULL ); + D_ASSERT( wm_local->funcs != NULL ); + D_ASSERT( wm_local->funcs->EnumWindows != NULL ); + + D_MAGIC_ASSERT( stack, CoreWindowStack ); + D_ASSERT( stack->flags & CWSF_INITIALIZED ); + + D_MAGIC_ASSERT( stack->context, CoreLayerContext ); + FUSION_SKIRMISH_ASSERT( &stack->context->lock ); + + D_ASSERT( callback != NULL ); + + return wm_local->funcs->EnumWindows( stack, wm_local->data, + stack->stack_data, callback, callback_ctx ); +} + +/** + * Give the wm a chance to specifiy a border + */ +DFBResult +dfb_wm_get_insets( CoreWindowStack *stack, + CoreWindow *window, + DFBInsets *insets) +{ + D_ASSERT( wm_local != NULL ); + D_ASSERT( wm_local->funcs != NULL ); + D_ASSERT( wm_local->funcs->GetInsets != NULL ); + + D_MAGIC_ASSERT( stack, CoreWindowStack ); + D_ASSERT( stack->flags & CWSF_INITIALIZED ); + + D_MAGIC_ASSERT( stack->context, CoreLayerContext ); + FUSION_SKIRMISH_ASSERT( &stack->context->lock ); + + D_ASSERT( window != NULL ); + D_ASSERT( insets != NULL ); + + return wm_local->funcs->GetInsets( stack, window, insets ); +} + +/** + * Give the wm a chance to override the windows configuration + */ +DFBResult +dfb_wm_preconfigure_window( CoreWindowStack *stack, + CoreWindow *window ) +{ + DFBResult ret; + void *window_data = NULL; + + D_ASSERT( wm_local != NULL ); + D_ASSERT( wm_local->funcs != NULL ); + D_ASSERT( wm_shared != NULL ); + D_MAGIC_ASSERT( stack, CoreWindowStack ); + D_ASSERT( stack->flags & CWSF_INITIALIZED ); + D_ASSERT( window != NULL ); + D_ASSERT( wm_local->funcs->PreConfigureWindow != NULL ); + + D_MAGIC_ASSERT( stack->context, CoreLayerContext ); + FUSION_SKIRMISH_ASSERT( &stack->context->lock ); + + D_DEBUG_AT( Core_WM, "%s( %p, %p [%d,%d-%dx%d] )\n", __FUNCTION__, + stack, window, DFB_RECTANGLE_VALS(&window->config.bounds) ); + + /* Allocate shared window data. */ + if (wm_shared->info.window_data_size) { + window_data = SHCALLOC( wm_shared->shmpool, 1, wm_shared->info.window_data_size ); + if (!window_data) { + D_WARN( "out of (shared) memory" ); + return D_OOSHM(); + } + } + + /* Keep shared window data. */ + window->window_data = window_data; + + /* Tell window manager about the new window. */ + ret = wm_local->funcs->PreConfigureWindow( stack, wm_local->data, + stack->stack_data, window, window_data ); + if (ret) { + if (window_data) { + SHFREE( wm_shared->shmpool, window_data ); + window->window_data = NULL; + } + + return ret; + } + + return DFB_OK; +} + +DFBResult +dfb_wm_add_window( CoreWindowStack *stack, + CoreWindow *window ) +{ + DFBResult ret; + + D_ASSERT( wm_local != NULL ); + D_ASSERT( wm_local->funcs != NULL ); + D_ASSERT( wm_local->funcs->AddWindow != NULL ); + D_ASSERT( wm_shared != NULL ); + + D_MAGIC_ASSERT( stack, CoreWindowStack ); + D_ASSERT( stack->flags & CWSF_INITIALIZED ); + + D_MAGIC_ASSERT( stack->context, CoreLayerContext ); + FUSION_SKIRMISH_ASSERT( &stack->context->lock ); + + D_ASSERT( window != NULL ); + + D_DEBUG_AT( Core_WM, "%s( %p, %p [%d,%d-%dx%d] )\n", __FUNCTION__, + stack, window, DFB_RECTANGLE_VALS(&window->config.bounds) ); + + /* Tell window manager about the new window. */ + ret = wm_local->funcs->AddWindow( stack, wm_local->data, + stack->stack_data, window, window->window_data ); + if (ret) { + if (window->window_data) + SHFREE( wm_shared->shmpool, window->window_data ); + return ret; + } + return DFB_OK; +} + +DFBResult +dfb_wm_remove_window( CoreWindowStack *stack, + CoreWindow *window ) +{ + DFBResult ret; + + D_ASSERT( wm_local != NULL ); + D_ASSERT( wm_local->funcs != NULL ); + D_ASSERT( wm_local->funcs->RemoveWindow != NULL ); + + D_MAGIC_ASSERT( stack, CoreWindowStack ); + D_ASSERT( stack->flags & CWSF_INITIALIZED ); + + D_MAGIC_ASSERT( stack->context, CoreLayerContext ); + FUSION_SKIRMISH_ASSERT( &stack->context->lock ); + + D_ASSERT( window != NULL ); + + D_DEBUG_AT( Core_WM, "%s( %p, %p [%d,%d-%dx%d] )\n", __FUNCTION__, + stack, window, DFB_RECTANGLE_VALS(&window->config.bounds) ); + + /* Remove window from window manager. */ + ret = wm_local->funcs->RemoveWindow( stack, wm_local->data, + stack->stack_data, window, window->window_data ); + + /* Deallocate shared stack data. */ + if (window->window_data) + SHFREE( wm_shared->shmpool, window->window_data ); + + return ret; +} + +/** + * Let the wm set a property on a window + */ +DFBResult +dfb_wm_set_window_property( CoreWindowStack *stack, + CoreWindow *window, + const char *key, + void *value, + void **ret_old_value ) +{ + D_ASSERT( wm_local != NULL ); + D_ASSERT( wm_local->funcs != NULL ); + D_ASSERT( wm_local->funcs->SetWindowProperty != NULL ); + + D_MAGIC_ASSERT( stack, CoreWindowStack ); + D_ASSERT( stack->flags & CWSF_INITIALIZED ); + + D_MAGIC_ASSERT( stack->context, CoreLayerContext ); + FUSION_SKIRMISH_ASSERT( &stack->context->lock ); + + D_ASSERT( window != NULL ); + D_ASSERT( key != NULL ); + + D_DEBUG_AT( Core_WM, "%s( %p, %p [%d,%d-%dx%d], '%s' = %p )\n", __FUNCTION__, + stack, window, DFB_RECTANGLE_VALS(&window->config.bounds), key, value ); + + return wm_local->funcs->SetWindowProperty( stack, wm_local->data, stack->stack_data, + window, window->window_data, + key, value, ret_old_value ); +} + +/** + * get the wm property on a window + */ +DFBResult +dfb_wm_get_window_property( CoreWindowStack *stack, + CoreWindow *window, + const char *key, + void **ret_value ) +{ + D_ASSERT( wm_local != NULL ); + D_ASSERT( wm_local->funcs != NULL ); + D_ASSERT( wm_local->funcs->GetWindowProperty != NULL ); + + D_MAGIC_ASSERT( stack, CoreWindowStack ); + D_ASSERT( stack->flags & CWSF_INITIALIZED ); + + D_MAGIC_ASSERT( stack->context, CoreLayerContext ); + FUSION_SKIRMISH_ASSERT( &stack->context->lock ); + + D_ASSERT( window != NULL ); + D_ASSERT( key != NULL ); + + D_DEBUG_AT( Core_WM, "%s( %p, %p [%d,%d-%dx%d], '%s' )\n", __FUNCTION__, + stack, window, DFB_RECTANGLE_VALS(&window->config.bounds), key ); + + return wm_local->funcs->GetWindowProperty( stack, wm_local->data, stack->stack_data, + window, window->window_data, key, ret_value ); +} + +/** + * remove th wm property on a window + */ +DFBResult +dfb_wm_remove_window_property( CoreWindowStack *stack, + CoreWindow *window, + const char *key, + void **ret_value ) +{ + D_ASSERT( wm_local != NULL ); + D_ASSERT( wm_local->funcs != NULL ); + D_ASSERT( wm_local->funcs->RemoveWindowProperty != NULL ); + + D_MAGIC_ASSERT( stack, CoreWindowStack ); + D_ASSERT( stack->flags & CWSF_INITIALIZED ); + + D_MAGIC_ASSERT( stack->context, CoreLayerContext ); + FUSION_SKIRMISH_ASSERT( &stack->context->lock ); + + D_ASSERT( window != NULL ); + D_ASSERT( key != NULL ); + + D_DEBUG_AT( Core_WM, "%s( %p, %p [%d,%d-%dx%d], '%s' )\n", __FUNCTION__, + stack, window, DFB_RECTANGLE_VALS(&window->config.bounds), key ); + + return wm_local->funcs->RemoveWindowProperty( stack, wm_local->data, stack->stack_data, + window, window->window_data, key, ret_value ); +} + +DFBResult +dfb_wm_set_window_config( CoreWindow *window, + const CoreWindowConfig *config, + CoreWindowConfigFlags flags ) +{ + D_ASSERT( wm_local != NULL ); + D_ASSERT( wm_local->funcs != NULL ); + D_ASSERT( wm_local->funcs->SetWindowConfig != NULL ); + + D_ASSERT( window != NULL ); + D_ASSERT( config != NULL ); + + D_MAGIC_ASSERT( window->stack, CoreWindowStack ); + D_MAGIC_ASSERT( window->stack->context, CoreLayerContext ); + FUSION_SKIRMISH_ASSERT( &window->stack->context->lock ); + + D_DEBUG_AT( Core_WM, "%s( %p [%d,%d-%dx%d], %p, 0x%x )\n", __FUNCTION__, + window, DFB_RECTANGLE_VALS(&window->config.bounds), config, flags ); + + return wm_local->funcs->SetWindowConfig( window, wm_local->data, + window->window_data, config, flags ); +} + +DFBResult +dfb_wm_restack_window( CoreWindow *window, + CoreWindow *relative, + int relation ) +{ + D_ASSERT( wm_local != NULL ); + D_ASSERT( wm_local->funcs != NULL ); + D_ASSERT( wm_local->funcs->RestackWindow != NULL ); + + D_ASSERT( window != NULL ); + + D_MAGIC_ASSERT( window->stack, CoreWindowStack ); + D_MAGIC_ASSERT( window->stack->context, CoreLayerContext ); + FUSION_SKIRMISH_ASSERT( &window->stack->context->lock ); + + D_ASSERT( relative == NULL || relative == window || relation != 0); + + D_DEBUG_AT( Core_WM, "%s( %p [%d,%d-%dx%d], %p, %d )\n", __FUNCTION__, + window, DFB_RECTANGLE_VALS(&window->config.bounds), relative, relation ); + + return wm_local->funcs->RestackWindow( window, wm_local->data, window->window_data, relative, + relative ? relative->window_data : NULL, relation ); +} + +DFBResult +dfb_wm_grab( CoreWindow *window, + CoreWMGrab *grab ) +{ + D_ASSERT( wm_local != NULL ); + D_ASSERT( wm_local->funcs != NULL ); + D_ASSERT( wm_local->funcs->Grab != NULL ); + + D_ASSERT( window != NULL ); + + D_MAGIC_ASSERT( window->stack, CoreWindowStack ); + D_MAGIC_ASSERT( window->stack->context, CoreLayerContext ); + FUSION_SKIRMISH_ASSERT( &window->stack->context->lock ); + + D_ASSERT( grab != NULL ); + + D_DEBUG_AT( Core_WM, "%s( %p [%d,%d-%dx%d], %d )\n", __FUNCTION__, + window, DFB_RECTANGLE_VALS(&window->config.bounds), grab->target ); + + return wm_local->funcs->Grab( window, wm_local->data, window->window_data, grab ); +} + +DFBResult +dfb_wm_ungrab( CoreWindow *window, + CoreWMGrab *grab ) +{ + D_ASSERT( wm_local != NULL ); + D_ASSERT( wm_local->funcs != NULL ); + D_ASSERT( wm_local->funcs->Ungrab != NULL ); + + D_ASSERT( window != NULL ); + + D_MAGIC_ASSERT( window->stack, CoreWindowStack ); + D_MAGIC_ASSERT( window->stack->context, CoreLayerContext ); + FUSION_SKIRMISH_ASSERT( &window->stack->context->lock ); + + D_ASSERT( grab != NULL ); + + D_DEBUG_AT( Core_WM, "%s( %p [%d,%d-%dx%d], %d )\n", __FUNCTION__, + window, DFB_RECTANGLE_VALS(&window->config.bounds), grab->target ); + + return wm_local->funcs->Ungrab( window, wm_local->data, window->window_data, grab ); +} + +DFBResult +dfb_wm_request_focus( CoreWindow *window ) +{ + D_ASSERT( wm_local != NULL ); + D_ASSERT( wm_local->funcs != NULL ); + D_ASSERT( wm_local->funcs->RequestFocus != NULL ); + + D_ASSERT( window != NULL ); + + D_MAGIC_ASSERT( window->stack, CoreWindowStack ); + D_MAGIC_ASSERT( window->stack->context, CoreLayerContext ); + FUSION_SKIRMISH_ASSERT( &window->stack->context->lock ); + + D_DEBUG_AT( Core_WM, "%s( %p [%d,%d-%dx%d] )\n", __FUNCTION__, + window, DFB_RECTANGLE_VALS(&window->config.bounds) ); + + return wm_local->funcs->RequestFocus( window, wm_local->data, window->window_data ); +} + +DFBResult +dfb_wm_begin_updates( CoreWindow *window, + const DFBRegion *update ) +{ + D_ASSERT( wm_local != NULL ); + D_ASSERT( wm_local->funcs != NULL ); + D_ASSERT( wm_local->funcs->RequestFocus != NULL ); + + D_ASSERT( window != NULL ); + + D_MAGIC_ASSERT( window->stack, CoreWindowStack ); + D_MAGIC_ASSERT( window->stack->context, CoreLayerContext ); + FUSION_SKIRMISH_ASSERT( &window->stack->context->lock ); + + D_DEBUG_AT( Core_WM, "%s( %p [%d,%d-%dx%d] )\n", __FUNCTION__, + window, DFB_RECTANGLE_VALS(&window->config.bounds) ); + + return wm_local->funcs->BeginUpdates( window, wm_local->data, window->window_data, update ); +} + +DFBResult +dfb_wm_set_cursor_position( CoreWindow *window, + int x, + int y ) +{ + D_ASSERT( wm_local != NULL ); + D_ASSERT( wm_local->funcs != NULL ); + D_ASSERT( wm_local->funcs->SetCursorPosition != NULL ); + + D_ASSERT( window != NULL ); + + D_MAGIC_ASSERT( window->stack, CoreWindowStack ); + D_MAGIC_ASSERT( window->stack->context, CoreLayerContext ); + FUSION_SKIRMISH_ASSERT( &window->stack->context->lock ); + + D_DEBUG_AT( Core_WM, "%s( %p [%d,%d] )\n", __FUNCTION__, window, x, y ); + + return wm_local->funcs->SetCursorPosition( window, wm_local->data, window->window_data, x, y ); +} + +DFBResult +dfb_wm_update_stack( CoreWindowStack *stack, + const DFBRegion *region, + DFBSurfaceFlipFlags flags ) +{ + D_ASSERT( wm_local != NULL ); + D_ASSERT( wm_local->funcs != NULL ); + D_ASSERT( wm_local->funcs->UpdateStack != NULL ); + + D_MAGIC_ASSERT( stack, CoreWindowStack ); + D_ASSERT( stack->flags & CWSF_INITIALIZED ); + + D_MAGIC_ASSERT( stack->context, CoreLayerContext ); + FUSION_SKIRMISH_ASSERT( &stack->context->lock ); + + DFB_REGION_ASSERT( region ); + + D_DEBUG_AT( Core_WM, "%s( %p, [%d,%d-%dx%d], 0x%x )\n", __FUNCTION__, + stack, DFB_RECTANGLE_VALS_FROM_REGION(region), flags ); + + return wm_local->funcs->UpdateStack( stack, wm_local->data, + stack->stack_data, region, flags ); +} + +DFBResult +dfb_wm_update_window( CoreWindow *window, + const DFBRegion *region, + DFBSurfaceFlipFlags flags ) +{ + D_ASSERT( wm_local != NULL ); + D_ASSERT( wm_local->funcs != NULL ); + D_ASSERT( wm_local->funcs->UpdateWindow != NULL ); + + D_ASSERT( window != NULL ); + + D_MAGIC_ASSERT( window->stack, CoreWindowStack ); + D_MAGIC_ASSERT( window->stack->context, CoreLayerContext ); + FUSION_SKIRMISH_ASSERT( &window->stack->context->lock ); + + DFB_REGION_ASSERT_IF( region ); + + D_DEBUG_AT( Core_WM, "%s( %p [%d,%d-%dx%d], [%d,%d-%dx%d], 0x%x )\n", __FUNCTION__, + window, DFB_RECTANGLE_VALS(&window->config.bounds), + DFB_RECTANGLE_VALS_FROM_REGION(region), flags ); + + return wm_local->funcs->UpdateWindow( window, wm_local->data, + window->window_data, region, flags ); +} + +DFBResult +dfb_wm_update_cursor( CoreWindowStack *stack, + CoreCursorUpdateFlags flags ) +{ + D_ASSERT( wm_local != NULL ); + D_ASSERT( wm_local->funcs != NULL ); + D_ASSERT( wm_local->funcs->UpdateStack != NULL ); + + D_MAGIC_ASSERT( stack, CoreWindowStack ); + D_ASSERT( stack->flags & CWSF_INITIALIZED ); + + D_MAGIC_ASSERT( stack->context, CoreLayerContext ); + FUSION_SKIRMISH_ASSERT( &stack->context->lock ); + + D_FLAGS_ASSERT( flags, CCUF_ALL ); + + if (dfb_config->no_cursor_updates) + return DFB_OK; + + return wm_local->funcs->UpdateCursor( stack, wm_local->data, + stack->stack_data, flags ); +} + diff --git a/Source/DirectFB/src/core/wm.h b/Source/DirectFB/src/core/wm.h new file mode 100755 index 0000000..eea4fd9 --- /dev/null +++ b/Source/DirectFB/src/core/wm.h @@ -0,0 +1,468 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef __DFB__CORE__WM_H__ +#define __DFB__CORE__WM_H__ + +#include +#include + +#include + +#include +#include + + +DECLARE_MODULE_DIRECTORY( dfb_core_wm_modules ); + + +/* + * Increase this number when changes result in binary incompatibility! + */ +#define DFB_CORE_WM_ABI_VERSION 9 + +#define DFB_CORE_WM_INFO_NAME_LENGTH 60 +#define DFB_CORE_WM_INFO_VENDOR_LENGTH 80 +#define DFB_CORE_WM_INFO_URL_LENGTH 120 +#define DFB_CORE_WM_INFO_LICENSE_LENGTH 40 + + +typedef struct { + int major; + int minor; + + int binary; +} CoreWMVersion; + +typedef struct { + CoreWMVersion version; + + char name [DFB_CORE_WM_INFO_NAME_LENGTH]; + char vendor [DFB_CORE_WM_INFO_VENDOR_LENGTH]; + char url [DFB_CORE_WM_INFO_URL_LENGTH]; + char license[DFB_CORE_WM_INFO_LICENSE_LENGTH]; + + unsigned int wm_data_size; + unsigned int wm_shared_size; + unsigned int stack_data_size; + unsigned int window_data_size; +} CoreWMInfo; + +typedef struct { + CoreWMGrabTarget target; + + /* Both for CWMGT_KEY only. */ + DFBInputDeviceKeySymbol symbol; + DFBInputDeviceModifierMask modifiers; +} CoreWMGrab; + +/* FIXME: move to cursor.h when it's there */ +typedef enum { + CCUF_NONE = 0x00000000, + + CCUF_ENABLE = 0x00000001, + CCUF_DISABLE = 0x00000002, + + CCUF_POSITION = 0x00000010, + CCUF_SIZE = 0x00000020, + CCUF_SHAPE = 0x00000040, + CCUF_OPACITY = 0x00000080, + + CCUF_ALL = 0x000000F3 +} CoreCursorUpdateFlags; + +typedef DFBEnumerationResult (*CoreWMWindowCallback) (CoreWindow *window, + void *ctx); + +typedef struct { + + /** Module **/ + + void (*GetWMInfo) ( CoreWMInfo *info ); + + DFBResult (*Initialize) ( CoreDFB *core, + void *wm_data, + void *shared_data ); + + DFBResult (*Join) ( CoreDFB *core, + void *wm_data, + void *shared_data ); + + DFBResult (*Shutdown) ( bool emergency, + void *wm_data, + void *shared_data ); + + DFBResult (*Leave) ( bool emergency, + void *wm_data, + void *shared_data ); + + DFBResult (*Suspend) ( void *wm_data, + void *shared_data ); + + DFBResult (*Resume) ( void *wm_data, + void *shared_data ); + + DFBResult (*PostInit) ( void *wm_data, + void *shared_data ); + + + /** Stack **/ + + DFBResult (*InitStack) ( CoreWindowStack *stack, + void *wm_data, + void *stack_data ); + + DFBResult (*CloseStack) ( CoreWindowStack *stack, + void *wm_data, + void *stack_data ); + + DFBResult (*SetActive) ( CoreWindowStack *stack, + void *wm_data, + void *stack_data, + bool active ); + + DFBResult (*ResizeStack) ( CoreWindowStack *stack, + void *wm_data, + void *stack_data, + int width, + int height ); + + DFBResult (*ProcessInput) ( CoreWindowStack *stack, + void *wm_data, + void *stack_data, + const DFBInputEvent *event ); + + DFBResult (*FlushKeys) ( CoreWindowStack *stack, + void *wm_data, + void *stack_data ); + + DFBResult (*WindowAt) ( CoreWindowStack *stack, + void *wm_data, + void *stack_data, + int x, + int y, + CoreWindow **ret_window ); + + DFBResult (*WindowLookup) ( CoreWindowStack *stack, + void *wm_data, + void *stack_data, + DFBWindowID window_id, + CoreWindow **ret_window ); + + DFBResult (*EnumWindows) ( CoreWindowStack *stack, + void *wm_data, + void *stack_data, + CoreWMWindowCallback callback, + void *callback_ctx ); + + + /** Window **/ + DFBResult (*SetWindowProperty)( CoreWindowStack *stack, + void *wm_data, + void *stack_data, + CoreWindow *window, + void *window_data, + const char *key, + void *value, + void **old_value ); + + DFBResult (*GetWindowProperty)( CoreWindowStack *stack, + void *wm_data, + void *stack_data, + CoreWindow *window, + void *window_data, + const char *key, + void **value); + + DFBResult (*RemoveWindowProperty)( CoreWindowStack *stack, + void *wm_data, + void *stack_data, + CoreWindow *window, + void *window_data, + const char *key, + void **value ); + + DFBResult (*GetInsets) ( CoreWindowStack *stack, + CoreWindow *window, + DFBInsets *insets ); + + DFBResult (*PreConfigureWindow)( CoreWindowStack *stack, + void *wm_data, + void *stack_data, + CoreWindow *window, + void *window_data ); + + DFBResult (*AddWindow) ( CoreWindowStack *stack, + void *wm_data, + void *stack_data, + CoreWindow *window, + void *window_data ); + + DFBResult (*RemoveWindow) ( CoreWindowStack *stack, + void *wm_data, + void *stack_data, + CoreWindow *window, + void *window_data ); + + DFBResult (*SetWindowConfig) ( CoreWindow *window, + void *wm_data, + void *window_data, + const CoreWindowConfig *config, + CoreWindowConfigFlags flags ); + + DFBResult (*RestackWindow) ( CoreWindow *window, + void *wm_data, + void *window_data, + CoreWindow *relative, + void *relative_data, + int relation ); + + DFBResult (*Grab) ( CoreWindow *window, + void *wm_data, + void *window_data, + CoreWMGrab *grab ); + + DFBResult (*Ungrab) ( CoreWindow *window, + void *wm_data, + void *window_data, + CoreWMGrab *grab ); + + DFBResult (*RequestFocus) ( CoreWindow *window, + void *wm_data, + void *window_data ); + + DFBResult (*BeginUpdates) ( CoreWindow *window, + void *wm_data, + void *window_data, + const DFBRegion *update ); + + DFBResult (*SetCursorPosition) ( CoreWindow *window, + void *wm_data, + void *window_data, + int x, + int y ); + + + /** Updates **/ + + DFBResult (*UpdateStack) ( CoreWindowStack *stack, + void *wm_data, + void *stack_data, + const DFBRegion *region, + DFBSurfaceFlipFlags flags ); + + DFBResult (*UpdateWindow) ( CoreWindow *window, + void *wm_data, + void *window_data, + const DFBRegion *region, + DFBSurfaceFlipFlags flags ); + + DFBResult (*UpdateCursor) ( CoreWindowStack *stack, + void *wm_data, + void *stack_data, + CoreCursorUpdateFlags flags ); +} CoreWMFuncs; + + + +typedef enum { + CORE_WM_WINDOW_ADD = 1, + CORE_WM_WINDOW_REMOVE = 2, + CORE_WM_WINDOW_CONFIG = 3, + CORE_WM_WINDOW_STATE = 4, + CORE_WM_WINDOW_RESTACK = 5, + CORE_WM_WINDOW_FOCUS = 6, + + _CORE_WM_NUM_CHANNELS +} CoreWMChannels; + +typedef struct { + DFBWindowInfo info; +} CoreWM_WindowAdd; + +typedef struct { + DFBWindowID window_id; +} CoreWM_WindowRemove; + +typedef struct { + DFBWindowID window_id; + DFBWindowConfig config; + DFBWindowConfigFlags flags; +} CoreWM_WindowConfig; + +typedef struct { + DFBWindowID window_id; + DFBWindowState state; +} CoreWM_WindowState; + +typedef struct { + DFBWindowID window_id; + unsigned int index; +} CoreWM_WindowRestack; + +typedef struct { + DFBWindowID window_id; +} CoreWM_WindowFocus; + + +DFBResult dfb_wm_attach ( CoreDFB *core, + int channel, + ReactionFunc func, + void *ctx, + Reaction *reaction ); + +DFBResult dfb_wm_detach ( CoreDFB *core, + Reaction *reaction ); + +DFBResult dfb_wm_dispatch( CoreDFB *core, + int channel, + const void *data, + int size ); + + +DFBResult dfb_wm_dispatch_WindowAdd ( CoreDFB *core, + CoreWindow *window ); + +DFBResult dfb_wm_dispatch_WindowRemove ( CoreDFB *core, + CoreWindow *window ); + +DFBResult dfb_wm_dispatch_WindowConfig ( CoreDFB *core, + CoreWindow *window, + DFBWindowConfigFlags flags ); + +DFBResult dfb_wm_dispatch_WindowState ( CoreDFB *core, + CoreWindow *window ); + +DFBResult dfb_wm_dispatch_WindowRestack( CoreDFB *core, + CoreWindow *window, + unsigned int index ); + +DFBResult dfb_wm_dispatch_WindowFocus ( CoreDFB *core, + CoreWindow *window ); + + + +void dfb_wm_get_info( CoreWMInfo *info ); + +DFBResult dfb_wm_post_init ( CoreDFB *core ); + +DFBResult dfb_wm_init_stack ( CoreWindowStack *stack ); + +DFBResult dfb_wm_close_stack ( CoreWindowStack *stack ); + +DFBResult dfb_wm_set_active ( CoreWindowStack *stack, + bool active ); + +DFBResult dfb_wm_resize_stack ( CoreWindowStack *stack, + int width, + int height ); + +DFBResult dfb_wm_process_input ( CoreWindowStack *stack, + const DFBInputEvent *event ); + +DFBResult dfb_wm_flush_keys ( CoreWindowStack *stack ); + +DFBResult dfb_wm_window_at ( CoreWindowStack *stack, + int x, + int y, + CoreWindow **ret_window ); + +DFBResult dfb_wm_window_lookup ( CoreWindowStack *stack, + DFBWindowID window_id, + CoreWindow **ret_window ); + +DFBResult dfb_wm_enum_windows ( CoreWindowStack *stack, + CoreWMWindowCallback callback, + void *callback_ctx ); + +DFBResult dfb_wm_get_insets ( CoreWindowStack *stack, + CoreWindow *window, + DFBInsets *insets ); + +DFBResult dfb_wm_set_window_property ( CoreWindowStack *stack, + CoreWindow *window, + const char *key, + void *value, + void **ret_old_value ); + +DFBResult dfb_wm_get_window_property ( CoreWindowStack *stack, + CoreWindow *window, + const char *key, + void **ret_value ); + +DFBResult dfb_wm_remove_window_property ( CoreWindowStack *stack, + CoreWindow *window, + const char *key, + void **ret_value ); + +DFBResult dfb_wm_preconfigure_window ( CoreWindowStack *stack, + CoreWindow *window ); + + +DFBResult dfb_wm_add_window ( CoreWindowStack *stack, + CoreWindow *window ); + +DFBResult dfb_wm_remove_window ( CoreWindowStack *stack, + CoreWindow *window ); + +DFBResult dfb_wm_set_window_config ( CoreWindow *window, + const CoreWindowConfig *config, + CoreWindowConfigFlags flags ); + +DFBResult dfb_wm_restack_window ( CoreWindow *window, + CoreWindow *relative, + int relation ); + +DFBResult dfb_wm_grab ( CoreWindow *window, + CoreWMGrab *grab ); + +DFBResult dfb_wm_ungrab ( CoreWindow *window, + CoreWMGrab *grab ); + +DFBResult dfb_wm_request_focus ( CoreWindow *window ); + +DFBResult dfb_wm_begin_updates ( CoreWindow *window, + const DFBRegion *update ); + +DFBResult dfb_wm_set_cursor_position( CoreWindow *window, + int x, + int y ); + + +DFBResult dfb_wm_update_stack ( CoreWindowStack *stack, + const DFBRegion *region, + DFBSurfaceFlipFlags flags ); + +DFBResult dfb_wm_update_window ( CoreWindow *window, + const DFBRegion *region, + DFBSurfaceFlipFlags flags ); + +DFBResult dfb_wm_update_cursor ( CoreWindowStack *stack, + CoreCursorUpdateFlags flags ); + +#endif diff --git a/Source/DirectFB/src/core/wm_module.h b/Source/DirectFB/src/core/wm_module.h new file mode 100755 index 0000000..b470ebd --- /dev/null +++ b/Source/DirectFB/src/core/wm_module.h @@ -0,0 +1,274 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef __DFB__CORE__WM_MODULE_H__ +#define __DFB__CORE__WM_MODULE_H__ + +#include + + +/** Module **/ + +static void wm_get_info ( CoreWMInfo *info ); + +static DFBResult wm_initialize ( CoreDFB *core, + void *wm_data, + void *shared_data ); + +static DFBResult wm_join ( CoreDFB *core, + void *wm_data, + void *shared_data ); + +static DFBResult wm_shutdown ( bool emergency, + void *wm_data, + void *shared_data ); + +static DFBResult wm_leave ( bool emergency, + void *wm_data, + void *shared_data ); + +static DFBResult wm_suspend ( void *wm_data, + void *shared_data ); + +static DFBResult wm_resume ( void *wm_data, + void *shared_data ); + +static DFBResult wm_post_init ( void *wm_data, + void *shared_data ); + + +/** Stack **/ + +static DFBResult wm_init_stack ( CoreWindowStack *stack, + void *wm_data, + void *stack_data ); + +static DFBResult wm_close_stack ( CoreWindowStack *stack, + void *wm_data, + void *stack_data ); + +static DFBResult wm_set_active ( CoreWindowStack *stack, + void *wm_data, + void *stack_data, + bool active ); + +static DFBResult wm_resize_stack ( CoreWindowStack *stack, + void *wm_data, + void *stack_data, + int width, + int height ); + +static DFBResult wm_process_input ( CoreWindowStack *stack, + void *wm_data, + void *stack_data, + const DFBInputEvent *event ); + +static DFBResult wm_flush_keys ( CoreWindowStack *stack, + void *wm_data, + void *stack_data ); + +static DFBResult wm_window_at ( CoreWindowStack *stack, + void *wm_data, + void *stack_data, + int x, + int y, + CoreWindow **ret_window ); + +static DFBResult wm_window_lookup ( CoreWindowStack *stack, + void *wm_data, + void *stack_data, + DFBWindowID window_id, + CoreWindow **ret_window ); + +static DFBResult wm_enum_windows ( CoreWindowStack *stack, + void *wm_data, + void *stack_data, + CoreWMWindowCallback callback, + void *callback_ctx ); + +/** Window **/ +static DFBResult wm_get_insets ( CoreWindowStack *stack, + CoreWindow *window, + DFBInsets *insets ); + +static DFBResult wm_preconfigure_window ( CoreWindowStack *stack, + void *wm_data, + void *stack_data, + CoreWindow *window, + void *window_data ); + +static DFBResult wm_set_window_property( CoreWindowStack *stack, + void *wm_data, + void *stack_data, + CoreWindow *window, + void *window_data, + const char *key, + void *value, + void **ret_old_value ); + +static DFBResult wm_get_window_property( CoreWindowStack *stack, + void *wm_data, + void *stack_data, + CoreWindow *window, + void *window_data, + const char *key, + void **ret_value ); + +static DFBResult wm_remove_window_property( CoreWindowStack *stack, + void *wm_data, + void *stack_data, + CoreWindow *window, + void *window_data, + const char *key, + void **ret_value ); + +static DFBResult wm_add_window ( CoreWindowStack *stack, + void *wm_data, + void *stack_data, + CoreWindow *window, + void *window_data ); + +static DFBResult wm_remove_window ( CoreWindowStack *stack, + void *wm_data, + void *stack_data, + CoreWindow *window, + void *window_data ); + +static DFBResult wm_set_window_config( CoreWindow *window, + void *wm_data, + void *window_data, + const CoreWindowConfig *config, + CoreWindowConfigFlags flags ); + +static DFBResult wm_restack_window ( CoreWindow *window, + void *wm_data, + void *window_data, + CoreWindow *relative, + void *relative_data, + int relation ); + +static DFBResult wm_grab ( CoreWindow *window, + void *wm_data, + void *window_data, + CoreWMGrab *grab ); + +static DFBResult wm_ungrab ( CoreWindow *window, + void *wm_data, + void *window_data, + CoreWMGrab *grab ); + +static DFBResult wm_request_focus ( CoreWindow *window, + void *wm_data, + void *window_data ); + +static DFBResult wm_begin_updates ( CoreWindow *window, + void *wm_data, + void *window_data, + const DFBRegion *update ); + +static DFBResult wm_set_cursor_position( CoreWindow *window, + void *wm_data, + void *window_data, + int x, + int y ); + +/** Updates **/ + +static DFBResult wm_update_stack ( CoreWindowStack *stack, + void *wm_data, + void *stack_data, + const DFBRegion *region, + DFBSurfaceFlipFlags flags ); + +static DFBResult wm_update_window ( CoreWindow *window, + void *wm_data, + void *window_data, + const DFBRegion *region, + DFBSurfaceFlipFlags flags ); + +static DFBResult wm_update_cursor ( CoreWindowStack *stack, + void *wm_data, + void *stack_data, + CoreCursorUpdateFlags flags ); + + +static CoreWMFuncs wm_funcs = { + .GetWMInfo = wm_get_info, + + .Initialize = wm_initialize, + .Join = wm_join, + .Shutdown = wm_shutdown, + .Leave = wm_leave, + .Suspend = wm_suspend, + .Resume = wm_resume, + .PostInit = wm_post_init, + + .InitStack = wm_init_stack, + .CloseStack = wm_close_stack, + .SetActive = wm_set_active, + .ResizeStack = wm_resize_stack, + .ProcessInput = wm_process_input, + .FlushKeys = wm_flush_keys, + .WindowAt = wm_window_at, + .WindowLookup = wm_window_lookup, + .EnumWindows = wm_enum_windows, + + .GetInsets = wm_get_insets, + .PreConfigureWindow = wm_preconfigure_window, + .SetWindowProperty = wm_set_window_property, + .GetWindowProperty = wm_get_window_property, + .RemoveWindowProperty = wm_remove_window_property, + .AddWindow = wm_add_window, + .RemoveWindow = wm_remove_window, + .SetWindowConfig = wm_set_window_config, + .RestackWindow = wm_restack_window, + .Grab = wm_grab, + .Ungrab = wm_ungrab, + .RequestFocus = wm_request_focus, + .BeginUpdates = wm_begin_updates, + .SetCursorPosition = wm_set_cursor_position, + + .UpdateStack = wm_update_stack, + .UpdateWindow = wm_update_window, + .UpdateCursor = wm_update_cursor +}; + + +#define DFB_WINDOW_MANAGER(shortname) \ +__attribute__((constructor)) void directfbwm_##shortname( void ); \ + \ +void \ +directfbwm_##shortname( void ) \ +{ \ + direct_modules_register( &dfb_core_wm_modules, \ + DFB_CORE_WM_ABI_VERSION, \ + #shortname, &wm_funcs ); \ +} + +#endif + -- cgit