Merging 2.0 branch
Andrew P.
9 years ago
0 | 0 | <?xml version="1.0" encoding="UTF-8"?> |
1 | 1 | <!-- Generated with glade 3.18.3 --> |
2 | 2 | <interface> |
3 | <requires lib="gtk+" version="3.4"/> | |
3 | <requires lib="gtk+" version="3.8"/> | |
4 | <requires lib="" version="3.8"/> | |
4 | 5 | <requires lib="gtk_greeter_settings" version="1.0"/> |
5 | <object class="GtkFileFilter" id="greeter_default-user-image_path_dialog_filter"> | |
6 | <mime-types> | |
7 | <mime-type>image/*</mime-type> | |
8 | </mime-types> | |
9 | </object> | |
10 | <object class="GtkImage" id="greeter_default-user-image_path_dialog_preview"> | |
11 | <property name="visible">True</property> | |
12 | <property name="can_focus">False</property> | |
13 | <property name="yalign">0</property> | |
14 | <property name="pixel_size">64</property> | |
15 | <property name="icon_name">unknown</property> | |
16 | <property name="icon_size">6</property> | |
17 | </object> | |
18 | 6 | <object class="GtkListStore" id="greeter_indicators_model"> |
19 | 7 | <columns> |
20 | 8 | <!-- column-name name --> |
21 | 9 | <column type="gchararray"/> |
22 | 10 | <!-- column-name tooltip --> |
23 | 11 | <column type="gchararray"/> |
24 | <!-- column-name editable --> | |
25 | <column type="gboolean"/> | |
26 | 12 | <!-- column-name has-state --> |
27 | 13 | <column type="gboolean"/> |
28 | 14 | <!-- column-name state --> |
29 | 15 | <column type="gboolean"/> |
16 | <!-- column-name options --> | |
17 | <column type="GObject"/> | |
18 | <!-- column-name icon --> | |
19 | <column type="gchararray"/> | |
20 | <!-- column-name markup --> | |
21 | <column type="gchararray"/> | |
30 | 22 | </columns> |
31 | <data> | |
32 | <row> | |
33 | <col id="0">~host</col> | |
34 | <col id="1" translatable="yes" context="option|indicators">Host name</col> | |
35 | <col id="2">False</col> | |
36 | <col id="3">True</col> | |
37 | <col id="4">False</col> | |
38 | </row> | |
39 | <row> | |
40 | <col id="0">~clock</col> | |
41 | <col id="1" translatable="yes" context="option|indicators">Clock</col> | |
42 | <col id="2">False</col> | |
43 | <col id="3">True</col> | |
44 | <col id="4">False</col> | |
45 | </row> | |
46 | <row> | |
47 | <col id="0">~layout</col> | |
48 | <col id="1" translatable="yes" context="option|indicators">Layout indicator</col> | |
49 | <col id="2">False</col> | |
50 | <col id="3">True</col> | |
51 | <col id="4">False</col> | |
52 | </row> | |
53 | <row> | |
54 | <col id="0">~session</col> | |
55 | <col id="1" translatable="yes" context="option|indicators">Sessions menu (xfce, unity, gnome etc.)</col> | |
56 | <col id="2">False</col> | |
57 | <col id="3">True</col> | |
58 | <col id="4">False</col> | |
59 | </row> | |
60 | <row> | |
61 | <col id="0">~language</col> | |
62 | <col id="1" translatable="yes" context="option|indicators">Languages menu</col> | |
63 | <col id="2">False</col> | |
64 | <col id="3">True</col> | |
65 | <col id="4">False</col> | |
66 | </row> | |
67 | <row> | |
68 | <col id="0">~a11y</col> | |
69 | <col id="1" translatable="yes" context="option|indicators">Accessibility menu</col> | |
70 | <col id="2">False</col> | |
71 | <col id="3">True</col> | |
72 | <col id="4">False</col> | |
73 | </row> | |
74 | <row> | |
75 | <col id="0">~power</col> | |
76 | <col id="1" translatable="yes" context="option|indicators">Power menu</col> | |
77 | <col id="2">False</col> | |
78 | <col id="3">True</col> | |
79 | <col id="4">False</col> | |
80 | </row> | |
81 | </data> | |
82 | 23 | </object> |
83 | 24 | <object class="GtkAdjustment" id="greeter_position_x_adjustment"> |
84 | 25 | <property name="upper">10000</property> |
95 | 36 | <property name="step_increment">1</property> |
96 | 37 | <property name="page_increment">10</property> |
97 | 38 | </object> |
98 | <object class="GtkListStore" id="greeter_xft-hintstyle_model"> | |
99 | <columns> | |
100 | <!-- column-name value --> | |
101 | <column type="gchararray"/> | |
102 | <!-- column-name title --> | |
103 | <column type="gchararray"/> | |
104 | </columns> | |
105 | <data> | |
106 | <row> | |
107 | <col id="0">hintnone</col> | |
108 | <col id="1" translatable="yes" context="option|hintstyle">None</col> | |
109 | </row> | |
110 | <row> | |
111 | <col id="0">hintslight</col> | |
112 | <col id="1" translatable="yes" context="option|hintstyle">Slight</col> | |
113 | </row> | |
114 | <row> | |
115 | <col id="0">hintmedium</col> | |
116 | <col id="1" translatable="yes" context="option|hintstyle">Medium</col> | |
117 | </row> | |
118 | <row> | |
119 | <col id="0">hintfull</col> | |
120 | <col id="1" translatable="yes" context="option|hintstyle">Full</col> | |
121 | </row> | |
122 | </data> | |
123 | </object> | |
124 | <object class="GtkListStore" id="greeter_xft-rgba_model"> | |
125 | <columns> | |
126 | <!-- column-name value --> | |
127 | <column type="gchararray"/> | |
128 | <!-- column-name title --> | |
129 | <column type="gchararray"/> | |
130 | </columns> | |
131 | <data> | |
132 | <row> | |
133 | <col id="0">none</col> | |
134 | <col id="1" translatable="yes" context="option|rgba">None</col> | |
135 | </row> | |
136 | <row> | |
137 | <col id="0">rgb</col> | |
138 | <col id="1" translatable="yes" context="option|rgba">RGB</col> | |
139 | </row> | |
140 | <row> | |
141 | <col id="0">bgr</col> | |
142 | <col id="1" translatable="yes" context="option|rgba">BGR</col> | |
143 | </row> | |
144 | <row> | |
145 | <col id="0">vrgb</col> | |
146 | <col id="1" translatable="yes" context="option|rgba">Vertical RGB</col> | |
147 | </row> | |
148 | <row> | |
149 | <col id="0">vbgr</col> | |
150 | <col id="1" translatable="yes" context="option|rgba">Vertical BGR</col> | |
151 | </row> | |
152 | </data> | |
153 | </object> | |
154 | <object class="GtkImage" id="icon_cancel"> | |
155 | <property name="visible">True</property> | |
156 | <property name="can_focus">False</property> | |
157 | <property name="icon_name">dialog-cancel</property> | |
158 | </object> | |
159 | 39 | <object class="GtkImage" id="icon_close"> |
160 | 40 | <property name="visible">True</property> |
161 | 41 | <property name="can_focus">False</property> |
162 | 42 | <property name="icon_name">dialog-close</property> |
163 | </object> | |
164 | <object class="GtkImage" id="icon_image"> | |
165 | <property name="visible">True</property> | |
166 | <property name="can_focus">False</property> | |
167 | <property name="icon_name">image</property> | |
168 | </object> | |
169 | <object class="GtkImage" id="icon_ok"> | |
170 | <property name="visible">True</property> | |
171 | <property name="can_focus">False</property> | |
172 | <property name="icon_name">dialog-ok</property> | |
173 | </object> | |
174 | <object class="GtkImage" id="icon_open"> | |
175 | <property name="visible">True</property> | |
176 | <property name="can_focus">False</property> | |
177 | <property name="icon_name">document-open</property> | |
178 | </object> | |
179 | <object class="GtkMenu" id="greeter_default-user-image_menu"> | |
180 | <property name="visible">True</property> | |
181 | <property name="can_focus">False</property> | |
182 | <child> | |
183 | <object class="GtkImageMenuItem" id="greeter_default-user-image_icon_item"> | |
184 | <property name="label">Icon</property> | |
185 | <property name="visible">True</property> | |
186 | <property name="can_focus">False</property> | |
187 | <property name="image">icon_image</property> | |
188 | <property name="use_stock">False</property> | |
189 | </object> | |
190 | </child> | |
191 | <child> | |
192 | <object class="GtkImageMenuItem" id="greeter_default-user-image_path_item"> | |
193 | <property name="label">Path</property> | |
194 | <property name="visible">True</property> | |
195 | <property name="can_focus">False</property> | |
196 | <property name="image">icon_open</property> | |
197 | <property name="use_stock">False</property> | |
198 | </object> | |
199 | </child> | |
200 | 43 | </object> |
201 | 44 | <object class="GtkImage" id="icon_reset"> |
202 | 45 | <property name="visible">True</property> |
247 | 90 | <property name="row_spacing">8</property> |
248 | 91 | <property name="column_spacing">12</property> |
249 | 92 | <child> |
250 | <object class="GtkLabel" id="greeter_gtk-theme_label"> | |
251 | <property name="visible">True</property> | |
252 | <property name="can_focus">False</property> | |
93 | <object class="GtkFontButton" id="greeter_font-name_value"> | |
94 | <property name="visible">True</property> | |
95 | <property name="can_focus">False</property> | |
96 | <property name="receives_default">True</property> | |
253 | 97 | <property name="halign">start</property> |
254 | <property name="hexpand">True</property> | |
255 | <property name="label" translatable="yes" context="option|gtk-theme">Theme</property> | |
256 | <attributes> | |
257 | <attribute name="weight" value="semibold"/> | |
258 | </attributes> | |
259 | </object> | |
260 | <packing> | |
261 | <property name="left_attach">0</property> | |
262 | <property name="top_attach">0</property> | |
263 | </packing> | |
264 | </child> | |
265 | <child> | |
266 | <object class="GtkLabel" id="greeter_icon-theme-name_label"> | |
267 | <property name="visible">True</property> | |
268 | <property name="can_focus">False</property> | |
269 | <property name="halign">start</property> | |
270 | <property name="hexpand">True</property> | |
271 | <property name="label" translatable="yes" context="option|icons-theme">Icons</property> | |
272 | <attributes> | |
273 | <attribute name="weight" value="semibold"/> | |
274 | </attributes> | |
275 | </object> | |
276 | <packing> | |
277 | <property name="left_attach">0</property> | |
278 | <property name="top_attach">1</property> | |
279 | </packing> | |
280 | </child> | |
281 | <child> | |
282 | <object class="GtkLabel" id="greeter_font-name_label"> | |
283 | <property name="visible">True</property> | |
284 | <property name="can_focus">False</property> | |
285 | <property name="halign">start</property> | |
286 | <property name="hexpand">True</property> | |
287 | <property name="label" translatable="yes" context="option|font">Font</property> | |
288 | <attributes> | |
289 | <attribute name="weight" value="semibold"/> | |
290 | </attributes> | |
291 | </object> | |
292 | <packing> | |
293 | <property name="left_attach">0</property> | |
294 | <property name="top_attach">2</property> | |
295 | </packing> | |
296 | </child> | |
297 | <child> | |
298 | <object class="GtkFontButton" id="greeter_font-name_value"> | |
299 | <property name="visible">True</property> | |
300 | <property name="can_focus">False</property> | |
301 | <property name="receives_default">True</property> | |
302 | 98 | <property name="font">Sans 12</property> |
303 | 99 | </object> |
304 | 100 | <packing> |
321 | 117 | <object class="GtkSwitch" id="greeter_xft-antialias_value"> |
322 | 118 | <property name="visible">True</property> |
323 | 119 | <property name="can_focus">False</property> |
324 | <property name="halign">end</property> | |
120 | <property name="halign">start</property> | |
325 | 121 | </object> |
326 | 122 | <packing> |
327 | 123 | <property name="left_attach">1</property> |
328 | 124 | <property name="top_attach">0</property> |
125 | </packing> | |
126 | </child> | |
127 | <child> | |
128 | <object class="GtkBox" id="box8"> | |
129 | <property name="visible">True</property> | |
130 | <property name="can_focus">False</property> | |
131 | <property name="halign">start</property> | |
132 | <property name="orientation">vertical</property> | |
133 | <property name="spacing">8</property> | |
134 | <child> | |
135 | <object class="GtkComboBoxText" id="greeter_xft-rgba_value"> | |
136 | <property name="visible">True</property> | |
137 | <property name="can_focus">False</property> | |
138 | <property name="active">0</property> | |
139 | <items> | |
140 | <item id="none" translatable="yes" context="option|greeter|xft-rgba">None</item> | |
141 | <item id="rgb" translatable="yes" context="option|greeter|xft-rgba">RGB</item> | |
142 | <item id="bgr" translatable="yes" context="option|greeter|xft-rgba">BGR</item> | |
143 | <item id="vrgb" translatable="yes" context="option|greeter|xft-rgba">Vertical RGB</item> | |
144 | <item id="vbgr" translatable="yes" context="option|greeter|xft-rgba">Vertical BGR</item> | |
145 | </items> | |
146 | </object> | |
147 | <packing> | |
148 | <property name="expand">False</property> | |
149 | <property name="fill">True</property> | |
150 | <property name="position">0</property> | |
151 | </packing> | |
152 | </child> | |
153 | <child> | |
154 | <object class="GtkComboBoxText" id="greeter_xft-hintstyle_value"> | |
155 | <property name="visible">True</property> | |
156 | <property name="can_focus">False</property> | |
157 | <property name="active">0</property> | |
158 | <items> | |
159 | <item id="hintnone" translatable="yes" context="option|greeter|xft-hintstyle">None</item> | |
160 | <item id="hintslight" translatable="yes" context="option|greeter|xft-hintstyle">Slight</item> | |
161 | <item id="hintmedium" translatable="yes" context="option|greeter|xft-hintstyle">Medium</item> | |
162 | <item id="hintfull" translatable="yes" context="option|greeter|xft-hintstyle">Full</item> | |
163 | </items> | |
164 | </object> | |
165 | <packing> | |
166 | <property name="expand">False</property> | |
167 | <property name="fill">True</property> | |
168 | <property name="position">1</property> | |
169 | </packing> | |
170 | </child> | |
171 | </object> | |
172 | <packing> | |
173 | <property name="left_attach">1</property> | |
174 | <property name="top_attach">2</property> | |
175 | <property name="height">2</property> | |
329 | 176 | </packing> |
330 | 177 | </child> |
331 | 178 | <child> |
352 | 199 | </packing> |
353 | 200 | </child> |
354 | 201 | <child> |
355 | <object class="GtkComboBox" id="greeter_xft-rgba_value"> | |
356 | <property name="visible">True</property> | |
357 | <property name="can_focus">False</property> | |
358 | <property name="model">greeter_xft-rgba_model</property> | |
359 | <property name="active">0</property> | |
360 | <property name="id_column">0</property> | |
202 | <object class="GtkEventBox" id="greeter_xft-antialias_label_holder"> | |
203 | <property name="visible">True</property> | |
204 | <property name="can_focus">False</property> | |
361 | 205 | <child> |
362 | <object class="GtkCellRendererText" id="cellrenderertext1"/> | |
363 | <attributes> | |
364 | <attribute name="text">1</attribute> | |
365 | </attributes> | |
206 | <object class="GtkCheckButton" id="greeter_xft-antialias_use"> | |
207 | <property name="label" translatable="yes" context="option|greeter|xft-antialias">Antialias</property> | |
208 | <property name="visible">True</property> | |
209 | <property name="can_focus">False</property> | |
210 | <property name="receives_default">False</property> | |
211 | <property name="has_tooltip">True</property> | |
212 | <property name="tooltip_text" translatable="yes">Enable this option to override system defaults</property> | |
213 | <property name="margin_left">24</property> | |
214 | <property name="hexpand">True</property> | |
215 | <property name="xalign">0.5</property> | |
216 | <property name="draw_indicator">True</property> | |
217 | </object> | |
366 | 218 | </child> |
367 | 219 | </object> |
368 | 220 | <packing> |
369 | <property name="left_attach">1</property> | |
370 | <property name="top_attach">2</property> | |
221 | <property name="left_attach">0</property> | |
222 | <property name="top_attach">0</property> | |
371 | 223 | </packing> |
372 | 224 | </child> |
373 | 225 | <child> |
374 | <object class="GtkCheckButton" id="greeter_xft-rgba_use"> | |
375 | <property name="label" translatable="yes" context="option|rgba">Subpixel rendering</property> | |
376 | <property name="visible">True</property> | |
377 | <property name="can_focus">False</property> | |
378 | <property name="receives_default">False</property> | |
379 | <property name="has_tooltip">True</property> | |
380 | <property name="tooltip_text" translatable="yes">Enable this option to override system defaults</property> | |
381 | <property name="margin_left">24</property> | |
382 | <property name="hexpand">True</property> | |
383 | <property name="xalign">0</property> | |
384 | <property name="draw_indicator">True</property> | |
226 | <object class="GtkEventBox" id="greeter_xft-dpi_label_holder"> | |
227 | <property name="visible">True</property> | |
228 | <property name="can_focus">False</property> | |
229 | <child> | |
230 | <object class="GtkCheckButton" id="greeter_xft-dpi_use"> | |
231 | <property name="label" translatable="yes" context="option|greeter|xft-dpi">DPI</property> | |
232 | <property name="visible">True</property> | |
233 | <property name="can_focus">False</property> | |
234 | <property name="receives_default">False</property> | |
235 | <property name="has_tooltip">True</property> | |
236 | <property name="tooltip_text" translatable="yes">Enable this option to override system defaults</property> | |
237 | <property name="margin_left">24</property> | |
238 | <property name="hexpand">True</property> | |
239 | <property name="xalign">0.5</property> | |
240 | <property name="draw_indicator">True</property> | |
241 | </object> | |
242 | </child> | |
243 | </object> | |
244 | <packing> | |
245 | <property name="left_attach">0</property> | |
246 | <property name="top_attach">1</property> | |
247 | </packing> | |
248 | </child> | |
249 | <child> | |
250 | <object class="GtkEventBox" id="greeter_xft-rgba_label_holder"> | |
251 | <property name="visible">True</property> | |
252 | <property name="can_focus">False</property> | |
253 | <child> | |
254 | <object class="GtkCheckButton" id="greeter_xft-rgba_use"> | |
255 | <property name="label" translatable="yes" context="option|greeter|xft-rgba">Subpixel rendering</property> | |
256 | <property name="visible">True</property> | |
257 | <property name="can_focus">False</property> | |
258 | <property name="receives_default">False</property> | |
259 | <property name="has_tooltip">True</property> | |
260 | <property name="tooltip_text" translatable="yes">Enable this option to override system defaults</property> | |
261 | <property name="margin_left">24</property> | |
262 | <property name="hexpand">True</property> | |
263 | <property name="xalign">0.5</property> | |
264 | <property name="draw_indicator">True</property> | |
265 | </object> | |
266 | </child> | |
385 | 267 | </object> |
386 | 268 | <packing> |
387 | 269 | <property name="left_attach">0</property> |
389 | 271 | </packing> |
390 | 272 | </child> |
391 | 273 | <child> |
392 | <object class="GtkCheckButton" id="greeter_xft-dpi_use"> | |
393 | <property name="label" translatable="yes" context="option|dpi">DPI</property> | |
394 | <property name="visible">True</property> | |
395 | <property name="can_focus">False</property> | |
396 | <property name="receives_default">False</property> | |
397 | <property name="has_tooltip">True</property> | |
398 | <property name="tooltip_text" translatable="yes">Enable this option to override system defaults</property> | |
399 | <property name="margin_left">24</property> | |
400 | <property name="hexpand">True</property> | |
401 | <property name="xalign">0</property> | |
402 | <property name="draw_indicator">True</property> | |
403 | </object> | |
404 | <packing> | |
405 | <property name="left_attach">0</property> | |
406 | <property name="top_attach">1</property> | |
407 | </packing> | |
408 | </child> | |
409 | <child> | |
410 | <object class="GtkCheckButton" id="greeter_xft-antialias_use"> | |
411 | <property name="label" translatable="yes" context="option|antialias">Antialias</property> | |
412 | <property name="visible">True</property> | |
413 | <property name="can_focus">False</property> | |
414 | <property name="receives_default">False</property> | |
415 | <property name="has_tooltip">True</property> | |
416 | <property name="tooltip_text" translatable="yes">Enable this option to override system defaults</property> | |
417 | <property name="margin_left">24</property> | |
418 | <property name="hexpand">True</property> | |
419 | <property name="xalign">0</property> | |
420 | <property name="draw_indicator">True</property> | |
421 | </object> | |
422 | <packing> | |
423 | <property name="left_attach">0</property> | |
424 | <property name="top_attach">0</property> | |
425 | </packing> | |
426 | </child> | |
427 | <child> | |
428 | <object class="GtkCheckButton" id="greeter_xft-hintstyle_use"> | |
429 | <property name="label" translatable="yes" context="option|hintstyle">Hinting</property> | |
430 | <property name="visible">True</property> | |
431 | <property name="can_focus">False</property> | |
432 | <property name="receives_default">False</property> | |
433 | <property name="has_tooltip">True</property> | |
434 | <property name="tooltip_text" translatable="yes">Enable this option to override system defaults</property> | |
435 | <property name="margin_left">24</property> | |
436 | <property name="hexpand">True</property> | |
437 | <property name="xalign">0</property> | |
438 | <property name="draw_indicator">True</property> | |
274 | <object class="GtkEventBox" id="greeter_xft-hintstyle_label_holder"> | |
275 | <property name="visible">True</property> | |
276 | <property name="can_focus">False</property> | |
277 | <child> | |
278 | <object class="GtkCheckButton" id="greeter_xft-hintstyle_use"> | |
279 | <property name="label" translatable="yes" context="option|greeter|xft-hintstyle">Hinting</property> | |
280 | <property name="visible">True</property> | |
281 | <property name="can_focus">False</property> | |
282 | <property name="receives_default">False</property> | |
283 | <property name="has_tooltip">True</property> | |
284 | <property name="tooltip_text" translatable="yes">Enable this option to override system defaults</property> | |
285 | <property name="margin_left">24</property> | |
286 | <property name="hexpand">True</property> | |
287 | <property name="xalign">0.5</property> | |
288 | <property name="draw_indicator">True</property> | |
289 | </object> | |
290 | </child> | |
439 | 291 | </object> |
440 | 292 | <packing> |
441 | 293 | <property name="left_attach">0</property> |
442 | 294 | <property name="top_attach">3</property> |
443 | 295 | </packing> |
444 | 296 | </child> |
445 | <child> | |
446 | <object class="GtkComboBox" id="greeter_xft-hintstyle_value"> | |
447 | <property name="visible">True</property> | |
448 | <property name="can_focus">False</property> | |
449 | <property name="model">greeter_xft-hintstyle_model</property> | |
450 | <property name="active">0</property> | |
451 | <property name="id_column">0</property> | |
452 | <child> | |
453 | <object class="GtkCellRendererText" id="cellrenderertext2"/> | |
454 | <attributes> | |
455 | <attribute name="text">1</attribute> | |
456 | </attributes> | |
457 | </child> | |
458 | </object> | |
459 | <packing> | |
460 | <property name="left_attach">1</property> | |
461 | <property name="top_attach">3</property> | |
462 | </packing> | |
463 | </child> | |
464 | 297 | </object> |
465 | 298 | </child> |
466 | 299 | <child type="label"> |
478 | 311 | </packing> |
479 | 312 | </child> |
480 | 313 | <child> |
481 | <object class="GtkRadioButton" id="greeter_background_image_choice"> | |
482 | <property name="label" translatable="yes" context="option|background">Image</property> | |
483 | <property name="visible">True</property> | |
484 | <property name="can_focus">False</property> | |
485 | <property name="receives_default">False</property> | |
314 | <object class="GtkFileChooserButton" id="greeter_background_image_value"> | |
315 | <property name="visible">True</property> | |
316 | <property name="can_focus">False</property> | |
486 | 317 | <property name="halign">start</property> |
487 | <property name="margin_left">24</property> | |
488 | <property name="hexpand">True</property> | |
489 | <property name="xalign">0</property> | |
490 | <property name="active">True</property> | |
491 | <property name="draw_indicator">True</property> | |
492 | </object> | |
493 | <packing> | |
494 | <property name="left_attach">0</property> | |
495 | <property name="top_attach">5</property> | |
496 | </packing> | |
497 | </child> | |
498 | <child> | |
499 | <object class="GtkFileChooserButton" id="greeter_background_image_value"> | |
500 | <property name="visible">True</property> | |
501 | <property name="can_focus">False</property> | |
502 | <property name="filter">greeter_default-user-image_path_dialog_filter</property> | |
318 | <property name="create_folders">False</property> | |
503 | 319 | </object> |
504 | 320 | <packing> |
505 | 321 | <property name="left_attach">1</property> |
507 | 323 | </packing> |
508 | 324 | </child> |
509 | 325 | <child> |
510 | <object class="GtkRadioButton" id="greeter_background_color_choice"> | |
511 | <property name="label" translatable="yes" context="option|background">Color</property> | |
512 | <property name="visible">True</property> | |
513 | <property name="can_focus">False</property> | |
514 | <property name="receives_default">False</property> | |
326 | <object class="GtkColorButton" id="greeter_background_color_value"> | |
327 | <property name="visible">True</property> | |
328 | <property name="can_focus">False</property> | |
329 | <property name="receives_default">True</property> | |
515 | 330 | <property name="halign">start</property> |
516 | <property name="margin_left">24</property> | |
517 | <property name="hexpand">True</property> | |
518 | <property name="xalign">0</property> | |
519 | <property name="active">True</property> | |
520 | <property name="draw_indicator">True</property> | |
521 | <property name="group">greeter_background_image_choice</property> | |
522 | </object> | |
523 | <packing> | |
524 | <property name="left_attach">0</property> | |
525 | <property name="top_attach">6</property> | |
526 | </packing> | |
527 | </child> | |
528 | <child> | |
529 | <object class="GtkColorButton" id="greeter_background_color_value"> | |
530 | <property name="visible">True</property> | |
531 | <property name="can_focus">False</property> | |
532 | <property name="receives_default">True</property> | |
533 | 331 | </object> |
534 | 332 | <packing> |
535 | 333 | <property name="left_attach">1</property> |
537 | 335 | </packing> |
538 | 336 | </child> |
539 | 337 | <child> |
540 | <object class="GtkLabel" id="greeter_default-user-image_label"> | |
541 | <property name="visible">True</property> | |
542 | <property name="can_focus">False</property> | |
543 | <property name="halign">start</property> | |
544 | <property name="valign">start</property> | |
545 | <property name="label" translatable="yes" context="option|user-image">Default user image</property> | |
546 | <attributes> | |
547 | <attribute name="weight" value="semibold"/> | |
548 | </attributes> | |
549 | </object> | |
550 | <packing> | |
551 | <property name="left_attach">0</property> | |
552 | <property name="top_attach">8</property> | |
553 | </packing> | |
554 | </child> | |
555 | <child> | |
556 | 338 | <object class="GtkComboBoxText" id="greeter_theme-name_values"> |
557 | 339 | <property name="visible">True</property> |
558 | 340 | <property name="can_focus">False</property> |
341 | <property name="hexpand">True</property> | |
559 | 342 | <property name="has_entry">True</property> |
560 | 343 | <child internal-child="entry"> |
561 | 344 | <object class="GtkEntry" id="greeter_theme-name_value"> |
585 | 368 | </packing> |
586 | 369 | </child> |
587 | 370 | <child> |
588 | <object class="GtkToggleButton" id="greeter_default-user-image_button"> | |
589 | <property name="visible">True</property> | |
590 | <property name="can_focus">False</property> | |
371 | <object class="GtkBox" id="box5"> | |
372 | <property name="visible">True</property> | |
373 | <property name="can_focus">False</property> | |
374 | <child> | |
375 | <object class="GtkEventBox" id="greeter_background_label_holder"> | |
376 | <property name="visible">True</property> | |
377 | <property name="can_focus">False</property> | |
378 | <child> | |
379 | <object class="GtkBox" id="box13"> | |
380 | <property name="visible">True</property> | |
381 | <property name="can_focus">False</property> | |
382 | <child> | |
383 | <object class="GtkLabel" id="greeter_background_label"> | |
384 | <property name="visible">True</property> | |
385 | <property name="can_focus">False</property> | |
386 | <property name="halign">start</property> | |
387 | <property name="label" translatable="yes" context="option|greeter|background">Background</property> | |
388 | <attributes> | |
389 | <attribute name="weight" value="semibold"/> | |
390 | </attributes> | |
391 | </object> | |
392 | <packing> | |
393 | <property name="expand">False</property> | |
394 | <property name="fill">True</property> | |
395 | <property name="position">0</property> | |
396 | </packing> | |
397 | </child> | |
398 | <child> | |
399 | <object class="GtkImage" id="greeter_background_error"> | |
400 | <property name="can_focus">False</property> | |
401 | <property name="yalign">0</property> | |
402 | <property name="pixel_size">12</property> | |
403 | <property name="icon_name">dialog-warning</property> | |
404 | <property name="icon_size">1</property> | |
405 | </object> | |
406 | <packing> | |
407 | <property name="expand">False</property> | |
408 | <property name="fill">True</property> | |
409 | <property name="position">1</property> | |
410 | </packing> | |
411 | </child> | |
412 | </object> | |
413 | </child> | |
414 | </object> | |
415 | <packing> | |
416 | <property name="expand">False</property> | |
417 | <property name="fill">True</property> | |
418 | <property name="position">0</property> | |
419 | </packing> | |
420 | </child> | |
421 | <child> | |
422 | <object class="GtkLabel" id="multihead_label"> | |
423 | <property name="visible">True</property> | |
424 | <property name="can_focus">True</property> | |
425 | <property name="label" translatable="yes" context="option|multihead"> <i>(or use <a href="">multihead setup</a> for individual monitors)</i></property> | |
426 | <property name="use_markup">True</property> | |
427 | </object> | |
428 | <packing> | |
429 | <property name="expand">False</property> | |
430 | <property name="fill">True</property> | |
431 | <property name="position">1</property> | |
432 | </packing> | |
433 | </child> | |
434 | </object> | |
435 | <packing> | |
436 | <property name="left_attach">0</property> | |
437 | <property name="top_attach">4</property> | |
438 | <property name="width">2</property> | |
439 | </packing> | |
440 | </child> | |
441 | <child> | |
442 | <object class="GtkSwitch" id="greeter_hide-user-image_value"> | |
443 | <property name="visible">True</property> | |
444 | <property name="can_focus">True</property> | |
445 | <property name="halign">start</property> | |
446 | </object> | |
447 | <packing> | |
448 | <property name="left_attach">1</property> | |
449 | <property name="top_attach">8</property> | |
450 | </packing> | |
451 | </child> | |
452 | <child> | |
453 | <object class="GtkMenuButton" id="greeter_default-user-image_button"> | |
454 | <property name="visible">True</property> | |
455 | <property name="can_focus">True</property> | |
591 | 456 | <property name="receives_default">True</property> |
592 | 457 | <property name="halign">start</property> |
593 | <property name="valign">start</property> | |
594 | 458 | <child> |
595 | 459 | <object class="GtkImage" id="greeter_default-user-image_image"> |
460 | <property name="width_request">64</property> | |
461 | <property name="height_request">64</property> | |
596 | 462 | <property name="visible">True</property> |
597 | 463 | <property name="can_focus">False</property> |
598 | 464 | <property name="pixel_size">64</property> |
602 | 468 | </object> |
603 | 469 | <packing> |
604 | 470 | <property name="left_attach">1</property> |
605 | <property name="top_attach">8</property> | |
606 | </packing> | |
607 | </child> | |
608 | <child> | |
609 | <object class="GtkCheckButton" id="greeter_user-background_value"> | |
610 | <property name="label" translatable="yes">Use user wallpaper if available</property> | |
611 | <property name="visible">True</property> | |
612 | <property name="can_focus">True</property> | |
471 | <property name="top_attach">9</property> | |
472 | </packing> | |
473 | </child> | |
474 | <child> | |
475 | <object class="GtkRadioButton" id="greeter_background_color_choice"> | |
476 | <property name="label" translatable="yes" context="option|greeter|background">Color</property> | |
477 | <property name="visible">True</property> | |
478 | <property name="can_focus">False</property> | |
613 | 479 | <property name="receives_default">False</property> |
480 | <property name="halign">start</property> | |
614 | 481 | <property name="margin_left">24</property> |
615 | <property name="xalign">0</property> | |
616 | <property name="image_position">right</property> | |
482 | <property name="xalign">0.5</property> | |
483 | <property name="active">True</property> | |
617 | 484 | <property name="draw_indicator">True</property> |
618 | 485 | </object> |
619 | 486 | <packing> |
620 | 487 | <property name="left_attach">0</property> |
621 | <property name="top_attach">7</property> | |
622 | <property name="width">2</property> | |
623 | </packing> | |
624 | </child> | |
625 | <child> | |
626 | <object class="GtkBox" id="box5"> | |
627 | <property name="visible">True</property> | |
628 | <property name="can_focus">False</property> | |
629 | <child> | |
630 | <object class="GtkLabel" id="greeter_background_label"> | |
488 | <property name="top_attach">6</property> | |
489 | </packing> | |
490 | </child> | |
491 | <child> | |
492 | <object class="GtkRadioButton" id="greeter_background_image_choice"> | |
493 | <property name="label" translatable="yes" context="option|greeter|background">Image</property> | |
494 | <property name="visible">True</property> | |
495 | <property name="can_focus">False</property> | |
496 | <property name="receives_default">False</property> | |
497 | <property name="halign">start</property> | |
498 | <property name="margin_left">24</property> | |
499 | <property name="xalign">0.5</property> | |
500 | <property name="active">True</property> | |
501 | <property name="draw_indicator">True</property> | |
502 | <property name="group">greeter_background_color_choice</property> | |
503 | </object> | |
504 | <packing> | |
505 | <property name="left_attach">0</property> | |
506 | <property name="top_attach">5</property> | |
507 | </packing> | |
508 | </child> | |
509 | <child> | |
510 | <object class="GtkEventBox" id="greeter_theme-name_label_holder"> | |
511 | <property name="visible">True</property> | |
512 | <property name="can_focus">False</property> | |
513 | <child> | |
514 | <object class="GtkBox" id="greeter_theme-name_label_box"> | |
515 | <property name="visible">True</property> | |
516 | <property name="can_focus">False</property> | |
517 | <child> | |
518 | <object class="GtkLabel" id="greeter_theme-name_label"> | |
519 | <property name="visible">True</property> | |
520 | <property name="can_focus">False</property> | |
521 | <property name="halign">start</property> | |
522 | <property name="label" translatable="yes" context="option|greeter|theme-name">Theme</property> | |
523 | <attributes> | |
524 | <attribute name="weight" value="semibold"/> | |
525 | </attributes> | |
526 | </object> | |
527 | <packing> | |
528 | <property name="expand">False</property> | |
529 | <property name="fill">True</property> | |
530 | <property name="position">0</property> | |
531 | </packing> | |
532 | </child> | |
533 | <child> | |
534 | <object class="GtkImage" id="greeter_theme-name_error"> | |
535 | <property name="can_focus">False</property> | |
536 | <property name="yalign">0</property> | |
537 | <property name="pixel_size">12</property> | |
538 | <property name="icon_name">dialog-warning</property> | |
539 | <property name="icon_size">1</property> | |
540 | </object> | |
541 | <packing> | |
542 | <property name="expand">False</property> | |
543 | <property name="fill">True</property> | |
544 | <property name="position">1</property> | |
545 | </packing> | |
546 | </child> | |
547 | </object> | |
548 | </child> | |
549 | </object> | |
550 | <packing> | |
551 | <property name="left_attach">0</property> | |
552 | <property name="top_attach">0</property> | |
553 | </packing> | |
554 | </child> | |
555 | <child> | |
556 | <object class="GtkEventBox" id="greeter_icon-theme-name_label_holder"> | |
557 | <property name="visible">True</property> | |
558 | <property name="can_focus">False</property> | |
559 | <child> | |
560 | <object class="GtkBox" id="greeter_icon-theme-name_label_box"> | |
561 | <property name="visible">True</property> | |
562 | <property name="can_focus">False</property> | |
563 | <child> | |
564 | <object class="GtkLabel" id="greeter_icon-theme-name_label"> | |
565 | <property name="visible">True</property> | |
566 | <property name="can_focus">False</property> | |
567 | <property name="halign">start</property> | |
568 | <property name="label" translatable="yes" context="option|greeter|icon-theme-name">Icons</property> | |
569 | <attributes> | |
570 | <attribute name="weight" value="semibold"/> | |
571 | </attributes> | |
572 | </object> | |
573 | <packing> | |
574 | <property name="expand">False</property> | |
575 | <property name="fill">True</property> | |
576 | <property name="position">0</property> | |
577 | </packing> | |
578 | </child> | |
579 | <child> | |
580 | <object class="GtkImage" id="greeter_icon-theme-name_error"> | |
581 | <property name="can_focus">False</property> | |
582 | <property name="yalign">0</property> | |
583 | <property name="pixel_size">12</property> | |
584 | <property name="icon_name">dialog-warning</property> | |
585 | <property name="icon_size">1</property> | |
586 | </object> | |
587 | <packing> | |
588 | <property name="expand">False</property> | |
589 | <property name="fill">True</property> | |
590 | <property name="position">1</property> | |
591 | </packing> | |
592 | </child> | |
593 | </object> | |
594 | </child> | |
595 | </object> | |
596 | <packing> | |
597 | <property name="left_attach">0</property> | |
598 | <property name="top_attach">1</property> | |
599 | </packing> | |
600 | </child> | |
601 | <child> | |
602 | <object class="GtkEventBox" id="greeter_font-name_label_holder"> | |
603 | <property name="visible">True</property> | |
604 | <property name="can_focus">False</property> | |
605 | <child> | |
606 | <object class="GtkLabel" id="greeter_font-name_label"> | |
631 | 607 | <property name="visible">True</property> |
632 | 608 | <property name="can_focus">False</property> |
633 | 609 | <property name="halign">start</property> |
634 | <property name="label" translatable="yes" context="option|background">Background</property> | |
610 | <property name="label" translatable="yes" context="option|greeter|font-name">Font</property> | |
635 | 611 | <attributes> |
636 | 612 | <attribute name="weight" value="semibold"/> |
637 | 613 | </attributes> |
638 | 614 | </object> |
639 | <packing> | |
640 | <property name="expand">False</property> | |
641 | <property name="fill">True</property> | |
642 | <property name="position">0</property> | |
643 | </packing> | |
644 | </child> | |
645 | <child> | |
646 | <object class="GtkLabel" id="multihead_label"> | |
615 | </child> | |
616 | </object> | |
617 | <packing> | |
618 | <property name="left_attach">0</property> | |
619 | <property name="top_attach">2</property> | |
620 | </packing> | |
621 | </child> | |
622 | <child> | |
623 | <object class="GtkEventBox" id="greeter_hide-user-image_label_holder"> | |
624 | <property name="visible">True</property> | |
625 | <property name="can_focus">False</property> | |
626 | <child> | |
627 | <object class="GtkLabel" id="greeter_hide-user-image_label"> | |
628 | <property name="visible">True</property> | |
629 | <property name="can_focus">False</property> | |
630 | <property name="halign">start</property> | |
631 | <property name="label" translatable="yes" context="option|greeter|hide-user-image">User image</property> | |
632 | <attributes> | |
633 | <attribute name="weight" value="semibold"/> | |
634 | </attributes> | |
635 | </object> | |
636 | </child> | |
637 | </object> | |
638 | <packing> | |
639 | <property name="left_attach">0</property> | |
640 | <property name="top_attach">8</property> | |
641 | </packing> | |
642 | </child> | |
643 | <child> | |
644 | <object class="GtkEventBox" id="greeter_default-user-image_label_holder"> | |
645 | <property name="visible">True</property> | |
646 | <property name="can_focus">False</property> | |
647 | <child> | |
648 | <object class="GtkBox" id="greeter_default-user-image_label_box"> | |
649 | <property name="visible">True</property> | |
650 | <property name="can_focus">False</property> | |
651 | <property name="valign">start</property> | |
652 | <child> | |
653 | <object class="GtkLabel" id="greeter_default-user-image_label"> | |
654 | <property name="visible">True</property> | |
655 | <property name="can_focus">False</property> | |
656 | <property name="halign">start</property> | |
657 | <property name="valign">start</property> | |
658 | <property name="margin_left">24</property> | |
659 | <property name="label" translatable="yes" context="option|greeter|default-user-image">Default user image</property> | |
660 | </object> | |
661 | <packing> | |
662 | <property name="expand">False</property> | |
663 | <property name="fill">True</property> | |
664 | <property name="position">0</property> | |
665 | </packing> | |
666 | </child> | |
667 | <child> | |
668 | <object class="GtkImage" id="greeter_default-user-image_error"> | |
669 | <property name="can_focus">False</property> | |
670 | <property name="yalign">0</property> | |
671 | <property name="pixel_size">12</property> | |
672 | <property name="icon_name">dialog-warning</property> | |
673 | <property name="icon_size">1</property> | |
674 | </object> | |
675 | <packing> | |
676 | <property name="expand">False</property> | |
677 | <property name="fill">True</property> | |
678 | <property name="position">1</property> | |
679 | </packing> | |
680 | </child> | |
681 | </object> | |
682 | </child> | |
683 | </object> | |
684 | <packing> | |
685 | <property name="left_attach">0</property> | |
686 | <property name="top_attach">9</property> | |
687 | </packing> | |
688 | </child> | |
689 | <child> | |
690 | <object class="GtkEventBox" id="greeter_user-background_label_holder"> | |
691 | <property name="visible">True</property> | |
692 | <property name="can_focus">False</property> | |
693 | <child> | |
694 | <object class="GtkCheckButton" id="greeter_user-background_value"> | |
695 | <property name="label" translatable="yes" context="option|greeter|user-background">Use user wallpaper if available</property> | |
647 | 696 | <property name="visible">True</property> |
648 | 697 | <property name="can_focus">True</property> |
649 | <property name="label" translatable="yes"> <i>(or you can use <a href="">multihead setup for individual monitors</a>)</i></property> | |
650 | <property name="use_markup">True</property> | |
651 | <property name="angle">0.029999999999999999</property> | |
652 | </object> | |
653 | <packing> | |
654 | <property name="expand">False</property> | |
655 | <property name="fill">True</property> | |
656 | <property name="position">1</property> | |
657 | </packing> | |
658 | </child> | |
659 | </object> | |
660 | <packing> | |
661 | <property name="left_attach">0</property> | |
662 | <property name="top_attach">4</property> | |
698 | <property name="receives_default">False</property> | |
699 | <property name="margin_left">24</property> | |
700 | <property name="xalign">0.5</property> | |
701 | <property name="image_position">right</property> | |
702 | <property name="draw_indicator">True</property> | |
703 | </object> | |
704 | </child> | |
705 | </object> | |
706 | <packing> | |
707 | <property name="left_attach">0</property> | |
708 | <property name="top_attach">7</property> | |
663 | 709 | <property name="width">2</property> |
664 | 710 | </packing> |
665 | 711 | </child> |
672 | 718 | <object class="GtkLabel" id="label1"> |
673 | 719 | <property name="visible">True</property> |
674 | 720 | <property name="can_focus">False</property> |
675 | <property name="label" translatable="yes">Appearance</property> | |
721 | <property name="label" translatable="yes" context="tabs">Appearance</property> | |
676 | 722 | </object> |
677 | 723 | <packing> |
724 | <property name="tab_expand">True</property> | |
678 | 725 | <property name="tab_fill">False</property> |
679 | 726 | </packing> |
680 | 727 | </child> |
691 | 738 | <property name="row_spacing">8</property> |
692 | 739 | <property name="column_spacing">12</property> |
693 | 740 | <child> |
694 | <object class="GtkLabel" id="greeter_indicators_label"> | |
695 | <property name="visible">True</property> | |
696 | <property name="can_focus">False</property> | |
697 | <property name="halign">start</property> | |
698 | <property name="hexpand">True</property> | |
699 | <property name="label" translatable="yes" context="option|indicators">Redefine indicators</property> | |
700 | <attributes> | |
701 | <attribute name="weight" value="semibold"/> | |
702 | </attributes> | |
703 | </object> | |
704 | <packing> | |
705 | <property name="left_attach">0</property> | |
706 | <property name="top_attach">4</property> | |
707 | </packing> | |
708 | </child> | |
709 | <child> | |
710 | 741 | <object class="GtkSwitch" id="greeter_indicators_use"> |
711 | 742 | <property name="visible">True</property> |
712 | 743 | <property name="can_focus">False</property> |
741 | 772 | <property name="halign">start</property> |
742 | 773 | <property name="margin_left">24</property> |
743 | 774 | <property name="hexpand">True</property> |
744 | <property name="label" translatable="yes" context="option|clock-format">%H %I - hours, %M - minutes, %S - seconds | |
775 | <property name="label" translatable="yes" context="option|greeter|clock-format">%H %I - hours, %M - minutes, %S - seconds | |
745 | 776 | %d - day, %m - month, %y %Y - year |
746 | 777 | %a %A - day of the week, %b %B - month name</property> |
747 | 778 | <attributes> |
763 | 794 | <property name="orientation">vertical</property> |
764 | 795 | <child> |
765 | 796 | <object class="GtkScrolledWindow" id="scrolledwindow1"> |
766 | <property name="height_request">160</property> | |
797 | <property name="height_request">170</property> | |
767 | 798 | <property name="visible">True</property> |
768 | 799 | <property name="can_focus">True</property> |
769 | 800 | <property name="hexpand">True</property> |
779 | 810 | <property name="headers_visible">False</property> |
780 | 811 | <property name="headers_clickable">False</property> |
781 | 812 | <property name="reorderable">True</property> |
782 | <property name="search_column">0</property> | |
813 | <property name="search_column">3</property> | |
783 | 814 | <property name="tooltip_column">1</property> |
784 | 815 | <child internal-child="selection"> |
785 | 816 | <object class="GtkTreeSelection" id="greeter_indicators_selection"> |
788 | 819 | </child> |
789 | 820 | <child> |
790 | 821 | <object class="GtkTreeViewColumn" id="greeter_indicators_state_column"> |
822 | <property name="visible">False</property> | |
791 | 823 | <property name="sizing">autosize</property> |
792 | 824 | <property name="title">column</property> |
793 | 825 | <property name="clickable">True</property> |
794 | 826 | <child> |
795 | 827 | <object class="GtkCellRendererToggle" id="greeter_indicators_state_renderer"/> |
796 | 828 | <attributes> |
797 | <attribute name="visible">3</attribute> | |
798 | <attribute name="active">4</attribute> | |
829 | <attribute name="visible">2</attribute> | |
830 | <attribute name="active">3</attribute> | |
799 | 831 | </attributes> |
800 | 832 | </child> |
801 | 833 | </object> |
806 | 838 | <property name="title">column</property> |
807 | 839 | <property name="expand">True</property> |
808 | 840 | <child> |
841 | <object class="GtkCellRendererPixbuf" id="greeter_indicators_image_renderer"/> | |
842 | <attributes> | |
843 | <attribute name="icon-name">5</attribute> | |
844 | </attributes> | |
845 | </child> | |
846 | <child> | |
809 | 847 | <object class="GtkCellRendererText" id="greeter_indicators_name_renderer"/> |
810 | 848 | <attributes> |
811 | <attribute name="editable">3</attribute> | |
812 | <attribute name="text">0</attribute> | |
849 | <attribute name="markup">6</attribute> | |
813 | 850 | </attributes> |
814 | 851 | </child> |
815 | 852 | </object> |
832 | 869 | <object class="GtkToolButton" id="greeter_indicators_add"> |
833 | 870 | <property name="visible">True</property> |
834 | 871 | <property name="can_focus">False</property> |
835 | <property name="tooltip_text" translatable="yes" context="option|indicators">Add indicator to list</property> | |
836 | <property name="label" translatable="yes" context="option|indicators">Add</property> | |
872 | <property name="tooltip_text" translatable="yes" context="option|greeter|indicators">Add indicator to list</property> | |
873 | <property name="label" translatable="yes" context="option|greeter|indicators">Add</property> | |
837 | 874 | <property name="use_underline">True</property> |
838 | 875 | <property name="icon_name">list-add-symbolic</property> |
839 | 876 | </object> |
846 | 883 | <object class="GtkToolButton" id="greeter_indicators_remove"> |
847 | 884 | <property name="visible">True</property> |
848 | 885 | <property name="can_focus">False</property> |
849 | <property name="tooltip_text" translatable="yes" context="option|indicators">Remove indicator from list</property> | |
850 | <property name="label" translatable="yes" context="option|indicators">Remove</property> | |
886 | <property name="tooltip_text" translatable="yes" context="option|greeter|indicators">Remove indicator from list</property> | |
887 | <property name="label" translatable="yes" context="option|greeter|indicators">Remove</property> | |
851 | 888 | <property name="use_underline">True</property> |
852 | 889 | <property name="icon_name">list-remove-symbolic</property> |
853 | 890 | </object> |
860 | 897 | <object class="GtkToolButton" id="greeter_indicators_up"> |
861 | 898 | <property name="visible">True</property> |
862 | 899 | <property name="can_focus">False</property> |
863 | <property name="tooltip_text" translatable="yes" context="option|indicators">Move up</property> | |
864 | <property name="label" translatable="yes" context="option|indicators">Up</property> | |
900 | <property name="tooltip_text" translatable="yes" context="option|greeter|indicators">Move up</property> | |
901 | <property name="label" translatable="yes" context="option|greeter|indicators">Up</property> | |
865 | 902 | <property name="use_underline">True</property> |
866 | 903 | <property name="icon_name">go-up-symbolic</property> |
867 | 904 | </object> |
874 | 911 | <object class="GtkToolButton" id="greeter_indicators_down"> |
875 | 912 | <property name="visible">True</property> |
876 | 913 | <property name="can_focus">False</property> |
877 | <property name="tooltip_text" translatable="yes" context="option|indicators">Move down</property> | |
878 | <property name="label" translatable="yes" context="option|indicators">Down</property> | |
914 | <property name="tooltip_text" translatable="yes" context="option|greeter|indicators">Move down</property> | |
915 | <property name="label" translatable="yes" context="option|greeter|indicators">Down</property> | |
879 | 916 | <property name="use_underline">True</property> |
880 | 917 | <property name="icon_name">go-down-symbolic</property> |
881 | 918 | </object> |
884 | 921 | <property name="homogeneous">True</property> |
885 | 922 | </packing> |
886 | 923 | </child> |
924 | <child> | |
925 | <object class="GtkToolButton" id="greeter_indicators_tools"> | |
926 | <property name="visible">True</property> | |
927 | <property name="can_focus">False</property> | |
928 | <property name="label" translatable="yes" context="option|greeter|indicators">Templates</property> | |
929 | <property name="use_underline">True</property> | |
930 | <property name="icon_name">preferences-other</property> | |
931 | </object> | |
932 | <packing> | |
933 | <property name="expand">False</property> | |
934 | <property name="homogeneous">False</property> | |
935 | </packing> | |
936 | </child> | |
887 | 937 | <style> |
888 | 938 | <class name="inline-toolbar"/> |
889 | 939 | </style> |
908 | 958 | <property name="margin_left">24</property> |
909 | 959 | <property name="spacing">6</property> |
910 | 960 | <child> |
911 | <object class="GtkLabel" id="greeter_clock-format_label"> | |
912 | <property name="visible">True</property> | |
913 | <property name="can_focus">False</property> | |
914 | <property name="label" translatable="yes" context="option|clock-format">Clock format:</property> | |
961 | <object class="GtkEventBox" id="greeter_clock-format_label_holder"> | |
962 | <property name="visible">True</property> | |
963 | <property name="can_focus">False</property> | |
964 | <child> | |
965 | <object class="GtkLabel" id="greeter_clock-format_label"> | |
966 | <property name="visible">True</property> | |
967 | <property name="can_focus">False</property> | |
968 | <property name="label" translatable="yes" context="option|greeter|clock-format">Clock format:</property> | |
969 | </object> | |
970 | </child> | |
915 | 971 | </object> |
916 | 972 | <packing> |
917 | 973 | <property name="expand">False</property> |
936 | 992 | <property name="left_attach">0</property> |
937 | 993 | <property name="top_attach">1</property> |
938 | 994 | <property name="width">2</property> |
995 | </packing> | |
996 | </child> | |
997 | <child> | |
998 | <object class="GtkEventBox" id="greeter_indicators_label_holder"> | |
999 | <property name="visible">True</property> | |
1000 | <property name="can_focus">False</property> | |
1001 | <child> | |
1002 | <object class="GtkLabel" id="greeter_indicators_label"> | |
1003 | <property name="visible">True</property> | |
1004 | <property name="can_focus">False</property> | |
1005 | <property name="halign">start</property> | |
1006 | <property name="hexpand">True</property> | |
1007 | <property name="label" translatable="yes" context="option|greeter|indicators">Redefine indicators</property> | |
1008 | <attributes> | |
1009 | <attribute name="weight" value="semibold"/> | |
1010 | </attributes> | |
1011 | </object> | |
1012 | </child> | |
1013 | </object> | |
1014 | <packing> | |
1015 | <property name="left_attach">0</property> | |
1016 | <property name="top_attach">4</property> | |
939 | 1017 | </packing> |
940 | 1018 | </child> |
941 | 1019 | <child> |
954 | 1032 | <object class="GtkLabel" id="label2"> |
955 | 1033 | <property name="visible">True</property> |
956 | 1034 | <property name="can_focus">False</property> |
957 | <property name="label" translatable="yes">Panel</property> | |
1035 | <property name="label" translatable="yes" context="tabs">Panel</property> | |
958 | 1036 | </object> |
959 | 1037 | <packing> |
960 | 1038 | <property name="position">1</property> |
1039 | <property name="tab_expand">True</property> | |
961 | 1040 | <property name="tab_fill">False</property> |
962 | 1041 | </packing> |
963 | 1042 | </child> |
974 | 1053 | <property name="row_spacing">8</property> |
975 | 1054 | <property name="column_spacing">8</property> |
976 | 1055 | <child> |
977 | <object class="GtkLabel" id="label6"> | |
1056 | <object class="GtkAspectFrame" id="greeter_position_screen_frame"> | |
1057 | <property name="visible">True</property> | |
1058 | <property name="can_focus">False</property> | |
1059 | <property name="hexpand">True</property> | |
1060 | <property name="vexpand">True</property> | |
1061 | <property name="label_xalign">0</property> | |
1062 | <property name="shadow_type">in</property> | |
1063 | <property name="obey_child">False</property> | |
1064 | <child> | |
1065 | <object class="GtkOverlay" id="greeter_position_screen_overlay"> | |
1066 | <property name="visible">True</property> | |
1067 | <property name="can_focus">False</property> | |
1068 | <property name="hexpand">True</property> | |
1069 | <property name="vexpand">True</property> | |
1070 | <child> | |
1071 | <object class="GtkBox" id="box3"> | |
1072 | <property name="visible">True</property> | |
1073 | <property name="can_focus">False</property> | |
1074 | <property name="hexpand">True</property> | |
1075 | <property name="vexpand">True</property> | |
1076 | <property name="orientation">vertical</property> | |
1077 | <child> | |
1078 | <placeholder/> | |
1079 | </child> | |
1080 | </object> | |
1081 | </child> | |
1082 | <child type="overlay"> | |
1083 | <object class="GtkEventBox" id="greeter_position_window_box"> | |
1084 | <property name="visible">True</property> | |
1085 | <property name="can_focus">False</property> | |
1086 | <property name="events">GDK_BUTTON1_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_STRUCTURE_MASK</property> | |
1087 | <property name="halign">start</property> | |
1088 | <property name="valign">start</property> | |
1089 | <child> | |
1090 | <object class="GtkFrame" id="greeter_position_window_frame"> | |
1091 | <property name="width_request">100</property> | |
1092 | <property name="height_request">80</property> | |
1093 | <property name="visible">True</property> | |
1094 | <property name="can_focus">False</property> | |
1095 | <property name="border_width">2</property> | |
1096 | <property name="label_xalign">0</property> | |
1097 | <property name="shadow_type">in</property> | |
1098 | <child> | |
1099 | <object class="GtkGrid" id="greeter_position_window_grid"> | |
1100 | <property name="visible">True</property> | |
1101 | <property name="can_focus">False</property> | |
1102 | <property name="column_spacing">30</property> | |
1103 | <property name="row_homogeneous">True</property> | |
1104 | <property name="column_homogeneous">True</property> | |
1105 | <child> | |
1106 | <placeholder/> | |
1107 | </child> | |
1108 | <child> | |
1109 | <placeholder/> | |
1110 | </child> | |
1111 | <child> | |
1112 | <placeholder/> | |
1113 | </child> | |
1114 | <child> | |
1115 | <placeholder/> | |
1116 | </child> | |
1117 | <child> | |
1118 | <placeholder/> | |
1119 | </child> | |
1120 | <child> | |
1121 | <placeholder/> | |
1122 | </child> | |
1123 | <child> | |
1124 | <placeholder/> | |
1125 | </child> | |
1126 | <child> | |
1127 | <placeholder/> | |
1128 | </child> | |
1129 | <child> | |
1130 | <placeholder/> | |
1131 | </child> | |
1132 | </object> | |
1133 | </child> | |
1134 | <child type="label_item"> | |
1135 | <placeholder/> | |
1136 | </child> | |
1137 | </object> | |
1138 | </child> | |
1139 | </object> | |
1140 | </child> | |
1141 | </object> | |
1142 | </child> | |
1143 | </object> | |
1144 | <packing> | |
1145 | <property name="left_attach">0</property> | |
1146 | <property name="top_attach">1</property> | |
1147 | <property name="width">3</property> | |
1148 | </packing> | |
1149 | </child> | |
1150 | <child> | |
1151 | <object class="GtkSeparator" id="separator1"> | |
1152 | <property name="visible">True</property> | |
1153 | <property name="can_focus">False</property> | |
1154 | <property name="orientation">vertical</property> | |
1155 | </object> | |
1156 | <packing> | |
1157 | <property name="left_attach">1</property> | |
1158 | <property name="top_attach">2</property> | |
1159 | <property name="height">3</property> | |
1160 | </packing> | |
1161 | </child> | |
1162 | <child> | |
1163 | <object class="GtkLabel" id="label9"> | |
978 | 1164 | <property name="visible">True</property> |
979 | 1165 | <property name="can_focus">False</property> |
980 | 1166 | <property name="halign">start</property> |
981 | <property name="valign">center</property> | |
982 | <property name="hexpand">True</property> | |
983 | <property name="label" translatable="yes" context="option|position">Horizontal </property> | |
984 | <attributes> | |
985 | <attribute name="weight" value="semibold"/> | |
986 | </attributes> | |
987 | </object> | |
988 | <packing> | |
989 | <property name="left_attach">0</property> | |
990 | <property name="top_attach">3</property> | |
991 | </packing> | |
992 | </child> | |
993 | <child> | |
994 | <object class="GtkBox" id="box8"> | |
1167 | <property name="label" translatable="yes" context="option|greeter|position">Horizontal</property> | |
1168 | </object> | |
1169 | <packing> | |
1170 | <property name="left_attach">0</property> | |
1171 | <property name="top_attach">2</property> | |
1172 | </packing> | |
1173 | </child> | |
1174 | <child> | |
1175 | <object class="GtkLabel" id="label10"> | |
1176 | <property name="visible">True</property> | |
1177 | <property name="can_focus">False</property> | |
1178 | <property name="halign">start</property> | |
1179 | <property name="label" translatable="yes" context="option|greeter|position">Vertical</property> | |
1180 | </object> | |
1181 | <packing> | |
1182 | <property name="left_attach">2</property> | |
1183 | <property name="top_attach">2</property> | |
1184 | </packing> | |
1185 | </child> | |
1186 | <child> | |
1187 | <object class="GtkBox" id="box6"> | |
995 | 1188 | <property name="visible">True</property> |
996 | 1189 | <property name="can_focus">False</property> |
997 | 1190 | <property name="spacing">8</property> |
998 | 1191 | <child> |
999 | <object class="GtkSpinButton" id="greeter_position_x_value"> | |
1192 | <object class="GtkSpinButton" id="greeter_position_x_entry"> | |
1000 | 1193 | <property name="visible">True</property> |
1001 | 1194 | <property name="can_focus">True</property> |
1002 | 1195 | <property name="halign">start</property> |
1003 | <property name="margin_left">24</property> | |
1004 | 1196 | <property name="invisible_char">●</property> |
1005 | 1197 | <property name="width_chars">6</property> |
1198 | <property name="text" translatable="yes">0</property> | |
1006 | 1199 | <property name="xalign">1</property> |
1007 | 1200 | <property name="adjustment">greeter_position_x_adjustment</property> |
1008 | 1201 | <property name="snap_to_ticks">True</property> |
1016 | 1209 | </child> |
1017 | 1210 | <child> |
1018 | 1211 | <object class="GtkCheckButton" id="greeter_position_x_percents"> |
1019 | <property name="label" translatable="yes" context="option|position">in %</property> | |
1212 | <property name="label" translatable="yes" context="option|greeter|position">in %</property> | |
1020 | 1213 | <property name="visible">True</property> |
1021 | 1214 | <property name="can_focus">True</property> |
1022 | 1215 | <property name="receives_default">False</property> |
1032 | 1225 | </object> |
1033 | 1226 | <packing> |
1034 | 1227 | <property name="left_attach">0</property> |
1035 | <property name="top_attach">4</property> | |
1036 | </packing> | |
1037 | </child> | |
1038 | <child> | |
1039 | <object class="GtkBox" id="box9"> | |
1228 | <property name="top_attach">3</property> | |
1229 | </packing> | |
1230 | </child> | |
1231 | <child> | |
1232 | <object class="GtkBox" id="box7"> | |
1040 | 1233 | <property name="visible">True</property> |
1041 | 1234 | <property name="can_focus">False</property> |
1042 | 1235 | <property name="spacing">8</property> |
1043 | 1236 | <child> |
1044 | <object class="GtkSpinButton" id="greeter_position_y_value"> | |
1237 | <object class="GtkSpinButton" id="greeter_position_y_entry"> | |
1045 | 1238 | <property name="visible">True</property> |
1046 | 1239 | <property name="can_focus">True</property> |
1047 | 1240 | <property name="halign">start</property> |
1048 | <property name="margin_left">24</property> | |
1049 | 1241 | <property name="invisible_char">●</property> |
1050 | 1242 | <property name="width_chars">6</property> |
1243 | <property name="text" translatable="yes">0</property> | |
1051 | 1244 | <property name="xalign">1</property> |
1052 | 1245 | <property name="adjustment">greeter_position_y_adjustment</property> |
1053 | 1246 | <property name="snap_to_ticks">True</property> |
1061 | 1254 | </child> |
1062 | 1255 | <child> |
1063 | 1256 | <object class="GtkCheckButton" id="greeter_position_y_percents"> |
1064 | <property name="label" translatable="yes" context="option|position">in %</property> | |
1257 | <property name="label" translatable="yes" context="option|greeter|position">in %</property> | |
1065 | 1258 | <property name="visible">True</property> |
1066 | 1259 | <property name="can_focus">True</property> |
1067 | 1260 | <property name="receives_default">False</property> |
1077 | 1270 | </object> |
1078 | 1271 | <packing> |
1079 | 1272 | <property name="left_attach">2</property> |
1273 | <property name="top_attach">3</property> | |
1274 | </packing> | |
1275 | </child> | |
1276 | <child> | |
1277 | <object class="GtkCheckButton" id="greeter_position_x_mirror"> | |
1278 | <property name="label" translatable="yes" context="option|greeter|position">from right</property> | |
1279 | <property name="visible">True</property> | |
1280 | <property name="can_focus">True</property> | |
1281 | <property name="receives_default">False</property> | |
1282 | <property name="xalign">0</property> | |
1283 | <property name="draw_indicator">True</property> | |
1284 | </object> | |
1285 | <packing> | |
1286 | <property name="left_attach">0</property> | |
1080 | 1287 | <property name="top_attach">4</property> |
1081 | 1288 | </packing> |
1082 | 1289 | </child> |
1083 | 1290 | <child> |
1084 | <object class="GtkLabel" id="label11"> | |
1085 | <property name="visible">True</property> | |
1086 | <property name="can_focus">False</property> | |
1087 | <property name="halign">start</property> | |
1088 | <property name="valign">center</property> | |
1089 | <property name="hexpand">True</property> | |
1090 | <property name="label" translatable="yes" context="option|position">Vertical</property> | |
1091 | <attributes> | |
1092 | <attribute name="weight" value="semibold"/> | |
1093 | </attributes> | |
1291 | <object class="GtkCheckButton" id="greeter_position_y_mirror"> | |
1292 | <property name="label" translatable="yes" context="option|greeter|position">from bottom</property> | |
1293 | <property name="visible">True</property> | |
1294 | <property name="can_focus">True</property> | |
1295 | <property name="receives_default">False</property> | |
1296 | <property name="xalign">0</property> | |
1297 | <property name="draw_indicator">True</property> | |
1094 | 1298 | </object> |
1095 | 1299 | <packing> |
1096 | 1300 | <property name="left_attach">2</property> |
1097 | <property name="top_attach">3</property> | |
1098 | </packing> | |
1099 | </child> | |
1100 | <child> | |
1101 | <object class="GtkSeparator" id="separator2"> | |
1102 | <property name="visible">True</property> | |
1103 | <property name="can_focus">False</property> | |
1104 | <property name="orientation">vertical</property> | |
1105 | </object> | |
1106 | <packing> | |
1107 | <property name="left_attach">1</property> | |
1108 | <property name="top_attach">3</property> | |
1109 | <property name="height">3</property> | |
1110 | </packing> | |
1111 | </child> | |
1112 | <child> | |
1113 | <object class="GtkLabel" id="greeter_position_label"> | |
1114 | <property name="visible">True</property> | |
1115 | <property name="can_focus">False</property> | |
1116 | <property name="halign">start</property> | |
1117 | <property name="label" translatable="yes" context="option|position">Select base point and its position</property> | |
1118 | <attributes> | |
1119 | <attribute name="style" value="oblique"/> | |
1120 | </attributes> | |
1301 | <property name="top_attach">4</property> | |
1302 | </packing> | |
1303 | </child> | |
1304 | <child> | |
1305 | <object class="GtkEventBox" id="greeter_position_label_holder"> | |
1306 | <property name="visible">True</property> | |
1307 | <property name="can_focus">False</property> | |
1308 | <child> | |
1309 | <object class="GtkLabel" id="greeter_position_label"> | |
1310 | <property name="visible">True</property> | |
1311 | <property name="can_focus">False</property> | |
1312 | <property name="halign">start</property> | |
1313 | <property name="label" translatable="yes" context="option|greeter|position">Select base point and its position.</property> | |
1314 | <attributes> | |
1315 | <attribute name="style" value="oblique"/> | |
1316 | </attributes> | |
1317 | </object> | |
1318 | </child> | |
1121 | 1319 | </object> |
1122 | 1320 | <packing> |
1123 | 1321 | <property name="left_attach">0</property> |
1124 | 1322 | <property name="top_attach">0</property> |
1125 | 1323 | <property name="width">3</property> |
1126 | </packing> | |
1127 | </child> | |
1128 | <child> | |
1129 | <object class="GtkCheckButton" id="greeter_position_x_mirror"> | |
1130 | <property name="label" translatable="yes" context="option|position">from right</property> | |
1131 | <property name="visible">True</property> | |
1132 | <property name="can_focus">True</property> | |
1133 | <property name="receives_default">False</property> | |
1134 | <property name="margin_left">24</property> | |
1135 | <property name="xalign">0</property> | |
1136 | <property name="draw_indicator">True</property> | |
1137 | </object> | |
1138 | <packing> | |
1139 | <property name="left_attach">0</property> | |
1140 | <property name="top_attach">5</property> | |
1141 | </packing> | |
1142 | </child> | |
1143 | <child> | |
1144 | <object class="GtkCheckButton" id="greeter_position_y_mirror"> | |
1145 | <property name="label" translatable="yes" context="option|position">from bottom</property> | |
1146 | <property name="visible">True</property> | |
1147 | <property name="can_focus">True</property> | |
1148 | <property name="receives_default">False</property> | |
1149 | <property name="margin_left">24</property> | |
1150 | <property name="xalign">0</property> | |
1151 | <property name="draw_indicator">True</property> | |
1152 | </object> | |
1153 | <packing> | |
1154 | <property name="left_attach">2</property> | |
1155 | <property name="top_attach">5</property> | |
1156 | </packing> | |
1157 | </child> | |
1158 | <child> | |
1159 | <object class="GtkFixed" id="greeter_position_screen"> | |
1160 | <property name="visible">True</property> | |
1161 | <property name="app_paintable">True</property> | |
1162 | <property name="can_focus">False</property> | |
1163 | <property name="hexpand">True</property> | |
1164 | <property name="vexpand">True</property> | |
1165 | <property name="resize_mode">immediate</property> | |
1166 | <child> | |
1167 | <object class="GtkFrame" id="greeter_position_window"> | |
1168 | <property name="width_request">100</property> | |
1169 | <property name="height_request">80</property> | |
1170 | <property name="visible">True</property> | |
1171 | <property name="can_focus">False</property> | |
1172 | <property name="halign">start</property> | |
1173 | <property name="valign">start</property> | |
1174 | <property name="border_width">2</property> | |
1175 | <property name="resize_mode">immediate</property> | |
1176 | <property name="label_xalign">0</property> | |
1177 | <property name="shadow_type">in</property> | |
1178 | <child> | |
1179 | <object class="GtkGrid" id="greeter_position_window_grid"> | |
1180 | <property name="visible">True</property> | |
1181 | <property name="can_focus">False</property> | |
1182 | <property name="hexpand">True</property> | |
1183 | <property name="vexpand">True</property> | |
1184 | <property name="column_spacing">30</property> | |
1185 | <property name="row_homogeneous">True</property> | |
1186 | <property name="column_homogeneous">True</property> | |
1187 | <child> | |
1188 | <object class="GtkRadioButton" id="greeter_position_base_start_start"> | |
1189 | <property name="visible">True</property> | |
1190 | <property name="can_focus">True</property> | |
1191 | <property name="receives_default">False</property> | |
1192 | <property name="halign">start</property> | |
1193 | <property name="valign">start</property> | |
1194 | <property name="xalign">0</property> | |
1195 | <property name="active">True</property> | |
1196 | <property name="draw_indicator">True</property> | |
1197 | </object> | |
1198 | <packing> | |
1199 | <property name="left_attach">0</property> | |
1200 | <property name="top_attach">0</property> | |
1201 | </packing> | |
1202 | </child> | |
1203 | <child> | |
1204 | <object class="GtkRadioButton" id="greeter_position_base_center_start"> | |
1205 | <property name="visible">True</property> | |
1206 | <property name="can_focus">True</property> | |
1207 | <property name="receives_default">False</property> | |
1208 | <property name="halign">center</property> | |
1209 | <property name="valign">start</property> | |
1210 | <property name="xalign">0</property> | |
1211 | <property name="draw_indicator">True</property> | |
1212 | <property name="group">greeter_position_base_start_start</property> | |
1213 | </object> | |
1214 | <packing> | |
1215 | <property name="left_attach">1</property> | |
1216 | <property name="top_attach">0</property> | |
1217 | </packing> | |
1218 | </child> | |
1219 | <child> | |
1220 | <object class="GtkRadioButton" id="greeter_position_base_end_start"> | |
1221 | <property name="visible">True</property> | |
1222 | <property name="can_focus">True</property> | |
1223 | <property name="receives_default">False</property> | |
1224 | <property name="halign">end</property> | |
1225 | <property name="valign">start</property> | |
1226 | <property name="xalign">0</property> | |
1227 | <property name="draw_indicator">True</property> | |
1228 | <property name="group">greeter_position_base_start_start</property> | |
1229 | </object> | |
1230 | <packing> | |
1231 | <property name="left_attach">2</property> | |
1232 | <property name="top_attach">0</property> | |
1233 | </packing> | |
1234 | </child> | |
1235 | <child> | |
1236 | <object class="GtkRadioButton" id="greeter_position_base_start_center"> | |
1237 | <property name="visible">True</property> | |
1238 | <property name="can_focus">True</property> | |
1239 | <property name="receives_default">False</property> | |
1240 | <property name="halign">start</property> | |
1241 | <property name="valign">center</property> | |
1242 | <property name="xalign">0</property> | |
1243 | <property name="draw_indicator">True</property> | |
1244 | <property name="group">greeter_position_base_start_start</property> | |
1245 | </object> | |
1246 | <packing> | |
1247 | <property name="left_attach">0</property> | |
1248 | <property name="top_attach">1</property> | |
1249 | </packing> | |
1250 | </child> | |
1251 | <child> | |
1252 | <object class="GtkRadioButton" id="greeter_position_base_center_center"> | |
1253 | <property name="visible">True</property> | |
1254 | <property name="can_focus">True</property> | |
1255 | <property name="receives_default">False</property> | |
1256 | <property name="halign">center</property> | |
1257 | <property name="valign">center</property> | |
1258 | <property name="xalign">0</property> | |
1259 | <property name="draw_indicator">True</property> | |
1260 | <property name="group">greeter_position_base_start_start</property> | |
1261 | </object> | |
1262 | <packing> | |
1263 | <property name="left_attach">1</property> | |
1264 | <property name="top_attach">1</property> | |
1265 | </packing> | |
1266 | </child> | |
1267 | <child> | |
1268 | <object class="GtkRadioButton" id="greeter_position_base_end_center"> | |
1269 | <property name="visible">True</property> | |
1270 | <property name="can_focus">True</property> | |
1271 | <property name="receives_default">False</property> | |
1272 | <property name="halign">end</property> | |
1273 | <property name="valign">center</property> | |
1274 | <property name="xalign">0</property> | |
1275 | <property name="draw_indicator">True</property> | |
1276 | <property name="group">greeter_position_base_start_start</property> | |
1277 | </object> | |
1278 | <packing> | |
1279 | <property name="left_attach">2</property> | |
1280 | <property name="top_attach">1</property> | |
1281 | </packing> | |
1282 | </child> | |
1283 | <child> | |
1284 | <object class="GtkRadioButton" id="greeter_position_base_start_end"> | |
1285 | <property name="visible">True</property> | |
1286 | <property name="can_focus">True</property> | |
1287 | <property name="receives_default">False</property> | |
1288 | <property name="halign">start</property> | |
1289 | <property name="valign">end</property> | |
1290 | <property name="xalign">0</property> | |
1291 | <property name="draw_indicator">True</property> | |
1292 | <property name="group">greeter_position_base_start_start</property> | |
1293 | </object> | |
1294 | <packing> | |
1295 | <property name="left_attach">0</property> | |
1296 | <property name="top_attach">2</property> | |
1297 | </packing> | |
1298 | </child> | |
1299 | <child> | |
1300 | <object class="GtkRadioButton" id="greeter_position_base_center_end"> | |
1301 | <property name="visible">True</property> | |
1302 | <property name="can_focus">True</property> | |
1303 | <property name="receives_default">False</property> | |
1304 | <property name="halign">center</property> | |
1305 | <property name="valign">end</property> | |
1306 | <property name="xalign">0</property> | |
1307 | <property name="draw_indicator">True</property> | |
1308 | <property name="group">greeter_position_base_start_start</property> | |
1309 | </object> | |
1310 | <packing> | |
1311 | <property name="left_attach">1</property> | |
1312 | <property name="top_attach">2</property> | |
1313 | </packing> | |
1314 | </child> | |
1315 | <child> | |
1316 | <object class="GtkRadioButton" id="greeter_position_base_end_end"> | |
1317 | <property name="visible">True</property> | |
1318 | <property name="can_focus">True</property> | |
1319 | <property name="receives_default">False</property> | |
1320 | <property name="halign">end</property> | |
1321 | <property name="valign">end</property> | |
1322 | <property name="xalign">0</property> | |
1323 | <property name="draw_indicator">True</property> | |
1324 | <property name="group">greeter_position_base_start_start</property> | |
1325 | </object> | |
1326 | <packing> | |
1327 | <property name="left_attach">2</property> | |
1328 | <property name="top_attach">2</property> | |
1329 | </packing> | |
1330 | </child> | |
1331 | </object> | |
1332 | </child> | |
1333 | <child type="label_item"> | |
1334 | <placeholder/> | |
1335 | </child> | |
1336 | </object> | |
1337 | </child> | |
1338 | </object> | |
1339 | <packing> | |
1340 | <property name="left_attach">0</property> | |
1341 | <property name="top_attach">1</property> | |
1342 | <property name="width">3</property> | |
1343 | <property name="height">2</property> | |
1344 | 1324 | </packing> |
1345 | 1325 | </child> |
1346 | 1326 | </object> |
1350 | 1330 | </packing> |
1351 | 1331 | </child> |
1352 | 1332 | <child type="tab"> |
1353 | <object class="GtkLabel" id="label3"> | |
1333 | <object class="GtkLabel" id="label5"> | |
1354 | 1334 | <property name="visible">True</property> |
1355 | 1335 | <property name="can_focus">False</property> |
1356 | <property name="label" translatable="yes">Window position</property> | |
1336 | <property name="label" translatable="yes" context="tabs">Window position</property> | |
1357 | 1337 | </object> |
1358 | 1338 | <packing> |
1359 | 1339 | <property name="position">2</property> |
1340 | <property name="tab_expand">True</property> | |
1360 | 1341 | <property name="tab_fill">False</property> |
1361 | 1342 | </packing> |
1362 | 1343 | </child> |
1373 | 1354 | <property name="row_spacing">8</property> |
1374 | 1355 | <property name="column_spacing">8</property> |
1375 | 1356 | <child> |
1376 | <object class="GtkLabel" id="greeter_screensaver-timeout_label"> | |
1377 | <property name="visible">True</property> | |
1378 | <property name="can_focus">False</property> | |
1379 | <property name="halign">start</property> | |
1380 | <property name="hexpand">True</property> | |
1381 | <property name="label" translatable="yes" context="option|timeout">Timeout until the screen blanks </property> | |
1382 | <attributes> | |
1383 | <attribute name="weight" value="semibold"/> | |
1384 | </attributes> | |
1385 | </object> | |
1386 | <packing> | |
1387 | <property name="left_attach">0</property> | |
1388 | <property name="top_attach">2</property> | |
1389 | <property name="width">2</property> | |
1390 | </packing> | |
1391 | </child> | |
1392 | <child> | |
1393 | <object class="GtkLabel" id="greeter_keyboard_label"> | |
1394 | <property name="visible">True</property> | |
1395 | <property name="can_focus">False</property> | |
1396 | <property name="halign">start</property> | |
1397 | <property name="hexpand">True</property> | |
1398 | <property name="label" translatable="yes" context="option|keyboard">Onscreen keyboard</property> | |
1399 | <attributes> | |
1400 | <attribute name="weight" value="semibold"/> | |
1401 | </attributes> | |
1402 | </object> | |
1403 | <packing> | |
1404 | <property name="left_attach">0</property> | |
1405 | <property name="top_attach">0</property> | |
1406 | </packing> | |
1407 | </child> | |
1408 | <child> | |
1409 | <object class="GtkComboBoxText" id="greeter_keyboard_values"> | |
1410 | <property name="visible">True</property> | |
1411 | <property name="can_focus">False</property> | |
1412 | <property name="margin_left">24</property> | |
1413 | <property name="has_entry">True</property> | |
1414 | <items> | |
1415 | <item>onboard</item> | |
1416 | </items> | |
1417 | <child internal-child="entry"> | |
1418 | <object class="GtkEntry" id="greeter_keyboard_value"> | |
1419 | <property name="can_focus">True</property> | |
1420 | </object> | |
1421 | </child> | |
1422 | </object> | |
1423 | <packing> | |
1424 | <property name="left_attach">0</property> | |
1425 | <property name="top_attach">1</property> | |
1426 | <property name="width">2</property> | |
1427 | </packing> | |
1428 | </child> | |
1429 | <child> | |
1430 | <object class="GtkSwitch" id="greeter_keyboard_use"> | |
1431 | <property name="visible">True</property> | |
1432 | <property name="can_focus">False</property> | |
1433 | <property name="halign">end</property> | |
1434 | </object> | |
1435 | <packing> | |
1436 | <property name="left_attach">1</property> | |
1437 | <property name="top_attach">0</property> | |
1438 | </packing> | |
1439 | </child> | |
1440 | <child> | |
1441 | 1357 | <object class="GtkBox" id="greeter_screensaver-timeout_box"> |
1442 | 1358 | <property name="visible">True</property> |
1443 | 1359 | <property name="can_focus">False</property> |
1448 | 1364 | <property name="visible">True</property> |
1449 | 1365 | <property name="can_focus">False</property> |
1450 | 1366 | <property name="valign">start</property> |
1451 | <property name="label" translatable="yes" context="option|timeout">Never</property> | |
1367 | <property name="label" translatable="yes" context="option|greeter|screensaver-timeout">Never</property> | |
1452 | 1368 | </object> |
1453 | 1369 | <packing> |
1454 | 1370 | <property name="expand">False</property> |
1489 | 1405 | <packing> |
1490 | 1406 | <property name="left_attach">0</property> |
1491 | 1407 | <property name="top_attach">3</property> |
1408 | <property name="width">2</property> | |
1409 | </packing> | |
1410 | </child> | |
1411 | <child> | |
1412 | <object class="GtkLabel" id="label4"> | |
1413 | <property name="visible">True</property> | |
1414 | <property name="can_focus">False</property> | |
1415 | <property name="halign">start</property> | |
1416 | <property name="label" translatable="yes">Accessibility</property> | |
1417 | <attributes> | |
1418 | <attribute name="weight" value="semibold"/> | |
1419 | </attributes> | |
1420 | </object> | |
1421 | <packing> | |
1422 | <property name="left_attach">0</property> | |
1423 | <property name="top_attach">0</property> | |
1424 | <property name="width">2</property> | |
1425 | </packing> | |
1426 | </child> | |
1427 | <child> | |
1428 | <object class="GtkGrid" id="grid1"> | |
1429 | <property name="visible">True</property> | |
1430 | <property name="can_focus">False</property> | |
1431 | <property name="margin_left">24</property> | |
1432 | <property name="row_spacing">8</property> | |
1433 | <property name="column_spacing">8</property> | |
1434 | <child> | |
1435 | <object class="GtkComboBoxText" id="greeter_reader_combo"> | |
1436 | <property name="visible">True</property> | |
1437 | <property name="can_focus">False</property> | |
1438 | <property name="hexpand">True</property> | |
1439 | <property name="has_entry">True</property> | |
1440 | <items> | |
1441 | <item id="select-path" translatable="yes" context="option|greeter|reader">Select path to reader...</item> | |
1442 | <item id="separator">-</item> | |
1443 | <item id="value">orca</item> | |
1444 | </items> | |
1445 | <child internal-child="entry"> | |
1446 | <object class="GtkEntry" id="greeter_reader_entry"> | |
1447 | <property name="can_focus">True</property> | |
1448 | <property name="placeholder_text" translatable="yes" context="option|greeter|reader">Command to launch screen reader</property> | |
1449 | </object> | |
1450 | </child> | |
1451 | </object> | |
1452 | <packing> | |
1453 | <property name="left_attach">1</property> | |
1454 | <property name="top_attach">2</property> | |
1455 | </packing> | |
1456 | </child> | |
1457 | <child> | |
1458 | <object class="GtkComboBoxText" id="greeter_keyboard_combo"> | |
1459 | <property name="visible">True</property> | |
1460 | <property name="can_focus">False</property> | |
1461 | <property name="hexpand">True</property> | |
1462 | <property name="has_entry">True</property> | |
1463 | <items> | |
1464 | <item id="select-path" translatable="yes" context="option|greeter|keyboard">Select path to keyboard...</item> | |
1465 | <item id="separator">-</item> | |
1466 | <item id="value">onboard</item> | |
1467 | </items> | |
1468 | <child internal-child="entry"> | |
1469 | <object class="GtkEntry" id="greeter_keyboard_entry"> | |
1470 | <property name="can_focus">True</property> | |
1471 | <property name="placeholder_text" translatable="yes" context="option|greeter|keyboard">Command to launch on-screen keyboard</property> | |
1472 | </object> | |
1473 | </child> | |
1474 | </object> | |
1475 | <packing> | |
1476 | <property name="left_attach">1</property> | |
1477 | <property name="top_attach">0</property> | |
1478 | </packing> | |
1479 | </child> | |
1480 | <child> | |
1481 | <object class="GtkComboBoxText" id="greeter_a11y-states_keyboard"> | |
1482 | <property name="visible">True</property> | |
1483 | <property name="can_focus">False</property> | |
1484 | <property name="halign">start</property> | |
1485 | <items> | |
1486 | <item id="-" translatable="yes" context="option|greeter|a11y-states">Disabled at start</item> | |
1487 | <item id="+" translatable="yes" context="option|greeter|a11y-states">Enabled at start</item> | |
1488 | <item id="~" translatable="yes" context="option|greeter|a11y-states">Save state between launches</item> | |
1489 | </items> | |
1490 | </object> | |
1491 | <packing> | |
1492 | <property name="left_attach">1</property> | |
1493 | <property name="top_attach">1</property> | |
1494 | </packing> | |
1495 | </child> | |
1496 | <child> | |
1497 | <object class="GtkComboBoxText" id="greeter_a11y-states_reader"> | |
1498 | <property name="visible">True</property> | |
1499 | <property name="can_focus">False</property> | |
1500 | <property name="halign">start</property> | |
1501 | <items> | |
1502 | <item id="-" translatable="yes" context="option|greeter|a11y-states">Disabled at start</item> | |
1503 | <item id="+" translatable="yes" context="option|greeter|a11y-states">Enabled at start</item> | |
1504 | <item id="~" translatable="yes" context="option|greeter|a11y-states">Save state between launches</item> | |
1505 | </items> | |
1506 | </object> | |
1507 | <packing> | |
1508 | <property name="left_attach">1</property> | |
1509 | <property name="top_attach">3</property> | |
1510 | </packing> | |
1511 | </child> | |
1512 | <child> | |
1513 | <object class="GtkComboBoxText" id="greeter_a11y-states_contrast"> | |
1514 | <property name="visible">True</property> | |
1515 | <property name="can_focus">False</property> | |
1516 | <property name="halign">start</property> | |
1517 | <items> | |
1518 | <item id="-" translatable="yes" context="option|greeter|a11y-states">Disabled at start</item> | |
1519 | <item id="+" translatable="yes" context="option|greeter|a11y-states">Enabled at start</item> | |
1520 | <item id="~" translatable="yes" context="option|greeter|a11y-states">Save state between launches</item> | |
1521 | </items> | |
1522 | </object> | |
1523 | <packing> | |
1524 | <property name="left_attach">1</property> | |
1525 | <property name="top_attach">4</property> | |
1526 | </packing> | |
1527 | </child> | |
1528 | <child> | |
1529 | <object class="GtkComboBoxText" id="greeter_a11y-states_font"> | |
1530 | <property name="visible">True</property> | |
1531 | <property name="can_focus">False</property> | |
1532 | <property name="halign">start</property> | |
1533 | <items> | |
1534 | <item id="-" translatable="yes" context="option|greeter|a11y-states">Disabled at start</item> | |
1535 | <item id="+" translatable="yes" context="option|greeter|a11y-states">Enabled at start</item> | |
1536 | <item id="~" translatable="yes" context="option|greeter|a11y-states">Save state between launches</item> | |
1537 | </items> | |
1538 | </object> | |
1539 | <packing> | |
1540 | <property name="left_attach">1</property> | |
1541 | <property name="top_attach">5</property> | |
1542 | </packing> | |
1543 | </child> | |
1544 | <child> | |
1545 | <object class="GtkEventBox" id="greeter_a11y-theme_label_holder"> | |
1546 | <property name="visible">True</property> | |
1547 | <property name="can_focus">False</property> | |
1548 | <child> | |
1549 | <object class="GtkLabel" id="greeter_a11y-theme_label"> | |
1550 | <property name="visible">True</property> | |
1551 | <property name="can_focus">False</property> | |
1552 | <property name="halign">start</property> | |
1553 | <property name="label" translatable="yes" context="option|greeter|a11y-theme">Contrast theme</property> | |
1554 | </object> | |
1555 | </child> | |
1556 | </object> | |
1557 | <packing> | |
1558 | <property name="left_attach">0</property> | |
1559 | <property name="top_attach">4</property> | |
1560 | </packing> | |
1561 | </child> | |
1562 | <child> | |
1563 | <object class="GtkEventBox" id="greeter_a11y-font_label_holder"> | |
1564 | <property name="visible">True</property> | |
1565 | <property name="can_focus">False</property> | |
1566 | <child> | |
1567 | <object class="GtkLabel" id="greeter_a11y-font_label"> | |
1568 | <property name="visible">True</property> | |
1569 | <property name="can_focus">False</property> | |
1570 | <property name="halign">start</property> | |
1571 | <property name="label" translatable="yes" context="option|greeter|a11y-font">Large font</property> | |
1572 | </object> | |
1573 | </child> | |
1574 | </object> | |
1575 | <packing> | |
1576 | <property name="left_attach">0</property> | |
1577 | <property name="top_attach">5</property> | |
1578 | </packing> | |
1579 | </child> | |
1580 | <child> | |
1581 | <object class="GtkEventBox" id="greeter_reader_label_holder"> | |
1582 | <property name="visible">True</property> | |
1583 | <property name="can_focus">False</property> | |
1584 | <child> | |
1585 | <object class="GtkCheckButton" id="greeter_reader_use"> | |
1586 | <property name="visible">True</property> | |
1587 | <property name="can_focus">True</property> | |
1588 | <property name="receives_default">False</property> | |
1589 | <property name="xalign">0</property> | |
1590 | <property name="draw_indicator">True</property> | |
1591 | <child> | |
1592 | <object class="GtkBox" id="box15"> | |
1593 | <property name="visible">True</property> | |
1594 | <property name="can_focus">False</property> | |
1595 | <child> | |
1596 | <object class="GtkLabel" id="greeter_reader_label"> | |
1597 | <property name="visible">True</property> | |
1598 | <property name="can_focus">False</property> | |
1599 | <property name="label" translatable="yes" context="greeter|option|reader">Reader</property> | |
1600 | </object> | |
1601 | <packing> | |
1602 | <property name="expand">False</property> | |
1603 | <property name="fill">True</property> | |
1604 | <property name="position">0</property> | |
1605 | </packing> | |
1606 | </child> | |
1607 | <child> | |
1608 | <object class="GtkImage" id="greeter_reader_error"> | |
1609 | <property name="can_focus">False</property> | |
1610 | <property name="yalign">0</property> | |
1611 | <property name="pixel_size">12</property> | |
1612 | <property name="icon_name">dialog-warning</property> | |
1613 | <property name="icon_size">1</property> | |
1614 | </object> | |
1615 | <packing> | |
1616 | <property name="expand">False</property> | |
1617 | <property name="fill">True</property> | |
1618 | <property name="position">1</property> | |
1619 | </packing> | |
1620 | </child> | |
1621 | </object> | |
1622 | </child> | |
1623 | </object> | |
1624 | </child> | |
1625 | </object> | |
1626 | <packing> | |
1627 | <property name="left_attach">0</property> | |
1628 | <property name="top_attach">2</property> | |
1629 | </packing> | |
1630 | </child> | |
1631 | <child> | |
1632 | <object class="GtkEventBox" id="greeter_keyboard_label_holder"> | |
1633 | <property name="visible">True</property> | |
1634 | <property name="can_focus">False</property> | |
1635 | <child> | |
1636 | <object class="GtkCheckButton" id="greeter_keyboard_use"> | |
1637 | <property name="visible">True</property> | |
1638 | <property name="can_focus">True</property> | |
1639 | <property name="receives_default">False</property> | |
1640 | <property name="xalign">0</property> | |
1641 | <property name="draw_indicator">True</property> | |
1642 | <child> | |
1643 | <object class="GtkBox" id="box14"> | |
1644 | <property name="visible">True</property> | |
1645 | <property name="can_focus">False</property> | |
1646 | <child> | |
1647 | <object class="GtkLabel" id="greeter_keyboard_label"> | |
1648 | <property name="visible">True</property> | |
1649 | <property name="can_focus">False</property> | |
1650 | <property name="label" translatable="yes" context="greeter|option|keyboard">Keyboard</property> | |
1651 | </object> | |
1652 | <packing> | |
1653 | <property name="expand">False</property> | |
1654 | <property name="fill">True</property> | |
1655 | <property name="position">0</property> | |
1656 | </packing> | |
1657 | </child> | |
1658 | <child> | |
1659 | <object class="GtkImage" id="greeter_keyboard_error"> | |
1660 | <property name="can_focus">False</property> | |
1661 | <property name="yalign">0</property> | |
1662 | <property name="pixel_size">12</property> | |
1663 | <property name="icon_name">dialog-warning</property> | |
1664 | <property name="icon_size">1</property> | |
1665 | </object> | |
1666 | <packing> | |
1667 | <property name="expand">False</property> | |
1668 | <property name="fill">True</property> | |
1669 | <property name="position">1</property> | |
1670 | </packing> | |
1671 | </child> | |
1672 | </object> | |
1673 | </child> | |
1674 | </object> | |
1675 | </child> | |
1676 | </object> | |
1677 | <packing> | |
1678 | <property name="left_attach">0</property> | |
1679 | <property name="top_attach">0</property> | |
1680 | </packing> | |
1681 | </child> | |
1682 | <child> | |
1683 | <placeholder/> | |
1684 | </child> | |
1685 | <child> | |
1686 | <placeholder/> | |
1687 | </child> | |
1688 | </object> | |
1689 | <packing> | |
1690 | <property name="left_attach">0</property> | |
1691 | <property name="top_attach">1</property> | |
1692 | <property name="width">2</property> | |
1693 | </packing> | |
1694 | </child> | |
1695 | <child> | |
1696 | <object class="GtkEventBox" id="greeter_screensaver-timeout_label_holder"> | |
1697 | <property name="visible">True</property> | |
1698 | <property name="can_focus">False</property> | |
1699 | <child> | |
1700 | <object class="GtkLabel" id="greeter_screensaver-timeout_label"> | |
1701 | <property name="visible">True</property> | |
1702 | <property name="can_focus">False</property> | |
1703 | <property name="halign">start</property> | |
1704 | <property name="hexpand">True</property> | |
1705 | <property name="label" translatable="yes" context="option|greeter|screensaver-timeout">Timeout until the screen blanks </property> | |
1706 | <attributes> | |
1707 | <attribute name="weight" value="semibold"/> | |
1708 | </attributes> | |
1709 | </object> | |
1710 | </child> | |
1711 | </object> | |
1712 | <packing> | |
1713 | <property name="left_attach">0</property> | |
1714 | <property name="top_attach">2</property> | |
1715 | <property name="width">2</property> | |
1716 | </packing> | |
1717 | </child> | |
1718 | <child> | |
1719 | <object class="GtkEventBox" id="greeter_allow-debugging_label_holder"> | |
1720 | <property name="visible">True</property> | |
1721 | <property name="can_focus">False</property> | |
1722 | <child> | |
1723 | <object class="GtkBox" id="box12"> | |
1724 | <property name="visible">True</property> | |
1725 | <property name="can_focus">False</property> | |
1726 | <child> | |
1727 | <object class="GtkCheckButton" id="greeter_allow-debugging_value"> | |
1728 | <property name="label" translatable="yes" context="greeter|option|allow-debugging">Debugging mode</property> | |
1729 | <property name="visible">True</property> | |
1730 | <property name="can_focus">True</property> | |
1731 | <property name="receives_default">False</property> | |
1732 | <property name="tooltip_text" translatable="yes" context="greeter|option|allow-debugging">Enable keys to launch GtkInspector | |
1733 | More informative log</property> | |
1734 | <property name="xalign">0</property> | |
1735 | <property name="draw_indicator">True</property> | |
1736 | </object> | |
1737 | <packing> | |
1738 | <property name="expand">False</property> | |
1739 | <property name="fill">True</property> | |
1740 | <property name="position">0</property> | |
1741 | </packing> | |
1742 | </child> | |
1743 | <child> | |
1744 | <object class="GtkImage" id="greeter_allow-debugging_error"> | |
1745 | <property name="can_focus">False</property> | |
1746 | <property name="yalign">0</property> | |
1747 | <property name="pixel_size">12</property> | |
1748 | <property name="icon_name">dialog-warning</property> | |
1749 | <property name="icon_size">1</property> | |
1750 | </object> | |
1751 | <packing> | |
1752 | <property name="expand">False</property> | |
1753 | <property name="fill">True</property> | |
1754 | <property name="position">1</property> | |
1755 | </packing> | |
1756 | </child> | |
1757 | </object> | |
1758 | </child> | |
1759 | </object> | |
1760 | <packing> | |
1761 | <property name="left_attach">0</property> | |
1762 | <property name="top_attach">4</property> | |
1492 | 1763 | <property name="width">2</property> |
1493 | 1764 | </packing> |
1494 | 1765 | </child> |
1499 | 1770 | </packing> |
1500 | 1771 | </child> |
1501 | 1772 | <child type="tab"> |
1502 | <object class="GtkLabel" id="label4"> | |
1773 | <object class="GtkLabel" id="label3"> | |
1503 | 1774 | <property name="visible">True</property> |
1504 | 1775 | <property name="can_focus">False</property> |
1505 | <property name="label" translatable="yes">Misc.</property> | |
1776 | <property name="label" translatable="yes" context="tabs">Misc.</property> | |
1506 | 1777 | </object> |
1507 | 1778 | <packing> |
1508 | 1779 | <property name="position">3</property> |
1780 | <property name="tab_expand">True</property> | |
1509 | 1781 | <property name="tab_fill">False</property> |
1510 | 1782 | </packing> |
1511 | 1783 | </child> |
1517 | 1789 | </packing> |
1518 | 1790 | </child> |
1519 | 1791 | <child> |
1520 | <object class="GtkInfoBar" id="no_access_infobar"> | |
1792 | <object class="GtkInfoBar" id="infobar"> | |
1521 | 1793 | <property name="visible">True</property> |
1522 | 1794 | <property name="app_paintable">True</property> |
1523 | 1795 | <property name="can_focus">False</property> |
1635 | 1907 | </object> |
1636 | 1908 | </child> |
1637 | 1909 | </object> |
1638 | <object class="GtkFileChooserDialog" id="greeter_default-user-image_path_dialog"> | |
1639 | <property name="can_focus">False</property> | |
1640 | <property name="border_width">5</property> | |
1641 | <property name="title" translatable="yes">Select image</property> | |
1642 | <property name="role">GtkFileChooserDialog</property> | |
1643 | <property name="window_position">center</property> | |
1644 | <property name="default_width">600</property> | |
1645 | <property name="default_height">450</property> | |
1646 | <property name="type_hint">dialog</property> | |
1647 | <property name="transient_for">settings_window</property> | |
1648 | <property name="create_folders">False</property> | |
1649 | <property name="filter">greeter_default-user-image_path_dialog_filter</property> | |
1650 | <property name="preview_widget">greeter_default-user-image_path_dialog_preview</property> | |
1651 | <child internal-child="vbox"> | |
1652 | <object class="GtkBox" id="filechooserdialog-vbox1"> | |
1653 | <property name="can_focus">False</property> | |
1654 | <property name="orientation">vertical</property> | |
1655 | <property name="spacing">2</property> | |
1656 | <child internal-child="action_area"> | |
1657 | <object class="GtkButtonBox" id="filechooserdialog-action_area1"> | |
1658 | <property name="can_focus">False</property> | |
1659 | <property name="layout_style">end</property> | |
1660 | <child> | |
1661 | <object class="GtkButton" id="button2"> | |
1662 | <property name="label" context="button">_Cancel</property> | |
1663 | <property name="visible">True</property> | |
1664 | <property name="can_focus">False</property> | |
1665 | <property name="receives_default">True</property> | |
1666 | <property name="image">icon_cancel</property> | |
1667 | <property name="use_underline">True</property> | |
1668 | </object> | |
1669 | <packing> | |
1670 | <property name="expand">False</property> | |
1671 | <property name="fill">True</property> | |
1672 | <property name="position">0</property> | |
1673 | </packing> | |
1674 | </child> | |
1675 | <child> | |
1676 | <object class="GtkButton" id="button1"> | |
1677 | <property name="label" context="button">_OK</property> | |
1678 | <property name="visible">True</property> | |
1679 | <property name="can_focus">False</property> | |
1680 | <property name="can_default">True</property> | |
1681 | <property name="has_default">True</property> | |
1682 | <property name="receives_default">True</property> | |
1683 | <property name="image">icon_ok</property> | |
1684 | <property name="use_underline">True</property> | |
1685 | </object> | |
1686 | <packing> | |
1687 | <property name="expand">False</property> | |
1688 | <property name="fill">True</property> | |
1689 | <property name="position">1</property> | |
1690 | </packing> | |
1691 | </child> | |
1692 | </object> | |
1693 | <packing> | |
1694 | <property name="expand">False</property> | |
1695 | <property name="fill">True</property> | |
1696 | <property name="pack_type">end</property> | |
1697 | <property name="position">0</property> | |
1698 | </packing> | |
1699 | </child> | |
1700 | </object> | |
1701 | </child> | |
1702 | <action-widgets> | |
1703 | <action-widget response="-6">button2</action-widget> | |
1704 | <action-widget response="-5">button1</action-widget> | |
1705 | </action-widgets> | |
1706 | </object> | |
1707 | 1910 | </interface> |
0 | 0 | <?xml version="1.0" encoding="UTF-8"?> |
1 | <!-- Generated with glade 3.18.3 --> | |
1 | 2 | <interface> |
2 | <!-- interface-requires gtk+ 3.0 --> | |
3 | <!-- interface-requires gtk_greeter_settings 1.0 --> | |
3 | <requires lib="gtk+" version="3.8"/> | |
4 | <requires lib="gtk_greeter_settings" version="1.0"/> | |
4 | 5 | <object class="GtkListStore" id="contexts_model"> |
5 | 6 | <columns> |
6 | 7 | <!-- column-name value --> |
27 | 28 | <object class="GtkTreeModelFilter" id="icons_filter"> |
28 | 29 | <property name="child_model">icons_model</property> |
29 | 30 | </object> |
31 | <object class="GtkTreeModelSort" id="icons_sorted"> | |
32 | <property name="model">icons_filter</property> | |
33 | </object> | |
34 | <object class="GtkEntryCompletion" id="name_completion"> | |
35 | <property name="model">icons_model</property> | |
36 | <property name="text_column">0</property> | |
37 | <property name="inline_completion">True</property> | |
38 | <property name="popup_completion">False</property> | |
39 | </object> | |
30 | 40 | <object class="GtkImage" id="image2"> |
31 | 41 | <property name="visible">True</property> |
32 | 42 | <property name="can_focus">False</property> |
38 | 48 | <property name="can_focus">False</property> |
39 | 49 | <property name="xpad">2</property> |
40 | 50 | <property name="icon_name">dialog-ok</property> |
41 | </object> | |
42 | <object class="GtkTreeModelSort" id="icons_sorted"> | |
43 | <property name="model">icons_filter</property> | |
44 | 51 | </object> |
45 | 52 | <object class="IconChooserDialog" id="icon_chooser_dialog"> |
46 | 53 | <property name="width_request">400</property> |
147 | 154 | </packing> |
148 | 155 | </child> |
149 | 156 | <child> |
150 | <object class="GtkEntry" id="name"> | |
157 | <object class="GtkEntry" id="name_entry"> | |
151 | 158 | <property name="visible">True</property> |
152 | 159 | <property name="can_focus">True</property> |
153 | 160 | <property name="invisible_char">●</property> |
154 | <property name="invisible_char_set">True</property> | |
155 | 161 | <property name="completion">name_completion</property> |
156 | 162 | <signal name="changed" handler="on_name_changed" swapped="no"/> |
157 | 163 | </object> |
166 | 172 | <property name="left_attach">0</property> |
167 | 173 | <property name="top_attach">0</property> |
168 | 174 | <property name="width">2</property> |
169 | <property name="height">1</property> | |
170 | 175 | </packing> |
171 | 176 | </child> |
172 | 177 | <child> |
180 | 185 | <packing> |
181 | 186 | <property name="left_attach">0</property> |
182 | 187 | <property name="top_attach">1</property> |
183 | <property name="width">1</property> | |
184 | <property name="height">1</property> | |
185 | 188 | </packing> |
186 | 189 | </child> |
187 | 190 | <child> |
195 | 198 | <packing> |
196 | 199 | <property name="left_attach">1</property> |
197 | 200 | <property name="top_attach">1</property> |
198 | <property name="width">1</property> | |
199 | <property name="height">1</property> | |
200 | </packing> | |
201 | </child> | |
202 | <child> | |
203 | <object class="GtkImage" id="preview"> | |
204 | <property name="visible">True</property> | |
205 | <property name="can_focus">False</property> | |
206 | <property name="halign">center</property> | |
207 | <property name="valign">start</property> | |
208 | <property name="stock">gtk-missing-image</property> | |
209 | <property name="pixel_size">32</property> | |
210 | <property name="icon-size">6</property> | |
211 | </object> | |
212 | <packing> | |
213 | <property name="left_attach">2</property> | |
214 | <property name="top_attach">0</property> | |
215 | <property name="width">1</property> | |
216 | <property name="height">2</property> | |
217 | 201 | </packing> |
218 | 202 | </child> |
219 | 203 | <child> |
232 | 216 | <property name="left_attach">0</property> |
233 | 217 | <property name="top_attach">3</property> |
234 | 218 | <property name="width">3</property> |
235 | <property name="height">1</property> | |
236 | 219 | </packing> |
237 | 220 | </child> |
238 | 221 | <child> |
288 | 271 | <property name="left_attach">1</property> |
289 | 272 | <property name="top_attach">2</property> |
290 | 273 | <property name="width">2</property> |
291 | <property name="height">1</property> | |
292 | 274 | </packing> |
293 | 275 | </child> |
294 | 276 | <child> |
327 | 309 | <packing> |
328 | 310 | <property name="left_attach">0</property> |
329 | 311 | <property name="top_attach">2</property> |
330 | <property name="width">1</property> | |
331 | <property name="height">1</property> | |
312 | </packing> | |
313 | </child> | |
314 | <child> | |
315 | <object class="GtkImage" id="preview_image"> | |
316 | <property name="width_request">32</property> | |
317 | <property name="height_request">32</property> | |
318 | <property name="visible">True</property> | |
319 | <property name="can_focus">False</property> | |
320 | <property name="halign">center</property> | |
321 | <property name="valign">start</property> | |
322 | <property name="pixel_size">32</property> | |
323 | <property name="icon_size">6</property> | |
324 | </object> | |
325 | <packing> | |
326 | <property name="left_attach">2</property> | |
327 | <property name="top_attach">0</property> | |
328 | <property name="height">2</property> | |
332 | 329 | </packing> |
333 | 330 | </child> |
334 | 331 | </object> |
345 | 342 | <action-widget response="-5">ok_button</action-widget> |
346 | 343 | </action-widgets> |
347 | 344 | </object> |
348 | <object class="GtkEntryCompletion" id="name_completion"> | |
349 | <property name="model">icons_model</property> | |
350 | <property name="text_column">0</property> | |
351 | <property name="inline_completion">True</property> | |
352 | <property name="popup_completion">False</property> | |
353 | </object> | |
354 | 345 | </interface> |
0 | <?xml version="1.0" encoding="UTF-8"?> | |
1 | <!-- Generated with glade 3.18.3 --> | |
2 | <interface> | |
3 | <requires lib="gtk+" version="3.8"/> | |
4 | <object class="GtkImage" id="cancel_image"> | |
5 | <property name="visible">True</property> | |
6 | <property name="can_focus">False</property> | |
7 | <property name="icon_name">dialog-cancel</property> | |
8 | </object> | |
9 | <object class="GtkFileFilter" id="filefilter1"> | |
10 | <mime-types> | |
11 | <mime-type>image/*</mime-type> | |
12 | </mime-types> | |
13 | </object> | |
14 | <object class="GtkImage" id="ok_image"> | |
15 | <property name="visible">True</property> | |
16 | <property name="can_focus">False</property> | |
17 | <property name="icon_name">dialog-ok</property> | |
18 | </object> | |
19 | <object class="GtkImage" id="preview_image"> | |
20 | <property name="visible">True</property> | |
21 | <property name="can_focus">False</property> | |
22 | <property name="valign">start</property> | |
23 | <property name="margin_right">8</property> | |
24 | <property name="icon_name">unknown</property> | |
25 | </object> | |
26 | <object class="GtkFileChooserDialog" id="dialog"> | |
27 | <property name="can_focus">False</property> | |
28 | <property name="type_hint">dialog</property> | |
29 | <property name="filter">filefilter1</property> | |
30 | <property name="preview_widget">preview_image</property> | |
31 | <child internal-child="vbox"> | |
32 | <object class="GtkBox" id="filechooserdialog-vbox1"> | |
33 | <property name="can_focus">False</property> | |
34 | <property name="orientation">vertical</property> | |
35 | <property name="spacing">2</property> | |
36 | <child internal-child="action_area"> | |
37 | <object class="GtkButtonBox" id="filechooserdialog-action_area1"> | |
38 | <property name="can_focus">False</property> | |
39 | <property name="layout_style">end</property> | |
40 | <child> | |
41 | <object class="GtkButton" id="cancel_button"> | |
42 | <property name="label" translatable="yes">_Cancel</property> | |
43 | <property name="visible">True</property> | |
44 | <property name="can_focus">True</property> | |
45 | <property name="receives_default">True</property> | |
46 | <property name="image">cancel_image</property> | |
47 | <property name="use_underline">True</property> | |
48 | </object> | |
49 | <packing> | |
50 | <property name="expand">True</property> | |
51 | <property name="fill">True</property> | |
52 | <property name="position">0</property> | |
53 | </packing> | |
54 | </child> | |
55 | <child> | |
56 | <object class="GtkButton" id="ok_button"> | |
57 | <property name="label" translatable="yes">_OK</property> | |
58 | <property name="visible">True</property> | |
59 | <property name="can_focus">True</property> | |
60 | <property name="can_default">True</property> | |
61 | <property name="receives_default">True</property> | |
62 | <property name="image">ok_image</property> | |
63 | <property name="use_underline">True</property> | |
64 | </object> | |
65 | <packing> | |
66 | <property name="expand">True</property> | |
67 | <property name="fill">True</property> | |
68 | <property name="position">1</property> | |
69 | </packing> | |
70 | </child> | |
71 | </object> | |
72 | <packing> | |
73 | <property name="expand">False</property> | |
74 | <property name="fill">False</property> | |
75 | <property name="position">0</property> | |
76 | </packing> | |
77 | </child> | |
78 | <child> | |
79 | <placeholder/> | |
80 | </child> | |
81 | </object> | |
82 | </child> | |
83 | <action-widgets> | |
84 | <action-widget response="-6">cancel_button</action-widget> | |
85 | <action-widget response="-5">ok_button</action-widget> | |
86 | </action-widgets> | |
87 | </object> | |
88 | </interface> |
0 | <?xml version="1.0" encoding="UTF-8"?> | |
1 | <interface> | |
2 | <!-- interface-requires gtk+ 3.0 --> | |
3 | <!-- interface-requires gtk_greeter_settings 1.0 --> | |
4 | <object class="GtkImage" id="image1"> | |
5 | <property name="visible">True</property> | |
6 | <property name="can_focus">False</property> | |
7 | <property name="xpad">2</property> | |
8 | <property name="icon_name">list-add</property> | |
9 | </object> | |
10 | <object class="GtkImage" id="image2"> | |
11 | <property name="visible">True</property> | |
12 | <property name="can_focus">False</property> | |
13 | <property name="xpad">2</property> | |
14 | <property name="icon_name">window-close</property> | |
15 | </object> | |
16 | <object class="GtkImage" id="image3"> | |
17 | <property name="visible">True</property> | |
18 | <property name="can_focus">False</property> | |
19 | <property name="xpad">2</property> | |
20 | <property name="icon_name">dialog-ok</property> | |
21 | </object> | |
22 | <object class="IndicatorChooserDialog" id="indicator_chooser_dialog"> | |
23 | <property name="width_request">400</property> | |
24 | <property name="can_focus">False</property> | |
25 | <property name="title" translatable="yes" context="indicators-dialog">Select indicator</property> | |
26 | <property name="modal">True</property> | |
27 | <property name="window_position">center</property> | |
28 | <property name="destroy_with_parent">True</property> | |
29 | <property name="icon_name">application-x-executable</property> | |
30 | <property name="type_hint">dialog</property> | |
31 | <child internal-child="vbox"> | |
32 | <object class="GtkBox" id="dialog-vbox1"> | |
33 | <property name="can_focus">False</property> | |
34 | <property name="margin_left">8</property> | |
35 | <property name="margin_right">8</property> | |
36 | <property name="margin_top">8</property> | |
37 | <property name="margin_bottom">8</property> | |
38 | <property name="orientation">vertical</property> | |
39 | <property name="spacing">8</property> | |
40 | <child internal-child="action_area"> | |
41 | <object class="GtkButtonBox" id="dialog-action_area1"> | |
42 | <property name="can_focus">False</property> | |
43 | <property name="layout_style">end</property> | |
44 | <child> | |
45 | <object class="GtkButton" id="cancel_button"> | |
46 | <property name="label" translatable="yes" context="button">_Close</property> | |
47 | <property name="visible">True</property> | |
48 | <property name="can_focus">True</property> | |
49 | <property name="receives_default">True</property> | |
50 | <property name="image">image2</property> | |
51 | <property name="use_underline">True</property> | |
52 | </object> | |
53 | <packing> | |
54 | <property name="expand">False</property> | |
55 | <property name="fill">True</property> | |
56 | <property name="position">0</property> | |
57 | </packing> | |
58 | </child> | |
59 | <child> | |
60 | <object class="GtkButton" id="ok_button"> | |
61 | <property name="label" translatable="yes" context="button">_OK</property> | |
62 | <property name="visible">True</property> | |
63 | <property name="can_focus">True</property> | |
64 | <property name="can_default">True</property> | |
65 | <property name="has_default">True</property> | |
66 | <property name="receives_default">True</property> | |
67 | <property name="tooltip_text" translatable="yes">Add selected indicator to the list and close this window</property> | |
68 | <property name="image">image3</property> | |
69 | <property name="use_underline">True</property> | |
70 | </object> | |
71 | <packing> | |
72 | <property name="expand">False</property> | |
73 | <property name="fill">True</property> | |
74 | <property name="position">1</property> | |
75 | </packing> | |
76 | </child> | |
77 | <child> | |
78 | <object class="GtkBox" id="box1"> | |
79 | <property name="visible">True</property> | |
80 | <property name="can_focus">False</property> | |
81 | <property name="orientation">vertical</property> | |
82 | <child> | |
83 | <object class="GtkButton" id="add_button"> | |
84 | <property name="label" translatable="yes" context="button">_Add</property> | |
85 | <property name="visible">True</property> | |
86 | <property name="can_focus">True</property> | |
87 | <property name="receives_default">True</property> | |
88 | <property name="has_tooltip">True</property> | |
89 | <property name="tooltip_text" translatable="yes">Add selected indicator to the list without closing this window</property> | |
90 | <property name="image">image1</property> | |
91 | <property name="use_underline">True</property> | |
92 | <signal name="clicked" handler="on_add_clicked" swapped="no"/> | |
93 | </object> | |
94 | <packing> | |
95 | <property name="expand">False</property> | |
96 | <property name="fill">True</property> | |
97 | <property name="position">0</property> | |
98 | </packing> | |
99 | </child> | |
100 | </object> | |
101 | <packing> | |
102 | <property name="expand">False</property> | |
103 | <property name="fill">True</property> | |
104 | <property name="position">2</property> | |
105 | <property name="secondary">True</property> | |
106 | <property name="non_homogeneous">True</property> | |
107 | </packing> | |
108 | </child> | |
109 | </object> | |
110 | <packing> | |
111 | <property name="expand">False</property> | |
112 | <property name="fill">True</property> | |
113 | <property name="pack_type">end</property> | |
114 | <property name="position">0</property> | |
115 | </packing> | |
116 | </child> | |
117 | <child> | |
118 | <object class="GtkBox" id="box7"> | |
119 | <property name="visible">True</property> | |
120 | <property name="can_focus">False</property> | |
121 | <property name="valign">start</property> | |
122 | <property name="hexpand">True</property> | |
123 | <property name="orientation">vertical</property> | |
124 | <property name="spacing">8</property> | |
125 | <child> | |
126 | <object class="GtkRadioButton" id="short_choice"> | |
127 | <property name="visible">True</property> | |
128 | <property name="can_focus">True</property> | |
129 | <property name="receives_default">False</property> | |
130 | <property name="xalign">0</property> | |
131 | <property name="active">True</property> | |
132 | <property name="draw_indicator">True</property> | |
133 | <signal name="toggled" handler="on_short_choice_toggled" swapped="no"/> | |
134 | <child> | |
135 | <object class="GtkLabel" id="label5"> | |
136 | <property name="visible">True</property> | |
137 | <property name="can_focus">False</property> | |
138 | <property name="halign">start</property> | |
139 | <property name="hexpand">True</property> | |
140 | <property name="label" translatable="yes" context="indicators-dialog">Short name</property> | |
141 | <attributes> | |
142 | <attribute name="weight" value="semibold"/> | |
143 | </attributes> | |
144 | </object> | |
145 | </child> | |
146 | </object> | |
147 | <packing> | |
148 | <property name="expand">False</property> | |
149 | <property name="fill">True</property> | |
150 | <property name="position">0</property> | |
151 | </packing> | |
152 | </child> | |
153 | <child> | |
154 | <object class="GtkComboBox" id="combobox1"> | |
155 | <property name="visible">True</property> | |
156 | <property name="can_focus">False</property> | |
157 | <property name="margin_left">24</property> | |
158 | <property name="model">short_model</property> | |
159 | <property name="has_entry">True</property> | |
160 | <property name="entry_text_column">0</property> | |
161 | <child internal-child="entry"> | |
162 | <object class="GtkEntry" id="short_value"> | |
163 | <property name="can_focus">True</property> | |
164 | <property name="is_focus">True</property> | |
165 | <signal name="changed" handler="on_short_value_changed" swapped="no"/> | |
166 | <signal name="activate" handler="on_short_value_activate" swapped="no"/> | |
167 | </object> | |
168 | </child> | |
169 | </object> | |
170 | <packing> | |
171 | <property name="expand">False</property> | |
172 | <property name="fill">True</property> | |
173 | <property name="position">1</property> | |
174 | </packing> | |
175 | </child> | |
176 | <child> | |
177 | <object class="GtkLabel" id="label17"> | |
178 | <property name="visible">True</property> | |
179 | <property name="can_focus">False</property> | |
180 | <property name="halign">start</property> | |
181 | <property name="margin_left">24</property> | |
182 | <property name="label" translatable="yes" context="indicators-dialog">Indicators that greeter can find without using absolute pathes</property> | |
183 | <attributes> | |
184 | <attribute name="style" value="oblique"/> | |
185 | </attributes> | |
186 | </object> | |
187 | <packing> | |
188 | <property name="expand">False</property> | |
189 | <property name="fill">True</property> | |
190 | <property name="position">2</property> | |
191 | </packing> | |
192 | </child> | |
193 | <child> | |
194 | <object class="GtkRadioButton" id="path_choice"> | |
195 | <property name="visible">True</property> | |
196 | <property name="can_focus">True</property> | |
197 | <property name="receives_default">False</property> | |
198 | <property name="xalign">0</property> | |
199 | <property name="draw_indicator">True</property> | |
200 | <property name="group">short_choice</property> | |
201 | <child> | |
202 | <object class="GtkLabel" id="label4"> | |
203 | <property name="visible">True</property> | |
204 | <property name="can_focus">False</property> | |
205 | <property name="halign">start</property> | |
206 | <property name="hexpand">True</property> | |
207 | <property name="label" translatable="yes" context="indicators-dialog">Path</property> | |
208 | <attributes> | |
209 | <attribute name="weight" value="semibold"/> | |
210 | </attributes> | |
211 | </object> | |
212 | </child> | |
213 | </object> | |
214 | <packing> | |
215 | <property name="expand">False</property> | |
216 | <property name="fill">True</property> | |
217 | <property name="position">3</property> | |
218 | </packing> | |
219 | </child> | |
220 | <child> | |
221 | <object class="GtkFileChooserButton" id="path_value"> | |
222 | <property name="visible">True</property> | |
223 | <property name="can_focus">False</property> | |
224 | <property name="margin_left">24</property> | |
225 | <property name="filter">library_file_filter</property> | |
226 | <signal name="file-set" handler="on_path_value_changed" swapped="no"/> | |
227 | </object> | |
228 | <packing> | |
229 | <property name="expand">False</property> | |
230 | <property name="fill">True</property> | |
231 | <property name="position">4</property> | |
232 | </packing> | |
233 | </child> | |
234 | <child> | |
235 | <object class="GtkLabel" id="label16"> | |
236 | <property name="visible">True</property> | |
237 | <property name="can_focus">False</property> | |
238 | <property name="halign">start</property> | |
239 | <property name="margin_left">24</property> | |
240 | <property name="label" translatable="yes" context="indicators-dialog">Absolute path to indicator library file (*.so)</property> | |
241 | <attributes> | |
242 | <attribute name="style" value="oblique"/> | |
243 | </attributes> | |
244 | </object> | |
245 | <packing> | |
246 | <property name="expand">False</property> | |
247 | <property name="fill">True</property> | |
248 | <property name="position">5</property> | |
249 | </packing> | |
250 | </child> | |
251 | <child> | |
252 | <object class="GtkSeparator" id="separator2"> | |
253 | <property name="visible">True</property> | |
254 | <property name="can_focus">False</property> | |
255 | </object> | |
256 | <packing> | |
257 | <property name="expand">False</property> | |
258 | <property name="fill">True</property> | |
259 | <property name="position">6</property> | |
260 | </packing> | |
261 | </child> | |
262 | <child> | |
263 | <object class="GtkGrid" id="grid1"> | |
264 | <property name="visible">True</property> | |
265 | <property name="can_focus">False</property> | |
266 | <property name="halign">start</property> | |
267 | <property name="row_spacing">4</property> | |
268 | <property name="column_spacing">8</property> | |
269 | <child> | |
270 | <object class="GtkLabel" id="label2"> | |
271 | <property name="visible">True</property> | |
272 | <property name="can_focus">False</property> | |
273 | <property name="halign">start</property> | |
274 | <property name="label" translatable="yes" context="indicators-dialog">Fills the maximum available space</property> | |
275 | <attributes> | |
276 | <attribute name="style" value="oblique"/> | |
277 | </attributes> | |
278 | </object> | |
279 | <packing> | |
280 | <property name="left_attach">1</property> | |
281 | <property name="top_attach">0</property> | |
282 | <property name="width">1</property> | |
283 | <property name="height">1</property> | |
284 | </packing> | |
285 | </child> | |
286 | <child> | |
287 | <object class="GtkRadioButton" id="spacer_choice"> | |
288 | <property name="visible">True</property> | |
289 | <property name="can_focus">True</property> | |
290 | <property name="receives_default">False</property> | |
291 | <property name="xalign">0</property> | |
292 | <property name="draw_indicator">True</property> | |
293 | <property name="group">short_choice</property> | |
294 | <child> | |
295 | <object class="GtkLabel" id="label1"> | |
296 | <property name="visible">True</property> | |
297 | <property name="can_focus">False</property> | |
298 | <property name="halign">start</property> | |
299 | <property name="hexpand">True</property> | |
300 | <property name="label" translatable="yes" context="indicators-dialog">Spacer</property> | |
301 | <attributes> | |
302 | <attribute name="weight" value="semibold"/> | |
303 | </attributes> | |
304 | </object> | |
305 | </child> | |
306 | </object> | |
307 | <packing> | |
308 | <property name="left_attach">0</property> | |
309 | <property name="top_attach">0</property> | |
310 | <property name="width">1</property> | |
311 | <property name="height">1</property> | |
312 | </packing> | |
313 | </child> | |
314 | <child> | |
315 | <object class="GtkRadioButton" id="separator_choice"> | |
316 | <property name="visible">True</property> | |
317 | <property name="can_focus">True</property> | |
318 | <property name="receives_default">False</property> | |
319 | <property name="xalign">0</property> | |
320 | <property name="draw_indicator">True</property> | |
321 | <property name="group">short_choice</property> | |
322 | <child> | |
323 | <object class="GtkLabel" id="label3"> | |
324 | <property name="visible">True</property> | |
325 | <property name="can_focus">False</property> | |
326 | <property name="halign">start</property> | |
327 | <property name="hexpand">True</property> | |
328 | <property name="label" translatable="yes" context="indicators-dialog">Separator</property> | |
329 | <attributes> | |
330 | <attribute name="weight" value="semibold"/> | |
331 | </attributes> | |
332 | </object> | |
333 | </child> | |
334 | </object> | |
335 | <packing> | |
336 | <property name="left_attach">0</property> | |
337 | <property name="top_attach">1</property> | |
338 | <property name="width">1</property> | |
339 | <property name="height">1</property> | |
340 | </packing> | |
341 | </child> | |
342 | <child> | |
343 | <object class="GtkLabel" id="label6"> | |
344 | <property name="visible">True</property> | |
345 | <property name="can_focus">False</property> | |
346 | <property name="halign">start</property> | |
347 | <property name="label" translatable="yes" context="indicators-dialog">Draw a separator</property> | |
348 | <attributes> | |
349 | <attribute name="style" value="oblique"/> | |
350 | </attributes> | |
351 | </object> | |
352 | <packing> | |
353 | <property name="left_attach">1</property> | |
354 | <property name="top_attach">1</property> | |
355 | <property name="width">1</property> | |
356 | <property name="height">1</property> | |
357 | </packing> | |
358 | </child> | |
359 | </object> | |
360 | <packing> | |
361 | <property name="expand">False</property> | |
362 | <property name="fill">True</property> | |
363 | <property name="position">7</property> | |
364 | </packing> | |
365 | </child> | |
366 | <child> | |
367 | <object class="GtkInfoBar" id="infobar"> | |
368 | <property name="visible">True</property> | |
369 | <property name="app_paintable">True</property> | |
370 | <property name="can_focus">False</property> | |
371 | <property name="message_type">warning</property> | |
372 | <child internal-child="content_area"> | |
373 | <object class="GtkBox" id="infobar-content_area1"> | |
374 | <property name="can_focus">False</property> | |
375 | <property name="border_width">8</property> | |
376 | <property name="spacing">16</property> | |
377 | <child> | |
378 | <object class="GtkLabel" id="message"> | |
379 | <property name="visible">True</property> | |
380 | <property name="can_focus">False</property> | |
381 | <property name="label">[message]</property> | |
382 | </object> | |
383 | <packing> | |
384 | <property name="expand">True</property> | |
385 | <property name="fill">True</property> | |
386 | <property name="position">0</property> | |
387 | </packing> | |
388 | </child> | |
389 | </object> | |
390 | <packing> | |
391 | <property name="expand">True</property> | |
392 | <property name="fill">True</property> | |
393 | <property name="position">0</property> | |
394 | </packing> | |
395 | </child> | |
396 | <child internal-child="action_area"> | |
397 | <object class="GtkButtonBox" id="infobar-action_area1"> | |
398 | <property name="can_focus">False</property> | |
399 | <property name="border_width">5</property> | |
400 | <property name="orientation">vertical</property> | |
401 | <property name="layout_style">start</property> | |
402 | <child> | |
403 | <placeholder/> | |
404 | </child> | |
405 | </object> | |
406 | <packing> | |
407 | <property name="expand">False</property> | |
408 | <property name="fill">True</property> | |
409 | <property name="position">1</property> | |
410 | </packing> | |
411 | </child> | |
412 | </object> | |
413 | <packing> | |
414 | <property name="expand">False</property> | |
415 | <property name="fill">True</property> | |
416 | <property name="position">8</property> | |
417 | </packing> | |
418 | </child> | |
419 | </object> | |
420 | <packing> | |
421 | <property name="expand">True</property> | |
422 | <property name="fill">True</property> | |
423 | <property name="position">1</property> | |
424 | </packing> | |
425 | </child> | |
426 | <child> | |
427 | <object class="GtkSeparator" id="separator1"> | |
428 | <property name="visible">True</property> | |
429 | <property name="can_focus">False</property> | |
430 | </object> | |
431 | <packing> | |
432 | <property name="expand">False</property> | |
433 | <property name="fill">True</property> | |
434 | <property name="position">2</property> | |
435 | </packing> | |
436 | </child> | |
437 | </object> | |
438 | </child> | |
439 | <action-widgets> | |
440 | <action-widget response="-7">cancel_button</action-widget> | |
441 | <action-widget response="-5">ok_button</action-widget> | |
442 | </action-widgets> | |
443 | </object> | |
444 | <object class="GtkFileFilter" id="library_file_filter"> | |
445 | <mime-types> | |
446 | <mime-type>application/x-sharedlib</mime-type> | |
447 | </mime-types> | |
448 | </object> | |
449 | <object class="GtkListStore" id="short_model"> | |
450 | <columns> | |
451 | <!-- column-name name --> | |
452 | <column type="gchararray"/> | |
453 | </columns> | |
454 | </object> | |
455 | </interface> |
0 | <?xml version="1.0" encoding="UTF-8"?> | |
1 | <!-- Generated with glade 3.18.3 --> | |
2 | <interface> | |
3 | <requires lib="gtk+" version="3.8"/> | |
4 | <requires lib="gtk_greeter_settings" version="1.0"/> | |
5 | <object class="GtkImage" id="image1"> | |
6 | <property name="visible">True</property> | |
7 | <property name="can_focus">False</property> | |
8 | <property name="xpad">2</property> | |
9 | <property name="icon_name">list-add</property> | |
10 | </object> | |
11 | <object class="GtkImage" id="image2"> | |
12 | <property name="visible">True</property> | |
13 | <property name="can_focus">False</property> | |
14 | <property name="xpad">2</property> | |
15 | <property name="icon_name">window-close</property> | |
16 | </object> | |
17 | <object class="GtkImage" id="image3"> | |
18 | <property name="visible">True</property> | |
19 | <property name="can_focus">False</property> | |
20 | <property name="xpad">2</property> | |
21 | <property name="icon_name">dialog-ok</property> | |
22 | </object> | |
23 | <object class="GtkFileFilter" id="library_file_filter"> | |
24 | <mime-types> | |
25 | <mime-type>application/x-sharedlib</mime-type> | |
26 | </mime-types> | |
27 | </object> | |
28 | <object class="GtkListStore" id="option_path_model"> | |
29 | <columns> | |
30 | <!-- column-name title --> | |
31 | <column type="gchararray"/> | |
32 | <!-- column-name type --> | |
33 | <column type="gchararray"/> | |
34 | <!-- column-name icon --> | |
35 | <column type="gchararray"/> | |
36 | </columns> | |
37 | <data> | |
38 | <row> | |
39 | <col id="0" translatable="yes" context="option-entry|indicators">Select file...</col> | |
40 | <col id="1">select-path</col> | |
41 | <col id="2">system-search</col> | |
42 | </row> | |
43 | <row> | |
44 | <col id="0">-</col> | |
45 | <col id="1">separator</col> | |
46 | <col id="2">-</col> | |
47 | </row> | |
48 | </data> | |
49 | </object> | |
50 | <object class="IndicatorPropertiesDialog" id="indicator_properties_dialog"> | |
51 | <property name="width_request">400</property> | |
52 | <property name="can_focus">False</property> | |
53 | <property name="title" translatable="yes" context="option-entry|indicators">Indicator properties</property> | |
54 | <property name="resizable">False</property> | |
55 | <property name="modal">True</property> | |
56 | <property name="window_position">center</property> | |
57 | <property name="destroy_with_parent">True</property> | |
58 | <property name="icon_name">application-x-executable</property> | |
59 | <property name="type_hint">dialog</property> | |
60 | <child internal-child="vbox"> | |
61 | <object class="GtkBox" id="dialog-vbox1"> | |
62 | <property name="can_focus">False</property> | |
63 | <property name="margin_left">8</property> | |
64 | <property name="margin_right">8</property> | |
65 | <property name="margin_top">8</property> | |
66 | <property name="margin_bottom">8</property> | |
67 | <property name="orientation">vertical</property> | |
68 | <property name="spacing">8</property> | |
69 | <child internal-child="action_area"> | |
70 | <object class="GtkButtonBox" id="dialog-action_area1"> | |
71 | <property name="can_focus">False</property> | |
72 | <property name="homogeneous">True</property> | |
73 | <property name="layout_style">end</property> | |
74 | <child> | |
75 | <object class="GtkButton" id="cancel_button"> | |
76 | <property name="label" translatable="yes" context="button">_Close</property> | |
77 | <property name="visible">True</property> | |
78 | <property name="can_focus">True</property> | |
79 | <property name="receives_default">True</property> | |
80 | <property name="image">image2</property> | |
81 | <property name="use_underline">True</property> | |
82 | </object> | |
83 | <packing> | |
84 | <property name="expand">False</property> | |
85 | <property name="fill">True</property> | |
86 | <property name="position">0</property> | |
87 | </packing> | |
88 | </child> | |
89 | <child> | |
90 | <object class="GtkButton" id="ok_button"> | |
91 | <property name="label" translatable="yes" context="button">_OK</property> | |
92 | <property name="visible">True</property> | |
93 | <property name="can_focus">True</property> | |
94 | <property name="can_default">True</property> | |
95 | <property name="has_default">True</property> | |
96 | <property name="receives_default">True</property> | |
97 | <property name="image">image3</property> | |
98 | <property name="use_underline">True</property> | |
99 | </object> | |
100 | <packing> | |
101 | <property name="expand">False</property> | |
102 | <property name="fill">True</property> | |
103 | <property name="position">1</property> | |
104 | </packing> | |
105 | </child> | |
106 | <child> | |
107 | <object class="GtkBox" id="box1"> | |
108 | <property name="visible">True</property> | |
109 | <property name="can_focus">False</property> | |
110 | <property name="orientation">vertical</property> | |
111 | <property name="homogeneous">True</property> | |
112 | <child> | |
113 | <object class="GtkButton" id="add_button"> | |
114 | <property name="label" translatable="yes" context="button">_Add</property> | |
115 | <property name="visible">True</property> | |
116 | <property name="can_focus">True</property> | |
117 | <property name="receives_default">True</property> | |
118 | <property name="image">image1</property> | |
119 | <property name="use_underline">True</property> | |
120 | <signal name="clicked" handler="on_add_clicked" swapped="no"/> | |
121 | </object> | |
122 | <packing> | |
123 | <property name="expand">False</property> | |
124 | <property name="fill">True</property> | |
125 | <property name="position">0</property> | |
126 | </packing> | |
127 | </child> | |
128 | </object> | |
129 | <packing> | |
130 | <property name="expand">False</property> | |
131 | <property name="fill">True</property> | |
132 | <property name="position">2</property> | |
133 | <property name="secondary">True</property> | |
134 | <property name="non_homogeneous">True</property> | |
135 | </packing> | |
136 | </child> | |
137 | </object> | |
138 | <packing> | |
139 | <property name="expand">False</property> | |
140 | <property name="fill">True</property> | |
141 | <property name="pack_type">end</property> | |
142 | <property name="position">0</property> | |
143 | </packing> | |
144 | </child> | |
145 | <child> | |
146 | <object class="GtkBox" id="box2"> | |
147 | <property name="visible">True</property> | |
148 | <property name="can_focus">False</property> | |
149 | <property name="spacing">6</property> | |
150 | <child> | |
151 | <object class="GtkRadioButton" id="option_type_indicator_choice"> | |
152 | <property name="label" translatable="yes" context="option-entry|indicators">Indicator</property> | |
153 | <property name="visible">True</property> | |
154 | <property name="can_focus">True</property> | |
155 | <property name="receives_default">False</property> | |
156 | <property name="xalign">0</property> | |
157 | <property name="active">True</property> | |
158 | <property name="draw_indicator">True</property> | |
159 | </object> | |
160 | <packing> | |
161 | <property name="expand">False</property> | |
162 | <property name="fill">True</property> | |
163 | <property name="position">0</property> | |
164 | </packing> | |
165 | </child> | |
166 | <child> | |
167 | <object class="GtkComboBoxText" id="option_type_types"> | |
168 | <property name="visible">True</property> | |
169 | <property name="can_focus">False</property> | |
170 | <signal name="changed" handler="on_option_type_types_changed" swapped="no"/> | |
171 | </object> | |
172 | <packing> | |
173 | <property name="expand">False</property> | |
174 | <property name="fill">True</property> | |
175 | <property name="position">1</property> | |
176 | </packing> | |
177 | </child> | |
178 | </object> | |
179 | <packing> | |
180 | <property name="expand">False</property> | |
181 | <property name="fill">True</property> | |
182 | <property name="position">0</property> | |
183 | </packing> | |
184 | </child> | |
185 | <child> | |
186 | <object class="GtkBox" id="option_type_indicator_box"> | |
187 | <property name="visible">True</property> | |
188 | <property name="can_focus">False</property> | |
189 | <property name="margin_left">24</property> | |
190 | <property name="orientation">vertical</property> | |
191 | <property name="spacing">4</property> | |
192 | <child> | |
193 | <object class="GtkGrid" id="common_options_box"> | |
194 | <property name="visible">True</property> | |
195 | <property name="can_focus">False</property> | |
196 | <property name="row_spacing">8</property> | |
197 | <property name="column_spacing">6</property> | |
198 | <child> | |
199 | <object class="GtkCheckButton" id="option_text_use"> | |
200 | <property name="label" translatable="yes" context="option-entry|indicators">Display label</property> | |
201 | <property name="visible">True</property> | |
202 | <property name="can_focus">True</property> | |
203 | <property name="receives_default">False</property> | |
204 | <property name="xalign">0</property> | |
205 | <property name="draw_indicator">True</property> | |
206 | </object> | |
207 | <packing> | |
208 | <property name="left_attach">0</property> | |
209 | <property name="top_attach">0</property> | |
210 | </packing> | |
211 | </child> | |
212 | <child> | |
213 | <object class="GtkEntry" id="option_text_value"> | |
214 | <property name="visible">True</property> | |
215 | <property name="can_focus">True</property> | |
216 | <property name="hexpand">True</property> | |
217 | <property name="placeholder_text" translatable="yes" context="option-entry|indicators">Leave empty to use default value</property> | |
218 | </object> | |
219 | <packing> | |
220 | <property name="left_attach">1</property> | |
221 | <property name="top_attach">0</property> | |
222 | </packing> | |
223 | </child> | |
224 | <child> | |
225 | <object class="GtkCheckButton" id="option_image_use"> | |
226 | <property name="label" translatable="yes" context="option-entry|indicators">Display image</property> | |
227 | <property name="visible">True</property> | |
228 | <property name="can_focus">True</property> | |
229 | <property name="receives_default">False</property> | |
230 | <property name="xalign">0</property> | |
231 | <property name="draw_indicator">True</property> | |
232 | </object> | |
233 | <packing> | |
234 | <property name="left_attach">0</property> | |
235 | <property name="top_attach">1</property> | |
236 | </packing> | |
237 | </child> | |
238 | <child> | |
239 | <object class="GtkMenuButton" id="option_image_button"> | |
240 | <property name="visible">True</property> | |
241 | <property name="can_focus">True</property> | |
242 | <property name="receives_default">True</property> | |
243 | <property name="halign">start</property> | |
244 | <child> | |
245 | <object class="GtkBox" id="box3"> | |
246 | <property name="visible">True</property> | |
247 | <property name="can_focus">False</property> | |
248 | <property name="spacing">4</property> | |
249 | <child> | |
250 | <object class="GtkImage" id="option_image_image"> | |
251 | <property name="width_request">24</property> | |
252 | <property name="height_request">24</property> | |
253 | <property name="visible">True</property> | |
254 | <property name="can_focus">False</property> | |
255 | <property name="pixel_size">24</property> | |
256 | <property name="icon_name">avatar-default</property> | |
257 | <property name="icon_size">1</property> | |
258 | </object> | |
259 | <packing> | |
260 | <property name="expand">False</property> | |
261 | <property name="fill">True</property> | |
262 | <property name="position">0</property> | |
263 | </packing> | |
264 | </child> | |
265 | <child> | |
266 | <object class="GtkLabel" id="option_image_label"> | |
267 | <property name="height_request">24</property> | |
268 | <property name="visible">True</property> | |
269 | <property name="can_focus">False</property> | |
270 | <property name="label">[icon]</property> | |
271 | </object> | |
272 | <packing> | |
273 | <property name="expand">False</property> | |
274 | <property name="fill">True</property> | |
275 | <property name="position">1</property> | |
276 | </packing> | |
277 | </child> | |
278 | </object> | |
279 | </child> | |
280 | </object> | |
281 | <packing> | |
282 | <property name="left_attach">1</property> | |
283 | <property name="top_attach">1</property> | |
284 | </packing> | |
285 | </child> | |
286 | </object> | |
287 | <packing> | |
288 | <property name="expand">False</property> | |
289 | <property name="fill">True</property> | |
290 | <property name="position">0</property> | |
291 | </packing> | |
292 | </child> | |
293 | <child> | |
294 | <object class="GtkNotebook" id="custom_options_box"> | |
295 | <property name="visible">True</property> | |
296 | <property name="can_focus">False</property> | |
297 | <property name="valign">start</property> | |
298 | <property name="show_tabs">False</property> | |
299 | <property name="show_border">False</property> | |
300 | <child> | |
301 | <object class="GtkBox" id="custom_options_external"> | |
302 | <property name="can_focus">False</property> | |
303 | <property name="orientation">vertical</property> | |
304 | <property name="spacing">4</property> | |
305 | <child> | |
306 | <object class="GtkLabel" id="label2"> | |
307 | <property name="visible">True</property> | |
308 | <property name="can_focus">False</property> | |
309 | <property name="halign">start</property> | |
310 | <property name="label" translatable="yes" context="option-entry|indicators">Indicator library/service:</property> | |
311 | </object> | |
312 | <packing> | |
313 | <property name="expand">False</property> | |
314 | <property name="fill">True</property> | |
315 | <property name="position">0</property> | |
316 | </packing> | |
317 | </child> | |
318 | <child> | |
319 | <object class="GtkComboBox" id="option_path_combo"> | |
320 | <property name="visible">True</property> | |
321 | <property name="can_focus">False</property> | |
322 | <property name="model">option_path_model</property> | |
323 | <property name="has_entry">True</property> | |
324 | <property name="entry_text_column">0</property> | |
325 | <property name="id_column">1</property> | |
326 | <child> | |
327 | <object class="GtkCellRendererPixbuf" id="cellrenderertext1"/> | |
328 | <attributes> | |
329 | <attribute name="icon-name">2</attribute> | |
330 | </attributes> | |
331 | </child> | |
332 | <child> | |
333 | <object class="GtkCellRendererText" id="cellrenderertext2"/> | |
334 | <attributes> | |
335 | <attribute name="text">0</attribute> | |
336 | </attributes> | |
337 | </child> | |
338 | <child internal-child="entry"> | |
339 | <object class="GtkEntry" id="option_path_entry"> | |
340 | <property name="can_focus">True</property> | |
341 | </object> | |
342 | </child> | |
343 | </object> | |
344 | <packing> | |
345 | <property name="expand">False</property> | |
346 | <property name="fill">True</property> | |
347 | <property name="position">1</property> | |
348 | </packing> | |
349 | </child> | |
350 | </object> | |
351 | </child> | |
352 | <child type="tab"> | |
353 | <object class="GtkLabel" id="label3"> | |
354 | <property name="visible">True</property> | |
355 | <property name="can_focus">False</property> | |
356 | <property name="label" translatable="yes">page 1</property> | |
357 | </object> | |
358 | <packing> | |
359 | <property name="tab_fill">False</property> | |
360 | </packing> | |
361 | </child> | |
362 | <child> | |
363 | <object class="GtkBox" id="custom_options_power"> | |
364 | <property name="can_focus">False</property> | |
365 | <property name="orientation">vertical</property> | |
366 | <child> | |
367 | <object class="GtkCheckButton" id="option_hide_disabled_value"> | |
368 | <property name="label" translatable="yes" context="option-entry|indicators">Hide disabled power actions</property> | |
369 | <property name="visible">True</property> | |
370 | <property name="can_focus">True</property> | |
371 | <property name="receives_default">False</property> | |
372 | <property name="xalign">0</property> | |
373 | <property name="draw_indicator">True</property> | |
374 | </object> | |
375 | <packing> | |
376 | <property name="expand">False</property> | |
377 | <property name="fill">True</property> | |
378 | <property name="position">0</property> | |
379 | </packing> | |
380 | </child> | |
381 | </object> | |
382 | <packing> | |
383 | <property name="position">1</property> | |
384 | </packing> | |
385 | </child> | |
386 | <child type="tab"> | |
387 | <object class="GtkLabel" id="label1"> | |
388 | <property name="visible">True</property> | |
389 | <property name="can_focus">False</property> | |
390 | <property name="label" translatable="yes">page 2</property> | |
391 | </object> | |
392 | <packing> | |
393 | <property name="position">1</property> | |
394 | <property name="tab_fill">False</property> | |
395 | </packing> | |
396 | </child> | |
397 | <child> | |
398 | <object class="GtkBox" id="custom_options_text"> | |
399 | <property name="visible">True</property> | |
400 | <property name="can_focus">False</property> | |
401 | <property name="orientation">vertical</property> | |
402 | <property name="spacing">4</property> | |
403 | <child> | |
404 | <object class="GtkLabel" id="label5"> | |
405 | <property name="visible">True</property> | |
406 | <property name="can_focus">False</property> | |
407 | <property name="halign">start</property> | |
408 | <property name="label" translatable="yes" context="option-entry|indicators">Text to display:</property> | |
409 | </object> | |
410 | <packing> | |
411 | <property name="expand">False</property> | |
412 | <property name="fill">True</property> | |
413 | <property name="position">0</property> | |
414 | </packing> | |
415 | </child> | |
416 | <child> | |
417 | <object class="GtkEntry" id="option_text_fallback_value"> | |
418 | <property name="visible">True</property> | |
419 | <property name="can_focus">True</property> | |
420 | </object> | |
421 | <packing> | |
422 | <property name="expand">False</property> | |
423 | <property name="fill">True</property> | |
424 | <property name="position">1</property> | |
425 | </packing> | |
426 | </child> | |
427 | </object> | |
428 | <packing> | |
429 | <property name="position">2</property> | |
430 | </packing> | |
431 | </child> | |
432 | <child type="tab"> | |
433 | <object class="GtkLabel" id="label4"> | |
434 | <property name="visible">True</property> | |
435 | <property name="can_focus">False</property> | |
436 | <property name="label" translatable="yes">page 3</property> | |
437 | </object> | |
438 | <packing> | |
439 | <property name="position">2</property> | |
440 | <property name="tab_fill">False</property> | |
441 | </packing> | |
442 | </child> | |
443 | </object> | |
444 | <packing> | |
445 | <property name="expand">False</property> | |
446 | <property name="fill">True</property> | |
447 | <property name="position">1</property> | |
448 | </packing> | |
449 | </child> | |
450 | </object> | |
451 | <packing> | |
452 | <property name="expand">False</property> | |
453 | <property name="fill">True</property> | |
454 | <property name="position">2</property> | |
455 | </packing> | |
456 | </child> | |
457 | <child> | |
458 | <object class="GtkRadioButton" id="option_type_spacer_choice"> | |
459 | <property name="label" translatable="yes" context="option-entry|indicators">Spacer - fills the maximum available space</property> | |
460 | <property name="visible">True</property> | |
461 | <property name="can_focus">True</property> | |
462 | <property name="receives_default">False</property> | |
463 | <property name="xalign">0</property> | |
464 | <property name="draw_indicator">True</property> | |
465 | <property name="group">option_type_indicator_choice</property> | |
466 | </object> | |
467 | <packing> | |
468 | <property name="expand">False</property> | |
469 | <property name="fill">True</property> | |
470 | <property name="position">3</property> | |
471 | </packing> | |
472 | </child> | |
473 | <child> | |
474 | <object class="GtkRadioButton" id="option_type_separator_choice"> | |
475 | <property name="label" translatable="yes" context="option-entry|indicators">Separator - draw a separator</property> | |
476 | <property name="visible">True</property> | |
477 | <property name="can_focus">True</property> | |
478 | <property name="receives_default">False</property> | |
479 | <property name="xalign">0</property> | |
480 | <property name="draw_indicator">True</property> | |
481 | <property name="group">option_type_indicator_choice</property> | |
482 | </object> | |
483 | <packing> | |
484 | <property name="expand">False</property> | |
485 | <property name="fill">True</property> | |
486 | <property name="position">4</property> | |
487 | </packing> | |
488 | </child> | |
489 | <child> | |
490 | <object class="GtkInfoBar" id="infobar"> | |
491 | <property name="app_paintable">True</property> | |
492 | <property name="can_focus">False</property> | |
493 | <property name="message_type">warning</property> | |
494 | <child internal-child="action_area"> | |
495 | <object class="GtkButtonBox" id="infobar-action_area"> | |
496 | <property name="can_focus">False</property> | |
497 | <property name="orientation">vertical</property> | |
498 | <property name="layout_style">start</property> | |
499 | <child> | |
500 | <placeholder/> | |
501 | </child> | |
502 | </object> | |
503 | <packing> | |
504 | <property name="expand">False</property> | |
505 | <property name="fill">True</property> | |
506 | <property name="position">1</property> | |
507 | </packing> | |
508 | </child> | |
509 | <child internal-child="content_area"> | |
510 | <object class="GtkBox" id="infobar-content_area"> | |
511 | <property name="can_focus">False</property> | |
512 | <property name="spacing">16</property> | |
513 | <child> | |
514 | <object class="GtkLabel" id="message"> | |
515 | <property name="visible">True</property> | |
516 | <property name="can_focus">False</property> | |
517 | <property name="label">[message]</property> | |
518 | </object> | |
519 | <packing> | |
520 | <property name="expand">True</property> | |
521 | <property name="fill">True</property> | |
522 | <property name="position">0</property> | |
523 | </packing> | |
524 | </child> | |
525 | </object> | |
526 | <packing> | |
527 | <property name="expand">True</property> | |
528 | <property name="fill">True</property> | |
529 | <property name="position">0</property> | |
530 | </packing> | |
531 | </child> | |
532 | </object> | |
533 | <packing> | |
534 | <property name="expand">False</property> | |
535 | <property name="fill">True</property> | |
536 | <property name="position">5</property> | |
537 | </packing> | |
538 | </child> | |
539 | <child> | |
540 | <object class="GtkSeparator" id="separator1"> | |
541 | <property name="visible">True</property> | |
542 | <property name="can_focus">False</property> | |
543 | </object> | |
544 | <packing> | |
545 | <property name="expand">False</property> | |
546 | <property name="fill">True</property> | |
547 | <property name="position">6</property> | |
548 | </packing> | |
549 | </child> | |
550 | </object> | |
551 | </child> | |
552 | <action-widgets> | |
553 | <action-widget response="-7">cancel_button</action-widget> | |
554 | <action-widget response="-5">ok_button</action-widget> | |
555 | </action-widgets> | |
556 | </object> | |
557 | </interface> |
0 | 0 | <?xml version="1.0" encoding="UTF-8"?> |
1 | 1 | <!-- Generated with glade 3.18.3 --> |
2 | 2 | <interface> |
3 | <requires lib="gtk+" version="3.6"/> | |
3 | <requires lib="gtk+" version="3.8"/> | |
4 | 4 | <requires lib="gtk_greeter_settings" version="1.0"/> |
5 | 5 | <object class="GtkListStore" id="background_model"> |
6 | 6 | <columns> |
16 | 16 | </row> |
17 | 17 | <row> |
18 | 18 | <col id="0" translatable="yes" context="option|multihead">Select color</col> |
19 | <col id="1">icon</col> | |
19 | <col id="1">color</col> | |
20 | 20 | </row> |
21 | 21 | <row> |
22 | 22 | <col id="0" translatable="yes" context="option|multihead">Use default value</col> |
59 | 59 | <column type="GdkPixbuf"/> |
60 | 60 | <!-- column-name background-is-color --> |
61 | 61 | <column type="gboolean"/> |
62 | <!-- column-name error-visible --> | |
63 | <column type="gboolean"/> | |
64 | <!-- column-name error-text --> | |
65 | <column type="gchararray"/> | |
62 | 66 | </columns> |
63 | 67 | </object> |
64 | 68 | <object class="MultiheadSetupDialog" id="multihead_setup_dialog"> |
65 | 69 | <property name="width_request">500</property> |
66 | 70 | <property name="can_focus">False</property> |
67 | <property name="title" translatable="yes" context="option|monitors">Multihead setup</property> | |
71 | <property name="title" translatable="yes" context="option|multihead">Multihead setup</property> | |
68 | 72 | <property name="modal">True</property> |
69 | 73 | <property name="window_position">center</property> |
70 | 74 | <property name="destroy_with_parent">True</property> |
152 | 156 | <property name="headers_clickable">False</property> |
153 | 157 | <property name="search_column">0</property> |
154 | 158 | <child internal-child="selection"> |
155 | <object class="GtkTreeSelection" id="treeview-selection"> | |
159 | <object class="GtkTreeSelection" id="monitors_selection"> | |
156 | 160 | <signal name="changed" handler="on_selection_changed" swapped="no"/> |
157 | 161 | </object> |
158 | 162 | </child> |
167 | 171 | </object> |
168 | 172 | <attributes> |
169 | 173 | <attribute name="text">0</attribute> |
174 | </attributes> | |
175 | </child> | |
176 | <child> | |
177 | <object class="GtkCellRendererPixbuf" id="error_renderer"> | |
178 | <property name="icon_name">dialog-warning</property> | |
179 | </object> | |
180 | <attributes> | |
181 | <attribute name="visible">8</attribute> | |
170 | 182 | </attributes> |
171 | 183 | </child> |
172 | 184 | </object> |
205 | 217 | <child> |
206 | 218 | <object class="GtkTreeViewColumn" id="background_column"> |
207 | 219 | <property name="resizable">True</property> |
220 | <property name="sizing">autosize</property> | |
208 | 221 | <property name="title" translatable="yes" context="option|multihead">Background</property> |
222 | <property name="expand">True</property> | |
209 | 223 | <child> |
210 | 224 | <object class="GtkCellRendererPixbuf" id="color_renderer"/> |
211 | 225 | <attributes> |
245 | 259 | <object class="GtkToolButton" id="add_button"> |
246 | 260 | <property name="visible">True</property> |
247 | 261 | <property name="can_focus">False</property> |
248 | <property name="tooltip_text" translatable="yes" context="option|monitors">Add monior to the list</property> | |
249 | <property name="label" translatable="yes" context="option|monitors">Add</property> | |
262 | <property name="tooltip_text" translatable="yes" context="option|multihead">Add monior to the list</property> | |
263 | <property name="label" translatable="yes" context="option|multihead">Add</property> | |
250 | 264 | <property name="use_underline">True</property> |
251 | 265 | <property name="icon_name">list-add-symbolic</property> |
252 | 266 | <signal name="clicked" handler="on_monitors_add_clicked" swapped="no"/> |
260 | 274 | <object class="GtkToolButton" id="remove_button"> |
261 | 275 | <property name="visible">True</property> |
262 | 276 | <property name="can_focus">False</property> |
263 | <property name="tooltip_text" translatable="yes" context="option|monitors">Remove monitor from the list</property> | |
264 | <property name="label" translatable="yes" context="option|monitors">Remove</property> | |
277 | <property name="tooltip_text" translatable="yes" context="option|multihead">Remove monitor from the list</property> | |
278 | <property name="label" translatable="yes" context="option|multihead">Remove</property> | |
265 | 279 | <property name="use_underline">True</property> |
266 | 280 | <property name="icon_name">list-remove-symbolic</property> |
267 | 281 | <signal name="clicked" handler="on_monitors_remove_clicked" swapped="no"/> |
3 | 3 | <glade-widget-class title="Settings Window" name="GtkGreeterSettingsWindow" |
4 | 4 | generic-name="GtkGreeterSettingsWindow" parent="GtkWindow" |
5 | 5 | icon-name="widget-gtk-window"/> |
6 | <glade-widget-class title="Indicator Chooser Dialog" name="IndicatorChooserDialog" | |
7 | generic-name="IndicatorChooserDialog" parent="GtkDialog" | |
6 | <glade-widget-class title="Indicator Properties Dialog" name="IndicatorPropertiesDialog" | |
7 | generic-name="IndicatorPropertiesDialog" parent="GtkDialog" | |
8 | 8 | icon-name="widget-gtk-dialog"/> |
9 | 9 | <glade-widget-class title="Icon Chooser Dialog" name="IconChooserDialog" |
10 | 10 | generic-name="IconChooserDialog" parent="GtkDialog" |
14 | 14 | # You should have received a copy of the GNU General Public License along |
15 | 15 | # with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | 16 | |
17 | from collections import namedtuple | |
17 | ||
18 | import collections | |
18 | 19 | import configparser |
20 | import os | |
21 | import shlex | |
22 | import sys | |
19 | 23 | from glob import iglob |
20 | 24 | from itertools import chain |
21 | 25 | from locale import gettext as _ |
22 | import os | |
23 | import sys | |
24 | ||
25 | from gi.repository import Gtk | |
26 | from lightdm_gtk_greeter_settings import OptionEntry | |
27 | from lightdm_gtk_greeter_settings import helpers | |
28 | from lightdm_gtk_greeter_settings.helpers import C_, WidgetsWrapper | |
29 | ||
30 | from lightdm_gtk_greeter_settings.MultiheadSetupDialog import MonitorsGroup | |
26 | ||
27 | from gi.repository import ( | |
28 | Gdk, | |
29 | Gtk) | |
30 | from gi.repository import Pango | |
31 | from gi.repository.GObject import markup_escape_text as escape_markup | |
32 | ||
33 | from lightdm_gtk_greeter_settings import ( | |
34 | helpers, | |
35 | IconEntry, | |
36 | IndicatorsEntry, | |
37 | OptionEntry, | |
38 | PositionEntry) | |
39 | from lightdm_gtk_greeter_settings.helpers import ( | |
40 | C_, | |
41 | string2bool, | |
42 | WidgetsEnum) | |
43 | from lightdm_gtk_greeter_settings.MonitorsGroup import MonitorsGroup | |
31 | 44 | from lightdm_gtk_greeter_settings.OptionGroup import SimpleGroup |
32 | 45 | |
33 | 46 | |
34 | 47 | __all__ = ['GtkGreeterSettingsWindow'] |
35 | 48 | |
36 | 49 | |
37 | InitialValue = namedtuple('InitialValue', ('value', 'enabled')) | |
50 | InitialValue = collections.namedtuple('InitialValue', ('value', 'enabled')) | |
38 | 51 | |
39 | 52 | |
40 | 53 | class GtkGreeterSettingsWindow(Gtk.Window): |
41 | 54 | |
42 | 55 | __gtype_name__ = 'GtkGreeterSettingsWindow' |
43 | 56 | |
44 | BUILDER_WIDGETS = ('apply_button', 'no_access_infobar', | |
45 | 'gtk_theme_values', 'icons_theme_values') | |
57 | class Widgets(WidgetsEnum): | |
58 | apply = 'apply_button' | |
59 | infobar = 'infobar' | |
46 | 60 | |
47 | 61 | def __new__(cls): |
48 | 62 | builder = Gtk.Builder() |
49 | 63 | builder.add_from_file(helpers.get_data_path('%s.ui' % cls.__name__)) |
50 | 64 | window = builder.get_object('settings_window') |
51 | window._builder = builder | |
52 | window._widgets = WidgetsWrapper(builder) | |
53 | window.__dict__.update(('_' + w, builder.get_object(w)) | |
54 | for w in cls.BUILDER_WIDGETS) | |
65 | window.builder = builder | |
55 | 66 | builder.connect_signals(window) |
56 | window._init_window() | |
67 | window.init_window() | |
57 | 68 | return window |
58 | 69 | |
59 | def _init_window(self): | |
60 | ||
61 | self._entries_setup = \ | |
62 | { | |
63 | ('greeter', 'screensaver-timeout'): self.on_entry_setup_greeter_screensaver_timeout, | |
64 | ('greeter', 'theme-name'): self.on_entry_setup_greeter_theme_name, | |
65 | ('greeter', 'icon-theme-name'): self.on_entry_setup_greeter_icon_theme_name, | |
66 | } | |
70 | builder = None | |
71 | ||
72 | entries_setup = { | |
73 | ('greeter', 'allow-debugging'): ('changed',), | |
74 | ('greeter', 'background'): ('changed',), | |
75 | ('greeter', 'default-user-image'): ('changed',), | |
76 | ('greeter', 'screensaver-timeout'): ('setup', 'get', 'set'), | |
77 | ('greeter', 'theme-name'): ('setup', 'changed'), | |
78 | ('greeter', 'icon-theme-name'): ('setup', 'changed'), | |
79 | ('greeter', 'keyboard'): ('changed',), | |
80 | ('greeter', 'reader'): ('changed',)} | |
81 | ||
82 | def init_window(self): | |
83 | self._widgets = self.Widgets(builder=self.builder) | |
67 | 84 | |
68 | 85 | self._multihead_dialog = None |
86 | self._entry_menu = None | |
69 | 87 | self._initial_values = {} |
70 | 88 | self._changed_entries = None |
71 | 89 | self._entries = None |
72 | self._groups = \ | |
73 | ( | |
74 | SimpleGroup('greeter', self._builder, | |
75 | { | |
90 | self._groups = ( | |
91 | SimpleGroup('greeter', self.builder, { | |
76 | 92 | # Appearance |
77 | 'theme-name': (OptionEntry.StringEntry, None), | |
78 | 'icon-theme-name': (OptionEntry.StringEntry, None), | |
93 | 'theme-name': (OptionEntry.StringEntry, ''), | |
94 | 'icon-theme-name': (OptionEntry.StringEntry, ''), | |
79 | 95 | 'font-name': (OptionEntry.FontEntry, 'Sans 10'), |
80 | 96 | 'xft-antialias': (OptionEntry.BooleanEntry, 'false'), |
81 | 97 | 'xft-dpi': (OptionEntry.StringEntry, None), |
83 | 99 | 'xft-hintstyle': (OptionEntry.ChoiceEntry, None), |
84 | 100 | 'background': (OptionEntry.BackgroundEntry, '#000000'), |
85 | 101 | 'user-background': (OptionEntry.BooleanEntry, 'true'), |
86 | 'default-user-image': (OptionEntry.IconEntry, '#avatar-default'), | |
102 | 'hide-user-image': (OptionEntry.InvertedBooleanEntry, 'false'), | |
103 | 'default-user-image': (IconEntry.IconEntry, '#avatar-default'), | |
87 | 104 | # Panel |
88 | 105 | 'clock-format': (OptionEntry.ClockFormatEntry, '%a, %H:%M'), |
89 | 'indicators': (OptionEntry.IndicatorsEntry, | |
106 | 'indicators': (IndicatorsEntry.IndicatorsEntry, | |
90 | 107 | '~host;~spacer;~clock;~spacer;~language;~session;~a11y;~power'), |
91 | 108 | # Position |
92 | 'position': (OptionEntry.PositionEntry, '50%,center'), | |
109 | 'position': (PositionEntry.PositionEntry, '50%,center'), | |
93 | 110 | # Misc |
94 | 'screensaver-timeout': (OptionEntry.AdjustmentEntry, 60), | |
95 | 'keyboard': (OptionEntry.StringEntry, None) | |
96 | }), | |
97 | MonitorsGroup(self._widgets) | |
98 | ) | |
111 | 'screensaver-timeout': (OptionEntry.AdjustmentEntry, '60'), | |
112 | 'keyboard': (OptionEntry.StringPathEntry, ''), | |
113 | 'reader': (OptionEntry.StringPathEntry, ''), | |
114 | 'a11y-states': (OptionEntry.AccessibilityStatesEntry, ''), | |
115 | 'allow-debugging': (OptionEntry.BooleanEntry, 'false'), }), | |
116 | MonitorsGroup(self.builder)) | |
99 | 117 | |
100 | 118 | for group in self._groups: |
101 | 119 | group.entry_added.connect(self.on_entry_added) |
102 | 120 | group.entry_removed.connect(self.on_entry_removed) |
103 | 121 | |
104 | self._timeout_adjustment = self._widgets['greeter', 'screensaver-timeout', 'adjustment'] | |
105 | ||
106 | 122 | self._config_path = helpers.get_config_path() |
107 | 123 | self._allow_edit = self._has_access_to_write(self._config_path) |
108 | self._no_access_infobar.props.visible = not self._allow_edit | |
109 | self._apply_button.props.visible = self._allow_edit | |
124 | self._widgets.infobar.props.visible = not self._allow_edit | |
125 | self._widgets.apply.props.visible = self._allow_edit | |
126 | ||
110 | 127 | if not self._allow_edit: |
111 | 128 | helpers.show_message( |
112 | 129 | text=_('No permissions to save configuration'), |
142 | 159 | group.read(self._config) |
143 | 160 | |
144 | 161 | self._initial_values = {entry: InitialValue(entry.value, entry.enabled) |
145 | for entry in self._initial_values.keys()} | |
162 | for entry in self._initial_values.keys()} | |
146 | 163 | self._changed_entries = set() |
147 | self._apply_button.props.sensitive = False | |
164 | self._widgets.apply.props.sensitive = False | |
148 | 165 | |
149 | 166 | def _write(self): |
150 | 167 | for group in self._groups: |
154 | 171 | self._initial_values[entry] = InitialValue(entry.value, entry.enabled) |
155 | 172 | |
156 | 173 | self._changed_entries.clear() |
157 | self._apply_button.props.sensitive = False | |
174 | self._widgets.apply.props.sensitive = False | |
158 | 175 | |
159 | 176 | try: |
160 | 177 | with open(self._config_path, 'w') as file: |
163 | 180 | helpers.show_message(e, Gtk.MessageType.ERROR) |
164 | 181 | |
165 | 182 | def on_entry_added(self, group, entry, key): |
166 | if isinstance(group, SimpleGroup): | |
167 | setup = self._entries_setup.get((group.name, key)) | |
168 | if setup: | |
169 | setup(entry) | |
183 | if isinstance(group, SimpleGroup) and (group.name, key) in self.entries_setup: | |
184 | for action in self.entries_setup[(group.name, key)]: | |
185 | fname = 'on_entry_%s_%s_%s' % (action, group.name, key) | |
186 | f = getattr(self, fname.replace('-', '_')) | |
187 | if action == 'setup': | |
188 | f(entry) | |
189 | else: | |
190 | entry.connect(action, f) | |
191 | ||
192 | label_holder = entry.widgets['label_holder'] | |
193 | if label_holder and isinstance(group, SimpleGroup): | |
194 | label_holder.connect('button-press-event', self.on_entry_label_clicked, | |
195 | entry, group, key) | |
196 | ||
170 | 197 | entry.changed.connect(self.on_entry_changed) |
171 | 198 | self._initial_values[entry] = InitialValue(entry.value, entry.enabled) |
172 | 199 | self.on_entry_changed(entry, force=True) |
173 | 200 | |
174 | 201 | def on_entry_removed(self, group, entry, key): |
175 | 202 | self._initial_values.pop(entry) |
203 | ||
176 | 204 | if self._changed_entries is None: |
177 | 205 | return |
178 | 206 | |
179 | 207 | self._changed_entries.discard(entry) |
180 | self._apply_button.props.sensitive = self._allow_edit and self._changed_entries | |
208 | self._widgets.apply.props.sensitive = self._allow_edit and self._changed_entries | |
181 | 209 | |
182 | 210 | def on_entry_changed(self, entry, force=False): |
183 | 211 | if self._changed_entries is None: |
184 | 212 | return |
185 | 213 | |
186 | if force or entry.enabled != self._initial_values[entry].enabled or \ | |
187 | (entry.enabled and entry.value != self._initial_values[entry].value): | |
214 | initial = self._initial_values[entry] | |
215 | if force or entry.enabled != initial.enabled or \ | |
216 | (entry.enabled and entry.value != initial.value): | |
188 | 217 | self._changed_entries.add(entry) |
189 | 218 | else: |
190 | 219 | self._changed_entries.discard(entry) |
191 | self._apply_button.props.sensitive = self._allow_edit and self._changed_entries | |
192 | ||
220 | ||
221 | self._widgets.apply.props.sensitive = self._allow_edit and self._changed_entries | |
222 | ||
223 | def on_entry_reset_clicked(self, item): | |
224 | entry, value, enabled = item._reset_entry_data | |
225 | if enabled is None: | |
226 | entry.value = value | |
227 | else: | |
228 | entry.enabled = enabled | |
229 | ||
230 | def on_entry_label_clicked(self, widget, event, entry, group, key): | |
231 | if event.button != 3: | |
232 | return | |
233 | ||
234 | if not self._entry_menu: | |
235 | def new_item(activate=None): | |
236 | item = Gtk.MenuItem('') | |
237 | item.get_child().props.use_markup = True | |
238 | item.get_child().props.ellipsize = Pango.EllipsizeMode.END | |
239 | item.get_child().props.max_width_chars = 90 | |
240 | if activate: | |
241 | item.connect('activate', activate) | |
242 | else: | |
243 | item.props.sensitive = False | |
244 | return item | |
245 | ||
246 | self._entry_menu = Gtk.Menu() | |
247 | self._entry_menu_label_item = new_item() | |
248 | self._entry_menu_separator_item = Gtk.SeparatorMenuItem() | |
249 | self._entry_menu_initial_item = new_item(self.on_entry_reset_clicked) | |
250 | self._entry_menu_default_item = new_item(self.on_entry_reset_clicked) | |
251 | ||
252 | self._entry_menu.append(self._entry_menu_label_item) | |
253 | self._entry_menu.append(self._entry_menu_separator_item) | |
254 | self._entry_menu.append(self._entry_menu_initial_item) | |
255 | self._entry_menu.append(self._entry_menu_default_item) | |
256 | self._entry_menu.show_all() | |
257 | ||
258 | def format_value(value=None, enabled=True): | |
259 | if not enabled: | |
260 | return _('<i>disabled</i>') | |
261 | if value == '': | |
262 | return _('<i>empty string</i>') | |
263 | elif value is None: | |
264 | return _('<i>None</i>') | |
265 | else: | |
266 | return escape_markup(str(value)) | |
267 | ||
268 | self._entry_menu_label_item.props.label = '{key} = {value}'.format( | |
269 | group=group.name, | |
270 | key=key, | |
271 | value=format_value(value=entry.value, enabled=entry.enabled)) | |
272 | ||
273 | if entry in self._changed_entries: | |
274 | initial = self._initial_values[entry] | |
275 | ||
276 | if entry.enabled != initial.enabled and not initial.enabled: | |
277 | self._entry_menu_initial_item._reset_entry_data = entry, None, initial.enabled | |
278 | else: | |
279 | self._entry_menu_initial_item._reset_entry_data = entry, initial.value, None | |
280 | ||
281 | value = format_value(value=initial.value, enabled=initial.enabled) | |
282 | self._entry_menu_initial_item.set_tooltip_markup(value) | |
283 | self._entry_menu_initial_item.props.visible = True | |
284 | self._entry_menu_initial_item.props.label = \ | |
285 | _('Reset to initial value: <b>{value}</b>').format(value=value) | |
286 | else: | |
287 | self._entry_menu_initial_item.props.visible = False | |
288 | ||
289 | default = group.defaults[key] | |
290 | if default is not None and entry.value != default: | |
291 | value = format_value(value=default) | |
292 | self._entry_menu_default_item._reset_entry_data = entry, default, None | |
293 | self._entry_menu_default_item.set_tooltip_markup(value) | |
294 | self._entry_menu_default_item.props.visible = True | |
295 | self._entry_menu_default_item.props.label = \ | |
296 | _('Reset to default value: <b>{value}</b>').format(value=value) | |
297 | else: | |
298 | self._entry_menu_default_item.props.visible = False | |
299 | ||
300 | self._entry_menu_separator_item.props.visible = \ | |
301 | (self._entry_menu_initial_item.props.visible or | |
302 | self._entry_menu_default_item.props.visible) | |
303 | self._entry_menu.popup(None, None, None, None, 0, Gtk.get_current_event_time()) | |
304 | ||
305 | # [greeter] screensaver-timeout | |
193 | 306 | def on_entry_setup_greeter_screensaver_timeout(self, entry): |
194 | timeout_view = entry.widgets['view'] | |
195 | timeout_adjustment = entry.widgets['adjustment'] | |
196 | timeout_end_label = entry.widgets['end-label'] | |
197 | for mark in chain(list(range(10, 61, 10)), | |
198 | list(range(69, | |
199 | int(timeout_adjustment.props.upper), | |
200 | 10))): | |
201 | timeout_view.add_mark(mark, Gtk.PositionType.BOTTOM, None) | |
202 | total = int(timeout_adjustment.props.upper - 60) + 1 | |
203 | timeout_end_label.props.label = C_('option|timeout', '{count} min').format(count=total) | |
204 | ||
205 | timeout_view.connect('format-value', self.on_entry_format_scale_greeter_screensaver_timeout, timeout_adjustment) | |
206 | entry.get.connect(self.on_entry_get_greeter_screensaver_timeout) | |
207 | entry.set.connect(self.on_entry_set_greeter_screensaver_timeout) | |
208 | ||
307 | view = entry.widgets['view'] | |
308 | adjustment = entry.widgets['adjustment'] | |
309 | end_label = entry.widgets['end-label'] | |
310 | for mark in chain((range(10, 61, 10)), | |
311 | (range(69, int(adjustment.props.upper), 10))): | |
312 | view.add_mark(mark, Gtk.PositionType.BOTTOM, None) | |
313 | total = int(adjustment.props.upper - 60) + 1 | |
314 | end_label.props.label = C_('option|greeter|screensaver-timeout', | |
315 | '{count} min').format(count=total) | |
316 | ||
317 | view.connect('format-value', | |
318 | self.on_entry_format_scale_greeter_screensaver_timeout, | |
319 | adjustment) | |
320 | ||
321 | def on_entry_get_greeter_screensaver_timeout(self, entry=None, value=None): | |
322 | try: | |
323 | value = int(float(value)) | |
324 | except ValueError: | |
325 | value = 60 | |
326 | ||
327 | if value > 60: | |
328 | return (value - 59) * 60 | |
329 | return value | |
330 | ||
331 | def on_entry_set_greeter_screensaver_timeout(self, entry=None, value=None): | |
332 | try: | |
333 | value = int(float(value)) | |
334 | except ValueError: | |
335 | value = 60 | |
336 | ||
337 | if value > 60: | |
338 | return value // 60 + 59 | |
339 | return value | |
340 | ||
341 | def on_entry_format_scale_greeter_screensaver_timeout(self, scale, value, adjustment): | |
342 | if value != adjustment.props.lower and value != adjustment.props.upper: | |
343 | value = self.on_entry_get_greeter_screensaver_timeout(value=value) | |
344 | return '%02d:%02d' % (value // 60, value % 60) | |
345 | return '' | |
346 | ||
347 | # [greeter] theme-name | |
209 | 348 | def on_entry_setup_greeter_theme_name(self, entry): |
210 | 349 | values = entry.widgets['values'] |
211 | 350 | for theme in sorted(iglob(os.path.join(sys.prefix, 'share', 'themes', '*', 'gtk-3.0'))): |
212 | 351 | values.append_text(theme.split(os.path.sep)[-2]) |
213 | 352 | |
353 | def on_entry_changed_greeter_theme_name(self, entry): | |
354 | if not entry.value or \ | |
355 | entry.value in (row[0] for row in entry.widgets['values'].props.model): | |
356 | entry.error = None | |
357 | else: | |
358 | entry.error = C_('option|greeter|theme-name', 'Selected theme is not available') | |
359 | ||
360 | # [greeter] icon-theme-name | |
214 | 361 | def on_entry_setup_greeter_icon_theme_name(self, entry): |
215 | 362 | values = entry.widgets['values'] |
216 | 363 | for theme in sorted(iglob(os.path.join(sys.prefix, 'share', 'icons', '*', 'index.theme'))): |
217 | 364 | values.append_text(theme.split(os.path.sep)[-2]) |
218 | 365 | |
219 | def on_entry_get_greeter_screensaver_timeout(self, entry=None, value=None): | |
220 | value = int(float(value)) | |
221 | if value > 60: | |
222 | return (value - 59) * 60 | |
223 | return value | |
224 | ||
225 | def on_entry_set_greeter_screensaver_timeout(self, entry=None, value=None): | |
226 | value = int(float(value)) | |
227 | if value > 60: | |
228 | return value // 60 + 59 | |
229 | return value | |
230 | ||
231 | def on_entry_format_scale_greeter_screensaver_timeout(self, scale, value, adjustment): | |
232 | if value != adjustment.props.lower and value != adjustment.props.upper: | |
233 | value = self.on_entry_get_greeter_screensaver_timeout(value=value) | |
234 | return '%02d:%02d' % (value // 60, value % 60) | |
235 | else: | |
236 | return '' | |
366 | def on_entry_changed_greeter_icon_theme_name(self, entry): | |
367 | if not entry.value or \ | |
368 | entry.value in (row[0] for row in entry.widgets['values'].props.model): | |
369 | entry.error = None | |
370 | else: | |
371 | entry.error = C_('option|greeter|icon-theme-name', 'Selected theme is not available') | |
372 | ||
373 | # [greeter] allow-debugging | |
374 | def on_entry_changed_greeter_allow_debugging(self, entry): | |
375 | if (Gtk.MAJOR_VERSION, Gtk.MINOR_VERSION, Gtk.MICRO_VERSION) < (3, 14, 0) and \ | |
376 | string2bool(entry.value): | |
377 | entry.error = C_('option|greeter|allow-debugging', | |
378 | 'GtkInspector is not available on your system') | |
379 | else: | |
380 | entry.error = None | |
381 | ||
382 | # [greeter] default-user-image | |
383 | def on_entry_changed_greeter_default_user_image(self, entry): | |
384 | value = entry.value | |
385 | if value.startswith('#'): | |
386 | entry.error = None | |
387 | else: | |
388 | entry.error = helpers.check_path_accessibility(value) | |
389 | ||
390 | # [greeter] background | |
391 | def on_entry_changed_greeter_background(self, entry): | |
392 | value = entry.value | |
393 | if not value or Gdk.RGBA().parse(value): | |
394 | entry.error = None | |
395 | else: | |
396 | entry.error = helpers.check_path_accessibility(value) | |
397 | ||
398 | # [greeter] keyboard | |
399 | def on_entry_changed_greeter_keyboard(self, entry): | |
400 | error = None | |
401 | if entry.enabled: | |
402 | value = entry.value | |
403 | if os.path.isabs(value): | |
404 | argv = shlex.split(value) | |
405 | error = helpers.check_path_accessibility(argv[0], executable=True) | |
406 | elif not value: | |
407 | error = _('Do not leave this field empty') | |
408 | entry.error = error | |
409 | ||
410 | # [greeter] reader | |
411 | on_entry_changed_greeter_reader = on_entry_changed_greeter_keyboard | |
237 | 412 | |
238 | 413 | def on_destroy(self, *unused): |
239 | 414 | Gtk.main_quit() |
14 | 14 | # You should have received a copy of the GNU General Public License along |
15 | 15 | # with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | 16 | |
17 | from collections import namedtuple | |
18 | from gi.repository import Gtk, GObject | |
19 | from lightdm_gtk_greeter_settings.helpers import ModelRowEnum | |
20 | from lightdm_gtk_greeter_settings.helpers import get_data_path | |
21 | from lightdm_gtk_greeter_settings.helpers import NC_, C_ | |
17 | ||
18 | from gi.repository import ( | |
19 | GObject, | |
20 | Gtk) | |
21 | ||
22 | from lightdm_gtk_greeter_settings.helpers import ( | |
23 | get_data_path, | |
24 | NC_, | |
25 | SimpleEnum, | |
26 | WidgetsEnum) | |
22 | 27 | |
23 | 28 | |
24 | 29 | __all__ = ['IconChooserDialog'] |
25 | 30 | |
26 | CONTEXT_ROW = ModelRowEnum('NAME', 'STANDARD', 'TITLE') | |
27 | ICON_ROW = ModelRowEnum('NAME', 'STANDARD', 'CONTEXT') | |
31 | ||
32 | class ContextRow(SimpleEnum): | |
33 | Name = () | |
34 | Standard = () | |
35 | Title = () | |
36 | ||
37 | ||
38 | class IconRow(SimpleEnum): | |
39 | Name = () | |
40 | Standard = () | |
41 | Context = () | |
28 | 42 | |
29 | 43 | |
30 | 44 | class IconChooserDialog(Gtk.Dialog): |
31 | 45 | |
32 | 46 | __gtype_name__ = 'IconChooserDialog' |
33 | ||
34 | IconsFilterArgs = namedtuple('IconsFilterArgs', ('standard', 'context')) | |
35 | ||
36 | BUILDER_WIDGETS = ('name', 'preview', 'standard_toggle', 'spinner', | |
37 | 'contexts_view', 'contexts_selection', 'contexts_model', | |
38 | 'contexts_filter', 'icons_view', 'icons_selection', | |
39 | 'icons_model', 'icons_sorted', 'icons_filter') | |
40 | 47 | |
41 | 48 | def __new__(cls): |
42 | 49 | builder = Gtk.Builder() |
43 | 50 | builder.add_from_file(get_data_path('%s.ui' % cls.__name__)) |
44 | 51 | window = builder.get_object('icon_chooser_dialog') |
45 | window._builder = builder | |
46 | window.__dict__.update(('_' + w, builder.get_object(w)) | |
47 | for w in cls.BUILDER_WIDGETS) | |
48 | ||
52 | window.builder = builder | |
49 | 53 | builder.connect_signals(window) |
50 | window._init_window() | |
54 | window.init_window() | |
51 | 55 | return window |
52 | 56 | |
53 | def _init_window(self): | |
57 | class Widgets(WidgetsEnum): | |
58 | name = 'name_entry' | |
59 | preview = 'preview_image' | |
60 | standard = 'standard_toggle' | |
61 | ok = 'ok_button' | |
62 | cancel = 'cancel_button' | |
63 | contexts_view = 'contexts_view' | |
64 | contexts_selection = 'contexts_selection' | |
65 | contexts_model = 'contexts_model' | |
66 | contexts_filter = 'contexts_filter' | |
67 | icons_view = 'icons_view' | |
68 | icons_selection = 'icons_selection' | |
69 | icons_model = 'icons_model' | |
70 | icons_sorted = 'icons_sorted' | |
71 | icons_filter = 'icons_filter' | |
72 | ||
73 | builder = None | |
74 | ||
75 | def init_window(self): | |
76 | self._widgets = self.Widgets(builder=self.builder) | |
77 | self._widgets_to_disable = (self._widgets.name, self._widgets.standard, | |
78 | self._widgets.contexts_view, self._widgets.icons_view, | |
79 | self._widgets.ok, self._widgets.cancel) | |
54 | 80 | |
55 | 81 | self._icons_loaded = False |
56 | 82 | self._icon_to_select = None |
57 | self._icons_filter_args = None | |
58 | ||
59 | self._contexts_view.set_row_separator_func( | |
60 | self._contexts_row_separator_callback, None) | |
61 | self._contexts_filter.set_visible_func( | |
62 | self._contexts_filter_visible_callback) | |
63 | ||
64 | self._icons_filter.set_visible_func( | |
65 | self._icons_filter_visible_callback) | |
66 | self._icons_sorted.set_sort_column_id(0, Gtk.SortType.ASCENDING) | |
83 | self._icon_filter_standard = True | |
84 | self._icon_filter_context = None | |
85 | ||
86 | self._widgets.contexts_view.set_row_separator_func(self._contexts_separator_callback, None) | |
87 | self._widgets.contexts_filter.set_visible_func(self._contexts_visible_callback) | |
88 | ||
89 | self._widgets.icons_filter.set_visible_func(self._icons_filter_visible_callback) | |
90 | self._widgets.icons_sorted.set_sort_column_id(0, Gtk.SortType.ASCENDING) | |
67 | 91 | |
68 | 92 | self._reload() |
93 | ||
94 | def _reload(self): | |
95 | for w in self._widgets_to_disable: | |
96 | w.props.sensitive = False | |
97 | GObject.idle_add(self._read_icons) | |
69 | 98 | |
70 | 99 | def _read_icons(self): |
71 | 100 | theme = Gtk.IconTheme.get_default() |
72 | standard_contexts = set(name for name, title in STANDARD_CONTEXTS) | |
73 | ||
74 | self._contexts_model.clear() | |
75 | for name, title in STANDARD_CONTEXTS: | |
76 | row = CONTEXT_ROW(NAME=name, STANDARD=True, | |
77 | TITLE=title and C_('icon-dialog', title)) | |
78 | self._contexts_model.append(row) | |
101 | standard_contexts = set(name for name, title in StandardContexts) | |
102 | ||
103 | self._widgets.contexts_model.clear() | |
104 | for name, title in StandardContexts: | |
105 | row = ContextRow._make(Name=name, Standard=True, Title=title) | |
106 | self._widgets.contexts_model.append(row) | |
79 | 107 | |
80 | 108 | for name in theme.list_contexts(): |
81 | 109 | if name not in standard_contexts: |
82 | row = CONTEXT_ROW(NAME=name, STANDARD=False, TITLE=name) | |
83 | self._contexts_model.append(row) | |
84 | ||
85 | self._icons_model.clear() | |
110 | row = ContextRow._make(Name=name, Standard=False, Title=name) | |
111 | self._widgets.contexts_model.append(row) | |
112 | ||
113 | self._widgets.icons_model.clear() | |
86 | 114 | for context in theme.list_contexts(): |
87 | 115 | for icon in theme.list_icons(context): |
88 | row = ICON_ROW(NAME=icon, CONTEXT=context, | |
89 | STANDARD=icon in STANDARD_ICON_NAMES) | |
90 | self._icons_model.append(row) | |
116 | row = IconRow._make(Name=icon, Standard=icon in StandardIconNames, Context=context) | |
117 | self._widgets.icons_model.append(row) | |
91 | 118 | |
92 | 119 | self._icons_loaded = True |
93 | 120 | if self._icon_to_select: |
94 | 121 | self.select_icon(self._icon_to_select) |
95 | 122 | self._icon_to_select = None |
123 | ||
124 | for w in self._widgets_to_disable: | |
125 | w.props.sensitive = True | |
126 | ||
96 | 127 | return False |
97 | 128 | |
98 | def _reload(self): | |
99 | GObject.idle_add(self._read_icons) | |
100 | ||
101 | 129 | def _update_contexts_filter(self): |
102 | selected_iter = self._contexts_selection.get_selected()[1] | |
103 | selected_path = self._contexts_filter.get_path( | |
104 | selected_iter) if selected_iter else None | |
105 | self._contexts_filter.refilter() | |
106 | if selected_path and \ | |
107 | self._contexts_selection.path_is_selected(selected_path): | |
108 | self._update_icons_filter() | |
130 | self._widgets.contexts_filter.refilter() | |
131 | self._update_icons_filter() | |
109 | 132 | |
110 | 133 | def _update_icons_filter(self): |
111 | model, rowiter = self._contexts_selection.get_selected() | |
134 | self._widgets.icons_view.props.model = None | |
135 | model, rowiter = self._widgets.contexts_selection.get_selected() | |
112 | 136 | if rowiter: |
113 | self._icons_filter_args = self.IconsFilterArgs( | |
114 | self._standard_toggle.props.active, | |
115 | model[rowiter][CONTEXT_ROW.NAME]) | |
116 | else: | |
117 | self._icons_filter_args = None | |
118 | self._icons_view.props.model = None | |
119 | self._icons_filter.refilter() | |
120 | self._icons_view.props.model = self._icons_sorted | |
121 | ||
122 | def _contexts_filter_visible_callback(self, model, rowiter, data): | |
123 | if not self._standard_toggle.props.active: | |
137 | self._icon_filter_standard = self._widgets.standard.props.active | |
138 | self._icon_filter_context = model[rowiter][ContextRow.Name] | |
139 | self._widgets.icons_filter.refilter() | |
140 | self._widgets.icons_view.props.model = self._widgets.icons_sorted | |
141 | ||
142 | def _contexts_visible_callback(self, model, rowiter, data): | |
143 | if not self._widgets.standard.props.active: | |
124 | 144 | return True |
125 | return model[rowiter][CONTEXT_ROW.STANDARD] | |
126 | ||
127 | def _contexts_row_separator_callback(self, model, rowiter, data): | |
128 | return not model[rowiter][CONTEXT_ROW.NAME] and \ | |
129 | not model[rowiter][CONTEXT_ROW.TITLE] | |
145 | return model[rowiter][ContextRow.Standard] | |
146 | ||
147 | def _contexts_separator_callback(self, model, rowiter, data): | |
148 | return not model[rowiter][ContextRow.Name] and not model[rowiter][ContextRow.Title] | |
130 | 149 | |
131 | 150 | def _icons_filter_visible_callback(self, model, rowiter, data): |
132 | if not self._icons_filter_args: | |
151 | if self._icon_filter_standard and not model[rowiter][IconRow.Standard]: | |
133 | 152 | return False |
134 | if self._icons_filter_args.standard and \ | |
135 | not model[rowiter][ICON_ROW.STANDARD]: | |
136 | return False | |
137 | if not self._icons_filter_args.context: | |
153 | if not self._icon_filter_context: | |
138 | 154 | return True |
139 | return model[rowiter][ICON_ROW.CONTEXT] == \ | |
140 | self._icons_filter_args.context | |
141 | ||
142 | def run(self): | |
143 | return super().run() | |
144 | ||
145 | def get_iconname(self): | |
146 | return self._name.props.text | |
155 | return model[rowiter][IconRow.Context] == self._icon_filter_context | |
156 | ||
157 | def get_selected_icon(self): | |
158 | return self._widgets.name.props.text | |
147 | 159 | |
148 | 160 | def select_icon(self, name): |
149 | 161 | if not self._icons_loaded: |
150 | 162 | self._icon_to_select = name |
151 | 163 | return |
152 | 164 | |
153 | if not self._icons_filter_args or \ | |
154 | self._icons_filter_args.context is not None: | |
155 | if name not in STANDARD_ICON_NAMES: | |
156 | self._standard_toggle.props.active = False | |
157 | self._contexts_selection.select_path(0) | |
158 | for row in self._icons_sorted: | |
159 | if row[ICON_ROW.NAME] == name: | |
160 | self._icons_view.set_cursor(row.path) | |
161 | self._icons_selection.select_path(row.path) | |
165 | if name not in StandardIconNames: | |
166 | self._widgets.standard.props.active = False | |
167 | self._widgets.contexts_selection.select_path(0) | |
168 | ||
169 | for row in self._widgets.icons_sorted: | |
170 | if row[IconRow.Name] == name: | |
171 | self._widgets.icons_view.set_cursor(row.path) | |
172 | self._widgets.icons_selection.select_path(row.path) | |
162 | 173 | break |
163 | 174 | else: |
164 | self._name.props.text = name | |
175 | self._widgets.name.props.text = name | |
165 | 176 | |
166 | 177 | def on_icons_selection_changed(self, selection): |
167 | model, rowiter = self._icons_selection.get_selected() | |
178 | model, rowiter = selection.get_selected() | |
168 | 179 | if rowiter: |
169 | name = model[rowiter][ICON_ROW.NAME] | |
170 | self._name.props.text = name | |
180 | self._widgets.name.props.text = model[rowiter][IconRow.Name] | |
171 | 181 | |
172 | 182 | def on_contexts_selection_changed(self, selection): |
173 | self._icons_selection.unselect_all() | |
183 | self._widgets.icons_selection.unselect_all() | |
174 | 184 | self._update_icons_filter() |
175 | 185 | |
176 | 186 | def on_standard_toggled(self, toggle): |
180 | 190 | name = entry.props.text |
181 | 191 | if not Gtk.IconTheme.get_default().has_icon(name): |
182 | 192 | name = '' |
183 | self._preview.props.icon_name = name | |
184 | ||
185 | ||
186 | #http://standards.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html | |
187 | ||
188 | STANDARD_CONTEXTS =\ | |
189 | ( | |
190 | (None, NC_('icon-dialog', 'All contexts')), | |
191 | (None, ''), # separator | |
192 | ('Actions', NC_('icon-dialog', 'Actions')), | |
193 | ('Applications', NC_('icon-dialog', 'Applications')), | |
194 | ('Categories', NC_('icon-dialog', 'Categories')), | |
195 | ('Devices', NC_('icon-dialog', 'Devices')), | |
196 | ('Emblems', NC_('icon-dialog', 'Emblems')), | |
197 | ('Emotes', NC_('icon-dialog', 'Emoticons')), | |
198 | ('International', NC_('icon-dialog', 'International')), | |
199 | ('MimeTypes', NC_('icon-dialog', 'MIME Types')), | |
200 | ('Places', NC_('icon-dialog', 'Places')), | |
201 | ('Status', NC_('icon-dialog', 'Status')) | |
202 | ) | |
203 | ||
204 | STANDARD_ICON_NAMES = \ | |
205 | { | |
206 | # Actions | |
207 | 'address-book-new', 'application-exit', 'appointment-new', | |
208 | 'call-start', 'call-stop', 'contact-new', 'document-new', | |
209 | 'document-open', 'document-open-recent', 'document-page-setup', | |
210 | 'document-print', 'document-print-preview', 'document-properties', | |
211 | 'document-revert', 'document-save', 'document-save-as', | |
212 | 'document-send', 'edit-clear', 'edit-copy', 'edit-cut', 'edit-delete', | |
213 | 'edit-find', 'edit-find-replace', 'edit-paste', 'edit-redo', | |
214 | 'edit-select-all', 'edit-undo', 'folder-new', 'format-indent-less', | |
215 | 'format-indent-more', 'format-justify-center', 'format-justify-fill', | |
216 | 'format-justify-left', 'format-justify-right', | |
217 | 'format-text-direction-ltr', 'format-text-direction-rtl', | |
218 | 'format-text-bold', 'format-text-italic', 'format-text-underline', | |
219 | 'format-text-strikethrough', 'go-bottom', 'go-down', 'go-first', | |
220 | 'go-home', 'go-jump', 'go-last', 'go-next', 'go-previous', 'go-top', | |
221 | 'go-up', 'help-about', 'help-contents', 'help-faq', 'insert-image', | |
222 | 'insert-link', 'insert-object', 'insert-text', 'list-add', | |
223 | 'list-remove', 'mail-forward', 'mail-mark-important', 'mail-mark-junk', | |
224 | 'mail-mark-notjunk', 'mail-mark-read', 'mail-mark-unread', | |
225 | 'mail-message-new', 'mail-reply-all', 'mail-reply-sender', 'mail-send', | |
226 | 'mail-send-receive', 'media-eject', 'media-playback-pause', | |
227 | 'media-playback-start', 'media-playback-stop', 'media-record', | |
228 | 'media-seek-backward', 'media-seek-forward', 'media-skip-backward', | |
229 | 'media-skip-forward', 'object-flip-horizontal', 'object-flip-vertical', | |
230 | 'object-rotate-left', 'object-rotate-right', 'process-stop', | |
231 | 'system-lock-screen', 'system-log-out', 'system-run', 'system-search', | |
232 | 'system-reboot', 'system-shutdown', 'tools-check-spelling', | |
233 | 'view-fullscreen', 'view-refresh', 'view-restore', | |
234 | 'view-sort-ascending', 'view-sort-descending', 'window-close', | |
235 | 'window-new', 'zoom-fit-best', 'zoom-in', 'zoom-original', 'zoom-out', | |
236 | # StandardApplicationIcons | |
237 | 'accessories-calculator', 'accessories-character-map', | |
238 | 'accessories-dictionary', 'accessories-text-editor', 'help-browser', | |
239 | 'multimedia-volume-control', 'preferences-desktop-accessibility', | |
240 | 'preferences-desktop-font', 'preferences-desktop-keyboard', | |
241 | 'preferences-desktop-locale', 'preferences-desktop-multimedia', | |
242 | 'preferences-desktop-screensaver', 'preferences-desktop-theme', | |
243 | 'preferences-desktop-wallpaper', 'system-file-manager', | |
244 | 'system-software-install', 'system-software-update', | |
245 | 'utilities-system-monitor', 'utilities-terminal', | |
246 | # StandardCategoryIcons | |
247 | 'applications-accessories', 'applications-development', | |
248 | 'applications-engineering', 'applications-games', | |
249 | 'applications-graphics', 'applications-internet', | |
250 | 'applications-multimedia', 'applications-office', 'applications-other', | |
251 | 'applications-science', 'applications-system', | |
252 | 'applications-utilities', 'preferences-desktop', | |
253 | 'preferences-desktop-peripherals', 'preferences-desktop-personal', | |
254 | 'preferences-other', 'preferences-system', | |
255 | 'preferences-system-network', 'system-help', | |
256 | # StandardDeviceIcons | |
257 | 'audio-card', 'audio-input-microphone', 'battery', 'camera-photo', | |
258 | 'camera-video', 'camera-web', 'computer', 'drive-harddisk', | |
259 | 'drive-optical', 'drive-removable-media', 'input-gaming', | |
260 | 'input-keyboard', 'input-mouse', 'input-tablet', 'media-flash', | |
261 | 'media-floppy', 'media-optical', 'media-tape', 'modem', | |
262 | 'multimedia-player', 'network-wired', 'network-wireless', 'pda', | |
263 | 'phone', 'printer', 'scanner', 'video-display', | |
264 | # StandardEmblemIcons | |
265 | 'emblem-default', 'emblem-documents', 'emblem-downloads', | |
266 | 'emblem-favorite', 'emblem-important', 'emblem-mail', 'emblem-photos', | |
267 | 'emblem-readonly', 'emblem-shared', 'emblem-symbolic-link', | |
268 | 'emblem-synchronized', 'emblem-system', 'emblem-unreadable', | |
269 | # StandardEmotionIcons | |
270 | 'face-angel', 'face-angry', 'face-cool', 'face-crying', | |
271 | 'face-devilish', 'face-embarrassed', 'face-kiss', 'face-laugh', | |
272 | 'face-monkey', 'face-plain', 'face-raspberry', 'face-sad', 'face-sick', | |
273 | 'face-smile', 'face-smile-big', 'face-smirk', 'face-surprise', | |
274 | 'face-tired', 'face-uncertain', 'face-wink', 'face-worried', | |
275 | # StandardInternationalIcons | |
276 | 'flag-aa', | |
277 | # StandardMIMETypeIcons | |
278 | 'application-x-executable', 'audio-x-generic', 'font-x-generic', | |
279 | 'image-x-generic', 'package-x-generic', 'text-html', 'text-x-generic', | |
280 | 'text-x-generic-template', 'text-x-script', 'video-x-generic', | |
281 | 'x-office-address-book', 'x-office-calendar', 'x-office-document', | |
282 | 'x-office-presentation', 'x-office-spreadsheet', | |
283 | # StandardPlaceIcons | |
284 | 'folder', 'folder-remote', 'network-server', 'network-workgroup', | |
285 | 'start-here', 'user-bookmarks', 'user-desktop', 'user-home', | |
286 | 'user-trash', | |
287 | # StandardStatusIcons | |
288 | 'appointment-missed', 'appointment-soon', 'audio-volume-high', | |
289 | 'audio-volume-low', 'audio-volume-medium', 'audio-volume-muted', | |
290 | 'battery-caution', 'battery-low', 'dialog-error', 'dialog-information', | |
291 | 'dialog-password', 'dialog-question', 'dialog-warning', | |
292 | 'folder-drag-accept', 'folder-open', 'folder-visiting', | |
293 | 'image-loading', 'image-missing', 'mail-attachment', 'mail-unread', | |
294 | 'mail-read', 'mail-replied', 'mail-signed', 'mail-signed-verified', | |
295 | 'media-playlist-repeat', 'media-playlist-shuffle', 'network-error', | |
296 | 'network-idle', 'network-offline', 'network-receive', | |
297 | 'network-transmit', 'network-transmit-receive', 'printer-error', | |
298 | 'printer-printing', 'security-high', 'security-medium', 'security-low', | |
299 | 'software-update-available', 'software-update-urgent', 'sync-error', | |
300 | 'sync-synchronizing', 'task-due', 'task-past-due', 'user-available', | |
301 | 'user-away', 'user-idle', 'user-offline', 'user-trash-full', | |
302 | 'weather-clear', 'weather-clear-night', 'weather-few-clouds', | |
303 | 'weather-few-clouds-night', 'weather-fog', 'weather-overcast', | |
304 | 'weather-severe-alert', 'weather-showers', 'weather-showers-scattered', | |
305 | 'weather-snow', 'weather-storm' | |
306 | } | |
193 | self._widgets.preview.props.icon_name = name | |
194 | ||
195 | ||
196 | # http://standards.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html | |
197 | ||
198 | StandardContexts = ( | |
199 | (None, NC_('icon-dialog', 'All contexts')), | |
200 | (None, ''), # separator | |
201 | ('Actions', NC_('icon-dialog', 'Actions')), | |
202 | ('Applications', NC_('icon-dialog', 'Applications')), | |
203 | ('Categories', NC_('icon-dialog', 'Categories')), | |
204 | ('Devices', NC_('icon-dialog', 'Devices')), | |
205 | ('Emblems', NC_('icon-dialog', 'Emblems')), | |
206 | ('Emotes', NC_('icon-dialog', 'Emoticons')), | |
207 | ('International', NC_('icon-dialog', 'International')), | |
208 | ('MimeTypes', NC_('icon-dialog', 'MIME Types')), | |
209 | ('Places', NC_('icon-dialog', 'Places')), | |
210 | ('Status', NC_('icon-dialog', 'Status'))) | |
211 | ||
212 | StandardIconNames = { | |
213 | # Actions | |
214 | 'address-book-new', 'application-exit', 'appointment-new', | |
215 | 'call-start', 'call-stop', 'contact-new', 'document-new', | |
216 | 'document-open', 'document-open-recent', 'document-page-setup', | |
217 | 'document-print', 'document-print-preview', 'document-properties', | |
218 | 'document-revert', 'document-save', 'document-save-as', | |
219 | 'document-send', 'edit-clear', 'edit-copy', 'edit-cut', 'edit-delete', | |
220 | 'edit-find', 'edit-find-replace', 'edit-paste', 'edit-redo', | |
221 | 'edit-select-all', 'edit-undo', 'folder-new', 'format-indent-less', | |
222 | 'format-indent-more', 'format-justify-center', 'format-justify-fill', | |
223 | 'format-justify-left', 'format-justify-right', | |
224 | 'format-text-direction-ltr', 'format-text-direction-rtl', | |
225 | 'format-text-bold', 'format-text-italic', 'format-text-underline', | |
226 | 'format-text-strikethrough', 'go-bottom', 'go-down', 'go-first', | |
227 | 'go-home', 'go-jump', 'go-last', 'go-next', 'go-previous', 'go-top', | |
228 | 'go-up', 'help-about', 'help-contents', 'help-faq', 'insert-image', | |
229 | 'insert-link', 'insert-object', 'insert-text', 'list-add', | |
230 | 'list-remove', 'mail-forward', 'mail-mark-important', 'mail-mark-junk', | |
231 | 'mail-mark-notjunk', 'mail-mark-read', 'mail-mark-unread', | |
232 | 'mail-message-new', 'mail-reply-all', 'mail-reply-sender', 'mail-send', | |
233 | 'mail-send-receive', 'media-eject', 'media-playback-pause', | |
234 | 'media-playback-start', 'media-playback-stop', 'media-record', | |
235 | 'media-seek-backward', 'media-seek-forward', 'media-skip-backward', | |
236 | 'media-skip-forward', 'object-flip-horizontal', 'object-flip-vertical', | |
237 | 'object-rotate-left', 'object-rotate-right', 'process-stop', | |
238 | 'system-lock-screen', 'system-log-out', 'system-run', 'system-search', | |
239 | 'system-reboot', 'system-shutdown', 'tools-check-spelling', | |
240 | 'view-fullscreen', 'view-refresh', 'view-restore', | |
241 | 'view-sort-ascending', 'view-sort-descending', 'window-close', | |
242 | 'window-new', 'zoom-fit-best', 'zoom-in', 'zoom-original', 'zoom-out', | |
243 | # StandardApplicationIcons | |
244 | 'accessories-calculator', 'accessories-character-map', | |
245 | 'accessories-dictionary', 'accessories-text-editor', 'help-browser', | |
246 | 'multimedia-volume-control', 'preferences-desktop-accessibility', | |
247 | 'preferences-desktop-font', 'preferences-desktop-keyboard', | |
248 | 'preferences-desktop-locale', 'preferences-desktop-multimedia', | |
249 | 'preferences-desktop-screensaver', 'preferences-desktop-theme', | |
250 | 'preferences-desktop-wallpaper', 'system-file-manager', | |
251 | 'system-software-install', 'system-software-update', | |
252 | 'utilities-system-monitor', 'utilities-terminal', | |
253 | # StandardCategoryIcons | |
254 | 'applications-accessories', 'applications-development', | |
255 | 'applications-engineering', 'applications-games', | |
256 | 'applications-graphics', 'applications-internet', | |
257 | 'applications-multimedia', 'applications-office', 'applications-other', | |
258 | 'applications-science', 'applications-system', | |
259 | 'applications-utilities', 'preferences-desktop', | |
260 | 'preferences-desktop-peripherals', 'preferences-desktop-personal', | |
261 | 'preferences-other', 'preferences-system', | |
262 | 'preferences-system-network', 'system-help', | |
263 | # StandardDeviceIcons | |
264 | 'audio-card', 'audio-input-microphone', 'battery', 'camera-photo', | |
265 | 'camera-video', 'camera-web', 'computer', 'drive-harddisk', | |
266 | 'drive-optical', 'drive-removable-media', 'input-gaming', | |
267 | 'input-keyboard', 'input-mouse', 'input-tablet', 'media-flash', | |
268 | 'media-floppy', 'media-optical', 'media-tape', 'modem', | |
269 | 'multimedia-player', 'network-wired', 'network-wireless', 'pda', | |
270 | 'phone', 'printer', 'scanner', 'video-display', | |
271 | # StandardEmblemIcons | |
272 | 'emblem-default', 'emblem-documents', 'emblem-downloads', | |
273 | 'emblem-favorite', 'emblem-important', 'emblem-mail', 'emblem-photos', | |
274 | 'emblem-readonly', 'emblem-shared', 'emblem-symbolic-link', | |
275 | 'emblem-synchronized', 'emblem-system', 'emblem-unreadable', | |
276 | # StandardEmotionIcons | |
277 | 'face-angel', 'face-angry', 'face-cool', 'face-crying', | |
278 | 'face-devilish', 'face-embarrassed', 'face-kiss', 'face-laugh', | |
279 | 'face-monkey', 'face-plain', 'face-raspberry', 'face-sad', 'face-sick', | |
280 | 'face-smile', 'face-smile-big', 'face-smirk', 'face-surprise', | |
281 | 'face-tired', 'face-uncertain', 'face-wink', 'face-worried', | |
282 | # StandardInternationalIcons | |
283 | 'flag-aa', | |
284 | # StandardMIMETypeIcons | |
285 | 'application-x-executable', 'audio-x-generic', 'font-x-generic', | |
286 | 'image-x-generic', 'package-x-generic', 'text-html', 'text-x-generic', | |
287 | 'text-x-generic-template', 'text-x-script', 'video-x-generic', | |
288 | 'x-office-address-book', 'x-office-calendar', 'x-office-document', | |
289 | 'x-office-presentation', 'x-office-spreadsheet', | |
290 | # StandardPlaceIcons | |
291 | 'folder', 'folder-remote', 'network-server', 'network-workgroup', | |
292 | 'start-here', 'user-bookmarks', 'user-desktop', 'user-home', | |
293 | 'user-trash', | |
294 | # StandardStatusIcons | |
295 | 'appointment-missed', 'appointment-soon', 'audio-volume-high', | |
296 | 'audio-volume-low', 'audio-volume-medium', 'audio-volume-muted', | |
297 | 'battery-caution', 'battery-low', 'dialog-error', 'dialog-information', | |
298 | 'dialog-password', 'dialog-question', 'dialog-warning', | |
299 | 'folder-drag-accept', 'folder-open', 'folder-visiting', | |
300 | 'image-loading', 'image-missing', 'mail-attachment', 'mail-unread', | |
301 | 'mail-read', 'mail-replied', 'mail-signed', 'mail-signed-verified', | |
302 | 'media-playlist-repeat', 'media-playlist-shuffle', 'network-error', | |
303 | 'network-idle', 'network-offline', 'network-receive', | |
304 | 'network-transmit', 'network-transmit-receive', 'printer-error', | |
305 | 'printer-printing', 'security-high', 'security-medium', 'security-low', | |
306 | 'software-update-available', 'software-update-urgent', 'sync-error', | |
307 | 'sync-synchronizing', 'task-due', 'task-past-due', 'user-available', | |
308 | 'user-away', 'user-idle', 'user-offline', 'user-trash-full', | |
309 | 'weather-clear', 'weather-clear-night', 'weather-few-clouds', | |
310 | 'weather-few-clouds-night', 'weather-fog', 'weather-overcast', | |
311 | 'weather-severe-alert', 'weather-showers', 'weather-showers-scattered', | |
312 | 'weather-snow', 'weather-storm'} |
0 | # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- | |
1 | # LightDM GTK Greeter Settings | |
2 | # Copyright (C) 2015 Andrew P. <pan.pav.7c5@gmail.com> | |
3 | # | |
4 | # This program is free software: you can redistribute it and/or modify it | |
5 | # under the terms of the GNU General Public License version 3, as published | |
6 | # by the Free Software Foundation. | |
7 | # | |
8 | # This program is distributed in the hope that it will be useful, but | |
9 | # WITHOUT ANY WARRANTY; without even the implied warranties of | |
10 | # MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR | |
11 | # PURPOSE. See the GNU General Public License for more details. | |
12 | # | |
13 | # You should have received a copy of the GNU General Public License along | |
14 | # with this program. If not, see <http://www.gnu.org/licenses/>. | |
15 | ||
16 | ||
17 | import os | |
18 | ||
19 | from gi.repository import Gtk | |
20 | ||
21 | from lightdm_gtk_greeter_settings.IconChooserDialog import IconChooserDialog | |
22 | from lightdm_gtk_greeter_settings.OptionEntry import BaseEntry | |
23 | from lightdm_gtk_greeter_settings.helpers import ( | |
24 | C_, | |
25 | get_data_path, | |
26 | set_image_from_path, | |
27 | SimpleEnum) | |
28 | ||
29 | ||
30 | __all__ = ['IconEntry'] | |
31 | ||
32 | ||
33 | class IconEntry(BaseEntry): | |
34 | ||
35 | class Item(SimpleEnum): | |
36 | priority = 0 | |
37 | # (value, just_label) => (label, tooltip) | |
38 | update = None | |
39 | # (old_value) => str or None | |
40 | ask = None | |
41 | # Associated menu item | |
42 | menuitem = None | |
43 | ||
44 | def __init__(self, widgets): | |
45 | super().__init__(widgets) | |
46 | self._value = None | |
47 | self._image = widgets['image'] | |
48 | self._button = widgets['button'] | |
49 | self._button.props.popup = Gtk.Menu() | |
50 | self._widgets_to_disable.append(self._button) | |
51 | self._icon_dialog = None | |
52 | self._path_dialog = None | |
53 | self._current_item = None | |
54 | ||
55 | self._items = [] | |
56 | for priority, (update, ask) in self._get_items(): | |
57 | item = self.Item(priority=priority, update=update, ask=ask) | |
58 | item.menuitem = Gtk.MenuItem() | |
59 | item.menuitem.props.visible = True | |
60 | item.menuitem.props.label = item.update(None, True)[0] | |
61 | item.menuitem.connect('activate', self._on_item_clicked, item) | |
62 | self._button.props.popup.append(item.menuitem) | |
63 | self._items.append(item) | |
64 | ||
65 | self._items.sort(key=lambda i: i.priority) | |
66 | ||
67 | def _get_value(self): | |
68 | return self._value | |
69 | ||
70 | def _set_value(self, value): | |
71 | applied_item = None | |
72 | tooltip = None | |
73 | for item in self._items: | |
74 | if applied_item: | |
75 | label, __ = item.update(None, True) | |
76 | else: | |
77 | label, tooltip = item.update(value, False) | |
78 | if tooltip: | |
79 | applied_item = item | |
80 | item.menuitem.get_child().set_markup(label) | |
81 | ||
82 | if not applied_item: | |
83 | tooltip = C_('option-entry|icon', 'Unrecognized value: {value}').format(value=value) | |
84 | self._button.set_tooltip_markup(tooltip) | |
85 | ||
86 | self._value = value | |
87 | self._current_item = applied_item | |
88 | ||
89 | self._emit_changed() | |
90 | ||
91 | def _get_items(self): | |
92 | return ((0, (self._update_icon, self._ask_icon)), | |
93 | (100, (self._update_image, self._ask_image))) | |
94 | ||
95 | def _on_item_clicked(self, menuitem, item): | |
96 | value = item.ask(self._value if item == self._current_item else None) | |
97 | if value is not None: | |
98 | self._set_value(value) | |
99 | ||
100 | def _update_icon(self, value, just_label=False): | |
101 | if just_label or value is None or not value.startswith('#'): | |
102 | return C_('option-entry|icon', 'Select icon name...'), None | |
103 | name = value[1:] | |
104 | label = C_('option-entry|icon', '<b>Icon: {icon}</b>').format(icon=name) | |
105 | tooltip = label | |
106 | self._image.set_from_icon_name(name, Gtk.IconSize.DIALOG) | |
107 | return label, tooltip | |
108 | ||
109 | def _ask_icon(self, oldvalue): | |
110 | if not self._icon_dialog: | |
111 | self._icon_dialog = IconChooserDialog() | |
112 | self._icon_dialog.props.transient_for = self._image.get_toplevel() | |
113 | if oldvalue: | |
114 | self._icon_dialog.select_icon(oldvalue[1:]) | |
115 | ||
116 | value = None | |
117 | if self._icon_dialog.run() == Gtk.ResponseType.OK: | |
118 | value = '#' + self._icon_dialog.get_selected_icon() | |
119 | self._icon_dialog.hide() | |
120 | return value | |
121 | ||
122 | def _update_image(self, value, just_label=False): | |
123 | if just_label or value is None: | |
124 | return C_('option-entry|icon', 'Select file...'), None | |
125 | ||
126 | if set_image_from_path(self._image, value): | |
127 | label = C_('option-entry|icon', '<b>File: {path}</b>') | |
128 | else: | |
129 | label = C_('option-entry|icon', '<b>File: {path}</b> (failed to load)') | |
130 | ||
131 | return (label.format(path=os.path.basename(value)), | |
132 | label.format(path=value)) | |
133 | ||
134 | def _ask_image(self, oldvalue): | |
135 | if not self._path_dialog: | |
136 | builder = Gtk.Builder() | |
137 | builder.add_from_file(get_data_path('ImageChooserDialog.ui')) | |
138 | ||
139 | self._path_dialog = builder.get_object('dialog') | |
140 | self._path_dialog.props.transient_for = self._image.get_toplevel() | |
141 | self._path_dialog.connect('update-preview', self._on_update_path_preview) | |
142 | ||
143 | preview_size = self._image.props.pixel_size | |
144 | preview = self._path_dialog.props.preview_widget | |
145 | preview.props.pixel_size = preview_size | |
146 | preview.set_size_request(preview_size, preview_size) | |
147 | ||
148 | if oldvalue is not None: | |
149 | self._path_dialog.select_filename(self._value) | |
150 | ||
151 | value = None | |
152 | if self._path_dialog.run() == Gtk.ResponseType.OK: | |
153 | value = self._path_dialog.get_filename() | |
154 | self._path_dialog.hide() | |
155 | return value | |
156 | ||
157 | def _on_update_path_preview(self, chooser): | |
158 | set_image_from_path(chooser.props.preview_widget, chooser.get_filename()) |
0 | #!/usr/bin/env python3 | |
1 | # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- | |
2 | # LightDM GTK Greeter Settings | |
3 | # Copyright (C) 2014 Andrew P. <pan.pav.7c5@gmail.com> | |
4 | # | |
5 | # This program is free software: you can redistribute it and/or modify it | |
6 | # under the terms of the GNU General Public License version 3, as published | |
7 | # by the Free Software Foundation. | |
8 | # | |
9 | # This program is distributed in the hope that it will be useful, but | |
10 | # WITHOUT ANY WARRANTY; without even the implied warranties of | |
11 | # MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR | |
12 | # PURPOSE. See the GNU General Public License for more details. | |
13 | # | |
14 | # You should have received a copy of the GNU General Public License along | |
15 | # with this program. If not, see <http://www.gnu.org/licenses/>. | |
16 | ||
17 | from glob import iglob | |
18 | import os | |
19 | import sys | |
20 | ||
21 | from gi.repository import Gtk | |
22 | from lightdm_gtk_greeter_settings import helpers | |
23 | ||
24 | ||
25 | __all__ = ['IndicatorChooserDialog'] | |
26 | ||
27 | ||
28 | class IndicatorChooserDialog(Gtk.Dialog): | |
29 | ||
30 | __gtype_name__ = 'IndicatorChooserDialog' | |
31 | ||
32 | BUILDER_WIDGETS = ('short_choice', 'short_value', 'short_model', | |
33 | 'path_choice', 'path_value', | |
34 | 'spacer_choice', 'separator_choice', | |
35 | 'add_button', 'ok_button', 'infobar', 'message') | |
36 | ||
37 | def __new__(cls, check_callback=None, add_callback=None): | |
38 | builder = Gtk.Builder() | |
39 | builder.add_from_file(helpers.get_data_path('%s.ui' % cls.__name__)) | |
40 | window = builder.get_object('indicator_chooser_dialog') | |
41 | window._builder = builder | |
42 | window.__dict__.update(('_' + w, builder.get_object(w)) | |
43 | for w in cls.BUILDER_WIDGETS) | |
44 | ||
45 | builder.connect_signals(window) | |
46 | window._init_window(check_callback, add_callback) | |
47 | return window | |
48 | ||
49 | def _init_window(self, check_callback, add_callback): | |
50 | self._check_callback = check_callback | |
51 | self._add_callback = add_callback | |
52 | self._add_button.props.visible = add_callback is not None | |
53 | ||
54 | for path in sorted(iglob(os.path.join(sys.prefix, 'share', 'unity', | |
55 | 'indicators', '*'))): | |
56 | name = os.path.basename(path) | |
57 | parts = name.rsplit('.', maxsplit=1) | |
58 | if len(parts) == 2 and parts[0] == 'com.canonical.indicator': | |
59 | name = parts[1] | |
60 | self._short_model.append((name,)) | |
61 | ||
62 | for path in sorted(iglob(os.path.join(sys.prefix, 'lib', 'indicators3', | |
63 | '7', '*.so'))): | |
64 | self._short_model.append((os.path.basename(path),)) | |
65 | ||
66 | def _get_current_value(self): | |
67 | if self._short_choice.props.active: | |
68 | return self._short_value.props.text | |
69 | elif self._path_choice.props.active: | |
70 | return self._path_value.get_filename() | |
71 | elif self._spacer_choice.props.active: | |
72 | return '~spacer'; | |
73 | else: | |
74 | return '~separator'; | |
75 | ||
76 | def _update_state(self, force_state=None): | |
77 | message = None | |
78 | if force_state is None: | |
79 | valid = False | |
80 | if self._check_callback is not None: | |
81 | check = self._check_callback(self._get_current_value()) | |
82 | if isinstance(check, str): | |
83 | message = check | |
84 | else: | |
85 | valid = bool(check) | |
86 | else: | |
87 | valid = True | |
88 | else: | |
89 | valid = force_state | |
90 | ||
91 | self._infobar.props.visible = message is not None | |
92 | if message is not None: | |
93 | self._message.props.label = message | |
94 | ||
95 | self._ok_button.props.sensitive = valid | |
96 | self._add_button.props.sensitive = valid | |
97 | ||
98 | def on_short_value_changed(self, widget): | |
99 | if not self._short_choice.props.active: | |
100 | self._short_choice.props.active = True | |
101 | else: | |
102 | self._update_state() | |
103 | ||
104 | def on_path_value_changed(self, widget): | |
105 | self._path_choice.props.active = True | |
106 | self._update_state() | |
107 | ||
108 | def on_short_choice_toggled(self, widget): | |
109 | self._update_state() | |
110 | ||
111 | def on_add_clicked(self, widget): | |
112 | value = self._get_current_value() | |
113 | if value: | |
114 | self._add_callback(value) | |
115 | self._update_state(False) | |
116 | ||
117 | def on_short_value_activate(self, entry): | |
118 | if self._short_choice.props.active and self._ok_button.props.sensitive: | |
119 | self._ok_button.clicked() | |
120 | ||
121 | def get_indicator(self): | |
122 | self._short_choice.props.active = True | |
123 | self._update_state() | |
124 | self._short_value.grab_focus() | |
125 | response = self.run() | |
126 | self.hide() | |
127 | if response == Gtk.ResponseType.OK: | |
128 | return self._get_current_value() | |
129 | return None |
0 | #!/usr/bin/env python3 | |
1 | # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- | |
2 | # LightDM GTK Greeter Settings | |
3 | # Copyright (C) 2014 Andrew P. <pan.pav.7c5@gmail.com> | |
4 | # | |
5 | # This program is free software: you can redistribute it and/or modify it | |
6 | # under the terms of the GNU General Public License version 3, as published | |
7 | # by the Free Software Foundation. | |
8 | # | |
9 | # This program is distributed in the hope that it will be useful, but | |
10 | # WITHOUT ANY WARRANTY; without even the implied warranties of | |
11 | # MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR | |
12 | # PURPOSE. See the GNU General Public License for more details. | |
13 | # | |
14 | # You should have received a copy of the GNU General Public License along | |
15 | # with this program. If not, see <http://www.gnu.org/licenses/>. | |
16 | ||
17 | ||
18 | import os | |
19 | import sys | |
20 | from copy import deepcopy | |
21 | from glob import iglob | |
22 | ||
23 | from gi.repository import Gtk | |
24 | ||
25 | from lightdm_gtk_greeter_settings import ( | |
26 | IconEntry, | |
27 | OptionEntry) | |
28 | from lightdm_gtk_greeter_settings.helpers import ( | |
29 | C_, | |
30 | bool2string, | |
31 | string2bool, | |
32 | get_data_path, | |
33 | get_greeter_version, | |
34 | SimpleEnum, | |
35 | WidgetsEnum, | |
36 | WidgetsWrapper) | |
37 | from lightdm_gtk_greeter_settings.IndicatorsEntry import ( | |
38 | EmptyIndicators, | |
39 | Indicators, | |
40 | LayoutSet, | |
41 | Option) | |
42 | ||
43 | ||
44 | __all__ = ['IndicatorPropertiesDialog'] | |
45 | ||
46 | ||
47 | class IndicatorPath(OptionEntry.StringPathEntry): | |
48 | ||
49 | class Row(SimpleEnum): | |
50 | Title = () | |
51 | Type = () | |
52 | Icon = () | |
53 | ||
54 | ||
55 | class IndicatorIconEntry(IconEntry.IconEntry): | |
56 | ||
57 | DefaultValue = () | |
58 | ||
59 | def __init__(self, widgets): | |
60 | self._label = widgets['label'] | |
61 | super().__init__(widgets) | |
62 | ||
63 | def _set_value(self, value): | |
64 | super()._set_value(self.DefaultValue if value is None else value) | |
65 | self._label.set_markup(self._current_item.menuitem.get_label()) | |
66 | self._image.props.visible = value not in (None, self.DefaultValue) | |
67 | ||
68 | def _get_value(self): | |
69 | return super()._get_value() or None | |
70 | ||
71 | def _get_items(self): | |
72 | for item in super()._get_items(): | |
73 | yield item | |
74 | yield -1, (self._update_default, self._ask_default) | |
75 | ||
76 | def _update_default(self, value, just_label): | |
77 | if just_label or value is not self.DefaultValue: | |
78 | return C_('option-entry|indicators', 'Use default value...'), None | |
79 | self._image.props.icon_name = '' | |
80 | label = C_('option-entry|indicators', '<b>Using default value</b>') | |
81 | return label, label | |
82 | ||
83 | def _ask_default(self, oldvalue): | |
84 | return self.DefaultValue | |
85 | ||
86 | ||
87 | class IndicatorTypeEntry(OptionEntry.BaseEntry): | |
88 | ||
89 | def __init__(self, widgets): | |
90 | super().__init__(widgets) | |
91 | ||
92 | self._types = widgets['types'] | |
93 | self._indicator_choice = widgets['indicator_choice'] | |
94 | self._spacer_choice = widgets['spacer_choice'] | |
95 | self._separator_choice = widgets['separator_choice'] | |
96 | ||
97 | self._types.connect('changed', self._emit_changed) | |
98 | self._indicator_choice.connect('toggled', self._on_choice_changed, None, | |
99 | (self._types, widgets['indicator_box'])) | |
100 | self._spacer_choice.connect('toggled', self._on_choice_changed, Indicators.Spacer) | |
101 | self._separator_choice.connect('toggled', self._on_choice_changed, Indicators.Separator) | |
102 | ||
103 | self._value = None | |
104 | ||
105 | def add_type(self, name, title): | |
106 | if name not in EmptyIndicators: | |
107 | self._types.append(name, title or name) | |
108 | ||
109 | def _get_value(self): | |
110 | if self._indicator_choice.props.active: | |
111 | return self._types.props.active_id | |
112 | else: | |
113 | return self._value | |
114 | ||
115 | def _set_value(self, value): | |
116 | if value == Indicators.Spacer: | |
117 | button = self._spacer_choice | |
118 | elif value == Indicators.Separator: | |
119 | button = self._separator_choice | |
120 | else: | |
121 | button = self._indicator_choice | |
122 | ||
123 | self._value = value | |
124 | self._types.set_active_id(value) | |
125 | ||
126 | if button.props.active: | |
127 | button.toggled() | |
128 | else: | |
129 | button.props.active = True | |
130 | ||
131 | def _on_choice_changed(self, button, value, widgets=[]): | |
132 | for w in widgets: | |
133 | w.props.sensitive = button.props.active | |
134 | ||
135 | if button.props.active: | |
136 | self._value = value if value else self._types.props.active_id | |
137 | self._emit_changed() | |
138 | ||
139 | ||
140 | class IndicatorPropertiesDialog(Gtk.Dialog): | |
141 | __gtype_name__ = 'IndicatorPropertiesDialog' | |
142 | ||
143 | class Widgets(WidgetsEnum): | |
144 | add = 'add_button' | |
145 | ok = 'ok_button' | |
146 | infobar = 'infobar' | |
147 | message = 'message' | |
148 | common_options = 'common_options_box' | |
149 | custom_options = 'custom_options_box' | |
150 | path = 'option_path_combo' | |
151 | path_model = 'option_path_model' | |
152 | hide_disabled = 'option_power_hide_disabled' | |
153 | ||
154 | def __new__(cls, *args, **kwargs): | |
155 | builder = Gtk.Builder() | |
156 | builder.add_from_file(get_data_path('%s.ui' % cls.__name__)) | |
157 | window = builder.get_object('indicator_properties_dialog') | |
158 | window.builder = builder | |
159 | builder.connect_signals(window) | |
160 | window.init_window(*args, **kwargs) | |
161 | return window | |
162 | ||
163 | def init_window(self, is_duplicate=None, get_defaults=None, get_name=str): | |
164 | self._widgets = self.Widgets(builder=self.builder) | |
165 | self._get_defaults = get_defaults | |
166 | self._add_indicator = None | |
167 | self._is_duplicate = is_duplicate | |
168 | self._get_name = get_name | |
169 | self._indicator_loaded = False | |
170 | self._name = None | |
171 | self._reversed = False | |
172 | ||
173 | self._name2page = {} | |
174 | for i in range(0, self._widgets.custom_options.get_n_pages()): | |
175 | page = self._widgets.custom_options.get_nth_page(i) | |
176 | name = Gtk.Buildable.get_name(page) | |
177 | self._name2page['~' + name.rsplit('_')[-1]] = i | |
178 | ||
179 | if get_greeter_version() < 0x020100: | |
180 | self._widgets.common_options.props.visible = False | |
181 | ||
182 | self._name2page = { | |
183 | Indicators.External: self._name2page[Indicators.External], | |
184 | Indicators.Text: self._name2page[Indicators.Text]} | |
185 | text_prefix = 'option_text_fallback' | |
186 | else: | |
187 | self._name2page[Indicators.Text] = -1 | |
188 | text_prefix = 'option_text' | |
189 | ||
190 | self._option_type = IndicatorTypeEntry(WidgetsWrapper(self.builder, 'option_type')) | |
191 | self._option_text = OptionEntry.StringEntry(WidgetsWrapper(self.builder, text_prefix)) | |
192 | self._option_image = IndicatorIconEntry(WidgetsWrapper(self.builder, 'option_image')) | |
193 | self._option_path = IndicatorPath(WidgetsWrapper(self.builder, 'option_path')) | |
194 | self._option_hide_disabled = \ | |
195 | OptionEntry.BooleanEntry(WidgetsWrapper(self.builder, 'option_hide_disabled')) | |
196 | ||
197 | for entry in (self._option_type, self._option_path): | |
198 | entry.changed.connect(self._on_option_changed) | |
199 | ||
200 | for name in Indicators: | |
201 | self._option_type.add_type(name, self._get_name(name)) | |
202 | ||
203 | # Hiding first column created by Gtk.ComboBoxText | |
204 | self._widgets.path.get_cells()[0].props.visible = False | |
205 | ||
206 | for path in sorted(iglob(os.path.join(sys.prefix, 'share', 'unity', 'indicators', '*'))): | |
207 | name = os.path.basename(path) | |
208 | parts = name.rsplit('.', maxsplit=1) | |
209 | if len(parts) == 2 and parts[0] == 'com.canonical.indicator': | |
210 | name = parts[1] | |
211 | row = IndicatorPath.Row._make(Type=IndicatorPath.ItemType.Value, | |
212 | Title=name, | |
213 | Icon='application-x-executable') | |
214 | self._widgets.path_model.append(row) | |
215 | ||
216 | for path in sorted(iglob(os.path.join(sys.prefix, 'lib', 'indicators3', '7', '*.so'))): | |
217 | row = IndicatorPath.Row._make(Type=IndicatorPath.ItemType.Value, | |
218 | Title=os.path.basename(path), | |
219 | Icon='application-x-executable') | |
220 | self._widgets.path_model.append(row) | |
221 | ||
222 | def _on_option_changed(self, entry=None): | |
223 | if not self._indicator_loaded: | |
224 | return | |
225 | ||
226 | name = self._option_type.value | |
227 | error = None | |
228 | warning = None | |
229 | ||
230 | if name == Indicators.External: | |
231 | if not str(self._option_path.value).strip(): | |
232 | error = C_('option-entry|indicators', 'Path/Service field is not filled') | |
233 | elif name != self._name: | |
234 | if self._is_duplicate and self._is_duplicate(name): | |
235 | warning = C_('option-entry|indicators', | |
236 | 'Indicator "{name}" is already in the list.\n' | |
237 | 'It will be overwritten.').format(name=self._get_name(name, name)) | |
238 | ||
239 | self._widgets.ok.props.sensitive = error is None | |
240 | self._widgets.add.props.sensitive = error is None | |
241 | self._widgets.infobar.props.visible = error or warning | |
242 | self._widgets.message.props.label = error or warning | |
243 | ||
244 | if error: | |
245 | self._widgets.infobar.props.message_type = Gtk.MessageType.WARNING | |
246 | elif warning: | |
247 | self._widgets.infobar.props.message_type = Gtk.MessageType.INFO | |
248 | else: | |
249 | self._widgets.infobar.props.message_type = Gtk.MessageType.OTHER | |
250 | ||
251 | def on_option_type_types_changed(self, combo): | |
252 | current = self._widgets.custom_options.props.page | |
253 | if current != -1: | |
254 | self._widgets.custom_options.get_nth_page(current).props.visible = False | |
255 | current = self._name2page.get(combo.props.active_id, -1) | |
256 | if current != -1: | |
257 | self._widgets.custom_options.get_nth_page(current).props.visible = True | |
258 | self._widgets.custom_options.props.page = current | |
259 | if self._indicator_loaded: | |
260 | defaults = self._get_defaults(combo.props.active_id) | |
261 | self._option_text.enabled = Option.Text in defaults | |
262 | self._option_image.enabled = Option.Image in defaults | |
263 | ||
264 | def on_add_clicked(self, widget): | |
265 | self._add_callback(self.get_indicator()) | |
266 | self._options = deepcopy(self._options) | |
267 | self._on_option_changed() | |
268 | ||
269 | @property | |
270 | def add_callback(self): | |
271 | return self._add_callback | |
272 | ||
273 | @add_callback.setter | |
274 | def add_callback(self, value): | |
275 | self._add_callback = value | |
276 | self._widgets.add.props.visible = value is not None | |
277 | ||
278 | def set_indicator(self, options): | |
279 | self._indicator_loaded = False | |
280 | self._options = deepcopy(options) | |
281 | self._name = options[Option.Name] | |
282 | ||
283 | self._option_type.value = options[Option.Name] | |
284 | self._option_path.value = options.get(Option.Path) | |
285 | ||
286 | self._option_text.value = options.get(Option.Text, '') | |
287 | self._option_text.enabled = Option.Text in options | |
288 | ||
289 | self._option_image.value = options.get(Option.Image) | |
290 | self._option_image.enabled = Option.Image in options | |
291 | ||
292 | self._reversed = Option.Layout in options and LayoutSet.Reversed in options[Option.Layout] | |
293 | ||
294 | hide_disabled = options.get(Option.HideDisabled, bool2string(False)) | |
295 | self._option_hide_disabled.value = hide_disabled or bool2string(True) | |
296 | ||
297 | self._indicator_loaded = True | |
298 | self._on_option_changed() | |
299 | ||
300 | def get_indicator(self): | |
301 | options = self._options | |
302 | ||
303 | name = self._option_type.value | |
304 | options[Option.Name] = name | |
305 | ||
306 | options[Option.Layout] = set() | |
307 | if name not in EmptyIndicators: | |
308 | if self._option_text.enabled: | |
309 | options[Option.Text] = self._option_text.value or None | |
310 | options[Option.Layout].add(LayoutSet.Text) | |
311 | if self._option_image.enabled: | |
312 | options[Option.Image] = self._option_image.value or None | |
313 | options[Option.Layout].add(LayoutSet.Image) | |
314 | if self._option_text.enabled and self._option_image.enabled and self._reversed: | |
315 | options[Option.Layout].add(LayoutSet.Reversed) | |
316 | ||
317 | if LayoutSet.Text not in options[Option.Layout] and Option.Text in options: | |
318 | del options[Option.Text] | |
319 | if LayoutSet.Image not in options[Option.Layout] and Option.Image in options: | |
320 | del options[Option.Image] | |
321 | ||
322 | if name == Indicators.External: | |
323 | options[Option.Path] = self._option_path.value | |
324 | else: | |
325 | options.pop(Option.Path, None) | |
326 | ||
327 | if name == Indicators.Power and string2bool(self._option_hide_disabled.value): | |
328 | options[Option.HideDisabled] = None | |
329 | elif Option.HideDisabled in options: | |
330 | options.pop(Option.HideDisabled, None) | |
331 | ||
332 | return options |
0 | # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- | |
1 | # LightDM GTK Greeter Settings | |
2 | # Copyright (C) 2014 Andrew P. <pan.pav.7c5@gmail.com> | |
3 | # | |
4 | # This program is free software: you can redistribute it and/or modify it | |
5 | # under the terms of the GNU General Public License version 3, as published | |
6 | # by the Free Software Foundation. | |
7 | # | |
8 | # This program is distributed in the hope that it will be useful, but | |
9 | # WITHOUT ANY WARRANTY; without even the implied warranties of | |
10 | # MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR | |
11 | # PURPOSE. See the GNU General Public License for more details. | |
12 | # | |
13 | # You should have received a copy of the GNU General Public License along | |
14 | # with this program. If not, see <http://www.gnu.org/licenses/>. | |
15 | ||
16 | ||
17 | import operator | |
18 | import platform | |
19 | import string | |
20 | from copy import deepcopy | |
21 | ||
22 | from gi.repository import ( | |
23 | Gtk, | |
24 | Gdk) | |
25 | from gi.repository.GObject import markup_escape_text as escape_markup | |
26 | ||
27 | from lightdm_gtk_greeter_settings.helpers import ( | |
28 | C_, | |
29 | get_greeter_version, | |
30 | get_markup_error, | |
31 | SimpleEnum, | |
32 | TreeStoreDataWrapper) | |
33 | from lightdm_gtk_greeter_settings.OptionEntry import BaseEntry | |
34 | ||
35 | ||
36 | __all__ = ['BuiltInIndicators', | |
37 | 'EmptyIndicators', | |
38 | 'Indicators', | |
39 | 'IndicatorsEntry', | |
40 | 'Option', | |
41 | 'SingleIndicators'] | |
42 | ||
43 | ||
44 | class Indicators(SimpleEnum): | |
45 | External = '~external' | |
46 | Spacer = '~spacer' | |
47 | Separator = '~separator' | |
48 | Text = '~text' | |
49 | Host = '~host' | |
50 | Clock = '~clock' | |
51 | Layout = '~layout' | |
52 | Session = '~session' | |
53 | Language = '~language' | |
54 | A11y = '~a11y' | |
55 | Power = '~power' | |
56 | ||
57 | ||
58 | # Valid builtin indicators | |
59 | BuiltInIndicators = set(Indicators) - {Indicators.External} | |
60 | ||
61 | # Special indicators | |
62 | EmptyIndicators = {Indicators.Spacer, Indicators.Separator} | |
63 | ||
64 | # These indicators can have only one instance | |
65 | SingleIndicators = set(Indicators) - {Indicators.External, Indicators.Text, | |
66 | Indicators.Spacer, Indicators.Separator} | |
67 | ||
68 | # Valid options names | |
69 | ||
70 | ||
71 | class Option(SimpleEnum): | |
72 | # Common | |
73 | Name = 'name' | |
74 | Layout = 'layout' | |
75 | Text = 'text' | |
76 | Image = 'image' | |
77 | FallbackImage = 'fallback-image' | |
78 | Tooltip = 'tooltip' | |
79 | Markup = 'markup' | |
80 | Expand = 'expand' | |
81 | Align = 'align' | |
82 | # External | |
83 | Path = 'path' | |
84 | # Power | |
85 | HideDisabled = 'hide-disabled' | |
86 | ||
87 | ||
88 | class Layout(SimpleEnum): | |
89 | Empty = '' | |
90 | Text = 'text' | |
91 | Image = 'image' | |
92 | ImageText = 'image-text' | |
93 | TextImage = 'text-image' | |
94 | ||
95 | @classmethod | |
96 | def _to_set(cls, value): | |
97 | return LayoutSet._str2set.get(value, set()) | |
98 | ||
99 | ||
100 | class LayoutSet(SimpleEnum): | |
101 | Text = 'text' | |
102 | Image = 'image' | |
103 | Reversed = 'reversed' | |
104 | ||
105 | _str2set = { | |
106 | Layout.Empty: set(), | |
107 | Layout.Text: {Text}, | |
108 | Layout.Image: {Image}, | |
109 | Layout.ImageText: {Text, Image}, | |
110 | Layout.TextImage: {Text, Image, Reversed}} | |
111 | ||
112 | @classmethod | |
113 | def _to_string(cls, value): | |
114 | return next((k for k, v in cls._str2set.items() if v == value), '') | |
115 | ||
116 | ||
117 | class Row(SimpleEnum): | |
118 | Name = () | |
119 | Tooltip = () | |
120 | HasState = () | |
121 | State = () | |
122 | Options = () | |
123 | Icon = () | |
124 | Markup = () | |
125 | ||
126 | ||
127 | class IndicatorsEntry(BaseEntry): | |
128 | # Readable names for indicators | |
129 | Names = { | |
130 | Indicators.External: C_('option-entry|indicators|name', 'External library/service'), | |
131 | Indicators.Spacer: C_('option-entry|indicators|name', 'Spacer'), | |
132 | Indicators.Separator: C_('option-entry|indicators|name', 'Separator'), | |
133 | Indicators.Text: C_('option-entry|indicators|name', 'Text'), | |
134 | Indicators.Clock: C_('option-entry|indicators|name', 'Clock'), | |
135 | Indicators.Host: C_('option-entry|indicators|name', 'Host name'), | |
136 | Indicators.Layout: C_('option-entry|indicators|name', 'Keyboard layout'), | |
137 | Indicators.Session: C_('option-entry|indicators|name', 'Sessions menu'), | |
138 | Indicators.Language: C_('option-entry|indicators|name', 'Languages menu'), | |
139 | Indicators.A11y: C_('option-entry|indicators|name', 'Accessibility menu'), | |
140 | Indicators.Power: C_('option-entry|indicators|name', 'Power menu')} | |
141 | # Default icons for indicators to display in treeview | |
142 | Icons = { | |
143 | Indicators.A11y: 'preferences-desktop-accessibility', | |
144 | Indicators.Session: 'document-properties', | |
145 | Indicators.Power: 'system-shutdown'} | |
146 | Tooltips = { | |
147 | Indicators.Spacer: C_('option-entry|indicators|tooltip', 'Spacer'), | |
148 | Indicators.Separator: C_('option-entry|indicators|tooltip', 'Separator'), | |
149 | Indicators.Text: C_('option-entry|indicators|tooltip', 'Custom text or/and image'), | |
150 | Indicators.Host: C_('option-entry|indicators|tooltip', 'Host name'), | |
151 | Indicators.Clock: C_('option-entry|indicators|tooltip', 'Clock'), | |
152 | Indicators.Layout: C_('option-entry|indicators|tooltip', 'Layout indicator'), | |
153 | Indicators.Session: C_('option-entry|indicators|tooltip', | |
154 | 'Sessions menu (xfce, unity, gnome etc.)'), | |
155 | Indicators.Language: C_('option-entry|indicators|tooltip', 'Languages menu'), | |
156 | Indicators.A11y: C_('option-entry|indicators|tooltip', 'Accessibility menu'), | |
157 | Indicators.Power: C_('option-entry|indicators|tooltip', 'Power menu')} | |
158 | # Default options for indicators | |
159 | DefaultOptions = { | |
160 | Indicators.External: {Option.Text: None, Option.Image: None}, | |
161 | Indicators.Spacer: {Option.Layout: set()}, | |
162 | Indicators.Separator: {Option.Layout: set()}, | |
163 | Indicators.Text: {Option.Layout: {LayoutSet.Text}, Option.Text: None}, | |
164 | Indicators.Host: {Option.Layout: {LayoutSet.Text}, Option.Text: None}, | |
165 | Indicators.Clock: {Option.Layout: {LayoutSet.Text}, Option.Text: None}, | |
166 | Indicators.Layout: {Option.Layout: {LayoutSet.Text}, Option.Text: None}, | |
167 | Indicators.Session: {Option.Layout: {LayoutSet.Text, LayoutSet.Image}, | |
168 | Option.Text: None, Option.Image: None}, | |
169 | Indicators.Language: {Option.Layout: {LayoutSet.Text}, Option.Text: None}, | |
170 | Indicators.A11y: {Option.Layout: {LayoutSet.Image}, Option.Image: None}, | |
171 | Indicators.Power: {Option.Layout: {LayoutSet.Image}, Option.Image: None}} | |
172 | ||
173 | def __init__(self, widgets): | |
174 | super().__init__(widgets) | |
175 | ||
176 | if get_greeter_version() < 0x020100: | |
177 | self._get_value = self._get_value_19 | |
178 | self._on_button_release = self._on_button_release_19 | |
179 | ||
180 | for k, v in self.DefaultOptions.items(): | |
181 | v[Option.Name] = k | |
182 | ||
183 | self._treeview = widgets['treeview'] | |
184 | self._selection = widgets['selection'] | |
185 | self._state_renderer = widgets['state_renderer'] | |
186 | self._state_column = widgets['state_column'] | |
187 | self._add = widgets['add'] | |
188 | self._remove = widgets['remove'] | |
189 | self._up = widgets['up'] | |
190 | self._down = widgets['down'] | |
191 | self._tools = widgets['tools'] | |
192 | self._model = widgets['model'] | |
193 | self._widgets_to_disable = [self._treeview, widgets['toolbar']] | |
194 | self._properties_dialog = None | |
195 | self._row_menu = None | |
196 | self._tools_menu = None | |
197 | self._show_unused = False | |
198 | ||
199 | self._treeview.connect('key-press-event', self._on_key_press) | |
200 | self._treeview.connect('row-activated', self._on_row_activated) | |
201 | self._treeview.connect('button-release-event', self._on_button_release) | |
202 | self._selection.connect('changed', self._on_selection_changed) | |
203 | self._state_renderer.connect('toggled', self._on_state_toggled) | |
204 | ||
205 | self._add.connect('clicked', self._on_add_clicked) | |
206 | self._remove.connect('clicked', self._on_remove_clicked) | |
207 | self._up.connect('clicked', self._on_up_clicked) | |
208 | self._down.connect('clicked', self._on_down_clicked) | |
209 | self._tools.connect('clicked', self._on_tools_clicked) | |
210 | ||
211 | self._on_row_changed_id = self._model.connect('row-changed', self._on_model_changed) | |
212 | self._on_row_deleted_id = self._model.connect('row-deleted', self._on_model_changed) | |
213 | self._on_row_inserted_id = self._model.connect('row-inserted', self._on_model_changed) | |
214 | self._on_rows_reordered_id = self._model.connect('rows-reordered', self._on_model_changed) | |
215 | ||
216 | def _on_model_changed(self, *unused): | |
217 | self._emit_changed() | |
218 | ||
219 | def _get_value(self): | |
220 | def fix_token(s): | |
221 | s = s.replace('"', r'\"') | |
222 | if any(c in s for c in string.whitespace): | |
223 | s = '"' + s + '"' | |
224 | return s | |
225 | ||
226 | items = [] | |
227 | for row in self._model: | |
228 | if row[Row.HasState] and not row[Row.State]: | |
229 | continue | |
230 | ||
231 | options = deepcopy(row[Row.Options].data) | |
232 | name = options.pop(Option.Name) | |
233 | defaults = deepcopy(self.DefaultOptions[name]) | |
234 | ||
235 | # text, image, layout=image-text -> text, image | |
236 | if options.get(Option.Layout) == {LayoutSet.Text, LayoutSet.Image}: | |
237 | del options[Option.Layout] | |
238 | ||
239 | for k in defaults.keys() & options.keys(): | |
240 | if defaults[k] == options[k]: | |
241 | del options[k] | |
242 | ||
243 | if Option.Layout in options: | |
244 | layout = options[Option.Layout] | |
245 | options[Option.Layout] = LayoutSet._to_string(layout) | |
246 | # text, layout=text -> layout=text | |
247 | if LayoutSet.Text in layout and options.get(Option.Text, self) is None: | |
248 | del options[Option.Text] | |
249 | if LayoutSet.Image in layout and options.get(Option.Image, self) is None: | |
250 | del options[Option.Image] | |
251 | ||
252 | # name=~text, text=value -> ~~value | |
253 | if name == Indicators.Text: | |
254 | name = '~~' + (options.pop(Option.Text, None) or '') | |
255 | elif name == Indicators.External: | |
256 | name = options.pop(Option.Path, None) or '' | |
257 | ||
258 | if not options: | |
259 | items.append(fix_token(name)) | |
260 | else: | |
261 | values = (fix_token(k) + '=' + fix_token(v) if v else fix_token(k) | |
262 | for k, v in sorted(options.items(), key=operator.itemgetter(0))) | |
263 | items.append(fix_token(name) + ': ' + ', '.join(values)) | |
264 | return '; '.join(items) | |
265 | ||
266 | def _get_value_19(self): | |
267 | ||
268 | items = [] | |
269 | for row in self._model: | |
270 | if row[Row.HasState] and not row[Row.State]: | |
271 | continue | |
272 | ||
273 | options = deepcopy(row[Row.Options].data) | |
274 | name = options.pop(Option.Name) | |
275 | ||
276 | # name=~text, text=value -> ~~value | |
277 | if name == Indicators.Text: | |
278 | name = '~~' + (options.pop(Option.Text, None) or '') | |
279 | elif name == Indicators.External: | |
280 | name = options.pop(Option.Path, None) or '' | |
281 | ||
282 | items.append(name) | |
283 | return ';'.join(items) | |
284 | ||
285 | def _set_value(self, value): | |
286 | with self._model.handler_block(self._on_row_deleted_id): | |
287 | self._model.clear() | |
288 | ||
289 | for options in self._read_options_string(value): | |
290 | name = options[Option.Name] | |
291 | ||
292 | if name.startswith('~~'): | |
293 | options.setdefault(Option.Text, name[2:]) | |
294 | options[Option.Name] = Indicators.Text | |
295 | name = Indicators.Text | |
296 | elif name not in BuiltInIndicators: | |
297 | options.setdefault(Option.Path, name) | |
298 | options[Option.Name] = Indicators.External | |
299 | name = Indicators.External | |
300 | ||
301 | defaults = deepcopy(self.DefaultOptions[name]) | |
302 | ||
303 | if Option.Markup in options: | |
304 | markup = options[Option.Markup] | |
305 | if markup is not None: | |
306 | options[Option.Text] = markup | |
307 | options[Option.Markup] = None | |
308 | ||
309 | if Option.Layout in options: | |
310 | options[Option.Layout] = Layout._to_set(options[Option.Layout]) | |
311 | else: | |
312 | options[Option.Layout] = defaults.get(Option.Layout) or set() | |
313 | ||
314 | if Option.Text in options: | |
315 | options[Option.Layout].add(LayoutSet.Text) | |
316 | elif LayoutSet.Text in options[Option.Layout]: | |
317 | options.setdefault(Option.Text, None) | |
318 | else: | |
319 | defaults.pop(Option.Text, None) | |
320 | ||
321 | if Option.Image in options: | |
322 | options[Option.Layout].add(LayoutSet.Image) | |
323 | elif LayoutSet.Image in options[Option.Layout]: | |
324 | options.setdefault(Option.Image, None) | |
325 | else: | |
326 | defaults.pop(Option.Image, None) | |
327 | ||
328 | options.update((k, defaults[k]) | |
329 | for k in defaults.keys() - options.keys()) | |
330 | ||
331 | with self._model.handler_block(self._on_row_changed_id), \ | |
332 | self._model.handler_block(self._on_row_inserted_id): | |
333 | self._set_row(None, options, select=False) | |
334 | ||
335 | if self._show_unused: | |
336 | self._tools_show_unused_toggled() | |
337 | ||
338 | self._selection.select_path(0) | |
339 | self._on_model_changed() | |
340 | ||
341 | def _read_options_string(self, s): | |
342 | ||
343 | while s: | |
344 | name, s = self._next_string_token(s, ':;') | |
345 | if not name: | |
346 | continue | |
347 | options = {Option.Name: name} | |
348 | ||
349 | if s.startswith(':'): | |
350 | while s: | |
351 | option, s = self._next_string_token(s[1:], '=,;') | |
352 | if s.startswith('='): | |
353 | value, s = self._next_string_token(s[1:], ',;') | |
354 | else: | |
355 | value = None | |
356 | options[option] = value | |
357 | if not s.startswith(','): | |
358 | break | |
359 | ||
360 | yield options | |
361 | s = s[1:] | |
362 | ||
363 | def _next_string_token(self, s, delimiters): | |
364 | token = [] | |
365 | quoted = False | |
366 | ||
367 | for last, c in enumerate(s): | |
368 | if not c.isspace(): | |
369 | break | |
370 | ||
371 | # Parsing quotes | |
372 | for i, c in enumerate(s[last:], last): | |
373 | if c == '"': | |
374 | if i > last and s[i - 1] == '\\': | |
375 | token.append(s[last:i - 1]) | |
376 | token.append('"') | |
377 | else: | |
378 | token.append(s[last:i]) | |
379 | quoted = not quoted | |
380 | last = i + 1 | |
381 | elif not quoted and c in delimiters: | |
382 | break | |
383 | ||
384 | if quoted: | |
385 | return '', '' | |
386 | ||
387 | if last != i or last == 0: | |
388 | token.append(s[last: i if c in delimiters else i + 1].rstrip()) | |
389 | ||
390 | return ''.join(token) if token else None, s[i:] | |
391 | ||
392 | def _remove_selection(self): | |
393 | model, rowiter = self._selection.get_selected() | |
394 | if rowiter: | |
395 | if self._show_unused and model[rowiter][Row.HasState]: | |
396 | model[rowiter][Row.State] = False | |
397 | else: | |
398 | model.remove(rowiter) | |
399 | self._on_selection_changed() | |
400 | ||
401 | def _move_selection(self, move_up): | |
402 | model, rowiter = self._selection.get_selected() | |
403 | if rowiter: | |
404 | next_iter = model.iter_previous( | |
405 | rowiter) if move_up else model.iter_next(rowiter) | |
406 | if self._show_unused and \ | |
407 | (model[rowiter][Row.HasState] and not model[rowiter][Row.State] or | |
408 | model[next_iter][Row.HasState] and not model[next_iter][Row.State]): | |
409 | with self._model.handler_block(self._on_rows_reordered_id): | |
410 | model.swap(rowiter, next_iter) | |
411 | else: | |
412 | model.swap(rowiter, next_iter) | |
413 | self._on_selection_changed() | |
414 | ||
415 | def _create_row_tuple(self, options): | |
416 | name = options[Option.Name] | |
417 | error = None | |
418 | ||
419 | text = options.get(Option.Text) | |
420 | if Option.Text in options: | |
421 | if text is not None: | |
422 | if Option.Markup in options: | |
423 | error = get_markup_error(text) | |
424 | if error: | |
425 | text = '<i>{text}</i>'.format(text=escape_markup(text)) | |
426 | else: | |
427 | text = escape_markup(text) | |
428 | text = '"' + text + '"' | |
429 | elif name == Indicators.Host: | |
430 | text = escape_markup(platform.node()) | |
431 | ||
432 | display_name = self.Names.get(name, name) | |
433 | if name == Indicators.External: | |
434 | if options.get(Option.Path): | |
435 | title = '{name} ({value})'.format(name=escape_markup(display_name), | |
436 | value=escape_markup(options[Option.Path])) | |
437 | else: | |
438 | title = escape_markup(display_name) | |
439 | else: | |
440 | title = escape_markup(display_name) | |
441 | ||
442 | if text: | |
443 | markup = '{name}: {text}'.format(name=title, text=text) | |
444 | else: | |
445 | markup = title | |
446 | ||
447 | if Option.Image in options or get_greeter_version() < 0x020100: | |
448 | icon = options.get(Option.Image) | |
449 | if icon and icon.startswith('#'): | |
450 | icon = icon[1:] | |
451 | elif icon: | |
452 | icon = 'image-x-generic' | |
453 | else: | |
454 | if name in self.Icons: | |
455 | icon = self.Icons[name] | |
456 | elif name in BuiltInIndicators: | |
457 | icon = 'applications-system' | |
458 | else: | |
459 | icon = 'application-x-executable' | |
460 | else: | |
461 | icon = '' | |
462 | ||
463 | has_state = name in SingleIndicators | |
464 | ||
465 | return Row._make(Name=name, | |
466 | Tooltip=self.Tooltips.get(name), | |
467 | Icon=icon, | |
468 | Markup=markup, | |
469 | HasState=has_state, State=has_state, | |
470 | Options=TreeStoreDataWrapper(options)) | |
471 | ||
472 | def _set_row(self, rowiter, options, select=True): | |
473 | old_name = self._model[rowiter][Row.Name] if rowiter else None | |
474 | new_name = options.get( | |
475 | Option.Name, '') if options is not None else None | |
476 | old_is_single = old_name in SingleIndicators | |
477 | new_is_single = new_name in SingleIndicators | |
478 | ||
479 | if new_name == old_name: | |
480 | # The same row - just update | |
481 | pass | |
482 | elif old_is_single and new_is_single: | |
483 | old_row = next( | |
484 | (row for row in self._model if row[Row.Name] == new_name), None) | |
485 | if old_row: | |
486 | if self._show_unused: | |
487 | # Swap current row with new_row | |
488 | with self._model.handler_block(self._on_rows_reordered_id): | |
489 | self._model.move_before(old_row.iter, rowiter) | |
490 | with self._model.handler_block(self._on_row_changed_id): | |
491 | self._model[rowiter][Row.State] = False | |
492 | rowiter = old_row.iter | |
493 | else: | |
494 | # Replace current row with replace_row | |
495 | with self._model.handler_block(self._on_row_deleted_id): | |
496 | self._model.remove(old_row.iter) | |
497 | elif old_is_single: | |
498 | if self._show_unused: | |
499 | # Uncheck old row and use new instead of it | |
500 | with self._model.handler_block(self._on_row_changed_id): | |
501 | self._model[rowiter][Row.State] = False | |
502 | with self._model.handler_block(self._on_row_inserted_id): | |
503 | new_iter = self._model.insert_after(rowiter) | |
504 | rowiter = new_iter | |
505 | elif new_is_single: | |
506 | old_row = next( | |
507 | (row for row in self._model if row[Row.Name] == new_name), None) | |
508 | if old_row: | |
509 | with self._model.handler_block(self._on_row_deleted_id): | |
510 | self._model.remove(old_row.iter) | |
511 | ||
512 | if rowiter and options: | |
513 | with self._model.handler_block(self._on_row_changed_id): | |
514 | self._model[rowiter] = self._create_row_tuple(options) | |
515 | self._model.row_changed(self._model.get_path(rowiter), rowiter) | |
516 | elif options: | |
517 | rowiter = self._model.append(self._create_row_tuple(options)) | |
518 | ||
519 | if select and rowiter: | |
520 | self._selection.select_iter(rowiter) | |
521 | ||
522 | return rowiter | |
523 | ||
524 | def _edit_indicator(self, options, add_callback=None): | |
525 | if not self._properties_dialog: | |
526 | from lightdm_gtk_greeter_settings.IndicatorPropertiesDialog \ | |
527 | import IndicatorPropertiesDialog as Dialog | |
528 | self._properties_dialog = Dialog(is_duplicate=self._is_duplicate, | |
529 | get_defaults=self.DefaultOptions.get, | |
530 | get_name=self.Names.get) | |
531 | self._properties_dialog.props.transient_for = self._treeview.get_toplevel() | |
532 | ||
533 | self._properties_dialog.add_callback = add_callback | |
534 | self._properties_dialog.set_indicator(options) | |
535 | if self._properties_dialog.run() == Gtk.ResponseType.OK: | |
536 | options = self._properties_dialog.get_indicator() | |
537 | else: | |
538 | options = None | |
539 | self._properties_dialog.hide() | |
540 | return options | |
541 | ||
542 | def _is_duplicate(self, name): | |
543 | return name in SingleIndicators and any(row[Row.Name] == name | |
544 | for row in self._model if row[Row.State]) | |
545 | ||
546 | def _add_indicator(self, options): | |
547 | self._set_row(None, options) | |
548 | ||
549 | def _on_key_press(self, treeview, event): | |
550 | if Gdk.keyval_name(event.keyval) == 'Delete': | |
551 | self._remove_selection() | |
552 | elif Gdk.keyval_name(event.keyval) == 'F2': | |
553 | model, rowiter = self._selection.get_selected() | |
554 | treeview.row_activated(model.get_path(rowiter), None) | |
555 | else: | |
556 | return False | |
557 | return True | |
558 | ||
559 | def _on_row_activated(self, treeview, path, column): | |
560 | if column != self._state_column: | |
561 | options = self._edit_indicator(self._model[path][Row.Options].data) | |
562 | if options: | |
563 | self._set_row(self._model.get_iter(path), options) | |
564 | ||
565 | def _on_button_release(self, treeview, event): | |
566 | if event.button != 3: | |
567 | return False | |
568 | ||
569 | pos = treeview.get_path_at_pos(int(event.x), int(event.y)) | |
570 | if not pos: | |
571 | return False | |
572 | ||
573 | row = self._model[pos[0]] | |
574 | if row[Row.HasState] and not row[Row.State]: | |
575 | return False | |
576 | ||
577 | if not self._row_menu: | |
578 | self._row_menu = Gtk.Menu() | |
579 | self._row_menu_reset = Gtk.MenuItem(C_('option-entry|indicators', | |
580 | 'Reset to _defaults')) | |
581 | self._row_menu_text = Gtk.CheckMenuItem(C_('option-entry|indicators', | |
582 | 'Display _label')) | |
583 | self._row_menu_image = Gtk.CheckMenuItem(C_('option-entry|indicators', | |
584 | 'Display _image')) | |
585 | self._row_menu_remove = Gtk.MenuItem( | |
586 | C_('option-entry|indicators', '_Remove')) | |
587 | ||
588 | self._row_menu_text_id = self._row_menu_text.connect('toggled', | |
589 | self._on_row_menu_toggled, | |
590 | Option.Text) | |
591 | self._row_menu_image_id = self._row_menu_image.connect('toggled', | |
592 | self._on_row_menu_toggled, | |
593 | Option.Image) | |
594 | self._row_menu_reset.connect( | |
595 | 'activate', self._on_row_menu_reset_clicked) | |
596 | self._row_menu_remove.connect('activate', self._on_remove_clicked) | |
597 | ||
598 | self._row_menu.append(self._row_menu_reset) | |
599 | self._row_menu.append(self._row_menu_text) | |
600 | self._row_menu.append(self._row_menu_image) | |
601 | self._row_menu.append(Gtk.SeparatorMenuItem()) | |
602 | self._row_menu.append(self._row_menu_remove) | |
603 | ||
604 | for item in self._row_menu: | |
605 | if type(item) is not Gtk.SeparatorMenuItem: | |
606 | item.props.use_underline = True | |
607 | item.props.visible = True | |
608 | ||
609 | options = row[Row.Options].data | |
610 | ||
611 | with self._row_menu_text.handler_block(self._row_menu_text_id): | |
612 | self._row_menu_text.props.active = Option.Text in options | |
613 | with self._row_menu_image.handler_block(self._row_menu_image_id): | |
614 | self._row_menu_image.props.active = Option.Image in options | |
615 | ||
616 | editable = options[Option.Name] not in { | |
617 | Indicators.Spacer, Indicators.Separator} | |
618 | self._row_menu_reset.props.sensitive = editable | |
619 | self._row_menu_text.props.sensitive = editable | |
620 | self._row_menu_image.props.sensitive = editable | |
621 | ||
622 | self._row_menu.popup(None, None, None, None, 0, | |
623 | Gtk.get_current_event_time()) | |
624 | ||
625 | return True | |
626 | ||
627 | def _on_button_release_19(self, treeview, event): | |
628 | pass | |
629 | ||
630 | def _on_row_menu_reset_clicked(self, item): | |
631 | model, rowiter = self._selection.get_selected() | |
632 | if rowiter: | |
633 | name = model[rowiter][Row.Name] | |
634 | options = deepcopy(self.DefaultOptions[name]) | |
635 | options[Option.Name] = name | |
636 | with model.handler_block(self._on_row_changed_id): | |
637 | model[rowiter] = self._create_row_tuple(options) | |
638 | model.row_changed(model.get_path(rowiter), rowiter) | |
639 | ||
640 | def _on_row_menu_toggled(self, item, option): | |
641 | model, rowiter = self._selection.get_selected() | |
642 | options = model[rowiter][Row.Options].data | |
643 | if item.props.active: | |
644 | options.setdefault(option, None) | |
645 | else: | |
646 | options.pop(option, None) | |
647 | model[rowiter] = self._create_row_tuple(options) | |
648 | ||
649 | def _on_state_toggled(self, renderer, path): | |
650 | self._model[path][Row.State] = not self._model[path][Row.State] | |
651 | ||
652 | def _on_selection_changed(self, selection=None): | |
653 | model, rowiter = self._selection.get_selected() | |
654 | if rowiter: | |
655 | row = model[rowiter] | |
656 | self._remove.props.sensitive = not row[ | |
657 | Row.HasState] or row[Row.State] | |
658 | self._down.props.sensitive = model.iter_next(rowiter) | |
659 | self._up.props.sensitive = model.iter_previous(rowiter) | |
660 | self._treeview.scroll_to_cell(model.get_path(rowiter)) | |
661 | else: | |
662 | self._remove.props.sensitive = False | |
663 | self._down.props.sensitive = False | |
664 | self._up.props.sensitive = False | |
665 | ||
666 | def _on_add_clicked(self, button=None): | |
667 | options = self._edit_indicator(self.DefaultOptions[Indicators.External], | |
668 | add_callback=self._add_indicator) | |
669 | if options: | |
670 | self._set_row(None, options, select=True) | |
671 | ||
672 | def _on_remove_clicked(self, button=None): | |
673 | self._remove_selection() | |
674 | ||
675 | def _on_up_clicked(self, button=None): | |
676 | self._move_selection(move_up=True) | |
677 | ||
678 | def _on_down_clicked(self, button=None): | |
679 | self._move_selection(move_up=False) | |
680 | ||
681 | def _on_tools_clicked(self, button=None): | |
682 | if not self._tools_menu: | |
683 | self._tools_menu = Gtk.Menu() | |
684 | self._tools_menu.attach_to_widget(self._tools) | |
685 | ||
686 | unused_item = Gtk.CheckMenuItem(C_('option-entry|indicators', 'Show unused items')) | |
687 | unused_item.connect('toggled', self._tools_show_unused_toggled) | |
688 | self._tools_menu.append(unused_item) | |
689 | ||
690 | header_item = Gtk.MenuItem(C_('option-entry|indicators', 'Predefined templates:')) | |
691 | header_item.props.sensitive = False | |
692 | self._tools_menu.append(Gtk.SeparatorMenuItem()) | |
693 | self._tools_menu.append(header_item) | |
694 | ||
695 | templates = ( | |
696 | ('host ~ clock, language, session, power', | |
697 | '~host;~spacer;~language;~session;~power'), | |
698 | ('host ~ clock ~ language, session, a11y, power', | |
699 | '~host;~spacer;~clock;~spacer;~language;~session;~a11y;~power'), | |
700 | ('host, layout, clock ~ language, session, power', | |
701 | '~host;~layout;~clock;~spacer;~language;~session;~power')) | |
702 | ||
703 | for title, value in templates: | |
704 | item = Gtk.MenuItem(title) | |
705 | item.connect('activate', self._on_tools_template_clicked, value) | |
706 | self._tools_menu.append(item) | |
707 | ||
708 | self._tools_menu.show_all() | |
709 | self._tools_menu.popup(None, None, None, None, 0, | |
710 | Gtk.get_current_event_time()) | |
711 | ||
712 | def _on_tools_template_clicked(self, item, value): | |
713 | self._set_value(value) | |
714 | ||
715 | def _tools_show_unused_toggled(self, widget=None): | |
716 | if widget: | |
717 | self._show_unused = widget.props.active | |
718 | self._state_column.props.visible = self._show_unused | |
719 | ||
720 | used = {row[Row.Name]: row | |
721 | for row in self._model if row[Row.Name] in SingleIndicators} | |
722 | if self._show_unused: | |
723 | for name in SingleIndicators - used.keys(): | |
724 | options = deepcopy(self.DefaultOptions[name]) | |
725 | options[Option.Name] = name | |
726 | with self._model.handler_block(self._on_row_changed_id),\ | |
727 | self._model.handler_block(self._on_row_inserted_id): | |
728 | rowiter = self._set_row(None, options, select=False) | |
729 | self._model[rowiter][Row.State] = False | |
730 | else: | |
731 | for row in used.values(): | |
732 | if row[Row.HasState] and not row[Row.State]: | |
733 | with self._model.handler_block(self._on_row_deleted_id): | |
734 | self._model.remove(row.iter) |
0 | #!/usr/bin/env python3 | |
1 | # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- | |
2 | # LightDM GTK Greeter Settings | |
3 | # Copyright (C) 2014 Andrew P. <pan.pav.7c5@gmail.com> | |
4 | # | |
5 | # This program is free software: you can redistribute it and/or modify it | |
6 | # under the terms of the GNU General Public License version 3, as published | |
7 | # by the Free Software Foundation. | |
8 | # | |
9 | # This program is distributed in the hope that it will be useful, but | |
10 | # WITHOUT ANY WARRANTY; without even the implied warranties of | |
11 | # MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR | |
12 | # PURPOSE. See the GNU General Public License for more details. | |
13 | # | |
14 | # You should have received a copy of the GNU General Public License along | |
15 | # with this program. If not, see <http://www.gnu.org/licenses/>. | |
16 | ||
17 | ||
18 | from gi.repository import Gtk | |
19 | ||
20 | from lightdm_gtk_greeter_settings.helpers import WidgetsWrapper | |
21 | from lightdm_gtk_greeter_settings.MultiheadSetupDialog import MultiheadSetupDialog | |
22 | from lightdm_gtk_greeter_settings.OptionEntry import BaseEntry | |
23 | from lightdm_gtk_greeter_settings.OptionGroup import BaseGroup | |
24 | ||
25 | ||
26 | __all__ = ['MonitorsGroup'] | |
27 | ||
28 | ||
29 | class MonitorsGroup(BaseGroup): | |
30 | GROUP_PREFIX = 'monitor:' | |
31 | ||
32 | def __init__(self, widgets): | |
33 | super().__init__(widgets) | |
34 | self._entries = {} | |
35 | self._widgets = WidgetsWrapper(widgets, 'multihead') | |
36 | self._dialog = None | |
37 | self._widgets['label'].connect('activate-link', self._on_label_link_activate) | |
38 | ||
39 | def read(self, config): | |
40 | self._entries.clear() | |
41 | for name, section in config.items(): | |
42 | if not name.startswith(self.GROUP_PREFIX): | |
43 | continue | |
44 | name = name[len(self.GROUP_PREFIX):].strip() | |
45 | entry = MonitorEntry(self._widgets) | |
46 | entry['background'] = section.get('background', None) | |
47 | entry['user-background'] = section.getboolean('user-background', None) | |
48 | entry['laptop'] = section.getboolean('laptop', None) | |
49 | self._entries[name] = entry | |
50 | self.entry_added.emit(entry, name) | |
51 | ||
52 | def write(self, config): | |
53 | for name in config.sections(): | |
54 | if name.startswith(self.GROUP_PREFIX): | |
55 | config.remove_section(name) | |
56 | for name, entry in self._entries.items(): | |
57 | section = '{prefix} {name}'.format(prefix=self.GROUP_PREFIX, name=name) | |
58 | config.add_section(section) | |
59 | for key, value in entry: | |
60 | if value is not None: | |
61 | config.set(section, key, value) | |
62 | ||
63 | def _on_label_link_activate(self, label, uri): | |
64 | if not self._dialog: | |
65 | self._dialog = MultiheadSetupDialog() | |
66 | self._dialog.props.transient_for = self._widgets['label'].get_toplevel() | |
67 | ||
68 | self._dialog.set_model(self._entries) | |
69 | ||
70 | if self._dialog.run() == Gtk.ResponseType.OK: | |
71 | current_names = set(self._entries.keys()) | |
72 | for name, values in self._dialog.get_model().items(): | |
73 | if name in self._entries: | |
74 | self._entries[name].assign(values) | |
75 | current_names.discard(name) | |
76 | else: | |
77 | entry = MonitorEntry(self._widgets, values) | |
78 | self._entries[name] = entry | |
79 | self.entry_added.emit(entry, name) | |
80 | for name in current_names: | |
81 | self.entry_added.emit(self._entries.pop(name), name) | |
82 | self._dialog.hide() | |
83 | return True | |
84 | ||
85 | ||
86 | class MonitorEntry(BaseEntry): | |
87 | ||
88 | def __init__(self, widgets, values=None): | |
89 | super().__init__(widgets) | |
90 | self._values = values or {} | |
91 | ||
92 | def _get_value(self): | |
93 | return self._values.copy() | |
94 | ||
95 | def _set_value(self, value): | |
96 | self._values = value.copy() | |
97 | ||
98 | def __getitem__(self, key): | |
99 | return self._values[key] | |
100 | ||
101 | def __setitem__(self, key, value): | |
102 | self._values[key] = value | |
103 | ||
104 | def __iter__(self): | |
105 | return iter(self._values.items()) | |
106 | ||
107 | def assign(self, values): | |
108 | if not self._values == values: | |
109 | self._values.update(values) | |
110 | self._emit_changed() |
18 | 18 | from builtins import max |
19 | 19 | from locale import gettext as _ |
20 | 20 | |
21 | from gi.repository import Gtk, Gdk, GdkPixbuf | |
22 | from lightdm_gtk_greeter_settings import helpers | |
23 | from lightdm_gtk_greeter_settings.OptionEntry import BaseEntry | |
24 | from lightdm_gtk_greeter_settings.helpers import WidgetsWrapper, C_, ModelRowEnum | |
25 | ||
26 | from lightdm_gtk_greeter_settings.OptionGroup import BaseGroup | |
21 | from gi.repository import ( | |
22 | Gdk, | |
23 | GdkPixbuf, | |
24 | Gtk) | |
25 | ||
26 | from lightdm_gtk_greeter_settings.helpers import ( | |
27 | C_, | |
28 | check_path_accessibility, | |
29 | get_data_path, | |
30 | SimpleEnum, | |
31 | WidgetsEnum) | |
27 | 32 | |
28 | 33 | |
29 | 34 | __all__ = ['MultiheadSetupDialog'] |
30 | 35 | |
31 | 36 | |
32 | ROW = ModelRowEnum('NAME', 'BACKGROUND', | |
33 | 'USER_BG', 'USER_BG_DISABLED', | |
34 | 'LAPTOP', 'LAPTOP_DISABLED', | |
35 | 'BACKGROUND_PIXBUF', 'BACKGROUND_IS_COLOR') | |
36 | ||
37 | BG_ROW = ModelRowEnum('TEXT', 'TYPE') | |
37 | class Row(SimpleEnum): | |
38 | Name = () | |
39 | Background = () | |
40 | UserBg = () | |
41 | UserBgDisabled = () | |
42 | Laptop = () | |
43 | LaptopDisabled = () | |
44 | BackgroundPixbuf = () | |
45 | BackgroundIsColor = () | |
46 | ErrorVisible = () | |
47 | ErrorText = () | |
48 | ||
49 | ||
50 | class BackgroundRow(SimpleEnum): | |
51 | Text = () | |
52 | Type = () | |
38 | 53 | |
39 | 54 | |
40 | 55 | class MultiheadSetupDialog(Gtk.Dialog): |
41 | ||
42 | 56 | __gtype_name__ = 'MultiheadSetupDialog' |
43 | 57 | |
44 | 58 | def __new__(cls): |
45 | 59 | builder = Gtk.Builder() |
46 | builder.add_from_file(helpers.get_data_path('%s.ui' % cls.__name__)) | |
60 | builder.add_from_file(get_data_path('%s.ui' % cls.__name__)) | |
47 | 61 | window = builder.get_object('multihead_setup_dialog') |
48 | window._widgets = WidgetsWrapper(builder) | |
62 | window.builder = builder | |
49 | 63 | builder.connect_signals(window) |
50 | window._init_window() | |
64 | window.init_window() | |
51 | 65 | return window |
52 | 66 | |
53 | def _init_window(self): | |
67 | class Widgets(WidgetsEnum): | |
68 | treeview = 'monitors_treeview' | |
69 | model = 'monitors_model' | |
70 | selection = 'monitors_selection' | |
71 | bg_model = 'background_model' | |
72 | bg_renderer = 'bg_renderer' | |
73 | bg_column = 'background_column' | |
74 | name_column = 'name_column' | |
75 | remove = 'remove_button' | |
76 | available = 'monitors_label' | |
77 | ||
78 | builder = None | |
79 | ||
80 | def init_window(self): | |
81 | self._widgets = self.Widgets(builder=self.builder) | |
54 | 82 | self._group = None |
55 | 83 | self._available_monitors = None |
56 | 84 | |
57 | self._remove_button = self._widgets['remove_button'] | |
58 | self._treeview = self._widgets['monitors_treeview'] | |
59 | self._model = self._widgets['monitors_model'] | |
60 | self._bg_model = self._widgets['background_model'] | |
61 | self._selection = self._treeview.get_selection() | |
62 | self._bg_renderer = self._widgets['bg_renderer'] | |
63 | self._bg_column = self._widgets['background_column'] | |
64 | self._name_column = self._widgets['name_column'] | |
65 | 85 | self._file_dialog = None |
66 | 86 | self._color_dialog = None |
67 | 87 | self._invalid_name_dialog = None |
68 | 88 | self._name_exists_dialog = None |
69 | 89 | |
70 | self._bg_renderer.set_property('placeholder-text', | |
71 | C_('option|multihead', 'Use default value')) | |
90 | self._widgets.treeview.props.tooltip_column = Row.ErrorText | |
91 | self._widgets.bg_renderer.set_property('placeholder-text', | |
92 | C_('option|multihead', 'Use default value')) | |
72 | 93 | |
73 | 94 | def _update_monitors_label(self): |
74 | used = set(row[ROW.NAME] for row in self._model) | |
75 | monitors = ['<a href="{name}">{name}</a>'.format(name=name) | |
76 | for name in self._available_monitors if name not in used] | |
77 | label = C_('option|monitors', 'Available monitors: <i>{monitors}</i>')\ | |
78 | .format(monitors=', '.join(monitors or ('none',))) | |
79 | self._widgets['monitors_label'].props.label = label | |
80 | ||
95 | if not self._available_monitors: | |
96 | self._widgets.available.props.visible = False | |
97 | return | |
98 | ||
99 | used = set(row[Row.Name] for row in self._widgets.model) | |
100 | monitors = [] | |
101 | for name in self._available_monitors: | |
102 | if name in used: | |
103 | monitors.append(name) | |
104 | else: | |
105 | monitors.append('<i><a href="{name}">{name}</a></i>'.format(name=name)) | |
106 | ||
107 | label = C_('option|multihead', | |
108 | 'Available monitors: {monitors}').format(monitors=', '.join(monitors)) | |
109 | self._widgets.available.props.label = label | |
110 | self._widgets.available.props.visible = True | |
81 | 111 | |
82 | 112 | def set_model(self, values): |
83 | self._model.clear() | |
113 | self._widgets.model.clear() | |
84 | 114 | for name, entry in values.items(): |
85 | rowiter = self._model.append(ROW(NAME=name, | |
86 | BACKGROUND=entry['background'], | |
87 | USER_BG=entry['user-background'], | |
88 | USER_BG_DISABLED=entry['user-background'] is None, | |
89 | LAPTOP=entry['laptop'], | |
90 | LAPTOP_DISABLED=entry['laptop'] is None, | |
91 | BACKGROUND_PIXBUF=None, | |
92 | BACKGROUND_IS_COLOR=False)) | |
93 | self._update_row_appearance(rowiter) | |
115 | row = Row._make(Name=name, | |
116 | Background=entry['background'], | |
117 | UserBg=entry['user-background'], | |
118 | UserBgDisabled=entry['user-background'] is None, | |
119 | Laptop=entry['laptop'], | |
120 | LaptopDisabled=entry['laptop'] is None, | |
121 | BackgroundPixbuf=None, | |
122 | BackgroundIsColor=False, | |
123 | ErrorVisible=False, | |
124 | ErrorText=None) | |
125 | self._update_row_appearance(self._widgets.model.append(row)) | |
94 | 126 | screen = Gdk.Screen.get_default() |
95 | 127 | self._available_monitors = [screen.get_monitor_plug_name(i) |
96 | 128 | for i in range(screen.get_n_monitors())] |
97 | 129 | self._update_monitors_label() |
98 | 130 | |
99 | 131 | def get_model(self): |
100 | return {row[ROW.NAME]: | |
101 | { | |
102 | 'background': row[ROW.BACKGROUND], | |
103 | 'user-background': self._get_toggle_state(row, ROW.USER_BG, ROW.USER_BG_DISABLED), | |
104 | 'laptop': self._get_toggle_state(row, ROW.LAPTOP, ROW.LAPTOP_DISABLED) | |
105 | } | |
106 | for row in self._model} | |
132 | return { | |
133 | row[Row.Name]: | |
134 | { | |
135 | 'background': row[Row.Background], | |
136 | 'user-background': self._get_toggle_state(row, Row.UserBg, Row.UserBgDisabled), | |
137 | 'laptop': self._get_toggle_state(row, Row.Laptop, Row.LaptopDisabled) | |
138 | } | |
139 | for row in self._widgets.model} | |
107 | 140 | |
108 | 141 | def _update_row_appearance(self, rowiter): |
109 | row = self._model[rowiter] | |
110 | bg = row[ROW.BACKGROUND] | |
111 | ||
112 | color = Gdk.color_parse(bg) | |
113 | if color: | |
114 | pixbuf = row[ROW.BACKGROUND_PIXBUF] | |
142 | row = self._widgets.model[rowiter] | |
143 | bg = row[Row.Background] | |
144 | ||
145 | error = None | |
146 | color = Gdk.RGBA() | |
147 | if color.parse(bg): | |
148 | pixbuf = row[Row.BackgroundPixbuf] | |
115 | 149 | if not pixbuf: |
116 | pixbuf = GdkPixbuf.Pixbuf.new(GdkPixbuf.Colorspace.RGB, | |
117 | False, 8, 16, 16) | |
118 | row[ROW.BACKGROUND_PIXBUF] = pixbuf | |
119 | value = (int(0xFF / Gdk.Color.MAX_VALUE * color.red) << 24) + \ | |
120 | (int(0xFF / Gdk.Color.MAX_VALUE * color.green) << 16) + \ | |
121 | (int(0xFF / Gdk.Color.MAX_VALUE * color.blue) << 8) | |
150 | pixbuf = GdkPixbuf.Pixbuf.new(GdkPixbuf.Colorspace.RGB, False, 8, 16, 16) | |
151 | row[Row.BackgroundPixbuf] = pixbuf | |
152 | value = (int(0xFF * color.red) << 24) + \ | |
153 | (int(0xFF * color.green) << 16) + \ | |
154 | (int(0xFF * color.blue) << 8) | |
122 | 155 | pixbuf.fill(value) |
123 | row[ROW.BACKGROUND_IS_COLOR] = True | |
156 | row[Row.BackgroundIsColor] = True | |
124 | 157 | else: |
125 | row[ROW.BACKGROUND_IS_COLOR] = False | |
126 | ||
127 | _TOGGLE_STATES = {None: True, False: None, True: False} | |
158 | row[Row.BackgroundIsColor] = False | |
159 | if bg: | |
160 | error = check_path_accessibility(bg) | |
161 | ||
162 | row[Row.ErrorVisible] = error is not None | |
163 | row[Row.ErrorText] = error | |
164 | ||
165 | ToggleStatesSeq = {None: True, False: None, True: False} | |
128 | 166 | |
129 | 167 | def _get_toggle_state(self, row, active_column, inconsistent_column): |
130 | 168 | return None if row[inconsistent_column] else row[active_column] |
131 | 169 | |
132 | 170 | def _toggle_state(self, row, active_column, inconsistent_column): |
133 | 171 | state = self._get_toggle_state(row, active_column, inconsistent_column) |
134 | row[active_column] = self._TOGGLE_STATES[state] | |
135 | row[inconsistent_column] = self._TOGGLE_STATES[state] is None | |
172 | row[active_column] = self.ToggleStatesSeq[state] | |
173 | row[inconsistent_column] = self.ToggleStatesSeq[state] is None | |
136 | 174 | |
137 | 175 | def on_monitors_add_clicked(self, button): |
138 | 176 | prefix = 'monitor' |
139 | numbers = (row[ROW.NAME][len(prefix):] | |
140 | for row in self._model if row[ROW.NAME].startswith(prefix)) | |
177 | numbers = (row[Row.Name][len(prefix):] | |
178 | for row in self._widgets.model if row[Row.Name].startswith(prefix)) | |
141 | 179 | try: |
142 | 180 | max_number = max(int(v) for v in numbers if v.isdigit()) |
143 | 181 | except ValueError: |
144 | 182 | max_number = 0 |
145 | rowiter = self._model.append(ROW(NAME='%s%d' % (prefix, max_number + 1), | |
146 | USER_BG=False, | |
147 | USER_BG_ENABLED=False, | |
148 | LAPTOP=True, | |
149 | LAPTOP_ENABLED=False, | |
150 | BACKGROUND='', | |
151 | BACKGROUND_PIXBUF=None, | |
152 | BACKGROUND_IS_COLOR=False)) | |
153 | self._treeview.set_cursor(self._model.get_path(rowiter), self._name_column, True) | |
183 | ||
184 | row = Row._make(Name='%s%d' % (prefix, max_number + 1), | |
185 | UserBg=False, | |
186 | UserBgDisabled=False, | |
187 | Laptop=True, | |
188 | LaptopDisabled=False, | |
189 | Background='', | |
190 | BackgroundPixbuf=None, | |
191 | BackgroundIsColor=False, | |
192 | ErrorVisible=False, | |
193 | ErrorText=None) | |
194 | rowiter = self._widgets.model.append(row) | |
195 | self._widgets.treeview.set_cursor(self._widgets.model.get_path(rowiter), | |
196 | self._widgets.name_column, True) | |
154 | 197 | |
155 | 198 | def on_monitors_remove_clicked(self, button): |
156 | model, rowiter = self._treeview.get_selection().get_selected() | |
199 | model, rowiter = self._widgets.selection.get_selected() | |
157 | 200 | model.remove(rowiter) |
201 | self._update_monitors_label() | |
158 | 202 | |
159 | 203 | def on_selection_changed(self, selection): |
160 | self._remove_button.props.sensitive = selection.get_selected()[1] is not None | |
204 | self._widgets.remove.props.sensitive = all(selection.get_selected()) | |
161 | 205 | |
162 | 206 | def on_monitors_label_activate_link(self, label, name): |
163 | rowiter = self._model.append(ROW(NAME=name, | |
164 | USER_BG=False, | |
165 | USER_BG_ENABLED=False, | |
166 | LAPTOP=True, | |
167 | LAPTOP_ENABLED=False, | |
168 | BACKGROUND='', | |
169 | BACKGROUND_PIXBUF=None, | |
170 | BACKGROUND_IS_COLOR=False)) | |
207 | row = Row._make(Name=name, | |
208 | UserBg=False, | |
209 | UserBgDisabled=False, | |
210 | Laptop=True, | |
211 | LaptopDisabled=False, | |
212 | Background='', | |
213 | BackgroundPixbuf=None, | |
214 | BackgroundIsColor=True, | |
215 | ErrorVisible=False, | |
216 | ErrorText=None) | |
217 | ||
218 | rowiter = self._widgets.model.append(row) | |
171 | 219 | self._update_row_appearance(rowiter) |
172 | self._treeview.get_selection().select_iter(rowiter) | |
220 | self._widgets.selection.select_iter(rowiter) | |
173 | 221 | self._update_monitors_label() |
174 | 222 | return True |
175 | 223 | |
177 | 225 | combobox.connect('format-entry-text', self.on_bg_combobox_format) |
178 | 226 | |
179 | 227 | def on_bg_combobox_format(self, combobox, path): |
180 | model, rowiter = self._selection.get_selected() | |
181 | item_type = combobox.props.model[path][BG_ROW.TYPE] | |
182 | value = model[rowiter][ROW.BACKGROUND] | |
228 | model, rowiter = self._widgets.selection.get_selected() | |
229 | item_type = combobox.props.model[path][BackgroundRow.Type] | |
230 | value = model[rowiter][Row.Background] | |
231 | ||
183 | 232 | if item_type == 'path': |
184 | 233 | if not self._file_dialog: |
185 | 234 | self._file_dialog = Gtk.FileChooserDialog( |
186 | parent=self, | |
187 | buttons=(_('_OK'), Gtk.ResponseType.OK, | |
188 | _('_Cancel'), Gtk.ResponseType.CANCEL), | |
189 | title=C_('option|multihead', 'Select background file')) | |
235 | parent=self, | |
236 | buttons=(_('_OK'), Gtk.ResponseType.OK, | |
237 | _('_Cancel'), Gtk.ResponseType.CANCEL), | |
238 | title=C_('option|multihead', 'Select background file')) | |
190 | 239 | self._file_dialog.props.filter = Gtk.FileFilter() |
191 | 240 | self._file_dialog.props.filter.add_mime_type('image/*') |
192 | 241 | if self._file_dialog.run() == Gtk.ResponseType.OK: |
193 | 242 | value = self._file_dialog.get_filename() |
194 | 243 | self._file_dialog.hide() |
195 | elif item_type == 'icon': | |
244 | elif item_type == 'color': | |
196 | 245 | if not self._color_dialog: |
197 | 246 | self._color_dialog = Gtk.ColorChooserDialog(parent=self) |
198 | 247 | if self._color_dialog.run() == Gtk.ResponseType.OK: |
200 | 249 | self._color_dialog.hide() |
201 | 250 | else: |
202 | 251 | value = '' |
252 | ||
203 | 253 | combobox.set_active(-1) |
204 | 254 | return value |
205 | 255 | |
206 | 256 | def on_bg_renderer_edited(self, renderer, path, new_text): |
207 | self._model[path][ROW.BACKGROUND] = new_text | |
208 | self._update_row_appearance(self._model.get_iter(path)) | |
257 | self._widgets.model[path][Row.Background] = new_text | |
258 | self._update_row_appearance(self._widgets.model.get_iter(path)) | |
209 | 259 | |
210 | 260 | def on_name_renderer_edited(self, renderer, path, new_name): |
211 | old_name = self._model[path][ROW.NAME] | |
261 | old_name = self._widgets.model[path][Row.Name] | |
212 | 262 | invalid_name = not new_name.strip() |
213 | name_in_use = new_name != old_name and any(new_name == row[ROW.NAME] for row in self._model) | |
263 | name_in_use = new_name != old_name and any(new_name == row[Row.Name] | |
264 | for row in self._widgets.model) | |
214 | 265 | if invalid_name or name_in_use: |
215 | 266 | if not self._invalid_name_dialog: |
216 | 267 | self._invalid_name_dialog = Gtk.MessageDialog(parent=self, |
217 | 268 | buttons=Gtk.ButtonsType.OK) |
218 | 269 | self._invalid_name_dialog.set_property('text', |
219 | C_('option|multihead', 'Invalid name: "{name}"') | |
220 | .format(name=new_name)) | |
270 | C_('option|multihead', | |
271 | 'Invalid name: "{name}"') | |
272 | .format(name=new_name)) | |
221 | 273 | if name_in_use: |
222 | 274 | message = C_('option|multihead', 'This name already in use.') |
223 | 275 | else: |
226 | 278 | self._invalid_name_dialog.run() |
227 | 279 | self._invalid_name_dialog.hide() |
228 | 280 | else: |
229 | self._model[path][ROW.NAME] = new_name | |
281 | self._widgets.model[path][Row.Name] = new_name | |
230 | 282 | self._update_monitors_label() |
231 | 283 | |
232 | 284 | def on_user_bg_renderer_toggled(self, renderer, path): |
233 | self._toggle_state(self._model[path], | |
234 | ROW.USER_BG, ROW.USER_BG_DISABLED) | |
285 | self._toggle_state(self._widgets.model[path], Row.UserBg, Row.UserBgDisabled) | |
235 | 286 | |
236 | 287 | def on_laptop_renderer_toggled(self, renderer, path): |
237 | self._toggle_state(self._model[path], | |
238 | ROW.LAPTOP, ROW.LAPTOP_DISABLED) | |
239 | ||
240 | class MonitorsGroup(BaseGroup): | |
241 | GROUP_PREFIX = 'monitor:' | |
242 | ||
243 | def __init__(self, widgets): | |
244 | super().__init__(widgets) | |
245 | self._entries = {} | |
246 | self._widgets = WidgetsWrapper(widgets, 'multihead') | |
247 | self._dialog = None | |
248 | self._widgets['label'].connect('activate-link', self._on_label_link_activate) | |
249 | ||
250 | def read(self, config): | |
251 | self._entries.clear() | |
252 | for name, section in config.items(): | |
253 | if not name.startswith(self.GROUP_PREFIX): | |
254 | continue | |
255 | name = name[len(self.GROUP_PREFIX):].strip() | |
256 | entry = MonitorEntry(self._widgets) | |
257 | entry['background'] = section.get('background', None) | |
258 | entry['user-background'] = section.getboolean('user-background', None) | |
259 | entry['laptop'] = section.getboolean('laptop', None) | |
260 | self._entries[name] = entry | |
261 | self.entry_added.emit(entry, name) | |
262 | ||
263 | def write(self, config): | |
264 | for name in config.sections(): | |
265 | if name.startswith(self.GROUP_PREFIX): | |
266 | config.remove_section(name) | |
267 | for name, entry in self._entries.items(): | |
268 | section = '{prefix} {name}'.format(prefix=self.GROUP_PREFIX, name=name) | |
269 | config.add_section(section) | |
270 | for key, value in entry: | |
271 | if value is not None: | |
272 | config.set(section, key, value) | |
273 | ||
274 | def _on_label_link_activate(self, label, uri): | |
275 | if not self._dialog: | |
276 | self._dialog = MultiheadSetupDialog() | |
277 | self._dialog.props.transient_for = self._widgets['label'].get_toplevel() | |
278 | ||
279 | self._dialog.set_model(self._entries) | |
280 | ||
281 | if self._dialog.run() == Gtk.ResponseType.OK: | |
282 | current_names = set(self._entries.keys()) | |
283 | for name, values in self._dialog.get_model().items(): | |
284 | if name in self._entries: | |
285 | self._entries[name].assign(values) | |
286 | current_names.discard(name) | |
287 | else: | |
288 | entry = MonitorEntry(self._widgets, values) | |
289 | self._entries[name] = entry | |
290 | self.entry_added.emit(entry, name) | |
291 | for name in current_names: | |
292 | self.entry_added.emit(self._entries.pop(name), name) | |
293 | self._dialog.hide() | |
294 | return True | |
295 | ||
296 | ||
297 | class MonitorEntry(BaseEntry): | |
298 | ||
299 | def __init__(self, widgets, values=None): | |
300 | super().__init__(widgets) | |
301 | self._values = values or {} | |
302 | ||
303 | def _get_value(self): | |
304 | return self._values.copy() | |
305 | ||
306 | def _set_value(self, value): | |
307 | self._values = value.copy() | |
308 | ||
309 | def __getitem__(self, key): | |
310 | return self._values[key] | |
311 | ||
312 | def __setitem__(self, key, value): | |
313 | self._values[key] = value | |
314 | ||
315 | def __iter__(self): | |
316 | return iter(self._values.items()) | |
317 | ||
318 | def assign(self, values): | |
319 | if not self._values == values: | |
320 | self._values.update(values) | |
321 | self._emit_changed() | |
288 | self._toggle_state(self._widgets.model[path], Row.Laptop, Row.LaptopDisabled) |
14 | 14 | # You should have received a copy of the GNU General Public License along |
15 | 15 | # with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | 16 | |
17 | from builtins import isinstance | |
18 | from collections import OrderedDict | |
19 | from itertools import product | |
17 | ||
18 | import time | |
20 | 19 | from locale import gettext as _ |
21 | import os | |
22 | import time | |
23 | ||
24 | from gi.repository import Gtk, Gdk, GObject, GLib | |
25 | from lightdm_gtk_greeter_settings.IconChooserDialog import IconChooserDialog | |
26 | from lightdm_gtk_greeter_settings.IndicatorChooserDialog import \ | |
27 | IndicatorChooserDialog | |
28 | from lightdm_gtk_greeter_settings.helpers import C_ | |
29 | from lightdm_gtk_greeter_settings.helpers import ModelRowEnum | |
30 | from lightdm_gtk_greeter_settings.helpers import string2bool, bool2string | |
31 | ||
32 | ||
33 | __all__ = ['BaseEntry', 'BooleanEntry', 'StringEntry', 'ClockFormatEntry', | |
34 | 'BackgroundEntry', 'IconEntry', 'IndicatorsEntry', 'PositionEntry', | |
35 | 'AdjustmentEntry', 'ChoiceEntry'] | |
36 | ||
37 | ||
38 | class BuilderWrapper: | |
39 | ||
40 | def __init__(self, builder, base): | |
41 | self._builder = builder | |
42 | self._base = base | |
43 | ||
44 | def __getitem__(self, key): | |
45 | return self._builder.get_object('%s_%s' % (self._base, key)) | |
20 | ||
21 | from gi.repository import ( | |
22 | Gdk, | |
23 | GLib, | |
24 | GObject, | |
25 | Gtk) | |
26 | from lightdm_gtk_greeter_settings import helpers | |
27 | from lightdm_gtk_greeter_settings.helpers import ( | |
28 | C_, | |
29 | bool2string, | |
30 | string2bool, SimpleEnum) | |
31 | ||
32 | ||
33 | __all__ = [ | |
34 | 'AccessibilityStatesEntry', | |
35 | 'AdjustmentEntry', | |
36 | 'BackgroundEntry', | |
37 | 'BaseEntry', | |
38 | 'BooleanEntry', | |
39 | 'ChoiceEntry', | |
40 | 'ClockFormatEntry', | |
41 | 'InvertedBooleanEntry', | |
42 | 'StringEntry', | |
43 | 'StringPathEntry'] | |
46 | 44 | |
47 | 45 | |
48 | 46 | class BaseEntry(GObject.GObject): |
50 | 48 | def __init__(self, widgets): |
51 | 49 | super().__init__() |
52 | 50 | self._widgets = widgets |
53 | self._use = widgets['use'] | |
54 | if self._use: | |
55 | self._use.connect('notify::active', self._on_use_toggled) | |
51 | self._widgets_to_disable = [] | |
52 | ||
53 | self.__use = widgets['use'] | |
54 | if self.__use: | |
55 | self.__use.connect('notify::active', self.__on_use_toggled) | |
56 | ||
57 | self.__error = widgets['error'] | |
56 | 58 | |
57 | 59 | @property |
58 | 60 | def value(self): |
63 | 65 | |
64 | 66 | @value.setter |
65 | 67 | def value(self, value): |
66 | if self._use: | |
67 | self._use.props.active = True | |
68 | if self.__use: | |
69 | self.__use.set_active(True) | |
68 | 70 | formatted = self.set.emit(value) |
69 | 71 | self._set_value(value if formatted is None else formatted) |
70 | 72 | |
71 | 73 | @property |
72 | 74 | def enabled(self): |
73 | '''Visual option state. You can get/set value of disabled option''' | |
74 | if self._use: | |
75 | return self._use.props.active | |
76 | return True | |
75 | return self._get_enabled() | |
77 | 76 | |
78 | 77 | @enabled.setter |
79 | 78 | def enabled(self, value): |
80 | if self._use: | |
81 | self._use.props.active = value | |
79 | self._set_enabled(value) | |
80 | ||
81 | @property | |
82 | def error(self): | |
83 | return self._get_error() | |
84 | ||
85 | @error.setter | |
86 | def error(self, value): | |
87 | self._set_error(value) | |
82 | 88 | |
83 | 89 | @property |
84 | 90 | def widgets(self): |
89 | 95 | pass |
90 | 96 | |
91 | 97 | @GObject.Signal(flags=GObject.SIGNAL_RUN_CLEANUP) |
92 | def get(self, value: str) -> str: # @IgnorePep8 | |
98 | def get(self, value: str) -> str: | |
93 | 99 | pass |
94 | 100 | |
95 | 101 | @GObject.Signal(flags=GObject.SIGNAL_RUN_CLEANUP) |
96 | def set(self, value: str) -> str: # @IgnorePep8 | |
102 | def set(self, value: str) -> str: | |
97 | 103 | pass |
98 | 104 | |
99 | 105 | def __repr__(self): |
110 | 116 | def _set_value(self, value): |
111 | 117 | raise NotImplementedError(self.__class__) |
112 | 118 | |
119 | def _get_error(self): | |
120 | if self.__error: | |
121 | return self.__error.props.tooltip_text | |
122 | return None | |
123 | ||
124 | def _set_error(self, text): | |
125 | if self.__error: | |
126 | self.__error.props.visible = text is not None | |
127 | self.__error.props.tooltip_text = text | |
128 | ||
129 | def _get_enabled(self): | |
130 | if self.__use: | |
131 | return self.__use.get_active() | |
132 | return True | |
133 | ||
113 | 134 | def _set_enabled(self, value): |
114 | raise NotImplementedError(self.__class__) | |
115 | ||
116 | def _on_use_toggled(self, toggle, *args): | |
117 | self._set_enabled(self._use.props.active) | |
135 | if self.__use: | |
136 | self.__use.set_active(value) | |
137 | if self._widgets_to_disable: | |
138 | for widget in self._widgets_to_disable: | |
139 | widget.props.sensitive = value | |
118 | 140 | self._emit_changed() |
141 | ||
142 | def _show_menu(self): | |
143 | self.__on_label_clicked() | |
119 | 144 | |
120 | 145 | def _emit_changed(self, *unused): |
121 | 146 | self.changed.emit() |
122 | 147 | |
148 | def __on_use_toggled(self, toggle, *unused): | |
149 | self._set_enabled(self.__use.props.active) | |
150 | ||
123 | 151 | |
124 | 152 | class BooleanEntry(BaseEntry): |
125 | 153 | |
127 | 155 | super().__init__(widgets) |
128 | 156 | self._value = widgets['value'] |
129 | 157 | self._value.connect('notify::active', self._emit_changed) |
158 | self._widgets_to_disable.append(self._value) | |
130 | 159 | |
131 | 160 | def _get_value(self): |
132 | 161 | return bool2string(self._value.props.active) |
134 | 163 | def _set_value(self, value): |
135 | 164 | self._value.props.active = string2bool(value) |
136 | 165 | |
137 | def _set_enabled(self, value): | |
138 | self._value.props.sensitive = value | |
166 | ||
167 | class InvertedBooleanEntry(BooleanEntry): | |
168 | ||
169 | def __init__(self, widgets): | |
170 | super().__init__(widgets) | |
171 | ||
172 | def _get_value(self): | |
173 | return bool2string(not self._value.props.active) | |
174 | ||
175 | def _set_value(self, value): | |
176 | self._value.props.active = not string2bool(value) | |
139 | 177 | |
140 | 178 | |
141 | 179 | class StringEntry(BaseEntry): |
143 | 181 | def __init__(self, widgets): |
144 | 182 | super().__init__(widgets) |
145 | 183 | self._value = widgets['value'] |
184 | self._widgets_to_disable.append(self._value) | |
185 | if isinstance(self._value.props.parent, Gtk.ComboBox): | |
186 | self._widgets_to_disable += [self._value.props.parent] | |
146 | 187 | self._value.connect('changed', self._emit_changed) |
147 | 188 | |
148 | 189 | def _get_value(self): |
151 | 192 | def _set_value(self, value): |
152 | 193 | self._value.props.text = value or '' |
153 | 194 | |
154 | def _set_enabled(self, value): | |
155 | self._value.props.sensitive = value | |
195 | ||
196 | class StringPathEntry(BaseEntry): | |
197 | ||
198 | class Row(helpers.SimpleEnum): | |
199 | Title = () | |
200 | Type = () | |
201 | ||
202 | class ItemType(SimpleEnum): | |
203 | Select = 'select-path' | |
204 | Value = 'value' | |
205 | Separator = 'separator' | |
206 | ||
207 | def __init__(self, widgets): | |
208 | super().__init__(widgets) | |
209 | ||
210 | self._file_dialog = None | |
211 | ||
212 | self._combo = widgets['combo'] | |
213 | self._entry = widgets['entry'] | |
214 | self._widgets_to_disable.append(self._combo) | |
215 | self._filters = () | |
216 | ||
217 | self._entry.connect('changed', self._emit_changed) | |
218 | self._combo.connect('format-entry-text', self._on_combobox_format) | |
219 | ||
220 | self._combo.set_row_separator_func(self._row_separator_callback, None) | |
221 | ||
222 | def add_filter(self, file_filter): | |
223 | if self._file_dialog: | |
224 | self._file_dialog.add_filter(file_filter) | |
225 | elif self._filters: | |
226 | self._filters.append(file_filter) | |
227 | else: | |
228 | self._filters = [file_filter] | |
229 | ||
230 | def _get_value(self): | |
231 | return self._entry.props.text | |
232 | ||
233 | def _set_value(self, value): | |
234 | self._entry.props.text = value or '' | |
235 | ||
236 | def _row_separator_callback(self, model, rowiter, data): | |
237 | return model[rowiter][self.Row.Type] == self.ItemType.Separator | |
238 | ||
239 | def _on_combobox_format(self, combobox, path): | |
240 | value = self._entry.props.text | |
241 | item_id = combobox.get_active_id() | |
242 | if item_id == self.ItemType.Select: | |
243 | if not self._file_dialog: | |
244 | self._file_dialog = Gtk.FileChooserDialog( | |
245 | parent=self._combo.get_toplevel(), | |
246 | buttons=(_('_OK'), Gtk.ResponseType.OK, | |
247 | _('_Cancel'), Gtk.ResponseType.CANCEL), | |
248 | title=C_('option|StringPathEntry', 'Select path')) | |
249 | for f in self._filters: | |
250 | self._file_dialog.add_filter(f) | |
251 | if self._file_dialog.run() == Gtk.ResponseType.OK: | |
252 | value = self._file_dialog.get_filename() | |
253 | self._file_dialog.hide() | |
254 | elif item_id == self.ItemType.Value: | |
255 | value = combobox.props.model[path][self.Row.Title] | |
256 | ||
257 | combobox.set_active(-1) | |
258 | combobox.grab_focus() | |
259 | return value | |
156 | 260 | |
157 | 261 | |
158 | 262 | class AdjustmentEntry(BaseEntry): |
161 | 265 | super().__init__(widgets) |
162 | 266 | self._value = widgets['adjustment'] |
163 | 267 | self._view = widgets['view'] |
268 | self._widgets_to_disable.append(self._view) | |
164 | 269 | self._value.connect('value-changed', self._emit_changed) |
165 | 270 | |
166 | 271 | def _get_value(self): |
172 | 277 | except ValueError: |
173 | 278 | self._value.props.value = 0 |
174 | 279 | |
175 | def _set_enabled(self, value): | |
176 | self._view.props.sensitive = value | |
177 | ||
178 | 280 | |
179 | 281 | class ChoiceEntry(BaseEntry): |
180 | 282 | |
181 | 283 | def __init__(self, widgets): |
182 | 284 | super().__init__(widgets) |
183 | 285 | self._value = widgets['value'] |
286 | self._widgets_to_disable.append(self._value) | |
184 | 287 | self._value.connect('changed', self._emit_changed) |
185 | 288 | |
186 | 289 | def _get_value(self): |
188 | 291 | |
189 | 292 | def _set_value(self, value): |
190 | 293 | self._value.props.active_id = value or '' |
191 | ||
192 | def _set_enabled(self, value): | |
193 | self._value.props.sensitive = value | |
194 | 294 | |
195 | 295 | |
196 | 296 | class ClockFormatEntry(StringEntry): |
215 | 315 | self._image_value = widgets['image_value'] |
216 | 316 | self._color_value = widgets['color_value'] |
217 | 317 | |
218 | self._color_choice.connect('toggled', self._on_color_choice_toggled) | |
318 | self._on_choice_id = self._color_choice.connect('toggled', self._on_color_choice_toggled) | |
219 | 319 | self._color_value.connect('color-set', self._on_color_set) |
220 | 320 | self._image_value.connect('file-set', self._on_file_set) |
221 | 321 | |
223 | 323 | if self._image_choice.props.active: |
224 | 324 | return self._image_value.get_filename() or '' |
225 | 325 | else: |
226 | return self._color_value.props.rgba.to_string() | |
326 | r, g, b, __ = (int(0xFF * v) for v in self._color_value.props.rgba) | |
327 | return '#%02x%02x%02x' % (r, g, b) | |
227 | 328 | |
228 | 329 | def _set_value(self, value): |
229 | 330 | if value is None: |
233 | 334 | if not rgba.parse(value): |
234 | 335 | rgba = None |
235 | 336 | |
236 | self._color_choice.props.active = rgba is not None | |
237 | self._image_choice.props.active = rgba is None | |
337 | with self._color_choice.handler_block(self._on_choice_id): | |
338 | self._color_choice.props.active = rgba is not None | |
339 | self._image_choice.props.active = rgba is None | |
238 | 340 | |
239 | 341 | if rgba is not None: |
240 | 342 | self._color_value.props.rgba = rgba |
245 | 347 | else: |
246 | 348 | self._image_value.unselect_all() |
247 | 349 | |
350 | self._emit_changed() | |
351 | ||
248 | 352 | def _on_color_choice_toggled(self, toggle): |
249 | 353 | self._emit_changed() |
250 | 354 | |
266 | 370 | def __init__(self, widgets): |
267 | 371 | super().__init__(widgets) |
268 | 372 | self._value = widgets['value'] |
373 | self._widgets_to_disable.append(self._value) | |
269 | 374 | self._value.connect('font-set', self._emit_changed) |
270 | 375 | |
271 | 376 | def _get_value(self): |
275 | 380 | self._value.props.font_name = value or '' |
276 | 381 | |
277 | 382 | |
278 | class IconEntry(BaseEntry): | |
279 | ||
280 | def __init__(self, widgets): | |
281 | super().__init__(widgets) | |
282 | self._value = None | |
283 | self._image = widgets['image'] | |
284 | self._button = widgets['button'] | |
285 | self._menu = widgets['menu'] | |
286 | self._icon_item = widgets['icon_item'] | |
287 | self._path_item = widgets['path_item'] | |
288 | self._path_dialog = widgets['path_dialog'] | |
289 | self._path_dialog_preview = widgets['path_dialog_preview'] | |
290 | self._icon_dialog = None | |
291 | ||
292 | self._button.connect('toggled', self._on_button_toggled) | |
293 | self._menu.connect('hide', self._on_menu_hide) | |
294 | self._icon_item.connect('activate', self._on_select_icon) | |
295 | self._path_item.connect('activate', self._on_select_path) | |
296 | self._path_dialog.connect( | |
297 | 'update-preview', self._on_update_path_preview) | |
298 | ||
299 | def _get_value(self): | |
300 | return self._value | |
301 | ||
302 | def _set_value(self, value): | |
303 | if value.startswith('#'): | |
304 | self._set_icon(value[1:]) | |
305 | else: | |
306 | self._set_path(value) | |
307 | ||
308 | def _set_icon(self, icon): | |
309 | self._value = '#' + icon | |
310 | self._image.set_from_icon_name(icon, Gtk.IconSize.DIALOG) | |
311 | self._update_menu_items(icon=icon) | |
312 | self._emit_changed() | |
313 | ||
314 | def _set_path(self, path): | |
315 | self._value = path | |
316 | self._image.set_from_file(path) | |
317 | self._update_menu_items(path=path) | |
318 | self._emit_changed() | |
319 | ||
320 | def _update_menu_items(self, icon=None, path=None): | |
321 | if icon: | |
322 | self._icon_item.get_child().set_markup(C_('option-entry|icon', | |
323 | '<b>Icon: {icon}</b>') | |
324 | .format(icon=icon)) | |
325 | else: | |
326 | self._icon_item.get_child().set_markup( | |
327 | C_('option-entry|icon', 'Select icon name...')) | |
328 | ||
329 | if path: | |
330 | self._path_item.get_child()\ | |
331 | .set_markup(C_('option-entry|icon', | |
332 | '<b>File: {path}</b>') | |
333 | .format(path=os.path.basename(path))) | |
334 | else: | |
335 | self._path_item.get_child().set_markup( | |
336 | C_('option-entry|icon', 'Select file...')) | |
337 | ||
338 | def _get_menu_position(self, menu, widget): | |
339 | allocation = widget.get_allocation() | |
340 | x, y = widget.get_window().get_position() | |
341 | x += allocation.x | |
342 | y += allocation.y + allocation.height | |
343 | return (x, y, False) | |
344 | ||
345 | def _on_button_toggled(self, toggle): | |
346 | if toggle.props.active: | |
347 | self._menu.popup(None, None, self._get_menu_position, | |
348 | self._button, 3, Gtk.get_current_event_time()) | |
349 | ||
350 | def _on_menu_hide(self, toggle): | |
351 | self._button.props.active = False | |
352 | ||
353 | def _on_select_icon(self, item): | |
354 | if not self._icon_dialog: | |
355 | self._icon_dialog = IconChooserDialog() | |
356 | self._icon_dialog.props.transient_for = self._image.get_toplevel() | |
357 | if self._value.startswith('#'): | |
358 | self._icon_dialog.select_icon(self._value[1:]) | |
359 | if self._icon_dialog.run() == Gtk.ResponseType.OK: | |
360 | self._set_icon(self._icon_dialog.get_iconname()) | |
361 | self._icon_dialog.hide() | |
362 | ||
363 | def _on_select_path(self, item): | |
364 | self._path_dialog.select_filename(self._value) | |
365 | if self._path_dialog.run() == Gtk.ResponseType.OK: | |
366 | self._set_path(self._path_dialog.get_filename()) | |
367 | self._path_dialog.hide() | |
368 | ||
369 | def _on_update_path_preview(self, chooser): | |
370 | path = chooser.get_filename() | |
371 | if not path or not os.path.isfile(path): | |
372 | self._path_dialog_preview.props.icon_name = 'unknown' | |
373 | return | |
374 | self._path_dialog_preview.set_from_file(path) | |
375 | ||
376 | ||
377 | class IndicatorsEntry(BaseEntry): | |
378 | ROW = ModelRowEnum('NAME', 'TOOLTIP', 'EDITABLE', 'HAS_STATE', 'STATE') | |
379 | NAMES_DELIMITER = ';' | |
380 | DEFAULT_TOOLTIPS = {'~spacer': C_('option-entry|indicators', 'Spacer'), | |
381 | '~separator': C_('option-entry|indicators', 'Separator')} | |
382 | ||
383 | def __init__(self, widgets): | |
384 | super().__init__(widgets) | |
385 | self._toolbar = widgets['toolbar'] | |
386 | self._treeview = widgets['treeview'] | |
387 | self._selection = widgets['selection'] | |
388 | self._state_renderer = widgets['state_renderer'] | |
389 | self._name_column = widgets['name_column'] | |
390 | self._name_renderer = widgets['name_renderer'] | |
391 | self._add = widgets['add'] | |
392 | self._remove = widgets['remove'] | |
393 | self._up = widgets['up'] | |
394 | self._down = widgets['down'] | |
395 | self._model = widgets['model'] | |
396 | self._indicators_dialog = None | |
397 | self._initial_items = OrderedDict((item.NAME, item) | |
398 | for item in map(self.ROW, self._model)) | |
399 | ||
400 | self._treeview.connect('key-press-event', self._on_key_press) | |
401 | self._selection.connect('changed', self._on_selection_changed) | |
402 | self._state_renderer.connect('toggled', self._on_state_toggled) | |
403 | self._name_renderer.connect('edited', self._on_name_edited) | |
404 | self._add.connect('clicked', self._on_add) | |
405 | self._remove.connect('clicked', self._on_remove) | |
406 | self._up.connect('clicked', self._on_up) | |
407 | self._down.connect('clicked', self._on_down) | |
408 | ||
409 | self._model.connect('row-changed', self._on_model_changed) | |
410 | self._model.connect('row-deleted', self._on_model_changed) | |
411 | self._model.connect('row-inserted', self._on_model_changed) | |
412 | self._model.connect('rows-reordered', self._on_model_changed) | |
413 | ||
414 | def _on_model_changed(self, *unused): | |
415 | self._emit_changed() | |
416 | ||
417 | def _get_value(self): | |
418 | names = (row[self.ROW.NAME] for row in self._model | |
419 | if not row[self.ROW.HAS_STATE] or row[self.ROW.STATE]) | |
420 | return self.NAMES_DELIMITER.join(names) | |
421 | ||
422 | def _set_value(self, value): | |
423 | self._model.clear() | |
424 | last_options = self._initial_items.copy() | |
383 | class AccessibilityStatesEntry(BaseEntry): | |
384 | ||
385 | Options = ('keyboard', 'reader', 'contrast', 'font') | |
386 | ||
387 | def __init__(self, widgets): | |
388 | super().__init__(widgets) | |
389 | ||
390 | self._states = {name: widgets[name] for name in self.Options} | |
391 | ||
392 | for w in self._states.values(): | |
393 | w.connect('changed', self._emit_changed) | |
394 | ||
395 | def _get_value(self): | |
396 | states = {name: widget.props.active_id | |
397 | for (name, widget) in self._states.items()} | |
398 | return ';'.join(state + name | |
399 | for (name, state) in states.items() if state not in {None, '-'}) | |
400 | ||
401 | def _set_value(self, value): | |
425 | 402 | if value: |
426 | for name in value.split(self.NAMES_DELIMITER): | |
427 | try: | |
428 | self._model[self._model.append(last_options.pop(name))]\ | |
429 | [self.ROW.STATE] = True | |
430 | except KeyError: | |
431 | self._model.append(self._get_indicator_tuple(name)) | |
432 | ||
433 | for item in list(last_options.values()): | |
434 | self._model.append(item) | |
435 | ||
436 | self._selection.select_path(0) | |
437 | ||
438 | def _set_enabled(self, value): | |
439 | self._toolbar.props.sensitive = value | |
440 | self._treeview.props.sensitive = value | |
441 | ||
442 | def _remove_selection(self): | |
443 | model, rowiter = self._selection.get_selected() | |
444 | if rowiter: | |
445 | previter = model.iter_previous(rowiter) | |
446 | model.remove(rowiter) | |
447 | if previter: | |
448 | self._selection.select_iter(previter) | |
449 | ||
450 | def _move_selection(self, move_up): | |
451 | model, rowiter = self._selection.get_selected() | |
452 | if rowiter: | |
453 | if move_up: | |
454 | model.swap(rowiter, model.iter_previous(rowiter)) | |
455 | else: | |
456 | model.swap(rowiter, model.iter_next(rowiter)) | |
457 | self._on_selection_changed(self._selection) | |
458 | ||
459 | def _check_indicator(self, name): | |
460 | ''' Returns True if name is valid, error message or False otherwise ''' | |
461 | if not name: | |
462 | return False | |
463 | elif name not in ('~spacer', '~separator'): | |
464 | if any(row[self.ROW.NAME] == name for row in self._model): | |
465 | return C_('option-entry|indicators', | |
466 | 'Indicator "{indicator}" is already in the list')\ | |
467 | .format(indicator=name) | |
468 | return True | |
469 | ||
470 | def _add_indicator(self, name): | |
471 | if name: | |
472 | rowiter = self._model.append(self._get_indicator_tuple(name)) | |
473 | self._selection.select_iter(rowiter) | |
474 | self._treeview.grab_focus() | |
475 | ||
476 | def _get_indicator_tuple(self, name): | |
477 | tooltip = self.DEFAULT_TOOLTIPS.get(name, | |
478 | C_('option-entry|indicators', 'Indicator: {name}') | |
479 | .format(name=name)) | |
480 | editable = name not in ('~spacer', '~separator') | |
481 | return self.ROW(NAME=name, TOOLTIP=tooltip, EDITABLE=editable, | |
482 | HAS_STATE=False, STATE=False) | |
483 | ||
484 | def _on_key_press(self, treeview, event): | |
485 | if Gdk.keyval_name(event.keyval) == 'Delete': | |
486 | self._remove_selection() | |
487 | elif Gdk.keyval_name(event.keyval) == 'F2': | |
488 | model, rowiter = self._selection.get_selected() | |
489 | if rowiter and model[rowiter][self.COLUMN.EDITABLE]: | |
490 | self._treeview.set_cursor( | |
491 | model.get_path(rowiter), self.COLUMN.NAME, True) | |
492 | else: | |
493 | return False | |
494 | return True | |
495 | ||
496 | def _on_state_toggled(self, renderer, path): | |
497 | self._model[path][self.ROW.STATE] = not self._model[path][self.ROW.STATE] | |
498 | ||
499 | def _on_name_edited(self, renderer, path, name): | |
500 | check = self._check_indicator(name) | |
501 | if not isinstance(check, str) and check: | |
502 | self._model[path][self.ROW.NAME] = name | |
503 | ||
504 | def _on_selection_changed(self, selection): | |
505 | model, rowiter = selection.get_selected() | |
506 | has_selection = rowiter is not None | |
507 | self._remove.props.sensitive = has_selection and \ | |
508 | not model[rowiter][self.ROW.HAS_STATE] | |
509 | self._down.props.sensitive = has_selection and model.iter_next( | |
510 | rowiter) is not None | |
511 | self._up.props.sensitive = has_selection and model.iter_previous( | |
512 | rowiter) is not None | |
513 | if has_selection: | |
514 | self._treeview.scroll_to_cell(model.get_path(rowiter)) | |
515 | ||
516 | def _on_add(self, *args): | |
517 | if not self._indicators_dialog: | |
518 | self._indicators_dialog = IndicatorChooserDialog( | |
519 | check_callback=self._check_indicator, | |
520 | add_callback=self._add_indicator) | |
521 | self._indicators_dialog.props.transient_for = \ | |
522 | self._treeview.get_toplevel() | |
523 | name = self._indicators_dialog.get_indicator() | |
524 | if name: | |
525 | self._add_indicator(name) | |
526 | ||
527 | def _on_remove(self, *args): | |
528 | self._remove_selection() | |
529 | ||
530 | def _on_up(self, *args): | |
531 | self._move_selection(move_up=True) | |
532 | ||
533 | def _on_down(self, *args): | |
534 | self._move_selection(move_up=False) | |
535 | ||
536 | ||
537 | class PositionEntry(BaseEntry): | |
538 | ||
539 | class Dimension: | |
540 | ||
541 | def __init__(self, name, widgets, anchors, on_changed): | |
542 | self.__dict__.update(('_%s' % w, widgets['%s_%s' % (name, w)]) | |
543 | for w in ('value', 'percents', 'mirror', | |
544 | 'adjustment')) | |
545 | self._name = name | |
546 | self._on_changed = on_changed | |
547 | self._anchor = '' | |
548 | ||
549 | self._percents.connect('toggled', self._on_percents_toggled) | |
550 | self._mirror.connect('toggled', self._on_mirror_toggled) | |
551 | self._on_value_changed_id = self._adjustment.connect( | |
552 | 'value-changed', | |
553 | self._on_value_changed) | |
554 | ||
555 | for (x, y), widget in list(anchors.items()): | |
556 | widget.connect('toggled', self._on_anchor_toggled, self, | |
557 | x if self._name == 'x' else y) | |
558 | ||
559 | @property | |
560 | def value(self): | |
561 | return '%s%d%s,%s' % ('-' if self._mirror.props.active else '', | |
562 | int(self._value.props.value), | |
563 | '%' if self._percents.props.active else '', | |
564 | self._anchor) | |
565 | ||
566 | @value.setter | |
567 | def value(self, dim_value): | |
568 | value, _, anchor = dim_value.partition(',') | |
569 | ||
570 | percents = value and value[-1] == '%' | |
571 | if percents: | |
572 | value = value[:-1] | |
573 | ||
574 | try: | |
575 | p = int(value) | |
576 | except ValueError: | |
577 | p = 0 | |
578 | ||
579 | negative = (p < 0) or (p == 0 and value and value[0] == '-') | |
580 | ||
581 | if not anchor or anchor not in ('start', 'center', 'end'): | |
582 | if negative: | |
583 | anchor = 'end' | |
584 | else: | |
585 | anchor = 'start' | |
586 | self._anchor = anchor | |
587 | ||
588 | self._percents.props.active = percents | |
589 | self._adjustment.props.upper = 100 if self._percents.props.active \ | |
590 | else 10000 | |
591 | self._mirror.props.active = negative | |
592 | with self._adjustment.handler_block(self._on_value_changed_id): | |
593 | self._adjustment.props.value = -p if negative else p | |
594 | ||
595 | @property | |
596 | def anchor(self): | |
597 | return self._anchor | |
598 | ||
599 | def get_scaled_position(self, screen, window, scale): | |
600 | screen_size = screen[0] if self._name == 'x' else screen[1] | |
601 | window_size = window[0] if self._name == 'x' else window[1] | |
602 | ||
603 | p = int(self._adjustment.props.value) | |
604 | if self._percents.props.active: | |
605 | p = screen_size * p / 100 | |
606 | else: | |
607 | p *= scale | |
608 | ||
609 | if self._mirror.props.active: | |
610 | p = screen_size - p | |
611 | ||
612 | if self._anchor == 'center': | |
613 | p -= window_size / 2 | |
614 | elif self._anchor == 'end': | |
615 | p -= window_size | |
616 | ||
617 | p = int(p) | |
618 | ||
619 | if p + window_size > screen_size: | |
620 | p = screen_size - window_size | |
621 | if p < 0: | |
622 | p = 0 | |
623 | ||
624 | return p | |
625 | ||
626 | def _on_value_changed(self, widget): | |
627 | self._on_changed(self) | |
628 | ||
629 | def _on_percents_toggled(self, toggle): | |
630 | self._adjustment.props.upper = 100 if toggle.props.active \ | |
631 | else 10000 | |
632 | self._on_changed(self) | |
633 | ||
634 | def _on_mirror_toggled(self, toggle): | |
635 | self._on_changed(self) | |
636 | ||
637 | def _on_anchor_toggled(self, toggle, dimension, anchor): | |
638 | if dimension == self and toggle.props.active \ | |
639 | and anchor != self._anchor: | |
640 | self._anchor = anchor | |
641 | self._on_changed(self) | |
642 | ||
643 | REAL_WINDOW_SIZE = 430, 210 | |
644 | ||
645 | def __init__(self, widgets): | |
646 | super().__init__(widgets) | |
647 | self._screen = widgets['screen'] | |
648 | self._window = widgets['window'] | |
649 | self._screen_pos = (0, 0) | |
650 | self._screen_size = (0, 0) | |
651 | ||
652 | self._anchors = {(x, y): widgets['base_%s_%s' % (x, y)] | |
653 | for x, y in product(('start', 'center', 'end'), | |
654 | repeat=2)} | |
655 | ||
656 | self._on_resize_id = self._screen.connect( | |
657 | 'size-allocate', self._on_resize) | |
658 | self._screen.connect('draw', self._on_draw_screen_border) | |
659 | self._screen.connect('screen-changed', self._on_gdkscreen_changed) | |
660 | self._on_gdkscreen_monitors_changed_id = \ | |
661 | self._screen.get_screen().connect('monitors-changed', | |
662 | self. | |
663 | _on_gdkscreen_monitors_changed) | |
664 | ||
665 | self._x = PositionEntry.Dimension( | |
666 | 'x', widgets, self._anchors, self._on_dimension_changed) | |
667 | self._y = PositionEntry.Dimension( | |
668 | 'y', widgets, self._anchors, self._on_dimension_changed) | |
669 | ||
670 | def _get_value(self): | |
671 | return self._x.value + ' ' + self._y.value | |
672 | ||
673 | def _set_value(self, value): | |
674 | if value: | |
675 | x, _, y = value.partition(' ') | |
676 | self._x.value = x | |
677 | self._y.value = y or x | |
678 | self._anchors[self._x.anchor, self._y.anchor].props.active = True | |
679 | self._update_layout() | |
680 | ||
681 | def _update_layout(self): | |
682 | screen = self._screen.get_toplevel().get_screen() | |
683 | geometry = screen.get_monitor_geometry(screen.get_primary_monitor()) | |
684 | window_allocation = self._window.get_allocation() | |
685 | window_size = window_allocation.width, window_allocation.height | |
686 | scale = self._screen_size[0] / geometry.width | |
687 | ||
688 | x = self._screen_pos[0] + \ | |
689 | self._x.get_scaled_position(self._screen_size, window_size, scale) | |
690 | y = self._screen_pos[1] + \ | |
691 | self._y.get_scaled_position(self._screen_size, window_size, scale) | |
692 | ||
693 | self._screen.move(self._window, x, y) | |
694 | self._screen.check_resize() | |
695 | ||
696 | def _on_resize(self, widget, allocation): | |
697 | screen = self._screen.get_toplevel().get_screen() | |
698 | geometry = screen.get_monitor_geometry(screen.get_primary_monitor()) | |
699 | screen_scale = geometry.height / geometry.width | |
700 | ||
701 | width = allocation.width | |
702 | height = int(width * screen_scale) | |
703 | ||
704 | if height > allocation.height: | |
705 | height = allocation.height | |
706 | width = min(width, int(height / screen_scale)) | |
707 | self._screen_pos = int((allocation.width - width) / 2), 0 | |
708 | self._screen_size = (width, height) | |
709 | ||
710 | with self._screen.handler_block(self._on_resize_id): | |
711 | scale = width / geometry.width | |
712 | self._window.set_size_request( | |
713 | PositionEntry.REAL_WINDOW_SIZE[0] * scale, | |
714 | PositionEntry.REAL_WINDOW_SIZE[1] * scale) | |
715 | self._update_layout() | |
716 | ||
717 | def _on_draw_screen_border(self, widget, cr): | |
718 | width, height = self._screen_size | |
719 | x, y = self._screen_pos | |
720 | line_width = 2 | |
721 | width -= line_width | |
722 | height -= line_width | |
723 | ||
724 | x += line_width / 2 | |
725 | y += line_width / 2 | |
726 | cr.set_source_rgba(0.2, 0.1, 0.2, 0.8) | |
727 | cr.set_line_width(line_width) | |
728 | ||
729 | cr.move_to(x, y) | |
730 | cr.line_to(x + width, y) | |
731 | cr.line_to(x + width, y + height) | |
732 | cr.line_to(x, y + height) | |
733 | cr.line_to(x, y - line_width / 2) | |
734 | cr.stroke_preserve() | |
735 | ||
736 | return False | |
737 | ||
738 | def _on_gdkscreen_changed(self, widget, prev_screen): | |
739 | widget.queue_resize() | |
740 | if prev_screen: | |
741 | prev_screen.disconnect(self._on_gdkscreen_monitors_changed_id) | |
742 | self._on_gdkscreen_monitors_changed_id = widget.get_screen().connect( | |
743 | 'monitors-changed', | |
744 | self._on_gdkscreen_monitors_changed) | |
745 | ||
746 | def _on_gdkscreen_monitors_changed(self, screen): | |
747 | self._screen.queue_resize() | |
748 | ||
749 | def _on_dimension_changed(self, dimension): | |
750 | with self._screen.handler_block(self._on_resize_id): | |
751 | self._update_layout() | |
752 | self._emit_changed() | |
403 | states = dict((v[1:], v[0]) if v[0] in ('-', '+', '~') else (v, '-') | |
404 | for v in value.split(';') if v) | |
405 | else: | |
406 | states = {} | |
407 | for name in self.Options: | |
408 | self._states[name].props.active_id = states.get(name, '-') |
16 | 16 | |
17 | 17 | |
18 | 18 | from gi.repository import GObject |
19 | ||
20 | from lightdm_gtk_greeter_settings.helpers import WidgetsWrapper | |
19 | 21 | from lightdm_gtk_greeter_settings.OptionEntry import BaseEntry |
20 | from lightdm_gtk_greeter_settings.helpers import WidgetsWrapper | |
21 | 22 | |
22 | 23 | |
23 | __all__ = ['BaseGroup', 'SimpleGroup'] | |
24 | __all__ = [ | |
25 | 'BaseGroup', | |
26 | 'SimpleGroup'] | |
24 | 27 | |
25 | 28 | |
26 | 29 | # Broken solution - too complex |
27 | ||
28 | 30 | class BaseGroup(GObject.GObject): |
29 | 31 | |
30 | 32 | def __init__(self, widgets): |
31 | 33 | super().__init__() |
34 | self.__defaults_wrapper = None | |
32 | 35 | |
33 | 36 | def read(self, config): |
34 | 37 | raise NotImplementedError(self.__class__) |
35 | 38 | |
36 | 39 | def write(self, config): |
40 | raise NotImplementedError(self.__class__) | |
41 | ||
42 | @property | |
43 | def defaults(self): | |
44 | if not self.__defaults_wrapper: | |
45 | class DefaultsWrapper: | |
46 | ||
47 | def __init__(self, getter): | |
48 | self._getter = getter | |
49 | ||
50 | def __getitem__(self, key): | |
51 | return self._getter(key) | |
52 | self.__defaults_wrapper = DefaultsWrapper(self._get_default) | |
53 | return self.__defaults_wrapper | |
54 | ||
55 | def _get_default(self, key): | |
37 | 56 | raise NotImplementedError(self.__class__) |
38 | 57 | |
39 | 58 | @GObject.Signal |
84 | 103 | config.add_section(self._name) |
85 | 104 | |
86 | 105 | for key, entry in self._entries.items(): |
87 | if entry.enabled: | |
106 | value = entry.value | |
107 | if entry.enabled and value != self._get_default(key): | |
88 | 108 | config.set(self._name, key, entry.value) |
89 | 109 | else: |
90 | 110 | config.remove_option(self._name, key) |
91 | 111 | |
112 | def _get_default(self, key): | |
113 | return self._defaults.get(key) |
0 | # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- | |
1 | # LightDM GTK Greeter Settings | |
2 | # Copyright (C) 2014 Andrew P. <pan.pav.7c5@gmail.com> | |
3 | # | |
4 | # This program is free software: you can redistribute it and/or modify it | |
5 | # under the terms of the GNU General Public License version 3, as published | |
6 | # by the Free Software Foundation. | |
7 | # | |
8 | # This program is distributed in the hope that it will be useful, but | |
9 | # WITHOUT ANY WARRANTY; without even the implied warranties of | |
10 | # MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR | |
11 | # PURPOSE. See the GNU General Public License for more details. | |
12 | # | |
13 | # You should have received a copy of the GNU General Public License along | |
14 | # with this program. If not, see <http://www.gnu.org/licenses/>. | |
15 | ||
16 | ||
17 | from itertools import product | |
18 | ||
19 | from gi.repository import ( | |
20 | Gdk, | |
21 | Gtk) | |
22 | ||
23 | from lightdm_gtk_greeter_settings.helpers import WidgetsWrapper | |
24 | from lightdm_gtk_greeter_settings.OptionEntry import BaseEntry | |
25 | ||
26 | ||
27 | __all__ = ['PositionEntry'] | |
28 | ||
29 | ||
30 | class PositionEntry(BaseEntry): | |
31 | ||
32 | class Dimension: | |
33 | ||
34 | def __init__(self, widgets, on_changed): | |
35 | self._entry = widgets['entry'] | |
36 | self._percents = widgets['percents'] | |
37 | self._mirror = widgets['mirror'] | |
38 | self._adjustment = widgets['adjustment'] | |
39 | self._on_changed = on_changed | |
40 | ||
41 | self._anchor = None | |
42 | ||
43 | self._on_percents_id = self._percents.connect('toggled', self._on_percents_toggled) | |
44 | self._on_mirror_id = self._mirror.connect('toggled', self._on_mirror_toggled) | |
45 | self._on_value_id = self._adjustment.connect('value-changed', self._on_value_changed) | |
46 | ||
47 | @property | |
48 | def value(self): | |
49 | return '%s%d%s,%s' % ('-' if self._mirror.props.active else '', | |
50 | int(self._entry.props.value), | |
51 | '%' if self._percents.props.active else '', | |
52 | self._anchor) | |
53 | ||
54 | @value.setter | |
55 | def value(self, s): | |
56 | if isinstance(s, tuple): | |
57 | p, percents, negative, anchor = s | |
58 | else: | |
59 | value, __, anchor = s.partition(',') | |
60 | ||
61 | percents = value and value[-1] == '%' | |
62 | if percents: | |
63 | value = value[:-1] | |
64 | ||
65 | try: | |
66 | p = int(value) | |
67 | except ValueError: | |
68 | p = 0 | |
69 | ||
70 | negative = (p < 0) or (p == 0 and value and value[0] == '-') | |
71 | ||
72 | if not anchor or anchor not in ('start', 'center', 'end'): | |
73 | if negative: | |
74 | anchor = 'end' | |
75 | else: | |
76 | anchor = 'start' | |
77 | ||
78 | self._anchor = anchor | |
79 | with self._percents.handler_block(self._on_percents_id): | |
80 | self._percents.props.active = percents | |
81 | self._adjustment.props.upper = 100 if self._percents.props.active else 10000 | |
82 | with self._mirror.handler_block(self._on_mirror_id): | |
83 | self._mirror.props.active = negative | |
84 | with self._adjustment.handler_block(self._on_value_id): | |
85 | self._adjustment.props.value = -p if negative else p | |
86 | ||
87 | @property | |
88 | def anchor(self): | |
89 | return self._anchor | |
90 | ||
91 | @anchor.setter | |
92 | def anchor(self, value): | |
93 | self._anchor = value | |
94 | ||
95 | @property | |
96 | def negative(self): | |
97 | return self._mirror.props.active | |
98 | ||
99 | @negative.setter | |
100 | def negative(self, value): | |
101 | self._mirror.props.active = value | |
102 | ||
103 | def get_value_for_screen(self, screen: int): | |
104 | p = int(self._adjustment.props.value) | |
105 | ||
106 | if self._percents.props.active: | |
107 | p = screen * p / 100 | |
108 | if self._mirror.props.active: | |
109 | p = screen - p | |
110 | ||
111 | return int(p) | |
112 | ||
113 | def _on_percents_toggled(self, toggle): | |
114 | self._adjustment.props.upper = 100 if toggle.props.active else 10000 | |
115 | self._on_changed(self) | |
116 | ||
117 | def _on_mirror_toggled(self, toggle): | |
118 | self._on_changed(self) | |
119 | ||
120 | def _on_value_changed(self, widget): | |
121 | self._on_changed(self) | |
122 | ||
123 | AssumedWindowSize = 430, 240 | |
124 | ||
125 | def __init__(self, widgets): | |
126 | super().__init__(widgets) | |
127 | ||
128 | self._screen_size = None | |
129 | self._last_overlay_size = None | |
130 | self._last_window_allocation = None | |
131 | ||
132 | self._screen_frame = widgets['screen_frame'] | |
133 | self._screen_overlay = widgets['screen_overlay'] | |
134 | window_box = widgets['window_box'] | |
135 | grid = widgets['window_grid'] | |
136 | ||
137 | self._motion = False | |
138 | ||
139 | window_box.connect('motion-notify-event', self._on_window_motion) | |
140 | window_box.connect('button-press-event', self._on_window_button_press) | |
141 | window_box.connect('button-release-event', self._on_window_button_release) | |
142 | ||
143 | # Creating points grid | |
144 | anchors_align = (Gtk.Align.START, Gtk.Align.CENTER, Gtk.Align.END) | |
145 | anchors = [(x, y, Gtk.RadioButton()) | |
146 | for x, y in product(enumerate(('start', 'center', 'end')), repeat=2)] | |
147 | ||
148 | self._anchors = {} | |
149 | self._anchors_handlers = {} | |
150 | for (left, x_anchor), (top, y_anchor), w in anchors: | |
151 | w.props.halign = anchors_align[left] | |
152 | w.props.valign = anchors_align[top] | |
153 | if w != anchors[0][-1]: | |
154 | w.props.group = anchors[0][-1] | |
155 | grid.attach(w, left, top, 1, 1) | |
156 | self._anchors[x_anchor, y_anchor] = w | |
157 | self._anchors_handlers[w] = w.connect('toggled', self._on_anchor_toggled, | |
158 | x_anchor, y_anchor) | |
159 | ||
160 | grid.show_all() | |
161 | ||
162 | self._x = PositionEntry.Dimension(WidgetsWrapper(widgets, 'x'), self._on_dimension_changed) | |
163 | self._y = PositionEntry.Dimension(WidgetsWrapper(widgets, 'y'), self._on_dimension_changed) | |
164 | ||
165 | self._on_gdk_screen_changed() | |
166 | ||
167 | self._screen_overlay.connect('get-child-position', | |
168 | self._on_screen_overlay_get_child_position) | |
169 | self._screen_overlay.connect('screen-changed', self._on_gdk_screen_changed) | |
170 | ||
171 | def _get_value(self): | |
172 | x = self._x.value | |
173 | y = self._y.value | |
174 | return x + ' ' + y if x != y else x | |
175 | ||
176 | def _set_value(self, value): | |
177 | self._last_window_allocation = None | |
178 | if value: | |
179 | x, __, y = value.partition(' ') | |
180 | self._x.value = x | |
181 | self._y.value = y or x | |
182 | anchor = self._anchors[self._x.anchor, self._y.anchor] | |
183 | with anchor.handler_block(self._anchors_handlers[anchor]): | |
184 | anchor.props.active = True | |
185 | self._screen_overlay.queue_resize() | |
186 | self._emit_changed() | |
187 | ||
188 | def _get_corrected_position(self, p, screen, window, anchor): | |
189 | if anchor == 'center': | |
190 | p -= window / 2 | |
191 | elif anchor == 'end': | |
192 | p -= window | |
193 | ||
194 | if p + window > screen: | |
195 | p = screen - window | |
196 | if p < 0: | |
197 | p = 0 | |
198 | ||
199 | return int(p) | |
200 | ||
201 | def _on_dimension_changed(self, dimension): | |
202 | self._last_window_allocation = None | |
203 | self._screen_overlay.queue_resize() | |
204 | self._emit_changed() | |
205 | ||
206 | def _on_screen_overlay_get_child_position(self, overlay, child, allocation): | |
207 | screen = overlay.get_allocation() | |
208 | ||
209 | if self._last_window_allocation and \ | |
210 | self._last_overlay_size == (screen.width, screen.height): | |
211 | (allocation.x, allocation.y, | |
212 | allocation.width, allocation.height) = self._last_window_allocation | |
213 | return True | |
214 | self._last_overlay_size = screen.width, screen.height | |
215 | ||
216 | scale = screen.width / self._screen_size[0] | |
217 | ||
218 | width = int(self.AssumedWindowSize[0] * scale) | |
219 | height = int(self.AssumedWindowSize[1] * scale) | |
220 | ||
221 | # Set desired size | |
222 | child.set_size_request(width, height) | |
223 | # And check what actually we have now | |
224 | width, height = child.size_request().width, child.size_request().height | |
225 | ||
226 | x = int(self._x.get_value_for_screen(self._screen_size[0]) * scale) | |
227 | y = int(self._y.get_value_for_screen(self._screen_size[1]) * scale) | |
228 | ||
229 | x = self._get_corrected_position(x, screen.width, width, self._x.anchor) | |
230 | y = self._get_corrected_position(y, screen.height, height, self._y.anchor) | |
231 | ||
232 | self._last_window_allocation = x, y, width, height | |
233 | allocation.x, allocation.y, allocation.width, allocation.height = x, y, width, height | |
234 | ||
235 | return True | |
236 | ||
237 | def _on_anchor_toggled(self, toggle, x, y): | |
238 | if not toggle.props.active: | |
239 | return | |
240 | self._x.anchor = x | |
241 | self._y.anchor = y | |
242 | self._last_window_allocation = None | |
243 | self._screen_overlay.queue_resize() | |
244 | self._emit_changed() | |
245 | ||
246 | def _on_gdk_screen_changed(self, widget=None, prev_screen=None): | |
247 | screen = self._screen_overlay.get_toplevel().get_screen() | |
248 | geometry = screen.get_monitor_geometry(screen.get_primary_monitor()) | |
249 | self._screen_size = geometry.width, geometry.height | |
250 | self._screen_frame.props.ratio = geometry.width / geometry.height | |
251 | ||
252 | def _on_window_motion(self, widget, event): | |
253 | if not event.state & Gdk.ModifierType.BUTTON1_MASK: | |
254 | return False | |
255 | ||
256 | screen = self._screen_overlay.get_allocation() | |
257 | x, y = widget.translate_coordinates(self._screen_overlay, event.x, event.y) | |
258 | ||
259 | for d, p in ((self._x, int(100 * x / screen.width)), | |
260 | (self._y, int(100 * y / screen.height))): | |
261 | if p < 0: | |
262 | p = 0 | |
263 | elif p > 100: | |
264 | p = 100 | |
265 | if d.negative: | |
266 | d.value = p - 100, True, True, d.anchor | |
267 | else: | |
268 | d.value = p, True, False, d.anchor | |
269 | ||
270 | self._motion = True | |
271 | self._last_window_allocation = None | |
272 | self._screen_overlay.queue_resize() | |
273 | return True | |
274 | ||
275 | def _on_window_button_press(self, widget, event): | |
276 | if event.button == 1: | |
277 | self._motion = False | |
278 | ||
279 | def _on_window_button_release(self, widget, event): | |
280 | if self._motion and event.button == 1: | |
281 | self._motion = False | |
282 | self._emit_changed() |
13 | 13 | # |
14 | 14 | # You should have received a copy of the GNU General Public License along |
15 | 15 | # with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | ||
16 | 17 | |
17 | 18 | def main(): |
18 | 19 | from gi.repository import Gtk |
14 | 14 | # You should have received a copy of the GNU General Public License along |
15 | 15 | # with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | 16 | |
17 | from collections import namedtuple | |
18 | from itertools import chain | |
17 | ||
18 | import configparser | |
19 | import glob | |
19 | 20 | import locale |
20 | 21 | import os |
21 | ||
22 | from gi.repository import Gtk | |
22 | import pwd | |
23 | import stat | |
24 | ||
25 | from collections import ( | |
26 | namedtuple, | |
27 | OrderedDict, | |
28 | defaultdict) | |
29 | from itertools import ( | |
30 | chain, | |
31 | accumulate) | |
32 | from locale import gettext as _ | |
33 | ||
34 | from gi.repository import ( | |
35 | GdkPixbuf, | |
36 | GLib, | |
37 | GObject, | |
38 | Gtk, | |
39 | Pango) | |
23 | 40 | |
24 | 41 | |
25 | 42 | __license__ = 'GPL-3' |
29 | 46 | |
30 | 47 | |
31 | 48 | try: |
32 | from . installation_config import * | |
49 | from . installation_config import ( | |
50 | __version__, | |
51 | __data_directory__, | |
52 | __config_path__) | |
33 | 53 | except ImportError: |
34 | 54 | pass |
35 | 55 | |
36 | 56 | |
37 | __all__ = ['C_', 'NC_', | |
38 | 'get_data_path', 'get_config_path', 'show_message', | |
39 | 'bool2string', 'string2bool', | |
40 | 'ModelRowEnum', 'WidgetsWrapper'] | |
57 | __all__ = [ | |
58 | 'bool2string', | |
59 | 'C_', | |
60 | 'clamp', | |
61 | 'check_path_accessibility', | |
62 | 'DefaultValueDict', | |
63 | 'file_is_readable_by_greeter', | |
64 | 'get_config_path', | |
65 | 'get_data_path', | |
66 | 'get_greeter_version' | |
67 | 'get_markup_error', | |
68 | 'get_version', | |
69 | 'ModelRowEnum', | |
70 | 'NC_', | |
71 | 'pixbuf_from_file_scaled_down', | |
72 | 'set_image_from_path', | |
73 | 'show_message', | |
74 | 'SimpleEnum', | |
75 | 'string2bool', | |
76 | 'TreeStoreDataWrapper', | |
77 | 'WidgetsEnum', | |
78 | 'WidgetsWrapper'] | |
41 | 79 | |
42 | 80 | |
43 | 81 | def C_(context, message): |
44 | CONTEXT_SEPARATOR = '\x04' | |
45 | message_with_context = '{}{}{}'.format(context, CONTEXT_SEPARATOR, message) | |
82 | separator = '\x04' | |
83 | message_with_context = '{}{}{}'.format(context, separator, message) | |
46 | 84 | result = locale.gettext(message_with_context) |
47 | if CONTEXT_SEPARATOR in result: | |
85 | if separator in result: | |
48 | 86 | result = message |
49 | 87 | return result |
50 | 88 | |
62 | 100 | return os.path.abspath(__config_path__) |
63 | 101 | |
64 | 102 | |
103 | def get_version(): | |
104 | return __version__ | |
105 | ||
106 | ||
107 | def get_greeter_version(): | |
108 | try: | |
109 | return get_greeter_version._version | |
110 | except AttributeError: | |
111 | try: | |
112 | get_greeter_version._version = int(os.getenv('GTK_GREETER_VERSION', '0x010900'), 16) | |
113 | except ValueError: | |
114 | get_greeter_version._version = 0x010900 | |
115 | ||
116 | return get_greeter_version._version | |
117 | ||
118 | ||
119 | def bool2string(value): | |
120 | return 'true' if value else 'false' | |
121 | ||
122 | ||
123 | def string2bool(value): | |
124 | return value and value.lower() in ('true', 'yes', '1') | |
125 | ||
126 | ||
65 | 127 | def show_message(**kwargs): |
66 | dialog = Gtk.MessageDialog(parent=Gtk.Window.list_toplevels()[0], buttons=Gtk.ButtonsType.CLOSE, **kwargs) | |
128 | dialog = Gtk.MessageDialog(parent=Gtk.Window.list_toplevels()[0], | |
129 | buttons=Gtk.ButtonsType.CLOSE, **kwargs) | |
67 | 130 | dialog.run() |
68 | 131 | dialog.destroy() |
69 | 132 | |
70 | def get_version(): | |
71 | return __version__ | |
72 | ||
73 | ||
74 | def bool2string(value): | |
75 | return 'true' if value else 'false' | |
76 | ||
77 | ||
78 | def string2bool(value): | |
79 | return value and value.lower() in ('true', 'yes', '1') | |
80 | ||
81 | ||
82 | class ModelRowEnum: | |
83 | ||
84 | def __init__(self, *names): | |
85 | self.__keys = tuple(names) | |
86 | self.__values = {name: i for i, name in enumerate(names)} | |
87 | self.__dict__.update(self.__values) | |
88 | self.__RowTuple = namedtuple('ModelRowEnumTuple', names) | |
89 | ||
90 | def __call__(self, *args, **kwargs): | |
133 | ||
134 | def pixbuf_from_file_scaled_down(path, width, height): | |
135 | pixbuf = GdkPixbuf.Pixbuf.new_from_file(path) | |
136 | scale = max(pixbuf.props.width / width, pixbuf.props.height / height) | |
137 | ||
138 | if scale > 1: | |
139 | return GdkPixbuf.Pixbuf.scale_simple(pixbuf, | |
140 | pixbuf.props.width / scale, | |
141 | pixbuf.props.height / scale, | |
142 | GdkPixbuf.InterpType.BILINEAR) | |
143 | return pixbuf | |
144 | ||
145 | ||
146 | def set_image_from_path(image, path): | |
147 | if not path or not os.path.isfile(path): | |
148 | image.props.icon_name = 'unknown' | |
149 | else: | |
150 | try: | |
151 | width, height = image.get_size_request() | |
152 | if -1 in (width, height): | |
153 | width, height = 64, 64 | |
154 | pixbuf = pixbuf_from_file_scaled_down(path, width, height) | |
155 | image.set_from_pixbuf(pixbuf) | |
156 | return True | |
157 | except GLib.Error: | |
158 | image.props.icon_name = 'file-broken' | |
159 | return False | |
160 | ||
161 | ||
162 | def check_path_accessibility(path, file=True, executable=False): | |
163 | """Return None if file is readable by greeter and error message otherwise""" | |
164 | ||
165 | if not os.path.exists(path): | |
166 | return _('File not found: {path}').format(path=path) | |
167 | ||
168 | try: | |
169 | uid, gids = check_path_accessibility.id_cached_data | |
170 | except AttributeError: | |
171 | files = glob.glob('/etc/lightdm/lightdm.d/*.conf') | |
172 | files += ['/etc/lightdm/lightdm.conf'] | |
173 | config = configparser.RawConfigParser(strict=False) | |
174 | config.read(files) | |
175 | username = config.get('LightDM', 'greeter-user', fallback='lightdm') | |
176 | ||
177 | pw = pwd.getpwnam(username) | |
178 | uid = pw.pw_uid | |
179 | gids = set(os.getgrouplist(username, pw.pw_gid)) | |
180 | check_path_accessibility.id_cached_data = uid, gids | |
181 | ||
182 | parts = os.path.normpath(path).split(os.path.sep) | |
183 | if not parts[0]: | |
184 | parts[0] = os.path.sep | |
185 | ||
186 | def check(p): | |
187 | try: | |
188 | st = os.stat(p) | |
189 | except OSError as e: | |
190 | return _('Failed to check permissions: {error}'.format(error=e.strerror)) | |
191 | ||
192 | if stat.S_ISDIR(st.st_mode) and not stat.S_IREAD: | |
193 | return _('Directory is not readable: {path}'.format(path=p)) | |
194 | if st.st_uid == uid: | |
195 | return not (st.st_mode & stat.S_IRUSR) and \ | |
196 | _('LightDM do not have permissions to read path: {path}'.format(path=p)) | |
197 | if st.st_gid in gids: | |
198 | return not (st.st_mode & stat.S_IRGRP) and \ | |
199 | _('LightDM do not have permissions to read path: {path}'.format(path=p)) | |
200 | return not (st.st_mode & stat.S_IROTH) and \ | |
201 | _('LightDM do not have permissions to read path: {path}'.format(path=p)) | |
202 | ||
203 | errors = (check(p) for p in accumulate(parts, os.path.join)) | |
204 | error = next((error for error in errors if error), None) | |
205 | ||
206 | if not error and file and not os.path.isfile(path): | |
207 | return _('Path is not a regular file: {path}'.format(path=path)) | |
208 | ||
209 | if not error and executable: | |
210 | st = os.stat(path) | |
211 | if st.st_uid == uid: | |
212 | if not st.st_mode & stat.S_IXUSR: | |
213 | return _('LightDM do not have permissions to execute file: {path}' | |
214 | .format(path=path)) | |
215 | elif st.st_gid in gids: | |
216 | if not st.st_mode & stat.S_IXGRP: | |
217 | return _('LightDM do not have permissions to execute file: {path}' | |
218 | .format(path=path)) | |
219 | elif not st.st_mode & stat.S_IXOTH: | |
220 | return _('LightDM do not have permissions to execute file: {path}'.format(path=path)) | |
221 | ||
222 | return error | |
223 | ||
224 | ||
225 | def get_markup_error(markup): | |
226 | try: | |
227 | Pango.parse_markup(markup, -1, '\0') | |
228 | except GLib.Error as e: | |
229 | return e.message | |
230 | return None | |
231 | ||
232 | ||
233 | def clamp(v, a, b): | |
234 | if v < a: | |
235 | return a | |
236 | if v > b: | |
237 | return b | |
238 | return v | |
239 | ||
240 | ||
241 | class DefaultValueDict(defaultdict): | |
242 | ||
243 | def __init__(self, *items, default=None, factory=None, source=None): | |
244 | super().__init__(None, source or items) | |
245 | self._value = default | |
246 | self._factory = factory | |
247 | ||
248 | def __missing__(self, key): | |
249 | return self._factory(key) if self._factory else self._value | |
250 | ||
251 | ||
252 | class SimpleEnumMeta(type): | |
253 | ||
254 | @classmethod | |
255 | def __prepare__(mcs, *args, **kwargs): | |
256 | return OrderedDict() | |
257 | ||
258 | def __new__(self, cls, bases, classdict): | |
259 | obj = super().__new__(self, cls, bases, classdict) | |
260 | obj._dict = OrderedDict((k, v) | |
261 | for k, v in classdict.items() if obj._accept_member_(k, v)) | |
262 | obj._tuple_type = namedtuple(obj.__class__.__name__ + 'Tuple', obj._dict.keys()) | |
263 | keys = list(obj._dict.keys()) | |
264 | for i in range(len(keys)): | |
265 | if obj._dict[keys[i]] is (): | |
266 | v = 0 if i == 0 else obj._dict[keys[i - 1]] + 1 | |
267 | setattr(obj, keys[i], v) | |
268 | obj._dict[keys[i]] = v | |
269 | return obj | |
270 | ||
271 | def __contains__(self, value): | |
272 | return value in self._dict.values() | |
273 | ||
274 | def __iter__(self): | |
275 | return iter(self._dict.values()) | |
276 | ||
277 | def _make(self, *args, **kwargs): | |
278 | return self._tuple_type._make(self._imake(*args, **kwargs)) | |
279 | ||
280 | def _imake(self, *args, **kwargs): | |
91 | 281 | if args: |
92 | return self.__RowTuple._make(chain.from_iterable(args)) | |
282 | return args | |
283 | elif kwargs: | |
284 | return (kwargs.get(k, v) for k, v in self._dict.items()) | |
93 | 285 | else: |
94 | return self.__RowTuple._make(kwargs.get(name, i) for i, name in enumerate(self.__keys)) | |
286 | return self._dict.values() | |
287 | ||
288 | ||
289 | class SimpleEnum(metaclass=SimpleEnumMeta): | |
290 | _dict = None | |
291 | ||
292 | def __init__(self, *args, **kwargs): | |
293 | if kwargs: | |
294 | self.__dict__.update(kwargs) | |
295 | else: | |
296 | self.__dict__.update((k, args[i]) for i, k in enumerate(self._dict)) | |
297 | ||
298 | def __iter__(self): | |
299 | return (self.__dict__[k] for k in self._dict) | |
300 | ||
301 | def __repr__(self): | |
302 | return repr(tuple((k, self.__dict__[k]) for k in self._dict)) | |
303 | ||
304 | @classmethod | |
305 | def _accept_member_(cls, name, value): | |
306 | return not name.startswith('_') and not name.endswith('_') | |
307 | ||
308 | ||
309 | class WidgetsEnum(SimpleEnum): | |
310 | ||
311 | def __init__(self, wrapper=None, builder=None): | |
312 | getter = wrapper.__getitem__ if wrapper else builder.get_object | |
313 | for k, v in self._dict.items(): | |
314 | if isinstance(v, type) and issubclass(v, WidgetsEnum): | |
315 | self.__dict__[k] = v(WidgetsWrapper(wrapper or builder, k)) | |
316 | else: | |
317 | self.__dict__[k] = getter(v or k) | |
95 | 318 | |
96 | 319 | |
97 | 320 | class WidgetsWrapper: |
321 | _builder = None | |
322 | _prefixes = None | |
98 | 323 | |
99 | 324 | def __init__(self, source, *prefixes): |
100 | 325 | if isinstance(source, Gtk.Builder): |
110 | 335 | if not isinstance(args, tuple): |
111 | 336 | args = (args,) |
112 | 337 | return self._builder.get_object('_'.join(chain(self._prefixes, args))) |
338 | ||
339 | ||
340 | class TreeStoreDataWrapper(GObject.Object): | |
341 | ||
342 | def __init__(self, data): | |
343 | super().__init__() | |
344 | self.data = data |
3 | 3 | # Glade Files |
4 | 4 | [type: gettext/glade]data/GtkGreeterSettingsWindow.ui |
5 | 5 | [type: gettext/glade]data/IconChooserDialog.ui |
6 | [type: gettext/glade]data/IndicatorChooserDialog.ui | |
6 | [type: gettext/glade]data/ImageChooserDialog.ui | |
7 | [type: gettext/glade]data/IndicatorPropertiesDialog.ui | |
7 | 8 | [type: gettext/glade]data/MultiheadSetupDialog.ui |
8 | 9 | |
9 | 10 | # Python Files |
11 | 12 | lightdm_gtk_greeter_settings/GtkGreeterSettingsWindow.py |
12 | 13 | lightdm_gtk_greeter_settings/helpers.py |
13 | 14 | lightdm_gtk_greeter_settings/IconChooserDialog.py |
14 | lightdm_gtk_greeter_settings/IndicatorChooserDialog.py | |
15 | lightdm_gtk_greeter_settings/IndicatorPropertiesDialog.py | |
16 | lightdm_gtk_greeter_settings/IndicatorsEntry.py | |
17 | lightdm_gtk_greeter_settings/MonitorsGroup.py | |
15 | 18 | lightdm_gtk_greeter_settings/MultiheadSetupDialog.py |
16 | 19 | lightdm_gtk_greeter_settings/OptionEntry.py |
20 | lightdm_gtk_greeter_settings/OptionGroup.py | |
21 | lightdm_gtk_greeter_settings/PositionEntry.py | |
22 | ||
17 | 23 | |
18 | 24 | com.ubuntu.pkexec.lightdm-gtk-greeter-settings.policy.in |
7 | 7 | msgstr "" |
8 | 8 | "Project-Id-Version: PACKAGE VERSION\n" |
9 | 9 | "Report-Msgid-Bugs-To: \n" |
10 | "POT-Creation-Date: 2014-03-15 23:23-0400\n" | |
10 | "POT-Creation-Date: 2015-01-25 18:54+0300\n" | |
11 | 11 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" |
12 | 12 | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" |
13 | 13 | "Language-Team: LANGUAGE <LL@li.org>\n" |
21 | 21 | msgstr "" |
22 | 22 | |
23 | 23 | #: ../data/GtkGreeterSettingsWindow.ui.h:1 |
24 | msgctxt "option|hintstyle" | |
24 | msgctxt "option|greeter|default-user-image" | |
25 | msgid "Icon" | |
26 | msgstr "" | |
27 | ||
28 | #: ../data/GtkGreeterSettingsWindow.ui.h:2 | |
29 | msgctxt "option|greeter|default-user-image" | |
30 | msgid "Path" | |
31 | msgstr "" | |
32 | ||
33 | #: ../data/GtkGreeterSettingsWindow.ui.h:3 | |
34 | msgid "LightDM GTK+ Greeter: settings" | |
35 | msgstr "" | |
36 | ||
37 | #: ../data/GtkGreeterSettingsWindow.ui.h:4 | |
38 | msgctxt "option|greeter|xft-rgba" | |
25 | 39 | msgid "None" |
26 | 40 | msgstr "" |
27 | 41 | |
28 | #: ../data/GtkGreeterSettingsWindow.ui.h:2 | |
29 | msgctxt "option|hintstyle" | |
42 | #: ../data/GtkGreeterSettingsWindow.ui.h:5 | |
43 | msgctxt "option|greeter|xft-rgba" | |
44 | msgid "RGB" | |
45 | msgstr "" | |
46 | ||
47 | #: ../data/GtkGreeterSettingsWindow.ui.h:6 | |
48 | msgctxt "option|greeter|xft-rgba" | |
49 | msgid "BGR" | |
50 | msgstr "" | |
51 | ||
52 | #: ../data/GtkGreeterSettingsWindow.ui.h:7 | |
53 | msgctxt "option|greeter|xft-rgba" | |
54 | msgid "Vertical RGB" | |
55 | msgstr "" | |
56 | ||
57 | #: ../data/GtkGreeterSettingsWindow.ui.h:8 | |
58 | msgctxt "option|greeter|xft-rgba" | |
59 | msgid "Vertical BGR" | |
60 | msgstr "" | |
61 | ||
62 | #: ../data/GtkGreeterSettingsWindow.ui.h:9 | |
63 | msgctxt "option|greeter|xft-hintstyle" | |
64 | msgid "None" | |
65 | msgstr "" | |
66 | ||
67 | #: ../data/GtkGreeterSettingsWindow.ui.h:10 | |
68 | msgctxt "option|greeter|xft-hintstyle" | |
30 | 69 | msgid "Slight" |
31 | 70 | msgstr "" |
32 | 71 | |
33 | #: ../data/GtkGreeterSettingsWindow.ui.h:3 | |
34 | msgctxt "option|hintstyle" | |
72 | #: ../data/GtkGreeterSettingsWindow.ui.h:11 | |
73 | msgctxt "option|greeter|xft-hintstyle" | |
35 | 74 | msgid "Medium" |
36 | 75 | msgstr "" |
37 | 76 | |
38 | #: ../data/GtkGreeterSettingsWindow.ui.h:4 | |
39 | msgctxt "option|hintstyle" | |
77 | #: ../data/GtkGreeterSettingsWindow.ui.h:12 | |
78 | msgctxt "option|greeter|xft-hintstyle" | |
40 | 79 | msgid "Full" |
41 | 80 | msgstr "" |
42 | 81 | |
43 | #: ../data/GtkGreeterSettingsWindow.ui.h:5 | |
44 | msgctxt "option|rgba" | |
45 | msgid "None" | |
46 | msgstr "" | |
47 | ||
48 | #: ../data/GtkGreeterSettingsWindow.ui.h:6 | |
49 | msgctxt "option|rgba" | |
50 | msgid "RGB" | |
51 | msgstr "" | |
52 | ||
53 | #: ../data/GtkGreeterSettingsWindow.ui.h:7 | |
54 | msgctxt "option|rgba" | |
55 | msgid "BGR" | |
56 | msgstr "" | |
57 | ||
58 | #: ../data/GtkGreeterSettingsWindow.ui.h:8 | |
59 | msgctxt "option|rgba" | |
60 | msgid "Vertical RGB" | |
61 | msgstr "" | |
62 | ||
63 | #: ../data/GtkGreeterSettingsWindow.ui.h:9 | |
64 | msgctxt "option|rgba" | |
65 | msgid "Vertical BGR" | |
66 | msgstr "" | |
67 | ||
68 | #: ../data/GtkGreeterSettingsWindow.ui.h:10 | |
69 | msgid "LightDM GTK+ Greeter: settings" | |
70 | msgstr "" | |
71 | ||
72 | #: ../data/GtkGreeterSettingsWindow.ui.h:11 | |
73 | msgctxt "option|gtk-theme" | |
82 | #: ../data/GtkGreeterSettingsWindow.ui.h:13 | |
83 | msgctxt "option|greeter|xft-antialias" | |
84 | msgid "Antialias" | |
85 | msgstr "" | |
86 | ||
87 | #: ../data/GtkGreeterSettingsWindow.ui.h:14 | |
88 | msgid "Enable this option to override system defaults" | |
89 | msgstr "" | |
90 | ||
91 | #: ../data/GtkGreeterSettingsWindow.ui.h:15 | |
92 | msgctxt "option|greeter|xft-dpi" | |
93 | msgid "DPI" | |
94 | msgstr "" | |
95 | ||
96 | #: ../data/GtkGreeterSettingsWindow.ui.h:16 | |
97 | msgctxt "option|greeter|xft-rgba" | |
98 | msgid "Subpixel rendering" | |
99 | msgstr "" | |
100 | ||
101 | #: ../data/GtkGreeterSettingsWindow.ui.h:17 | |
102 | msgctxt "option|greeter|xft-hintstyle" | |
103 | msgid "Hinting" | |
104 | msgstr "" | |
105 | ||
106 | #: ../data/GtkGreeterSettingsWindow.ui.h:18 | |
107 | msgid "Additional font options" | |
108 | msgstr "" | |
109 | ||
110 | #: ../data/GtkGreeterSettingsWindow.ui.h:19 | |
111 | msgctxt "option|greeter|background" | |
112 | msgid "Background" | |
113 | msgstr "" | |
114 | ||
115 | #: ../data/GtkGreeterSettingsWindow.ui.h:20 | |
116 | msgctxt "option|multihead" | |
117 | msgid "" | |
118 | " <i>(or use <a href=\"\">multihead setup</a> for individual monitors)</i>" | |
119 | msgstr "" | |
120 | ||
121 | #: ../data/GtkGreeterSettingsWindow.ui.h:21 | |
122 | msgctxt "option|greeter|background" | |
123 | msgid "Color" | |
124 | msgstr "" | |
125 | ||
126 | #: ../data/GtkGreeterSettingsWindow.ui.h:22 | |
127 | msgctxt "option|greeter|background" | |
128 | msgid "Image" | |
129 | msgstr "" | |
130 | ||
131 | #: ../data/GtkGreeterSettingsWindow.ui.h:23 | |
132 | msgctxt "option|greeter|theme-name" | |
74 | 133 | msgid "Theme" |
75 | 134 | msgstr "" |
76 | 135 | |
77 | #: ../data/GtkGreeterSettingsWindow.ui.h:12 | |
78 | msgctxt "option|icons-theme" | |
136 | #: ../data/GtkGreeterSettingsWindow.ui.h:24 | |
137 | msgctxt "option|greeter|icon-theme-name" | |
79 | 138 | msgid "Icons" |
80 | 139 | msgstr "" |
81 | 140 | |
82 | #: ../data/GtkGreeterSettingsWindow.ui.h:13 | |
83 | msgctxt "option|font" | |
141 | #: ../data/GtkGreeterSettingsWindow.ui.h:25 | |
142 | msgctxt "option|greeter|font-name" | |
84 | 143 | msgid "Font" |
85 | 144 | msgstr "" |
86 | 145 | |
87 | #: ../data/GtkGreeterSettingsWindow.ui.h:14 | |
88 | msgctxt "option|rgba" | |
89 | msgid "Subpixel rendering" | |
90 | msgstr "" | |
91 | ||
92 | #: ../data/GtkGreeterSettingsWindow.ui.h:15 | |
93 | msgid "Enable this option to override system defaults" | |
94 | msgstr "" | |
95 | ||
96 | #: ../data/GtkGreeterSettingsWindow.ui.h:16 | |
97 | msgctxt "option|dpi" | |
98 | msgid "DPI" | |
99 | msgstr "" | |
100 | ||
101 | #: ../data/GtkGreeterSettingsWindow.ui.h:17 | |
102 | msgctxt "option|antialias" | |
103 | msgid "Antialias" | |
104 | msgstr "" | |
105 | ||
106 | #: ../data/GtkGreeterSettingsWindow.ui.h:18 | |
107 | msgctxt "option|hintstyle" | |
108 | msgid "Hinting" | |
109 | msgstr "" | |
110 | ||
111 | #: ../data/GtkGreeterSettingsWindow.ui.h:19 | |
112 | msgid "Additional font options" | |
113 | msgstr "" | |
114 | ||
115 | #: ../data/GtkGreeterSettingsWindow.ui.h:20 | |
116 | msgctxt "option|background" | |
117 | msgid "Background" | |
118 | msgstr "" | |
119 | ||
120 | #: ../data/GtkGreeterSettingsWindow.ui.h:21 | |
121 | msgctxt "option|background" | |
122 | msgid "Image" | |
123 | msgstr "" | |
124 | ||
125 | #: ../data/GtkGreeterSettingsWindow.ui.h:22 | |
126 | msgctxt "option|background" | |
127 | msgid "Color" | |
128 | msgstr "" | |
129 | ||
130 | #: ../data/GtkGreeterSettingsWindow.ui.h:23 | |
131 | msgctxt "option|user-image" | |
146 | #: ../data/GtkGreeterSettingsWindow.ui.h:26 | |
147 | msgctxt "option|greeter|hide-user-image" | |
148 | msgid "User image" | |
149 | msgstr "" | |
150 | ||
151 | #: ../data/GtkGreeterSettingsWindow.ui.h:27 | |
152 | msgctxt "option|greeter|default-user-image" | |
132 | 153 | msgid "Default user image" |
133 | 154 | msgstr "" |
134 | 155 | |
135 | #: ../data/GtkGreeterSettingsWindow.ui.h:24 | |
156 | #: ../data/GtkGreeterSettingsWindow.ui.h:28 | |
157 | msgctxt "option|greeter|user-background" | |
158 | msgid "Use user wallpaper if available" | |
159 | msgstr "" | |
160 | ||
161 | #: ../data/GtkGreeterSettingsWindow.ui.h:29 | |
162 | msgctxt "tabs" | |
136 | 163 | msgid "Appearance" |
137 | 164 | msgstr "" |
138 | 165 | |
139 | #: ../data/GtkGreeterSettingsWindow.ui.h:25 | |
140 | msgctxt "option|clock" | |
141 | msgid "Clock" | |
142 | msgstr "" | |
143 | ||
144 | #: ../data/GtkGreeterSettingsWindow.ui.h:26 | |
145 | msgctxt "option|indicators" | |
146 | msgid "Redefine indicators" | |
147 | msgstr "" | |
148 | ||
149 | #: ../data/GtkGreeterSettingsWindow.ui.h:28 | |
166 | #: ../data/GtkGreeterSettingsWindow.ui.h:31 | |
150 | 167 | #, no-c-format |
151 | msgctxt "option|clock-format" | |
168 | msgctxt "option|greeter|clock-format" | |
152 | 169 | msgid "" |
153 | 170 | "%H %I - hours, %M - minutes, %S - seconds\n" |
154 | 171 | "%d - day, %m - month, %y %Y - year\n" |
155 | 172 | "%a %A - day of the week, %b %B - month name" |
156 | 173 | msgstr "" |
157 | 174 | |
158 | #: ../data/GtkGreeterSettingsWindow.ui.h:31 | |
159 | msgctxt "option|indicators" | |
175 | #: ../data/GtkGreeterSettingsWindow.ui.h:34 | |
176 | msgctxt "option|greeter|indicators" | |
160 | 177 | msgid "Add indicator to list" |
161 | 178 | msgstr "" |
162 | 179 | |
163 | #: ../data/GtkGreeterSettingsWindow.ui.h:32 | |
164 | msgctxt "option|indicators" | |
180 | #: ../data/GtkGreeterSettingsWindow.ui.h:35 | |
181 | msgctxt "option|greeter|indicators" | |
165 | 182 | msgid "Add" |
166 | 183 | msgstr "" |
167 | 184 | |
168 | #: ../data/GtkGreeterSettingsWindow.ui.h:33 | |
169 | msgctxt "option|indicators" | |
185 | #: ../data/GtkGreeterSettingsWindow.ui.h:36 | |
186 | msgctxt "option|greeter|indicators" | |
170 | 187 | msgid "Remove indicator from list" |
171 | 188 | msgstr "" |
172 | 189 | |
173 | #: ../data/GtkGreeterSettingsWindow.ui.h:34 | |
174 | msgctxt "option|indicators" | |
190 | #: ../data/GtkGreeterSettingsWindow.ui.h:37 | |
191 | msgctxt "option|greeter|indicators" | |
175 | 192 | msgid "Remove" |
176 | 193 | msgstr "" |
177 | 194 | |
178 | #: ../data/GtkGreeterSettingsWindow.ui.h:35 | |
179 | msgctxt "option|indicators" | |
195 | #: ../data/GtkGreeterSettingsWindow.ui.h:38 | |
196 | msgctxt "option|greeter|indicators" | |
180 | 197 | msgid "Move up" |
181 | 198 | msgstr "" |
182 | 199 | |
183 | #: ../data/GtkGreeterSettingsWindow.ui.h:36 | |
184 | msgctxt "option|indicators" | |
200 | #: ../data/GtkGreeterSettingsWindow.ui.h:39 | |
201 | msgctxt "option|greeter|indicators" | |
185 | 202 | msgid "Up" |
186 | 203 | msgstr "" |
187 | 204 | |
188 | #: ../data/GtkGreeterSettingsWindow.ui.h:37 | |
189 | msgctxt "option|indicators" | |
205 | #: ../data/GtkGreeterSettingsWindow.ui.h:40 | |
206 | msgctxt "option|greeter|indicators" | |
190 | 207 | msgid "Move down" |
191 | 208 | msgstr "" |
192 | 209 | |
193 | #: ../data/GtkGreeterSettingsWindow.ui.h:38 | |
194 | msgctxt "option|indicators" | |
210 | #: ../data/GtkGreeterSettingsWindow.ui.h:41 | |
211 | msgctxt "option|greeter|indicators" | |
195 | 212 | msgid "Down" |
196 | 213 | msgstr "" |
197 | 214 | |
198 | #: ../data/GtkGreeterSettingsWindow.ui.h:39 | |
199 | msgctxt "option|clock-format" | |
200 | msgid "Format:" | |
201 | msgstr "" | |
202 | ||
203 | #: ../data/GtkGreeterSettingsWindow.ui.h:40 | |
215 | #: ../data/GtkGreeterSettingsWindow.ui.h:42 | |
216 | msgctxt "option|greeter|indicators" | |
217 | msgid "Templates" | |
218 | msgstr "" | |
219 | ||
220 | #: ../data/GtkGreeterSettingsWindow.ui.h:43 | |
221 | msgctxt "option|greeter|clock-format" | |
222 | msgid "Clock format:" | |
223 | msgstr "" | |
224 | ||
225 | #: ../data/GtkGreeterSettingsWindow.ui.h:44 | |
226 | msgctxt "option|greeter|indicators" | |
227 | msgid "Redefine indicators" | |
228 | msgstr "" | |
229 | ||
230 | #: ../data/GtkGreeterSettingsWindow.ui.h:45 | |
231 | msgctxt "tabs" | |
204 | 232 | msgid "Panel" |
205 | 233 | msgstr "" |
206 | 234 | |
207 | #: ../data/GtkGreeterSettingsWindow.ui.h:41 | |
208 | msgctxt "option|position" | |
209 | msgid "Horizontal " | |
210 | msgstr "" | |
211 | ||
212 | #: ../data/GtkGreeterSettingsWindow.ui.h:43 | |
235 | #: ../data/GtkGreeterSettingsWindow.ui.h:46 | |
236 | msgctxt "option|greeter|position" | |
237 | msgid "Horizontal" | |
238 | msgstr "" | |
239 | ||
240 | #: ../data/GtkGreeterSettingsWindow.ui.h:47 | |
241 | msgctxt "option|greeter|position" | |
242 | msgid "Vertical" | |
243 | msgstr "" | |
244 | ||
245 | #: ../data/GtkGreeterSettingsWindow.ui.h:48 | |
246 | msgid "0" | |
247 | msgstr "" | |
248 | ||
249 | #: ../data/GtkGreeterSettingsWindow.ui.h:50 | |
213 | 250 | #, no-c-format |
214 | msgctxt "option|position" | |
251 | msgctxt "option|greeter|position" | |
215 | 252 | msgid "in %" |
216 | 253 | msgstr "" |
217 | 254 | |
218 | #: ../data/GtkGreeterSettingsWindow.ui.h:44 | |
219 | msgctxt "option|position" | |
220 | msgid "Vertical" | |
221 | msgstr "" | |
222 | ||
223 | #: ../data/GtkGreeterSettingsWindow.ui.h:45 | |
224 | msgctxt "option|position" | |
225 | msgid "Select base point and its position" | |
226 | msgstr "" | |
227 | ||
228 | #: ../data/GtkGreeterSettingsWindow.ui.h:46 | |
229 | msgctxt "option|position" | |
255 | #: ../data/GtkGreeterSettingsWindow.ui.h:51 | |
256 | msgctxt "option|greeter|position" | |
230 | 257 | msgid "from right" |
231 | 258 | msgstr "" |
232 | 259 | |
233 | #: ../data/GtkGreeterSettingsWindow.ui.h:47 | |
234 | msgctxt "option|position" | |
260 | #: ../data/GtkGreeterSettingsWindow.ui.h:52 | |
261 | msgctxt "option|greeter|position" | |
235 | 262 | msgid "from bottom" |
236 | 263 | msgstr "" |
237 | 264 | |
238 | #: ../data/GtkGreeterSettingsWindow.ui.h:48 | |
265 | #: ../data/GtkGreeterSettingsWindow.ui.h:53 | |
266 | msgctxt "option|greeter|position" | |
267 | msgid "Select base point and its position." | |
268 | msgstr "" | |
269 | ||
270 | #: ../data/GtkGreeterSettingsWindow.ui.h:54 | |
271 | msgctxt "tabs" | |
239 | 272 | msgid "Window position" |
240 | 273 | msgstr "" |
241 | 274 | |
242 | #: ../data/GtkGreeterSettingsWindow.ui.h:49 | |
243 | msgctxt "option|timeout" | |
275 | #: ../data/GtkGreeterSettingsWindow.ui.h:55 | |
276 | msgctxt "option|greeter|screensaver-timeout" | |
277 | msgid "Never" | |
278 | msgstr "" | |
279 | ||
280 | #: ../data/GtkGreeterSettingsWindow.ui.h:56 | |
281 | msgid "Accessibility" | |
282 | msgstr "" | |
283 | ||
284 | #: ../data/GtkGreeterSettingsWindow.ui.h:57 | |
285 | msgctxt "option|greeter|reader" | |
286 | msgid "Select path to reader..." | |
287 | msgstr "" | |
288 | ||
289 | #: ../data/GtkGreeterSettingsWindow.ui.h:58 | |
290 | msgctxt "option|greeter|reader" | |
291 | msgid "Command to launch screen reader" | |
292 | msgstr "" | |
293 | ||
294 | #: ../data/GtkGreeterSettingsWindow.ui.h:59 | |
295 | msgctxt "option|greeter|keyboard" | |
296 | msgid "Select path to keyboard..." | |
297 | msgstr "" | |
298 | ||
299 | #: ../data/GtkGreeterSettingsWindow.ui.h:60 | |
300 | msgctxt "option|greeter|keyboard" | |
301 | msgid "Command to launch on-screen keyboard" | |
302 | msgstr "" | |
303 | ||
304 | #: ../data/GtkGreeterSettingsWindow.ui.h:61 | |
305 | msgctxt "option|greeter|a11y-states" | |
306 | msgid "Disabled at start" | |
307 | msgstr "" | |
308 | ||
309 | #: ../data/GtkGreeterSettingsWindow.ui.h:62 | |
310 | msgctxt "option|greeter|a11y-states" | |
311 | msgid "Enabled at start" | |
312 | msgstr "" | |
313 | ||
314 | #: ../data/GtkGreeterSettingsWindow.ui.h:63 | |
315 | msgctxt "option|greeter|a11y-states" | |
316 | msgid "Save state between launches" | |
317 | msgstr "" | |
318 | ||
319 | #: ../data/GtkGreeterSettingsWindow.ui.h:64 | |
320 | msgctxt "option|greeter|a11y-theme" | |
321 | msgid "Contrast theme" | |
322 | msgstr "" | |
323 | ||
324 | #: ../data/GtkGreeterSettingsWindow.ui.h:65 | |
325 | msgctxt "option|greeter|a11y-font" | |
326 | msgid "Large font" | |
327 | msgstr "" | |
328 | ||
329 | #: ../data/GtkGreeterSettingsWindow.ui.h:66 | |
330 | msgctxt "greeter|option|reader" | |
331 | msgid "Reader" | |
332 | msgstr "" | |
333 | ||
334 | #: ../data/GtkGreeterSettingsWindow.ui.h:67 | |
335 | msgctxt "greeter|option|keyboard" | |
336 | msgid "Keyboard" | |
337 | msgstr "" | |
338 | ||
339 | #: ../data/GtkGreeterSettingsWindow.ui.h:68 | |
340 | msgctxt "option|greeter|screensaver-timeout" | |
244 | 341 | msgid "Timeout until the screen blanks " |
245 | 342 | msgstr "" |
246 | 343 | |
247 | #: ../data/GtkGreeterSettingsWindow.ui.h:50 | |
248 | msgctxt "option|keyboard" | |
249 | msgid "Onscreen keyboard" | |
250 | msgstr "" | |
251 | ||
252 | #: ../data/GtkGreeterSettingsWindow.ui.h:51 | |
253 | msgctxt "option|timeout" | |
254 | msgid "Never" | |
255 | msgstr "" | |
256 | ||
257 | #: ../data/GtkGreeterSettingsWindow.ui.h:52 | |
344 | #: ../data/GtkGreeterSettingsWindow.ui.h:69 | |
345 | msgctxt "greeter|option|allow-debugging" | |
346 | msgid "Debugging mode" | |
347 | msgstr "" | |
348 | ||
349 | #: ../data/GtkGreeterSettingsWindow.ui.h:70 | |
350 | msgctxt "greeter|option|allow-debugging" | |
351 | msgid "" | |
352 | "Enable keys to launch GtkInspector\n" | |
353 | "More informative log" | |
354 | msgstr "" | |
355 | ||
356 | #: ../data/GtkGreeterSettingsWindow.ui.h:72 | |
357 | msgctxt "tabs" | |
258 | 358 | msgid "Misc." |
259 | 359 | msgstr "" |
260 | 360 | |
261 | #: ../data/GtkGreeterSettingsWindow.ui.h:53 | |
361 | #: ../data/GtkGreeterSettingsWindow.ui.h:73 | |
262 | 362 | msgid "You don't have permissions to change greeter configuration" |
263 | 363 | msgstr "" |
264 | 364 | |
265 | #: ../data/GtkGreeterSettingsWindow.ui.h:54 | |
266 | #: ../data/IndicatorChooserDialog.ui.h:2 | |
365 | #: ../data/GtkGreeterSettingsWindow.ui.h:74 | |
366 | #: ../data/IndicatorPropertiesDialog.ui.h:3 | |
267 | 367 | msgctxt "button" |
268 | 368 | msgid "_Close" |
269 | 369 | msgstr "" |
270 | 370 | |
271 | #: ../data/GtkGreeterSettingsWindow.ui.h:55 | |
371 | #: ../data/GtkGreeterSettingsWindow.ui.h:75 | |
272 | 372 | msgctxt "button" |
273 | 373 | msgid "_Save" |
274 | 374 | msgstr "" |
275 | 375 | |
276 | #: ../data/GtkGreeterSettingsWindow.ui.h:56 | |
376 | #: ../data/GtkGreeterSettingsWindow.ui.h:76 | |
277 | 377 | msgctxt "button" |
278 | 378 | msgid "_Reload" |
279 | 379 | msgstr "" |
280 | 380 | |
281 | #: ../data/GtkGreeterSettingsWindow.ui.h:57 | |
381 | #: ../data/GtkGreeterSettingsWindow.ui.h:77 | |
282 | 382 | msgid "Read configuration file" |
283 | 383 | msgstr "" |
284 | 384 | |
285 | #: ../data/GtkGreeterSettingsWindow.ui.h:58 | |
286 | msgid "Select image" | |
287 | msgstr "" | |
288 | ||
289 | 385 | #: ../data/IconChooserDialog.ui.h:1 |
290 | 386 | msgctxt "icon-dialog" |
291 | 387 | msgid "Select icon" |
292 | 388 | msgstr "" |
293 | 389 | |
294 | #: ../data/IconChooserDialog.ui.h:2 | |
390 | #: ../data/IconChooserDialog.ui.h:2 ../data/MultiheadSetupDialog.ui.h:5 | |
295 | 391 | msgctxt "button" |
296 | 392 | msgid "_Cancel" |
297 | 393 | msgstr "" |
298 | 394 | |
299 | #: ../data/IconChooserDialog.ui.h:3 ../data/IndicatorChooserDialog.ui.h:3 | |
395 | #: ../data/IconChooserDialog.ui.h:3 ../data/IndicatorPropertiesDialog.ui.h:4 | |
396 | #: ../data/MultiheadSetupDialog.ui.h:6 | |
300 | 397 | msgctxt "button" |
301 | 398 | msgid "_OK" |
302 | 399 | msgstr "" |
303 | 400 | |
304 | #: ../data/IconChooserDialog.ui.h:4 ../data/IndicatorChooserDialog.ui.h:4 | |
401 | #: ../data/IconChooserDialog.ui.h:4 | |
305 | 402 | msgid "Add selected indicator to the list and close this window" |
306 | 403 | msgstr "" |
307 | 404 | |
325 | 422 | msgid "List _standard icons only" |
326 | 423 | msgstr "" |
327 | 424 | |
328 | #: ../data/IndicatorChooserDialog.ui.h:1 | |
329 | msgctxt "indicators-dialog" | |
330 | msgid "Select indicator" | |
331 | msgstr "" | |
332 | ||
333 | #: ../data/IndicatorChooserDialog.ui.h:5 | |
425 | #: ../data/ImageChooserDialog.ui.h:1 | |
426 | #: ../lightdm_gtk_greeter_settings/MultiheadSetupDialog.py:238 | |
427 | #: ../lightdm_gtk_greeter_settings/OptionEntry.py:251 | |
428 | msgid "_Cancel" | |
429 | msgstr "" | |
430 | ||
431 | #: ../data/ImageChooserDialog.ui.h:2 | |
432 | #: ../lightdm_gtk_greeter_settings/MultiheadSetupDialog.py:237 | |
433 | #: ../lightdm_gtk_greeter_settings/OptionEntry.py:250 | |
434 | msgid "_OK" | |
435 | msgstr "" | |
436 | ||
437 | #: ../data/IndicatorPropertiesDialog.ui.h:1 | |
438 | msgctxt "option-entry|indicators" | |
439 | msgid "Select file..." | |
440 | msgstr "" | |
441 | ||
442 | #: ../data/IndicatorPropertiesDialog.ui.h:2 | |
443 | msgctxt "option-entry|indicators" | |
444 | msgid "Indicator properties" | |
445 | msgstr "" | |
446 | ||
447 | #: ../data/IndicatorPropertiesDialog.ui.h:5 | |
334 | 448 | msgctxt "button" |
335 | 449 | msgid "_Add" |
336 | 450 | msgstr "" |
337 | 451 | |
338 | #: ../data/IndicatorChooserDialog.ui.h:6 | |
339 | msgid "Add selected indicator to the list without closing this window" | |
340 | msgstr "" | |
341 | ||
342 | #: ../data/IndicatorChooserDialog.ui.h:7 | |
343 | msgctxt "indicators-dialog" | |
344 | msgid "Short name" | |
345 | msgstr "" | |
346 | ||
347 | #: ../data/IndicatorChooserDialog.ui.h:8 | |
348 | msgctxt "indicators-dialog" | |
349 | msgid "Indicators that greeter can find without using absolute pathes" | |
350 | msgstr "" | |
351 | ||
352 | #: ../data/IndicatorChooserDialog.ui.h:9 | |
353 | msgctxt "indicators-dialog" | |
354 | msgid "Path" | |
355 | msgstr "" | |
356 | ||
357 | #: ../data/IndicatorChooserDialog.ui.h:10 | |
358 | msgctxt "indicators-dialog" | |
359 | msgid "Absolute path to indicator library file (*.so)" | |
360 | msgstr "" | |
361 | ||
362 | #: ../lightdm_gtk_greeter_settings/GtkGreeterSettingsWindow.py:102 | |
452 | #: ../data/IndicatorPropertiesDialog.ui.h:6 | |
453 | msgctxt "option-entry|indicators" | |
454 | msgid "Indicator" | |
455 | msgstr "" | |
456 | ||
457 | #: ../data/IndicatorPropertiesDialog.ui.h:7 | |
458 | msgctxt "option-entry|indicators" | |
459 | msgid "Display label" | |
460 | msgstr "" | |
461 | ||
462 | #: ../data/IndicatorPropertiesDialog.ui.h:8 | |
463 | msgctxt "option-entry|indicators" | |
464 | msgid "Leave empty to use default value" | |
465 | msgstr "" | |
466 | ||
467 | #: ../data/IndicatorPropertiesDialog.ui.h:9 | |
468 | msgctxt "option-entry|indicators" | |
469 | msgid "Display image" | |
470 | msgstr "" | |
471 | ||
472 | #: ../data/IndicatorPropertiesDialog.ui.h:10 | |
473 | msgctxt "option-entry|indicators" | |
474 | msgid "Indicator library/service:" | |
475 | msgstr "" | |
476 | ||
477 | #: ../data/IndicatorPropertiesDialog.ui.h:11 | |
478 | msgid "page 1" | |
479 | msgstr "" | |
480 | ||
481 | #: ../data/IndicatorPropertiesDialog.ui.h:12 | |
482 | msgctxt "option-entry|indicators" | |
483 | msgid "Hide disabled power actions" | |
484 | msgstr "" | |
485 | ||
486 | #: ../data/IndicatorPropertiesDialog.ui.h:13 | |
487 | msgid "page 2" | |
488 | msgstr "" | |
489 | ||
490 | #: ../data/IndicatorPropertiesDialog.ui.h:14 | |
491 | msgctxt "option-entry|indicators" | |
492 | msgid "Text to display:" | |
493 | msgstr "" | |
494 | ||
495 | #: ../data/IndicatorPropertiesDialog.ui.h:15 | |
496 | msgid "page 3" | |
497 | msgstr "" | |
498 | ||
499 | #: ../data/IndicatorPropertiesDialog.ui.h:16 | |
500 | msgctxt "option-entry|indicators" | |
501 | msgid "Spacer - fills the maximum available space" | |
502 | msgstr "" | |
503 | ||
504 | #: ../data/IndicatorPropertiesDialog.ui.h:17 | |
505 | msgctxt "option-entry|indicators" | |
506 | msgid "Separator - draw a separator" | |
507 | msgstr "" | |
508 | ||
509 | #: ../data/MultiheadSetupDialog.ui.h:1 | |
510 | msgctxt "option|multihead" | |
511 | msgid "Select a file" | |
512 | msgstr "" | |
513 | ||
514 | #: ../data/MultiheadSetupDialog.ui.h:2 | |
515 | msgctxt "option|multihead" | |
516 | msgid "Select color" | |
517 | msgstr "" | |
518 | ||
519 | #: ../data/MultiheadSetupDialog.ui.h:3 | |
520 | #: ../lightdm_gtk_greeter_settings/MultiheadSetupDialog.py:93 | |
521 | msgctxt "option|multihead" | |
522 | msgid "Use default value" | |
523 | msgstr "" | |
524 | ||
525 | #: ../data/MultiheadSetupDialog.ui.h:4 | |
526 | msgctxt "option|multihead" | |
527 | msgid "Multihead setup" | |
528 | msgstr "" | |
529 | ||
530 | #: ../data/MultiheadSetupDialog.ui.h:7 | |
531 | msgctxt "option|multihead" | |
532 | msgid "Monitor" | |
533 | msgstr "" | |
534 | ||
535 | #: ../data/MultiheadSetupDialog.ui.h:8 | |
536 | msgctxt "option|multihead" | |
537 | msgid "User's" | |
538 | msgstr "" | |
539 | ||
540 | #: ../data/MultiheadSetupDialog.ui.h:9 | |
541 | msgctxt "option|multihead" | |
542 | msgid "Laptop" | |
543 | msgstr "" | |
544 | ||
545 | #: ../data/MultiheadSetupDialog.ui.h:10 | |
546 | msgctxt "option|multihead" | |
547 | msgid "Background" | |
548 | msgstr "" | |
549 | ||
550 | #: ../data/MultiheadSetupDialog.ui.h:11 | |
551 | msgctxt "option|multihead" | |
552 | msgid "Add monior to the list" | |
553 | msgstr "" | |
554 | ||
555 | #: ../data/MultiheadSetupDialog.ui.h:12 | |
556 | msgctxt "option|multihead" | |
557 | msgid "Add" | |
558 | msgstr "" | |
559 | ||
560 | #: ../data/MultiheadSetupDialog.ui.h:13 | |
561 | msgctxt "option|multihead" | |
562 | msgid "Remove monitor from the list" | |
563 | msgstr "" | |
564 | ||
565 | #: ../data/MultiheadSetupDialog.ui.h:14 | |
566 | msgctxt "option|multihead" | |
567 | msgid "Remove" | |
568 | msgstr "" | |
569 | ||
570 | #: ../data/MultiheadSetupDialog.ui.h:15 | |
571 | msgctxt "option|multihead" | |
572 | msgid "" | |
573 | "<i>Note: greeter do not set monitors geometry.\n" | |
574 | "You need to configure it by yourself.</i>" | |
575 | msgstr "" | |
576 | ||
577 | #: ../lightdm_gtk_greeter_settings/GtkGreeterSettingsWindow.py:129 | |
363 | 578 | msgid "No permissions to save configuration" |
364 | 579 | msgstr "" |
365 | 580 | |
366 | #: ../lightdm_gtk_greeter_settings/GtkGreeterSettingsWindow.py:104 | |
581 | #: ../lightdm_gtk_greeter_settings/GtkGreeterSettingsWindow.py:131 | |
367 | 582 | #, python-brace-format |
368 | 583 | msgid "" |
369 | 584 | "It seems that you don't have permissions to write to file:\n" |
372 | 587 | "Try to run this program using \"sudo\" or \"pkexec\"" |
373 | 588 | msgstr "" |
374 | 589 | |
375 | #: ../lightdm_gtk_greeter_settings/GtkGreeterSettingsWindow.py:133 | |
376 | #, python-brace-format | |
377 | msgctxt "option|timeout" | |
590 | #: ../lightdm_gtk_greeter_settings/GtkGreeterSettingsWindow.py:148 | |
591 | #, python-brace-format | |
592 | msgid "Failed to read configuration file: {path}" | |
593 | msgstr "" | |
594 | ||
595 | #: ../lightdm_gtk_greeter_settings/GtkGreeterSettingsWindow.py:260 | |
596 | msgid "<i>disabled</i>" | |
597 | msgstr "" | |
598 | ||
599 | #: ../lightdm_gtk_greeter_settings/GtkGreeterSettingsWindow.py:262 | |
600 | msgid "<i>empty string</i>" | |
601 | msgstr "" | |
602 | ||
603 | #: ../lightdm_gtk_greeter_settings/GtkGreeterSettingsWindow.py:264 | |
604 | msgid "<i>None</i>" | |
605 | msgstr "" | |
606 | ||
607 | #: ../lightdm_gtk_greeter_settings/GtkGreeterSettingsWindow.py:285 | |
608 | #, python-brace-format | |
609 | msgid "Reset to initial value: <b>{value}</b>" | |
610 | msgstr "" | |
611 | ||
612 | #: ../lightdm_gtk_greeter_settings/GtkGreeterSettingsWindow.py:296 | |
613 | #, python-brace-format | |
614 | msgid "Reset to default value: <b>{value}</b>" | |
615 | msgstr "" | |
616 | ||
617 | #: ../lightdm_gtk_greeter_settings/GtkGreeterSettingsWindow.py:315 | |
618 | #, python-brace-format | |
619 | msgctxt "option|greeter|screensaver-timeout" | |
378 | 620 | msgid "{count} min" |
379 | 621 | msgstr "" |
380 | 622 | |
381 | #: ../lightdm_gtk_greeter_settings/GtkGreeterSettingsWindow.py:150 | |
382 | #, python-brace-format | |
383 | msgid "Failed to read configuration file: {path}" | |
384 | msgstr "" | |
385 | ||
386 | #: ../lightdm_gtk_greeter_settings/IconChooserDialog.py:186 | |
623 | #: ../lightdm_gtk_greeter_settings/GtkGreeterSettingsWindow.py:358 | |
624 | msgctxt "option|greeter|theme-name" | |
625 | msgid "Selected theme is not available" | |
626 | msgstr "" | |
627 | ||
628 | #: ../lightdm_gtk_greeter_settings/GtkGreeterSettingsWindow.py:371 | |
629 | msgctxt "option|greeter|icon-theme-name" | |
630 | msgid "Selected theme is not available" | |
631 | msgstr "" | |
632 | ||
633 | #: ../lightdm_gtk_greeter_settings/GtkGreeterSettingsWindow.py:378 | |
634 | msgctxt "option|greeter|allow-debugging" | |
635 | msgid "GtkInspector is not available on your system" | |
636 | msgstr "" | |
637 | ||
638 | #: ../lightdm_gtk_greeter_settings/GtkGreeterSettingsWindow.py:407 | |
639 | msgid "Do not leave this field empty" | |
640 | msgstr "" | |
641 | ||
642 | #: ../lightdm_gtk_greeter_settings/helpers.py:150 | |
643 | #, python-brace-format | |
644 | msgid "File not found: {path}" | |
645 | msgstr "" | |
646 | ||
647 | #: ../lightdm_gtk_greeter_settings/helpers.py:174 | |
648 | #, python-brace-format | |
649 | msgid "Failed to check permissions: {error}" | |
650 | msgstr "" | |
651 | ||
652 | #: ../lightdm_gtk_greeter_settings/helpers.py:177 | |
653 | #, python-brace-format | |
654 | msgid "Directory is not readable: {path}" | |
655 | msgstr "" | |
656 | ||
657 | #: ../lightdm_gtk_greeter_settings/helpers.py:180 | |
658 | #: ../lightdm_gtk_greeter_settings/helpers.py:183 | |
659 | #: ../lightdm_gtk_greeter_settings/helpers.py:185 | |
660 | #, python-brace-format | |
661 | msgid "LightDM do not have permissions to read path: {path}" | |
662 | msgstr "" | |
663 | ||
664 | #: ../lightdm_gtk_greeter_settings/helpers.py:191 | |
665 | #, python-brace-format | |
666 | msgid "Path is not a regular file: {path}" | |
667 | msgstr "" | |
668 | ||
669 | #: ../lightdm_gtk_greeter_settings/helpers.py:197 | |
670 | #: ../lightdm_gtk_greeter_settings/helpers.py:201 | |
671 | #: ../lightdm_gtk_greeter_settings/helpers.py:204 | |
672 | #, python-brace-format | |
673 | msgid "LightDM do not have permissions to execute file: {path}" | |
674 | msgstr "" | |
675 | ||
676 | #: ../lightdm_gtk_greeter_settings/IconChooserDialog.py:200 | |
387 | 677 | msgctxt "icon-dialog" |
388 | 678 | msgid "All contexts" |
389 | 679 | msgstr "" |
390 | 680 | |
391 | 681 | #. separator |
392 | #: ../lightdm_gtk_greeter_settings/IconChooserDialog.py:188 | |
682 | #: ../lightdm_gtk_greeter_settings/IconChooserDialog.py:202 | |
393 | 683 | msgctxt "icon-dialog" |
394 | 684 | msgid "Actions" |
395 | 685 | msgstr "" |
396 | 686 | |
397 | #: ../lightdm_gtk_greeter_settings/IconChooserDialog.py:189 | |
687 | #: ../lightdm_gtk_greeter_settings/IconChooserDialog.py:203 | |
398 | 688 | msgctxt "icon-dialog" |
399 | 689 | msgid "Applications" |
400 | 690 | msgstr "" |
401 | 691 | |
402 | #: ../lightdm_gtk_greeter_settings/IconChooserDialog.py:190 | |
692 | #: ../lightdm_gtk_greeter_settings/IconChooserDialog.py:204 | |
403 | 693 | msgctxt "icon-dialog" |
404 | 694 | msgid "Categories" |
405 | 695 | msgstr "" |
406 | 696 | |
407 | #: ../lightdm_gtk_greeter_settings/IconChooserDialog.py:191 | |
697 | #: ../lightdm_gtk_greeter_settings/IconChooserDialog.py:205 | |
408 | 698 | msgctxt "icon-dialog" |
409 | 699 | msgid "Devices" |
410 | 700 | msgstr "" |
411 | 701 | |
412 | #: ../lightdm_gtk_greeter_settings/IconChooserDialog.py:192 | |
702 | #: ../lightdm_gtk_greeter_settings/IconChooserDialog.py:206 | |
413 | 703 | msgctxt "icon-dialog" |
414 | 704 | msgid "Emblems" |
415 | 705 | msgstr "" |
416 | 706 | |
417 | #: ../lightdm_gtk_greeter_settings/IconChooserDialog.py:193 | |
707 | #: ../lightdm_gtk_greeter_settings/IconChooserDialog.py:207 | |
418 | 708 | msgctxt "icon-dialog" |
419 | 709 | msgid "Emoticons" |
420 | 710 | msgstr "" |
421 | 711 | |
422 | #: ../lightdm_gtk_greeter_settings/IconChooserDialog.py:194 | |
712 | #: ../lightdm_gtk_greeter_settings/IconChooserDialog.py:208 | |
423 | 713 | msgctxt "icon-dialog" |
424 | 714 | msgid "International" |
425 | 715 | msgstr "" |
426 | 716 | |
427 | #: ../lightdm_gtk_greeter_settings/IconChooserDialog.py:195 | |
717 | #: ../lightdm_gtk_greeter_settings/IconChooserDialog.py:209 | |
428 | 718 | msgctxt "icon-dialog" |
429 | 719 | msgid "MIME Types" |
430 | 720 | msgstr "" |
431 | 721 | |
432 | #: ../lightdm_gtk_greeter_settings/IconChooserDialog.py:196 | |
722 | #: ../lightdm_gtk_greeter_settings/IconChooserDialog.py:210 | |
433 | 723 | msgctxt "icon-dialog" |
434 | 724 | msgid "Places" |
435 | 725 | msgstr "" |
436 | 726 | |
437 | #: ../lightdm_gtk_greeter_settings/IconChooserDialog.py:197 | |
727 | #: ../lightdm_gtk_greeter_settings/IconChooserDialog.py:211 | |
438 | 728 | msgctxt "icon-dialog" |
439 | 729 | msgid "Status" |
440 | 730 | msgstr "" |
441 | 731 | |
442 | #: ../lightdm_gtk_greeter_settings/OptionEntry.py:290 | |
732 | #: ../lightdm_gtk_greeter_settings/IndicatorPropertiesDialog.py:71 | |
733 | msgctxt "option-entry|indicators" | |
734 | msgid "<b>Using default value</b>" | |
735 | msgstr "" | |
736 | ||
737 | #: ../lightdm_gtk_greeter_settings/IndicatorPropertiesDialog.py:77 | |
738 | msgctxt "option-entry|indicators" | |
739 | msgid "Use default value..." | |
740 | msgstr "" | |
741 | ||
742 | #: ../lightdm_gtk_greeter_settings/IndicatorPropertiesDialog.py:233 | |
743 | msgctxt "option-entry|indicators" | |
744 | msgid "Path/Service field is not filled" | |
745 | msgstr "" | |
746 | ||
747 | #: ../lightdm_gtk_greeter_settings/IndicatorPropertiesDialog.py:237 | |
748 | #, python-brace-format | |
749 | msgctxt "option-entry|indicators" | |
750 | msgid "" | |
751 | "Indicator \"{name}\" is already in the list.\n" | |
752 | "It will be overwritten." | |
753 | msgstr "" | |
754 | ||
755 | #: ../lightdm_gtk_greeter_settings/IndicatorsEntry.py:131 | |
756 | msgctxt "option-entry|indicators|name" | |
757 | msgid "External library/service" | |
758 | msgstr "" | |
759 | ||
760 | #: ../lightdm_gtk_greeter_settings/IndicatorsEntry.py:132 | |
761 | msgctxt "option-entry|indicators|name" | |
762 | msgid "Spacer" | |
763 | msgstr "" | |
764 | ||
765 | #: ../lightdm_gtk_greeter_settings/IndicatorsEntry.py:133 | |
766 | msgctxt "option-entry|indicators|name" | |
767 | msgid "Separator" | |
768 | msgstr "" | |
769 | ||
770 | #: ../lightdm_gtk_greeter_settings/IndicatorsEntry.py:134 | |
771 | msgctxt "option-entry|indicators|name" | |
772 | msgid "Text" | |
773 | msgstr "" | |
774 | ||
775 | #: ../lightdm_gtk_greeter_settings/IndicatorsEntry.py:135 | |
776 | msgctxt "option-entry|indicators|name" | |
777 | msgid "Clock" | |
778 | msgstr "" | |
779 | ||
780 | #: ../lightdm_gtk_greeter_settings/IndicatorsEntry.py:136 | |
781 | msgctxt "option-entry|indicators|name" | |
782 | msgid "Host name" | |
783 | msgstr "" | |
784 | ||
785 | #: ../lightdm_gtk_greeter_settings/IndicatorsEntry.py:137 | |
786 | msgctxt "option-entry|indicators|name" | |
787 | msgid "Keyboard layout" | |
788 | msgstr "" | |
789 | ||
790 | #: ../lightdm_gtk_greeter_settings/IndicatorsEntry.py:138 | |
791 | msgctxt "option-entry|indicators|name" | |
792 | msgid "Sessions menu" | |
793 | msgstr "" | |
794 | ||
795 | #: ../lightdm_gtk_greeter_settings/IndicatorsEntry.py:139 | |
796 | msgctxt "option-entry|indicators|name" | |
797 | msgid "Languages menu" | |
798 | msgstr "" | |
799 | ||
800 | #: ../lightdm_gtk_greeter_settings/IndicatorsEntry.py:140 | |
801 | msgctxt "option-entry|indicators|name" | |
802 | msgid "Accessibility menu" | |
803 | msgstr "" | |
804 | ||
805 | #: ../lightdm_gtk_greeter_settings/IndicatorsEntry.py:141 | |
806 | msgctxt "option-entry|indicators|name" | |
807 | msgid "Power menu" | |
808 | msgstr "" | |
809 | ||
810 | #: ../lightdm_gtk_greeter_settings/IndicatorsEntry.py:148 | |
811 | msgctxt "option-entry|indicators|tooltip" | |
812 | msgid "Spacer" | |
813 | msgstr "" | |
814 | ||
815 | #: ../lightdm_gtk_greeter_settings/IndicatorsEntry.py:149 | |
816 | msgctxt "option-entry|indicators|tooltip" | |
817 | msgid "Separator" | |
818 | msgstr "" | |
819 | ||
820 | #: ../lightdm_gtk_greeter_settings/IndicatorsEntry.py:150 | |
821 | msgctxt "option-entry|indicators|tooltip" | |
822 | msgid "Custom text or/and image" | |
823 | msgstr "" | |
824 | ||
825 | #: ../lightdm_gtk_greeter_settings/IndicatorsEntry.py:151 | |
826 | msgctxt "option-entry|indicators|tooltip" | |
827 | msgid "Host name" | |
828 | msgstr "" | |
829 | ||
830 | #: ../lightdm_gtk_greeter_settings/IndicatorsEntry.py:152 | |
831 | msgctxt "option-entry|indicators|tooltip" | |
832 | msgid "Clock" | |
833 | msgstr "" | |
834 | ||
835 | #: ../lightdm_gtk_greeter_settings/IndicatorsEntry.py:153 | |
836 | msgctxt "option-entry|indicators|tooltip" | |
837 | msgid "Layout indicator" | |
838 | msgstr "" | |
839 | ||
840 | #: ../lightdm_gtk_greeter_settings/IndicatorsEntry.py:155 | |
841 | msgctxt "option-entry|indicators|tooltip" | |
842 | msgid "Sessions menu (xfce, unity, gnome etc.)" | |
843 | msgstr "" | |
844 | ||
845 | #: ../lightdm_gtk_greeter_settings/IndicatorsEntry.py:156 | |
846 | msgctxt "option-entry|indicators|tooltip" | |
847 | msgid "Languages menu" | |
848 | msgstr "" | |
849 | ||
850 | #: ../lightdm_gtk_greeter_settings/IndicatorsEntry.py:157 | |
851 | msgctxt "option-entry|indicators|tooltip" | |
852 | msgid "Accessibility menu" | |
853 | msgstr "" | |
854 | ||
855 | #: ../lightdm_gtk_greeter_settings/IndicatorsEntry.py:158 | |
856 | msgctxt "option-entry|indicators|tooltip" | |
857 | msgid "Power menu" | |
858 | msgstr "" | |
859 | ||
860 | #: ../lightdm_gtk_greeter_settings/IndicatorsEntry.py:581 | |
861 | msgctxt "option-entry|indicators" | |
862 | msgid "Reset to _defaults" | |
863 | msgstr "" | |
864 | ||
865 | #: ../lightdm_gtk_greeter_settings/IndicatorsEntry.py:583 | |
866 | msgctxt "option-entry|indicators" | |
867 | msgid "Display _label" | |
868 | msgstr "" | |
869 | ||
870 | #: ../lightdm_gtk_greeter_settings/IndicatorsEntry.py:585 | |
871 | msgctxt "option-entry|indicators" | |
872 | msgid "Display _image" | |
873 | msgstr "" | |
874 | ||
875 | #: ../lightdm_gtk_greeter_settings/IndicatorsEntry.py:587 | |
876 | msgctxt "option-entry|indicators" | |
877 | msgid "_Remove" | |
878 | msgstr "" | |
879 | ||
880 | #: ../lightdm_gtk_greeter_settings/IndicatorsEntry.py:687 | |
881 | msgctxt "option-entry|indicators" | |
882 | msgid "Show unused items" | |
883 | msgstr "" | |
884 | ||
885 | #: ../lightdm_gtk_greeter_settings/IndicatorsEntry.py:691 | |
886 | msgctxt "option-entry|indicators" | |
887 | msgid "Predefined templates:" | |
888 | msgstr "" | |
889 | ||
890 | #: ../lightdm_gtk_greeter_settings/MultiheadSetupDialog.py:109 | |
891 | #, python-brace-format | |
892 | msgctxt "option|multihead" | |
893 | msgid "Available monitors: {monitors}" | |
894 | msgstr "" | |
895 | ||
896 | #: ../lightdm_gtk_greeter_settings/MultiheadSetupDialog.py:239 | |
897 | msgctxt "option|multihead" | |
898 | msgid "Select background file" | |
899 | msgstr "" | |
900 | ||
901 | #: ../lightdm_gtk_greeter_settings/MultiheadSetupDialog.py:272 | |
902 | #, python-brace-format | |
903 | msgctxt "option|multihead" | |
904 | msgid "Invalid name: \"{name}\"" | |
905 | msgstr "" | |
906 | ||
907 | #: ../lightdm_gtk_greeter_settings/MultiheadSetupDialog.py:275 | |
908 | msgctxt "option|multihead" | |
909 | msgid "This name already in use." | |
910 | msgstr "" | |
911 | ||
912 | #: ../lightdm_gtk_greeter_settings/MultiheadSetupDialog.py:277 | |
913 | msgctxt "option|multihead" | |
914 | msgid "This name is not valid." | |
915 | msgstr "" | |
916 | ||
917 | #: ../lightdm_gtk_greeter_settings/OptionEntry.py:252 | |
918 | msgctxt "option|StringPathEntry" | |
919 | msgid "Select path" | |
920 | msgstr "" | |
921 | ||
922 | #: ../lightdm_gtk_greeter_settings/OptionEntry.py:426 | |
443 | 923 | #, python-brace-format |
444 | 924 | msgctxt "option-entry|icon" |
445 | 925 | msgid "<b>Icon: {icon}</b>" |
446 | 926 | msgstr "" |
447 | 927 | |
448 | #: ../lightdm_gtk_greeter_settings/OptionEntry.py:294 | |
928 | #: ../lightdm_gtk_greeter_settings/OptionEntry.py:431 | |
449 | 929 | msgctxt "option-entry|icon" |
450 | 930 | msgid "Select icon name..." |
451 | 931 | msgstr "" |
452 | 932 | |
453 | #: ../lightdm_gtk_greeter_settings/OptionEntry.py:299 | |
933 | #: ../lightdm_gtk_greeter_settings/OptionEntry.py:435 | |
934 | #, python-brace-format | |
935 | msgctxt "option-entry|icon" | |
936 | msgid "<b>File: {path}</b> (failed to load)" | |
937 | msgstr "" | |
938 | ||
939 | #: ../lightdm_gtk_greeter_settings/OptionEntry.py:437 | |
454 | 940 | #, python-brace-format |
455 | 941 | msgctxt "option-entry|icon" |
456 | 942 | msgid "<b>File: {path}</b>" |
457 | 943 | msgstr "" |
458 | 944 | |
459 | #: ../lightdm_gtk_greeter_settings/OptionEntry.py:303 | |
945 | #: ../lightdm_gtk_greeter_settings/OptionEntry.py:443 | |
460 | 946 | msgctxt "option-entry|icon" |
461 | 947 | msgid "Select file..." |
462 | msgstr "" | |
463 | ||
464 | #: ../lightdm_gtk_greeter_settings/OptionEntry.py:444 | |
465 | #, python-brace-format | |
466 | msgctxt "option-entry|indicators" | |
467 | msgid "Indicator \"{indicator}\" is already in the list" | |
468 | 948 | msgstr "" |
469 | 949 | |
470 | 950 | #: ../com.ubuntu.pkexec.lightdm-gtk-greeter-settings.policy.in.h:1 |