Add a port of the gdm Dusty theme.
authorHong Jen Yee (PCMan) <pcman.tw@gmail.com>
Sun, 11 Nov 2012 10:17:05 +0000 (18:17 +0800)
committerHong Jen Yee (PCMan) <pcman.tw@gmail.com>
Sun, 11 Nov 2012 10:17:05 +0000 (18:17 +0800)
Support setting language/session with buttons.

18 files changed:
configure.ac
data/Makefile.am
data/themes/Dusty/Makefile.am [new file with mode: 0644]
data/themes/Dusty/arrow_left.png [new file with mode: 0644]
data/themes/Dusty/arrow_right.png [new file with mode: 0644]
data/themes/Dusty/arrow_up.png [new file with mode: 0644]
data/themes/Dusty/bg.jpg [new file with mode: 0644]
data/themes/Dusty/greeter-gtk2.ui [new file with mode: 0644]
data/themes/Dusty/gtk2.rc [new file with mode: 0644]
data/themes/Dusty/halt.png [new file with mode: 0644]
data/themes/Dusty/index.theme.in [new file with mode: 0644]
data/themes/Dusty/reboot.png [new file with mode: 0644]
data/themes/Dusty/suspend.png [new file with mode: 0644]
data/themes/Makefile.am
data/ui/chooser.ui [new file with mode: 0644]
po/POTFILES.in
src/Makefile.am
src/lightdm-gtk-builder-greeter.c

index e20d301..e778758 100644 (file)
@@ -108,6 +108,8 @@ AC_CONFIG_FILES([
     data/themes/Makefile
     data/themes/Industrial/Makefile
     data/themes/Industrial/index.theme
+    data/themes/Dusty/Makefile
+    data/themes/Dusty/index.theme
     po/Makefile.in
 ])
 
index 3e6a7f6..076497c 100644 (file)
@@ -4,6 +4,11 @@ SUBDIRS= \
        themes \
        $(NULL)
 
+uidir=$(datadir)/lightdm-gtk-builder-greeter/ui
+ui_DATA= \
+       ui/chooser.ui \
+       $(NULL)
+
 xgreetersdir = $(datadir)/xgreeters
 xgreeters_in_files = \
        lightdm-gtk-builder-greeter.desktop
@@ -25,6 +30,7 @@ glade_DATA=
 endif
 
 EXTRA_DIST= \
+       $(ui_DATA) \
        $(xgreeters_DATA) \
        $(config_DATA) \
        $(glade_DATA) \
diff --git a/data/themes/Dusty/Makefile.am b/data/themes/Dusty/Makefile.am
new file mode 100644 (file)
index 0000000..d2cb508
--- /dev/null
@@ -0,0 +1,19 @@
+NULL=
+
+themedir=$(datadir)/lightdm-gtk-builder-greeter/themes/Dusty
+theme_DATA= \
+       greeter-gtk2.ui \
+       gtk2.rc \
+       index.theme \
+       arrow_left.png \
+       arrow_right.png \
+       arrow_up.png \
+       bg.jpg \
+       halt.png \
+       reboot.png \
+       suspend.png \
+       $(NULL)
+
+EXTRA_DIST= \
+       $(theme_DATA) \
+       $(NULL)
diff --git a/data/themes/Dusty/arrow_left.png b/data/themes/Dusty/arrow_left.png
new file mode 100644 (file)
index 0000000..09c6658
Binary files /dev/null and b/data/themes/Dusty/arrow_left.png differ
diff --git a/data/themes/Dusty/arrow_right.png b/data/themes/Dusty/arrow_right.png
new file mode 100644 (file)
index 0000000..e260468
Binary files /dev/null and b/data/themes/Dusty/arrow_right.png differ
diff --git a/data/themes/Dusty/arrow_up.png b/data/themes/Dusty/arrow_up.png
new file mode 100644 (file)
index 0000000..340a965
Binary files /dev/null and b/data/themes/Dusty/arrow_up.png differ
diff --git a/data/themes/Dusty/bg.jpg b/data/themes/Dusty/bg.jpg
new file mode 100644 (file)
index 0000000..6eabc89
Binary files /dev/null and b/data/themes/Dusty/bg.jpg differ
diff --git a/data/themes/Dusty/greeter-gtk2.ui b/data/themes/Dusty/greeter-gtk2.ui
new file mode 100644 (file)
index 0000000..80dd897
--- /dev/null
@@ -0,0 +1,387 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <!-- interface-requires gtk+ 2.12 -->
+  <!-- interface-requires ldmwidget 0.0 -->
+  <!-- interface-naming-policy project-wide -->
+  <object class="GtkWindow" id="win">
+    <property name="can_focus">False</property>
+    <child>
+      <object class="LdmLayout" id="top_box">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="image">bg.jpg</property>
+        <property name="color">#000000000000</property>
+        <property name="alpha">0</property>
+        <child>
+          <object class="GtkVBox" id="vbox2">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <child>
+              <object class="GtkLabel" id="time">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="xalign">1</property>
+                <property name="xpad">12</property>
+                <property name="ypad">12</property>
+                <property name="single_line_mode">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="LdmAlignment" id="ldm_alignment1">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="top_padding">20</property>
+                <property name="bottom_padding">20</property>
+                <property name="left_padding">30</property>
+                <property name="right_padding">30</property>
+                <property name="color">#000000000000</property>
+                <property name="alpha">0.14999999999999999</property>
+                <child>
+                  <object class="GtkVBox" id="vbox1">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <child>
+                      <object class="GtkLabel" id="prompt">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="label" translatable="yes">login:</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkEntry" id="login_entry">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="invisible_char">‚óŹ</property>
+                        <property name="invisible_char_set">True</property>
+                        <property name="primary_icon_activatable">False</property>
+                        <property name="secondary_icon_activatable">False</property>
+                        <property name="primary_icon_sensitive">True</property>
+                        <property name="secondary_icon_sensitive">True</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkHBox" id="middle_hbox">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="spacing">20</property>
+                        <child>
+                          <object class="GtkButton" id="lang_btn">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">True</property>
+                            <property name="use_action_appearance">False</property>
+                            <property name="relief">none</property>
+                            <child>
+                              <object class="GtkHBox" id="hbox4">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <child>
+                                  <object class="GtkImage" id="image6">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="pixbuf">arrow_left.png</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">True</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkLabel" id="label6">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="label" translatable="yes">Language</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">True</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkImage" id="image7">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="pixbuf">arrow_right.png</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">True</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">2</property>
+                                  </packing>
+                                </child>
+                              </object>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">True</property>
+                            <property name="fill">True</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkButton" id="sessions_btn">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">True</property>
+                            <property name="use_action_appearance">False</property>
+                            <property name="relief">none</property>
+                            <child>
+                              <object class="GtkHBox" id="hbox3">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <child>
+                                  <object class="GtkImage" id="image4">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="pixbuf">arrow_left.png</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">True</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkLabel" id="label5">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="label" translatable="yes">Session</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">True</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkImage" id="image5">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="pixbuf">arrow_right.png</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">True</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">2</property>
+                                  </packing>
+                                </child>
+                              </object>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">True</property>
+                            <property name="fill">True</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="expand">True</property>
+                        <property name="fill">True</property>
+                        <property name="position">2</property>
+                      </packing>
+                    </child>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="x_align">0.5</property>
+            <property name="y_align">0.5</property>
+          </packing>
+        </child>
+        <child>
+          <object class="LdmLayout" id="bottom_pane">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="color">#000000000000</property>
+            <property name="alpha">0.14999999999999999</property>
+            <child>
+              <object class="GtkHBox" id="bottom_hbox">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="border_width">6</property>
+                <property name="spacing">12</property>
+                <child>
+                  <object class="GtkHBox" id="hbox1">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <child>
+                      <object class="GtkButton" id="shutdown_btn">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">True</property>
+                        <property name="use_action_appearance">False</property>
+                        <property name="relief">none</property>
+                        <child>
+                          <object class="GtkVBox" id="vbox5">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <child>
+                              <object class="GtkImage" id="image3">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="pixbuf">halt.png</property>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkLabel" id="label4">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="label" translatable="yes">Shutdown</property>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                          </object>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="pack_type">end</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkButton" id="restart_btn">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">True</property>
+                        <property name="use_action_appearance">False</property>
+                        <property name="relief">none</property>
+                        <child>
+                          <object class="GtkVBox" id="vbox3">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <child>
+                              <object class="GtkImage" id="image1">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="pixbuf">reboot.png</property>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkLabel" id="label1">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="label" translatable="yes">Restart</property>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                          </object>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="expand">True</property>
+                        <property name="fill">True</property>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkButton" id="suspend_btn">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">True</property>
+                        <property name="use_action_appearance">False</property>
+                        <property name="relief">none</property>
+                        <child>
+                          <object class="GtkVBox" id="vbox4">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <child>
+                              <object class="GtkImage" id="image2">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="pixbuf">suspend.png</property>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkLabel" id="label3">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="label" translatable="yes">Suspend</property>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                          </object>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="expand">True</property>
+                        <property name="fill">True</property>
+                        <property name="position">2</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="pack_type">end</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="width">100%</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="bottom_padding">0</property>
+            <property name="width">100%</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </object>
+</interface>
diff --git a/data/themes/Dusty/gtk2.rc b/data/themes/Dusty/gtk2.rc
new file mode 100644 (file)
index 0000000..ac7eb49
--- /dev/null
@@ -0,0 +1,22 @@
+style "time"
+{
+    fg[NORMAL]="#ffffff"
+    font_name="Sans 12"
+}
+
+style "prompt"
+{
+    fg[NORMAL]="#ffffff"
+    font_name="Sans Bold 14"
+}
+
+style "bottom"
+{
+    fg[NORMAL]="#ffffff"
+    font_name="Sans 12"
+}
+
+widget "win.*.time" style "time"
+widget "win.*.prompt" style "prompt"
+widget "win.*.bottom_hbox.*" style "bottom"
+widget "win.*.middle_hbox.*" style "bottom"
diff --git a/data/themes/Dusty/halt.png b/data/themes/Dusty/halt.png
new file mode 100644 (file)
index 0000000..2db6dd0
Binary files /dev/null and b/data/themes/Dusty/halt.png differ
diff --git a/data/themes/Dusty/index.theme.in b/data/themes/Dusty/index.theme.in
new file mode 100644 (file)
index 0000000..c7733ca
--- /dev/null
@@ -0,0 +1,5 @@
+[theme]
+name=Dusty
+description=The Dusty Theme ported from gdm
+author=ClearenGlish;Hong Jen Yee(PCMan) <pcman.tw@gmail.com>
+license=GPL
diff --git a/data/themes/Dusty/reboot.png b/data/themes/Dusty/reboot.png
new file mode 100644 (file)
index 0000000..bd9e954
Binary files /dev/null and b/data/themes/Dusty/reboot.png differ
diff --git a/data/themes/Dusty/suspend.png b/data/themes/Dusty/suspend.png
new file mode 100644 (file)
index 0000000..d83d5fe
Binary files /dev/null and b/data/themes/Dusty/suspend.png differ
index 97076e1..733220a 100644 (file)
@@ -2,4 +2,5 @@ NULL=
 
 SUBDIRS= \
        Industrial \
+       Dusty \
        $(NULL)
diff --git a/data/ui/chooser.ui b/data/ui/chooser.ui
new file mode 100644 (file)
index 0000000..8f5a47e
--- /dev/null
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <requires lib="gtk+" version="2.24"/>
+  <!-- interface-naming-policy project-wide -->
+  <object class="GtkDialog" id="dlg">
+    <property name="can_focus">False</property>
+    <property name="border_width">10</property>
+    <property name="default_width">320</property>
+    <property name="default_height">400</property>
+    <property name="type_hint">dialog</property>
+    <child internal-child="vbox">
+      <object class="GtkVBox" id="dialog-vbox1">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="spacing">6</property>
+        <child internal-child="action_area">
+          <object class="GtkHButtonBox" id="dialog-action_area1">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="cancel">
+                <property name="label">gtk-cancel</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_action_appearance">False</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="ok">
+                <property name="label">gtk-ok</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_action_appearance">False</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="message">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="xalign">0</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkScrolledWindow" id="scrolledwindow1">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="hscrollbar_policy">never</property>
+            <property name="vscrollbar_policy">automatic</property>
+            <property name="shadow_type">etched-in</property>
+            <child>
+              <object class="GtkTreeView" id="view">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="headers_visible">False</property>
+                <child>
+                  <object class="GtkTreeViewColumn" id="treeviewcolumn1">
+                    <property name="title" translatable="yes">column</property>
+                    <child>
+                      <object class="GtkCellRendererText" id="cellrenderertext1"/>
+                      <attributes>
+                        <attribute name="text">0</attribute>
+                      </attributes>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">True</property>
+            <property name="fill">True</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="-6">cancel</action-widget>
+      <action-widget response="-5">ok</action-widget>
+    </action-widgets>
+  </object>
+</interface>
index 4381408..97f1994 100644 (file)
@@ -6,5 +6,5 @@ src/ldm-layout.c
 src/lightdm-gtk-builder-greeter.c
 
 data/lightdm-gtk-builder-greeter.desktop.in
-data/themes/Industrial/index.theme.in
 [type: gettext/glade]data/themes/Industrial/greeter-gtk2.ui
+[type: gettext/glade]data/themes/Dusty/greeter-gtk2.ui
index 6cfeff1..7af308e 100644 (file)
@@ -4,6 +4,7 @@ AM_CPPFLAGS = \
        -I$(srcdir) \
        -DCONFIG_DIR=\""$(sysconfdir)/lightdm"\" \
        -DPACKAGE_DATA_DIR=\""$(datadir)/lightdm-gtk-builder-greeter"\" \
+       -DPACKAGE_UI_DIR=\""$(datadir)/lightdm-gtk-builder-greeter/ui"\" \
        -DPACKAGE_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \
        $(NULL)
 
index cf99e84..e25d8c5 100644 (file)
@@ -44,23 +44,39 @@ static char* test_dir = NULL;
 static LightDMGreeter *greeter = NULL;
 static char* theme_dir = NULL;
 
-static GtkWidget* win;
-static GtkWidget* prompt;
-static GtkWidget* login_entry;
-
-static GtkWidget* user_list;
-
-static GtkWidget* sessions_combo;
-static GtkWidget* lang_combo;
-
-static GtkWidget* exit_btn;
-
-static GtkWidget* exit_menu;
+static GtkWidget* win = NULL;
+static GtkWidget* prompt = NULL;
+static GtkWidget* login_entry = NULL;
+
+/* in the future, we'll support user list. */
+static GtkWidget* user_list = NULL;
+
+/* the user can use either a combobox or a button to select a session */
+static GtkListStore* sessions_model = NULL;
+static GtkWidget* sessions_combo = NULL;
+static GtkWidget* sessions_btn = NULL;
+GtkTreeIter selected_session_it = {0};
+
+/* the user can use either a combobox or a button to select a language */
+static GtkListStore* languages_model = NULL;
+static GtkWidget* lang_combo = NULL;
+static GtkWidget* lang_btn = NULL;
+GtkTreeIter selected_language_it = {0};
+
+/* exit button popups a menu with suspend, restart, shutdown options inside. */
+static GtkWidget* exit_btn = NULL;
+static GtkWidget* exit_menu = NULL;
+
+/* or the theme authors can use the buttons directly */
+static GtkWidget* suspend_btn = NULL;
+static GtkWidget* hibernate_btn = NULL;
+static GtkWidget* shutdown_btn = NULL;
+static GtkWidget* restart_btn = NULL;
 
 static GOptionEntry option_entries[] =
 {
     {"test-dir", 't', G_OPTION_FLAG_FILENAME, G_OPTION_ARG_FILENAME, &test_dir, "Test theme dir", "<dir>"},
-    { NULL }
+    {0}
 };
 
 static void select_language(const char *lang);
@@ -82,7 +98,9 @@ static void select_session(const char *session)
             gtk_tree_model_get(model, &iter, 1, &key, -1);
             if(g_strcmp0(key, session) == 0)
             {
-                gtk_combo_box_set_active_iter(GTK_COMBO_BOX(sessions_combo), &iter);
+                if(sessions_combo)
+                    gtk_combo_box_set_active_iter(GTK_COMBO_BOX(sessions_combo), &iter);
+                selected_session_it = iter;
                 g_free(key);
                 break;
             }
@@ -125,12 +143,10 @@ static void on_show_prompt(LightDMGreeter *greeter, gchar* text,
 
 static const char* get_selected_language()
 {
-    GtkTreeIter it;
-    if(gtk_combo_box_get_active_iter(GTK_COMBO_BOX(lang_combo), &it))
+    if(selected_language_it.stamp != 0) /* valid */
     {
         LightDMLanguage* lang;
-        GtkTreeModel* model = gtk_combo_box_get_model(GTK_COMBO_BOX(lang_combo));
-        gtk_tree_model_get(model, &it, 1, &lang, -1);
+        gtk_tree_model_get(languages_model, &selected_language_it, 1, &lang, -1);
         if(lang)
             g_object_unref(lang);
         return lightdm_language_get_code(lang);
@@ -150,7 +166,9 @@ static void select_language(const char *lang)
             gtk_tree_model_get(model, &iter, 1, &language, -1);
             if(g_strcmp0(lightdm_language_get_code(language), lang) == 0)
             {
-                gtk_combo_box_set_active_iter(GTK_COMBO_BOX(lang_combo), &iter);
+                if(lang_combo)
+                    gtk_combo_box_set_active_iter(GTK_COMBO_BOX(lang_combo), &iter);
+                selected_language_it = iter;
                 break;
             }
         }
@@ -162,12 +180,8 @@ static void authenticate_user(const gchar *username)
 {
     LightDMUser *user;
     user = lightdm_user_list_get_user_by_name(lightdm_user_list_get_instance(), username);
-    g_debug("authenticate user: %s", user);
     if(user)
-    {
         select_session(lightdm_user_get_session(user));
-        g_debug("user session: %s", lightdm_user_get_session(user));
-    }
     else
         select_session(NULL);
     lightdm_greeter_authenticate(greeter, username);
@@ -175,13 +189,9 @@ static void authenticate_user(const gchar *username)
 
 static gchar *get_selected_session()
 {
-    GtkTreeIter it;
     char* session = NULL;
-    if(gtk_combo_box_get_active_iter(GTK_COMBO_BOX(sessions_combo), &it))
-    {
-        GtkTreeModel* model = gtk_combo_box_get_model(GTK_COMBO_BOX(sessions_combo));
-        gtk_tree_model_get(model, &it, 1, &session, -1);
-    }
+    if(selected_session_it.stamp != 0) /* valid iter */
+        gtk_tree_model_get(sessions_model, &selected_session_it, 1, &session, -1);
     return session;
 }
 
@@ -265,7 +275,7 @@ static gboolean on_combobox_entry_button_release(GtkWidget* w, GdkEventButton* e
     return FALSE;
 }
 
-static void fix_combobox_entry(GtkWidget* combo)
+static void init_combobox_entry(GtkWidget* combo)
 {
     GtkWidget* edit = gtk_bin_get_child(GTK_BIN(combo));
     gtk_editable_set_editable( (GtkEditable*)edit, FALSE );
@@ -280,14 +290,80 @@ static gboolean on_timeout(GtkLabel* label)
     struct tm* tmbuf;
     time(&t);
     tmbuf = localtime(&t);
+    /* TODO: make format of time configurable. */
     strftime(buf, 128, "%c", tmbuf);
     gtk_label_set_text(label, buf);
     return TRUE;
 }
 
-static void load_sessions()
+static gboolean select_from_model(const char* title, const char* prompt_msg, GtkTreeModel* model, GtkTreeIter* selected_it)
+{
+    gboolean ret = FALSE;
+    GtkBuilder* builder = gtk_builder_new();
+    if(gtk_builder_add_from_file(builder, PACKAGE_UI_DIR "/chooser.ui", NULL))
+    {
+        GtkDialog* dlg = GTK_DIALOG(gtk_builder_get_object(builder, "dlg"));
+        GtkLabel* message = GTK_LABEL(gtk_builder_get_object(builder, "message"));
+        GtkTreeView* view = GTK_TREE_VIEW(gtk_builder_get_object(builder, "view"));
+        GtkTreeSelection* tree_sel = gtk_tree_view_get_selection(view);
+
+        gtk_window_set_title(GTK_WINDOW(dlg), title);
+        gtk_label_set_text(message, prompt_msg);
+
+        gtk_tree_view_set_model(view, model);
+        gtk_tree_selection_set_mode(tree_sel, GTK_SELECTION_BROWSE);
+        gtk_tree_selection_select_iter(tree_sel, selected_it);
+
+        if(gtk_dialog_run(dlg) == GTK_RESPONSE_OK)
+        {
+            gtk_tree_selection_get_selected(tree_sel, NULL, selected_it);
+            ret = TRUE;
+        }
+        gtk_widget_destroy(GTK_WIDGET(dlg));
+    }
+    g_object_unref(builder);
+
+    /* focus the entry again */
+    if(login_entry)
+        gtk_widget_grab_focus(login_entry);
+    return ret;
+}
+
+static void on_sessions_btn_clicked(GtkButton* btn, gpointer user_data)
+{
+    /* ask the user to select a desktop session */
+    if(select_from_model(_("Desktop Sessions"),
+        _("Select a desktop session:"),
+        GTK_TREE_MODEL(sessions_model), &selected_session_it))
+    {
+        gtk_combo_box_set_active_iter(sessions_combo, &selected_session_it);
+    }
+}
+
+static void on_languages_btn_clicked(GtkButton* btn, gpointer user_data)
+{
+    /* ask the user to select a language */
+    if(select_from_model(_("Languages"),
+        _("Select a language:"),
+        GTK_TREE_MODEL(languages_model), &selected_language_it))
+    {
+        gtk_combo_box_set_active_iter(lang_combo, &selected_language_it);
+    }
+}
+
+static void on_sessions_combo_changed(GtkComboBox* combo, gpointer user_data)
+{
+    gtk_combo_box_get_active_iter(combo, &selected_session_it);
+}
+
+static void on_languages_combo_changed(GtkComboBox* combo, gpointer user_data)
 {
-    GtkTreeIter it, active_it = {0};
+    gtk_combo_box_get_active_iter(combo, &selected_language_it);
+}
+
+static void init_sessions(GtkBuilder* builder)
+{
+    GtkTreeIter it;
     const char* default_session = lightdm_greeter_get_default_session_hint(greeter);
     const GList* sessions = lightdm_get_sessions();
     const GList* l;
@@ -302,22 +378,33 @@ static void load_sessions()
                                           0, name,
                                           1, key, -1);
         if(g_strcmp0(key, default_session) == 0)
-            active_it = it;
+            selected_session_it = it;
     }
+    sessions_model = store;
 
-    gtk_combo_box_set_model(GTK_COMBO_BOX(sessions_combo), GTK_TREE_MODEL(store));
-    gtk_combo_box_entry_set_text_column(GTK_COMBO_BOX_ENTRY(sessions_combo), 0);
-    if( active_it.stamp )
-        gtk_combo_box_set_active_iter(GTK_COMBO_BOX(sessions_combo), &active_it);
-    else
-        gtk_combo_box_set_active(GTK_COMBO_BOX(sessions_combo), 0);
+    /* session selection combo box is used */
+    sessions_combo = (GtkWidget*)gtk_builder_get_object(builder, "sessions");
+    if(sessions_combo)
+    {
+        init_combobox_entry(sessions_combo);
+        g_signal_connect(sessions_combo, "changed", G_CALLBACK(on_sessions_combo_changed), NULL);
+
+        gtk_combo_box_set_model(GTK_COMBO_BOX(sessions_combo), GTK_TREE_MODEL(store));
+        gtk_combo_box_entry_set_text_column(GTK_COMBO_BOX_ENTRY(sessions_combo), 0);
+        if(selected_session_it.stamp == 0) /* invalid */
+            gtk_tree_model_get_iter_first(sessions_model, &selected_session_it);
+        gtk_combo_box_set_active_iter(GTK_COMBO_BOX(sessions_combo), &selected_session_it);
+    }
 
-    g_object_unref(store);
+    /* session selection button */
+    sessions_btn = (GtkWidget*)gtk_builder_get_object(builder, "sessions_btn");
+    if(sessions_btn)
+        g_signal_connect(sessions_btn, "clicked", G_CALLBACK(on_sessions_btn_clicked), NULL);
 }
 
-static void load_languages()
+static void init_languages(GtkBuilder* builder)
 {
-    GtkTreeIter it, active_it = {0};
+    GtkTreeIter it;
     const LightDMLanguage* default_lang = lightdm_get_language();
     const GList* langs = lightdm_get_languages();
     const GList* l;
@@ -332,17 +419,26 @@ static void load_languages()
         gtk_list_store_insert_with_values(list, &it, -1, 0, title, 1, lang, -1);
         g_free(title);
         if(default_lang == lang)
-            active_it = it;
+            selected_language_it = it;
     }
+    languages_model = list;
 
-    gtk_combo_box_set_model( GTK_COMBO_BOX(lang_combo), GTK_TREE_MODEL(list) );
-    gtk_combo_box_entry_set_text_column(GTK_COMBO_BOX_ENTRY(lang_combo), 0);
-    if( active_it.stamp )
-        gtk_combo_box_set_active_iter(GTK_COMBO_BOX(lang_combo), &active_it);
-    else
-        gtk_combo_box_set_active(GTK_COMBO_BOX(lang_combo), 0);
+    lang_combo = (GtkWidget*)gtk_builder_get_object(builder, "lang");
+    if(lang_combo)
+    {
+        init_combobox_entry(lang_combo);
+        g_signal_connect(sessions_combo, "changed", G_CALLBACK(on_languages_combo_changed), NULL);
+
+        gtk_combo_box_set_model( GTK_COMBO_BOX(lang_combo), GTK_TREE_MODEL(list) );
+        gtk_combo_box_entry_set_text_column(GTK_COMBO_BOX_ENTRY(lang_combo), 0);
+        if(selected_language_it.stamp == 0) /* invalid iter */
+            gtk_tree_model_get_iter_first(languages_model, &selected_language_it);
+        gtk_combo_box_set_active_iter(GTK_COMBO_BOX(lang_combo), &selected_language_it);
+    }
 
-    g_object_unref(list);
+    lang_btn = (GtkWidget*)gtk_builder_get_object(builder, "lang_btn");
+    if(lang_btn)
+        g_signal_connect(lang_btn, "clicked", G_CALLBACK(on_languages_btn_clicked), NULL);
 }
 
 static void on_exit_btn_clicked(GtkButton* btn, GtkMenu* menu)
@@ -358,7 +454,8 @@ static void show_error(const char* title, const char* message)
     gtk_widget_destroy(dlg);
 }
 
-static void on_suspend(GtkMenuItem* item, gpointer user_data)
+/* item can be a GtkButton or a GtkMenuItem */
+static void on_suspend(GtkWidget* item, gpointer user_data)
 {
     GError* error = NULL;
     if(!lightdm_suspend(&error))
@@ -368,7 +465,8 @@ static void on_suspend(GtkMenuItem* item, gpointer user_data)
     }
 }
 
-static void on_hibernate(GtkMenuItem* item, gpointer user_data)
+/* item can be a GtkButton or a GtkMenuItem */
+static void on_hibernate(GtkWidget* item, gpointer user_data)
 {
     GError* error = NULL;
     if(!lightdm_hibernate(&error))
@@ -378,7 +476,8 @@ static void on_hibernate(GtkMenuItem* item, gpointer user_data)
     }
 }
 
-static void on_restart(GtkMenuItem* item, gpointer user_data)
+/* item can be a GtkButton or a GtkMenuItem */
+static void on_restart(GtkWidget* item, gpointer user_data)
 {
     GError* error = NULL;
     if(!lightdm_restart(&error))
@@ -388,7 +487,8 @@ static void on_restart(GtkMenuItem* item, gpointer user_data)
     }
 }
 
-static void on_shutdown(GtkMenuItem* item, gpointer user_data)
+/* item can be a GtkButton or a GtkMenuItem */
+static void on_shutdown(GtkWidget* item, gpointer user_data)
 {
     GError* error = NULL;
     if(!lightdm_shutdown(&error))
@@ -398,37 +498,56 @@ static void on_shutdown(GtkMenuItem* item, gpointer user_data)
     }
 }
 
-static void load_exit_btn()
+static void load_exit_buttons(GtkBuilder* builder)
 {
-    GtkWidget* menu = gtk_menu_new();
-    GtkWidget* item;
-    if(lightdm_get_can_suspend())
-    {
-        item = gtk_menu_item_new_with_label(_("Suspend"));
-        gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
-        g_signal_connect(item, "activate", G_CALLBACK(on_suspend), NULL);
-    }
-    if(lightdm_get_can_hibernate())
-    {
-        item = gtk_menu_item_new_with_label(_("Hibernate"));
-        gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
-        g_signal_connect(item, "activate", G_CALLBACK(on_hibernate), NULL);
-    }
-    if(lightdm_get_can_restart())
-    {
-        item = gtk_menu_item_new_with_label(_("Restart"));
-        gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
-        g_signal_connect(item, "activate", G_CALLBACK(on_restart), NULL);
-    }
-    if(lightdm_get_can_shutdown())
+    exit_btn = GTK_WIDGET(gtk_builder_get_object(builder, "exit_btn"));
+
+    suspend_btn = GTK_WIDGET(gtk_builder_get_object(builder, "suspend_btn"));
+    hibernate_btn = GTK_WIDGET(gtk_builder_get_object(builder, "hibernate_btn"));
+    shutdown_btn = GTK_WIDGET(gtk_builder_get_object(builder, "shutdown_btn"));
+    restart_btn = GTK_WIDGET(gtk_builder_get_object(builder, "restart_btn"));
+
+    if(exit_btn)
     {
-        item = gtk_menu_item_new_with_label(_("Shutdown"));
-        gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
-        g_signal_connect(item, "activate", G_CALLBACK(on_shutdown), NULL);
+        GtkWidget* menu = gtk_menu_new();
+        GtkWidget* item;
+        if(lightdm_get_can_suspend())
+        {
+            item = gtk_menu_item_new_with_label(_("Suspend"));
+            gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+            g_signal_connect(item, "activate", G_CALLBACK(on_suspend), NULL);
+        }
+        if(lightdm_get_can_hibernate())
+        {
+            item = gtk_menu_item_new_with_label(_("Hibernate"));
+            gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+            g_signal_connect(item, "activate", G_CALLBACK(on_hibernate), NULL);
+        }
+        if(lightdm_get_can_restart())
+        {
+            item = gtk_menu_item_new_with_label(_("Restart"));
+            gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+            g_signal_connect(item, "activate", G_CALLBACK(on_restart), NULL);
+        }
+        if(lightdm_get_can_shutdown())
+        {
+            item = gtk_menu_item_new_with_label(_("Shutdown"));
+            gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+            g_signal_connect(item, "activate", G_CALLBACK(on_shutdown), NULL);
+        }
+        gtk_widget_show_all(menu);
+        g_signal_connect_swapped(exit_btn, "destroy", G_CALLBACK(gtk_widget_destroy), menu);
+        g_signal_connect(exit_btn, "clicked", G_CALLBACK(on_exit_btn_clicked), menu);
     }
-    gtk_widget_show_all(menu);
-    g_signal_connect_swapped(exit_btn, "destroy", G_CALLBACK(gtk_widget_destroy), menu);
-    g_signal_connect(exit_btn, "clicked", G_CALLBACK(on_exit_btn_clicked), menu);
+
+    if(suspend_btn)
+        g_signal_connect(suspend_btn, "clicked", G_CALLBACK(on_suspend), NULL);
+    if(hibernate_btn)
+        g_signal_connect(suspend_btn, "clicked", G_CALLBACK(on_hibernate), NULL);
+    if(shutdown_btn)
+        g_signal_connect(suspend_btn, "clicked", G_CALLBACK(on_shutdown), NULL);
+    if(restart_btn)
+        g_signal_connect(suspend_btn, "clicked", G_CALLBACK(on_restart), NULL);
 }
 
 static void on_login_entry_activate(GtkEntry* entry, gpointer user_data)
@@ -497,13 +616,8 @@ static gboolean show_ui()
     }
 #endif
 
-    sessions_combo = (GtkWidget*)gtk_builder_get_object(builder, "sessions");
-    fix_combobox_entry(sessions_combo);
-    load_sessions();
-
-    lang_combo = (GtkWidget*)gtk_builder_get_object(builder, "lang");
-    fix_combobox_entry(lang_combo);
-    load_languages();
+    init_sessions(builder);
+    init_languages(builder);
 
     if( w = (GtkWidget*)gtk_builder_get_object(builder, "time") )
     {
@@ -513,8 +627,8 @@ static gboolean show_ui()
         on_timeout((GtkLabel*)w);
     }
 
-    exit_btn = (GtkWidget*)gtk_builder_get_object(builder, "exit_btn");
-    load_exit_btn();
+    /* load "Exit", "Shutdown", "Reboot",...etc. */
+    load_exit_buttons(builder);
 
     g_object_unref(builder);
 
@@ -570,7 +684,7 @@ int main(int argc, char** argv)
     g_signal_connect(greeter, "authentication-complete", G_CALLBACK(on_authentication_complete), NULL);
     g_signal_connect(greeter, "autologin-timer-expired", G_CALLBACK(on_autologin_timer_expired), NULL);
 
-    if(!lightdm_greeter_connect_sync(greeter, NULL))
+    if(!test_dir && !lightdm_greeter_connect_sync(greeter, NULL))
     {
         g_print("Error: unable to connect to lightdm deamon.\n");
         return 1;
@@ -635,7 +749,8 @@ int main(int argc, char** argv)
      * IMO, whether to show user list or not is theme specific.
      * For now, we do not support user list. */
     /* if (lightdm_greeter_get_hide_users_hint (greeter)) */
-    lightdm_greeter_authenticate(greeter, NULL);
+    if(!test_dir)
+        lightdm_greeter_authenticate(greeter, NULL);
 
     gtk_main();