File Coverage

blib/lib/Win32/Snarl.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             package Win32::Snarl;
2            
3 1     1   34978 use 5.008000;
  1         3  
  1         32  
4 1     1   5 use strict;
  1         1  
  1         28  
5 1     1   3 use warnings;
  1         6  
  1         9010  
6            
7             our @ISA = qw();
8             our $VERSION = '1.01';
9            
10 1     1   11 use Carp;
  1         2  
  1         146  
11 1     1   515 use Win32::GUI ();
  0            
  0            
12            
13             # Windows message number
14             use constant WM_COPYDATA => 0x04a;
15             use constant WM_USER => 0x400;
16             use constant WM_SNARLTEST => WM_USER + 237;
17            
18             # Snarl Commands
19             use constant SNARL_SHOW => 1;
20             use constant SNARL_HIDE => 2;
21             use constant SNARL_UPDATE => 3;
22             use constant SNARL_IS_VISIBLE => 4;
23             use constant SNARL_GET_VERSION => 5;
24             use constant SNARL_REGISTER_CONFIG_WINDOW => 6;
25             use constant SNARL_REVOKE_CONFIG_WINDOW => 7;
26             use constant SNARL_REGISTER_ALERT => 8;
27             use constant SNARL_REVOKE_ALERT => 9;
28             use constant SNARL_REGISTER_CONFIG_WINDOW_2 => 10;
29             use constant SNARL_EX_SHOW => 32;
30            
31             # Global Events
32             use constant SNARL_LAUNCHED => 1;
33             use constant SNARL_QUIT => 2;
34             use constant SNARL_ASK_APPLET_VER => 3;
35             use constant SNARL_SHOW_APP_UI => 4;
36            
37             # Notification Events
38             use constant SNARL_NOTIFICATION_CLICKED => 32;
39             use constant SNARL_NOTIFICATION_TIMED_OUT => 33;
40             use constant SNARL_NOTIFICATION_ACK => 34;
41             use constant SNARL_NOTIFICATION_CANCELLED => 32;
42            
43             # Error Responses
44             use constant M_NOT_IMPLEMENTED => 0x80000001;
45             use constant M_OUT_OF_MEMORY => 0x80000002;
46             use constant M_INVALID_ARGS => 0x80000003;
47             use constant M_NO_INTERFACE => 0x80000004;
48             use constant M_BAD_POINTER => 0x80000005;
49             use constant M_BAD_HANDLE => 0x80000006;
50             use constant M_ABORTED => 0x80000007;
51             use constant M_FAILED => 0x80000008;
52             use constant M_ACCESS_DENIED => 0x80000009;
53             use constant M_TIMED_OUT => 0x8000000a;
54             use constant M_NOT_FOUND => 0x8000000b;
55             use constant M_ALREADY_EXISTS => 0x8000000c;
56            
57             # C Struct Formats
58             use constant PACK_FORMAT => 'l4a1024a1024a1024';
59             use constant PACK_FORMAT_EX => 'l4a1024a1024a1024 a1024a1024a1024l2';
60            
61             # Subroutines
62            
63             sub _Dump {
64             my ($mem) = @_;
65            
66             unpack('H2' x length($mem), $mem);
67             }
68            
69             sub _Test {
70             my $hwnd = GetSnarlWindow() or return M_FAILED;
71             Win32::GUI::SendMessage($hwnd, WM_SNARLTEST, 0, 0);
72             }
73            
74             sub _SendMessage {
75             my ($struct) = @_;
76            
77             my $hwnd = GetSnarlWindow() or return M_FAILED;
78             my $cd = pack 'L2P', 2, length $struct, $struct;
79             my $res = Win32::GUI::SendMessage($hwnd, WM_COPYDATA, 0, $cd);
80            
81             if (my $err = _Error($res)) {
82             croak $err;
83             }
84            
85             $res;
86             }
87            
88             sub _MakeString {
89             my ($data) = @_;
90            
91             substr($data, 0, 1023);
92             }
93            
94             sub _MakeStruct {
95             my %params = @_;
96            
97             my @fields = qw[command id timeout data title text icon];
98            
99             $params{$_} ||= 0 for qw[command id timeout data];
100             $params{$_} = _MakeString($params{$_} || '') for qw[title text icon];
101            
102             pack PACK_FORMAT, @params{@fields};
103             }
104            
105             sub _MakeStructEx {
106             my %params = @_;
107            
108             my @fields = qw[command id timeout data title text icon class extra extra2 reserved1 reserved2];
109            
110             $params{$_} ||= 0 for qw[command id timeout data reserved1 reserved2];
111             $params{$_} = _MakeString($params{$_} || '') for qw[title text icon class extra extra2];
112            
113             pack PACK_FORMAT_EX, @params{@fields};
114             }
115            
116             sub _Error {
117             my ($value) = @_;
118            
119             $value += 0xffffffff if $value < 0;
120            
121             my %errors = (
122             0x80000001 => 'Not Implemented',
123             0x80000002 => 'Out of Memory',
124             0x80000003 => 'Invalid Arguments',
125             0x80000004 => 'No Interface',
126             0x80000005 => 'Bad Pointer',
127             0x80000006 => 'Bad Handle',
128             0x80000007 => 'Aborted',
129             0x80000008 => 'Failed',
130             0x80000009 => 'Access Denied',
131             0x8000000a => 'Timed Out',
132             0x8000000b => 'Not Found',
133             0x8000000c => 'Already Exists',
134             );
135            
136             return $errors{$value};
137             }
138            
139             =head1 NAME
140            
141             Win32::Snarl - Perl extension for Snarl notifications
142            
143             =head1 SYNOPSIS
144            
145             use Win32::Snarl;
146            
147             Win32::Snarl::ShowMessage('Perl', 'Perl is awesome, so is Snarl.');
148            
149             my $msg_id = Win32::Snarl::ShowMessage('Time', 'The time is now ' . (scalar localtime));
150             while (Win32::Snarl::IsMessageVisible($msg_id)) {
151             sleep 1;
152             Win32::Snarl::UpdateMessage($msg_id, 'Time', 'The time is now ' . (scalar localtime));
153             }
154            
155             =head1 DESCRIPTION
156            
157             Snarl Ehttp://www.fullphat.net/E is a notification system inspired by
158             Growl Ehttp://growl.info/E for Macintosh that lets applications display
159             nice alpha-blended messages on the screen.
160            
161             C is the perl interface to Snarl.
162            
163             =head1 NORMAL METHOD INTERFACE
164            
165             =cut
166            
167             sub GetAppPath { M_NOT_IMPLEMENTED }
168             sub GetGlobalMsg { M_NOT_IMPLEMENTED }
169             sub GetIconsPath { M_NOT_IMPLEMENTED }
170             sub GetVersion { M_NOT_IMPLEMENTED }
171             sub SetTimeout { M_NOT_IMPLEMENTED }
172            
173             =head2 GetSnarlWindow()
174            
175             Returns a handle to the current Snarl Dispatcher window, or zero if it wasn't
176             found. This is the recommended way to test if Snarl is running or not.
177            
178             =cut
179            
180             sub GetSnarlWindow {
181             # no parameters
182            
183             my $hwnd = Win32::GUI::FindWindow('', 'Snarl');
184             return unless Win32::GUI::IsWindow($hwnd);
185            
186             return $hwnd;
187             }
188            
189             =head2 GetVersionEx()
190            
191             Returns the Snarl system version number. This is an integer value which
192             represents the system build number and can be used to identify the specific
193             version of Snarl running. Of course, as this function is only available as of
194             Snarl V37, if calling it returns zero (or an M_RESULT value) you should use
195             C to determine which pre-V37 version of Snarl is installed.
196            
197             =cut
198            
199             sub GetVersionEx {
200             # no parameters
201            
202             _SendMessage(_MakeStruct(
203             command => SNARL_GET_VERSION,
204             ));
205             }
206            
207             =head2 HideMessage($id)
208            
209             Hides the notification specified by $id. $id is the value returned by
210             C or C when the notification was initially created.
211             This function returns True if the notification was successfully hidden or False
212             otherwise (for example, the notification may no longer exist).
213            
214             =cut
215            
216             sub HideMessage {
217             my ($id) = @_;
218            
219             _SendMessage(_MakeStruct(
220             command => SNARL_HIDE,
221             id => $id,
222             ));
223             }
224            
225             =head2 IsMessageVisible($id)
226            
227             Returns True if the notification specified by $id is still visible, or False if
228             not. $id is the value returned by c or c when the
229             notification was initially created.
230            
231             =cut
232            
233             sub IsMessageVisible {
234             my ($id) = @_;
235            
236             _SendMessage(_MakeStruct(
237             command => SNARL_IS_VISIBLE,
238             id => $id,
239             ));
240             }
241            
242             =head2 RegisterAlert($application, $class)
243            
244             Registers an alert of $class for application $application which must have
245             previously been registered with either C or C.
246             $class is displayed in the Snarl Preferences panel so it should be people
247             friendly ("My cool alert" as opposed to "my_cool_alert").
248            
249             If $application isn't registered you'll get M_NOT_FOUND returned. Other
250             possible return values are M_FAILED if Snarl isn't running, M_TIMED_OUT if
251             Snarl couldn't process the request quickly enough, or M_ALREADY_EXISTS if the
252             alert has already been registered. If all went well, M_OK is returned.
253            
254             =cut
255            
256             sub RegisterAlert {
257             my ($application, $class) = @_;
258            
259             _SendMessage(_MakeStruct(
260             command => SNARL_REGISTER_ALERT,
261             title => $application,
262             text => $class,
263             ));
264             }
265            
266             =head2 RegisterConfig($hwnd, $application, $reply)
267            
268             Registers an application's configuration interface with Snarl. $application is
269             the text that's displayed in the Applications list so it should be people
270             friendly ("My cool app" rather than "my_cool_app"). Also, it really should
271             match the name of the application as when a user runs an application called
272             "MyCoolApp.exe" they'd expect to see that appear in the Applications list and
273             not "Titanics Cruncher 1.1".
274            
275             As of V37, if the user double-clicks the application's entry in the Preferences
276             panel, one of two things can happen: if the window specified in $hwnd has a
277             title then it is simply displayed by Snarl - this is to maintain backwards
278             compatability with previous releases of Snarl. If, however, the window has no
279             title and $reply is non-zero then Snarl sends $reply to the window specified in
280             $hwnd with SNARL_SHOW_APP_UI in wParam.
281            
282             Be sure to call C when your application exits. If you fail to do
283             this, your application will remain orphaned in Snarl's Preferences panel until
284             the user quits Snarl.
285            
286             =cut
287            
288             sub RegisterConfig {
289             my ($hwnd, $application, $reply) = @_;
290            
291             _SendMessage(_MakeStruct(
292             command => SNARL_REGISTER_CONFIG_WINDOW,
293             id => $reply,
294             data => $hwnd,
295             title => $application,
296             ));
297             }
298            
299             =head2 RegisterConfig2($hwnd, $application, $reply, $icon)
300            
301             Registers an application's configuration interface with Snarl. This function is
302             identical to C except that $icon can be used to specify a PNG
303             image which will be displayed against the application's entry in Snarl's
304             Preferences panel.
305            
306             Be sure to call C when your application exits. If you fail to do
307             this, your application will remain orphaned in Snarl's Preferences panel until
308             the user quits Snarl.
309            
310             =cut
311            
312             sub RegisterConfig2 {
313             my ($hwnd, $application, $reply, $icon) = @_;
314            
315             _SendMessage(_MakeStruct(
316             command => SNARL_REGISTER_CONFIG_WINDOW_2,
317             id => $reply,
318             data => $hwnd,
319             title => $application,
320             icon => $icon,
321             ));
322             }
323            
324             =head2 RevokeConfig($hwnd)
325            
326             Removes the application previously registered using C or
327             C. $hwnd should be the same as that used during registration.
328             Typically this is done as part of an application's shutdown procedure.
329            
330             This function returns M_OK on success. Other possible return values are
331             M_FAILED if Snarl isn't running, M_TIMED_OUT if Snarl couldn't process the
332             request quickly enough or M_NOT_FOUND if the application wasn't already
333             registered.
334            
335             =cut
336            
337             sub RevokeConfig {
338             my ($hwnd) = @_;
339            
340             _SendMessage(_MakeStruct(
341             command => SNARL_REVOKE_CONFIG_WINDOW,
342             data => $hwnd,
343             ));
344             }
345            
346             =head2 ShowMessage($title, $text, $timeout, $icon, $hwnd, $reply)
347            
348             Displays a message with $title and $text. $timeout controls how long the
349             message is displayed for (in seconds) (omitting this value means the message is
350             displayed indefinately). $icon specifies the location of a PNG image which will
351             be displayed alongside the message text.
352            
353             $hwnd and $reply identify the handle of a window and a Windows message
354             respectively. If both are provided then $reply will be sent to $hwnd if the
355             user right- or left-clicks the message, or the message times out. In each
356             instance the wParam value of the message will be set to one of the following
357             values:
358            
359             Right Click SNARL_NOTIFICATION_CLICKED
360             Left Click SNARL_NOTIFICATION_ACK
361             Interval Expires SNARL_NOTIFICATION_TIMED_OUT
362            
363             If all goes well this function returns a value which uniquely identifies the
364             new notification. Other possible return values are M_FAILED if Snarl isn't
365             running, or M_TIMED_OUT if Snarl couldn't process the request quickly enough.
366            
367             =cut
368            
369             sub ShowMessage {
370             my ($title, $text, $timeout, $icon, $hwnd, $reply) = @_;
371            
372             _SendMessage(_MakeStruct(
373             command => SNARL_SHOW,
374             id => $reply,
375             timeout => $timeout,
376             data => $hwnd,
377             title => $title,
378             text => $text,
379             icon => $icon,
380             ));
381             }
382            
383             =head2 ShowMessageEx($class, $title, $text, $timeout, $icon, $hwnd, $reply, $sound)
384            
385             Displays a notification. This function is identical to C except
386             that $class specifies an alert previously registered with C and
387             $sound can optionally specify a WAV sound to play when the notification is
388             displayed on screen.
389            
390             $sound can either be a filename to a specific sound to play, or it can
391             represent a system sound. To play a system sound, prefix the name of the sound
392             with a '+' symbol. For example, to play the default 'Mail Received' system
393             sound, you would specify "+MailBeep" in SoundFile. System sounds are listed
394             under C in the Registry. Note that if
395             an existing sound is being played, the requested sound may not be played,
396             although the notification will still be displayed.
397            
398             If all goes well this function returns a value which uniquely identifies the
399             new notification. Other possible return values are M_FAILED if Snarl isn't
400             running, M_TIMED_OUT if Snarl couldn't process the request quickly enough,
401             M_BAD_HANDLE or M_NOT_FOUND if the application isn't registered with Snarl or
402             M_ACCESS_DENIED if the user has blocked the notification class within Snarl's
403             preferences.
404            
405             =cut
406            
407             sub ShowMessageEx {
408             my ($class, $title, $text, $timeout, $icon, $hwnd, $reply, $sound) = @_;
409            
410             _SendMessage(_MakeStructEx(
411             command => SNARL_EX_SHOW,
412             id => $reply,
413             timeout => $timeout,
414             data => $hwnd,
415             title => $title,
416             text => $text,
417             icon => $icon,
418             class => $class,
419             extra => $sound,
420             ));
421             }
422            
423             =head2 UpdateMessage($id, $title, $text, $icon)
424            
425             Changes the title and text in the message specified by $id to the values
426             specified by $title and $text respectively. $id is the value returned by
427             C or C when the notification was originally
428             created. To change the timeout parameter of a notification, use C
429            
430             If all goes well this function returns M_OK. Other possible return values are
431             M_FAILED if Snarl isn't running, M_TIMED_OUT if Snarl couldn't process the
432             request quickly enough or M_NOT_FOUND if the specified notification wasn't
433             found.
434            
435             =cut
436            
437             sub UpdateMessage {
438             my ($id, $title, $text, $icon) = @_;
439            
440             _SendMessage(_MakeStruct(
441             command => SNARL_UPDATE,
442             id => $id,
443             title => $title,
444             text => $text,
445             icon => $icon,
446             ));
447             }
448            
449             =head1 OBJECT INTERFACE
450            
451             There is also an object interface to this module but it is a work in progress.
452            
453             =head1 KNOWN ISSUES
454            
455             Currently, the C function gets a M_BAD_POINTER response and does
456             not function. This makes C, C, and
457             C pretty useless.
458            
459             =head1 SEE ALSO
460            
461             C For Windows API Calls
462            
463             Snarl Documentation Ehttp://www.fullphat.net/dev/E
464            
465             =head1 AUTHOR
466            
467             Alan Berndt, Ealan@eatabrick.orgE
468            
469             =head1 COPYRIGHT AND LICENSE
470            
471             Copyright (C) 2010 by Alan Berndt
472            
473             This library is free software; you can redistribute it and/or modify
474             it under the same terms as Perl itself, either Perl version 5.8.8 or,
475             at your option, any later version of Perl 5 you may have available.
476            
477             =cut
478            
479             1;