Skip to content

Commit a24b778

Browse files
committed
Implement overrides for signals
This enables `GObjectSignal` instances to map input callbacks to callbacks consumed by the GJS runtime.
1 parent 85e7f07 commit a24b778

File tree

5 files changed

+141
-24
lines changed

5 files changed

+141
-24
lines changed

src/AGS/Service/Mpris.purs

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@ module AGS.Service.Mpris
55
, disconnectMpris
66
, players
77
, matchPlayer
8-
, BusName
98
, Player
109
, PlayerProps
1110
, PlayerSignals
11+
, PlayerSignalsOverrides
12+
, PlayerPosition(..)
1213
, PlayerRecord
1314
, PlayerRecordR
15+
, BusName(..)
1416
, MprisMetadata
1517
, MprisMetadataF
1618
, fromPlayer
@@ -28,10 +30,12 @@ import Prelude
2830
import AGS.Binding (class BindProp, Binding)
2931
import AGS.Service (class BindServiceProp, class ServiceConnect, Service)
3032
import Data.Maybe (Maybe)
33+
import Data.Newtype (class Newtype)
3134
import Data.Nullable (Nullable, toMaybe)
3235
import Data.Symbol (class IsSymbol, reflectSymbol)
36+
import Data.Variant as V
3337
import Effect (Effect)
34-
import Effect.Uncurried (EffectFn1, EffectFn2)
38+
import Effect.Uncurried (EffectFn1, EffectFn2, mkEffectFn1, mkEffectFn2)
3539
import GObject (class GObjectSignal, HandlerID, unsafeCopyGObjectProps)
3640
import Record as R
3741
import Record.Studio.MapKind (mapRecordKind)
@@ -83,35 +87,52 @@ foreign import matchPlayerImpl ∷ String → Effect (Nullable Player)
8387

8488
-- *** Player
8589

90+
foreign import data PlayerType
91+
8692
newtype BusName = BusName String
8793

94+
derive instance Newtype BusName _
95+
instance Show BusName where
96+
show (BusName bn) = "(BusName " <> bn <> ")"
97+
98+
derive newtype instance Eq BusName
99+
100+
newtype PlayerPosition = PlayerPosition Number
101+
102+
derive instance Newtype PlayerPosition _
103+
104+
instance Show PlayerPosition where
105+
show (PlayerPosition pos) = "(PlayerPosition " <> show pos <> ")"
106+
107+
derive newtype instance Eq PlayerPosition
108+
derive newtype instance Ord PlayerPosition
109+
derive newtype instance Semiring PlayerPosition
110+
88111
type PlayerRecord = Record PlayerRecordR
89112

90113
type PlayerRecordR =
91-
( "bus-name"String
114+
( "bus-name"BusName
92115
, "can-go-next"Boolean
93116
, "can-go-prev"Boolean
94117
, "can-play"Boolean
95118
, "cover-path"Maybe String
96119
, entryString
97120
, identityString
98-
, lengthInt
121+
, lengthNumber
99122
, "loop-status"Maybe Boolean
100123
, metadataMprisMetadata
101124
, nameString
102125
, "play-back-status"String
103-
, positionInt
126+
, positionPlayerPosition
104127
, "shuffle-status"Maybe Boolean
105128
, "track-artists"Array String
106129
, "track-cover-url"String
107130
, "track-title"String
108131
, "track-album"String
109132
, trackidString
110-
, volumeInt
133+
, volumeNumber
111134
)
112135

113-
foreign import data PlayerType
114-
115136
type MprisMetadata = MprisMetadataF Maybe
116137

117138
type MprisMetadataF f =
@@ -156,7 +177,7 @@ fromPlayer = unsafeCopyGObjectProps @PlayerRecordR
156177

157178
type PlayerProps =
158179
-- the dbus name that starts with org.mpris.MediaPlayer2
159-
( "bus-name"String
180+
( "bus-name"BusName
160181
-- stripped from busName like spotify or firefox
161182
, nameString
162183
-- name of the player like Spotify or Mozilla Firefox
@@ -189,11 +210,17 @@ instance BindProp Player PlayerProps
189210
-- * Signals
190211

191212
type PlayerSignals =
192-
( position EffectFn2 Player Number Unit
213+
( position Player PlayerPosition Effect Unit
214+
, closed Player Effect Unit
215+
)
216+
217+
type PlayerSignalsOverrides =
218+
( position EffectFn2 Player PlayerPosition Unit
193219
, closed EffectFn1 Player Unit
194220
)
195221

196-
instance GObjectSignal Player PlayerSignals
222+
instance GObjectSignal Player PlayerSignals PlayerSignalsOverrides where
223+
overrides = V.over { position: mkEffectFn2, closed: mkEffectFn1 }
197224

198225
-- * Methods
199226

src/AGS/Service/Notifications.purs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,10 @@ import Data.Nullable (Nullable, toMaybe)
4141
import Data.Show.Generic (genericShow)
4242
import Data.Symbol (class IsSymbol, reflectSymbol)
4343
import Data.Time.Duration (Milliseconds(..))
44+
import Data.Variant as V
4445
import Effect (Effect)
45-
import Effect.Aff.Compat (runEffectFn1)
46-
import Effect.Uncurried (EffectFn2)
46+
import Effect.Aff.Compat (mkEffectFn1, runEffectFn1)
47+
import Effect.Uncurried (EffectFn2, mkEffectFn2)
4748
import GObject (class GObjectSignal, HandlerID, unsafeCopyGObjectProps)
4849
import Partial.Unsafe (unsafePartial)
4950
import Record as Record
@@ -144,12 +145,21 @@ fromNotification =
144145
-- * Signals
145146

146147
type NotificationSignals =
148+
( dismissed Notification Effect Unit
149+
, closed Notification Effect Unit
150+
, invoked Notification ActionID Effect Unit
151+
)
152+
153+
type NotificationSignalsOverrides =
147154
( dismissed EffectFn1 Notification Unit
148155
, closed EffectFn1 Notification Unit
149156
, invoked EffectFn2 Notification ActionID Unit
150157
)
151158

152-
instance GObjectSignal Notification NotificationSignals
159+
instance
160+
GObjectSignal Notification NotificationSignals NotificationSignalsOverrides where
161+
overrides = V.over
162+
{ dismissed: mkEffectFn1, closed: mkEffectFn1, invoked: mkEffectFn2 }
153163

154164
-- * Bindings and props
155165

src/AGS/Variable.purs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
module AGS.Variable
22
( Variable
33
, VariableSignals
4+
, VariableSignalsOverrides
45
, get
56
, set
67
, bindValue
@@ -14,17 +15,25 @@ import Prelude
1415

1516
import AGS.Binding (class BindProp, Binding, bindProp)
1617
import Data.Time.Duration (Milliseconds)
18+
import Data.Variant as V
1719
import Effect (Effect)
18-
import Effect.Uncurried (EffectFn1)
20+
import Effect.Uncurried (EffectFn1, mkEffectFn1)
1921
import GObject (class GObjectSignal)
2022

2123
foreign import data VariableType Type
2224

2325
type VariableSignals a =
26+
( changed Variable a Effect Unit
27+
)
28+
29+
type VariableSignalsOverrides a =
2430
( changed EffectFn1 (Variable a) Unit
2531
)
2632

27-
instance GObjectSignal (Variable a) (VariableSignals a)
33+
instance
34+
GObjectSignal (Variable a) (VariableSignals a) (VariableSignalsOverrides a)
35+
where
36+
overrides = V.over { changed: mkEffectFn1 }
2837

2938
-- | Get the value of a variable.
3039
foreign import get a. Variable a Effect a

src/GObject.purs

Lines changed: 57 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,90 @@
11
module GObject
22
( HandlerID
33
, class GObjectSignal
4+
, overrides
45
, connect
56
, disconnect
67
, unsafeCopyGObjectProps
78
) where
89

910
import Prelude
1011

12+
import Data.Maybe (Maybe(..))
1113
import Data.Symbol (class IsSymbol, reflectSymbol)
14+
import Data.Variant (Variant)
15+
import Data.Variant as V
1216
import Effect (Effect)
1317
import Effect.Uncurried (EffectFn2, EffectFn3, runEffectFn2, runEffectFn3)
18+
import Partial.Unsafe (unsafeCrashWith)
1419
import Prim.Row as R
1520
import Record.Studio.Keys (class Keys, keys)
1621
import Type.Proxy (Proxy(..))
1722

1823
foreign import data HandlerID k. k Type
1924

20-
class GObjectSignalType Row Type Constraint
21-
class GObjectSignal object signals | object signals
25+
-- | This class establishes how different GObjects should connect to signals.
26+
-- | The first type parameter lays out the user-facing callback types, and
27+
-- | the second type parameter lays out the types used by GJS runtime.
28+
-- | An instance could look as follows:
29+
-- |
30+
-- | ```purescript
31+
-- | foreign import data Object1 ∷ Type -- the GObject
32+
-- | type Signals = ( changed ∷ EffectFn2 Object1 Int Unit )
33+
-- | -- don't apply any overrides
34+
-- | instance GObjectSignal Object1 Signals Signals where
35+
-- | overrides = V.over {}
36+
-- |
37+
-- | -- now the same, but with overrides
38+
-- | foreign import data Object2 ∷ Type
39+
-- | type Signals = ( changed ∷ Effect Unit )
40+
-- | type SignalOverrides = ( changed ∷ EffectFn2 Object2 String Unit )
41+
-- | instance GObjectSignal Object2 Signals SignalOverrides where
42+
-- | overrides = V.over { changed: \cb → mkEffectFn2 \_ _ → cb }
43+
-- | ```
44+
-- |
45+
-- | *Note*: for an instance to be found, a type alias used in the
46+
-- | instance head must be exported.
47+
class GObjectSignalType Row Type Row Type Constraint
48+
class
49+
GObjectSignal object signals overrides
50+
| object signals overrides
51+
where
52+
overrides Variant signals Variant overrides
2253

54+
-- | Connect a GObject to a signal.
55+
-- | Example:
56+
-- |
57+
-- | ```purescript
58+
-- | connect @"changed" myObject \_obj info → log info
59+
-- | ```
2360
connect
24-
@sig @obj cb rt os
61+
@sig @obj cb pcb rt os ovs
2562
. R.Cons sig cb rt os
26-
GObjectSignal obj os
63+
-- This constraint aids the compiler find the type of
64+
-- the processed callback to project the variant's value.
65+
-- It shouldn't be removed.
66+
R.Cons sig pcb rt ovs
67+
GObjectSignal obj os ovs
2768
IsSymbol sig
2869
obj
2970
cb
3071
Effect (HandlerID obj)
31-
connect = runEffectFn3 connectImpl (reflectSymbol (Proxy @sig))
72+
connect o cb' =
73+
V.inj label cb'
74+
# overrides @obj @os
75+
# V.prj label
76+
# case _ of
77+
Just cb → runEffectFn3 connectImpl (reflectSymbol label) o cb
78+
Nothing → unsafeCrashWith "connect: impossible"
79+
80+
where
81+
label = Proxy @sig
3282

3383
foreign import connectImpl f o. EffectFn3 String o f (HandlerID o)
3484

3585
-- | Disconnect a GObject given its HandlerID.
36-
disconnect @obj os. GObjectSignal obj os obj HandlerID obj Effect Unit
86+
disconnect
87+
@obj os ovs. GObjectSignal obj os ovs obj HandlerID obj Effect Unit
3788
disconnect = runEffectFn2 disconnectImpl
3889

3990
foreign import disconnectImpl o. EffectFn2 o (HandlerID o) Unit

src/Gio/FileMonitor.purs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
module Gio.FileMonitor
22
( GioFileMonitor
33
, FileMonitorSignals
4+
, FileMonitorSignalsOverrides
45
, monitor
56
, monitorFile
67
, monitorDirectory
@@ -11,31 +12,50 @@ module Gio.FileMonitor
1112

1213
import Prelude
1314

15+
import Data.Enum (toEnum)
16+
import Data.Maybe (fromJust)
1417
import Data.Nullable (Nullable)
18+
import Data.Variant as V
1519
import Effect (Effect)
1620
import Effect.Uncurried
1721
( EffectFn1
1822
, EffectFn2
1923
, EffectFn4
24+
, mkEffectFn1
25+
, mkEffectFn4
2026
, runEffectFn1
2127
, runEffectFn2
2228
)
2329
import GObject (class GObjectSignal)
2430
import Gio.File (GioFile)
2531
import Gio.FileMonitorEvent (GioFileMonitorEvent)
2632
import Gio.FileMonitorFlags (GioFileMonitorFlags)
33+
import Partial.Unsafe (unsafePartial)
2734
import Unsafe.Coerce (unsafeCoerce)
2835

2936
foreign import data GioFileMonitorType
3037

3138
-- * Signals
3239

3340
type FileMonitorSignals =
34-
( changed EffectFn4 GioFileMonitor GioFile GioFile GioFileMonitorEvent Unit
41+
( changed
42+
GioFileMonitor GioFile GioFile GioFileMonitorEvent Effect Unit
43+
, "notify::cancelled"GioFileMonitor Effect Unit
44+
)
45+
46+
type FileMonitorSignalsOverrides =
47+
( changed EffectFn4 GioFileMonitor GioFile GioFile Int Unit
3548
, "notify::cancelled"EffectFn1 GioFileMonitor Unit
3649
)
3750

38-
instance GObjectSignal GioFileMonitor FileMonitorSignals
51+
instance
52+
GObjectSignal GioFileMonitor FileMonitorSignals FileMonitorSignalsOverrides
53+
where
54+
overrides = V.over
55+
{ changed: \cb → mkEffectFn4 \a b c int →
56+
cb a b c (unsafePartial $ fromJust $ toEnum int)
57+
, "notify::cancelled": mkEffectFn1
58+
}
3959

4060
-- * Methods
4161

0 commit comments

Comments
 (0)