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