1
1
use cascade:: cascade;
2
2
use gio:: prelude:: * ;
3
+ use glib:: subclass;
4
+ use glib:: subclass:: prelude:: * ;
3
5
use gtk:: prelude:: * ;
6
+ use gtk:: subclass:: prelude:: * ;
7
+ use glib:: translate:: { FromGlibPtrFull , ToGlib , ToGlibPtr } ;
8
+ use once_cell:: unsync:: OnceCell ;
9
+ use std:: sync:: atomic:: { AtomicUsize , Ordering } ;
4
10
use std:: rc:: Rc ;
5
11
6
12
use crate :: daemon:: { Daemon , DaemonClient , DaemonDummy , daemon_server} ;
@@ -15,97 +21,168 @@ mod rect;
15
21
use keyboard:: Keyboard ;
16
22
use picker:: Picker ;
17
23
18
- fn main_app ( app : & gtk:: Application , daemon : Rc < dyn Daemon > ) {
19
- let boards = daemon. boards ( ) . expect ( "Failed to load boards" ) ;
24
+ pub struct ConfiguratorAppInner {
25
+ board_dropdown : gtk:: ComboBoxText ,
26
+ count : AtomicUsize ,
27
+ picker : Picker ,
28
+ scrolled_window : gtk:: ScrolledWindow ,
29
+ stack : gtk:: Stack ,
30
+ window : OnceCell < gtk:: ApplicationWindow > ,
31
+ }
20
32
21
- let board_dropdown = cascade ! {
22
- gtk:: ComboBoxText :: new( ) ;
23
- } ;
33
+ impl ObjectSubclass for ConfiguratorAppInner {
34
+ const NAME : & ' static str = "S76ConfiguratorApp" ;
24
35
25
- let stack = cascade ! {
26
- gtk:: Stack :: new( ) ;
27
- ..set_transition_duration( 0 ) ;
28
- } ;
36
+ type ParentType = gtk:: Application ;
29
37
30
- let picker = Picker :: new ( ) ;
38
+ type Instance = subclass:: simple:: InstanceStruct < Self > ;
39
+ type Class = subclass:: simple:: ClassStruct < Self > ;
31
40
32
- board_dropdown. connect_changed ( clone ! ( @weak stack, @weak picker => @default -panic, move |combobox| {
33
- if let Some ( id) = combobox. get_active_id( ) {
34
- stack. set_visible_child_name( & id) ;
35
- let keyboard = stack. get_child_by_name( & id) . unwrap( ) . downcast( ) . unwrap( ) ;
36
- picker. set_keyboard( Some ( keyboard) ) ;
37
- }
38
- } ) ) ;
41
+ glib_object_subclass ! ( ) ;
39
42
40
- let mut count = 0 ;
41
- for ( i, board) in boards. iter ( ) . enumerate ( ) {
42
- if let Some ( keyboard) = Keyboard :: new_board ( board, daemon. clone ( ) , i) {
43
- board_dropdown. append ( Some ( & board) , & board) ;
44
- stack. add_named ( & keyboard, & board) ;
45
- count += 1 ;
46
-
47
- if count == 1 {
48
- keyboard. show ( ) ;
49
- board_dropdown. set_active_id ( Some ( & board) ) ;
50
- picker. set_keyboard ( Some ( keyboard. clone ( ) ) ) ;
43
+ fn new ( ) -> Self {
44
+ let board_dropdown = cascade ! {
45
+ gtk:: ComboBoxText :: new( ) ;
46
+ } ;
47
+
48
+ let stack = cascade ! {
49
+ gtk:: Stack :: new( ) ;
50
+ ..set_transition_duration( 0 ) ;
51
+ } ;
52
+
53
+ let picker = Picker :: new ( ) ;
54
+
55
+ board_dropdown. connect_changed ( clone ! ( @weak stack, @weak picker => @default -panic, move |combobox| {
56
+ if let Some ( id) = combobox. get_active_id( ) {
57
+ stack. set_visible_child_name( & id) ;
58
+ let keyboard = stack. get_child_by_name( & id) . unwrap( ) . downcast( ) . unwrap( ) ;
59
+ picker. set_keyboard( Some ( keyboard) ) ;
51
60
}
52
- } else {
53
- eprintln ! ( "Failed to locate layout for '{}'" , board) ;
61
+ } ) ) ;
62
+
63
+ let vbox = cascade ! {
64
+ gtk:: Box :: new( gtk:: Orientation :: Vertical , 32 ) ;
65
+ ..set_property_margin( 10 ) ;
66
+ ..set_halign( gtk:: Align :: Center ) ;
67
+ ..add( & board_dropdown) ;
68
+ ..add( & stack) ;
69
+ ..add( & picker) ;
70
+ } ;
71
+
72
+ let scrolled_window = cascade ! {
73
+ gtk:: ScrolledWindow :: new:: <gtk:: Adjustment , gtk:: Adjustment >( None , None ) ;
74
+ ..add( & vbox) ;
75
+ } ;
76
+
77
+ Self {
78
+ board_dropdown,
79
+ count : AtomicUsize :: new ( 0 ) ,
80
+ picker,
81
+ scrolled_window,
82
+ stack,
83
+ window : OnceCell :: new ( ) ,
54
84
}
55
85
}
86
+ }
87
+
88
+ impl ObjectImpl for ConfiguratorAppInner {
89
+ glib_object_impl ! ( ) ;
90
+
91
+ fn constructed ( & self , obj : & glib:: Object ) {
92
+ self . parent_constructed ( obj) ;
93
+
94
+ let app: & ConfiguratorApp = obj. downcast_ref ( ) . unwrap ( ) ;
95
+ app. set_application_id ( Some ( "com.system76.keyboard-layout" ) ) ;
96
+ }
97
+ }
56
98
57
- if count == 0 {
58
- eprintln ! ( "Failed to locate any keyboards, showing demo" ) ;
99
+ impl ApplicationImpl for ConfiguratorAppInner {
100
+ fn activate ( & self , app : & gio:: Application ) {
101
+ let app: & ConfiguratorApp = app. downcast_ref ( ) . unwrap ( ) ;
59
102
60
- let board_names = layout:: layouts ( ) . iter ( ) . map ( |s| s. to_string ( ) ) . collect ( ) ;
61
- let daemon = Rc :: new ( DaemonDummy :: new ( board_names) ) ;
62
- let boards = daemon. boards ( ) . unwrap ( ) ;
103
+ if let Some ( window) = app. get_active_window ( ) {
104
+ //TODO
105
+ eprintln ! ( "Focusing current window" ) ;
106
+ window. present ( ) ;
107
+ } else {
108
+ let window = cascade ! {
109
+ gtk:: ApplicationWindow :: new( app) ;
110
+ ..set_title( "Keyboard Layout" ) ;
111
+ ..set_position( gtk:: WindowPosition :: Center ) ;
112
+ ..set_default_size( 1024 , 768 ) ;
113
+ ..add( & app. inner( ) . scrolled_window) ;
114
+ } ;
115
+
116
+ window. set_focus :: < gtk:: Widget > ( None ) ;
117
+ window. show_all ( ) ;
118
+
119
+ window. connect_destroy ( |_| {
120
+ eprintln ! ( "Window close" ) ;
121
+ } ) ;
63
122
64
- for ( i, board) in boards. iter ( ) . enumerate ( ) {
65
- if let Some ( keyboard) = Keyboard :: new_board ( board, daemon. clone ( ) , i) {
66
- board_dropdown. append ( Some ( & board) , & board) ;
67
- stack. add_named ( & keyboard, & board) ;
68
- count += 1 ;
123
+ let _ = app. inner ( ) . window . set ( window) ;
124
+
125
+ let daemon = daemon ( ) ;
126
+ let boards = daemon. boards ( ) . expect ( "Failed to load boards" ) ;
127
+
128
+ for ( i, board) in boards. iter ( ) . enumerate ( ) {
129
+ app. add_keyboard ( daemon. clone ( ) , board, i) ;
130
+ }
69
131
70
- if count == 1 {
71
- keyboard. show ( ) ;
72
- board_dropdown. set_active_id ( Some ( & board) ) ;
73
- picker. set_keyboard ( Some ( keyboard. clone ( ) ) ) ;
132
+ if app. inner ( ) . count . load ( Ordering :: Relaxed ) == 0 {
133
+ eprintln ! ( "Failed to locate any keyboards, showing demo" ) ;
134
+
135
+ let board_names = layout:: layouts ( ) . iter ( ) . map ( |s| s. to_string ( ) ) . collect ( ) ;
136
+ let daemon = Rc :: new ( DaemonDummy :: new ( board_names) ) ;
137
+ let boards = daemon. boards ( ) . unwrap ( ) ;
138
+
139
+ for ( i, board) in boards. iter ( ) . enumerate ( ) {
140
+ app. add_keyboard ( daemon. clone ( ) , board, i) ;
74
141
}
75
- } else {
76
- eprintln ! ( "Failed to locate layout for '{}'" , board) ;
77
142
}
78
143
}
79
144
}
145
+ }
80
146
81
- let vbox = cascade ! {
82
- gtk:: Box :: new( gtk:: Orientation :: Vertical , 32 ) ;
83
- ..set_property_margin( 10 ) ;
84
- ..set_halign( gtk:: Align :: Center ) ;
85
- ..add( & board_dropdown) ;
86
- ..add( & stack) ;
87
- ..add( & picker) ;
88
- } ;
147
+ impl GtkApplicationImpl for ConfiguratorAppInner { }
89
148
90
- let scrolled_window = cascade ! {
91
- gtk:: ScrolledWindow :: new:: <gtk:: Adjustment , gtk:: Adjustment >( None , None ) ;
92
- ..add( & vbox) ;
93
- } ;
149
+ glib_wrapper ! {
150
+ pub struct ConfiguratorApp (
151
+ Object <subclass:: simple:: InstanceStruct <ConfiguratorAppInner >,
152
+ subclass:: simple:: ClassStruct <ConfiguratorAppInner >, ConfiguratorAppClass >)
153
+ @extends gtk:: Application , gio:: Application ;
94
154
95
- let window = cascade ! {
96
- gtk:: ApplicationWindow :: new( app) ;
97
- ..set_title( "Keyboard Layout" ) ;
98
- ..set_position( gtk:: WindowPosition :: Center ) ;
99
- ..set_default_size( 1024 , 768 ) ;
100
- ..add( & scrolled_window) ;
101
- } ;
155
+ match fn {
156
+ get_type => || ConfiguratorAppInner :: get_type( ) . to_glib( ) ,
157
+ }
158
+ }
159
+
160
+ impl ConfiguratorApp {
161
+ fn new ( ) -> Self {
162
+ glib:: Object :: new ( Self :: static_type ( ) , & [ ] )
163
+ . unwrap ( )
164
+ . downcast ( )
165
+ . unwrap ( )
166
+ }
102
167
103
- window. set_focus :: < gtk:: Widget > ( None ) ;
104
- window. show_all ( ) ;
168
+ fn inner ( & self ) -> & ConfiguratorAppInner {
169
+ ConfiguratorAppInner :: from_instance ( self )
170
+ }
171
+
172
+ fn add_keyboard ( & self , daemon : Rc < dyn Daemon > , board : & str , i : usize ) {
173
+ if let Some ( keyboard) = Keyboard :: new_board ( board, daemon. clone ( ) , i) {
174
+ keyboard. show_all ( ) ;
175
+ self . inner ( ) . board_dropdown . append ( Some ( & board) , & board) ;
176
+ self . inner ( ) . stack . add_named ( & keyboard, & board) ;
105
177
106
- window. connect_destroy ( |_| {
107
- eprintln ! ( "Window close" ) ;
108
- } ) ;
178
+ if self . inner ( ) . count . fetch_add ( 1 , Ordering :: Relaxed ) == 0 {
179
+ self . inner ( ) . board_dropdown . set_active_id ( Some ( & board) ) ;
180
+ self . inner ( ) . picker . set_keyboard ( Some ( keyboard. clone ( ) ) ) ;
181
+ }
182
+ } else {
183
+ eprintln ! ( "Failed to locate layout for '{}'" , board) ;
184
+ }
185
+ }
109
186
}
110
187
111
188
#[ cfg( target_os = "linux" ) ]
@@ -190,19 +267,8 @@ pub fn run(args: Vec<String>) -> i32 {
190
267
#[ cfg( target_os = "windows" ) ]
191
268
windows_init ( ) ;
192
269
193
- let application =
194
- gtk:: Application :: new ( Some ( "com.system76.keyboard-layout" ) , Default :: default ( ) )
195
- . expect ( "Failed to create gtk::Application" ) ;
196
-
197
- application. connect_activate ( move |app| {
198
- if let Some ( window) = app. get_active_window ( ) {
199
- //TODO
200
- eprintln ! ( "Focusing current window" ) ;
201
- window. present ( ) ;
202
- } else {
203
- main_app ( app, daemon ( ) ) ;
204
- }
205
- } ) ;
270
+ gtk:: init ( ) . unwrap ( ) ;
206
271
272
+ let application = ConfiguratorApp :: new ( ) ;
207
273
application. run ( & args)
208
274
}
0 commit comments