Copy support for X11
This commit is contained in:
		
							parent
							
								
									cd74f5da8d
								
							
						
					
					
						commit
						3e1d6b165d
					
				@ -6236,7 +6236,7 @@ static int PNG_read_unknown_chunk(png_structp ptr, png_unknown_chunkp chunk)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct PNG_memory_buffer {
 | 
			
		||||
  const char * buffer;
 | 
			
		||||
  char * buffer;
 | 
			
		||||
  unsigned long offset;
 | 
			
		||||
  unsigned long size;
 | 
			
		||||
};
 | 
			
		||||
@ -6294,7 +6294,7 @@ void Load_PNG_Sub(T_IO_Context * context, FILE * file, const char * memory_buffe
 | 
			
		||||
          png_init_io(png_ptr, file);
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
          buffer.buffer = memory_buffer;
 | 
			
		||||
          buffer.buffer = (char *)memory_buffer;
 | 
			
		||||
          buffer.offset = 8;  // skip header
 | 
			
		||||
          buffer.size = memory_buffer_size;
 | 
			
		||||
          png_set_read_fn(png_ptr, &buffer, PNG_memory_read);
 | 
			
		||||
@ -6623,165 +6623,184 @@ void Load_PNG(T_IO_Context * context)
 | 
			
		||||
    File_error=1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Save a PNG file
 | 
			
		||||
void Save_PNG(T_IO_Context * context)
 | 
			
		||||
 | 
			
		||||
static void PNG_memory_write(png_structp png_ptr, png_bytep p, png_size_t count)
 | 
			
		||||
{
 | 
			
		||||
  FILE *file;
 | 
			
		||||
  struct PNG_memory_buffer * buffer = (struct PNG_memory_buffer *)png_get_io_ptr(png_ptr);
 | 
			
		||||
  GFX2_Log(GFX2_DEBUG, "PNG_memory_write(%p, %p, %u) (io_ptr=%p)\n", png_ptr, p, count, buffer);
 | 
			
		||||
  if (buffer->size < buffer->offset + count)
 | 
			
		||||
  {
 | 
			
		||||
    char * tmp = realloc(buffer->buffer, buffer->offset + count + 1024);
 | 
			
		||||
    if (tmp == NULL)
 | 
			
		||||
    {
 | 
			
		||||
      GFX2_Log(GFX2_ERROR, "PNG_memory_write() Failed to allocate %u bytes of memory\n", buffer->offset + count + 1024);
 | 
			
		||||
      File_error = 1;
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    buffer->buffer = tmp;
 | 
			
		||||
    buffer->size = buffer->offset + count + 1024;
 | 
			
		||||
  }
 | 
			
		||||
  memcpy(buffer->buffer + buffer->offset, p, count);
 | 
			
		||||
  buffer->offset += count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void PNG_memory_flush(png_structp png_ptr)
 | 
			
		||||
{
 | 
			
		||||
  struct PNG_memory_buffer * buffer = (struct PNG_memory_buffer *)png_get_io_ptr(png_ptr);
 | 
			
		||||
  GFX2_Log(GFX2_DEBUG, "PNG_memory_flush(%p) (io_ptr=%p)\n", png_ptr, buffer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Save_PNG_Sub(T_IO_Context * context, FILE * file, char * * buffer, unsigned long * buffer_size)
 | 
			
		||||
{
 | 
			
		||||
  static png_bytep * Row_pointers = NULL;
 | 
			
		||||
  int y;
 | 
			
		||||
  byte * pixel_ptr;
 | 
			
		||||
  png_structp png_ptr;
 | 
			
		||||
  png_infop info_ptr;
 | 
			
		||||
  png_unknown_chunk crng_chunk;
 | 
			
		||||
  byte cycle_data[16*6]; // Storage for color-cycling data, referenced by crng_chunk
 | 
			
		||||
  static png_bytep * Row_pointers;
 | 
			
		||||
  
 | 
			
		||||
  File_error=0;
 | 
			
		||||
  Row_pointers = NULL;
 | 
			
		||||
  
 | 
			
		||||
  // Ouverture du fichier
 | 
			
		||||
  if ((file=Open_file_write(context)))
 | 
			
		||||
  {
 | 
			
		||||
    setvbuf(file, NULL, _IOFBF, 64*1024);
 | 
			
		||||
    
 | 
			
		||||
    /* initialisation */
 | 
			
		||||
    if ((png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL))
 | 
			
		||||
  struct PNG_memory_buffer memory_buffer;
 | 
			
		||||
 | 
			
		||||
  /* initialisation */
 | 
			
		||||
  if ((png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL))
 | 
			
		||||
      && (info_ptr = png_create_info_struct(png_ptr)))
 | 
			
		||||
  {
 | 
			
		||||
    if (!setjmp(png_jmpbuf(png_ptr)))
 | 
			
		||||
    {
 | 
			
		||||
  
 | 
			
		||||
      if (!setjmp(png_jmpbuf(png_ptr)))
 | 
			
		||||
      {    
 | 
			
		||||
      if (file != NULL)
 | 
			
		||||
        png_init_io(png_ptr, file);
 | 
			
		||||
      else
 | 
			
		||||
      {
 | 
			
		||||
        memset(&memory_buffer, 0, sizeof(memory_buffer));
 | 
			
		||||
        png_set_write_fn(png_ptr, &memory_buffer, PNG_memory_write, PNG_memory_flush);
 | 
			
		||||
      }
 | 
			
		||||
      
 | 
			
		||||
        /* en-tete */
 | 
			
		||||
        if (!setjmp(png_jmpbuf(png_ptr)))
 | 
			
		||||
        {
 | 
			
		||||
          png_set_IHDR(png_ptr, info_ptr, context->Width, context->Height,
 | 
			
		||||
      /* en-tete */
 | 
			
		||||
      if (!setjmp(png_jmpbuf(png_ptr)))
 | 
			
		||||
      {
 | 
			
		||||
        png_set_IHDR(png_ptr, info_ptr, context->Width, context->Height,
 | 
			
		||||
            8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE,
 | 
			
		||||
            PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
 | 
			
		||||
 | 
			
		||||
          png_set_PLTE(png_ptr, info_ptr, (png_colorp)context->Palette, 256);
 | 
			
		||||
        png_set_PLTE(png_ptr, info_ptr, (png_colorp)context->Palette, 256);
 | 
			
		||||
        {
 | 
			
		||||
          // Commentaires texte PNG
 | 
			
		||||
          // Cette partie est optionnelle
 | 
			
		||||
          png_text text_ptr[2] = {
 | 
			
		||||
#ifdef PNG_iTXt_SUPPORTED
 | 
			
		||||
            {-1, "Software", "Grafx2", 6, 0, NULL, NULL},
 | 
			
		||||
            {-1, "Title", NULL, 0, 0, NULL, NULL}
 | 
			
		||||
#else
 | 
			
		||||
            {-1, "Software", "Grafx2", 6},
 | 
			
		||||
            {-1, "Title", NULL, 0}
 | 
			
		||||
#endif
 | 
			
		||||
          };
 | 
			
		||||
          int nb_text_chunks=1;
 | 
			
		||||
          if (context->Comment[0])
 | 
			
		||||
          {
 | 
			
		||||
            // Commentaires texte PNG
 | 
			
		||||
            // Cette partie est optionnelle
 | 
			
		||||
            #ifdef PNG_iTXt_SUPPORTED
 | 
			
		||||
              png_text text_ptr[2] = {
 | 
			
		||||
                {-1, "Software", "Grafx2", 6, 0, NULL, NULL},
 | 
			
		||||
                {-1, "Title", NULL, 0, 0, NULL, NULL}
 | 
			
		||||
            #else
 | 
			
		||||
            png_text text_ptr[2] = {
 | 
			
		||||
              {-1, "Software", "Grafx2", 6},
 | 
			
		||||
              {-1, "Title", NULL, 0}
 | 
			
		||||
            #endif
 | 
			
		||||
            };
 | 
			
		||||
            int nb_text_chunks=1;
 | 
			
		||||
            if (context->Comment[0])
 | 
			
		||||
            {
 | 
			
		||||
              text_ptr[1].text=context->Comment;
 | 
			
		||||
              text_ptr[1].text_length=strlen(context->Comment);
 | 
			
		||||
              nb_text_chunks=2;
 | 
			
		||||
            }
 | 
			
		||||
            png_set_text(png_ptr, info_ptr, text_ptr, nb_text_chunks);
 | 
			
		||||
            text_ptr[1].text=context->Comment;
 | 
			
		||||
            text_ptr[1].text_length=strlen(context->Comment);
 | 
			
		||||
            nb_text_chunks=2;
 | 
			
		||||
          }
 | 
			
		||||
          if (context->Background_transparent)
 | 
			
		||||
          {
 | 
			
		||||
            // Transparency
 | 
			
		||||
            byte opacity[256];
 | 
			
		||||
            // Need to fill a segment with '255', up to the transparent color
 | 
			
		||||
            // which will have a 0. This piece of data (1 to 256 bytes)
 | 
			
		||||
            // will be stored in the file.
 | 
			
		||||
            memset(opacity, 255,context->Transparent_color);
 | 
			
		||||
            opacity[context->Transparent_color]=0;
 | 
			
		||||
            png_set_tRNS(png_ptr, info_ptr, opacity, (int)1 + context->Transparent_color,0);
 | 
			
		||||
          }
 | 
			
		||||
          // if using PNG_RESOLUTION_METER, unit is in dot per meter.
 | 
			
		||||
          // 72 DPI = 2835,  600 DPI = 23622
 | 
			
		||||
          // with PNG_RESOLUTION_UNKNOWN, it is arbitrary
 | 
			
		||||
          switch(Pixel_ratio)
 | 
			
		||||
          {
 | 
			
		||||
            case PIXEL_WIDE:
 | 
			
		||||
            case PIXEL_WIDE2:
 | 
			
		||||
              png_set_pHYs(png_ptr, info_ptr, 1, 2, PNG_RESOLUTION_UNKNOWN);
 | 
			
		||||
              break;
 | 
			
		||||
            case PIXEL_TALL:
 | 
			
		||||
            case PIXEL_TALL2:
 | 
			
		||||
              png_set_pHYs(png_ptr, info_ptr, 2, 1, PNG_RESOLUTION_UNKNOWN);
 | 
			
		||||
              break;
 | 
			
		||||
            case PIXEL_TALL3:
 | 
			
		||||
              png_set_pHYs(png_ptr, info_ptr, 4, 3, PNG_RESOLUTION_UNKNOWN);
 | 
			
		||||
              break;
 | 
			
		||||
            default:
 | 
			
		||||
              break;
 | 
			
		||||
          }
 | 
			
		||||
          // Write cycling colors
 | 
			
		||||
          if (context->Color_cycles)
 | 
			
		||||
          {
 | 
			
		||||
            // Save a chunk called 'crNg'
 | 
			
		||||
            // The case is selected by the following rules from PNG standard:
 | 
			
		||||
            // char 1: non-mandatory = lowercase
 | 
			
		||||
            // char 2: private (not standard) = lowercase
 | 
			
		||||
            // char 3: reserved = always uppercase
 | 
			
		||||
            // char 4: can be copied by editors = lowercase
 | 
			
		||||
          png_set_text(png_ptr, info_ptr, text_ptr, nb_text_chunks);
 | 
			
		||||
        }
 | 
			
		||||
        if (context->Background_transparent)
 | 
			
		||||
        {
 | 
			
		||||
          // Transparency
 | 
			
		||||
          byte opacity[256];
 | 
			
		||||
          // Need to fill a segment with '255', up to the transparent color
 | 
			
		||||
          // which will have a 0. This piece of data (1 to 256 bytes)
 | 
			
		||||
          // will be stored in the file.
 | 
			
		||||
          memset(opacity, 255,context->Transparent_color);
 | 
			
		||||
          opacity[context->Transparent_color]=0;
 | 
			
		||||
          png_set_tRNS(png_ptr, info_ptr, opacity, (int)1 + context->Transparent_color,0);
 | 
			
		||||
        }
 | 
			
		||||
        // if using PNG_RESOLUTION_METER, unit is in dot per meter.
 | 
			
		||||
        // 72 DPI = 2835,  600 DPI = 23622
 | 
			
		||||
        // with PNG_RESOLUTION_UNKNOWN, it is arbitrary
 | 
			
		||||
        switch(Pixel_ratio)
 | 
			
		||||
        {
 | 
			
		||||
          case PIXEL_WIDE:
 | 
			
		||||
          case PIXEL_WIDE2:
 | 
			
		||||
            png_set_pHYs(png_ptr, info_ptr, 1, 2, PNG_RESOLUTION_UNKNOWN);
 | 
			
		||||
            break;
 | 
			
		||||
          case PIXEL_TALL:
 | 
			
		||||
          case PIXEL_TALL2:
 | 
			
		||||
            png_set_pHYs(png_ptr, info_ptr, 2, 1, PNG_RESOLUTION_UNKNOWN);
 | 
			
		||||
            break;
 | 
			
		||||
          case PIXEL_TALL3:
 | 
			
		||||
            png_set_pHYs(png_ptr, info_ptr, 4, 3, PNG_RESOLUTION_UNKNOWN);
 | 
			
		||||
            break;
 | 
			
		||||
          default:
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        // Write cycling colors
 | 
			
		||||
        if (context->Color_cycles)
 | 
			
		||||
        {
 | 
			
		||||
          // Save a chunk called 'crNg'
 | 
			
		||||
          // The case is selected by the following rules from PNG standard:
 | 
			
		||||
          // char 1: non-mandatory = lowercase
 | 
			
		||||
          // char 2: private (not standard) = lowercase
 | 
			
		||||
          // char 3: reserved = always uppercase
 | 
			
		||||
          // char 4: can be copied by editors = lowercase
 | 
			
		||||
 | 
			
		||||
            // First, turn our nice structure into byte array
 | 
			
		||||
            // (just to avoid padding in structures)
 | 
			
		||||
          // First, turn our nice structure into byte array
 | 
			
		||||
          // (just to avoid padding in structures)
 | 
			
		||||
            
 | 
			
		||||
            byte *chunk_ptr = cycle_data;
 | 
			
		||||
            int i;
 | 
			
		||||
          byte *chunk_ptr = cycle_data;
 | 
			
		||||
          int i;
 | 
			
		||||
            
 | 
			
		||||
            for (i=0; i<context->Color_cycles; i++)
 | 
			
		||||
            {
 | 
			
		||||
              word flags=0;
 | 
			
		||||
              flags|= context->Cycle_range[i].Speed?1:0; // Cycling or not
 | 
			
		||||
              flags|= context->Cycle_range[i].Inverse?2:0; // Inverted
 | 
			
		||||
              
 | 
			
		||||
              // Big end of Rate
 | 
			
		||||
              *(chunk_ptr++) = (context->Cycle_range[i].Speed*78) >> 8;
 | 
			
		||||
              // Low end of Rate
 | 
			
		||||
              *(chunk_ptr++) = (context->Cycle_range[i].Speed*78) & 0xFF;
 | 
			
		||||
              
 | 
			
		||||
              // Big end of Flags
 | 
			
		||||
              *(chunk_ptr++) = (flags) >> 8;
 | 
			
		||||
              // Low end of Flags
 | 
			
		||||
              *(chunk_ptr++) = (flags) & 0xFF;
 | 
			
		||||
              
 | 
			
		||||
              // Min color
 | 
			
		||||
              *(chunk_ptr++) = context->Cycle_range[i].Start;
 | 
			
		||||
              // Max color
 | 
			
		||||
              *(chunk_ptr++) = context->Cycle_range[i].End;
 | 
			
		||||
            }
 | 
			
		||||
          for (i=0; i<context->Color_cycles; i++)
 | 
			
		||||
          {
 | 
			
		||||
            word flags=0;
 | 
			
		||||
            flags|= context->Cycle_range[i].Speed?1:0; // Cycling or not
 | 
			
		||||
            flags|= context->Cycle_range[i].Inverse?2:0; // Inverted
 | 
			
		||||
 | 
			
		||||
            // Build one unknown_chuck structure        
 | 
			
		||||
            memcpy(crng_chunk.name, "crNg",5);
 | 
			
		||||
            crng_chunk.data=cycle_data;
 | 
			
		||||
            crng_chunk.size=context->Color_cycles*6;
 | 
			
		||||
            crng_chunk.location=PNG_HAVE_PLTE;
 | 
			
		||||
            
 | 
			
		||||
            // Give it to libpng
 | 
			
		||||
            png_set_unknown_chunks(png_ptr, info_ptr, &crng_chunk, 1);
 | 
			
		||||
            // libpng seems to ignore the location I provided earlier.
 | 
			
		||||
            png_set_unknown_chunk_location(png_ptr, info_ptr, 0, PNG_HAVE_PLTE);
 | 
			
		||||
            // Big end of Rate
 | 
			
		||||
            *(chunk_ptr++) = (context->Cycle_range[i].Speed*78) >> 8;
 | 
			
		||||
            // Low end of Rate
 | 
			
		||||
            *(chunk_ptr++) = (context->Cycle_range[i].Speed*78) & 0xFF;
 | 
			
		||||
 | 
			
		||||
            // Big end of Flags
 | 
			
		||||
            *(chunk_ptr++) = (flags) >> 8;
 | 
			
		||||
            // Low end of Flags
 | 
			
		||||
            *(chunk_ptr++) = (flags) & 0xFF;
 | 
			
		||||
 | 
			
		||||
            // Min color
 | 
			
		||||
            *(chunk_ptr++) = context->Cycle_range[i].Start;
 | 
			
		||||
            // Max color
 | 
			
		||||
            *(chunk_ptr++) = context->Cycle_range[i].End;
 | 
			
		||||
          }
 | 
			
		||||
          
 | 
			
		||||
          
 | 
			
		||||
          png_write_info(png_ptr, info_ptr);
 | 
			
		||||
 | 
			
		||||
          /* ecriture des pixels de l'image */
 | 
			
		||||
          Row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * context->Height);
 | 
			
		||||
          pixel_ptr = context->Target_address;
 | 
			
		||||
          for (y=0; y<context->Height; y++)
 | 
			
		||||
            Row_pointers[y] = (png_byte*)(pixel_ptr+y*context->Pitch);
 | 
			
		||||
          // Build one unknown_chuck structure
 | 
			
		||||
          memcpy(crng_chunk.name, "crNg",5);
 | 
			
		||||
          crng_chunk.data=cycle_data;
 | 
			
		||||
          crng_chunk.size=context->Color_cycles*6;
 | 
			
		||||
          crng_chunk.location=PNG_HAVE_PLTE;
 | 
			
		||||
 | 
			
		||||
          // Give it to libpng
 | 
			
		||||
          png_set_unknown_chunks(png_ptr, info_ptr, &crng_chunk, 1);
 | 
			
		||||
          // libpng seems to ignore the location I provided earlier.
 | 
			
		||||
          png_set_unknown_chunk_location(png_ptr, info_ptr, 0, PNG_HAVE_PLTE);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        png_write_info(png_ptr, info_ptr);
 | 
			
		||||
 | 
			
		||||
        /* ecriture des pixels de l'image */
 | 
			
		||||
        Row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * context->Height);
 | 
			
		||||
        pixel_ptr = context->Target_address;
 | 
			
		||||
        for (y=0; y<context->Height; y++)
 | 
			
		||||
          Row_pointers[y] = (png_byte*)(pixel_ptr+y*context->Pitch);
 | 
			
		||||
 | 
			
		||||
        if (!setjmp(png_jmpbuf(png_ptr)))
 | 
			
		||||
        {
 | 
			
		||||
          png_write_image(png_ptr, Row_pointers);
 | 
			
		||||
 | 
			
		||||
          /* cloture png */
 | 
			
		||||
          if (!setjmp(png_jmpbuf(png_ptr)))
 | 
			
		||||
          {
 | 
			
		||||
            png_write_image(png_ptr, Row_pointers);
 | 
			
		||||
          
 | 
			
		||||
            /* cloture png */
 | 
			
		||||
            if (!setjmp(png_jmpbuf(png_ptr)))
 | 
			
		||||
            {          
 | 
			
		||||
              png_write_end(png_ptr, NULL);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
              File_error=1;
 | 
			
		||||
            png_write_end(png_ptr, NULL);
 | 
			
		||||
          }
 | 
			
		||||
          else
 | 
			
		||||
            File_error=1;
 | 
			
		||||
@ -6790,27 +6809,44 @@ void Save_PNG(T_IO_Context * context)
 | 
			
		||||
          File_error=1;
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      {
 | 
			
		||||
        File_error=1;
 | 
			
		||||
      }
 | 
			
		||||
      png_destroy_write_struct(&png_ptr, &info_ptr);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
      File_error=1;
 | 
			
		||||
    // fermeture du fichier
 | 
			
		||||
    fclose(file);
 | 
			
		||||
    }
 | 
			
		||||
    png_destroy_write_struct(&png_ptr, &info_ptr);
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
    File_error=1;
 | 
			
		||||
 | 
			
		||||
  //   S'il y a eu une erreur de sauvegarde, on ne va tout de même pas laisser
 | 
			
		||||
  // ce fichier pourri trainait... Ca fait pas propre.
 | 
			
		||||
  if (File_error)
 | 
			
		||||
    Remove_file(context);
 | 
			
		||||
  
 | 
			
		||||
  if (Row_pointers)
 | 
			
		||||
  {
 | 
			
		||||
    free(Row_pointers);
 | 
			
		||||
    Row_pointers=NULL;
 | 
			
		||||
  if (memory_buffer.buffer)
 | 
			
		||||
  {
 | 
			
		||||
    *buffer = memory_buffer.buffer;
 | 
			
		||||
    *buffer_size = memory_buffer.offset;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Save a PNG file
 | 
			
		||||
void Save_PNG(T_IO_Context * context)
 | 
			
		||||
{
 | 
			
		||||
  FILE *file;
 | 
			
		||||
 | 
			
		||||
  File_error = 0;
 | 
			
		||||
 | 
			
		||||
  file = Open_file_write(context);
 | 
			
		||||
  if (file != NULL)
 | 
			
		||||
  {
 | 
			
		||||
    Save_PNG_Sub(context, file, NULL, NULL);
 | 
			
		||||
    fclose(file);
 | 
			
		||||
    // remove the file if there was an error
 | 
			
		||||
    if (File_error)
 | 
			
		||||
      Remove_file(context);
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
    File_error = 1;
 | 
			
		||||
}
 | 
			
		||||
#endif  // __no_pnglib__
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -141,6 +141,7 @@ void Test_PNG(T_IO_Context *, FILE *);
 | 
			
		||||
void Load_PNG(T_IO_Context *);
 | 
			
		||||
void Save_PNG(T_IO_Context *);
 | 
			
		||||
void Load_PNG_Sub(T_IO_Context * context, FILE * file, const char * memory_buffer, unsigned long memory_buffer_size);
 | 
			
		||||
void Save_PNG_Sub(T_IO_Context * context, FILE * file, char * * buffer, unsigned long * buffer_size);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// -- INFO (Amiga ICONS) ----------------------------------------------------
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										84
									
								
								src/input.c
									
									
									
									
									
								
							
							
						
						
									
										84
									
								
								src/input.c
									
									
									
									
									
								
							@ -38,6 +38,7 @@
 | 
			
		||||
#include <X11/Xlib.h>
 | 
			
		||||
#include <X11/XKBlib.h>
 | 
			
		||||
#include <X11/Xutil.h>
 | 
			
		||||
#include <X11/Xatom.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "gfx2log.h"
 | 
			
		||||
@ -522,6 +523,60 @@ static int Handle_SelectionNotify(const XSelectionEvent* xselection)
 | 
			
		||||
  }
 | 
			
		||||
  return user_feedback_required;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void Handle_SelectionRequest(const XSelectionRequestEvent* xselectionrequest)
 | 
			
		||||
{
 | 
			
		||||
  XSelectionEvent xselection; 
 | 
			
		||||
  char * target_name;
 | 
			
		||||
  char * property_name;
 | 
			
		||||
  Atom png;
 | 
			
		||||
#if defined(SDL_VIDEO_DRIVER_X11)
 | 
			
		||||
  Display * X11_display;
 | 
			
		||||
  Window X11_window;
 | 
			
		||||
 | 
			
		||||
  if (!GFX2_Get_X11_Display_Window(&X11_display, &X11_window))
 | 
			
		||||
  {
 | 
			
		||||
    GFX2_Log(GFX2_ERROR, "Failed to get X11 display and window\n");
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  png = XInternAtom(X11_display, "image/png", False);
 | 
			
		||||
 | 
			
		||||
  target_name = XGetAtomName(X11_display, xselectionrequest->target);
 | 
			
		||||
  property_name = XGetAtomName(X11_display, xselectionrequest->property);
 | 
			
		||||
  GFX2_Log(GFX2_DEBUG, "Handle_SelectionRequest target=%s property=%s\n", target_name, property_name);
 | 
			
		||||
  XFree(target_name);
 | 
			
		||||
  XFree(property_name);
 | 
			
		||||
 | 
			
		||||
  xselection.type = SelectionNotify;
 | 
			
		||||
  xselection.requestor = xselectionrequest->requestor;
 | 
			
		||||
  xselection.selection = xselectionrequest->selection;
 | 
			
		||||
  xselection.target = xselectionrequest->target;
 | 
			
		||||
  xselection.property = xselectionrequest->property;
 | 
			
		||||
  xselection.time = xselectionrequest->time;
 | 
			
		||||
 | 
			
		||||
  if (xselectionrequest->target == XInternAtom(X11_display, "TARGETS", False))
 | 
			
		||||
  {
 | 
			
		||||
    Atom targets[1];
 | 
			
		||||
    targets[0] = png;
 | 
			
		||||
    XChangeProperty(X11_display, xselectionrequest->requestor, xselectionrequest->property,
 | 
			
		||||
                    XA_ATOM, 32, PropModeReplace,
 | 
			
		||||
                    (unsigned char *)targets, 1);
 | 
			
		||||
  }
 | 
			
		||||
  else if (xselectionrequest->target == png)
 | 
			
		||||
  {
 | 
			
		||||
    XChangeProperty(X11_display, xselectionrequest->requestor, xselectionrequest->property,
 | 
			
		||||
                    png, 8, PropModeReplace,
 | 
			
		||||
                    (unsigned char *)X11_clipboard, X11_clipboard_size);
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    xselection.property = None; // refuse
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  XSendEvent(X11_display, xselectionrequest->requestor, True, NoEventMask, (XEvent *)&xselection);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(USE_SDL)
 | 
			
		||||
@ -1351,6 +1406,18 @@ int Get_input(int sleep_time)
 | 
			
		||||
                  if (Handle_SelectionNotify(&(xevent.xselection)))
 | 
			
		||||
                    user_feedback_required = 1;
 | 
			
		||||
                  break;
 | 
			
		||||
                case SelectionRequest:
 | 
			
		||||
                  Handle_SelectionRequest(&(xevent.xselectionrequest));
 | 
			
		||||
                  break;
 | 
			
		||||
                case SelectionClear:
 | 
			
		||||
                  GFX2_Log(GFX2_DEBUG, "X11 SelectionClear\n");
 | 
			
		||||
                  if (X11_clipboard)
 | 
			
		||||
                  {
 | 
			
		||||
                    free(X11_clipboard);
 | 
			
		||||
                    X11_clipboard_size = 0;
 | 
			
		||||
                  }
 | 
			
		||||
                  SDL_EventState(SDL_SYSWMEVENT, SDL_DISABLE);
 | 
			
		||||
                  break;
 | 
			
		||||
                case ButtonPress:
 | 
			
		||||
                case ButtonRelease:
 | 
			
		||||
                case MotionNotify:
 | 
			
		||||
@ -1687,6 +1754,23 @@ int Get_input(int sleep_time)
 | 
			
		||||
          if (Handle_SelectionNotify(&event.xselection))
 | 
			
		||||
            user_feedback_required = 1;
 | 
			
		||||
          break;
 | 
			
		||||
        case SelectionClear:
 | 
			
		||||
          GFX2_Log(GFX2_DEBUG, "X11 SelectionClear\n");
 | 
			
		||||
          if (X11_clipboard)
 | 
			
		||||
          {
 | 
			
		||||
            free(X11_clipboard);
 | 
			
		||||
            X11_clipboard_size = 0;
 | 
			
		||||
          }
 | 
			
		||||
          break;
 | 
			
		||||
        case SelectionRequest:
 | 
			
		||||
          Handle_SelectionRequest(&event.xselectionrequest);
 | 
			
		||||
          break;
 | 
			
		||||
        case ReparentNotify:
 | 
			
		||||
          GFX2_Log(GFX2_DEBUG, "X11 ReparentNotify\n");
 | 
			
		||||
          break;
 | 
			
		||||
        case MapNotify:
 | 
			
		||||
          GFX2_Log(GFX2_DEBUG, "X11 MapNotify\n");
 | 
			
		||||
          break;
 | 
			
		||||
        default:
 | 
			
		||||
          GFX2_Log(GFX2_INFO, "X11 event.type = %d not handled\n", event.type);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
@ -1566,6 +1566,46 @@ static void Save_ClipBoard_Image(T_IO_Context * context)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  CloseClipboard();
 | 
			
		||||
#elif defined(USE_X11) || (defined(SDL_VIDEO_DRIVER_X11) && !defined(NO_X11))
 | 
			
		||||
  Atom selection;
 | 
			
		||||
#if defined(SDL_VIDEO_DRIVER_X11)
 | 
			
		||||
  Display * X11_display;
 | 
			
		||||
  Window X11_window;
 | 
			
		||||
  //int old_wmevent_state;
 | 
			
		||||
 | 
			
		||||
  if (!GFX2_Get_X11_Display_Window(&X11_display, &X11_window))
 | 
			
		||||
  {
 | 
			
		||||
    GFX2_Log(GFX2_ERROR, "Failed to get X11 display and window\n");
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  if (X11_display == NULL)
 | 
			
		||||
  {
 | 
			
		||||
#if defined(USE_SDL)
 | 
			
		||||
    char video_driver_name[32];
 | 
			
		||||
    GFX2_Log(GFX2_WARNING, "X11 display is NULL. X11 is needed for Copy/Paste. SDL video driver is currently %s\n", SDL_VideoDriverName(video_driver_name, sizeof(video_driver_name)));
 | 
			
		||||
#elif defined(USE_SDL2)
 | 
			
		||||
    GFX2_Log(GFX2_WARNING, "X11 display is NULL. X11 is needed for Copy/Paste. SDL video driver is currently %s\n", SDL_GetCurrentVideoDriver());
 | 
			
		||||
#endif
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  File_error = 0;
 | 
			
		||||
  if (X11_clipboard != NULL)
 | 
			
		||||
  {
 | 
			
		||||
    free(X11_clipboard);
 | 
			
		||||
    X11_clipboard = NULL;
 | 
			
		||||
    X11_clipboard_size = 0;
 | 
			
		||||
  }
 | 
			
		||||
  Save_PNG_Sub(context, NULL, &X11_clipboard, &X11_clipboard_size);
 | 
			
		||||
  if (!File_error)
 | 
			
		||||
  {
 | 
			
		||||
#if defined(USE_SDL) || defined(USE_SDL2)
 | 
			
		||||
    SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
 | 
			
		||||
#endif
 | 
			
		||||
    selection = XInternAtom(X11_display, "CLIPBOARD", False);
 | 
			
		||||
    XSetSelectionOwner(X11_display, selection, X11_window, CurrentTime);
 | 
			
		||||
  }
 | 
			
		||||
#else
 | 
			
		||||
  GFX2_Log(GFX2_ERROR, "Save_ClipBoard_Image() not implemented on this platform yet\n");
 | 
			
		||||
  File_error = 1;
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user