1# Copyright (c) 2003-2009, Mikhael Goikhman 2# 3# This program is free software; you can redistribute it and/or modify 4# it under the terms of the GNU General Public License as published by 5# the Free Software Foundation; either version 2 of the License, or 6# (at your option) any later version. 7# 8# This program is distributed in the hope that it will be useful, 9# but WITHOUT ANY WARRANTY; without even the implied warranty of 10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11# GNU General Public License for more details. 12# 13# You should have received a copy of the GNU General Public License 14# along with this program; if not, see: <http://www.gnu.org/licenses/> 15 16package FVWM::EventNames; 17 18use strict; 19use FVWM::Constants; 20 21use constant number => 0; 22use constant bool => 1; 23use constant window => 2; 24use constant pixel => 3; 25use constant string => 4; 26use constant wflags => 5; 27use constant looped => 6; 28 29use vars qw($EVENTS_INFO); 30 31# ---------------------------------------------------------------------------- 32# start of the would-be-generated part 33 34$EVENTS_INFO = { 35 36 &M_NEW_PAGE => { 37 format => "l!3L!4", 38 fields => [ 39 vp_x => number, 40 vp_y => number, 41 desk_n => number, 42 vp_width => number, 43 vp_height => number, 44 desk_pages_x => number, 45 desk_pages_y => number, 46 ], 47 aliases => { 48 desk => 'desk_n', 49 }, 50 }, 51 52 &M_NEW_DESK => { 53 format => "l!", 54 fields => [ 55 desk_n => number, 56 ], 57 aliases => { 58 desk => 'desk_n', 59 }, 60 }, 61 62# &M_OLD_ADD_WINDOW => { 63# }, 64 65 &M_RAISE_WINDOW => { 66 format => "L!3", 67 fields => [ 68 win_id => window, 69 frame_id => window, 70 ptr => number, 71 ], 72 }, 73 74 &M_LOWER_WINDOW => { 75 format => "L!3", 76 fields => [ 77 win_id => window, 78 frame_id => window, 79 ptr => number, 80 ], 81 }, 82 83# &M_OLD_CONFIGURE_WINDOW => { 84# }, 85 86 &M_FOCUS_CHANGE => { 87 format => "L!5", 88 fields => [ 89 win_id => window, 90 frame_id => window, 91 flip => bool, 92 focus_fg => pixel, 93 focus_bg => pixel, 94 ], 95 }, 96 97 &M_DESTROY_WINDOW => { 98 format => "L!3", 99 fields => [ 100 win_id => window, 101 frame_id => window, 102 ptr => number, 103 ], 104 }, 105 106 &M_ICONIFY => { 107 format => "L!3l!8", 108 fields => [ 109 win_id => window, 110 frame_id => window, 111 ptr => number, 112 icon_x => number, 113 icon_y => number, 114 icon_width => number, 115 icon_height => number, 116 frame_x => number, 117 frame_y => number, 118 frame_width => number, 119 frame_height => number, 120 ], 121 }, 122 123 &M_DEICONIFY => { 124 format => "L!3l!8", 125 fields => [ 126 win_id => window, 127 frame_id => window, 128 ptr => number, 129 icon_x => number, 130 icon_y => number, 131 icon_width => number, 132 icon_height => number, 133 frame_x => number, 134 frame_y => number, 135 frame_width => number, 136 frame_height => number, 137 ], 138 }, 139 140 &M_WINDOW_NAME => { 141 format => "L!3a*", 142 fields => [ 143 win_id => window, 144 frame_id => window, 145 ptr => number, 146 name => string, 147 ], 148 }, 149 150 &M_ICON_NAME => { 151 format => "L!3a*", 152 fields => [ 153 win_id => window, 154 frame_id => window, 155 ptr => number, 156 name => string, 157 ], 158 }, 159 160 &M_RES_CLASS => { 161 format => "L!3a*", 162 fields => [ 163 win_id => window, 164 frame_id => window, 165 ptr => number, 166 name => string, 167 ], 168 }, 169 170 &M_RES_NAME => { 171 format => "L!3a*", 172 fields => [ 173 win_id => window, 174 frame_id => window, 175 ptr => number, 176 name => string, 177 ], 178 }, 179 180 &M_END_WINDOWLIST => { 181 format => "", 182 fields => [ 183 ], 184 }, 185 186 &M_ICON_LOCATION => { 187 format => "L!3l!4", 188 fields => [ 189 win_id => window, 190 frame_id => window, 191 ptr => number, 192 x => number, 193 y => number, 194 width => number, 195 height => number, 196 ], 197 }, 198 199 &M_MAP => { 200 format => "L!3", 201 fields => [ 202 win_id => window, 203 frame_id => window, 204 ptr => number, 205 ], 206 }, 207 208 &M_ERROR => { 209 format => "L!3a*", 210 fields => [ 211 win_id => window, 212 frame_id => window, 213 ptr => number, 214 text => string, 215 ], 216 }, 217 218 &M_CONFIG_INFO => { 219 format => "L!3a*", 220 fields => [ 221 win_id => window, 222 frame_id => window, 223 ptr => number, 224 text => string, 225 ], 226 }, 227 228 &M_END_CONFIG_INFO => { 229 format => "", 230 fields => [ 231 ], 232 }, 233 234 &M_ICON_FILE => { 235 format => "L!3a*", 236 fields => [ 237 win_id => window, 238 frame_id => window, 239 ptr => number, 240 name => string, 241 ], 242 }, 243 244 &M_DEFAULTICON => { 245 format => "L!3a*", 246 fields => [ 247 win_id => window, 248 frame_id => window, 249 ptr => number, 250 name => string, 251 ], 252 }, 253 254 &M_STRING => { 255 format => "L!3a*", 256 fields => [ 257 win_id => window, 258 frame_id => window, 259 ptr => number, 260 text => string, 261 ], 262 }, 263 264 &M_MINI_ICON => { 265 format => "L!9a*", 266 fields => [ 267 win_id => window, 268 frame_id => window, 269 ptr => number, 270 width => number, 271 height => number, 272 depth => number, 273 icon_id => window, 274 mask => number, 275 alpha => number, 276 name => string, 277 ], 278 }, 279 280 &M_WINDOWSHADE => { 281 format => "L!3", 282 fields => [ 283 win_id => window, 284 frame_id => window, 285 ptr => number, 286 ], 287 }, 288 289 &M_DEWINDOWSHADE => { 290 format => "L!3", 291 fields => [ 292 win_id => window, 293 frame_id => window, 294 ptr => number, 295 ], 296 }, 297 298 &M_VISIBLE_NAME => { 299 format => "L!3a*", 300 fields => [ 301 win_id => window, 302 frame_id => window, 303 ptr => number, 304 name => string, 305 ], 306 }, 307 308# &M_SENDCONFIG => { 309# }, 310 311 &M_RESTACK => { 312 format => "L!3a*", 313 fields => [ 314 win_id => window, 315 frame_id => window, 316 ptr => number, 317 low_windows => looped, 318 ], 319 loop_format => "L!3a*", 320 loop_fields => [ 321 win_id => window, 322 frame_id => window, 323 ptr => number, 324 ], 325 }, 326 327 &M_ADD_WINDOW => { 328 format => "L!3l!6l!8L!2l!L!2l!3S4a*", 329 fields => [ 330 win_id => window, 331 frame_id => window, 332 ptr => number, 333 frame_x => number, 334 frame_y => number, 335 frame_width => number, 336 frame_height => number, 337 desk => number, 338 layer => number, 339 win_width => number, 340 win_height => number, 341 resize_width_inc => number, 342 resize_height_inc => number, 343 minimum_width => number, 344 minimum_height => number, 345 maximum_width => number, 346 maximum_height => number, 347 icon_title_id => window, 348 icon_image_id => window, 349 gravity => number, 350 fore_color => pixel, 351 back_color => pixel, 352 ewmh_layer => number, 353 ewmh_desktop => number, 354 ewmh_window_type => number, 355 title_height => number, 356 border_width => number, 357 dummy_zero_1 => number, 358 dummy_zero_2 => number, 359 window_flags => wflags, 360 ], 361 }, 362 363 &M_CONFIGURE_WINDOW => { 364 format => "L!3l!6l!8L!2l!L!2l!3S4a*", 365 fields => [ 366 win_id => window, 367 frame_id => window, 368 ptr => number, 369 frame_x => number, 370 frame_y => number, 371 frame_width => number, 372 frame_height => number, 373 desk => number, 374 layer => number, 375 win_width => number, 376 win_height => number, 377 resize_width_inc => number, 378 resize_height_inc => number, 379 minimum_width => number, 380 minimum_height => number, 381 maximum_width => number, 382 maximum_height => number, 383 icon_title_id => window, 384 icon_image_id => window, 385 gravity => number, 386 fore_color => pixel, 387 back_color => pixel, 388 ewmh_layer => number, 389 ewmh_desktop => number, 390 ewmh_window_type => number, 391 title_height => number, 392 border_width => number, 393 dummy_zero_1 => number, 394 dummy_zero_2 => number, 395 window_flags => wflags, 396 ], 397 }, 398 399# &M_EXTENDED_MSG => { 400# }, 401 402 &MX_VISIBLE_ICON_NAME => { 403 format => "L!3a*", 404 fields => [ 405 win_id => window, 406 frame_id => window, 407 ptr => number, 408 name => string, 409 ], 410 }, 411 412 &MX_ENTER_WINDOW => { 413 format => "L!3", 414 fields => [ 415 win_id => window, 416 frame_id => window, 417 ptr => number, 418 ], 419 }, 420 421 &MX_LEAVE_WINDOW => { 422 format => "L!3", 423 fields => [ 424 win_id => window, 425 frame_id => window, 426 ptr => number, 427 ], 428 }, 429 430 &MX_PROPERTY_CHANGE => { 431 format => "L!3a*", 432 fields => [ 433 type => number, 434 value => number, 435 win_id => window, 436 text => string, 437 ], 438 info => { 439 type_names => [ qw(NONE BACKGROUND SWALLOW) ], 440 }, 441 }, 442 443 &MX_REPLY => { 444 format => "L!3a*", 445 fields => [ 446 win_id => window, 447 frame_id => window, 448 ptr => number, 449 text => string, 450 ], 451 }, 452 453 "faked" => { 454 format => "", 455 fields => [ 456 ], 457 }, 458 459 &MX_MONITOR_DISABLED => { 460 format => "L!3a*", 461 fields => [ 462 win_id => window, 463 frame_id => window, 464 ptr => number, 465 name => string, 466 ], 467 }, 468 &MX_MONITOR_ENABLED => { 469 format => "L!3a*", 470 fields => [ 471 win_id => window, 472 frame_id => window, 473 ptr => number, 474 name => string, 475 ], 476 }, 477 &MX_MONITOR_CHANGED => { 478 format => "L!3a*", 479 fields => [ 480 win_id => window, 481 frame_id => window, 482 ptr => number, 483 name => string, 484 ], 485 }, 486 &MX_MONITOR_FOCUS => { 487 format => "L!3a*", 488 fields => [ 489 win_id => window, 490 frame_id => window, 491 ptr => number, 492 name => string, 493 ], 494 }, 495 &MX_ECHO => { 496 format => "L!a*", 497 fields => [ 498 message => string, 499 ], 500 }, 501}; 502 503# end of the would-be-generated part 504# ---------------------------------------------------------------------------- 505 506use Exporter; 507use vars qw(@EXPORT @ISA $EVENT_TYPES $EVENT_NAMES $EVENT_TYPE_NAMES); 508@EXPORT = ( 509 @FVWM::Constants::EXPORT, 510 qw(event_name event_arg_names event_arg_types event_arg_values event_args), 511 qw(event_loop_arg_names event_loop_arg_types), 512 qw(event_arg_aliases all_event_names all_event_types) 513); 514@ISA = qw(Exporter); 515 516sub all_event_type_names () { 517 if (!defined $EVENT_TYPE_NAMES) { 518 $EVENT_TYPES = []; 519 $EVENT_NAMES = []; 520 $EVENT_TYPE_NAMES = {}; 521 my ($type, $name); 522 foreach $name (@FVWM::Constants::EXPORT) { 523 next unless $name =~ /^MX?_/; 524 next if $name eq 'M_EXTENDED_MSG'; 525 no strict 'refs'; 526 $type = &$name(); 527 next if $name =~ /^MX_/ && !($type & M_EXTENDED_MSG); 528 push @$EVENT_TYPES, $type; 529 push @$EVENT_NAMES, $name; 530 $EVENT_TYPE_NAMES->{$type} = $name; 531 } 532 } 533 return $EVENT_TYPE_NAMES; 534} 535 536sub all_event_names () { 537 all_event_type_names(); 538 return wantarray? @$EVENT_NAMES: $EVENT_NAMES; 539} 540 541sub all_event_types () { 542 all_event_type_names(); 543 return wantarray? @$EVENT_TYPES: $EVENT_TYPES; 544} 545 546sub event_name ($) { 547 my $type = shift; 548 return all_event_type_names()->{$type}; 549} 550 551sub event_type_to_binary ($) { 552 my $type = shift || "no-event-type"; 553 554 return $type unless $type =~ /^\d+$/; 555 return sprintf("%b", $type); 556} 557 558sub event_info ($) { 559 my $type = shift; 560 unless (defined $EVENTS_INFO->{$type}) { 561 die "FVWM::EventNames: Unknown event type (" . 562 event_type_to_binary($type) . ")\n"; 563 } 564 return $EVENTS_INFO->{$type}; 565} 566 567sub calculate_internals ($) { 568 my $type = shift; 569 570 my $event_info = event_info($type); 571 $event_info->{names} = []; 572 $event_info->{types} = []; 573 574 my $i = 0; 575 foreach (@{$event_info->{fields}}) { 576 push @{$event_info->{names}}, $_ if ($i % 2) == 0; 577 push @{$event_info->{types}}, $_ if ($i % 2) == 1; 578 $i++; 579 } 580 581 # handle loop args if any 582 return unless exists $event_info->{loop_fields}; 583 $event_info->{loop_names} = []; 584 $event_info->{loop_types} = []; 585 586 $i = 0; 587 foreach (@{$event_info->{loop_fields}}) { 588 push @{$event_info->{loop_names}}, $_ if ($i % 2) == 0; 589 push @{$event_info->{loop_types}}, $_ if ($i % 2) == 1; 590 $i++; 591 } 592} 593 594sub event_arg_names ($$) { 595 my $type = shift; 596 my $arg_values = shift; 597 598 my $event_info = event_info($type); 599 my $arg_names = $event_info->{names}; 600 return $arg_names if defined $arg_names; 601 calculate_internals($type); 602 return $event_info->{names}; 603} 604 605sub event_arg_types ($$) { 606 my $type = shift; 607 my $arg_values = shift; 608 609 my $event_info = event_info($type); 610 my $arg_types = $event_info->{types}; 611 return $arg_types if defined $arg_types; 612 calculate_internals($type); 613 return $event_info->{types}; 614} 615 616sub event_arg_values ($$) { 617 my $type = shift; 618 my $packed_str = shift; 619 620 my $event_info = event_info($type); 621 my @arg_values = unpack($event_info->{format}, $packed_str); 622 my $arg_fields = $event_info->{fields}; 623 push @arg_values, (undef) x ((@$arg_fields / 2) - @arg_values); 624 625 # process looped args 626 if (@$arg_fields && $arg_fields->[@$arg_fields - 1] == looped) { 627 my @loop_arg_values = (); 628 629 my $rest_str = pop @arg_values; 630 while ($rest_str ne "") { 631 my @new_arg_values = unpack($event_info->{loop_format}, $rest_str); 632 die "Internal error, no loop args unpacked ($type)\n" unless @new_arg_values > 1; 633 $rest_str = pop @new_arg_values; 634 push @loop_arg_values, @new_arg_values; 635 } 636 637 push @arg_values, \@loop_arg_values; 638 } 639 640 # strip everything past the first null (or newline) if needed 641 if (@$arg_fields && $arg_fields->[-1] == string) { 642 $arg_values[-1] =~ s/\n*\0.*//s; 643 } 644 645 return \@arg_values; 646} 647 648sub event_loop_arg_names ($$) { 649 my $type = shift; 650 my $arg_values = shift; 651 652 my $event_info = event_info($type); 653 my $arg_names = $event_info->{loop_names}; 654 return $arg_names if defined $arg_names; 655 calculate_internals($type); 656 return $event_info->{loop_names}; 657} 658 659sub event_loop_arg_types ($$) { 660 my $type = shift; 661 my $arg_values = shift; 662 663 my $event_info = event_info($type); 664 my $arg_types = $event_info->{loop_types}; 665 return $arg_types if defined $arg_types; 666 calculate_internals($type); 667 return $event_info->{loop_types}; 668} 669 670sub event_args ($$) { 671 my $type = shift; 672 my $arg_values = shift; 673 674 my $arg_names = event_arg_names($type, $arg_values); 675 676 die sprintf "Internal error, event type %s (%d names, %d values)\n", 677 event_type_to_binary($type), scalar @$arg_names, scalar @$arg_values 678 if @$arg_names != @$arg_values; 679 680 my $loop_arg_names = event_loop_arg_names($type, $arg_values); 681 682 die sprintf "Internal error, event type %s (%d loop names, non array)\n", 683 event_type_to_binary($type), scalar @$loop_arg_names 684 if $loop_arg_names && ref($loop_arg_names) ne 'ARRAY' 685 && !@$loop_arg_names && ref($arg_values->[-1]) ne 'ARRAY'; 686 687 my $i = 0; 688 my %args = map { 689 my $value = $_; 690 $arg_names->[$i++], ref($value) ne 'ARRAY'? $value: do { 691 my $loop_value = []; 692 my $j = 0; 693 while ($j < @$value) { 694 my %loop_hash = map { $_, $value->[$j++] } @$loop_arg_names; 695 push @$loop_value, \%loop_hash; 696 } 697 $loop_value 698 } 699 } @$arg_values; 700 return \%args; 701} 702 703sub event_arg_aliases ($) { 704 my $type = shift; 705 706 return event_info($type)->{aliases} || {}; 707} 708 709# ---------------------------------------------------------------------------- 710 711=head1 NAME 712 713FVWM::EventNames - names and types of all fvwm event arguments 714 715=head1 SYNOPSIS 716 717 use FVWM::EventNames; 718 719 print "All event names: ", join(", ", @{all_event_names()}), "\n"; 720 print "All event types: ", join(", ", @{all_event_types()}), "\n"; 721 722 my $name = event_name (M_ICON_LOCATION); 723 my $arg_values = event_arg_values(M_ICON_LOCATION, $packed_str); 724 my $arg_names = event_arg_names (M_ICON_LOCATION, $arg_values); 725 my $arg_types = event_arg_types (M_ICON_LOCATION, $arg_values); 726 my $args = event_args (M_ICON_LOCATION, $arg_values); 727 728=head1 DESCRIPTION 729 730Every event send by I<fvwm> consist of arguments. The argument names and 731types vary from one event type to another. For example, event of the 732type B<M_NEW_DESK> consists of only one argument I<desk> of type I<number>. 733B<M_NEW_PAGE> consists of 5 numeric arguments, B<M_MINI_ICON> consists of 10 734arguments of different types. 735 736This class provides information about all fvwm events. It provides such 737services as listing all supported event types and their names, 738converting event type to event name, listing the event argument names/types, 739constructing event argument values from the plain packet data. 740 741Usually you do not need to work with this class directly, but, instead, with 742B<FVWM::Event> objects. Hovewer, you may need this class source as a 743reference for the names of the event arguments and their types. 744 745=head1 PUBLIC FUNCTIONS 746 747=over 4 748 749=item B<event_name> I<type> 750 751Returns the string representation of the numeric event I<type> constant, 752like I<M_RAISE_WINDOW> or I<MX_ENTER_WINDOW>. 753 754=item B<event_arg_values> I<type> I<packed_str> 755 756Constructs array ref of argument values for the event I<type> 757from the I<packed_str> (as received from I<fvwm>). 758 759If the last argument type of the event is string, for convenience, 760everything past the first null (or newline) is automatically stripped 761from the last argument value. 762 763=item B<event_arg_names> I<type> I<arg_values> 764 765Returns array ref of argument names of the event type. 766 767I<arg_values> is either the real array ref of values (as returned by 768B<event_arg_values>) or a number of actual values. 769The returned array has the same number of elements. 770 771=item B<event_arg_types> I<type> I<arg_values> 772 773Returns array ref of argument types of the event type. 774 775I<arg_values> is either the real array ref of values (as returned by 776B<event_arg_values>) or a number of actual values. 777The returned array has the same number of elements. 778 779=item B<event_loop_arg_names> I<type> I<arg_values> 780 781Returns array ref of looped argument names of the event type (or undef). 782 783=item B<event_loop_arg_types> I<type> I<arg_values> 784 785Returns array ref of looped argument types of the event type (or undef). 786 787=item B<event_args> I<type> I<arg_values> 788 789Constructs hash ref of the named arguments for the event I<type> 790from the I<arg_values> array ref (as returned by B<event_arg_values>). 791 792=item B<event_arg_aliases> I<type> 793 794This method is provided for backward compatibility when argument names 795are changed. For example, in the past the argument name of I<M_NEW_DESK> 796was B<desk>, but now it is B<desk_n>. Using this method it is possible 797to make both names supported. Returns hash ref (old-name => new-name). 798 799=item B<all_event_names> 800 801Returns array ref of all known event names (strings). 802In the list context returns list of these names. 803 804=item B<all_event_types> 805 806Returns array ref of all known event types (numbers). 807In the list context returns list of these types. 808 809=item B<all_event_type_names> 810 811Returns hash ref of all known event names and types (type => name). 812 813=back 814 815=head1 SEE ALSO 816 817L<FVWM::Event>. 818 819=cut 820 8211; 822