view release on metacpan or search on metacpan
- 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
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.
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;
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;
{
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
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);
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;
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))))
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;
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 &&
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;
}
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);
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;
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;
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");
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;
}
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 )
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