Back to index

lightning-sunbird  0.9+nobinonly
nsLookAndFeel.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* vim:expandtab:shiftwidth=4:tabstop=4:
00003  */
00004 /* ***** BEGIN LICENSE BLOCK *****
00005  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00006  *
00007  * The contents of this file are subject to the Mozilla Public License Version
00008  * 1.1 (the "License"); you may not use this file except in compliance with
00009  * the License. You may obtain a copy of the License at
00010  * http://www.mozilla.org/MPL/
00011  *
00012  * Software distributed under the License is distributed on an "AS IS" basis,
00013  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00014  * for the specific language governing rights and limitations under the
00015  * License.
00016  *
00017  * The Original Code is mozilla.org code.
00018  *
00019  * The Initial Developer of the Original Code is
00020  * Netscape Communications Corporation.
00021  * Portions created by the Initial Developer are Copyright (C) 1998
00022  * the Initial Developer. All Rights Reserved.
00023  *
00024  * Contributor(s):
00025  *   Brian Ryner <bryner@brianryner.com>
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either the GNU General Public License Version 2 or later (the "GPL"), or
00029  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
00040 
00041 #include "nsLookAndFeel.h"
00042 #include <gtk/gtkinvisible.h>
00043 
00044 #define GDK_COLOR_TO_NS_RGB(c) \
00045     ((nscolor) NS_RGB(c.red>>8, c.green>>8, c.blue>>8))
00046 
00047 nscolor nsLookAndFeel::sInfoText = 0;
00048 nscolor nsLookAndFeel::sInfoBackground = 0;
00049 nscolor nsLookAndFeel::sMenuText = 0;
00050 nscolor nsLookAndFeel::sMenuHover = 0;
00051 nscolor nsLookAndFeel::sMenuHoverText = 0;
00052 nscolor nsLookAndFeel::sMenuBackground = 0;
00053 nscolor nsLookAndFeel::sButtonBackground = 0;
00054 nscolor nsLookAndFeel::sButtonText = 0;
00055 nscolor nsLookAndFeel::sButtonOuterLightBorder = 0;
00056 nscolor nsLookAndFeel::sButtonInnerDarkBorder = 0;
00057 PRBool  nsLookAndFeel::sColorsInitialized = PR_FALSE;
00058 
00059 //-------------------------------------------------------------------------
00060 //
00061 // Query interface implementation
00062 //
00063 //-------------------------------------------------------------------------
00064 nsLookAndFeel::nsLookAndFeel() : nsXPLookAndFeel()
00065 {
00066     InitWidget();
00067 
00068     if (!sColorsInitialized)
00069         InitColors();
00070 }
00071 
00072 nsLookAndFeel::~nsLookAndFeel()
00073 {
00074     //  gtk_widget_destroy(mWidget);
00075     gtk_widget_unref(mWidget);
00076 }
00077 
00078 nsresult nsLookAndFeel::NativeGetColor(const nsColorID aID, nscolor& aColor)
00079 {
00080     nsresult res = NS_OK;
00081 
00082     switch (aID) {
00083         // These colors don't seem to be used for anything anymore in Mozilla
00084         // (except here at least TextSelectBackground and TextSelectForeground)
00085         // The CSS2 colors below are used.
00086     case eColor_WindowBackground:
00087         aColor = GDK_COLOR_TO_NS_RGB(mStyle->base[GTK_STATE_NORMAL]);
00088         break;
00089     case eColor_WindowForeground:
00090         aColor = GDK_COLOR_TO_NS_RGB(mStyle->text[GTK_STATE_NORMAL]);
00091         break;
00092     case eColor_WidgetBackground:
00093         aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_NORMAL]);
00094         break;
00095     case eColor_WidgetForeground:
00096         aColor = GDK_COLOR_TO_NS_RGB(mStyle->fg[GTK_STATE_NORMAL]);
00097         break;
00098     case eColor_WidgetSelectBackground:
00099         aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_SELECTED]);
00100         break;
00101     case eColor_WidgetSelectForeground:
00102         aColor = GDK_COLOR_TO_NS_RGB(mStyle->fg[GTK_STATE_SELECTED]);
00103         break;
00104     case eColor_Widget3DHighlight:
00105         aColor = NS_RGB(0xa0,0xa0,0xa0);
00106         break;
00107     case eColor_Widget3DShadow:
00108         aColor = NS_RGB(0x40,0x40,0x40);
00109         break;
00110     case eColor_TextBackground:
00111         // not used?
00112         aColor = GDK_COLOR_TO_NS_RGB(mStyle->base[GTK_STATE_NORMAL]);
00113         break;
00114     case eColor_TextForeground: 
00115         // not used?
00116         aColor = GDK_COLOR_TO_NS_RGB(mStyle->text[GTK_STATE_NORMAL]);
00117         break;
00118     case eColor_TextSelectBackground:
00119         // still used
00120         aColor = GDK_COLOR_TO_NS_RGB(mStyle->base[GTK_STATE_SELECTED]);
00121         break;
00122     case eColor_TextSelectForeground:
00123         // still used
00124         aColor = GDK_COLOR_TO_NS_RGB(mStyle->text[GTK_STATE_SELECTED]);
00125         break;
00126 
00127         // css2  http://www.w3.org/TR/REC-CSS2/ui.html#system-colors
00128     case eColor_activeborder:
00129         // active window border
00130         aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_NORMAL]);
00131         break;
00132     case eColor_activecaption:
00133         // active window caption background
00134         aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_NORMAL]);
00135         break;
00136     case eColor_appworkspace:
00137         // MDI background color
00138         aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_NORMAL]);
00139         break;
00140     case eColor_background:
00141         // desktop background
00142         aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_NORMAL]);
00143         break;
00144     case eColor_captiontext:
00145         // text in active window caption, size box, and scrollbar arrow box (!)
00146         aColor = GDK_COLOR_TO_NS_RGB(mStyle->fg[GTK_STATE_NORMAL]);
00147         break;
00148     case eColor_graytext:
00149         // disabled text in windows, menus, etc.
00150         aColor = GDK_COLOR_TO_NS_RGB(mStyle->fg[GTK_STATE_INSENSITIVE]);
00151         break;
00152     case eColor_highlight:
00153         // background of selected item
00154         aColor = GDK_COLOR_TO_NS_RGB(mStyle->base[GTK_STATE_SELECTED]);
00155         break;
00156     case eColor_highlighttext:
00157         // text of selected item
00158         aColor = GDK_COLOR_TO_NS_RGB(mStyle->text[GTK_STATE_SELECTED]);
00159         break;
00160     case eColor_inactiveborder:
00161         // inactive window border
00162         aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_NORMAL]);
00163         break;
00164     case eColor_inactivecaption:
00165         // inactive window caption
00166         aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_INSENSITIVE]);
00167         break;
00168     case eColor_inactivecaptiontext:
00169         // text in inactive window caption
00170         aColor = GDK_COLOR_TO_NS_RGB(mStyle->fg[GTK_STATE_INSENSITIVE]);
00171         break;
00172     case eColor_infobackground:
00173         // tooltip background color
00174         aColor = sInfoBackground;
00175         break;
00176     case eColor_infotext:
00177         // tooltip text color
00178         aColor = sInfoText;
00179         break;
00180     case eColor_menu:
00181         // menu background
00182         aColor = sMenuBackground;
00183         break;
00184     case eColor_menutext:
00185         // menu text
00186         aColor = sMenuText;
00187         break;
00188     case eColor_scrollbar:
00189         // scrollbar gray area
00190         aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_ACTIVE]);
00191         break;
00192 
00193     case eColor_threedface:
00194     case eColor_buttonface:
00195         // 3-D face color
00196         aColor = sButtonBackground;
00197         break;
00198 
00199     case eColor_buttontext:
00200         // text on push buttons
00201         aColor = sButtonText;
00202         break;
00203 
00204     case eColor_buttonhighlight:
00205         // 3-D highlighted edge color
00206     case eColor_threedhighlight:
00207         // 3-D highlighted outer edge color
00208         aColor = sButtonOuterLightBorder;
00209         break;
00210 
00211     case eColor_threedlightshadow:
00212         // 3-D highlighted inner edge color
00213         aColor = sButtonBackground; // always same as background in GTK code
00214         break;
00215 
00216     case eColor_buttonshadow:
00217         // 3-D shadow edge color
00218     case eColor_threedshadow:
00219         // 3-D shadow inner edge color
00220         aColor = sButtonInnerDarkBorder;
00221         break;
00222 
00223     case eColor_threeddarkshadow:
00224         // 3-D shadow outer edge color
00225         aColor = GDK_COLOR_TO_NS_RGB(mStyle->black);
00226         break;
00227 
00228     case eColor_window:
00229     case eColor_windowframe:
00230         aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_NORMAL]);
00231         break;
00232 
00233     case eColor_windowtext:
00234         aColor = GDK_COLOR_TO_NS_RGB(mStyle->fg[GTK_STATE_NORMAL]);
00235         break;
00236 
00237         // from the CSS3 working draft (not yet finalized)
00238         // http://www.w3.org/tr/2000/wd-css3-userint-20000216.html#color
00239 
00240     case eColor__moz_field:
00241         aColor = GDK_COLOR_TO_NS_RGB(mStyle->base[GTK_STATE_NORMAL]);
00242         break;
00243     case eColor__moz_fieldtext:
00244         aColor = GDK_COLOR_TO_NS_RGB(mStyle->text[GTK_STATE_NORMAL]);
00245         break;
00246     case eColor__moz_dialog:
00247         aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_NORMAL]);
00248         break;
00249     case eColor__moz_dialogtext:
00250         aColor = GDK_COLOR_TO_NS_RGB(mStyle->fg[GTK_STATE_NORMAL]);
00251         break;
00252     case eColor__moz_dragtargetzone:
00253         aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_SELECTED]);
00254         break; 
00255     case eColor__moz_buttondefault:
00256         // default button border color
00257         aColor = GDK_COLOR_TO_NS_RGB(mStyle->black);
00258         break;
00259     case eColor__moz_buttonhoverface:
00260         aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_PRELIGHT]);
00261         break;
00262     case eColor__moz_buttonhovertext:
00263         aColor = GDK_COLOR_TO_NS_RGB(mStyle->fg[GTK_STATE_PRELIGHT]);
00264         break;
00265     case eColor__moz_cellhighlight:
00266         aColor = GDK_COLOR_TO_NS_RGB(mStyle->base[GTK_STATE_ACTIVE]);
00267         break;
00268     case eColor__moz_cellhighlighttext:
00269         aColor = GDK_COLOR_TO_NS_RGB(mStyle->text[GTK_STATE_ACTIVE]);
00270         break;
00271     case eColor__moz_menuhover:
00272         aColor = sMenuHover;
00273         break;
00274     case eColor__moz_menuhovertext:
00275         aColor = sMenuHoverText;
00276         break;
00277     default:
00278         /* default color is BLACK */
00279         aColor = 0;
00280         res    = NS_ERROR_FAILURE;
00281         break;
00282     }
00283 
00284     return res;
00285 }
00286 
00287 NS_IMETHODIMP nsLookAndFeel::GetMetric(const nsMetricID aID, PRInt32 & aMetric)
00288 {
00289     nsresult res = NS_OK;
00290 
00291     res = nsXPLookAndFeel::GetMetric(aID, aMetric);
00292     if (NS_SUCCEEDED(res))
00293         return res;
00294     res = NS_OK;
00295 
00296     switch (aID) {
00297     case eMetric_WindowTitleHeight:
00298         aMetric = 0;
00299         break;
00300     case eMetric_WindowBorderWidth:
00301         // XXXldb Why is this commented out?
00302         //    aMetric = mStyle->klass->xthickness;
00303         break;
00304     case eMetric_WindowBorderHeight:
00305         // XXXldb Why is this commented out?
00306         //    aMetric = mStyle->klass->ythickness;
00307         break;
00308     case eMetric_Widget3DBorder:
00309         // XXXldb Why is this commented out?
00310         //    aMetric = 4;
00311         break;
00312     case eMetric_TextFieldHeight:
00313         {
00314             GtkRequisition req;
00315             GtkWidget *text = gtk_entry_new();
00316             // needed to avoid memory leak
00317             gtk_widget_ref(text);
00318             gtk_object_sink(GTK_OBJECT(text));
00319             gtk_widget_size_request(text,&req);
00320             aMetric = req.height;
00321             gtk_widget_destroy(text);
00322             gtk_widget_unref(text);
00323         }
00324         break;
00325     case eMetric_TextFieldBorder:
00326         aMetric = 2;
00327         break;
00328     case eMetric_TextVerticalInsidePadding:
00329         aMetric = 0;
00330         break;
00331     case eMetric_TextShouldUseVerticalInsidePadding:
00332         aMetric = 0;
00333         break;
00334     case eMetric_TextHorizontalInsideMinimumPadding:
00335         aMetric = 15;
00336         break;
00337     case eMetric_TextShouldUseHorizontalInsideMinimumPadding:
00338         aMetric = 1;
00339         break;
00340     case eMetric_ButtonHorizontalInsidePaddingNavQuirks:
00341         aMetric = 10;
00342         break;
00343     case eMetric_ButtonHorizontalInsidePaddingOffsetNavQuirks:
00344         aMetric = 8;
00345         break;
00346     case eMetric_CheckboxSize:
00347         aMetric = 15;
00348         break;
00349     case eMetric_RadioboxSize:
00350         aMetric = 15;
00351         break;
00352     case eMetric_ListShouldUseHorizontalInsideMinimumPadding:
00353         aMetric = 15;
00354         break;
00355     case eMetric_ListHorizontalInsideMinimumPadding:
00356         aMetric = 15;
00357         break;
00358     case eMetric_ListShouldUseVerticalInsidePadding:
00359         aMetric = 1;
00360         break;
00361     case eMetric_ListVerticalInsidePadding:
00362         aMetric = 1;
00363         break;
00364     case eMetric_CaretBlinkTime:
00365         aMetric = 500;
00366         break;
00367     case eMetric_CaretWidth:
00368         aMetric = 1;
00369         break;
00370     case eMetric_ShowCaretDuringSelection:
00371         aMetric = 0;
00372         break;
00373     case eMetric_SelectTextfieldsOnKeyFocus:
00374         {
00375             GtkWidget *entry;
00376             GtkSettings *settings;
00377             gboolean select_on_focus;
00378 
00379             entry = gtk_entry_new();
00380             gtk_widget_ref(entry);
00381             gtk_object_sink(GTK_OBJECT(entry));
00382             settings = gtk_widget_get_settings(entry);
00383             g_object_get(settings, 
00384                          "gtk-entry-select-on-focus",
00385                          &select_on_focus,
00386                          NULL);
00387             
00388             if(select_on_focus)
00389                 aMetric = 1;
00390             else
00391                 aMetric = 0;
00392 
00393             gtk_widget_destroy(entry);
00394             gtk_widget_unref(entry);
00395         }
00396         break;
00397     case eMetric_SubmenuDelay:
00398         aMetric = 200;
00399         break;
00400     case eMetric_MenusCanOverlapOSBar:
00401         // we want XUL popups to be able to overlap the task bar.
00402         aMetric = 1;
00403         break;
00404     case eMetric_SkipNavigatingDisabledMenuItem:
00405         aMetric = 1;
00406         break;
00407     case eMetric_DragFullWindow:
00408         aMetric = 1;
00409         break;
00410     case eMetric_DragThresholdX:
00411     case eMetric_DragThresholdY:
00412         {
00413             GtkWidget* box = gtk_hbox_new(FALSE, 5);
00414             gint threshold = 0;
00415             g_object_get(gtk_widget_get_settings(box),
00416                          "gtk-dnd-drag-threshold", &threshold,
00417                          NULL);
00418             gtk_object_sink(GTK_OBJECT(box));
00419             aMetric = threshold;
00420         }
00421         break;
00422     case eMetric_ScrollArrowStyle:
00423         aMetric = eMetric_ScrollArrowStyleSingle;
00424         break;
00425     case eMetric_ScrollSliderStyle:
00426         aMetric = eMetric_ScrollThumbStyleProportional;
00427         break;
00428     case eMetric_TreeOpenDelay:
00429         aMetric = 1000;
00430         break;
00431     case eMetric_TreeCloseDelay:
00432         aMetric = 1000;
00433         break;
00434     case eMetric_TreeLazyScrollDelay:
00435         aMetric = 150;
00436         break;
00437     case eMetric_TreeScrollDelay:
00438         aMetric = 100;
00439         break;
00440     case eMetric_TreeScrollLinesMax:
00441         aMetric = 3;
00442         break;
00443 
00444     default:
00445         aMetric = 0;
00446         res     = NS_ERROR_FAILURE;
00447     }
00448 
00449     return res;
00450 }
00451 
00452 NS_IMETHODIMP nsLookAndFeel::GetMetric(const nsMetricFloatID aID,
00453                                        float & aMetric)
00454 {
00455     nsresult res = NS_OK;
00456     res = nsXPLookAndFeel::GetMetric(aID, aMetric);
00457     if (NS_SUCCEEDED(res))
00458         return res;
00459     res = NS_OK;
00460 
00461     switch (aID) {
00462     case eMetricFloat_TextFieldVerticalInsidePadding:
00463         aMetric = 0.25f;
00464         break;
00465     case eMetricFloat_TextFieldHorizontalInsidePadding:
00466         aMetric = 0.95f; // large number on purpose so minimum padding is used
00467         break;
00468     case eMetricFloat_TextAreaVerticalInsidePadding:
00469         aMetric = 0.40f;    
00470         break;
00471     case eMetricFloat_TextAreaHorizontalInsidePadding:
00472         aMetric = 0.40f; // large number on purpose so minimum padding is used
00473         break;
00474     case eMetricFloat_ListVerticalInsidePadding:
00475         aMetric = 0.10f;
00476         break;
00477     case eMetricFloat_ListHorizontalInsidePadding:
00478         aMetric = 0.40f;
00479         break;
00480     case eMetricFloat_ButtonVerticalInsidePadding:
00481         aMetric = 0.25f;
00482         break;
00483     case eMetricFloat_ButtonHorizontalInsidePadding:
00484         aMetric = 0.25f;
00485         break;
00486     default:
00487         aMetric = -1.0;
00488         res = NS_ERROR_FAILURE;
00489     }
00490     return res;
00491 }
00492 
00493 void
00494 nsLookAndFeel::InitColors()
00495 {
00496     sColorsInitialized = PR_TRUE;
00497     GtkStyle *style;
00498 
00499     // tooltip foreground and background
00500     style = gtk_rc_get_style_by_paths(gtk_settings_get_default(),
00501                                       "gtk-tooltips", "GtkWindow",
00502                                       GTK_TYPE_WINDOW);
00503     if (style) {
00504         sInfoBackground = GDK_COLOR_TO_NS_RGB(style->bg[GTK_STATE_NORMAL]);
00505         sInfoText = GDK_COLOR_TO_NS_RGB(style->fg[GTK_STATE_NORMAL]);
00506     }
00507 
00508     // menu foreground & menu background
00509     GtkWidget *accel_label = gtk_accel_label_new("M");
00510     GtkWidget *menuitem = gtk_menu_item_new();
00511     GtkWidget *menu = gtk_menu_new();
00512     gtk_object_ref(GTK_OBJECT(menu));
00513     gtk_object_sink(GTK_OBJECT(menu));
00514 
00515     gtk_container_add(GTK_CONTAINER(menuitem), accel_label);
00516     gtk_menu_append(GTK_MENU(menu), menuitem);
00517 
00518     gtk_widget_set_rc_style(accel_label);
00519     gtk_widget_set_rc_style(menu);
00520     gtk_widget_realize(menu);
00521     gtk_widget_realize(accel_label);
00522 
00523     style = gtk_widget_get_style(accel_label);
00524     if (style) {
00525         sMenuText = GDK_COLOR_TO_NS_RGB(style->fg[GTK_STATE_NORMAL]);
00526     }
00527 
00528     style = gtk_widget_get_style(menu);
00529     if (style) {
00530         sMenuBackground = GDK_COLOR_TO_NS_RGB(style->bg[GTK_STATE_NORMAL]);
00531     }
00532     
00533     style = gtk_widget_get_style(menuitem);
00534     if (style) {
00535         sMenuHover = GDK_COLOR_TO_NS_RGB(style->bg[GTK_STATE_PRELIGHT]);
00536         sMenuHoverText = GDK_COLOR_TO_NS_RGB(style->fg[GTK_STATE_PRELIGHT]);
00537     }
00538 
00539     gtk_widget_unref(menu);
00540 
00541 
00542     // button styles
00543     GtkWidget *parent = gtk_fixed_new();
00544     GtkWidget *button = gtk_button_new();
00545     GtkWidget *label = gtk_label_new("M");
00546     GtkWidget *window = gtk_window_new(GTK_WINDOW_POPUP);
00547 
00548     gtk_container_add(GTK_CONTAINER(button), label);
00549     gtk_container_add(GTK_CONTAINER(parent), button);
00550     gtk_container_add(GTK_CONTAINER(window), parent);
00551 
00552     gtk_widget_set_rc_style(button);
00553     gtk_widget_set_rc_style(label);
00554 
00555     gtk_widget_realize(button);
00556     gtk_widget_realize(label);
00557 
00558     style = gtk_widget_get_style(label);
00559     if (style) {
00560         sButtonText = GDK_COLOR_TO_NS_RGB(style->fg[GTK_STATE_NORMAL]);
00561     }
00562 
00563     style = gtk_widget_get_style(button);
00564     if (style) {
00565         sButtonBackground = GDK_COLOR_TO_NS_RGB(style->bg[GTK_STATE_NORMAL]);
00566         sButtonOuterLightBorder =
00567             GDK_COLOR_TO_NS_RGB(style->light[GTK_STATE_NORMAL]);
00568         sButtonInnerDarkBorder =
00569             GDK_COLOR_TO_NS_RGB(style->dark[GTK_STATE_NORMAL]);
00570     }
00571 
00572     gtk_widget_destroy(window);
00573 }
00574 
00575 NS_IMETHODIMP
00576 nsLookAndFeel::LookAndFeelChanged()
00577 {
00578     nsXPLookAndFeel::LookAndFeelChanged();
00579 
00580     if (mWidget)
00581         gtk_widget_unref(mWidget);
00582  
00583     InitWidget();
00584     InitColors();
00585 
00586     return NS_OK;
00587 }