<commit_before>/*
   (c) Copyright 2001-2010  The world wide DirectFB Open Source Community (directfb.org)
   (c) Copyright 2000-2004  Convergence (integrated media) GmbH

   All rights reserved.

   Written by <NAME> <<EMAIL>>,
              <NAME> <<EMAIL>>,
              <NAME> <<EMAIL>>,
              <NAME> <<EMAIL>> and
              <NAME> <<EMAIL>>.

   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 <config.h>

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <string.h>

#include <directfb.h>
#include <directfb_version.h>

#include <core/core.h>

#include <core/CoreDFB.h>
#include <core/CoreLayer.h>
#include <core/CoreLayerContext.h>
#include <core/CoreLayerRegion.h>
#include <core/CorePalette.h>
#include <core/CoreScreen.h>
#include <core/CoreSurface.h>
#include <core/CoreWindow.h>
#include <core/CoreWindowStack.h>

#include <core/clipboard.h>
#include <core/state.h>
#include <core/gfxcard.h>
#include <core/input.h>
#include <core/layer_context.h>
#include <core/layer_control.h>
#include <core/layer_region.h>
#include <core/layers.h>
#include <core/layers_internal.h>
#include <core/palette.h>
#include <core/screen.h>
#include <core/screens.h>
#include <core/surface.h>
#include <core/surface_pool.h>
#include <core/system.h>
#include <core/windows.h>
#include <core/windows_internal.h> /* FIXME */
#include <core/windowstack.h>

#include <display/idirectfbpalette.h>
#include <display/idirectfbscreen.h>
#include <display/idirectfbsurface.h>
#include <display/idirectfbsurface_layer.h>
#include <display/idirectfbsurface_window.h>
#include <display/idirectfbdisplaylayer.h>
#include <input/idirectfbinputbuffer.h>
#include <input/idirectfbinputdevice.h>
#include <media/idirectfbfont.h>
#include <media/idirectfbimageprovider.h>
#include <media/idirectfbvideoprovider.h>
#include <media/idirectfbdatabuffer.h>

#include <idirectfb.h>

#include <gfx/convert.h>

#include <misc/conf.h>

#include <direct/direct.h>
#include <direct/interface.h>
#include <direct/mem.h>
#include <direct/memcpy.h>
#include <direct/messages.h>
#include <direct/util.h>

#include <misc/util.h>

D_DEBUG_DOMAIN( IDFB, "IDirectFB", "DirectFB Main Interface" );

/**********************************************************************************************************************/

typedef struct {
     DFBScreenCallback  callback;
     void              *callback_ctx;
} EnumScreens_Context;

typedef struct {
     IDirectFBScreen **interface;
     DFBScreenID       id;
     DFBResult         ret;
} GetScreen_Context;

typedef struct {
     DFBDisplayLayerCallback  callback;
     void                    *callback_ctx;
} EnumDisplayLayers_Context;

typedef struct {
     IDirectFBDisplayLayer **interface;
     DFBDisplayLayerID       id;
     DFBResult               ret;
     CoreDFB                *core;
     IDirectFB              *idirectfb;
} GetDisplayLayer_Context;

typedef struct {
     DFBInputDeviceCallback  callback;
     void                   *callback_ctx;
} EnumInputDevices_Context;

typedef struct {
     IDirectFBInputDevice **interface;
     DFBInputDeviceID       id;
     DFBResult              ret;
} GetInputDevice_Context;

typedef struct {
     IDirectFBEventBuffer       **interface;
     DFBInputDeviceCapabilities   caps;
} CreateEventBuffer_Context;

/**********************************************************************************************************************/

static DFBEnumerationResult EnumScreens_Callback      ( CoreScreen  *screen,
                                                        void        *ctx );
static DFBEnumerationResult GetScreen_Callback        ( CoreScreen  *screen,
                                                        void        *ctx );

static DFBEnumerationResult EnumDisplayLayers_Callback( CoreLayer   *layer,
                                                        void        *ctx );
static DFBEnumerationResult GetDisplayLayer_Callback  ( CoreLayer   *layer,
                                                        void        *ctx );

static DFBEnumerationResult EnumInputDevices_Callback ( CoreInputDevice *device,
                                                        void            *ctx );
static DFBEnumerationResult GetInputDevice_Callback   ( CoreInputDevice *device,
                                                        void            *ctx );

static DFBEnumerationResult CreateEventBuffer_Callback( CoreInputDevice *device,
                                                        void            *ctx );

static ReactionResult focus_listener( const void *msg_data,
                                      void       *ctx );

static bool input_filter_local( DFBEvent *evt,
                                void     *ctx );

static bool input_filter_global( DFBEvent *evt,
                                 void     *ctx );

static void drop_window( IDirectFB_data *data, bool enable_cursor );

/**********************************************************************************************************************/

/* The containers_XXXX function family will maintain the connections between
 * event buffers created by IDirectFB::CreateInputEventBuffer and input
 * devices that are hot-plugged in.
 */

static  DirectLink      *containers      = NULL;
static  pthread_mutex_t  containers_lock = PTHREAD_MUTEX_INITIALIZER;

typedef struct {
     DirectLink                  link;
     DFBInputDeviceCapabilities  caps;
     IDirectFBEventBuffer       *iface;

} Event_Buffer_Container;

void
containers_attach_device(CoreInputDevice *device)
{
     Event_Buffer_Container  *container;
     DFBInputDeviceCapabilities dev_caps;

     D_ASSERT( device != NULL );

     dev_caps = dfb_input_device_caps(device);

     pthread_mutex_lock( &containers_lock );

     direct_list_foreach(container, containers) {
          if (dev_caps & container->caps) {
               IDirectFBEventBuffer_AttachInputDevice( container->iface, device );
          }
     }

     pthread_mutex_unlock( &containers_lock );
}

void
containers_detach_device(CoreInputDevice *device)
{
     Event_Buffer_Container  *container;

     pthread_mutex_lock( &containers_lock );

     direct_list_foreach(container, containers) {
          IDirectFBEventBuffer_DetachInputDevice(container->iface, device);
     }

     pthread_mutex_unlock( &containers_lock );
}

static void
containers_add_input_eventbuffer(CreateEventBuffer_Context * context)
{
     Event_Buffer_Container  *container;

     pthread_mutex_lock( &containers_lock );

     container = D_CALLOC(1, sizeof(Event_Buffer_Container));
     if (!container) {
          D_OOM();
          D_ERROR( "Can not allocate memory! in %s\n", __FUNCTION__ );
     }
     container->caps = context->caps;
     container->iface = *context->interface;

     direct_list_append(&containers, &container->link);

     pthread_mutex_unlock( &containers_lock );
}

void
containers_remove_input_eventbuffer(IDirectFBEventBuffer  *thiz)
{
     Event_Buffer_Container  *container = NULL;

     pthread_mutex_lock( &containers_lock );

     direct_list_foreach(container, containers) {
          if (thiz == container->iface) {
               direct_list_remove(&containers, &container->link);
               D_FREE(container);
          }
     }

     pthread_mutex_unlock( &containers_lock );
}

/**********************************************************************************************************************/

/*
 * Destructor
 *
 * Free data structure and set the pointer to NULL,
 * to indicate the dead interface.
 */
void
IDirectFB_Destruct( IDirectFB *thiz )
{
     int             i;
     IDirectFB_data *data = (IDirectFB_data*)thiz->priv;

     D_DEBUG_AT( IDFB, "%s( %p )\n", __FUNCTION__, thiz );

     drop_window( data, false );

     if (data->primary.context)
          dfb_layer_context_unref( data->primary.context );

     dfb_layer_context_unref( data->context );

     for (i=0; i<MAX_LAYERS; i++) {
          if (data->layers[i].context) {
               if (data->layers[i].palette)
                    dfb_palette_unref( data->layers[i].palette );

               dfb_surface_unref( data->layers[i].surface );
               dfb_layer_region_unref( data->layers[i].region );
               dfb_layer_context_unref( data->layers[i].context );
          }
     }

     dfb_core_destroy( data->core, false );

     DIRECT_DEALLOCATE_INTERFACE( thiz );

     direct_shutdown();

     if (thiz == idirectfb_singleton)
          idirectfb_singleton = NULL;
}


static DirectResult
IDirectFB_AddRef( IDirectFB *thiz )
{
     DIRECT_INTERFACE_GET_DATA(IDirectFB)

     D_DEBUG_AT( IDFB, "%s( %p )\n", __FUNCTION__, thiz );

     data->ref++;

     return DFB_OK;
}

static DirectResult
IDirectFB_Release( IDirectFB *thiz )
{
     DIRECT_INTERFACE_GET_DATA(IDirectFB)

     D_DEBUG_AT( IDFB, "%s( %p )\n", __FUNCTION__, thiz );

     if (--data->ref == 0)
          IDirectFB_Destruct( thiz );

     return DFB_OK;
}

static DFBResult
IDirectFB_SetCooperativeLevel( IDirectFB           *thiz,
                               DFBCooperativeLevel  level )
{
     DFBResult         ret;
     CoreLayerContext *context;

     DIRECT_INTERFACE_GET_DATA(IDirectFB)

     D_DEBUG_AT( IDFB, "%s( %p, %d )\n", __FUNCTION__, thiz, level );

     if (level == data->level)
          return DFB_OK;

     switch (level) {
          case DFSCL_NORMAL:
               data->primary.focused = false;

               dfb_layer_context_unref( data->primary.context );

               data->primary.context = NULL;
               break;

          case DFSCL_FULLSCREEN:
          case DFSCL_EXCLUSIVE:
               if (dfb_config->primary_id)
                    return DFB_ACCESSDENIED;

               if (dfb_config->force_windowed || dfb_config->force_desktop)
                    return DFB_ACCESSDENIED;

               if (data->level == DFSCL_NORMAL) {
                    ret = CoreLayer_CreateContext( data->layer, &context );
                    if (ret)
                         return ret;

                    ret = CoreLayer_ActivateContext( data->layer, context );
                    if (ret) {
                         dfb_layer_context_unref( context );
                         return ret;
                    }

                    drop_window( data, true );

                    data->primary.context = context;
               }

               data->primary.focused = true;
               break;

          default:
               return DFB_INVARG;
     }

     data->level = level;

     return DFB_OK;
}

static DFBResult
IDirectFB_GetDeviceDescription( IDirectFB                    *thiz,
                                DFBGraphicsDeviceDescription *ret_desc )
{
     GraphicsDeviceInfo device_info;
     GraphicsDriverInfo driver_info;

     DIRECT_INTERFACE_GET_DATA(IDirectFB)

     D_DEBUG_AT( IDFB, "%s( %p )\n", __FUNCTION__, thiz );

     if (!ret_desc)
          return DFB_INVARG;

     dfb_gfxcard_get_device_info( &device_info );
     dfb_gfxcard_get_driver_info( &driver_info );

     ret_desc->acceleration_mask = device_info.caps.accel;
     ret_desc->blitting_flags    = device_info.caps.blitting;
     ret_desc->drawing_flags     = device_info.caps.drawing;
     ret_desc->video_memory      = dfb_gfxcard_memory_length();

     direct_snputs( ret_desc->name,   device_info.name,   DFB_GRAPHICS_DEVICE_DESC_NAME_LENGTH );
     direct_snputs( ret_desc->vendor, device_info.vendor, DFB_GRAPHICS_DEVICE_DESC_NAME_LENGTH );

     ret_desc->driver.major = driver_info.version.major;
     ret_desc->driver.minor = driver_info.version.minor;

     direct_snputs( ret_desc->driver.name,   driver_info.name,   DFB_GRAPHICS_DRIVER_INFO_NAME_LENGTH );
     direct_snputs( ret_desc->driver.vendor, driver_info.vendor, DFB_GRAPHICS_DRIVER_INFO_VENDOR_LENGTH );

     return DFB_OK;
}

static DFBResult
IDirectFB_EnumVideoModes( IDirectFB            *thiz,
                          DFBVideoModeCallback  callbackfunc,
                          void                 *callbackdata )
{
     VideoMode *m;

     DIRECT_INTERFACE_GET_DATA(IDirectFB)

     D_DEBUG_AT( IDFB, "%s( %p, %p, %p )\n", __FUNCTION__, thiz, callbackfunc, callbackdata );

     if (!callbackfunc)
          return DFB_INVARG;

     m = dfb_system_modes();
     while (m) {
          if (callbackfunc( m->xres, m->yres,
                            m->bpp, callbackdata ) == DFENUM_CANCEL)
               break;

          m = m->next;
     }

     return DFB_OK;
}

static DFBResult
IDirectFB_SetVideoMode( IDirectFB    *thiz,
                        int           width,
                        int           height,
                        int           bpp )
{
     DFBResult ret;
     DFBSurfacePixelFormat format;
     DFBSurfaceColorSpace colorspace;

     DIRECT_INTERFACE_GET_DATA(IDirectFB)

     D_DEBUG_AT( IDFB, "%s( %p, %dx%d %dbit )\n", __FUNCTION__, thiz, width, height, bpp );

     if (width < 1 || height < 1 || bpp < 1)
          return DFB_INVARG;

     format = dfb_pixelformat_for_depth( bpp );
     if (format == DSPF_UNKNOWN)
          return DFB_INVARG;
     colorspace = DFB_COLORSPACE_DEFAULT(format);

     switch (data->level) {
          case DFSCL_NORMAL:
               if (data->primary.window) {
                    ret = dfb_window_resize( data->primary.window, width, height );
                    if (ret)
                         return ret;
               }
               break;

          case DFSCL_FULLSCREEN:
          case DFSCL_EXCLUSIVE: {
               DFBResult ret;
               DFBDisplayLayerConfig config;

               config.flags       = DLCONF_WIDTH | DLCONF_HEIGHT |
                                    DLCONF_PIXELFORMAT;
               config.width       = width;
               config.height      = height;
               config.pixelformat = format;
               config.colorspace  = colorspace;

               ret = CoreLayerContext_SetConfiguration( data->primary.context,
                                                          &config );
               if (ret)
                    return ret;

               break;
          }
     }

     data->primary.width      = width;
     data->primary.height     = height;
     data->primary.format     = format;
     data->primary.colorspace = colorspace;

     return DFB_OK;
}

static DFBResult
init_palette( CoreSurface *surface, const DFBSurfaceDescription *desc )
{
     DFBResult    ret;
     CorePalette *palette;

     if (!(desc->flags & DSDESC_PALETTE))
          return DFB_OK;

     ret = CoreSurface_GetPalette( surface, &palette );
     if (ret)
          return ret;

     ret = CorePalette_SetEntries( palette, desc->palette.entries, MIN( desc->palette.size, palette->num_entries ), 0 );

     dfb_palette_unref( palette );

     return ret;
}

static DFBResult
IDirectFB_CreateSurface( IDirectFB                    *thiz,
                         const DFBSurfaceDescription  *desc,
                         IDirectFBSurface            **interface )
{
     IDirectFBSurface *iface;
     DFBResult ret;
     int width = 256;
     int height = 256;
     DFBSurfacePixelFormat format;
     DFBSurfaceColorSpace colorspace;
     DFBSurfaceCapabilities caps = DSCAPS_NONE;
     CoreSurface *surface = NULL;
     unsigned long resource_id = 0;
     DFBDisplayLayerConfig  config;

     DIRECT_INTERFACE_GET_DATA(IDirectFB)

     D_DEBUG_AT( IDFB, "%s( %p )\n", __FUNCTION__, thiz );

     if (data->primary.context)
          dfb_layer_context_get_configuration( data->primary.context, &config );
     else
          dfb_layer_context_get_configuration( data->context, &config );

     if (desc->flags & DSDESC_HINTS && desc->hints & DSHF_FONT) {
          format = dfb_config->font_format;
          colorspace = DFB_COLORSPACE_DEFAULT(format);

          if (dfb_config->font_premult)
               caps = DSCAPS_PREMULTIPLIED;
     }
     else {
          format = config.pixelformat;
          colorspace = config.colorspace;
     }

     if (!desc || !interface)
          return DFB_INVARG;

     D_DEBUG_AT( IDFB, "  -> flags  0x%08x\n", desc->flags );

     if (desc->flags & DSDESC_WIDTH) {
          D_DEBUG_AT( IDFB, "  -> width  %d\n", desc->width );

          width = desc->width;
          if (width < 1 || width > 20480)
               return DFB_INVARG;
     }

     if (desc->flags & DSDESC_HEIGHT) {
          D_DEBUG_AT( IDFB, "  -> height %d\n", desc->height );

          height = desc->height;
          if (height < 1 || height > 20480)
               return DFB_INVARG;
     }

     if (desc->flags & DSDESC_PALETTE) {
          D_DEBUG_AT( IDFB, "  -> PALETTE\n" );

          if (!desc->palette.entries) {
               D_DEBUG_AT( IDFB, "  -> no entries!\n" );
               return DFB_INVARG;
          }

          if (!desc->palette.size) {
               D_DEBUG_AT( IDFB, "  -> no size!\n" );
               return DFB_INVARG;
          }
     }

     if (desc->flags & DSDESC_CAPS) {
          D_DEBUG_AT( IDFB, "  -> caps   0x%08x\n", desc->caps );

          caps = desc->caps;
     }

     if (desc->flags & DSDESC_PIXELFORMAT) {
          D_DEBUG_AT( IDFB, "  -> format %s\n", dfb_pixelformat_name(desc->pixelformat) );

          format = desc->pixelformat;
          colorspace = DFB_COLORSPACE_DEFAULT(format);
     }

     if (desc->flags & DSDESC_COLORSPACE) {
          D_DEBUG_AT( IDFB, "  -> colorspace %s\n", dfb_colorspace_name(desc->pixelformat) );

          if (!DFB_COLORSPACE_IS_COMPATIBLE(desc->colorspace, format)) {
               D_DEBUG_AT( IDFB, "  -> incompatible color space!\n" );
               return DFB_INVARG;
          }

          colorspace = desc->colorspace;
     }

     if (desc->flags & DSDESC_RESOURCE_ID)
          resource_id = desc->resource_id;

     switch (format) {
          case DSPF_A1:
          case DSPF_A1_LSB:
          case DSPF_A4:
          case DSPF_A8:
          case DSPF_ARGB:
          case DSPF_ABGR:
          case DSPF_ARGB8565:
          case DSPF_ARGB1555:
          case DSPF_RGBA5551:
          case DSPF_ARGB1666:
          case DSPF_ARGB6666:
          case DSPF_ARGB2554:
          case DSPF_ARGB4444:
          case DSPF_RGBA4444:
          case DSPF_AYUV:
          case DSPF_AVYU:
          case DSPF_AiRGB:
          case DSPF_I420:
          case DSPF_LUT2:
          case DSPF_LUT8:
          case DSPF_ALUT44:
          case DSPF_RGB16:
          case DSPF_RGB18:
          case DSPF_RGB24:
          case DSPF_RGB32:
          case DSPF_RGB332:
          case DSPF_UYVY:
          case DSPF_YUY2:
          case DSPF_YV12:
          case DSPF_YV16:
          case DSPF_NV12:
          case DSPF_NV21:
          case DSPF_NV16:
          case DSPF_VYU:
          case DSPF_RGB444:
          case DSPF_RGB555:
          case DSPF_BGR555:
          case DSPF_RGBAF88871:
          case DSPF_YUV444P:
               break;

          default:
               D_DEBUG_AT( IDFB, "  -> invalid pixelformat 0x%08x\n", format );
               return DFB_INVARG;
     }

     if (caps & DSCAPS_PRIMARY) {
          if (dfb_config->primary_id) {
               ret = CoreDFB_GetSurface( data->core, dfb_config->primary_id, &surface );
               if (ret)
                    return ret;

               DIRECT_ALLOCATE_INTERFACE( iface, IDirectFBSurface );

               ret = IDirectFBSurface_Construct( iface, NULL, NULL, NULL, NULL, surface, DSCAPS_PRIMARY, data->core, thiz );
               if (ret) {
                    dfb_surface_unref( surface );
                    return ret;
               }

               init_palette( surface, desc );

               dfb_surface_unref( surface );

               *interface = iface;

               return ret;
          }

          if (desc->flags & DSDESC_PREALLOCATED) {
               D_DEBUG_AT( IDFB, "  -> cannot make preallocated primary!\n" );
               return DFB_INVARG;
          }

          if (desc->flags & DSDESC_PIXELFORMAT)   // FIXME COLORSPACE
               format = desc->pixelformat;
          else if (data->primary.format) {
               format = data->primary.format;
               colorspace = data->primary.colorspace;
          }
          else if (dfb_config->mode.format) {
               format = dfb_config->mode.format;
               colorspace = DFB_COLORSPACE_DEFAULT(format);
          }
          else {
               format = config.pixelformat;
               colorspace = config.colorspace;
          }

          if (desc->flags & DSDESC_WIDTH)
               width = desc->width;
          else if (data->primary.width)
               width = data->primary.width;
          else if (dfb_config->mode.width)
               width = dfb_config->mode.width;
          else
               width = config.width;

          if (desc->flags & DSDESC_HEIGHT)
               height = desc->height;
          else if (data->primary.height)
               height = data->primary.height;
          else if (dfb_config->mode.height)
               height = dfb_config->mode.height;
          else
               height = config.height;

          /* FIXME: should we allow to create more primaries in windowed mode?
                    should the primary surface be a singleton?
                    or should we return an error? */
          switch (data->level) {
               case DFSCL_NORMAL:
                    if (dfb_config->force_desktop) {
                         CoreSurface *surface;

                         /* Source compatibility with older programs */
                         if ((caps & DSCAPS_FLIPPING) == DSCAPS_FLIPPING)
                              caps &= ~DSCAPS_TRIPLE;

                         ret = dfb_surface_create_simple( data->core,
                                                          width, height,
                                                          format, colorspace, caps,
                                                          CSTF_SHARED, resource_id,
                                                          NULL, &surface );
                         if (ret)
                              return ret;

                         surface->notifications |= CSNF_FLIP;

                         init_palette( surface, desc );

                         DIRECT_ALLOCATE_INTERFACE( iface, IDirectFBSurface );

                         ret = IDirectFBSurface_Construct( iface, NULL,
                                                           NULL, NULL, NULL, surface, caps, data->core, thiz );
                         if (ret == DFB_OK) {
                              CoreWindowStack_BackgroundSetImage( data->stack, surface );
                              CoreWindowStack_BackgroundSetMode( data->stack, DLBM_IMAGE );
                         }

                         dfb_surface_unref( surface );

                         if (!ret)
                              *interface = iface;

                         return ret;
                    }
                    else {
                         CoreWindow           *window;
                         DFBWindowDescription  wd;

                         memset( &wd, 0, sizeof(wd) );

                         wd.flags = DWDESC_POSX | DWDESC_POSY | DWDESC_WIDTH | DWDESC_HEIGHT |
                                    DWDESC_PIXELFORMAT | DWDESC_COLORSPACE | DWDESC_SURFACE_CAPS | DWDESC_CAPS | DWDESC_RESOURCE_ID;

                         if (dfb_config->scaled.width && dfb_config->scaled.height) {
                              wd.posx = (config.width  - dfb_config->scaled.width)  / 2;
                              wd.posy = (config.height - dfb_config->scaled.height) / 2;
                         }
                         else {
                              wd.posx = (config.width  - width)  / 2;
                              wd.posy = (config.height - height) / 2;
                         }

                         wd.width        = width;
                         wd.height       = height;
                         wd.pixelformat  = format;
                         wd.colorspace   = colorspace;
                         wd.surface_caps = caps & ~DSCAPS_FLIPPING;
                         wd.resource_id  = resource_id;

                         switch (format) {
                              case DSPF_ARGB8565:
                              case DSPF_ARGB4444:
                              case DSPF_RGBA4444:
                              case DSPF_ARGB2554:
                              case DSPF_ARGB1555:
                              case DSPF_RGBA5551:
                              case DSPF_ARGB:
                              case DSPF_ABGR:
                              case DSPF_AYUV:
                              case DSPF_AVYU:
                              case DSPF_AiRGB:
                              case DSPF_RGBAF88871:
                                   wd.caps |= DWCAPS_ALPHACHANNEL;<commit_msg>IDirectFB: Do not mask out DSCAPS_FLIPPING when creating a windowed primary surface.<commit_after>/*
   (c) Copyright 2001-2010  The world wide DirectFB Open Source Community (directfb.org)
   (c) Copyright 2000-2004  Convergence (integrated media) GmbH

   All rights reserved.

   Written by <NAME> <<EMAIL>>,
              <NAME> <<EMAIL>>,
              <NAME> <<EMAIL>>,
              <NAME> <<EMAIL>> and
              <NAME> <<EMAIL>>.

   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 <config.h>

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <string.h>

#include <directfb.h>
#include <directfb_version.h>

#include <core/core.h>

#include <core/CoreDFB.h>
#include <core/CoreLayer.h>
#include <core/CoreLayerContext.h>
#include <core/CoreLayerRegion.h>
#include <core/CorePalette.h>
#include <core/CoreScreen.h>
#include <core/CoreSurface.h>
#include <core/CoreWindow.h>
#include <core/CoreWindowStack.h>

#include <core/clipboard.h>
#include <core/state.h>
#include <core/gfxcard.h>
#include <core/input.h>
#include <core/layer_context.h>
#include <core/layer_control.h>
#include <core/layer_region.h>
#include <core/layers.h>
#include <core/layers_internal.h>
#include <core/palette.h>
#include <core/screen.h>
#include <core/screens.h>
#include <core/surface.h>
#include <core/surface_pool.h>
#include <core/system.h>
#include <core/windows.h>
#include <core/windows_internal.h> /* FIXME */
#include <core/windowstack.h>

#include <display/idirectfbpalette.h>
#include <display/idirectfbscreen.h>
#include <display/idirectfbsurface.h>
#include <display/idirectfbsurface_layer.h>
#include <display/idirectfbsurface_window.h>
#include <display/idirectfbdisplaylayer.h>
#include <input/idirectfbinputbuffer.h>
#include <input/idirectfbinputdevice.h>
#include <media/idirectfbfont.h>
#include <media/idirectfbimageprovider.h>
#include <media/idirectfbvideoprovider.h>
#include <media/idirectfbdatabuffer.h>

#include <idirectfb.h>

#include <gfx/convert.h>

#include <misc/conf.h>

#include <direct/direct.h>
#include <direct/interface.h>
#include <direct/mem.h>
#include <direct/memcpy.h>
#include <direct/messages.h>
#include <direct/util.h>

#include <misc/util.h>

D_DEBUG_DOMAIN( IDFB, "IDirectFB", "DirectFB Main Interface" );

/**********************************************************************************************************************/

typedef struct {
     DFBScreenCallback  callback;
     void              *callback_ctx;
} EnumScreens_Context;

typedef struct {
     IDirectFBScreen **interface;
     DFBScreenID       id;
     DFBResult         ret;
} GetScreen_Context;

typedef struct {
     DFBDisplayLayerCallback  callback;
     void                    *callback_ctx;
} EnumDisplayLayers_Context;

typedef struct {
     IDirectFBDisplayLayer **interface;
     DFBDisplayLayerID       id;
     DFBResult               ret;
     CoreDFB                *core;
     IDirectFB              *idirectfb;
} GetDisplayLayer_Context;

typedef struct {
     DFBInputDeviceCallback  callback;
     void                   *callback_ctx;
} EnumInputDevices_Context;

typedef struct {
     IDirectFBInputDevice **interface;
     DFBInputDeviceID       id;
     DFBResult              ret;
} GetInputDevice_Context;

typedef struct {
     IDirectFBEventBuffer       **interface;
     DFBInputDeviceCapabilities   caps;
} CreateEventBuffer_Context;

/**********************************************************************************************************************/

static DFBEnumerationResult EnumScreens_Callback      ( CoreScreen  *screen,
                                                        void        *ctx );
static DFBEnumerationResult GetScreen_Callback        ( CoreScreen  *screen,
                                                        void        *ctx );

static DFBEnumerationResult EnumDisplayLayers_Callback( CoreLayer   *layer,
                                                        void        *ctx );
static DFBEnumerationResult GetDisplayLayer_Callback  ( CoreLayer   *layer,
                                                        void        *ctx );

static DFBEnumerationResult EnumInputDevices_Callback ( CoreInputDevice *device,
                                                        void            *ctx );
static DFBEnumerationResult GetInputDevice_Callback   ( CoreInputDevice *device,
                                                        void            *ctx );

static DFBEnumerationResult CreateEventBuffer_Callback( CoreInputDevice *device,
                                                        void            *ctx );

static ReactionResult focus_listener( const void *msg_data,
                                      void       *ctx );

static bool input_filter_local( DFBEvent *evt,
                                void     *ctx );

static bool input_filter_global( DFBEvent *evt,
                                 void     *ctx );

static void drop_window( IDirectFB_data *data, bool enable_cursor );

/**********************************************************************************************************************/

/* The containers_XXXX function family will maintain the connections between
 * event buffers created by IDirectFB::CreateInputEventBuffer and input
 * devices that are hot-plugged in.
 */

static  DirectLink      *containers      = NULL;
static  pthread_mutex_t  containers_lock = PTHREAD_MUTEX_INITIALIZER;

typedef struct {
     DirectLink                  link;
     DFBInputDeviceCapabilities  caps;
     IDirectFBEventBuffer       *iface;

} Event_Buffer_Container;

void
containers_attach_device(CoreInputDevice *device)
{
     Event_Buffer_Container  *container;
     DFBInputDeviceCapabilities dev_caps;

     D_ASSERT( device != NULL );

     dev_caps = dfb_input_device_caps(device);

     pthread_mutex_lock( &containers_lock );

     direct_list_foreach(container, containers) {
          if (dev_caps & container->caps) {
               IDirectFBEventBuffer_AttachInputDevice( container->iface, device );
          }
     }

     pthread_mutex_unlock( &containers_lock );
}

void
containers_detach_device(CoreInputDevice *device)
{
     Event_Buffer_Container  *container;

     pthread_mutex_lock( &containers_lock );

     direct_list_foreach(container, containers) {
          IDirectFBEventBuffer_DetachInputDevice(container->iface, device);
     }

     pthread_mutex_unlock( &containers_lock );
}

static void
containers_add_input_eventbuffer(CreateEventBuffer_Context * context)
{
     Event_Buffer_Container  *container;

     pthread_mutex_lock( &containers_lock );

     container = D_CALLOC(1, sizeof(Event_Buffer_Container));
     if (!container) {
          D_OOM();
          D_ERROR( "Can not allocate memory! in %s\n", __FUNCTION__ );
     }
     container->caps = context->caps;
     container->iface = *context->interface;

     direct_list_append(&containers, &container->link);

     pthread_mutex_unlock( &containers_lock );
}

void
containers_remove_input_eventbuffer(IDirectFBEventBuffer  *thiz)
{
     Event_Buffer_Container  *container = NULL;

     pthread_mutex_lock( &containers_lock );

     direct_list_foreach(container, containers) {
          if (thiz == container->iface) {
               direct_list_remove(&containers, &container->link);
               D_FREE(container);
          }
     }

     pthread_mutex_unlock( &containers_lock );
}

/**********************************************************************************************************************/

/*
 * Destructor
 *
 * Free data structure and set the pointer to NULL,
 * to indicate the dead interface.
 */
void
IDirectFB_Destruct( IDirectFB *thiz )
{
     int             i;
     IDirectFB_data *data = (IDirectFB_data*)thiz->priv;

     D_DEBUG_AT( IDFB, "%s( %p )\n", __FUNCTION__, thiz );

     drop_window( data, false );

     if (data->primary.context)
          dfb_layer_context_unref( data->primary.context );

     dfb_layer_context_unref( data->context );

     for (i=0; i<MAX_LAYERS; i++) {
          if (data->layers[i].context) {
               if (data->layers[i].palette)
                    dfb_palette_unref( data->layers[i].palette );

               dfb_surface_unref( data->layers[i].surface );
               dfb_layer_region_unref( data->layers[i].region );
               dfb_layer_context_unref( data->layers[i].context );
          }
     }

     dfb_core_destroy( data->core, false );

     DIRECT_DEALLOCATE_INTERFACE( thiz );

     direct_shutdown();

     if (thiz == idirectfb_singleton)
          idirectfb_singleton = NULL;
}


static DirectResult
IDirectFB_AddRef( IDirectFB *thiz )
{
     DIRECT_INTERFACE_GET_DATA(IDirectFB)

     D_DEBUG_AT( IDFB, "%s( %p )\n", __FUNCTION__, thiz );

     data->ref++;

     return DFB_OK;
}

static DirectResult
IDirectFB_Release( IDirectFB *thiz )
{
     DIRECT_INTERFACE_GET_DATA(IDirectFB)

     D_DEBUG_AT( IDFB, "%s( %p )\n", __FUNCTION__, thiz );

     if (--data->ref == 0)
          IDirectFB_Destruct( thiz );

     return DFB_OK;
}

static DFBResult
IDirectFB_SetCooperativeLevel( IDirectFB           *thiz,
                               DFBCooperativeLevel  level )
{
     DFBResult         ret;
     CoreLayerContext *context;

     DIRECT_INTERFACE_GET_DATA(IDirectFB)

     D_DEBUG_AT( IDFB, "%s( %p, %d )\n", __FUNCTION__, thiz, level );

     if (level == data->level)
          return DFB_OK;

     switch (level) {
          case DFSCL_NORMAL:
               data->primary.focused = false;

               dfb_layer_context_unref( data->primary.context );

               data->primary.context = NULL;
               break;

          case DFSCL_FULLSCREEN:
          case DFSCL_EXCLUSIVE:
               if (dfb_config->primary_id)
                    return DFB_ACCESSDENIED;

               if (dfb_config->force_windowed || dfb_config->force_desktop)
                    return DFB_ACCESSDENIED;

               if (data->level == DFSCL_NORMAL) {
                    ret = CoreLayer_CreateContext( data->layer, &context );
                    if (ret)
                         return ret;

                    ret = CoreLayer_ActivateContext( data->layer, context );
                    if (ret) {
                         dfb_layer_context_unref( context );
                         return ret;
                    }

                    drop_window( data, true );

                    data->primary.context = context;
               }

               data->primary.focused = true;
               break;

          default:
               return DFB_INVARG;
     }

     data->level = level;

     return DFB_OK;
}

static DFBResult
IDirectFB_GetDeviceDescription( IDirectFB                    *thiz,
                                DFBGraphicsDeviceDescription *ret_desc )
{
     GraphicsDeviceInfo device_info;
     GraphicsDriverInfo driver_info;

     DIRECT_INTERFACE_GET_DATA(IDirectFB)

     D_DEBUG_AT( IDFB, "%s( %p )\n", __FUNCTION__, thiz );

     if (!ret_desc)
          return DFB_INVARG;

     dfb_gfxcard_get_device_info( &device_info );
     dfb_gfxcard_get_driver_info( &driver_info );

     ret_desc->acceleration_mask = device_info.caps.accel;
     ret_desc->blitting_flags    = device_info.caps.blitting;
     ret_desc->drawing_flags     = device_info.caps.drawing;
     ret_desc->video_memory      = dfb_gfxcard_memory_length();

     direct_snputs( ret_desc->name,   device_info.name,   DFB_GRAPHICS_DEVICE_DESC_NAME_LENGTH );
     direct_snputs( ret_desc->vendor, device_info.vendor, DFB_GRAPHICS_DEVICE_DESC_NAME_LENGTH );

     ret_desc->driver.major = driver_info.version.major;
     ret_desc->driver.minor = driver_info.version.minor;

     direct_snputs( ret_desc->driver.name,   driver_info.name,   DFB_GRAPHICS_DRIVER_INFO_NAME_LENGTH );
     direct_snputs( ret_desc->driver.vendor, driver_info.vendor, DFB_GRAPHICS_DRIVER_INFO_VENDOR_LENGTH );

     return DFB_OK;
}

static DFBResult
IDirectFB_EnumVideoModes( IDirectFB            *thiz,
                          DFBVideoModeCallback  callbackfunc,
                          void                 *callbackdata )
{
     VideoMode *m;

     DIRECT_INTERFACE_GET_DATA(IDirectFB)

     D_DEBUG_AT( IDFB, "%s( %p, %p, %p )\n", __FUNCTION__, thiz, callbackfunc, callbackdata );

     if (!callbackfunc)
          return DFB_INVARG;

     m = dfb_system_modes();
     while (m) {
          if (callbackfunc( m->xres, m->yres,
                            m->bpp, callbackdata ) == DFENUM_CANCEL)
               break;

          m = m->next;
     }

     return DFB_OK;
}

static DFBResult
IDirectFB_SetVideoMode( IDirectFB    *thiz,
                        int           width,
                        int           height,
                        int           bpp )
{
     DFBResult ret;
     DFBSurfacePixelFormat format;
     DFBSurfaceColorSpace colorspace;

     DIRECT_INTERFACE_GET_DATA(IDirectFB)

     D_DEBUG_AT( IDFB, "%s( %p, %dx%d %dbit )\n", __FUNCTION__, thiz, width, height, bpp );

     if (width < 1 || height < 1 || bpp < 1)
          return DFB_INVARG;

     format = dfb_pixelformat_for_depth( bpp );
     if (format == DSPF_UNKNOWN)
          return DFB_INVARG;
     colorspace = DFB_COLORSPACE_DEFAULT(format);

     switch (data->level) {
          case DFSCL_NORMAL:
               if (data->primary.window) {
                    ret = dfb_window_resize( data->primary.window, width, height );
                    if (ret)
                         return ret;
               }
               break;

          case DFSCL_FULLSCREEN:
          case DFSCL_EXCLUSIVE: {
               DFBResult ret;
               DFBDisplayLayerConfig config;

               config.flags       = DLCONF_WIDTH | DLCONF_HEIGHT |
                                    DLCONF_PIXELFORMAT;
               config.width       = width;
               config.height      = height;
               config.pixelformat = format;
               config.colorspace  = colorspace;

               ret = CoreLayerContext_SetConfiguration( data->primary.context,
                                                          &config );
               if (ret)
                    return ret;

               break;
          }
     }

     data->primary.width      = width;
     data->primary.height     = height;
     data->primary.format     = format;
     data->primary.colorspace = colorspace;

     return DFB_OK;
}

static DFBResult
init_palette( CoreSurface *surface, const DFBSurfaceDescription *desc )
{
     DFBResult    ret;
     CorePalette *palette;

     if (!(desc->flags & DSDESC_PALETTE))
          return DFB_OK;

     ret = CoreSurface_GetPalette( surface, &palette );
     if (ret)
          return ret;

     ret = CorePalette_SetEntries( palette, desc->palette.entries, MIN( desc->palette.size, palette->num_entries ), 0 );

     dfb_palette_unref( palette );

     return ret;
}

static DFBResult
IDirectFB_CreateSurface( IDirectFB                    *thiz,
                         const DFBSurfaceDescription  *desc,
                         IDirectFBSurface            **interface )
{
     IDirectFBSurface *iface;
     DFBResult ret;
     int width = 256;
     int height = 256;
     DFBSurfacePixelFormat format;
     DFBSurfaceColorSpace colorspace;
     DFBSurfaceCapabilities caps = DSCAPS_NONE;
     CoreSurface *surface = NULL;
     unsigned long resource_id = 0;
     DFBDisplayLayerConfig  config;

     DIRECT_INTERFACE_GET_DATA(IDirectFB)

     D_DEBUG_AT( IDFB, "%s( %p )\n", __FUNCTION__, thiz );

     if (data->primary.context)
          dfb_layer_context_get_configuration( data->primary.context, &config );
     else
          dfb_layer_context_get_configuration( data->context, &config );

     if (desc->flags & DSDESC_HINTS && desc->hints & DSHF_FONT) {
          format = dfb_config->font_format;
          colorspace = DFB_COLORSPACE_DEFAULT(format);

          if (dfb_config->font_premult)
               caps = DSCAPS_PREMULTIPLIED;
     }
     else {
          format = config.pixelformat;
          colorspace = config.colorspace;
     }

     if (!desc || !interface)
          return DFB_INVARG;

     D_DEBUG_AT( IDFB, "  -> flags  0x%08x\n", desc->flags );

     if (desc->flags & DSDESC_WIDTH) {
          D_DEBUG_AT( IDFB, "  -> width  %d\n", desc->width );

          width = desc->width;
          if (width < 1 || width > 20480)
               return DFB_INVARG;
     }

     if (desc->flags & DSDESC_HEIGHT) {
          D_DEBUG_AT( IDFB, "  -> height %d\n", desc->height );

          height = desc->height;
          if (height < 1 || height > 20480)
               return DFB_INVARG;
     }

     if (desc->flags & DSDESC_PALETTE) {
          D_DEBUG_AT( IDFB, "  -> PALETTE\n" );

          if (!desc->palette.entries) {
               D_DEBUG_AT( IDFB, "  -> no entries!\n" );
               return DFB_INVARG;
          }

          if (!desc->palette.size) {
               D_DEBUG_AT( IDFB, "  -> no size!\n" );
               return DFB_INVARG;
          }
     }

     if (desc->flags & DSDESC_CAPS) {
          D_DEBUG_AT( IDFB, "  -> caps   0x%08x\n", desc->caps );

          caps = desc->caps;
     }

     if (desc->flags & DSDESC_PIXELFORMAT) {
          D_DEBUG_AT( IDFB, "  -> format %s\n", dfb_pixelformat_name(desc->pixelformat) );

          format = desc->pixelformat;
          colorspace = DFB_COLORSPACE_DEFAULT(format);
     }

     if (desc->flags & DSDESC_COLORSPACE) {
          D_DEBUG_AT( IDFB, "  -> colorspace %s\n", dfb_colorspace_name(desc->pixelformat) );

          if (!DFB_COLORSPACE_IS_COMPATIBLE(desc->colorspace, format)) {
               D_DEBUG_AT( IDFB, "  -> incompatible color space!\n" );
               return DFB_INVARG;
          }

          colorspace = desc->colorspace;
     }

     if (desc->flags & DSDESC_RESOURCE_ID)
          resource_id = desc->resource_id;

     switch (format) {
          case DSPF_A1:
          case DSPF_A1_LSB:
          case DSPF_A4:
          case DSPF_A8:
          case DSPF_ARGB:
          case DSPF_ABGR:
          case DSPF_ARGB8565:
          case DSPF_ARGB1555:
          case DSPF_RGBA5551:
          case DSPF_ARGB1666:
          case DSPF_ARGB6666:
          case DSPF_ARGB2554:
          case DSPF_ARGB4444:
          case DSPF_RGBA4444:
          case DSPF_AYUV:
          case DSPF_AVYU:
          case DSPF_AiRGB:
          case DSPF_I420:
          case DSPF_LUT2:
          case DSPF_LUT8:
          case DSPF_ALUT44:
          case DSPF_RGB16:
          case DSPF_RGB18:
          case DSPF_RGB24:
          case DSPF_RGB32:
          case DSPF_RGB332:
          case DSPF_UYVY:
          case DSPF_YUY2:
          case DSPF_YV12:
          case DSPF_YV16:
          case DSPF_NV12:
          case DSPF_NV21:
          case DSPF_NV16:
          case DSPF_VYU:
          case DSPF_RGB444:
          case DSPF_RGB555:
          case DSPF_BGR555:
          case DSPF_RGBAF88871:
          case DSPF_YUV444P:
               break;

          default:
               D_DEBUG_AT( IDFB, "  -> invalid pixelformat 0x%08x\n", format );
               return DFB_INVARG;
     }

     if (caps & DSCAPS_PRIMARY) {
          if (dfb_config->primary_id) {
               ret = CoreDFB_GetSurface( data->core, dfb_config->primary_id, &surface );
               if (ret)
                    return ret;

               DIRECT_ALLOCATE_INTERFACE( iface, IDirectFBSurface );

               ret = IDirectFBSurface_Construct( iface, NULL, NULL, NULL, NULL, surface, DSCAPS_PRIMARY, data->core, thiz );
               if (ret) {
                    dfb_surface_unref( surface );
                    return ret;
               }

               init_palette( surface, desc );

               dfb_surface_unref( surface );

               *interface = iface;

               return ret;
          }

          if (desc->flags & DSDESC_PREALLOCATED) {
               D_DEBUG_AT( IDFB, "  -> cannot make preallocated primary!\n" );
               return DFB_INVARG;
          }

          if (desc->flags & DSDESC_PIXELFORMAT)   // FIXME COLORSPACE
               format = desc->pixelformat;
          else if (data->primary.format) {
               format = data->primary.format;
               colorspace = data->primary.colorspace;
          }
          else if (dfb_config->mode.format) {
               format = dfb_config->mode.format;
               colorspace = DFB_COLORSPACE_DEFAULT(format);
          }
          else {
               format = config.pixelformat;
               colorspace = config.colorspace;
          }

          if (desc->flags & DSDESC_WIDTH)
               width = desc->width;
          else if (data->primary.width)
               width = data->primary.width;
          else if (dfb_config->mode.width)
               width = dfb_config->mode.width;
          else
               width = config.width;

          if (desc->flags & DSDESC_HEIGHT)
               height = desc->height;
          else if (data->primary.height)
               height = data->primary.height;
          else if (dfb_config->mode.height)
               height = dfb_config->mode.height;
          else
               height = config.height;

          /* FIXME: should we allow to create more primaries in windowed mode?
                    should the primary surface be a singleton?
                    or should we return an error? */
          switch (data->level) {
               case DFSCL_NORMAL:
                    if (dfb_config->force_desktop) {
                         CoreSurface *surface;

                         /* Source compatibility with older programs */
                         if ((caps & DSCAPS_FLIPPING) == DSCAPS_FLIPPING)
                              caps &= ~DSCAPS_TRIPLE;

                         ret = dfb_surface_create_simple( data->core,
                                                          width, height,
                                                          format, colorspace, caps,
                                                          CSTF_SHARED, resource_id,
                                                          NULL, &surface );
                         if (ret)
                              return ret;

                         surface->notifications |= CSNF_FLIP;

                         init_palette( surface, desc );

                         DIRECT_ALLOCATE_INTERFACE( iface, IDirectFBSurface );

                         ret = IDirectFBSurface_Construct( iface, NULL,
                                                           NULL, NULL, NULL, surface, caps, data->core, thiz );
                         if (ret == DFB_OK) {
                              CoreWindowStack_BackgroundSetImage( data->stack, surface );
                              CoreWindowStack_BackgroundSetMode( data->stack, DLBM_IMAGE );
                         }

                         dfb_surface_unref( surface );

                         if (!ret)
                              *interface = iface;

                         return ret;
                    }
                    else {
                         CoreWindow           *window;
                         DFBWindowDescription  wd;

                         memset( &wd, 0, sizeof(wd) );

                         wd.flags = DWDESC_POSX | DWDESC_POSY | DWDESC_WIDTH | DWDESC_HEIGHT |
                                    DWDESC_PIXELFORMAT | DWDESC_COLORSPACE | DWDESC_SURFACE_CAPS | DWDESC_CAPS | DWDESC_RESOURCE_ID;

                         if (dfb_config->scaled.width && dfb_config->scaled.height) {
                              wd.posx = (config.width  - dfb_config->scaled.width)  / 2;
                              wd.posy = (config.height - dfb_config->scaled.height) / 2;
                         }
                         else {
                              wd.posx = (config.width  - width)  / 2;
                              wd.posy = (config.height - height) / 2;
                         }

                         wd.width        = width;
                         wd.height       = height;
                         wd.pixelformat  = format;
                         wd.colorspace   = colorspace;
                         wd.surface_caps = caps;
                         wd.resource_id  = resource_id;

                         switch (format) {
                              case DSPF_ARGB8565:
                              case DSPF_ARGB4444:
                              case DSPF_RGBA4444:
                              case DSPF_ARGB2554:
                              case DSPF_ARGB1555:
                              case DSPF_RGBA5551:
                              case DSPF_ARGB:
                              case DSPF_ABGR:
                              case DSPF_AYUV:
                              case DSPF_AVYU:
                              case DSPF_AiRGB:
                              case DSPF_RGBAF88871:
                                   wd.caps |= DWCAPS_ALPHACHANNEL;
{'fraction_non_alphanumeric': 0.10374863897962358, 'fraction_numerical': 0.007077305957380619, 'mean_word_length': 1.7438250200053347, 'pattern_counts': {'":': 0, '<': 165, '<?xml version=': 0, '>': 433, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 72, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2590155', 'n_tokens_mistral': 15495, 'n_tokens_neox': 14681, 'n_words': 3077}