Prima

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN

 - Add Image .clone,.bar,.mirror,.rotate
 - Support bidirectional texts with Text::Bidi

1.44 2015-08-04
 - Rewrite rubberband
 - Work on portable perls
 - Better support of graphic libs where several versions are available

1.43 2015-04-10
 - Rewrite font test and polish rough ends in xft font handling
 - Copy images to clipboard so that GTK recognizes them

1.42 2015-03-11
 - Tests became TAP compliant and using Prima::Test
 - Jpeg exif orientation support added
 - Scrollbar overriding properties added for scroller widgets

1.41 2014-11-08
 - Add ImageViewer.autoZoom
 - Fixes to Notebook

Changes  view on Meta::CPAN


1.34 2012-05-27
 - Unicode fixes, ready for 5.16

1.33 2012-02-10
 - Image codecs: remove prigraph, add XBM, and enhance TIFF support
 - Add RubberBand.pm

1.32 2011-10-19
 - Major rehaul of Makefile.PL, migrated to ExtUtils::MakeMaker.
 - Support image/mime clipboard formats under GTK.

1.31 2011-07-25
 - Compile on 5.14 and libpng15.
 - Enhance unicode input on win32.
 - Better libiconv support.

1.30 2011-05-08
 - Compile on 5.13.
 - Compile on 64-bit ActiveState and strawberry builds.
 - Support Prima::codecs::win64.

MANIFEST  view on Meta::CPAN

t/Widget/Size.t
t/Widget/SizeLimits.t
t/Widget/Window.t
t/Widget/ZOrder.t
t/misc/cpan.t
t/misc/fs.t
t/misc/pod.t
t/misc/precision.t
t/misc/syntax.t
unix/app.c
unix/clipboard.c
unix/cocoa.c
unix/color.c
unix/cursor.c
unix/dnd.c
unix/event.c
unix/file.c
unix/font.c
unix/graphics.c
unix/gtk.c
unix/image.c

Prima/Application.pm  view on Meta::CPAN

Result of L<get_printer> method points to an automatically created printer
object, responsible for the system-driven printing. Depending on the operating
system, it is either Prima::Printer, if the system provides GUI printing
capabilities, or generic Prima::PS::Printer, the PostScript document interface.

See L<Prima::Printer> for details.

=item Clipboard

$::application hosts set of Prima::Clipboard objects, created automatically to
reflect the system-provided clipboard IPC functionality. Their number depends
on the system, - under X11 environment there is three clipboard objects, and
only one under Win32.

These are no methods to access these clipboard objects, except fetch() ( or,
the indirect name calling ) - the clipboard objects are named after the system
clipboard names, which are returned by
Prima::Clipboard::get_standard_clipboards.

The default clipboard is named I<Clipboard>, and is accessible via

	my $clipboard = $::application-> Clipboard;

code.

See L<Prima::Clipboard> for details.

=item Help subsystem

The toolkit has a built-in help viewer, that understands perl's native POD (
plain old documentation ) format.  Whereas the viewer functionality itself is
part of the toolkit, and resides in C<Prima::HelpViewer> module, any custom

Prima/Application.pm  view on Meta::CPAN


See also: L<Prima/Stress>.

=item wantUnicodeInput BOOLEAN

Selects if the system is allowed to generate key codes in unicode.  Returns the
effective state of the unicode input flag, which cannot be changed if perl or
operating system do not support UTF8.

If 1, C<Prima::Clipboard::text> property may return UTF8 text from system
clipboards is available.

Default value: 1

=back

=head2 Events

=over

=item Clipboard $CLIPBOARD, $ACTION, $TARGET

With (the only implemented) C<$ACTION> I<copy>, is called whenever another
application requests clipboard data in format C<$TARGET>. This notification is
handled internally to optimize image pasting through the cliboard. Since the
clipboard pasting semantics in Prima is such that data must be supplied to the
clipboard in advance, before another application can request it, there is a
problem which format to use. In order to not encode an image or other complex
data in all possible formats but do that on demand and in the format the other
application wants, this notification can be used.

Only implemented for X11.

=item CopyImage $CLIPBOARD, $IMAGE

The notification stores C<$IMAGE> in clipboard.

=item CopyText $CLIPBOARD, $TEXT

The notification stores C<$TEXT> in clipboard.

=item Die $@, $STACK

Called when an exception occurs inside the event loop C<Prima::run>.  By
default, consults the C<guiException> property, and if it is set, displays the
system message dialog allowing the user to decide when to do next.

=item Idle

Called when the event loop handled all pending events, and
is about to sleep waiting for more.

=item PasteImage $CLIPBOARD, $$IMAGE_REF

The notification queries C<$CLIPBOARD> for image content and stores in
C<$$IMAGE_REF>. Default action is that C<'Image'> format is queried.  On unix,
encoded formats C<'image/bmp'>, C<'image/png'> etc are queried if the default
C<'Image'> is not found.

The C<PasteImage> mechanism is devised to read images from clipboard in GTK
environment.

=item PasteText $CLIPBOARD, $$TEXT_REF

The notification queries C<$CLIPBOARD> for text content and stores in
C<$$TEXT_REF>. Default action is that C<'Text'> format is queried if
C<wantUnicodeInput> is unset. Otherwise, C<'UTF8'> format is queried
beforehand.

The C<PasteText> mechanism is devised to ease defining text unicode/ascii
conversion between clipboard and standard widgets, in a standard way.

=back

=head2 Methods

=over

=item add_startup_notification @CALLBACK

CALLBACK is an array of anonymous subs, which is executed when

Prima/Application.pm  view on Meta::CPAN


Returns the default system font.  The method can be called with a class string
instead of an object instance.

=item get_default_scrollbar_metrics

Returns dimensions of the system scrollbars - width of the standard vertical
scrollbar and height of the standard horizon scrollbar.  The method can be
called with a class string instead of an object instance.

=item get_dnd_clipboard

Returns the predefined special clipboard used as a proxy for drag and drop
interactions.

See also: C<Widget/Drag and drop>, C<Clipboard/is_dnd>.

=item get_default_window_borders BORDER_STYLE = bs::Sizeable

Returns width and height of standard system window border decorations for one
of C<bs::XXX> constants.  The method can be called with a class string instead
of an object instance.

Prima/Classes.pm  view on Meta::CPAN

		push @id, 
			map { $self-> add_notification( $_ => sub { $break = -1 }) }
			qw(MouseLeave MouseClick MouseDown MouseUp Destroy);
		1 while !$break && $::application->yield(1);
		return dnd::None unless $self->alive;
		$self->remove_notification($_) for @id;
		return -1 if $break < 0;
	}

	# data
	my $clipboard = $::application->get_dnd_clipboard;
	if ( exists $opt{text}) {
		$clipboard->text($opt{text});
		$opt{preview} //= $opt{text};
	} elsif ( exists $opt{image}) {
		$clipboard->image($opt{image});
		$opt{preview} //= $opt{image};
	} elsif ( exists $opt{format} and exists $opt{data}) {
		$clipboard->copy($opt{format}, $opt{data});
	} # or else you fill the clipboard yourself

	my @id;
	my %pointers;
	my $last_action = -1;
	$opt{preview} = undef unless $::application->get_system_value(sv::ColorPointer);

	my @max = map { $_ / 8 } $::application->size;
	if ( $opt{preview} && !ref($opt{preview}) ) {
		my @lines = split "\n", $opt{preview};
		my $fh    = $self->font->height;

Prima/Classes.pm  view on Meta::CPAN

		$_-> ($::application) for @_;
	} else {
		push( @startupNotifications, @_);
	}
}

sub setup
{
	my $self = $::application = shift;
	$self-> SUPER::setup;
	for my $clp (Prima::Clipboard-> get_standard_clipboards()) {
		$self-> {$clp} = $self-> insert( qw(Prima::Clipboard), name => $clp)
			unless exists $self-> {$clp};
	}
	$_-> ($self) for @startupNotifications;
	undef @startupNotifications;

	# setup image cliboard transfer routines specific to gtk
	if ( $unix ) {
		my %weights = (
			png  => 4,  # png is lossless
			bmp  => 3,  # bmp is independent on codecs but huge
			tiff => 2,  # tiff is usually lossless
		);
		my %codecs  = map { lc($_-> {fileShortType})  => $_ } @{Prima::Image-> codecs};
		$_->{weight} = $weights{ lc($_-> {fileShortType}) } || 1 for values %codecs;
		my @codecs = map { {
			mime => "image/$_",
			id   => $codecs{$_}->{codecID},
			w    => $codecs{$_}->{weight},
		} } sort { $codecs{$b}->{weight} <=> $codecs{$a}->{weight} } keys %codecs;
		my $clipboard = $self-> Clipboard;
		$clipboard-> register_format($_->{mime}) for @codecs;
		$self-> {GTKImageClipboardFormats} = \@codecs;
	}
}

sub get_fullscreen_image
{
	my $self = shift;
	if ( $^O eq 'darwin') {
		require Prima::sys::XQuartz;
		return Prima::sys::XQuartz::get_fullscreen_image($self);

Prima/Classes.pm  view on Meta::CPAN


sub on_die
{
	my ($self, $err, $stack) = @_;
	return unless $GUI_EXCEPTION;
	require Prima::MsgBox;
	$self->clear_event if
		Prima::MsgBox::signal_dialog($self->name . ' fatal error', $err, $stack) != mb::Abort;
}

sub on_clipboard
{
	my ( $self, $clipboard, $action, $target ) = @_;
	if ($clipboard->format_exists('Image')) {
		if ( my ( $codec ) = grep { $target eq $_->{mime} } @{ $self-> {GTKImageClipboardFormats} // [] }) {
			my ($bits, $handle) = ('');
			my $i = $clipboard->fetch('Image') or return;
			if (open( $handle, '>', \$bits) and $i->save($handle, codecID => $codec->{id})) {
				$clipboard->store($codec->{mime}, $bits);
			}
		}
	}
}

sub on_copy
{
	my ( $self, $format, $clipboard, $data ) = @_;
	$clipboard-> store( $format, $data);
	if ( $format eq 'Image') {
		# store(undef) is a special flag for x11 when data can be provided on demand for this format
		$clipboard->store($_, undef) for map { $_->{mime} } @{ $self-> {GTKImageClipboardFormats} // [] };
	}
}

sub on_formatexists
{
	my ( $self, $format, $clipboard, $ref) = @_;

	if ( $format eq 'Text') {
		if ( $self-> wantUnicodeInput) {
			return $$ref = 'UTF8' if $clipboard-> format_exists( 'UTF8');
		}
		$$ref = $clipboard-> format_exists( $format ) ? $format : undef;
	} elsif ( $format eq 'Image') {
		$$ref = undef;
		return $$ref = 'Image' if $clipboard-> format_exists( 'Image');
		my $codecs = $self-> {GTKImageClipboardFormats} or return;
		my %formats = map { $_ => 1 } $clipboard-> get_formats;
		my @codecs  = grep { $formats{$_->{mime}} } @$codecs or return;
		$$ref = $codecs[0]->{mime} if $clipboard-> format_exists($codecs[0]->{mime});
	} else {
		$$ref = $clipboard-> format_exists( $format ) ? $format : undef;
	}
	undef;
}

sub on_paste
{
	my ( $self, $format, $clipboard, $ref) = @_;

	if ( $format eq 'Text') {
		if ( $self-> wantUnicodeInput) {
			return if defined ( $$ref = $clipboard-> fetch( 'UTF8'));
		}
		$$ref = $clipboard-> fetch( 'Text');
	} elsif ( $format eq 'Image') {
		my $codecs  = $self-> {GTKImageClipboardFormats} or goto DEFAULT;
		my %formats = map  { $_ => 1 } $clipboard-> get_formats;
		my @codecs  = grep { $formats{$_->{mime}} && $_->{w} > 1 } @$codecs or goto DEFAULT;
		my $data    = $clipboard-> fetch($codecs[0]->{mime});
		return unless defined $data;

		my $handle;
		open( $handle, '<', \$data) or return;

		local $@;
		$$ref = Prima::Image-> load($handle, loadExtras => 1 );
	} else {
	DEFAULT:
       		$$ref = $clipboard-> fetch( $format);
	}
	undef;
}

1;

=pod

=head1 NAME

Prima/Edit.pm  view on Meta::CPAN

			[ DupLine        => 0, 0, '^K',          sub {$_[0]-> insert_line($_[0]-> cursorY, $_[0]-> get_line($_[0]-> cursorY)) }],
			[ DeleteBlock    => 0, 0, '@D',          q(delete_block) ],
			[ SplitLine      => 0, 0, kb::Enter,     sub {$_[0]-> split_line if $_[0]-> {wantReturns}}],
			[ SplitLine2     => 0, 0, km::Ctrl|kb::Enter,sub {$_[0]-> split_line if !$_[0]-> {wantReturns}}],
# block keys
			[ CancelBlock    => 0, 0, '@U',          q(cancel_block)],
			[ MarkVertical   => 0, 0, '@B',          q(mark_vertical)],
			[ MarkHorizontal => 0, 0, '@L',          q(mark_horizontal)],
			[ CopyBlock      => 0, 0, '@C',          q(copy_block)],
			[ OvertypeBlock  => 0, 0, '@O',          q(overtype_block)],
# clipboard keys
			[ Cut            => 0, 0, km::Shift|kb::Delete, q(cut)],
			[ Copy           => 0, 0, km::Ctrl |kb::Insert, q(copy)],
			[ Paste          => 0, 0, km::Shift|kb::Insert, q(paste)],
			[ CutMS          => 0, 0, '^X', q(cut)],
			[ CopyMS         => 0, 0, '^C', q(copy)],
			[ PasteMS        => 0, 0, '^V', q(paste)],
# undo
			[ Undo            => 0, 0, km::Alt|kb::Backspace, q(undo)],
			[ Redo            => 0, 0, '^R', q(redo)],
		],

Prima/Edit.pm  view on Meta::CPAN

sub on_parsesyntax { $_[0]-> {syntaxer}-> (@_); }

sub on_dragbegin
{
	my $self = shift;
	$self->{drop_transaction} = [];
}

sub on_dragover
{
	my ($self, $clipboard, $action, $mod, $x, $y, $ref) = @_;
	$ref->{allow} = 1;
	my $dt;
	if ( $dt = $self->{drop_transaction} and @$dt) {
		$self-> invalidate_rect(@$dt);
	}
	$self-> cursor( $self-> point2xy( $x, $y));
	my @cp = $self->cursorPos;
	my @cs = $self->cursorSize;
	$self->{drop_transaction} = [@cp, $cp[0] + $self->{defcw}, $cp[1] + $cs[1]];
	$self-> invalidate_rect(@{ $self->{drop_transaction} });
}

sub on_dragend
{
	my ($self, $clipboard, $action, $mod, $x, $y, $ref) = @_;
	my $dt;
	if ( $dt = $self->{drop_transaction} and @$dt ) {
		$self-> invalidate_rect(@$dt);
	}
	delete $self->{drop_transaction};
	return unless $clipboard;
	my $cap = $clipboard->text;
	$self->insert_text($cap) if defined $cap;
}

sub set_block_type
{
	my ( $self, $bt) = @_;
	return if $bt == $self-> {blockType};
	$self-> push_group_undo_action('blockType', $self-> {blockType});
	$self-> {blockType} = $bt;
	return unless $self-> has_selection;

Prima/Edit.pm  view on Meta::CPAN

Default key: Alt+U

=item change_locked

Returns 1 if the logical locking is on, 0 if it is off.

See also L<lock_change>.

=item copy

Copies the selected text, if any, to the clipboard.

Default key: Ctrl+Insert

=item copy_block

Copies the selected text and inserts it into the cursor position, according to
the L<blockType> value.

Default key: Alt+C

Prima/Edit.pm  view on Meta::CPAN

Default key: PageUp

=item cursor_shift_key [ ACCEL_TABLE_ITEM ]

Performs action of the cursor movement, bound to ACCEL_TABLE_ITEM action
( defined in C<accelTable> or C<accelItems> property ), and extends the
selection block along the cursor movement. Not called directly.

=item cut

Cuts the selected text into the clipboard.

Default key: Shift+Delete

=item delete_block

Removes the selected text.

Default key: Alt+D

=item delete_char [ REPEAT = 1 ]

Prima/Edit.pm  view on Meta::CPAN


=item overtype_block

Copies the selected text and overwrites the text next to the cursor position, according to
the L<blockType> value.

Default key: Alt+O

=item paste

Copies text from the clipboard and inserts it in the cursor position.

Default key: Shift+Insert

=item realize_panning

Performs deferred widget panning, activated by setting C<{delayPanning}> to 1.
The deferred operations are those performed by L<offset> and L<topLine>.

=item set_line LINE_ID, TEXT, [ OPERATION, FROM, LENGTH ]

Prima/InputLine.pm  view on Meta::CPAN

}

sub on_dragbegin
{
	my $self = shift;
	$self->{drop_transaction} = 1;
}

sub on_dragend
{
	my ( $self, $clipboard, $action, $modmap, $x, $y, $ref) = @_;
	$self->{drop_transaction} = 0;
	return unless $clipboard;
	my $cap = $clipboard->text;
	$self->text($cap) if defined $cap;
}

sub select_all { $_[0]-> selection(0,-1); }

sub autoHeight
{
	return $_[0]-> {autoHeight} unless $#_;
	$_[0]-> {autoHeight} = $_[1];
	$_[0]-> check_auto_size;

Prima/InputLine.pm  view on Meta::CPAN

	run Prima;

=for podview <img src="inputline.gif">

=for html <p><img src="https://raw.githubusercontent.com/dk/Prima/master/pod/Prima/inputline.gif">

=head1 DESCRIPTION

The class provides basic functionality of an input line,
including hidden input, read-only state, selection, and
clipboard operations. The input line text data is
contained in L<text> property.

=head1 API

=head2 Events

=over

=item Change

Prima/InputLine.pm  view on Meta::CPAN

=over

=item blink %options

Produces a short blink by setting background to red color.
Can be used to signal invalid input, f ex from C<on_validate>.
C<%options> allows C<backColor> and C<color> entries.

=item copy

Copies the selected text, if any, to the clipboard.

Default key: Ctrl+Insert

=item cut

Cuts the selected text into the clipboard.

Default key: Shift+Delete

=item delete

Removes the selected text.

Default key: Delete

=item paste

Copies text from the clipboard and inserts it in the cursor position.

Default key: Shift+Insert

=item select_all

Selects all text

=back

=head2 Bi-directional input and output

Prima/ScrollBar.pm  view on Meta::CPAN

}

sub on_dragbegin
{
	my $self = shift;
	$self->{drop_transaction} = [0,0];
}

sub on_dragover
{
	my ($self, $clipboard, $action, $mod, $x, $y, $ref) = @_;
	$ref->{allow} = 0;
	if ( $self-> {mouseTransaction} ) {
		$self->notify(q(MouseMove), 0, $x, $y);
		@{$self->{drop_transaction}} = [$x, $y];
	} else {
		$self->notify(q(MouseDown), mb::Left, 0, $x, $y);
	}
}

sub on_dragend
{
	my ($self, $clipboard, $action, $mod, $x, $y, $ref) = @_;
	$ref->{allow} = 0;
	$self->notify(q(MouseUp), mb::Left, 0, $x, $y);
	undef $self->{drop_transaction};
}

sub reset
{
	my $self = $_[0];

	$self-> { b1} -> { enabled} = $self-> { value} > $self-> { min};

Prima/Sliders.pm  view on Meta::CPAN

	$z *= $self-> {pageStep} if $mod & km::Ctrl;
	my $value = $self-> value;
	$self-> value( $value + $z * $self-> {step});
	$self-> value( $z > 0 ? $self-> min : $self-> max)
		if $self-> {circulate} && ( $self-> value == $value);
	$edit-> clear_event;
}

sub InputLine_DragEnd
{
	my ( $self, $edit, $clipboard, $action, $mod, $x, $y, $ref ) = @_;
	return unless $clipboard;
	my $text = $clipboard->text;
	return unless defined $text;
	$text =~ s/^\s+//;
	$text =~ s/\s+$//;
	return if $text =~ /^-?\d+(\.\d+)?$/ and $text >= $self->min and $text <= $self->max;
	$edit->clear_event;
	$edit->on_dragend(undef, $action, $mod, $x, $y, $ref);
	$ref->{allow} = 0;
}

sub Spin_Increment

Prima/TextView.pm  view on Meta::CPAN

=head2 Text selection

The text selection is performed automatically when the user selects a text
region with a mouse. The selection is stored in (TEXT_OFFSET,BLOCK)
coordinate pair, and is accessible via the C<::selection> property.
If its value is assigned to (-1,-1,-1,-1) this indicates that there is
no selection. For convenience the C<has_selection> method is introduced.

Also, C<get_selected_text> returns the text within the selection
(or undef with no selection ), and C<copy> copies automatically
the selected text into the clipboard. The latter action is bound to
C<Ctrl+Insert> key combination.

A block with TEXT_OFFSET set to -1 will be treated as not containing any text,
and therefore will not be able to get selected.

=head2 Event rectangles

Partly as an option for future development, partly as a hack a
concept of 'event rectangles' was introduced. Currently, C<{contents}>
private variable points to an array of objects, equipped with

Prima/VB/Classes.pm  view on Meta::CPAN

The popup object must be named C<'AltPopup'>.

=back

=head2 Events

=over

=item Load

Called when the widget is loaded from a file or the clipboard.

=back

=head1 Prima::VB::Types::generic

Root of all type classes.

A type class can be used with
and without object instance. The instantiated class
contains reference to ID string, which is a property

Prima/VB/VB.pl  view on Meta::CPAN

have to be saved.

=back

=item Edit

=over

=item Copy

Copies the selected widgets into the clipboard, so they can be
inserted later by using L<Paste> command.
The form window can not be copied.

=item Paste

Reads the information, put by the builder L<Copy> command into the
clipboard, and inserts the widgets into the form window. The child-parent
relation is kept by names of the widgets; if the widget with the name of
the parent of the clipboard-read widgets is not found, the widgets are inserted
into the form window.
The form window is not affected by this command.

=item Delete

Deletes the selected widgets.
The form window can not be deleted.

=item Select all

class/Application.cls  view on Meta::CPAN

	method void   end_paint_info();
	method SV*    fonts( char * name = "", char * encoding = "");
	method SV*    font_encodings( char * encoding = "");
	static SV*    font_mapper_action( char * dummy, HV * profile);
	method Handle get_active_window();
	static Font   get_caption_font( char * dummy = "");
	static int    get_default_cursor_width( char * dummy = "");
	static Font   get_default_font( char * dummy = "");
	static Point  get_default_scrollbar_metrics( char * dummy = "");
	static Point  get_default_window_borders( char * dummy = "", int borderStyle = bsSizeable);
	method Handle get_dnd_clipboard() => apc_dnd_get_clipboard;
	method Handle get_focused_widget();
	method Handle get_widget_from_handle( SV * handle);
	method Handle get_hint_widget();
	method Rect   get_indents() => apc_application_get_indents;
	static Font   get_message_font( char * dummy = "");
	method SV *   get_monitor_rects();
	method Handle get_modal_window( int modalFlag = mtExclusive, Bool topMost = true);
	method Point  get_scroll_rate();
	static SV *   get_system_info( char * dummy = "");
	static int    get_system_value( char * dummy = "", int sysValue = 0);

class/Clipboard.c  view on Meta::CPAN

	void                          *data;
	Bool                           written;
	Bool                           success;
} ClipboardFormatReg, *PClipboardFormatReg;

static SV * text_server  ( Handle self, PClipboardFormatReg, int, SV *);
static SV * utf8_server  ( Handle self, PClipboardFormatReg, int, SV *);
static SV * image_server ( Handle self, PClipboardFormatReg, int, SV *);
static SV * binary_server( Handle self, PClipboardFormatReg, int, SV *);

static int clipboards = 0;
static int formatCount = 0;
static Bool protect_formats = false;
static PClipboardFormatReg formats = NULL;

void *
Clipboard_register_format_proc( Handle self, char * format, void * serverProc);

void
Clipboard_init( Handle self, HV * profile)
{
	inherited init( self, profile);
	if ( !apc_clipboard_create(self))
		croak( "Cannot create clipboard");
	if (clipboards == 0) {
		Clipboard_register_format_proc( self, "Text",  (void*)text_server);
		Clipboard_register_format_proc( self, "Image", (void*)image_server);
		Clipboard_register_format_proc( self, "UTF8",  (void*)utf8_server);
		protect_formats = 1;
	}
	clipboards++;
	CORE_INIT_TRANSIENT(Clipboard);
}

void
Clipboard_done( Handle self)
{
	clipboards--;
	if ( clipboards == 0) {
		protect_formats = 0;
		while( formatCount)
			my-> deregister_format( self, formats-> id);
	}
	apc_clipboard_destroy(self);
	inherited done( self);
}

void Clipboard_handle_event( Handle self, PEvent event)
{
	switch ( event-> cmd)
	{
		case cmClipboard: {
			var-> openCount++;
			C_APPLICATION-> push_event( prima_guts.application);

class/Clipboard.c  view on Meta::CPAN

	formats = fr;
}

Bool
Clipboard_open( Handle self)
{
	var-> openCount++;
	if ( var-> openCount > 1) return true;

	first_that( self, (void*) reset_written, NULL);
	return apc_clipboard_open( self);
}

void
Clipboard_close( Handle self)
{
	PClipboardFormatReg text, utf8;
	if ( var-> openCount <= 0) {
		var-> openCount = 0;
		return;
	}

class/Clipboard.c  view on Meta::CPAN

				char c = ( u < 0x7f) ? u : '?';
				src += charlen;
				bytelen -= charlen;
				sv_catpvn( text_sv, &c, 1);
				if ( charlen == 0 ) break;
			}
			text-> server( self, text, cefFetch, text_sv);
			sv_free( text_sv);
		}
	}
	apc_clipboard_close( self);
}

Bool
Clipboard_format_exists( Handle self, char * format)
{
	Bool ret;
	PClipboardFormatReg fr = first_that( self, (void*)find_format, format);
	if ( !fr) return false;
	my-> open( self);
	ret = apc_clipboard_has_format( self, fr-> sysId);
	my-> close( self);
	return ret;
}

SV *
Clipboard_fetch( Handle self, char * format)
{
	SV * ret;
	PClipboardFormatReg fr = first_that( self, (void*)find_format, format);
	my-> open( self);

class/Clipboard.c  view on Meta::CPAN


Bool
Clipboard_store( Handle self, char * format, SV * data)
{
	PClipboardFormatReg fr = first_that( self, (void*)find_format, format);

	if ( !fr) return false;
	if ( !my-> open( self)) return false;
	if ( var->  openCount == 1) {
		first_that( self, (void*) reset_written, NULL);
		apc_clipboard_clear( self);
	}
	fr-> server( self, fr, cefStore, data);
	my-> close( self);
	return fr-> success;
}

void
Clipboard_clear( Handle self)
{
	my-> open( self);
	first_that( self, (void*) reset_written, NULL);
	apc_clipboard_clear( self);
	my-> close( self);
}

SV *
Clipboard_get_handle( Handle self)
{
	char buf[ 256];
	snprintf( buf, 256, PR_HANDLE_FMT, apc_clipboard_get_handle( self));
	return newSVpv( buf, 0);
}


Bool
Clipboard_register_format( Handle self, char * format)
{
	void * proc;
	if (( strlen( format) == 0)          ||
		( strcmp( format, "Text") == 0)  ||

class/Clipboard.c  view on Meta::CPAN


	if ( items != 1 && items != 2)
		croak ("Invalid usage of Clipboard.get_formats");
	SP -= items;
	self = gimme_the_mate( ST( 0));
	if ( self == NULL_HANDLE)
		croak( "Illegal object reference passed to Clipboard.get_formats");
	include_unregistered = (items > 1) ? SvBOOL(ST(1)) : false;
	my-> open( self);
	if ( include_unregistered ) {
		PList list = apc_clipboard_get_formats(self);
		if (list) for ( i = 0; i < list->count; i++) {
			XPUSHs( sv_2mortal( newSVpv( (char*) list->items[i], 0)));
			free( (void*) list->items[i] );
		}
		free(list);
	} else {
		PClipboardFormatReg list = formats;
		for ( i = 0; i < formatCount; i++) {
			if ( !apc_clipboard_has_format( self, list[ i]. sysId)) continue;
			XPUSHs( sv_2mortal( newSVpv( list[ i]. id, 0)));
		}
	}
	my-> close( self);
	PUTBACK;
}

XS( Clipboard_get_registered_formats_FROMPERL)
{
	dXSARGS;

class/Clipboard.c  view on Meta::CPAN

	self = gimme_the_mate( ST( 0));
	if ( self == NULL_HANDLE)
		croak( "Illegal object reference passed to Clipboard.get_registered_formats");
	list = formats;
	EXTEND( sp, formatCount);
	for ( i = 0; i < formatCount; i++)
		PUSHs( sv_2mortal( newSVpv( list[ i]. id, 0)));
	PUTBACK;
}

XS( Clipboard_get_standard_clipboards_FROMPERL)
{
	dXSARGS;
	int i;
	PList l;

	(void)ax; SP -= items;
	l = apc_get_standard_clipboards();
	if ( l && l-> count > 0) {
		EXTEND( sp, l-> count);
		for ( i = 0; i < l-> count; i++) {
			char *cc = (char *)list_at( l, i);
			PUSHs( sv_2mortal( newSVpv(cc, 0)));
		}
	}
	if (l) {
		list_delete_all( l, true);
		plist_destroy( l);
	}
	PUTBACK;
}

void Clipboard_get_formats                       ( Handle self, Bool unr) { warn("Invalid call of Clipboard::get_formats"); }
void Clipboard_get_formats_REDEFINED             ( Handle self, Bool unr) { warn("Invalid call of Clipboard::get_formats"); }
void Clipboard_get_registered_formats            ( Handle self) { warn("Invalid call of Clipboard::get_registered_formats"); }
void Clipboard_get_registered_formats_REDEFINED  ( Handle self) { warn("Invalid call of Clipboard::get_registered_formats"); }
void Clipboard_get_standard_clipboards               ( Handle self) { warn("Invalid call of Clipboard::get_standard_clipboards"); }
void Clipboard_get_standard_clipboards_REDEFINED     ( Handle self) { warn("Invalid call of Clipboard::get_standard_clipboards"); }

static SV *
text_server( Handle self, PClipboardFormatReg instance, int function, SV * data)
{
	ClipboardDataRec c;

	switch( function) {
	case cefInit:
		return ( SV *) cfText;

	case cefFetch:
		if ( apc_clipboard_get_data( self, cfText, &c)) {
			data = newSVpv(( char*) c. data, c. length);
			free( c. data);
			return data;
		}
		break;

	case cefStore:
		if ( prima_is_utf8_sv( data)) {
			/* jump to UTF8. close() will later downgrade data to ascii, if any */
			instance = formats + cfUTF8;
			return instance-> server( self, instance, cefStore, data);
		} else {
			STRLEN l;
			c. data   = ( Byte*) SvPV( data, l);
			c. length = l;
			instance-> success = apc_clipboard_set_data( self, cfText, &c);
			instance-> written = true;
		}
		break;
	}
	return NULL_SV;
}

static SV *
utf8_server( Handle self, PClipboardFormatReg instance, int function, SV * data)
{
	ClipboardDataRec c;
	STRLEN l;

	switch( function) {
	case cefInit:
		return ( SV *) cfUTF8;

	case cefFetch:
		if ( apc_clipboard_get_data( self, cfUTF8, &c)) {
			data = newSVpv(( char*) c. data, c. length);
			SvUTF8_on( data);
			free( c. data);
			return data;
		}
		break;

	case cefStore:
		c. data   = ( Byte*) SvPV( data, l);
		c. length = l;
		instance-> success = apc_clipboard_set_data( self, cfUTF8, &c);
		instance-> written = true;
		break;
	}
	return NULL_SV;
}

static SV *
image_server( Handle self, PClipboardFormatReg instance, int function, SV * data)
{
	ClipboardDataRec c;
	switch( function) {
	case cefInit:
		return ( SV *) cfBitmap;
	case cefFetch:
		if ( apc_clipboard_get_data( self, cfBitmap, &c))
			return newSVsv( PImage(c. image)->  mate);
		break;
	case cefStore:
		c. image = gimme_the_mate( data);

		if ( !kind_of( c. image, CImage)) {
			warn("Not an image passed to clipboard");
			return NULL_SV;
		}
		instance-> success = apc_clipboard_set_data( self, cfBitmap, &c);
		instance-> written = true;
		break;
	}
	return NULL_SV;
}

static SV *
binary_server( Handle self, PClipboardFormatReg instance, int function, SV * data)
{
	ClipboardDataRec c;
	switch( function) {
	case cefInit:
		return ( SV*) apc_clipboard_register_format( self, instance-> id);
	case cefDone:
		apc_clipboard_deregister_format( self, instance-> sysId);
		break;
	case cefFetch:
		if ( apc_clipboard_get_data( self, instance-> sysId, &c)) {
			SV * ret = newSVpv((char*) c. data, c. length);
			free( c. data);
			return ret;
		}
		break;
	case cefStore:
		if ( !SvOK(data)) {
			c. data = NULL;
			c. length = -1;
		} else {
			STRLEN l;
			c. data   = ( Byte*) SvPV( data, l);
			c. length = l;
		}
		instance-> success = apc_clipboard_set_data( self, instance-> sysId, &c);
		instance-> written = true;
		break;
	}
	return NULL_SV;
}

#ifdef __cplusplus
}
#endif

class/Clipboard.cls  view on Meta::CPAN


	method void   clear();
	method void   close();
	method void   deregister_format( char * format);
	method void   done();
	method SV *   fetch( char * format);
	method Bool   format_exists( char * format);
	method SV *   get_handle();
	public void   get_formats( Bool include_unregistered = 0 );
	public void   get_registered_formats();
	public void   get_standard_clipboards();
	c_only void   handle_event ( PEvent event);
	method void   init( HV * profile);
	method Bool   is_dnd() => apc_clipboard_is_dnd;
	method Bool   open();
	method Bool   register_format( char * format);
	method Bool   store( char * format, SV * data);
	c_only Bool   validate_owner( Handle * newOwner, HV * profile);
}

class/Widget/events.c  view on Meta::CPAN


static Bool
dnd_event_wanted(Handle self, PEvent event)
{
	Bool r;
	SV * ret;
	if ( var-> dndAware == NULL) return false;
	if ( strcmp(var->dndAware, "1") == 0) return true;
	ENTER;
	SAVETMPS;
	ret = call_perl( event->dnd.clipboard, "has_format", "<s", var->dndAware);
	r = ret ? SvTRUE( ret) : false;
	FREETMPS;
	LEAVE;
	return r;
}

static void
handle_drag_begin( Handle self, PEvent event)
{
	enter_method;
	if ( !dnd_event_wanted(self, event)) {
		opt_clear(optDropSession);
		return;
	}
	opt_set(optDropSession);
	my-> notify( self, "<sHiiPH", "DragBegin",
		event-> dnd. clipboard,
		event-> dnd. action,
		event-> dnd. modmap,
		event-> dnd. where,
		event-> dnd. counterpart
	);
}

static void
handle_drag_over( Handle self, PEvent event)
{

class/Widget/events.c  view on Meta::CPAN

		event-> dnd.pad.height = size.y;
		return;
	}

	profile = newHV();
	ref = newRV_noinc((SV*) profile);

	pset_i(allow,1);
	pset_i(action,dndCopy);
	my-> notify( self, "<sHiiPHS", "DragOver",
		event-> dnd. clipboard,
		event-> dnd. action,
		event-> dnd. modmap,
		event-> dnd. where,
		event-> dnd. counterpart,
		ref
	);

	event-> dnd. allow  = pexist(allow)  ? pget_i(allow)  : 1;
	event-> dnd. action = pexist(action) ? pget_i(action) : dndCopy;
	memset( &event-> dnd.pad, 0, sizeof(Rect));

class/Widget/events.c  view on Meta::CPAN

		return;
	}
	opt_clear(optDropSession);

	profile = newHV();
	ref = newRV_noinc((SV*) profile);

	pset_i(allow, 1);
	pset_i(action, event->dnd.action);
	my-> notify( self, "<sHiiPHS", "DragEnd", 
		event-> dnd. allow ? event-> dnd.clipboard : NULL_HANDLE, 
		event-> dnd. action,
		event-> dnd. modmap,
		event-> dnd. where,
		event-> dnd. counterpart,
		ref
	);
	event-> dnd. allow  = pexist(allow)  ? pget_i(allow)  : 1;
	event-> dnd. action = pexist(action) ? pget_i(action) : dndCopy;

	sv_free(ref);

examples/buttons2.pl  view on Meta::CPAN

=pod

=head1 NAME

examples/buttons2.pl - Prima button widgets

=head1 FEATURES

Demonstrates the variety of built-in buttons functionality.
Note the "Bits for toolbar" button, which copies and
pastes its image into the clipboard.

=cut

use strict;
use warnings;

use Prima qw(Buttons StdBitmap Application);

my $w = Prima::MainWindow-> create(
	text=> "Handmade buttons",

examples/buttons2.pl  view on Meta::CPAN

$w-> insert( Button =>
	origin     => [ 130, 10],
	text    => "Bits for toolbar",
	image      => $i,
	glyphs     => 2,
	vertical   => 1,
	height     => 120,
	imageScale => 3,
	selectable => 0,
	flat       => 1,
	hint       => "Pressing this button copies its image\n into clipboard",
	onClick    => sub {
		my $self = $_[0];
		unless ( $self-> get_shift_state & km::Ctrl) {
			my $i = Prima::Image-> create(
				width  => $self-> width,
				height => $self-> height,
				font   => $self-> font,
				type   => im::Byte,
			);
			$i-> begin_paint;

include/apricot.h  view on Meta::CPAN


#ifdef DNDEvent
#undef DNDEvent
#endif

typedef struct _DNDEvent {
	int    cmd;
	int    allow;
	int    action;
	int    modmap;
	Handle clipboard;
	Point  where;
	Box    pad;
	Handle counterpart;
} DNDEvent, *PDNDEvent;

#ifdef GenericEvent
#undef GenericEvent
#endif

typedef struct _GenericEvent {

include/apricot.h  view on Meta::CPAN

#define cfUTF8     2
#define cfCustom   3

typedef struct {
	Handle image;
	Byte * data;
	IV length;
} ClipboardDataRec, *PClipboardDataRec;

extern PList
apc_get_standard_clipboards( void);

extern Bool
apc_clipboard_create( Handle self);

extern Bool
apc_clipboard_destroy( Handle self);

extern Bool
apc_clipboard_open( Handle self);

extern Bool
apc_clipboard_close( Handle self);

extern Bool
apc_clipboard_clear( Handle self);

extern PList
apc_clipboard_get_formats( Handle self);

extern Bool
apc_clipboard_get_data( Handle self, Handle id, PClipboardDataRec c);

extern ApiHandle
apc_clipboard_get_handle( Handle self);

extern Bool
apc_clipboard_has_format( Handle self, Handle id);

extern Bool
apc_clipboard_set_data( Handle self, Handle id, PClipboardDataRec c);

extern Handle
apc_clipboard_register_format( Handle self, const char *format);

extern Bool
apc_clipboard_deregister_format( Handle self, Handle id);

extern Bool
apc_clipboard_is_dnd( Handle self);

/* Drag and drop */

#define DND(const_name) CONSTANT(dnd,const_name)
START_TABLE(dnd,UV)
#define    dndNone               0x00
DND(None)
#define    dndCopy               0x01
DND(Copy)
#define    dndMove               0x02

include/apricot.h  view on Meta::CPAN

extern Bool
apc_dnd_get_aware( Handle self );

extern Bool
apc_dnd_set_aware( Handle self, Bool is_target );

extern int
apc_dnd_start( Handle self, int actions, Bool default_pointers, Handle * counterpart);

extern Handle
apc_dnd_get_clipboard( Handle self );

/* Menus & popups */

typedef struct _MenuItemReg {   /* Menu item registration record */
	char * variable;             /* perl variable name */
	char * text;                 /* menu text */
	char * accel;                /* accelerator text */
	int    key;                  /* accelerator key, kbXXX */
	int    id;                   /* unique id */
	char * perlSub;              /* sub name */

include/unix/guts.h  view on Meta::CPAN

#endif
} CustomPointer;

#define MAX_UNICODE_HEX_LENGTH 6

typedef struct _UnixGuts
{
	/* Event management */
	Time                         click_time_frame;
	Time                         double_click_time_frame;
	PHash                        clipboards;
	PHash                        clipboard_xfers;
	Atom *                       clipboard_formats;
	int                          clipboard_formats_count;
	long                         clipboard_event_timeout;
	fd_set                       excpt_set;
	PList                        files;
	long                         handled_events;
	XButtonEvent                 last_button_event;
	XButtonEvent                 last_click;
	unsigned int                 last_mouseclick_number;
	Time                         last_time;
	int (*                       main_error_handler   )(Display*,XErrorEvent*);
	int                          max_fd;
	int                          modal_count;

include/unix/guts.h  view on Meta::CPAN

	unsigned int			debug;
	Bool                         icccm_only;
	Bool                         net_wm_maximization;
	int                          net_wm_maximize_HORZ_vs_HORIZ;
	Bool                         net_wm_fullscreen;
	int                          use_gtk;
	int                          use_quartz;
	Bool                         use_harfbuzz;
	Bool                         is_xwayland;
	/* DND: Common */
	Handle                       xdnd_clipboard;
	int                          xdnd_disabled;
	/* DND: Receiver */
	Handle                       xdndr_receiver, xdndr_widget, xdndr_last_target;
	XWindow                      xdndr_source;
	long                         xdndr_timestamp;
	int                          xdndr_version, xdndr_last_action, xdndr_action_list_cache;
	Bool                         xdndr_last_drop_response;
	Box                          xdndr_suppress_events_within; /* in prima coordinates */
	/* DND: Sender */
	Handle                       xdnds_widget;

include/unix/guts.h  view on Meta::CPAN

#define CF_32        (sizeof(long)*8)        /* 32-bit properties are hacky */

typedef struct {
	IV size;
	unsigned char * data;
	Handle image;
	Atom name;
	Bool immediate;
} ClipboardDataItem, *PClipboardDataItem;

typedef struct _clipboard_sys_data
{
	COMPONENT_SYS_DATA;
	Atom                 selection;
	Atom                 target;
	Bool                 opened;
	Bool                 inside_event;
	Bool                 need_write;
	Handle               selection_owner;
	PClipboardDataItem   external;
	PClipboardDataItem   internal;

include/unix/guts.h  view on Meta::CPAN

} ClipboardXfer;

typedef unsigned char ClipboardXferKey[sizeof(XWindow)+sizeof(Atom)];

#define CLIPBOARD_XFER_KEY(key,window,property) \
	memcpy(key,&window,sizeof(XWindow));\
	memcpy(((unsigned char*)key) + sizeof(XWindow),&property,sizeof(Atom))

typedef union _unix_sys_data
{
	ClipboardSysData             clipboard;
	struct {
		COMPONENT_SYS_DATA;
	}                            component;
	DrawableSysData              drawable;
	MenuSysData                  menu;
	TimerSysData                 timer;
	RegionSysData                region;
} UnixSysData, *PUnixSysData;

#define DISP		(pguts-> display)

include/unix/guts.h  view on Meta::CPAN

extern void
prima_get_fill_pattern_offsets( Handle self, int * x, int * y );

extern void
prima_rebuild_watchers( void);

extern void
prima_release_gc( PDrawableSysData);

extern Bool
prima_init_clipboard_subsystem( char * error_buf);

extern Bool
prima_init_font_subsystem( char * error_buf);

extern Bool
prima_font_subsystem_set_option( char *, char *);

extern Bool
prima_init_color_subsystem( char * error_buf);

include/unix/guts.h  view on Meta::CPAN

#define RPS_ERROR    3

extern Bool
prima_handle_dnd_event( Handle self, XEvent *xev);

extern int
prima_read_property( XWindow window, Atom property, Atom * type, int * format,
	unsigned long * size, unsigned char ** data, Bool delete_property);

extern void
prima_clipboard_kill_item( PClipboardDataItem item, Handle id);

extern void
prima_detach_xfers( PClipboardSysData XX, Handle id, Bool clear_original_data);

extern void
prima_clipboard_query_targets( Handle self );

extern int
prima_clipboard_fill_targets( Handle self);

extern void
prima_update_dnd_aware( Handle self );

extern Cursor
prima_get_cursor(Handle self);

extern void
prima_paint_text_background( Handle self, Point * p, int x, int y );

include/win32/win32guts.h  view on Meta::CPAN

	DWORD          version;              // GetVersion() cached result
	Point          cmDOUBLECLK;          // cached SM_CxDOUBLECLK values
	int            mouse_timer;          // is mouse timer started
	Bool           popup_active;         // flag to avoid double popup activation
	Bool           pointer_invisible;
	HWND           console;              // win32-bound console window
	Bool           dont_xlate_message;   // one-time stopper to TranslateMessage() call
	int            utf8_prepend_0x202D;  // newer windows do automatic bidi conversion, this is to cancel it
	WCHAR *      (*alloc_utf8_to_wchar_visual)(const char*,int,int*);
	ULONG_PTR      gdiplus_token;        // GDI+ handle
	Handle         clipboards[2];
	Bool           ole_initialized;
	void*          dnd_data_sender;      // IDropTarget.DragEnter.DataObject dnd storage object
	void*          dnd_data_receiver;    // CLIPBOARD_DND storage object
	Bool           dnd_inside_event;     // to distinguish whether the clipboard is read-only or not
	Bool           dnd_default_cursors;
	void*          drag_source;          // not null if dragging
	Handle         drag_source_widget;   //
	Handle         drag_target;          // last successful drop
	WORD           language_id;          // default shaping language
	char           language_descr[32];
	Bool           application_stop_signal;
	long           apc_error;
	Bool           wc2mb_is_fragile;     // cannot properly process current ACP

include/win32/win32guts.h  view on Meta::CPAN

extern void         aa_free_arena(Handle self, Bool for_reuse);
extern WCHAR *      alloc_utf8_to_wchar( const char * utf8, int length, int * mb_len);
extern WCHAR *      alloc_utf8_to_wchar_visual( const char * utf8, int length, int * mb_len);
extern WCHAR *      alloc_ascii_to_wchar( const char * text, int *length);
extern char *       alloc_wchar_to_utf8( WCHAR * src, int * len );
extern int          apcUpdateWindow( HWND wnd );
extern Bool         add_font_to_hash( const PFont key, const PFont font, Bool addSizeEntry);
extern char *       cf2name( UINT cf );
extern void         char2wchar( WCHAR * dest, char * src, int lim);
extern void         cleanup_gc_stack(Handle self, Bool all);
extern Bool         clipboard_get_data(int cfid, PClipboardDataRec c, void * p1, void * p2);
extern void         cm_squeeze_palette( PRGBColor source, int srcColors, PRGBColor dest, int destColors);
extern Bool         create_font_hash( void);
extern Bool         cursor_update( Handle self);
extern HDC          dc_alloc( void);
extern void         dc_free( void);
extern HDC          dc_compat_alloc( HDC compatDC);
extern void         dc_compat_free( void);
extern void         dbm_recreate( Handle self);
extern Bool         destroy_font_hash( void);
extern Bool         dnd_clipboard_create(void);
extern void         dnd_clipboard_destroy(void);
extern Bool         dnd_clipboard_open(void);
extern Bool         dnd_clipboard_close(void);
extern Bool         dnd_clipboard_clear(void);
extern PList        dnd_clipboard_get_formats(void);
extern Bool         dnd_clipboard_get_data( Handle id, PClipboardDataRec c);
extern Bool         dnd_clipboard_has_format( Handle id);
extern Bool         dnd_clipboard_set_data( Handle id, PClipboardDataRec c);
extern PList        dnd_clipboard_get_formats();
extern void         dpi_change(void);
extern char *       err_msg( DWORD errId, char * buffer);
extern char *       err_msg_gplus( GpStatus errId, char * buffer);
extern Bool         file_process_events(int cmd, WPARAM param1, LPARAM param2);
extern void         file_subsystem_done( void);
extern Bool         file_subsystem_init( void);
extern PDCFont      font_alloc( Font * data);
extern void         font_change( Handle self, Font * font);
extern void         font_clean( void);
extern void         font_font2logfont( Font * font, LOGFONTW * lf);

pod/Prima/Clipboard.pod  view on Meta::CPAN

=head1 NAME

Prima::Clipboard - GUI interprocess data exchange

=head1 DESCRIPTION

Prima::Clipboard is an interface to system clipboards. Depending on the OS,
there can be only one clipboard (Win32), or three (X11). The class is also used
for data exchange in drag-and-drop interactions.

=head1 SYNOPSIS

   my $c = $::application-> Clipboard;

   # paste data
   my $string = $c-> text;
   my $image  = $c-> image;
   my $other  = $c-> fetch('Other type');

pod/Prima/Clipboard.pod  view on Meta::CPAN

   $c-> text( $string);
   $c-> image( $image);
   $c-> store( $image);
   $c-> close;

   # clear
   $c-> clear;

=head1 USAGE

Prima::Clipboard provides access to the system clipboard data storage. For the
easier communication, the system clipboard has one 'format' field, that is
stored along with the data.  This field is used to distinguish between data
formats.  Moreover, a clipboard can hold simultaneously several data instances,
of different data formats. Since the primary usage of a clipboard is 'copying'
and 'pasting', an application can store copied information in several formats,
increasing possibility that the receiving application can recognize the data.

Different systems provide spectrum of predefined data types, but the toolkit
uses only three of these out of the box - ascii text, utf8 text, and image. It does not limit,
however, the data format being one of these three types - an application is
free to register its own formats. Both predefined and newly defined data
formats are described by a string, and the three predefined formats are
represented by C<'Text'>, C<'UTF8'>, and C<'Image'> string constants.

pod/Prima/Clipboard.pod  view on Meta::CPAN

   my $c = $::application-> Clipboard;

   # paste
   my $string = $c-> text;

   # copy
   $c-> text( $string);

Here is what happens under the hood:

First, the default clipboard is accessible by an implicit name call, as an
object named 'Clipboard'. This scheme makes it easily overridable.  A more
important point is, that the default clipboard object might be accompanied by
other clipboard objects. This is the case with X11 environment, which defines
also 'Primary' and 'Secondary' system clipboards. Their functionality is
identical to the default clipboard, however. C<get_standard_clipboards()>
method returns strings for the clipboards, provided by the system.

Second, code for fetching and/or storing multi-format data is somewhat different.
Clipboard is viewed as a shared system resource, and has to be 'opened',
before a process can grab it, so other processes can access the clipboard data
only after the clipboard is 'closed' ( note: It is not so under X11, where
there is no such thing as clipboard locking, -- but the toolkit imposes this model
for the consistency sake).

C<fetch()> and C<store()> implicitly call C<open()> and C<close()>, but these
functions must be called explicitly for the multi-format data handling. The
code below illustrates the said:

    # copy text and image
    if ( $c-> open) {
       $c-> clear;
       $c-> store('Text', $string);

pod/Prima/Clipboard.pod  view on Meta::CPAN

      $c-> open;
      $c-> clear;
      $c-> store('Text', 'sample text');
      $c-> store($myformat', 'sample ## text');
      $c-> close;
   }

=head2 On-demand storage

Under X11 it is possible to skip the generation of data in all possible
clipboard format when when copying. The native X11 mechanism allows to ask the
source application for the exact data format needed by the target application,
and the toolkit uses special event C<onClipboard> triggered on the application
whenever necessary.

By default this event handler responds to querying image in file encoded
formats (gif,jpg) under X11 on the fly. It can be extended to generate other
formats as well. See L<Prima::Application/Events> Clipboard for the details.

=head2 Custom formats

pod/Prima/Clipboard.pod  view on Meta::CPAN

de-registered. It is not a mandatory action, however - the toolkit cleans up
before exit. Moreover, the system maintains a reference counter on the
custom-registered formats; de-registering thus does not mean deletion. If two
processes use a custom format, and one exits and re-starts, the other still can
access the data in the same format, registered by its previous incarnation.

=head2 Unicode

Applications can interchange text in both ascii and utf8, leaving the selection
choice to reader programs. While it is possible to access both at the same
time, by C<fetch>'ing content of C<Text> and C<UTF8> clipboard slots, the widget
proposes its own pasting scheme, where the mechanics are hidden under the
C<text> property call. The property is advised to be used instead of
individual C<'Text'> and C<'UTF8'> formats. This method is used in all the
standard widgets, and is implemented so the programmer can reprogram its
default action by overloading C<PasteText> notification of
C<Prima::Application> ( see L<Prima::Application/PasteText> ).

The default action of C<PasteText> is to query first if C<'Text'> format is
available, and if so, return the ascii text scalar. If
C<Prima::Application::wantUnicodeInput> is set (default), C<'UTF8'> format is

pod/Prima/Clipboard.pod  view on Meta::CPAN

lowest level is raw pixel data in display-based format, whereas GTK-based
applications can also exchange images in file-based formats, such as bmp, png
etc. To avoid further complications in the implementations, C<PasteImage>
action was introduced to handle these cases, together with a symmetrical
C<CopyImage>.

The default action of C<PasteImage> is to check whether lossless encoded image data
is present, and if so, load a new image from this data, before falling back to
OS-dependent image storage.

When storing the image on the clipboard, only the default format, raw pixel data
is used. Under X11 the toolkit can also serve images encoded as file formats.

Note: Under X11 you'll need to keep the image alive during the whole time it might
get copied from the application - Prima doesn't keep a copy of the image, only
the reference. Changing the image after it was stored in the clipboard will affect
the clipboard content.


=head2 Exact and meta formats

Prima registers two special I<meta formats>, C<Image> and C<Text>, that
interoperate with the system clipboard, storing data in the format that matches
best with system convention when copying and pasting images and text,
correspondingly. It is recommended to use meta-format calls (has_format, text,
image, copy, paste) rather than exact format calls (format_exists, store,
fetch) when possible.

Where the exact format method operate on a single format data storage, meta
format calls may operate on several exact formats. F.ex. C<text> can check
whether there exists a UTF-8 text storage, before resorting to 8-bit text.
C<image> on X11 is even more complicated, and may use image codecs to transfer
encoded PNG streams, for example.

=head1 API

=head2 Properties

=over

=item image OBJECT, [KEEP]

Provides access to an image, stored in the system clipboard. In get-mode call
return C<undef> if no image is stored.  In set-mode clears the clipboard unless
KEEP is set.

=item text STRING, [KEEP]

Provides access to the text stored in the system clipboard. In get-mode call
return C<undef> if no text information is present.  In set-mode clears the
clipboard unless KEEP is set.

=back

=head2 Methods

=over

=item clear

Deletes all data from clipboard.

=item close

Closes the open/close brackets. open() and close() can
be called recursively; only the last close() removes the
actual clipboard locking, so other processes can use it as well.

=item copy FORMAT, DATA, KEEP

Sets DATA in FORMAT. Clears the clipboard before unless KEEP is set.

=item deregister_format FORMAT_STRING

De-registers a previously registered data format.  Called implicitly for all
not de-registered format before a clipboard object is destroyed.

=item fetch FORMAT_STRING

Returns the data of exact FORMAT_STRING data format, if present in the
clipboard.  Depending on FORMAT_STRING, data is either text string for
C<'Text'> format, Prima::Image object for C<'Image'> format and a binary scalar
value for all custom formats.

=item format_exists FORMAT_STRING

Returns a boolean flag, showing whether FORMAT_STRING exact format data is
present in the clipboard or not.

=item has_format FORMAT_STRING

Returns a boolean flag, showing whether FORMAT_STRING meta format data is
present in the clipboard or not.

=item get_handle

Returns the system handle for the clipboard object.

=item get_formats INCLUDE_UNREGISTERED = 0

Returns an array of strings, where each is a format ID, reflecting the formats
present in the clipboard.

Only the predefined formats, and the formats registered via
C<register_format()> are returned if C<INCLUDE_UNREGISTERED> is unset.  If the
flag is set, then all existing formats returned, however their names are not
necessarily are the same as registered with Prima.

=item get_registered_formats

Returns an array of strings, each representing a registered format. C<Text> and
C<Image> are returned also.

=item get_standard_clipboards

Returns array of strings, each representing a system clipboard. The default
C<Clipboard> is always present. Other clipboards are optional. As an example,
this function returns only C<Clipboard> under win32, but also C<Primary> and
C<Secondary> under X11. The code, specific to these clipboards must refer to
this function first.

=item is_dnd

Returns 1 if the clipboard is the special clipboard used as
a proxy for drag and drop interactions.

See also: C<Widget/Drag and drop>, C<Application/get_dnd_clipboard>.

=item open

Opens a system clipboard and locks it for the process single use; returns a
success flag. Subsequent C<open> calls are possible, and always return 1. Each
C<open()> must correspond to C<close()>, otherwise the clipboard will stay
locked until the blocking process is finished.

=item paste FORMAT_STRING

Returns data of meta format FORMAT_STRING if found in the clipboard, or undef otherwise.

=item register_format FORMAT_STRING

Registers a data format under FORMAT_STRING string ID, returns a success flag.
If a format is already registered, 1 is returned. All formats, registered via
C<register_format()> are de-registered with C<deregister_format()> when a
program is finished.

=item store FORMAT_STRING, SCALAR

Stores SCALAR value into the clipboard in FORMAT_STRING exact data format.
Depending of FORMAT_STRING, SCALAR is treated as follows:

   FORMAT_STRING     SCALAR
   ------------------------------------
   Text              text string in ASCII
   UTF8              text string in UTF8
   Image             Prima::Image object
   other formats     binary scalar value


pod/Prima/Widget.pod  view on Meta::CPAN

=head2 Drag and drop

Widgets can participate in full drag and drop sessions with other applications
and itself, with very few restrictions. See below how to use this
functionality.

=over

=item Data exchange

Prima defines a special clipboard object that serves as an exchange point
whenever data is to be either sent or received. In order to either offer to, or
choose from, many formats of another DND client, use that clipboard to operate
with standard open/fetch/store/close methods (see more at L<Prima::Clipboard>).

The clipboard can be accessed at any time by calling C< $::application->
get_dnd_clipboard >, however during handling of dropping events it will stay
read-only.

To successfully exchange data with other applications, one may investigate
results of C<< $clipboard-> get_formats(1) >> to see what types of data the
selected application can exchange. With a high probability many programs can
exchange text and image in a system-dependent format, however it is also common
to see applications to exchange data in format names that match their MIME
description. For example Prima supports image formats like C<image/bmp> out of
the box, and C<text/plain> on X11, that are selected automatically when
operating with pseudo-formats C<Text> or C<Image>. Other MIME formats like
f.ex.  C<text/html> are not known to Prima, but can be exchanged quite easily;
one needs to register that format first using C<Clipboard::register_format>,
once, and then it is ready for exchange.

=item Dragging

To initiate the drag, first fill the DND clipboard with data to be exchanged,
using one or more formats, then call either L</start_dnd>. Alternatively, call
L</begin_drag>, a wrapper method that can set up clipboard data itself. See
their documentation for more details.

During the dragging, the sender will receive L</DragQuery> and L</DragResponse> events,
in order to decide whether the drag session must continue or stop depending on
the user input, and reflect that back to the user. Traditionally, mouse cursors
are changed to show whether an application will receive a drop, and if yes,
what action (copy, move, or link) it will participate in. Prima will try its best
to either use system cursors, or synthesize ones that are informative enough;
if that is not sufficient, one may present own cursor schema (see f.ex 
how C<begin_drag> is implemented).

=item Dropping

To register a widget as a drop target, set its L</dndAware> property to either
1, to mark that it will answer to all formats, or to a string, in which case
drop events will only be delivered if the DND clipboard contains a format with
that string.

Thereafter, when the user will initiate a DND session and will move mouse
pointer over the widget, it will receive a L</DragBegin> event, then series of
L</DragOver> events, and finally a L</DragEnd> event with a flag telling whether
the user chose to drop the data or cancel the session.

The C<DragOver> and C<DragEnd> callbacks have a chance to either allow or deny
data, and select an action (if there are more than one allowed by the other
application) to proceed with. To do so, set appropriate values to C<{allow}>

pod/Prima/Widget.pod  view on Meta::CPAN


The color used to substitute C<::color> when a widget
is in its disabled state.

See also: C<disabledBackColor>, C<colorIndex>, C<ColorChanged>

=item dndAware 0 | 1 | FORMAT

To register a widget as a drop target, set its L</dndAware> property to either
1, to mark that it will answer to all formats, or to a string, in which case
drop events will only be delivered if the DND clipboard contains a format with
that string.

Default: 0

See also: C<Drag and Drop>

=item enabled BOOLEAN

Specifies if a widget can accept focus, keyboard and mouse events.
Default value is 1, however, being 'enabled' does not automatically

pod/Prima/Widget.pod  view on Meta::CPAN

=over

=item actions INTEGER = dnd::Copy

Combination of C<dnd::> constants, to tell a DND receiver whether copying,
moving, and/or linking of the data is allowed. The method fails on the invalid
C<actions> input.

=item format FORMAT, data INPUT

If set, the clipboard will be assigned to contain a single entry of C<INPUT> of the
C<FORMAT> format, where format is either one of the standard C<Text> or C<Image>, or
one of the format registered by C<Clipboard::register_format>.

If not set, the caller needs to fill the clipboard in advance, f.ex. to offer
data in more than one format.

=item image INPUT

Shortcut for C< format => 'Image', data => $INPUT, preview => $INPUT >

=item preview INPUT

If set, mouse pointers sending feedback to the user will be equipped with
either text or image (depending on whether C<INPUT> is a scalar or an image

pod/Prima/Widget.pod  view on Meta::CPAN


=item deselect

Alias for C<selected(0)> call

See also: C<select>, C<selected>, C<Enter>, C<Leave>

=item dnd_start ACTIONS = dnd::Copy, USE_DEFAULT_POINTERS = 1

Starts a drag and drop session with a combination of C<ACTIONS> allowed.  It is
expected that a DND clipboard will be filled with data that are prepared to be
sent to a DND receiver.

Returns -1 if a session cannot start, C<dnd::None> if it was canceled by the
user, or any other C<dnd::> constant when the DND receiver has selected and
successfully performed that action. For example, after a call to C<dnd_start>
returning C<dnd::Move> (depending on a context), the called may remove the data
the user selected to move (C<Prima::InputLine> and C<Prima::Edit> do exactly
this).

Also returns the widget that accepted the drop, if that was a Prima widget within

pod/Prima/Widget.pod  view on Meta::CPAN

See also: C<Enable>, C<enabled>, C<responsive>

=item DragBegin CLIPBOARD, ACTION, MOD, X, Y, COUNTERPART

Triggered on a receiver widget when a mouse with a DND object enters it.
C<CLIPBOARD> contains the DND data, C<ACTION> is a combination of C<dnd::>
constants, the actions the sender is ready to offer, C<MOD> is a combination of
modifier keys (C<kb::>), and C<X> and C<Y> are coordinates where the mouse has
entered the widget. This event, and the following C<DragOver> and C<DragEnd>
events are happening only if the property C<dndAware> is set either to 1, or
if it matches a clipboard format that exists in C<CLIPBOARD>.

C<COUNTERPART> is the Prima DND sender widget, if the session is initiated within
the same program.

See also: L</Drag and Drop>, C<DragOver>, C<DragEnd>

=item DragEnd CLIPBOARD, ACTION, MOD, X, Y, COUNTERPART, ANSWER

Triggered on a received widget when the user either drops or cancels the DND
session. In case of a canceled drop, C<CLIPBOARD> is set to C<undef> and

pod/Prima/X11.pod  view on Meta::CPAN

EGA mode.  This visual is rarely met.

=item PseudoColor

All color cells are modifiable. Typically, 8-bit displays define this class for
a default visual. For both I<StaticColor> and I<PseudoColor> visuals dithering
is always used, although for C<PseudoColor> Prima resorts to that only if X
server cannot allocate another color.

On C<PseudoColor> and C<GrayScale> Prima allocates a small set of colors, not
used in palette modifications. When a bitmap is to be exported via clipboard,
or displayed in menu, or sent to a window manager as an icon to be displayed,
it is downgraded to using these colors only, which are though always to
stay permanent through life of the application.

=item TrueColor

Each pixel value is explicitly coded as RGB. Typical example are 16, 24, or 32-bit
display modes. This visual class is the best in terms of visual quality.

=item DirectColor

pod/Prima/X11.pod  view on Meta::CPAN


Prima supports shared memory image X extension, which speeds up image display
for X servers and clients running on same machine. The price for this is that
if Prima program aborts, the shared memory will never be returned to the OS.
To remove the leftover segments, use your OS facilities, for example, C<ipcrm>
on *BSD.

To disable shared memory with images, use C<--no-shmem> switch in command-line
arguments.

The clipboard exchange of images is incompletely implemented, since Prima does
not accompany ( and neither reads ) COLORMAP, FOREGROUND, and BACKGROUND
clipboard data, which contains pixel RGB values for a paletted image. As a
palliative, the clipboard-bound images are downgraded to a safe set of colors,
locked immutable either by X server or Prima core.

On images in the clipboard: contrary to the text in the clipboard, which can be
used several times, images seemingly cannot. The Bitmap or Pixmap descriptor,
stored in the clipboard, is rendered invalid after it has been read once.

=head1 Window managers

The original design of X protocol did not include the notion of a window
manager, and latter is was implemented as an ad-hoc patch, which results in
race conditions when configuring widgets. The extreme situation may well happen
when even a non-top level widget may be influenced by a window manager, when
for example a top-level widget was reparented into another widget, but the
window manager is not aware or this yet.

pod/Prima/X11.pod  view on Meta::CPAN

using iconv charset converter library.

=head2 Input

Prima does not support extended input methods ( XIM etc ), primarily because
the authors are not acquainted with CIJK problem domain. Volunteers are
welcome.

=head2 Clipboard

Prima supports UTF8 text in clipboard via C<UTF8_STRING> transparently,
although not by default.

   Prima::Application-> wantUnicodeInput(1)

is the easiest ( see L<Prima::Application> ) way to initiate UTF8 clipboard
text exchange.

Due to the fact that any application can take ownership over the clipboard
at any time, C<open>/C<close> brackets are not strictly respected in X11
implementation. Practically, this means that when modern X11 clipboard daemons
( KDE klipper, for example ) interfere with Prima clipboard, the results may
not be consistent from the programmer's view, for example, clipboard contains
data after C<clear> call, and the like. It must be noted though that this
behavior is expected by the users.

=head1 Other XRDB resources

=head2 Timeouts

Raw X11 provides no such GUI helpers as double-click event, cursor, or menu.
Neither does it provide the related time how often, for example, a cursor would
blink. Therefore Prima emulates these, but allows the user to reprogram the

pod/Prima/X11.pod  view on Meta::CPAN


The famous 'use the source' call is highly actual with Prima. However, some
debug information comes compiled in, and can be activated by C<--debug>
command-line key. Combination of letters to the key activates debug printouts
of different subsystems:

=over

=item *

C - clipboard

=item *

E - events subsystem

=item *

F - fonts

=item *

pod/Prima/faq.pod  view on Meta::CPAN

Prima by default is unicode-aware, in some areas more than the Perl (as of 5.32) itself.

For example on win32 Perl has big difficulties with files with unicode
characters, and this is recommended to mitigate using L<Prima::sys::FS>, which
overrides C<open>, C<opendir> and the like builtin functions with their
unicode-friendly versions. It doesn't though overload C<-f>,C<-e> syntax, so
use C<_f>,C<_e> etc instead.

Displaying UTF8 text is unproblematic, because Perl scalars can be
unambiguously told whether the text they contain is in UTF8 or not. The text
that comes from the user input, i e keyboard and clipboard, can be treated and
reported to Prima either as UTF8 r plain text, depending on
C<Prima::Application::wantUnicodeInput> property, which is set to 1 by default.
Remember though that if data are to be put through file I/O, the C<'utf8'> IO
layer must be selected ( see L<open> ).

The keyboard input is also easy, because a character key event comes with the
character code, not the character itself, and conversion between these is done
via standard perl's C<chr> and C<ord>.

The clipboard input is more complicated, because the clipboard may contain both
UTF8 and plain text data at once, and it must be decided by the programmer
explicitly which one is desired.  See more in L<Prima::Clipboard/Unicode>.

=head2 Is there a way to display POD text that comes with my program / package ?

   $::application-> open_help( "file://$0" );
   $::application-> open_help( "file://$0|DESCRIPTION" );
   $::application-> open_help( 'My::Package/BUGS' );

=head2 How to implement parallel processing?

t/Object/Clipboard.t  view on Meta::CPAN

$::application->end_paint;

sub try(&$)
{
	my $sub  = shift;
	my $skip = shift;
	for ( 1..2 ) {
		return 1 if $sub->();
		sleep(1);
	}
	my $msg = "Cannot acquire clipboard: " . (Prima::Utils::last_error() // 'unknown error');
	skip $msg, $skip;
}

try { $c->open } 9;
$c->close;

try { $c-> store( "Text", 'jabba dabba du') } 9;
try { $c->open } 9;
my $res = $c-> fetch( 'Text');
unless ( defined $res ) {
	my $msg = "Cannot fetch data from clipboard: " . (Prima::Utils::last_error() // 'unknown error');
	skip $msg, 9;
}
my %fm = map { $_ => 1 } $c-> get_formats;
ok( exists $fm{Text} && defined $res, "text exists");
is( $res, 'jabba dabba du', "text is correct" );
$c->close;

my $i = Prima::Image-> create( width => 32, height => 32);
try { $c-> store( "Image", $i) } 7;
try { $c->open } 7;

unix/app.c  view on Meta::CPAN

	guts. wm_event_timeout = 100;
	guts. menu_timeout = 200;
	guts. scroll_first = 200;
	guts. scroll_next = 50;
	apc_timer_create( CURSOR_TIMER);
	apc_timer_set_timeout(CURSOR_TIMER, 2);
	apc_timer_create( MENU_TIMER);
	apc_timer_set_timeout( MENU_TIMER,  guts. menu_timeout);
	apc_timer_create( MENU_UNFOCUS_TIMER);
	apc_timer_set_timeout( MENU_UNFOCUS_TIMER, 50);
	if ( !prima_init_clipboard_subsystem (error_buf)) return false;
	if ( !prima_init_color_subsystem     (error_buf)) return false;
	if ( !do_no_xrender)
		if ( !prima_init_xrender_subsystem(error_buf)) return false;
	if ( !prima_init_font_subsystem      (error_buf)) return false;
#ifdef WITH_GTK
	guts. use_gtk = do_no_gtk ? false : ( prima_gtk_init() != NULL );
#endif
#ifdef WITH_COCOA
	if ( prima_cocoa_is_x11_local())
		guts. use_quartz = !do_no_quartz;

unix/app.c  view on Meta::CPAN

{
	static char * x11_argv[] = {
	"no-x11", "runs Prima without X11 display initialized",
	"display", "selects X11 DISPLAY (--display=:0.0)",
	"visual", "X visual id (--visual=0x21, run `xdpyinfo` for list of supported visuals)",
	"sync", "synchronize X connection",
	"icccm", "do not use NET_WM (kde/gnome) and MOTIF extensions, ICCCM only",
	"debug", "turns on debugging on subsystems, selected by characters (--debug=FC). "\
				"Recognized characters are: "\
				" 0(none),"\
				" C(clipboard),"\
				" E(events),"\
				" F(fonts),"\
				" M(miscellaneous),"\
				" P(palettes and colors),"\
				" X(XRDB),"\
				" A(all together)",
#ifdef USE_MITSHM
	"no-shmem",       "do not use shared memory for images",
#endif
#ifdef X_HAVE_UTF8_STRING

unix/app.c  view on Meta::CPAN

		guts. hostname. value = NULL;
	}

	prima_end_menu();

	free_gc_pool(&guts.bitmap_gc_pool);
	free_gc_pool(&guts.screen_gc_pool);
	free_gc_pool(&guts.argb_gc_pool);
	prima_done_color_subsystem();
	prima_done_xrender_subsystem();
	free( guts. clipboard_formats);

	XFreeGC( DISP, guts. menugc);
	prima_gc_ximages();          /* verrry dangerous, very quiet please */
	if ( guts.pointer_font) {
		XFreeFont( DISP, guts.pointer_font);
		guts.pointer_font = NULL;
	}
	XCloseDisplay( DISP);
	DISP = NULL;

	plist_destroy( guts. files);
	guts. files = NULL;

	XrmDestroyDatabase( guts.db);
	if (guts.ximages)            hash_destroy( guts.ximages, false);
	if (guts.menu_windows)       hash_destroy( guts.menu_windows, false);
	if (guts.windows)            hash_destroy( guts.windows, false);
	if (guts.clipboards)         hash_destroy( guts.clipboards, false);
	if (guts.clipboard_xfers)    hash_destroy( guts.clipboard_xfers, false);
	prima_cleanup_font_subsystem();
	bzero(&guts, sizeof(guts));
}

static int
can_access_root_screen(void)
{
	static int result = -1;
	XImage * im;
	XErrorEvent xr;

unix/clipboard.c  view on Meta::CPAN

#include "unix/guts.h"
#include "Application.h"
#include "Clipboard.h"
#include "Icon.h"

#define WIN PComponent(prima_guts.application)-> handle

#define CF_NAME(x)   (guts. clipboard_formats[(x)*3])
#define CF_TYPE(x)   (guts. clipboard_formats[(x)*3+1])
#define CF_FORMAT(x) (guts. clipboard_formats[(x)*3+2])
#define CF_ASSIGN(i,a,b,c) CF_NAME(i)=(a);CF_TYPE(i)=(b);CF_FORMAT(i)=((Atom)c)

Bool
prima_init_clipboard_subsystem(char * error_buf)
{
	guts. clipboards = hash_create();

	if ( !(guts. clipboard_formats = malloc( cfCOUNT * 3 * sizeof(Atom)))) {
		sprintf( error_buf, "No memory");
		return false;
	}
	guts. clipboard_formats_count = cfCOUNT;
#if (cfText != 0) || (cfBitmap != 1) || (cfUTF8 != 2)
#error broken clipboard type formats
#endif

	CF_ASSIGN(cfText, XA_STRING, XA_STRING, 8);
	CF_ASSIGN(cfUTF8, UTF8_STRING, UTF8_STRING, 8);
	CF_ASSIGN(cfBitmap, XA_PIXMAP, XA_PIXMAP, CF_32);
	CF_ASSIGN(cfTargets, CF_TARGETS, XA_ATOM, CF_32);

	/* XXX - bitmaps and indexed pixmaps may have the associated colormap or pixel values
	CF_ASSIGN(cfPalette, XA_COLORMAP, XA_ATOM, CF_32);
	CF_ASSIGN(cfForeground, CF_FOREGROUND, CF_PIXEL, CF_32);
	CF_ASSIGN(cfBackground, CF_BACKGROUND, CF_PIXEL, CF_32);
	*/

	guts. clipboard_event_timeout = 2000;
	return true;
}

PList
apc_get_standard_clipboards( void)
{
	PList l = plist_create( 4, 1);
	if (!l) return NULL;
	list_add( l, (Handle)duplicate_string( "Primary"));
	list_add( l, (Handle)duplicate_string( "Secondary"));
	list_add( l, (Handle)duplicate_string( "Clipboard"));
	list_add( l, (Handle)duplicate_string( "XdndSelection"));
	return l;
}

Bool
apc_clipboard_create( Handle self)
{
	PClipboard c = (PClipboard)self;
	int i;
	DEFCC;

	if ( strcmp(c->name, "XdndSelection") != 0 ) {
		char *name, *x;
		name = x = duplicate_string( c-> name);
		while (*x) {
			*x = toupper(*x);
			x++;
		}
		XX-> selection = XInternAtom( DISP, name, false);
		free( name);
	} else {
		XX-> selection = XdndSelection;
	}

	if ( hash_fetch( guts.clipboards, &XX->selection, sizeof(XX->selection))) {
		warn("This clipboard is already present");
		return false;
	}

	if ( !( XX-> internal = malloc( sizeof( ClipboardDataItem) * cfCOUNT))) {
		warn("Not enough memory");
		return false;
	}
	if ( !( XX-> external = malloc( sizeof( ClipboardDataItem) * cfCOUNT))) {
		free( XX-> internal);
		warn("Not enough memory");
		return false;
	}
	bzero( XX-> internal, sizeof( ClipboardDataItem) * cfCOUNT);
	bzero( XX-> external, sizeof( ClipboardDataItem) * cfCOUNT);

	XX->internal[cfTargets].name = CF_NAME(cfTargets);

	for ( i = 0; i < cfCOUNT; i++) 
		XX->internal[i].immediate = XX->external[i].immediate = true;

	hash_store( guts.clipboards, &XX->selection, sizeof(XX->selection), (void*)self);

	if ( XX-> selection == XdndSelection )
		guts. xdnd_clipboard = self;

	return true;
}

static void
clipboard_free_data( void * data, int size, Handle id)
{
	if ( size <= 0) {
		if ( size == 0 && data != NULL) free( data);
		return;
	}
	if ( id == cfBitmap) {
		int i;
		Pixmap * p = (Pixmap*) data;
		for ( i = 0; i < size/sizeof(Pixmap); i++, p++)
			if ( *p)
				XFreePixmap( DISP, *p);
	}
	free( data);
}

/*
	each clipboard type can be represented by a set of
	X properties pairs, where each is X name and X type.
	get_typename() returns such pairs by the index.
*/
static Atom
get_typename( Handle id, int index, Atom * type)
{
	if ( type) *type = None;
	switch ( id) {
	case cfText:
		if ( index > 1) return None;

unix/clipboard.c  view on Meta::CPAN

			if ( type) *type = CF_TARGETS;
			return CF_NAME(id);
		}
	}
	if ( index > 0) return None;
	if ( type) *type = CF_TYPE(id);
	return CF_NAME(id);
}

void
prima_clipboard_kill_item( PClipboardDataItem item, Handle id)
{
	item += id;
	clipboard_free_data( item-> data, item-> size, id);
	if ( item-> image ) {
		if ( PObject(item->image)-> mate && PObject(item->image)-> mate != NULL_SV)
			SvREFCNT_dec( SvRV( PObject(item-> image)->mate ));
		unprotect_object( item-> image );
	}
	item-> image = NULL_HANDLE;
	item-> data = NULL;
	item-> size = 0;
	item-> name = get_typename( id, 0, NULL);
	item-> immediate = true;
}

/*
	Deletes a transfer record from pending xfer chain.
*/
static void
delete_xfer( PClipboardSysData cc, ClipboardXfer * xfer)
{
	ClipboardXferKey key;
	CLIPBOARD_XFER_KEY( key, xfer-> requestor, xfer-> property);
	if ( guts. clipboard_xfers) {
		IV refcnt;
		hash_delete( guts. clipboard_xfers, key, sizeof( key), false);
		refcnt = PTR2IV( hash_fetch( guts. clipboard_xfers, &xfer-> requestor, sizeof(XWindow)));
		if ( --refcnt == 0) {
			XSelectInput( DISP, xfer-> requestor, 0);
			hash_delete( guts. clipboard_xfers, &xfer-> requestor, sizeof(XWindow), false);
		} else {
			if ( refcnt < 0) refcnt = 0;
			hash_store( guts. clipboard_xfers, &xfer-> requestor, sizeof(XWindow), INT2PTR(void*, refcnt));
		}
	}
	if ( cc-> xfers)
		list_delete( cc-> xfers, ( Handle) xfer);
	if ( xfer-> data_detached && xfer-> data_master)
		clipboard_free_data( xfer-> data, xfer-> size, xfer-> id);
	free( xfer);
}

Bool
apc_clipboard_destroy( Handle self)
{
	DEFCC;
	int i;

	if ( guts. xdnd_clipboard == self )
		guts. xdnd_clipboard = NULL_HANDLE;

	if (XX-> selection == None) return true;

	if ( XX-> xfers) {
		for ( i = 0; i < XX-> xfers-> count; i++)
			delete_xfer( XX, ( ClipboardXfer*) XX-> xfers-> items[i]);
		plist_destroy( XX-> xfers);
	}

	for ( i = 0; i < guts. clipboard_formats_count; i++) {
		if ( XX-> external) prima_clipboard_kill_item( XX-> external, i);
		if ( XX-> internal) prima_clipboard_kill_item( XX-> internal, i);
	}

	free( XX-> external);
	free( XX-> internal);
	hash_delete( guts.clipboards, &XX->selection, sizeof(XX->selection), false);

	XX-> selection = None;
	return true;
}

Bool
apc_clipboard_open( Handle self)
{
	DEFCC;
	if ( XX-> xdnd_receiving ) return true;
	if ( XX-> opened) return false;
	XX-> opened = true;

	if ( !XX-> inside_event) XX-> need_write = false;

	return true;
}

Bool
apc_clipboard_close( Handle self)
{
	DEFCC;
	if ( XX-> xdnd_receiving ) return true; /* XXX */
	if ( !XX-> opened) return false;
	XX-> opened = false;

	/* check if UTF8 is present and Text is not, and downgrade */
	if ( XX-> need_write &&
		XX-> internal[cfUTF8]. size > 0 &&
		XX-> internal[cfText]. size == 0) {

unix/clipboard.c  view on Meta::CPAN

				register UV u = prima_utf8_uvchr_end(src, end, &charlen);
				*(dst++) = ( u < 0x7f) ? u : '?'; /* XXX employ $LANG and iconv() */
				src += charlen;
			}
		}
	}


	if ( !XX-> inside_event) {
		int i;
		for ( i = 0; i < guts. clipboard_formats_count; i++)
			prima_clipboard_kill_item( XX-> external, i);
		if ( XX-> need_write && (!XX->xdnd_receiving || XX->xdnd_sending))
			if ( XGetSelectionOwner( DISP, XX-> selection) != WIN)
				XSetSelectionOwner( DISP, XX-> selection, WIN, CurrentTime);
	}

	return true;
}

/*
	Detaches data for pending transfers from XX, so eventual changes
	to XX->internal would not affect them. detach_xfers() should be
	called before clipboard_kill_item(XX-> internal), otherwise
	there's a chance of coredump.
*/
void
prima_detach_xfers( PClipboardSysData XX, Handle id, Bool clear_original_data)
{
	int i, got_master = 0, got_anything = 0;
	if ( !XX-> xfers) return;
	for ( i = 0; i < XX-> xfers-> count; i++) {
		ClipboardXfer * x = ( ClipboardXfer *) XX-> xfers-> items[i];
		if ( x-> data_detached || x-> id != id) continue;

unix/clipboard.c  view on Meta::CPAN

		x-> data_detached = true;
	}
	if ( got_anything && clear_original_data) {
		XX-> internal[id]. data = NULL;
		XX-> internal[id]. size = 0;
		XX-> internal[id]. name = get_typename( id, 0, NULL);
	}
}

Bool
apc_clipboard_clear( Handle self)
{
	DEFCC;
	int i;

	for ( i = 0; i < guts. clipboard_formats_count; i++) {
		prima_detach_xfers( XX, i, true);
		prima_clipboard_kill_item( XX-> internal, i);
		prima_clipboard_kill_item( XX-> external, i);
	}

	if ( XX-> inside_event) {
		XX-> need_write = true;
	} else if ( !XX->xdnd_receiving || XX->xdnd_sending) {
		XWindow owner = XGetSelectionOwner( DISP, XX-> selection);
		XX-> need_write = false;
		if ( owner != None && owner != WIN)
			XSetSelectionOwner( DISP, XX-> selection, None, CurrentTime);
	}

unix/clipboard.c  view on Meta::CPAN


int
prima_read_property( XWindow window, Atom property, Atom * type, int * format,
	unsigned long * size, unsigned char ** data, Bool delete_property)
{
	int ret = ( *size > 0) ? RPS_PARTIAL : RPS_ERROR;
	unsigned char * prop, *a1;
	unsigned long n, left, offs = 0, new_size, big_offs = *size;

	XCHECKPOINT;
	Cdebug("clipboard: read_property: %s\n", XGetAtomName(DISP, property));
	while ( 1) {
		if ( XGetWindowProperty( DISP, window, property,
			offs, guts. limits. request_length - 4, false,
			AnyPropertyType,
			type, format, &n, &left, &prop) != Success) {
			if ( delete_property )
				XDeleteProperty( DISP, window, property);
			Cdebug("clipboard:fail\n");
			return ret;
		}
		XCHECKPOINT;
		Cdebug("clipboard: type=0x%x(%s) fmt=%d n=%d left=%d\n",
				*type, XGetAtomName(DISP,*type), *format, n, left);

		if ( *format == 32) *format = CF_32;

		if ( *type == 0 ) return RPS_NODATA;

		new_size = n * *format / 8;

		if ( new_size > 0) {
			if ( !( a1 = realloc( *data, big_offs + offs * 4 + new_size))) {

unix/clipboard.c  view on Meta::CPAN

	SelectionProcData spd;
	unsigned long size = 0, incr = 0, old_size, delay;
	long timestamp;
	unsigned char * data;
	struct timeval start_time, timeout;
	XWindow window;

	/* init */
	if ( query_target == None) return false;
	window = XX-> xdnd_receiving ? PWidget(guts.xdndr_receiver)->handle : WIN;
	if ( window == None ) return false; /* don't operate on XDND clipboard outside the drag */
	timestamp = XX-> xdnd_receiving ? guts.xdndr_timestamp : guts.last_time;

	data = malloc(0);
	XX-> external[id]. size = CFDATA_ERROR;
	gettimeofday( &start_time, NULL);
	XCHECKPOINT;

	Cdebug("clipboard:convert %s from %08x on %s\n", XGetAtomName( DISP, query_target), window, XGetAtomName(DISP, XX->selection));
	XDeleteProperty( DISP, WIN, XX-> selection);
	XConvertSelection( DISP, XX-> selection, query_target, XX-> selection, window, timestamp);
	XFlush( DISP);
	XCHECKPOINT;

	/* wait for SelectionNotify */
	spd. selection = XX-> selection;
	spd. mask = SELECTION_NOTIFY_MASK;
	while ( 1) {
		Bool ok;

		ok = XCheckIfEvent( DISP, &ev, (XIfEventProcType)selection_filter, (char*)&spd);
		if ( !ok ) {
			gettimeofday( &timeout, NULL);
			delay = (( timeout. tv_sec - start_time. tv_sec) * 1000 +
				( timeout. tv_usec - start_time. tv_usec) / 1000);
			if ( delay > guts. clipboard_event_timeout) {
				Cdebug("clipboard:selection timeout\n");
				goto FAIL;
			}
			XFlush( DISP);
			continue;
		}
		gettimeofday( &timeout, NULL);
		delay = 2 * (( timeout. tv_sec - start_time. tv_sec) * 1000 +
			( timeout. tv_usec - start_time. tv_usec) / 1000);
		if ( ev. type != SelectionNotify) {
			prima_handle_event( &ev, NULL);
			continue;
		}
		if ( ev. xselection. property == None) goto FAIL;
		Cdebug("clipboard:read SelectionNotify  %s %s\n",
				XGetAtomName(DISP, ev. xselection. property),
				XGetAtomName(DISP, ev. xselection. target));
		if ( prima_read_property( window, ev. xselection. property, &type, &format, &size, &data, 1) > RPS_PARTIAL)
			goto FAIL;
		XFlush( DISP);
		break;
	}
	XCHECKPOINT;

	if ( type != XA_INCR) { /* ordinary, single-property selection */
		if ( format != CF_FORMAT(id) || type != query_type) {
			if ( format != CF_FORMAT(id))
				Cdebug("clipboard: id=%d: formats mismatch: got %d, want %d\n", id, format, CF_FORMAT(id));
			if ( type != query_type)
				Cdebug("clipboard: id=%d: types mismatch: got %s, want %s\n", id,
						XGetAtomName(DISP,type), XGetAtomName(DISP,query_type));
			return false;
		}
		XX-> external[id]. size = size;
		XX-> external[id]. data = data;
		XX-> external[id]. name = query_target;
		return true;
	}

	/* setup INCR */

unix/clipboard.c  view on Meta::CPAN

	while (( name = get_typename( id, index++, NULL)) != None) {
		for ( i = 0; i < length / sizeof(Atom); i++) {
			if ( data[i] == name)
				return name;
		}
	}
	return None;
}

void
prima_clipboard_query_targets( Handle self)
{
	DEFCC;

	if ( !XX->xdnd_receiving ) {
		if ( XX-> external[cfTargets]. size != 0)
			return;
		query_data( self, cfTargets);
	}

	/* read TARGETS, which is an array of ATOMs */
	if ( XX-> external[cfTargets].size > 0) {
		int i, size = XX-> external[cfTargets].size;
		Atom * data = ( Atom*)(XX-> external[cfTargets]. data);
		Atom ret;

		Cdebug("clipboard targets:");
		for ( i = 0; i < size/sizeof(Atom); i++)
			Cdebug("%s\n", XGetAtomName( DISP, data[i]));

		/* find our index for TARGETS[i], assign CFDATA_NOT_ACQUIRED to it */
		for ( i = 0; i < guts. clipboard_formats_count; i++) {
			if ( i == cfTargets) continue;
			ret = find_atoms( data, size, i);
			if (
				XX-> external[i]. size == 0 ||
				XX-> external[i]. size == CFDATA_ERROR
			) {
				XX-> external[i]. size = CFDATA_NOT_ACQUIRED;
				XX-> external[i]. name = ret;
			}
		}
	}
}

Bool
apc_clipboard_has_format( Handle self, Handle id)
{
	DEFCC;
	if ( id >= guts. clipboard_formats_count) return false;

	if ( XX-> inside_event) {
		return XX-> internal[id]. size > 0 || !XX->internal[id].immediate || XX-> external[id]. size > 0;
	} else {
		if ( XX-> internal[id]. size > 0 || !XX->internal[id].immediate) return true;
		prima_clipboard_query_targets(self);
		if ( XX-> external[cfTargets]. size > 0) {
			return find_atoms(
				(Atom*) XX-> external[cfTargets]. data,
				XX-> external[cfTargets]. size, id
			) != None;
		}

		if ( XX-> external[id]. size > 0 ||
			XX-> external[id]. size == CFDATA_NOT_ACQUIRED)
			return true;

unix/clipboard.c  view on Meta::CPAN

			return false;

		/* selection owner does not support TARGETS, so peek */
		if ( XX-> external[cfTargets]. size == 0 && XX-> internal[id]. size == 0)
			return query_data( self, id);
	}
	return false;
}

PList
apc_clipboard_get_formats( Handle self)
{
	DEFCC;
	int id;
	PList list = plist_create(guts.clipboard_formats_count, 8);
	Byte visited[1024]; /* 8K formats */

	bzero( visited, sizeof(visited));

	if ( !XX-> inside_event ) {
		int i, j, size;
		Atom * data;

		prima_clipboard_query_targets(self);
		size = XX-> external[cfTargets].size;
		data = ( Atom*)(XX-> external[cfTargets]. data);
		if ( size > 0 && data != NULL ) {
			/* TARGETS supported */
			for ( i = 0; i < size/sizeof(Atom); i++, data++) {
				Atom atom = None;
				char *name = NULL;
				/* try to map back f.ex. text/plain to Text */
				for ( j = 0; j < guts.clipboard_formats_count; j++) {
					if (*data == XX->external[j].name) {
						atom = CF_NAME(j);
						if (atom == XA_STRING )
							name = "Text";
						else if ( atom == XA_BITMAP)
							name = "Image";
						else if ( atom == UTF8_STRING )
							name = "UTF8";
					}
					if ( atom != None || name != NULL ) {

unix/clipboard.c  view on Meta::CPAN

						if ( ofs < 1024 ) visited[ofs] |= 1 << (j & 7);
					}
				}
				if ( atom == None ) atom = *data;
				if ( name == NULL ) name = XGetAtomName(DISP, atom);
				list_add( list, (Handle) duplicate_string(name));
			}
		}
	}

	for ( id = 0; id < guts. clipboard_formats_count; id++) {
		int ofs = id >> 3;
		int was_visited = ( ofs < 1024 ) ? visited[ofs] & (1 << (id & 7)) : 0;
		if (XX-> internal[id]. size > 0 || !XX->internal[id]. immediate || XX-> external[id]. size > 0) {
			char * name;
			if ( was_visited ) continue;
			switch ( id ) {
			case cfText: 
				name = "Text";
				break;
			case cfUTF8: 

unix/clipboard.c  view on Meta::CPAN

	return list;
}

static Bool
fill_target( Handle self, Atom target );

static Bool
fill_bitmap( Handle self );

Bool
apc_clipboard_get_data( Handle self, Handle id, PClipboardDataRec c)
{
	DEFCC;
	STRLEN size;
	unsigned char * data;
	Bool imm;

	if ( id >= guts. clipboard_formats_count) return false;

	if ( !XX-> inside_event) {
		if ( XX-> internal[id]. size == 0) {
			if ( XX-> external[id]. size == CFDATA_NOT_ACQUIRED) {
				if ( !query_data( self, id)) return false;
			}
			if ( XX-> external[id]. size == CFDATA_ERROR) return false;
		}
	}
	if ( XX-> internal[id]. size == CFDATA_ERROR) return false;

unix/clipboard.c  view on Meta::CPAN

		}
		memcpy( ret, data, size);
		c-> data = ( Byte * ) ret;
		c-> length = size;
		break;}
	}
	return true;
}

Bool
apc_clipboard_set_data( Handle self, Handle id, PClipboardDataRec c)
{
	DEFCC;
	if ( id >= guts. clipboard_formats_count) return false;

	if ( id >= cfTargets && id < cfCOUNT ) return false;
	prima_detach_xfers( XX, id, true);
	prima_clipboard_kill_item( XX-> internal, id);

	switch ( id) {
	case cfBitmap:
		if (( XX-> internal[id]. image = c-> image) != NULL_HANDLE) {
			protect_object( XX-> internal[id]. image );
			SvREFCNT_inc( SvRV( PObject(XX-> internal[id]. image)-> mate ));
			XX-> internal[id]. immediate = false;
		}
		break;
	default:

unix/clipboard.c  view on Meta::CPAN

			XX-> internal[id]. size = c-> length;
			memcpy( XX-> internal[id]. data, c-> data, c-> length);
		}
		break;
	}
	XX-> need_write = true;
	return true;
}

static Bool
expand_clipboards( Handle self, int keyLen, void * key, void * dummy)
{
	DEFCC;
	PClipboardDataItem f;

	if ( !( f = realloc( XX-> internal,
		sizeof( ClipboardDataItem) * guts. clipboard_formats_count))) {
		guts. clipboard_formats_count--;
		return true;
	}
	f[ guts. clipboard_formats_count-1].size      = 0;
	f[ guts. clipboard_formats_count-1].data      = NULL;
	f[ guts. clipboard_formats_count-1].name      = CF_NAME(guts. clipboard_formats_count-1);
	f[ guts. clipboard_formats_count-1].immediate = true;
	f[ guts. clipboard_formats_count-1].image     = NULL_HANDLE;
	XX-> internal = f;
	if ( !( f = realloc( XX-> external,
		sizeof( ClipboardDataItem) * guts. clipboard_formats_count))) {
		guts. clipboard_formats_count--;
		return true;
	}
	f[ guts. clipboard_formats_count-1].size      = 0;
	f[ guts. clipboard_formats_count-1].data      = NULL;
	f[ guts. clipboard_formats_count-1].name      = CF_NAME(guts. clipboard_formats_count-1);
	f[ guts. clipboard_formats_count-1].immediate = true;       /* unused */
	f[ guts. clipboard_formats_count-1].image     = NULL_HANDLE;  /* unused */
	XX-> external = f;
	return false;
}

Handle
apc_clipboard_register_format( Handle self, const char* format)
{
	int i;
	Atom x = XInternAtom( DISP, format, false);
	Atom *f;

	for ( i = 0; i < guts. clipboard_formats_count; i++) {
		if ( x == CF_NAME(i))
			return i;
	}

	if ( !( f = realloc( guts. clipboard_formats,
		sizeof( Atom) * 3 * ( guts. clipboard_formats_count + 1))))
		return false;

	guts. clipboard_formats = f;
	CF_ASSIGN( guts. clipboard_formats_count, x, x, 8);
	guts. clipboard_formats_count++;

	if ( hash_first_that( guts. clipboards, (void*)expand_clipboards, NULL, NULL, NULL))
		return -1;

	return guts. clipboard_formats_count - 1;
}

Bool
apc_clipboard_deregister_format( Handle self, Handle id)
{
	return true;
}

ApiHandle
apc_clipboard_get_handle( Handle self)
{
	return C(self)-> selection;
}

Bool
apc_clipboard_is_dnd( Handle self)
{
	return guts. xdnd_clipboard == self;
}

static Bool
delete_xfers( Handle self, int keyLen, void * key, XWindow * window)
{
	DEFCC;
	if ( XX-> xfers) {
		int i;
		for ( i = 0; i < XX-> xfers-> count; i++)
			delete_xfer( XX, ( ClipboardXfer*) XX-> xfers-> items[i]);
	}
	hash_delete( guts. clipboard_xfers, window, sizeof( XWindow), false);
	return false;
}

int
prima_clipboard_fill_targets( Handle self)
{
	DEFCC;
	int i, count = 0, have_utf8 = 0, have_plaintext = 0;
	Atom * ci;
	prima_detach_xfers( XX, cfTargets, true);
	prima_clipboard_kill_item( XX-> internal, cfTargets);

	for ( i = 0; i < guts. clipboard_formats_count; i++) {
		if ( i != cfTargets && (XX-> internal[i]. size > 0 || !XX-> internal[i]. immediate)) {
			count++;
			if ( i == cfUTF8) {
				count++;
				have_utf8 = 1;
			}
			if ( i == cfText) {
				count++;
				have_plaintext = 1;
			}
		}
	}
	if ( count == 0 ) return 0;

	if (( XX-> internal[cfTargets]. data = malloc( count * sizeof( Atom)))) {
		Cdebug("clipboard: fill targets: ", guts. clipboard_formats_count);
		XX-> internal[cfTargets]. size = count * sizeof( Atom);
		ci = (Atom*)XX-> internal[cfTargets]. data;
		for ( i = 0; i < guts. clipboard_formats_count; i++) {
			if ( i != cfTargets && ( XX-> internal[i]. size > 0 || !XX-> internal[i]. immediate)) {
				*(ci++) = CF_NAME(i);
				Cdebug("%s ", XGetAtomName(DISP, CF_NAME(i)));
			}
		}
		if ( have_utf8) {
			*(ci++) = UTF8_MIME;
			Cdebug("UTF8_MIME ");
		}
		if ( have_plaintext) {

unix/clipboard.c  view on Meta::CPAN

}

static void
handle_selection_request( XEvent *ev, XWindow win, Handle self)
{
	XEvent xe;
	int i, id = -1;
	Atom
		prop   = ev-> xselectionrequest. property,
		target = ev-> xselectionrequest. target;
	self = ( Handle) hash_fetch( guts. clipboards, &ev-> xselectionrequest. selection, sizeof( Atom));

	guts. last_time = ev-> xselectionrequest. time;
	xe. type      = SelectionNotify;
	xe. xselection. send_event = true;
	xe. xselection. serial    = ev-> xselectionrequest. serial;
	xe. xselection. display   = ev-> xselectionrequest. display;
	xe. xselection. requestor = ev-> xselectionrequest. requestor;
	xe. xselection. selection = ev-> xselectionrequest. selection;
	xe. xselection. target    = target;
	xe. xselection. property  = None;
	xe. xselection. time      = ev-> xselectionrequest. time;

	Cdebug("clipboard: from %08x %s at %s\n", ev-> xselectionrequest. requestor,
		XGetAtomName( DISP, ev-> xselectionrequest. target),
		XGetAtomName( DISP, ev-> xselectionrequest. property)
	);

	if ( self) {
		PClipboardSysData CC = C(self);
		int format, utf8_mime = 0, plaintext_mime = 0;

		for ( i = 0; i < guts. clipboard_formats_count; i++) {
			if ( xe. xselection. target == CC-> internal[i]. name) {
				id = i;
				break;
			} else if ( i == cfUTF8 && xe. xselection. target == UTF8_MIME) {
				id = i;
				utf8_mime = 1;
				break;
			} else if ( i == cfText && xe. xselection. target == PLAINTEXT_MIME) {
				id = i;
				plaintext_mime = 1;
				break;
			}
		}
		if ( id < 0) goto SEND_EMPTY;
		for ( i = 0; i < guts. clipboard_formats_count; i++)
			prima_clipboard_kill_item( CC-> external, i);

		CC-> target = xe. xselection. target;
		CC-> need_write = false;

		if ( !CC-> internal[id]. immediate && id != cfTargets ) {
			Bool ret;
			ret = ( id == cfBitmap ) ? fill_bitmap(self) : fill_target(self, target);
			if ( !ret ) goto SEND_EMPTY;
		}

		format = CF_FORMAT(id);
		target = CF_TYPE( id);
		if ( utf8_mime) target = UTF8_MIME;
		if ( plaintext_mime) target = PLAINTEXT_MIME;

		if ( id == cfTargets)
			prima_clipboard_fill_targets(self);

		if ( CC-> internal[id]. size > 0) {
			Atom incr;
			int mode = PropModeReplace;
			unsigned char * data = CC-> internal[id]. data;
			unsigned long size = CC-> internal[id]. size * 8 / format;
			if ( CC-> internal[id]. size > guts. limits. request_length - 4) {
				int ok = 0;
				int reqlen = guts. limits. request_length - 4;
				/* INCR */
				if ( !guts. clipboard_xfers)
					guts. clipboard_xfers = hash_create();
				if ( !CC-> xfers)
					CC-> xfers = plist_create( 1, 1);
				if ( CC-> xfers && guts. clipboard_xfers) {
					ClipboardXfer * x = malloc( sizeof( ClipboardXfer));
					if ( x) {
						IV refcnt;
						ClipboardXferKey key;

						bzero( x, sizeof( ClipboardXfer));
						list_add( CC-> xfers, ( Handle) x);
						x-> size = CC-> internal[id]. size;
						x-> data = CC-> internal[id]. data;
						x-> blocks = ( x-> size / reqlen ) + ( x-> size % reqlen) ? 1 : 0;
						x-> requestor = xe. xselection. requestor;
						x-> property  = prop;
						x-> target    = xe. xselection. target;
						x-> self      = self;
						x-> format    = format;
						x-> id        = id;
						gettimeofday( &x-> time, NULL);

						CLIPBOARD_XFER_KEY( key, x-> requestor, x-> property);
						hash_store( guts. clipboard_xfers, key, sizeof(key), (void*) x);
						refcnt = PTR2IV( hash_fetch( guts. clipboard_xfers, &x-> requestor, sizeof( XWindow)));
						if ( refcnt++ == 0)
							XSelectInput( DISP, x-> requestor, PropertyChangeMask|StructureNotifyMask);
						hash_store( guts. clipboard_xfers, &x-> requestor, sizeof(XWindow), INT2PTR( void*, refcnt));

						format = CF_32;
						size = 1;
						incr = ( Atom) CC-> internal[id]. size;
						data = ( unsigned char*) &incr;
						ok = 1;
						target = XA_INCR;
						Cdebug("clipboard: init INCR for %08x %d\n", x-> requestor, x-> property);
					}
				}
				if ( !ok) size = reqlen;
			}

			if ( format == CF_32) format = 32;
			XChangeProperty(
				xe. xselection. display,
				xe. xselection. requestor,
				prop, target, format, mode, data, size);
			Cdebug("clipboard: store prop %s f=%d s=%d\n", XGetAtomName( DISP, prop), format, size);
			xe. xselection. property = prop;
		}

		/* content of PIXMAP or BITMAP is seemingly gets invalidated
			after the selection transfer, unlike the string data format */
		if ( id == cfBitmap) {
			bzero( CC-> internal[id].data, CC-> internal[id].size);
			bzero( CC-> external[id].data, CC-> external[id].size);
			prima_clipboard_kill_item( CC-> internal, id);
			prima_clipboard_kill_item( CC-> external, id);
		}
	}
SEND_EMPTY:

	XSendEvent( xe.xselection.display, xe.xselection.requestor, false, 0, &xe);
	XFlush( DISP);
	Cdebug("clipboard:id %d, SelectionNotify to %08x , %s %s\n", id, xe.xselection.requestor,
		xe. xselection. property ? XGetAtomName( DISP, xe. xselection. property) : "None",
		XGetAtomName( DISP, xe. xselection. target));
	exception_check_raise();
}

static void
handle_selection_clear( XEvent *ev, XWindow win, Handle self)
{
	guts. last_time = ev-> xselectionclear. time;
	if ( XGetSelectionOwner( DISP, ev-> xselectionclear. selection) != WIN) {
		Handle c = ( Handle) hash_fetch( guts. clipboards,
			&ev-> xselectionclear. selection, sizeof( Atom));
		guts. last_time = ev-> xselectionclear. time;
		if (c) {
			int i;
			C(c)-> selection_owner = NULL_HANDLE;
			for ( i = 0; i < guts. clipboard_formats_count; i++) {
				prima_detach_xfers( C(c), i, true);
				prima_clipboard_kill_item( C(c)-> external, i);
				prima_clipboard_kill_item( C(c)-> internal, i);
			}
		}
	}
}

static void
handle_property_notify( XEvent *ev, XWindow win, Handle self)
{
	unsigned long offs, size, reqlen = guts. limits. request_length - 4, format;
	ClipboardXfer * x = ( ClipboardXfer *) self;

unix/clipboard.c  view on Meta::CPAN

		return;

	offs = x-> offset * reqlen;
	if ( offs >= x-> size) { /* clear termination */
		size = 0;
		offs = 0;
	} else {
		size = x-> size - offs;
		if ( size > reqlen) size = reqlen;
	}
	Cdebug("clipboard: put %d %d in %08x %d\n", x-> offset, size, x-> requestor, x-> property);
	if ( x-> format > 8)  size /= 2;
	if ( x-> format > 16) size /= 2;
	format = ( x-> format == CF_32) ? 32 : x-> format;
	XChangeProperty( DISP, x-> requestor, x-> property, x-> target,
		format, PropModeReplace,
		x-> data + offs, size);
	XFlush( DISP);
	x-> offset++;
	if ( size == 0) delete_xfer( CC, x);
}

static void
handle_destroy_notify( XEvent *ev, XWindow win, Handle self)
{
	Cdebug("clipboard: destroy xfers at %08x\n", ev-> xdestroywindow. window);
	hash_first_that( guts. clipboards, (void*)delete_xfers, (void*) &ev-> xdestroywindow. window, NULL, NULL);
	XFlush( DISP);
}

void
prima_handle_selection_event( XEvent *ev, XWindow win, Handle self)
{
	XCHECKPOINT;
	switch ( ev-> type) {
	case SelectionRequest:
		handle_selection_request(ev, win, self);

unix/dnd.c  view on Meta::CPAN

static Bool
handle_xdnd_leave( Handle self)
{
	if (guts.xdnd_disabled) return false;

	if ( guts.xdndr_receiver != self )
		self = guts.xdndr_receiver;
	guts.xdndr_receiver = NULL_HANDLE;
	guts.xdndr_source   = None;

	if ( guts.xdnd_clipboard )
		C(guts.xdnd_clipboard)-> xdnd_receiving = false;

	if ( guts.xdndr_widget ) {
		XWindow dummy;
		Event ev = { cmDragEnd };
		ev.dnd.allow = 0;
		ev.dnd.clipboard = NULL_HANDLE;
		ev.dnd.modmap  = query_pointer(NULL,&ev.dnd.where);
		ev.dnd.action  = dndNone;
		ev.dnd.counterpart = guts. xdnds_widget;
		XTranslateCoordinates(DISP, guts.root, X(guts.xdndr_widget)->client, 
			ev.dnd.where.x, ev.dnd.where.y,
			&ev.dnd.where.x, &ev.dnd.where.y,
			&dummy);
		guts.xdnd_disabled = true;
		CComponent(guts.xdndr_widget)-> message(guts.xdndr_widget, &ev);
		guts.xdnd_disabled = false;

unix/dnd.c  view on Meta::CPAN

	guts.xdnds_finished = true;
	return true;
}

static Bool
handle_xdnd_enter( Handle self, XEvent* xev)
{
	int i;
	PClipboardSysData CC;

	if (guts.xdnd_disabled || !guts. xdnd_clipboard) return false;

	/* consistency */
	if ( guts.xdndr_receiver != NULL_HANDLE ) {
		handle_xdnd_leave(guts. xdndr_receiver);
		guts. xdndr_receiver = NULL_HANDLE;
	}
	CC = C(guts. xdnd_clipboard);
	CC-> xdnd_receiving = true;
	guts. xdndr_receiver = self;
	guts. xdndr_action_list_cache = 0;

	/* pre-read available formats */
	guts.xdndr_source  = xev->xclient.data.l[0];
	guts.xdndr_version = xev->xclient.data.l[1] >> 24;

	if (guts.xdndr_source == guts.xdnds_sender) {
		Cdebug("dnd:enter local\n");
		return true;
	}

	Cdebug("dnd:enter %08x v%d %d %s %s %s\n", guts.xdndr_source, guts.xdndr_version,
		xev->xclient.data.l[1] & 1,
		atom_name(xev->xclient.data.l[2]),
		atom_name(xev->xclient.data.l[3]),
		atom_name(xev->xclient.data.l[4])
	);
	for ( i = 0; i < guts. clipboard_formats_count; i++) {
		prima_detach_xfers( CC, i, true);
		if ( !CC-> xdnd_sending )
			prima_clipboard_kill_item( CC-> internal, i);
		prima_clipboard_kill_item( CC-> external, i);
	}

	/* prefill 1-3 targets as if CF_TARGETS exists */
	if ((xev->xclient.data.l[1] & 1) == 0) {
		int i, size = 0;
		Atom atoms[3];
		for ( i = 2; i <= 4; i++)
			if ( xev->xclient.data.l[i] != None )
				atoms[size++] = xev->xclient.data.l[i];
		if ( !( CC-> external[cfTargets].data = malloc(size * sizeof(Atom))))

unix/dnd.c  view on Meta::CPAN

		rps = prima_read_property( guts.xdndr_source, XdndTypeList, &type, &format, &size, &data, 0);
		if ( rps != RPS_OK ) {
			free(data);
			return false;
		}
		CC-> external[cfTargets].size = size;
		CC-> external[cfTargets].data = data;
		if (pguts->debug & DEBUG_CLIP)  {
			int i;
			Atom * types = (Atom *) data;
			_debug("dnd clipboard formats:\n");
			for ( i = 0; i < size / sizeof(Atom); i++, types++)
				_debug("%d:%x %s\n", i, *types, XGetAtomName(DISP, *types));
		}
	}
	CC-> external[cfTargets].name = CF_TARGETS;
	prima_clipboard_query_targets(guts. xdnd_clipboard);

	return true;
}

static Bool
handle_xdnd_position( Handle self, XEvent* xev)
{
	Box box;
	Bool ret = false;
	int x, y, dx, dy, action, modmap;

unix/dnd.c  view on Meta::CPAN

	XTranslateCoordinates(DISP, guts.root, X(h)->client, x, y, &x, &y, &to);
	dx -= x;
	dy -= y;
	y = X(h)->size.y - y - 1;
	/* Cdebug("xdnd:final position %d %d for %08x/%08x\n",x,y,h); */

	/* send enter/leave messages */
	if ( guts. xdndr_widget != h && guts. xdndr_widget != NULL_HANDLE ) {
		Event ev = { cmDragEnd };
		ev.dnd.allow = 0;
		ev.dnd.clipboard = NULL_HANDLE;
		ev.dnd.modmap  = modmap;
		ev.dnd.where.x = x;
		ev.dnd.where.y = y;
		ev.dnd.action  = dndNone;
		if ( h )
			protect_object(h);
		guts.xdnd_disabled = true;
		CComponent(guts.xdndr_widget)-> message(guts.xdndr_widget, &ev);
		guts.xdndr_widget = NULL_HANDLE;
		guts.xdnd_disabled = false;
		if ( h ) {
			int h_stage = PObject(h)-> stage;
			unprotect_object(h);
			if (h_stage == csDead) goto FAIL;
		}
		if ( !guts.xdnd_clipboard ) goto FAIL;
	}
	if ( !h ||
		PObject(h)->stage != csNormal ||
		!X(h)->flags.dnd_aware
	)
		goto FAIL;

	action = dndCopy;
	if (guts.xdndr_version > 1)
		action = xdnd_atom_to_constant(xev->xclient.data.l[4]);

	if ( guts.xdndr_widget != h ) {
		Event ev = { cmDragBegin };
		ev.dnd.clipboard = guts.xdnd_clipboard;
		ev.dnd.modmap  = modmap;
		ev.dnd.where.x = x;
		ev.dnd.where.y = y;
		ev.dnd.action  = action;
		ev.dnd.counterpart = guts. xdnds_widget;
		guts.xdnd_disabled = true;
		CComponent(h)-> message(h, &ev);
		guts.xdnd_disabled = false;
		if (PObject(h)->stage != csNormal || !guts.xdnd_clipboard)
			goto FAIL;

		guts.xdndr_widget = h;
		bzero(&guts. xdndr_suppress_events_within, sizeof(Box));
		guts. xdndr_last_action = dndCopy;
	}

	if (!(
		action == guts.xdndr_last_action &&
		guts.xdndr_suppress_events_within.width > 0 &&

unix/dnd.c  view on Meta::CPAN

			y > guts.xdndr_suppress_events_within.height + guts.xdndr_suppress_events_within.y
		)
	)) {
		Event ev = { cmDragOver };

		if ( action == dndAsk )
			action = xdnd_read_ask_actions();
		if ( action == dndNone )
			action = dndCopy;

		ev.dnd.clipboard = guts.xdnd_clipboard;
		ev.dnd.where.x = x;
		ev.dnd.where.y = y;
		ev.dnd.action  = action;
		ev.dnd.modmap  = query_pointer(NULL,NULL);
		ev.dnd.counterpart = guts. xdnds_widget;
		guts.xdnd_disabled = true;
		CComponent(h)-> message(h, &ev);
		guts.xdnd_disabled = false;

		if (ev.dnd.pad.x < 0) ev.dnd.pad.x = 0;

unix/dnd.c  view on Meta::CPAN

}

static Bool
handle_xdnd_drop( Handle self, XEvent* xev)
{
	Event ev;
	Atom action = None;
	XEvent xr;
	XWindow last_source;

	if (!guts.xdnd_clipboard || guts.xdnd_disabled) return false;

	if (
		guts.xdndr_receiver != self ||
		guts.xdndr_widget == NULL_HANDLE
	) {
		handle_xdnd_leave(guts. xdndr_receiver);
		return false;
	}

	Cdebug("dnd:drop from %08x\n", guts.xdndr_source);

unix/dnd.c  view on Meta::CPAN

		ev.cmd = cmDragEnd;
		ev.dnd.modmap  = query_pointer(NULL,&ev.dnd.where);
		XTranslateCoordinates(DISP, guts.root, X(guts.xdndr_widget)->client, 
			ev.dnd.where.x, ev.dnd.where.y,
			&ev.dnd.where.x, &ev.dnd.where.y,
			&dummy);
		guts.xdndr_source = xev->xclient.data.l[0];
		guts.xdndr_timestamp = (guts.xdndr_version >= 1) ? xev-> xclient.data.l[2] : CurrentTime;
		ev.dnd.action = guts.xdndr_last_action;
		ev.dnd.allow = guts.xdndr_last_action != dndNone;
		ev.dnd.clipboard = ev.dnd.allow ? guts.xdnd_clipboard : NULL_HANDLE;
		ev.dnd.counterpart = guts.xdnds_widget;
		guts.xdnd_disabled = true;
		CComponent(guts.xdndr_widget)-> message(guts.xdndr_widget, &ev);
		guts.xdnd_disabled = false;
		guts.xdndr_last_target = guts.xdndr_widget;
	} else {
		ev.dnd.allow = 0;
		ev.dnd.action = dndCopy;
	}

	/* cleanup */
	guts.xdndr_widget   = NULL_HANDLE;
	last_source = guts.xdndr_source;
	guts.xdndr_source   = None;
	guts.xdndr_receiver = NULL_HANDLE;
	if ( guts. xdnd_clipboard )
		C(guts.xdnd_clipboard)->xdnd_receiving = false;

	/* respond */
	if (ev.dnd.allow) {
		if (( ev.dnd.action & dndMask ) == 0) ev.dnd.action = None;
		/* never return a combination, if DragEnd never bothered to ask */
		if ( ev.dnd.action & dndCopy ) ev.dnd.action = dndCopy;
		else if ( ev.dnd.action & dndMove ) ev.dnd.action = dndMove;
		else if ( ev.dnd.action & dndLink ) ev.dnd.action = dndLink;
		else ev.dnd.action = dndNone;
		if ( ev.dnd.action == dndNone ) ev.dnd.allow = false;

unix/dnd.c  view on Meta::CPAN

	if ( src == dst ) return true;
	top_level = get_top_window(self);
	if ( top_level == prima_guts.application ) return false;

	XX->flags. dnd_aware = dst;
	prima_update_dnd_aware( top_level );
	return true;
}

Handle
apc_dnd_get_clipboard( Handle self )
{
	return guts. xdnd_clipboard;
}

static Bool
send_drag_response(Handle self, Bool allow, int action)
{
	Event ev = { cmDragResponse };
	ev.dnd.allow = allow;
	ev.dnd.action = action;
	ev.dnd.counterpart = guts.xdndr_widget;
	guts.xdnd_disabled = true;

unix/dnd.c  view on Meta::CPAN

	Bool got_session = false;
	Point ptr, last_ptr = { -1, -1 };
	int ret = dndNone, i, modmap, first_modmap, n_actions = 0;
	Atom actions_list[3], curr_action, last_action = -1;
	char *ac_ptr, actions_descriptions[16] = ""; /* Copy Move Link */
	PClipboardSysData CC;
	Handle top_level, banned_receiver = None;
	XWindow last_xdndr_source = None;
	int old_pointer;

	if ( guts.xdnd_disabled || guts.xdnds_widget || !guts.xdnd_clipboard ) {
		Cdebug("dnd:already is action\n");
		return -1;
	}
	if ((actions & dndMask) == 0) {
		Cdebug("dnd:bad actions\n");
		return -1;
	}
	top_level = get_top_window(self);
	if ( top_level == prima_guts.application ) {
		Cdebug("dnd:no toplevel window\n");

unix/dnd.c  view on Meta::CPAN

		case dndLink: strncpy(ac_ptr, "Link", 5); break;
		default     : continue;
		}
		ac_ptr += 5;
	}
	if ( n_actions == 0) {
		Cdebug("dnd:no actions\n");
		return -1;
	}

	if ( prima_clipboard_fill_targets(guts.xdnd_clipboard) == 0) {
		Cdebug("dnd:no clipboard data\n");
		return -1; /* nothing to drag */
	}

	guts. xdnds_default_pointers = default_pointers;
	guts. xdnds_sender = PWidget(top_level)->handle;
	guts. xdnds_widget = self;
	guts. xdnds_finished = false;
	modmap = query_pointer(NULL,NULL);
	first_modmap = modmap & 0xffff;
	guts.xdnds_escape_key = false;
	guts.xdnds_last_drop_response = false;
	guts.xdnds_target = None;
	guts.xdnds_version = 0;
	guts.xdnds_last_action = guts.xdnds_last_action_response = dndNone;
	bzero( &guts.xdnds_suppress_events_within, sizeof(Box));
	protect_object(self);
	Cdebug("dnd:begin\n");

	CC = C(guts.xdnd_clipboard);
	prima_detach_xfers( CC, cfTargets, true);
	prima_clipboard_kill_item( CC-> internal, cfTargets);
	CC->internal[cfTargets].name = XdndTypeList;

	old_pointer = apc_pointer_get_shape(self);
	apc_pointer_set_shape(self, crDragNone);
	apc_widget_set_capture(self, true, NULL_HANDLE);

	if ( !default_pointers && !X(self)->flags. dnd_aware) {
		if ( !send_drag_response(self, false, dndNone)) goto EXIT;
	}

unix/dnd.c  view on Meta::CPAN

	XChangeProperty(DISP, guts. xdnds_sender, XdndActionDescription, XA_STRING, 8,
		PropModeReplace, (unsigned char*)&actions_descriptions, ac_ptr - actions_descriptions);
	XCHECKPOINT;

	guts.xdnds_last_action = actions;
	curr_action = (n_actions > 1) ? XdndActionAsk : actions_list[0];
	while ( prima_one_loop_round( WAIT_ALWAYS, true)) {
		int new_modmap;
		XWindow new_receiver;

		if ( !guts.xdnds_widget || !guts.xdnd_clipboard ) {
			Cdebug("dnd:objects killed\n");
			ret = dndNone;
			goto EXIT;
		}

		new_modmap = query_pointer(&new_receiver, &ptr);
		if ( new_receiver == banned_receiver && banned_receiver != None )
			new_receiver = guts.xdnds_target;

		if ( guts.xdnds_escape_key )

unix/dnd.c  view on Meta::CPAN

				rps = prima_read_property( new_receiver, XdndAware, &type, &format,
					&size, &data, 0);
				if ( rps != RPS_OK || type != XA_ATOM || format != CF_32 || size != sizeof(Atom)) {
					free(data);
					Cdebug("dnd:bad XdndAware\n");
					banned_receiver = new_receiver;
					continue;
				}
				guts.xdnds_version = *((Atom*)data);
				free(data);
				rps = prima_clipboard_fill_targets(guts.xdnd_clipboard);
				if ( rps == 0 ) {
					Cdebug("dnd:failed to query clipboard targets\n");
					ret = -1;
					goto EXIT;
				}

				got_session = true;
				guts.xdnds_target = new_receiver;
				targets = (Atom*) CC->internal[cfTargets].data;
				Cdebug("dnd:send enter to %08x\n",guts.xdnds_target);
				xdnds_send_enter_message(rps, targets);
			}

unix/event.c  view on Meta::CPAN

	case ReparentNotify:
		win = ev-> xreparent. window;
		break;
	case MapNotify:
		win = ev-> xmap. window;
		break;
	case UnmapNotify:
		win = ev-> xunmap. window;
		break;
	case DestroyNotify:
		if ( guts. clipboard_xfers &&
			hash_fetch( guts. clipboard_xfers, &ev-> xdestroywindow. window, sizeof( XWindow))) {
			prima_handle_selection_event( ev, ev-> xproperty. window, NULL_HANDLE);
			return;
		}
		goto DEFAULT;
	case PropertyNotify:
		guts. last_time = ev-> xproperty. time;
		if ( guts. clipboard_xfers) {
			Handle value;
			ClipboardXferKey key;
			CLIPBOARD_XFER_KEY( key, ev-> xproperty. window, ev-> xproperty. atom);
			value = ( Handle) hash_fetch( guts. clipboard_xfers, key, sizeof( key));
			if ( value) {
				prima_handle_selection_event( ev, ev-> xproperty. window, value);
				return;
			}
		}
		goto DEFAULT;
	DEFAULT:
	default:
		win = ev-> xany. window;
	}

unix/image.c  view on Meta::CPAN

		if ( !ok ) return NULL;

		cache-> type = type;
		return cache;
	}

	/*
		apply as much of system palette colors as possible to new image,
		if we're working on 1-8 bit displays. CACHE_LOW_RES on displays with
		dynamic colors goes only after conservative strategy, using only
		immutable colors to be copied to clipboard, icon, etc.
	*/
	if ( target_bpp <= 8 && img-> type != imBW) {
		int bpp, colors = 0;
		RGBColor palbuf[256], *palptr = NULL;
		if ( !dup) {
			if (!(dup = img-> self-> dup(( Handle) img)))
				return NULL;
		}
		pass = ( PImage) dup;
		if ( target_bpp <= 1) bpp = imbpp1; else

win32/clip.c  view on Meta::CPAN

#endif


#define  sys (( PDrawableData)(( PComponent) self)-> sysData)->
#define  dsys( view) (( PDrawableData)(( PComponent) view)-> sysData)->
#define var (( PWidget) self)->
#define HANDLE sys handle
#define DHANDLE(x) dsys(x) handle

PList
apc_get_standard_clipboards( void)
{
	PList l = plist_create( 1, 1);
	if (!l) return NULL;
	list_add( l, (Handle)duplicate_string( "Clipboard"));
	list_add( l, (Handle)duplicate_string( "DragDrop"));
	return l;
}

Bool
apc_clipboard_create( Handle self)
{
	char * c = ((PClipboard)self)-> name;
	if ( !c ) return false;

	if (strcmp(c, "Clipboard") == 0)
		guts.clipboards[CLIPBOARD_MAIN] = self;
	else if (strcmp(c, "DragDrop") == 0) {
		guts.clipboards[CLIPBOARD_DND] = self;
		return dnd_clipboard_create();
	} else
		return false;
	return true;
}

Bool
apc_clipboard_destroy( Handle self)
{
	int i;
	if (self == guts.clipboards[CLIPBOARD_DND])
		dnd_clipboard_destroy();
	for ( i = 0; i < 2; i++)
		if ( guts.clipboards[i] == self )
			guts.clipboards[i] = NULL_HANDLE;
	return true;
}

Bool
apc_clipboard_open( Handle self)
{
	if (self == guts.clipboards[CLIPBOARD_DND])
		return dnd_clipboard_open();

	if ( !OpenClipboard( NULL)) apiErrRet;
	return true;
}

Bool
apc_clipboard_close( Handle self)
{
	if (self == guts.clipboards[CLIPBOARD_DND])
		return dnd_clipboard_close();

	if ( !CloseClipboard()) apiErrRet;
	return true;
}

Bool
apc_clipboard_clear( Handle self)
{
	if (self == guts.clipboards[CLIPBOARD_DND])
		return dnd_clipboard_clear();

	if ( !EmptyClipboard()) apiErrRet;
	return true;
}

static Handle cf2CF( Handle id)
{
	if ( id == cfText)   return CF_TEXT;
	if ( id == cfUTF8)   return CF_UNICODETEXT;
	if ( id == cfBitmap) return CF_BITMAP;

win32/clip.c  view on Meta::CPAN

				return duplicate_string(formats[i]. desc);
			i++;
		}
		if ( GetClipboardFormatName( f, name, 255))
			return duplicate_string(name);
	}}
	return NULL;
}

PList
apc_clipboard_get_formats( Handle self)
{
	UINT f = 0;
	PList list;

	if (self == guts.clipboards[CLIPBOARD_DND])
		return dnd_clipboard_get_formats();

	list = plist_create(8, 8);
	while (( f = EnumClipboardFormats( f))) {
		char * name = cf2name(f);
		if ( f )
			list_add(list, (Handle)name);
	}

	return list;
}

Bool
apc_clipboard_has_format( Handle self, Handle id)
{
	id = cf2CF( id);
	if (self == guts.clipboards[CLIPBOARD_DND])
		return dnd_clipboard_has_format(id);

	return IsClipboardFormatAvailable( id) ||
		(( id == CF_TEXT) && IsClipboardFormatAvailable( CF_UNICODETEXT));
}

Bool
clipboard_get_data(int cfid, PClipboardDataRec c, void * p1, void * p2)
{
	switch( cfid)
	{
		case CF_DIB: {
			PIcon i;
			XBITMAPINFO * bi;
			if ( !( bi = ( XBITMAPINFO*) GlobalLock( p1)))
				apiErrRet;
			if ( bi-> header.biCompression != BI_RGB ) {
				GlobalUnlock( p1);

win32/clip.c  view on Meta::CPAN

			if (( c-> data = malloc( c-> length)))
				memcpy( c-> data, ptr, c-> length);
			GlobalUnlock( p1);
			return true;
		}
	}
	return false;
}

Bool
apc_clipboard_get_data( Handle self, Handle id, PClipboardDataRec c)
{
	void *ph;

	id = cf2CF( id);
	if (self == guts.clipboards[CLIPBOARD_DND])
		return dnd_clipboard_get_data(id, c);

	if ((ph = GetClipboardData(id)) == NULL) {
		apcErr( errInvClipboardData);
		return false;
	}

	return clipboard_get_data(id, c, ph,
		(id == CF_BITMAP) ? (void*) GetClipboardData( CF_PALETTE) : NULL);
}

Bool
apc_clipboard_set_data( Handle self, Handle id, PClipboardDataRec c)
{
	id = cf2CF( id);
	if (self == guts.clipboards[CLIPBOARD_DND])
		return dnd_clipboard_set_data(id, c);

	switch ( id)
	{
		case CF_BITMAP:
			{
				HPALETTE p = palette_create( c-> image);
				HBITMAP b  = image_create_bitmap_by_type( c-> image, p, NULL, BM_AUTO);

				if ( b == NULL) {
					if ( p) DeleteObject( p);

win32/clip.c  view on Meta::CPAN

				memcpy( ptr, c-> data, c-> length);
				GlobalUnlock( glob);
				if ( !SetClipboardData( id, glob)) apiErrRet;
				return true;
			}
	}
	return false;
}

Handle
apc_clipboard_register_format( Handle self, const char * format)
{
	UINT r;
	int i = 0;
	while ( formats[i]. format != CF_MAX) {
		if ( strcmp(formats[i]. desc, format) == 0) 
			return formats[i]. format + cfCustom;
		i++;
	}
	if ( !( r = RegisterClipboardFormat( format))) apiErrRet;
	return r + cfCustom;
}

Bool
apc_clipboard_deregister_format( Handle self, Handle id)
{
	return true;
}

ApiHandle
apc_clipboard_get_handle( Handle self)
{
	return NULL_HANDLE;
}

Bool
apc_clipboard_is_dnd( Handle self)
{
	return self == guts.clipboards[CLIPBOARD_DND];
}

#ifdef __cplusplus
}
#endif



( run in 3.283 seconds using v1.01-cache-2.11-cpan-2398b32b56e )