summaryrefslogtreecommitdiffstats
path: root/src/perl/xim-onthespot
blob: b5acee294a944b88c3f26ae94f7f4af8b810a2f1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#! perl

=head1 NAME

xim-onthespot - implement XIM "on-the-spot" behaviour

=head1 DESCRIPTION

This perl extension implements OnTheSpot editing. It does not work
perfectly, and some input methods don't seem to work well with OnTheSpot
editing in general, but it seems to work at least for SCIM and kinput2.

You enable it by specifying this extension and a preedit style of
C<OnTheSpot>, i.e.:

   urxvt -pt OnTheSpot -pe xim-onthespot

=cut

#
# problems with this implementation include
#
# - primary, secondary, tertiary are NO different to other highlighting styles
# - if rend values are missing, they are not being interpolated
#

my $SIZEOF_LONG = length pack "l!", 0;

sub refresh {
   my ($self) = @_;

   delete $self->{overlay};

   my $text = $self->{text};

   return unless length $text;

   my ($row, $col) = $self->screen_cur;

   my $idx = 0;

   my @rend = map {
      my $rstyle = $self->{caret} == $idx ? urxvt::OVERLAY_RSTYLE : $self->rstyle;

      $rstyle |= urxvt::RS_Uline   if $_ & (urxvt::XIMUnderline | urxvt::XIMPrimary);
      $rstyle |= urxvt::RS_RVid    if $_ & (urxvt::XIMReverse   | urxvt::XIMSecondary);
      $rstyle |= urxvt::RS_Italic  if $_ & (urxvt::XIMHighlight | urxvt::XIMTertiary);

      ($rstyle) x ($self->strwidth (substr $text, $idx++, 1))
   } unpack "l!*", $self->{rend};

   if ($self->{caret} >= length $text) {
      $text .= " ";
      push @rend, urxvt::OVERLAY_RSTYLE;
   }

   $self->{overlay} = $self->overlay ($col, $row, $self->strwidth ($text), 1, $self->rstyle, 0);
   $self->{overlay}->set (0, 0, $self->special_encode ($text), \@rend);
}

sub on_xim_preedit_start {
   my ($self) = @_;

   ()
}

sub on_xim_preedit_done {
   my ($self) = @_;

   delete $self->{overlay};
   delete $self->{text};
   delete $self->{rend};

   ()
}

sub on_xim_preedit_draw {
   my ($self, $caret, $pos, $len, $feedback, $chars) = @_;

   $self->{caret} = $caret;

   substr $self->{rend}, $pos * $SIZEOF_LONG, $len * $SIZEOF_LONG, $feedback;
   substr $self->{text}, $pos               , $len               , $chars if defined $feedback || !defined $chars;

   $self->refresh;

   ()
}