Index: /trunk/roundcubemail/CHANGELOG
===================================================================
--- /trunk/roundcubemail/CHANGELOG	(revision 5993)
+++ /trunk/roundcubemail/CHANGELOG	(revision 5994)
@@ -2,4 +2,5 @@
 ===========================
 
+- Unified (single) spellchecker button
 - Fix encoding of attachment with comma in name (#1488389)
 - Scroll long lists on drag&drop (#1485946)
Index: /trunk/roundcubemail/program/js/app.js
===================================================================
--- /trunk/roundcubemail/program/js/app.js	(revision 5993)
+++ /trunk/roundcubemail/program/js/app.js	(revision 5994)
@@ -262,9 +262,7 @@
 
           if (this.env.spellcheck) {
-            this.env.spellcheck.spelling_state_observer = function(s){ ref.set_spellcheck_state(s); };
+            this.env.spellcheck.spelling_state_observer = function(s) { ref.spellcheck_state(); };
             this.env.compose_commands.push('spellcheck')
-            this.set_spellcheck_state('ready');
-            if ($("input[name='_is_html']").val() == '1')
-              this.display_spellcheck_controls(false);
+            this.enable_command('spellcheck', true);
           }
 
@@ -899,11 +897,16 @@
 
       case 'spellcheck':
-        if (window.tinyMCE && tinyMCE.get(this.env.composebody)) {
-          tinyMCE.execCommand('mceSpellCheck', true);
-        }
-        else if (this.env.spellcheck && this.env.spellcheck.spellCheck && this.spellcheck_ready) {
-          this.env.spellcheck.spellCheck();
-          this.set_spellcheck_state('checking');
-        }
+        if (this.spellcheck_state()) {
+          this.stop_spellchecking();
+        }
+        else {
+          if (window.tinyMCE && tinyMCE.get(this.env.composebody)) {
+            tinyMCE.execCommand('mceSpellCheck', true);
+          }
+          else if (this.env.spellcheck && this.env.spellcheck.spellCheck) {
+            this.env.spellcheck.spellCheck();
+          }
+        }
+        this.spellcheck_state();
         break;
 
@@ -3117,6 +3120,7 @@
   this.toggle_editor = function(props)
   {
+    this.stop_spellchecking();
+
     if (props.mode == 'html') {
-      this.display_spellcheck_controls(false);
       this.plain2html($('#'+props.id).val(), props.id);
       tinyMCE.execCommand('mceAddControl', false, props.id);
@@ -3129,6 +3133,4 @@
     else {
       var thisMCE = tinyMCE.get(props.id), existingHtml;
-      if (thisMCE.plugins.spellchecker && thisMCE.plugins.spellchecker.active)
-        thisMCE.execCommand('mceSpellCheck', false);
 
       if (existingHtml = thisMCE.getContent()) {
@@ -3139,5 +3141,4 @@
       }
       tinyMCE.execCommand('mceRemoveControl', false, props.id);
-      this.display_spellcheck_controls(true);
     }
 
@@ -3148,29 +3149,29 @@
   {
     var ed;
+
     if (window.tinyMCE && (ed = tinyMCE.get(this.env.composebody))) {
       if (ed.plugins.spellchecker && ed.plugins.spellchecker.active)
         ed.execCommand('mceSpellCheck');
     }
-    else if ((ed = this.env.spellcheck) && !this.spellcheck_ready) {
-      $(ed.spell_span).trigger('click');
-      this.set_spellcheck_state('ready');
-    }
-  };
-
-  this.display_spellcheck_controls = function(vis)
-  {
-    if (this.env.spellcheck) {
-      // stop spellchecking process
-      if (!vis)
-        this.stop_spellchecking();
-
-      $(this.env.spellcheck.spell_container)[vis ? 'show' : 'hide']();
-    }
-  };
-
-  this.set_spellcheck_state = function(s)
-  {
-    this.spellcheck_ready = (s == 'ready' || s == 'no_error_found');
-    this.enable_command('spellcheck', this.spellcheck_ready);
+    else if (ed = this.env.spellcheck) {
+      if (ed.state && ed.state != 'ready' && ed.state != 'no_error_found')
+        $(ed.spell_span).trigger('click');
+    }
+
+    this.spellcheck_state();
+  };
+
+  this.spellcheck_state = function()
+  {
+    var ed, active;
+
+    if (window.tinyMCE && (ed = tinyMCE.get(this.env.composebody)) && ed.plugins.spellchecker)
+      active = ed.plugins.spellchecker.active;
+    else if ((ed = this.env.spellcheck) && ed.state)
+      active = ed.state != 'ready' && ed.state != 'no_error_found';
+
+    $('#'+rcmail.buttons.spellcheck[0].id)[active ? 'addClass' : 'removeClass']('selected');
+
+    return active;
   };
 
@@ -3179,10 +3180,19 @@
   {
     var ed;
-    if (window.tinyMCE && (ed = tinyMCE.get(this.env.composebody)) && ed.plugins.spellchecker) {
+
+    if (window.tinyMCE && (ed = tinyMCE.get(this.env.composebody)) && ed.plugins.spellchecker)
       return ed.plugins.spellchecker.selectedLang;
-    }
-    else if (this.env.spellcheck) {
+    else if (this.env.spellcheck)
       return GOOGIE_CUR_LANG;
-    }
+  };
+
+  this.spellcheck_lang_set = function(lang)
+  {
+    var editor;
+
+    if (window.tinyMCE && (editor = tinyMCE.get(this.env.composebody)))
+      editor.plugins.spellchecker.selectedLang = lang;
+    else if (this.env.spellcheck)
+      this.env.spellcheck.setCurrentLanguage(lang);
   };
 
@@ -3203,4 +3213,6 @@
       sp.processData(data);
     }
+
+    this.spellcheck_state();
   }
 
Index: /trunk/roundcubemail/program/js/editor.js
===================================================================
--- /trunk/roundcubemail/program/js/editor.js	(revision 5993)
+++ /trunk/roundcubemail/program/js/editor.js	(revision 5994)
@@ -45,9 +45,9 @@
       theme_advanced_buttons2: ',fontselect,fontsizeselect'
     });
-  else // mail compose
+  else { // mail compose
     $.extend(conf, {
       plugins: 'paste,emotions,media,nonbreaking,table,searchreplace,visualchars,directionality,tabfocus' + (config.spellcheck ? ',spellchecker' : ''),
       theme_advanced_buttons1: 'bold,italic,underline,|,justifyleft,justifycenter,justifyright,justifyfull,|,bullist,numlist,outdent,indent,ltr,rtl,blockquote,|,forecolor,backcolor,fontselect,fontsizeselect',
-      theme_advanced_buttons2: 'link,unlink,table,|,emotions,charmap,image,media,|,code,search' + (config.spellcheck ? ',spellchecker' : '') + ',undo,redo',
+      theme_advanced_buttons2: 'link,unlink,table,|,emotions,charmap,image,media,|,code,search,undo,redo',
       spellchecker_languages: (rcmail.env.spellcheck_langs ? rcmail.env.spellcheck_langs : 'Dansk=da,Deutsch=de,+English=en,Espanol=es,Francais=fr,Italiano=it,Nederlands=nl,Polski=pl,Portugues=pt,Suomi=fi,Svenska=sv'),
       spellchecker_rpc_url: '?_task=utils&_action=spell_html',
@@ -56,4 +56,13 @@
       oninit: 'rcmail_editor_callback'
     });
+
+    // add handler for spellcheck button state update
+    conf.setup = function(ed) {
+      ed.onSetProgressState.add(function(ed, active) {
+        if (!active)
+          rcmail.spellcheck_state();
+      });
+    }
+  }
 
   // support external configuration settings e.g. from skin
Index: /trunk/roundcubemail/program/steps/mail/compose.inc
===================================================================
--- /trunk/roundcubemail/program/steps/mail/compose.inc	(revision 5993)
+++ /trunk/roundcubemail/program/steps/mail/compose.inc	(revision 5994)
@@ -814,4 +814,7 @@
       $lang = 'en';
 
+    $OUTPUT->set_env('spell_langs', $spellcheck_langs);
+    $OUTPUT->set_env('spell_lang', $lang);
+
     $editor_lang_set = array();
     foreach ($spellcheck_langs as $key => $name) {
@@ -831,5 +834,5 @@
       "googie.setLanguages(%s);\n".
       "googie.setCurrentLanguage('%s');\n".
-      "googie.setSpellContainer('spellcheck-control');\n".
+      "googie.setDecoration(false);\n".
       "googie.decorateTextarea('%s');\n".
       "%s.set_env('spellcheck', googie);",
Index: /trunk/roundcubemail/skins/default/common.css
===================================================================
--- /trunk/roundcubemail/skins/default/common.css	(revision 5993)
+++ /trunk/roundcubemail/skins/default/common.css	(revision 5994)
@@ -496,4 +496,5 @@
   text-decoration: none;
   min-height: 14px;
+  background: transparent;
 }
 
@@ -505,5 +506,6 @@
 }
 
-.popupmenu li a.active:hover
+.popupmenu li a.active:hover,
+.popupmenu.selectable li a.selected:hover
 {
   color: #fff;
@@ -514,4 +516,14 @@
 {
   float: left;
+}
+
+.popupmenu.selectable li a.selected
+{
+  background: url(images/messageicons.png) 2px -372px no-repeat;
+}
+
+.popupmenu.selectable li a
+{
+  padding-left: 20px;
 }
 
Index: /trunk/roundcubemail/skins/default/functions.js
===================================================================
--- /trunk/roundcubemail/skins/default/functions.js	(revision 5993)
+++ /trunk/roundcubemail/skins/default/functions.js	(revision 5994)
@@ -103,4 +103,5 @@
     mailboxmenu:    {id:'mailboxoptionsmenu', above:1},
     composemenu:    {id:'composeoptionsmenu', editable:1, overlap:1},
+    spellmenu:      {id:'spellmenu'},
     // toggle: #1486823, #1486930
     uploadmenu:     {id:'attachment-form', editable:1, above:1, toggle:!bw.ie&&!bw.linux },
@@ -352,4 +353,41 @@
 },
 
+spellmenu: function(show)
+{
+  var link, li,
+    lang = rcmail.spellcheck_lang(),
+    menu = this.popups.spellmenu.obj,
+    ul = $('ul', menu);
+
+  if (!ul.length) {
+    ul = $('<ul>');
+
+    for (i in rcmail.env.spell_langs) {
+      li = $('<li>');
+      link = $('<a href="#">').text(rcmail.env.spell_langs[i])
+        .addClass('active').data('lang', i)
+        .click(function() {
+          rcmail.spellcheck_lang_set($(this).data('lang'));
+        });
+
+      link.appendTo(li);
+      li.appendTo(ul);
+    }
+
+    ul.appendTo(menu);
+  }
+
+  // select current language
+  $('li', ul).each(function() {
+    var el = $('a', this);
+    if (el.data('lang') == lang)
+      el.addClass('selected');
+    else if (el.hasClass('selected'))
+      el.removeClass('selected');
+  });
+
+  this.show_popupmenu('spellmenu', show);
+},
+
 body_mouseup: function(evt, p)
 {
Index: /trunk/roundcubemail/skins/default/mail.css
===================================================================
--- /trunk/roundcubemail/skins/default/mail.css	(revision 5993)
+++ /trunk/roundcubemail/skins/default/mail.css	(revision 5994)
@@ -37,4 +37,15 @@
 #messagetoolbar a.buttonPas {
   opacity: 0.35;
+}
+
+#messagetoolbar a.button.selected {
+  background-color: #ddd;
+  margin-left: 4px;
+  margin-right: 4px;
+  margin-top: -1px;
+  border: 1px solid #ccc;
+  border-radius: 3px;
+  -moz-border-radius: 3px;
+  -webkit-border-radius: 3px;
 }
 
Index: /trunk/roundcubemail/skins/default/templates/compose.html
===================================================================
--- /trunk/roundcubemail/skins/default/templates/compose.html	(revision 5993)
+++ /trunk/roundcubemail/skins/default/templates/compose.html	(revision 5994)
@@ -4,5 +4,7 @@
 <title><roundcube:object name="productname" /> :: <roundcube:label name="compose" /></title>
 <roundcube:include file="/includes/links.html" />
+<roundcube:if condition="config:enable_spellcheck" />
 <link rel="stylesheet" type="text/css" href="/googiespell.css" />
+<roundcube:endif />
 <script type="text/javascript" src="/functions.js"></script>
 <script type="text/javascript" src="/splitter.js"></script>
@@ -24,5 +26,10 @@
     <roundcube:button command="list" type="link" class="button back" classAct="button back" classSel="button backSel" title="backtolist" content=" " />
     <roundcube:button command="send" type="link" class="buttonPas send" classAct="button send" classSel="button sendSel" title="sendmessage" content=" " />
-    <roundcube:button command="spellcheck" type="link" class="buttonPas spellcheck" classAct="button spellcheck" classSel="button spellcheckSel" title="checkspelling" content=" " />
+<roundcube:if condition="config:enable_spellcheck" />
+    <span class="dropbutton">
+        <roundcube:button command="spellcheck" type="link" class="buttonPas spellcheck" classAct="button spellcheck" classSel="button spellcheckSel" title="checkspelling" content=" " />
+        <span id="spellmenulink" onclick="rcmail_ui.show_popup('spellmenu');return false"></span>
+    </span>
+<roundcube:endif />
     <roundcube:button name="addattachment" type="link" class="button attach" classAct="button attach" classSel="button attachSel" title="addattachment" onclick="rcmail_ui.show_popup('uploadmenu', true);return false" content=" " />
     <roundcube:button command="insert-sig" type="link" class="buttonPas insertsig" classAct="button insertsig" classSel="button insertsigSel" title="insertsignature" content=" " />
@@ -112,5 +119,4 @@
             </div>
             <div id="compose-editorfooter">
-                <span id="spellcheck-control" style="margin-right:10px"></span>
                 <roundcube:if condition="!in_array('htmleditor', (array)config:dont_override)" />
                 <span>
@@ -144,4 +150,6 @@
 </div>
 
+<div id="spellmenu" class="popupmenu selectable"></div>
+
 </form>
 
Index: /trunk/roundcubemail/skins/larry/mail.css
===================================================================
--- /trunk/roundcubemail/skins/larry/mail.css	(revision 5993)
+++ /trunk/roundcubemail/skins/larry/mail.css	(revision 5994)
@@ -1167,9 +1167,10 @@
 #composebody {
 	position: absolute;
-	top: 24px;
+	top: 1px;
 	left: 0;
 	bottom: 0;
 	width: 99%;
 	border: 0;
+	border-radius: 0;
 	padding: 8px 0 8px 8px;
 	box-shadow: none;
@@ -1196,9 +1197,4 @@
 }
 
-#spellcheck-control {
-	margin: 6px 8px;
-	text-align: right;
-}
-
 .defaultSkin table.mceLayout,
 .defaultSkin table.mceLayout tr.mceLast td {
Index: /trunk/roundcubemail/skins/larry/styles.css
===================================================================
--- /trunk/roundcubemail/skins/larry/styles.css	(revision 5993)
+++ /trunk/roundcubemail/skins/larry/styles.css	(revision 5994)
@@ -1391,5 +1391,6 @@
 
 .toolbar a.button.spellcheck {
-	background-position: center -930px;
+	min-width: 64px;
+	background-position: left -930px;
 }
 
@@ -1575,6 +1576,11 @@
 }
 
-ul.toolbarmenu.iconized li a {
+ul.toolbarmenu.iconized li a,
+ul.toolbarmenu.selectable li a {
 	padding-left: 30px;
+}
+
+ul.toolbarmenu.selectable li a.selected {
+	background: url(images/messages.png) 4px -27px no-repeat;
 }
 
Index: /trunk/roundcubemail/skins/larry/templates/compose.html
===================================================================
--- /trunk/roundcubemail/skins/larry/templates/compose.html	(revision 5993)
+++ /trunk/roundcubemail/skins/larry/templates/compose.html	(revision 5994)
@@ -4,5 +4,7 @@
 <title><roundcube:object name="pagetitle" /></title>
 <roundcube:include file="/includes/links.html" />
+<roundcube:if condition="config:enable_spellcheck" />
 <link rel="stylesheet" type="text/css" href="/googiespell.css" />
+<roundcube:endif />
 </head>
 <body class="noscroll">
@@ -39,5 +41,10 @@
 <div id="messagetoolbar" class="fullwidth">
 <div id="mailtoolbar" class="toolbar">
-	<roundcube:button command="spellcheck" type="link" class="button spellcheck disabled" classAct="button spellcheck" classSel="button spellcheck pressed" label="spellcheck" title="checkspelling" />
+	<roundcube:if condition="config:enable_spellcheck" />
+	<span class="dropbutton">
+		<roundcube:button command="spellcheck" type="link" class="button spellcheck disabled" classAct="button spellcheck" classSel="button spellcheck pressed" label="spellcheck" title="checkspelling" />
+		<span class="dropbuttontip" id="spellmenulink" onclick="UI.show_popup('spellmenu');return false"></span>
+	</span>
+	<roundcube:endif />
 	<roundcube:button name="addattachment" type="link" class="button attach" classAct="button attach" classSel="button attach pressed" label="attach" title="addattachment" onclick="UI.show_uploadform();return false" />
 	<roundcube:button command="insert-sig" type="link" class="button insertsig disabled" classAct="button insertsig" classSel="button insertsig pressed" label="signature" title="insertsignature" />
@@ -143,5 +150,4 @@
 <div id="composeview-bottom">
 	<div id="composebodycontainer">
-		<div id="spellcheck-control"></div>
 		<roundcube:object name="composeBody" id="composebody" form="form" cols="70" rows="20" tabindex="9" />
 	</div>
@@ -172,4 +178,6 @@
 </div>
 
+<div id="spellmenu" class="popupmenu"></div>
+
 <roundcube:include file="/includes/footer.html" />
 
Index: /trunk/roundcubemail/skins/larry/ui.js
===================================================================
--- /trunk/roundcubemail/skins/larry/ui.js	(revision 5993)
+++ /trunk/roundcubemail/skins/larry/ui.js	(revision 5994)
@@ -25,4 +25,5 @@
     mailboxmenu:        { above:1 },
     composeoptionsmenu: { editable:1, overlap:1 },
+    spellmenu:          { callback: spellmenu },
     // toggle: #1486823, #1486930
     'attachment-form':  { editable:1, above:1, toggle:!bw.ie&&!bw.linux },
@@ -339,11 +340,11 @@
     bottom.css('height', (form.height() - bottom.position().top) + 'px');
 
-    w = body.parent().width() - 6;
-    h = body.parent().height() - 36;
+    w = body.parent().width() - 5;
+    h = body.parent().height() - 16;
     body.width(w).height(h);
 
     if (window.tinyMCE && tinyMCE.get('composebody')) {
-      $('#composebody_tbl').width((w+10)+'px').height('').css('margin-top', '1px');
-      $('#composebody_ifr').width((w+10)+'px').height((h-22)+'px');
+      $('#composebody_tbl').width((w+8)+'px').height('').css('margin-top', '1px');
+      $('#composebody_ifr').width((w+8)+'px').height((h-40)+'px');
     }
     else {
@@ -426,5 +427,5 @@
       $('select', obj).css('visibility', 'inherit');
     }
-    
+
     return show;
   }
@@ -552,4 +553,40 @@
       }
     }
+  }
+
+
+  function spellmenu(show)
+  {
+    var link, li,
+      lang = rcmail.spellcheck_lang(),
+      menu = popups.spellmenu,
+      ul = $('ul', menu);
+
+    if (!ul.length) {
+      ul = $('<ul class="toolbarmenu selectable">');
+
+      for (i in rcmail.env.spell_langs) {
+        li = $('<li>');
+        link = $('<a href="#">').text(rcmail.env.spell_langs[i])
+          .addClass('active').data('lang', i)
+          .click(function() {
+            rcmail.spellcheck_lang_set($(this).data('lang'));
+          });
+
+        link.appendTo(li);
+        li.appendTo(ul);
+      }
+
+      ul.appendTo(menu);
+    }
+
+    // select current language
+    $('li', ul).each(function() {
+      var el = $('a', this);
+      if (el.data('lang') == lang)
+        el.addClass('selected');
+      else if (el.hasClass('selected'))
+        el.removeClass('selected');
+    });
   }
 
