Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file notification.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345(*
* notification.ml
* ---------------
* Copyright : (c) 2008, Jeremie Dimino <jeremie@dimino.org>
* Licence : BSD3
*
* This file is a part of obus, an ocaml implementation of D-Bus.
*)openLwt_reactopenLwtopenOBus_valueletapp_name=ref(Filename.basenameSys.argv.(0))letdesktop_entry=refNone(* +-----------------------------------------------------------------+
| Types |
+-----------------------------------------------------------------+ *)typeserver_info={server_name:string;server_vendor:string;server_version:string;server_spec_version:string;}typeimage={img_width:int;img_height:int;img_rowstride:int;img_has_alpha:bool;img_bits_per_sample:int;img_channels:int;img_data:string;}typeurgency=[`Low|`Normal|`Critical]typeid=int32(* An notification id *)(* All informations about an opened notification *)typenotification={mutablenotif_deleted:bool;(* Wether the notification as already been closed *)notif_action:string->unit;(* Wakeup the waiting thread when an action is received *)notif_closed:unit->unit;(* Wakeup the waiting thread with [`Closed] when a notification is
closed *)}type'at={result:'aLwt.t;notification:notification;peer:OBus_peer.t;id:id;}modulePeer_map=Map.Make(OBus_peer)moduleId_map=Map.Make(Int32)letnotifications:notificationId_map.trefPeer_map.tref=refPeer_map.empty(* All opened notifications, by peer then id *)letdefault_action="default"(* Default action for notifications *)(* +-----------------------------------------------------------------+
| D-Bus methods and signals |
+-----------------------------------------------------------------+ *)letserver_name="org.freedesktop.Notifications"letserver_path=["org";"freedesktop";"Notifications"]openNotification_interfaces.Org_freedesktop_Notificationsletproxy=lazy(let%lwtbus=OBus_bus.session()inreturn(OBus_proxy.make(OBus_peer.makebusserver_name)server_path))letget_server_information()=let%lwtproxy=Lazy.forceproxyinlet%lwtname,vendor,version,spec_version=OBus_method.callm_GetServerInformationproxy()inreturn{server_name=name;server_vendor=vendor;server_version=version;server_spec_version=spec_version;}letget_capabilities()=let%lwtproxy=Lazy.forceproxyinOBus_method.callm_GetCapabilitiesproxy()letnotifyproxy~app_name~id~icon~summary~body~actions~hints~timeout=let%lwtcontext,return_id=OBus_method.call_with_contextm_Notifyproxy(app_name,id,icon,summary,body,actions,hints,Int32.of_inttimeout)inreturn(OBus_context.sendercontext,return_id)letclose_notificationproxyid=OBus_method.callm_CloseNotificationproxyidlets_NotificationClosed=OBus_member.Signal.make~interface:"org.freedesktop.Notifications"~member:"NotificationClosed"~args:(arg2(None,C.basic_uint32)(None,C.basic_uint32))~annotations:[]letnotification_closedproxy=OBus_signal.makes_NotificationClosedproxylets_ActionInvoked=OBus_member.Signal.make~interface:"org.freedesktop.Notifications"~member:"ActionInvoked"~args:(arg2(None,C.basic_uint32)(None,C.basic_string))~annotations:[]letaction_invokedproxy=OBus_signal.makes_ActionInvokedproxy(* +-----------------------------------------------------------------+
| Notifications monitoring |
+-----------------------------------------------------------------+ *)letmonitor_peerpeer=ignorebeginlet%lwt()=OBus_peer.wait_for_exitpeerinletm=Peer_map.findpeer!notificationsinnotifications:=Peer_map.removepeer!notifications;(* Cancel all opened notification opened on this peer: *)Id_map.iter(funidnotif->notif.notif_closed())!m;return()endletremove_notificationpeeridnotif=notif.notif_deleted<-true;letr=Peer_map.findpeer!notificationsinr:=Id_map.removeid!rletinit_callbacks=lazy(let%lwtbus=OBus_bus.session()in(* Create an anymous proxy for connecting signals, so we will
receive signals comming from any daemon *)letanonymous_proxy={OBus_proxy.peer=OBus_peer.anonymousbus;OBus_proxy.path=server_path}inlet%lwtevent=OBus_signal.connect(OBus_signal.map_with_context(funcontext(id,reason)->(OBus_context.sendercontext,id,reason))(notification_closedanonymous_proxy))in(* Handle signals for closed notifications *)E.keep(E.map_p(fun(peer,id,reason)->matchtrySome(Peer_map.findpeer!notifications)withNot_found->Nonewith|None->return()|Somem->matchtrySome(Id_map.findid!m)withNot_found->Nonewith|None->return()|Somenotif->remove_notificationpeeridnotif;notif.notif_closed();return())event);let%lwtevent=OBus_signal.connect(OBus_signal.map_with_context(funcontext(id,action)->(OBus_context.sendercontext,id,action))(action_invokedanonymous_proxy))in(* Handle signals for actions *)E.keep(E.map_p(fun(peer,id,action)->matchtrySome(Peer_map.findpeer!notifications)withNot_found->Nonewith|None->return()|Somem->matchtrySome(Id_map.findid!m)withNot_found->Nonewith|None->return()|Somenotif->remove_notificationpeeridnotif;notif.notif_actionaction;return())event);return())(* +-----------------------------------------------------------------+
| Operations on notifications |
+-----------------------------------------------------------------+ *)letresultn=n.resultletclosen=letnotif=n.notificationinifnotnotif.notif_deletedthenbeginremove_notificationn.peern.idnotif;notif.notif_closed();(* Call the method on the peer which have opened the
notification *)close_notification(OBus_proxy.maken.peerserver_path)n.idendelsereturn()(* +-----------------------------------------------------------------+
| Openning notifications |
+-----------------------------------------------------------------+ *)letrecfilter_opt=function|[]->[]|Somex::l->x::filter_optl|None::l->filter_optlletdefault_desktop_entry=desktop_entryletnotify?(app_name=!app_name)?desktop_entry?replace?(icon="")?image~summary?(body="")?(actions=[])?urgency?category?sound_file?suppress_sound?pos?(hints=[])?(timeout=-1)()=letdesktop_entry=matchdesktop_entrywith|None->!default_desktop_entry|x->xin(*** Creation of hints ***)letmake_hintnamexf=matchxwith|Somex->Some(name,fx)|None->Noneinlethints=filter_opt[make_hint"desktop-entry"desktop_entryV.basic_string;make_hint"image_data"image(funimage->V.structure[V.basic_int32(Int32.of_intimage.img_width);V.basic_int32(Int32.of_intimage.img_height);V.basic_int32(Int32.of_intimage.img_rowstride);V.basic_booleanimage.img_has_alpha;V.basic_int32(Int32.of_intimage.img_bits_per_sample);V.basic_int32(Int32.of_intimage.img_channels);V.byte_arrayimage.img_data]);make_hint"urgency"urgency(funurgency->V.basic_int32(matchurgencywith|`Low->0l|`Normal->1l|`Critical->2l));make_hint"category"categoryV.basic_string;make_hint"sound-file"sound_fileV.basic_string;make_hint"suppress-sound"suppress_soundV.basic_boolean;make_hint"x"pos(fun(x,y)->V.basic_int32(Int32.of_intx));make_hint"y"pos(fun(x,y)->V.basic_int32(Int32.of_inty))]@hintsin(*** Handling of actions ***)let_,actions,actions_map=List.fold_right(fun(text,user_key)(acc,al,am)->(* For each action, generate a key and associate it to the
given function *)letkey=Printf.sprintf"key%d"accin(acc+1,key::text::al,(key,user_key)::am))actions(0,[],[])inletactions_map=(default_action,`Default)::actions_mapin(* Setup callbacks *)let%lwt()=Lazy.forceinit_callbacksin(* Get the proxy *)let%lwtdaemon=Lazy.forceproxyin(* Create the notification *)let%lwtpeer,id=notifydaemon~app_name~id:(matchreplacewith|Somen->n.id|None->0l)~icon~summary~body~actions~hints~timeoutinletwaiter,wakener=wait()inletnotif={notif_deleted=false;notif_action=(funaction->wakeupwakener(tryList.assocactionactions_mapwithNot_found->`Default));notif_closed=(fun()->wakeupwakener`Closed);}inbegintryletr=Peer_map.findpeer!notificationsinr:=Id_map.addidnotif!rwithNot_found->notifications:=Peer_map.addpeer(ref(Id_map.addidnotifId_map.empty))!notifications;(* Monitor the peer to be sure the notification is closed when
the peer exits *)monitor_peerpeerend;return{result=waiter;notification=notif;peer=peer;id=id;}