diff --git a/i3bar/include/config.h b/i3bar/include/config.h
index c648671..e716e0a 100644
--- a/i3bar/include/config.h
+++ b/i3bar/include/config.h
@@ -21,6 +21,9 @@ typedef enum {
 typedef struct config_t {
     int          modifier;
     position_t   position;
+    int          panel_size;
+    int          tray_icon_size;
+    int          tray_icon_padding;
     int          verbose;
     struct xcb_color_strings_t colors;
     bool         disable_binding_mode_indicator;
diff --git a/i3bar/src/config.c b/i3bar/src/config.c
index 5ac31b1..40627ea 100644
--- a/i3bar/src/config.c
+++ b/i3bar/src/config.c
@@ -188,6 +188,44 @@ static int config_string_cb(void *params_, const unsigned char *val, unsigned in
     return 0;
 }
 
+#if YAJL_MAJOR >= 2
+static int config_integer_cb(void *params_, long long val) {
+#else
+static int config_integer_cb(void *params_, long val) {
+#endif
+    if (!strcmp(cur_key, "panel_size")) {
+        if (val < 0)
+            config.panel_size = 0;
+        else if (val > INT16_MAX)
+            config.panel_size = INT16_MAX;
+        else
+            config.panel_size = (int)val;
+        return 1;
+    }
+    
+    if (!strcmp(cur_key, "tray_icon_size")) {
+        if (val < 0)
+            config.tray_icon_size = 0;
+        else if (val > INT16_MAX)
+            config.tray_icon_size = INT16_MAX;
+        else
+            config.tray_icon_size = (int)val;
+        return 1;
+    }
+    
+    if (!strcmp(cur_key, "tray_icon_padding")) {
+        if (val < 0)
+            config.tray_icon_padding = 0;
+        else if (val > INT16_MAX)
+            config.tray_icon_padding = INT16_MAX;
+        else
+            config.tray_icon_padding = (int)val;
+        return 1;
+    }
+    
+    return 0;
+}
+
 /*
  * Parse a boolean value
  *
@@ -216,14 +254,14 @@ static int config_boolean_cb(void *params_, int val) {
 
 /* A datastructure to pass all these callbacks to yajl */
 static yajl_callbacks outputs_callbacks = {
-    &config_null_cb,
-    &config_boolean_cb,
-    NULL,
+    config_null_cb,
+    config_boolean_cb,
+    config_integer_cb,
     NULL,
     NULL,
-    &config_string_cb,
+    config_string_cb,
     NULL,
-    &config_map_key_cb,
+    config_map_key_cb,
     NULL,
     NULL,
     NULL
diff --git a/i3bar/src/xcb.c b/i3bar/src/xcb.c
index 8286103..963cac6 100644
--- a/i3bar/src/xcb.c
+++ b/i3bar/src/xcb.c
@@ -62,6 +62,10 @@ static i3Font font;
 /* Overall height of the bar (based on font size) */
 int bar_height;
 
+/* Size of each tray icon */
+int tray_icon_size;
+int tray_icon_padding;
+
 /* These are only relevant for XKB, which we only need for grabbing modifiers */
 Display          *xkb_dpy;
 int              xkb_event_base;
@@ -372,7 +376,7 @@ void handle_button(xcb_button_press_event_t *event) {
                 TAILQ_FOREACH_REVERSE(trayclient, walk->trayclients, tc_head, tailq) {
                     if (!trayclient->mapped)
                         continue;
-                    tray_width += (font.height + 2);
+                    tray_width += tray_icon_size + 2;
                 }
 
                 int block_x = 0, last_block_x;
@@ -452,8 +456,8 @@ static void configure_trayclients(void) {
             clients++;
 
             DLOG("Configuring tray window %08x to x=%d\n",
-                 trayclient->win, output->rect.w - (clients * (font.height + 2)));
-            uint32_t x = output->rect.w - (clients * (font.height + 2));
+                 trayclient->win, output->rect.w - (clients * (tray_icon_size + 2)));
+            uint32_t x = output->rect.w - (clients * (tray_icon_size + 2));
             xcb_configure_window(xcb_connection,
                                  trayclient->win,
                                  XCB_CONFIG_WINDOW_X,
@@ -563,16 +567,16 @@ static void handle_client_message(xcb_client_message_event_t* event) {
             xcb_reparent_window(xcb_connection,
                                 client,
                                 output->bar,
-                                output->rect.w - font.height - 2,
-                                2);
+                                output->rect.w - tray_icon_size - 2,
+                                (bar_height - tray_icon_size)/2);
             /* We reconfigure the window to use a reasonable size. The systray
              * specification explicitly says:
              *   Tray icons may be assigned any size by the system tray, and
              *   should do their best to cope with any size effectively
              */
             mask = XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
-            values[0] = font.height;
-            values[1] = font.height;
+            values[0] = tray_icon_size;
+            values[1] = tray_icon_size;
             xcb_configure_window(xcb_connection,
                                  client,
                                  mask,
@@ -802,10 +806,10 @@ static void handle_configure_request(xcb_configure_request_event_t *event) {
                 continue;
 
             xcb_rectangle_t rect;
-            rect.x = output->rect.w - (clients * (font.height + 2));
-            rect.y = 2;
-            rect.width = font.height;
-            rect.height = font.height;
+            rect.x = output->rect.w - (clients * (tray_icon_size + 2));
+            rect.y = (bar_height - tray_icon_size)/2;
+            rect.width = tray_icon_size;
+            rect.height = tray_icon_size;
 
             DLOG("This is a tray window. x = %d\n", rect.x);
             fake_configure_notify(xcb_connection, rect, event->window, 0);
@@ -1094,6 +1098,29 @@ void deregister_xkb_keyevents() {
     }
 }
 
+static int select_optimal_tray_icon_size(int max_size)
+{
+    /* Return max_size if we cannot get 16x16 icon to fit */
+    if (max_size < 16)
+        return max_size;
+    
+    if (max_size < 32) {
+        if (max_size < 22)
+            return 16;
+        if (max_size < 24)
+            return 22;
+        return 24;
+    }
+    else if (max_size < 256) {
+        if (max_size < 48)
+            return 32;
+        if (max_size < 128)
+            return 48;
+        return 128;
+    }
+    return 256;
+}
+
 /*
  * Initialization which depends on 'config' being usable. Called after the
  * configuration has arrived.
@@ -1107,7 +1134,34 @@ void init_xcb_late(char *fontname) {
     font = load_font(fontname, true);
     set_font(&font);
     DLOG("Calculated Font-height: %d\n", font.height);
+    
     bar_height = font.height + 6;
+    
+    if (config.panel_size > bar_height)
+        bar_height = config.panel_size;
+    
+    if (config.tray_icon_size != 0) {
+        /* Tray icon size is set */
+        
+        if (config.tray_icon_size < bar_height) {
+            /* It is smaller than bar size, use it */
+            tray_icon_size = config.tray_icon_size;
+        }
+        else if (config.panel_size == 0) {
+            /* Panel size is not set and tray icon is larger than font-size based
+             * panel height -> Increase the panel height */
+            bar_height = config.tray_icon_size;
+            tray_icon_size = config.tray_icon_size;
+        }
+        else {
+            /* Panel size is set and tray icon is too large. Use maximum size */
+            tray_icon_size = bar_height;
+        }
+    }
+    else {
+        /* Tray icon size is not set. Use some magic to detect it */
+        tray_icon_size = select_optimal_tray_icon_size(bar_height);
+    }
 
     xcb_flush(xcb_connection);
 
@@ -1706,7 +1760,7 @@ void draw_bars(bool unhide) {
                 /* We assume the tray icons are quadratic (we use the font
                  * *height* as *width* of the icons) because we configured them
                  * like this. */
-                traypx += font.height + 2;
+                traypx += tray_icon_size + 2;
             }
             /* Add 2px of padding if there are any tray icons */
             if (traypx > 0)
@@ -1715,9 +1769,12 @@ void draw_bars(bool unhide) {
                           statusline_pm,
                           outputs_walk->buffer,
                           outputs_walk->bargc,
-                          MAX(0, (int16_t)(statusline_width - outputs_walk->rect.w + 4)), 0,
-                          MAX(0, (int16_t)(outputs_walk->rect.w - statusline_width - traypx - 4)), 3,
-                          MIN(outputs_walk->rect.w - traypx - 4, statusline_width), font.height + 2);
+                          /*src_x*/MAX(0, (int16_t)(statusline_width - outputs_walk->rect.w + 4)), 
+                          /*src_y*/0,
+                          /*dst_x*/MAX(0, (int16_t)(outputs_walk->rect.w - statusline_width - traypx - 4)), 
+                          /*dst_y*/(bar_height - font.height - 2)/2+1,
+                          /*width*/MIN(outputs_walk->rect.w - traypx - 4, statusline_width),
+                          /*height*/font.height + 2);
         }
 
         if (!config.disable_ws) {
@@ -1752,7 +1809,13 @@ void draw_bars(bool unhide) {
                               outputs_walk->bargc,
                               mask,
                               vals_border);
-                xcb_rectangle_t rect_border = { i, 1, ws_walk->name_width + 10, font.height + 4 };
+                
+                xcb_rectangle_t rect_border = {
+                    i,
+                    1,
+                    ws_walk->name_width + 10,
+                    /*font.height + 4*/bar_height-2};
+                
                 xcb_poly_fill_rectangle(xcb_connection,
                                         outputs_walk->buffer,
                                         outputs_walk->bargc,
@@ -1763,7 +1826,12 @@ void draw_bars(bool unhide) {
                               outputs_walk->bargc,
                               mask,
                               vals);
-                xcb_rectangle_t rect = { i + 1, 2, ws_walk->name_width + 8, font.height + 2 };
+                
+                xcb_rectangle_t rect = {
+                    i + 1,
+                    2,
+                    ws_walk->name_width + 8,
+                    /*font.height + 2*/bar_height-4};
                 xcb_poly_fill_rectangle(xcb_connection,
                                         outputs_walk->buffer,
                                         outputs_walk->bargc,
@@ -1771,7 +1839,7 @@ void draw_bars(bool unhide) {
                                         &rect);
                 set_font_colors(outputs_walk->bargc, fg_color, bg_color);
                 draw_text(ws_walk->name, outputs_walk->buffer, outputs_walk->bargc,
-                          i + 5, 3, ws_walk->name_width);
+                          i + 5, (bar_height - font.height)/2+1, ws_walk->name_width);
                 i += 10 + ws_walk->name_width + 1;
 
             }
diff --git a/include/config.h b/include/config.h
index 4267dcf..a4f4b6f 100644
--- a/include/config.h
+++ b/include/config.h
@@ -223,6 +223,9 @@ struct Barconfig {
     /** Output on which the tray should be shown. The special value of 'no'
      * disables the tray (it’s enabled by default). */
     char *tray_output;
+    
+    int tray_icon_size;
+    int panel_size;
 
     /** Path to the i3 IPC socket. This option is discouraged since programs
      * can find out the path by looking for the I3_SOCKET_PATH property on the
diff --git a/include/config_directives.h b/include/config_directives.h
index 9569a7b..e6d6301 100644
--- a/include/config_directives.h
+++ b/include/config_directives.h
@@ -72,6 +72,8 @@ CFGFUN(bar_i3bar_command, const char *i3bar_command);
 CFGFUN(bar_color, const char *colorclass, const char *border, const char *background, const char *text);
 CFGFUN(bar_socket_path, const char *socket_path);
 CFGFUN(bar_tray_output, const char *output);
+CFGFUN(bar_tray_icon_size, const long size);
+CFGFUN(bar_panel_size, const long size);
 CFGFUN(bar_color_single, const char *colorclass, const char *color);
 CFGFUN(bar_status_command, const char *command);
 CFGFUN(bar_binding_mode_indicator, const char *value);
diff --git a/parser-specs/config.spec b/parser-specs/config.spec
index dfd6401..7e849f9 100644
--- a/parser-specs/config.spec
+++ b/parser-specs/config.spec
@@ -355,6 +355,8 @@ state BAR:
   'position'               -> BAR_POSITION
   'output'                 -> BAR_OUTPUT
   'tray_output'            -> BAR_TRAY_OUTPUT
+  'tray_icon_size'         -> BAR_TRAY_ICON_SIZE
+  'panel_size'             -> BAR_PANEL_SIZE
   'font'                   -> BAR_FONT
   'binding_mode_indicator' -> BAR_BINDING_MODE_INDICATOR
   'workspace_buttons'      -> BAR_WORKSPACE_BUTTONS
@@ -408,6 +410,14 @@ state BAR_TRAY_OUTPUT:
   output = string
       -> call cfg_bar_tray_output($output); BAR
 
+state BAR_TRAY_ICON_SIZE:
+  tray_icon_size = number
+              -> call cfg_bar_tray_icon_size(&tray_icon_size); BAR
+
+state BAR_PANEL_SIZE:
+  panel_size = number
+            -> call cfg_bar_panel_size(&panel_size); BAR
+
 state BAR_FONT:
   font = string
       -> call cfg_bar_font($font); BAR
diff --git a/src/config_directives.c b/src/config_directives.c
index b28ad49..102f197 100644
--- a/src/config_directives.c
+++ b/src/config_directives.c
@@ -526,6 +526,14 @@ CFGFUN(bar_tray_output, const char *output) {
     current_bar.tray_output = sstrdup(output);
 }
 
+CFGFUN(bar_tray_icon_size, const long size) {
+    current_bar.tray_icon_size = size;
+}
+
+CFGFUN(bar_panel_size, const long size) {
+    current_bar.panel_size = size;
+}
+
 CFGFUN(bar_color_single, const char *colorclass, const char *color) {
     if (strcmp(colorclass, "background") == 0)
         current_bar.colors.background = sstrdup(color);
diff --git a/src/ipc.c b/src/ipc.c
index 4247ca5..54ab04b 100644
--- a/src/ipc.c
+++ b/src/ipc.c
@@ -674,6 +674,12 @@ IPC_HANDLER(get_bar_config) {
                 ystr("Mod4");
                 break;
         }
+        
+        ystr("tray_icon_size");
+        y(integer, config->tray_icon_size);
+        
+        ystr("panel_size");
+        y(integer, config->panel_size);
 
         ystr("position");
         if (config->position == P_BOTTOM)
