1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* vim:expandtab:shiftwidth=4:tabstop=4:
3 : */
4 : /* ***** BEGIN LICENSE BLOCK *****
5 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 : *
7 : * The contents of this file are subject to the Mozilla Public License Version
8 : * 1.1 (the "License"); you may not use this file except in compliance with
9 : * the License. You may obtain a copy of the License at
10 : * http://www.mozilla.org/MPL/
11 : *
12 : * Software distributed under the License is distributed on an "AS IS" basis,
13 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 : * for the specific language governing rights and limitations under the
15 : * License.
16 : *
17 : * The Original Code is mozilla.org code.
18 : *
19 : * The Initial Developer of the Original Code is
20 : * Netscape Communications Corporation.
21 : * Portions created by the Initial Developer are Copyright (C) 1998
22 : * the Initial Developer. All Rights Reserved.
23 : *
24 : * Contributor(s):
25 : * Brian Ryner <bryner@brianryner.com>
26 : *
27 : * Alternatively, the contents of this file may be used under the terms of
28 : * either the GNU General Public License Version 2 or later (the "GPL"), or
29 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 : * in which case the provisions of the GPL or the LGPL are applicable instead
31 : * of those above. If you wish to allow use of your version of this file only
32 : * under the terms of either the GPL or the LGPL, and not to allow others to
33 : * use your version of this file under the terms of the MPL, indicate your
34 : * decision by deleting the provisions above and replace them with the notice
35 : * and other provisions required by the GPL or the LGPL. If you do not delete
36 : * the provisions above, a recipient may use your version of this file under
37 : * the terms of any one of the MPL, the GPL or the LGPL.
38 : *
39 : * ***** END LICENSE BLOCK ***** */
40 :
41 : // for strtod()
42 : #include <stdlib.h>
43 :
44 : #include "nsLookAndFeel.h"
45 :
46 : #include <gtk/gtk.h>
47 : #include <gdk/gdk.h>
48 :
49 : #ifdef MOZ_PANGO
50 : #include <pango/pango.h>
51 : #include <pango/pango-fontmap.h>
52 : #endif
53 :
54 : #include <fontconfig/fontconfig.h>
55 : #include "gfxPlatformGtk.h"
56 :
57 : #include "gtkdrawing.h"
58 : #include "nsStyleConsts.h"
59 :
60 : #ifdef MOZ_PLATFORM_MAEMO
61 : #include "nsIServiceManager.h"
62 : #include "nsIPropertyBag2.h"
63 : #include "nsLiteralString.h"
64 : #endif
65 :
66 : using mozilla::LookAndFeel;
67 :
68 : #define GDK_COLOR_TO_NS_RGB(c) \
69 : ((nscolor) NS_RGB(c.red>>8, c.green>>8, c.blue>>8))
70 :
71 : nscolor nsLookAndFeel::sInfoText = 0;
72 : nscolor nsLookAndFeel::sInfoBackground = 0;
73 : nscolor nsLookAndFeel::sMenuBarText = 0;
74 : nscolor nsLookAndFeel::sMenuBarHoverText = 0;
75 : nscolor nsLookAndFeel::sMenuText = 0;
76 : nscolor nsLookAndFeel::sMenuHover = 0;
77 : nscolor nsLookAndFeel::sMenuHoverText = 0;
78 : nscolor nsLookAndFeel::sMenuBackground = 0;
79 : nscolor nsLookAndFeel::sButtonBackground = 0;
80 : nscolor nsLookAndFeel::sButtonText = 0;
81 : nscolor nsLookAndFeel::sButtonOuterLightBorder = 0;
82 : nscolor nsLookAndFeel::sButtonInnerDarkBorder = 0;
83 : nscolor nsLookAndFeel::sOddCellBackground = 0;
84 : nscolor nsLookAndFeel::sNativeHyperLinkText = 0;
85 : nscolor nsLookAndFeel::sComboBoxText = 0;
86 : nscolor nsLookAndFeel::sComboBoxBackground = 0;
87 : PRUnichar nsLookAndFeel::sInvisibleCharacter = PRUnichar('*');
88 : float nsLookAndFeel::sCaretRatio = 0;
89 : bool nsLookAndFeel::sMenuSupportsDrag = false;
90 :
91 0 : nsLookAndFeel::nsLookAndFeel()
92 : : nsXPLookAndFeel(),
93 : mStyle(nsnull),
94 : mDefaultFontCached(false), mButtonFontCached(false),
95 0 : mFieldFontCached(false), mMenuFontCached(false)
96 : {
97 0 : InitWidget();
98 :
99 : static bool sInitialized = false;
100 :
101 0 : if (!sInitialized) {
102 0 : sInitialized = true;
103 0 : InitLookAndFeel();
104 : }
105 0 : }
106 :
107 0 : nsLookAndFeel::~nsLookAndFeel()
108 : {
109 0 : g_object_unref(mStyle);
110 0 : }
111 :
112 : nsresult
113 0 : nsLookAndFeel::NativeGetColor(ColorID aID, nscolor& aColor)
114 : {
115 0 : nsresult res = NS_OK;
116 :
117 0 : switch (aID) {
118 : // These colors don't seem to be used for anything anymore in Mozilla
119 : // (except here at least TextSelectBackground and TextSelectForeground)
120 : // The CSS2 colors below are used.
121 : case eColorID_WindowBackground:
122 0 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->base[GTK_STATE_NORMAL]);
123 0 : break;
124 : case eColorID_WindowForeground:
125 0 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->text[GTK_STATE_NORMAL]);
126 0 : break;
127 : case eColorID_WidgetBackground:
128 0 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_NORMAL]);
129 0 : break;
130 : case eColorID_WidgetForeground:
131 0 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->fg[GTK_STATE_NORMAL]);
132 0 : break;
133 : case eColorID_WidgetSelectBackground:
134 0 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_SELECTED]);
135 0 : break;
136 : case eColorID_WidgetSelectForeground:
137 0 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->fg[GTK_STATE_SELECTED]);
138 0 : break;
139 : case eColorID_Widget3DHighlight:
140 0 : aColor = NS_RGB(0xa0,0xa0,0xa0);
141 0 : break;
142 : case eColorID_Widget3DShadow:
143 0 : aColor = NS_RGB(0x40,0x40,0x40);
144 0 : break;
145 : case eColorID_TextBackground:
146 : // not used?
147 0 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->base[GTK_STATE_NORMAL]);
148 0 : break;
149 : case eColorID_TextForeground:
150 : // not used?
151 0 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->text[GTK_STATE_NORMAL]);
152 0 : break;
153 : case eColorID_TextSelectBackground:
154 : case eColorID_IMESelectedRawTextBackground:
155 : case eColorID_IMESelectedConvertedTextBackground:
156 : // still used
157 0 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->base[GTK_STATE_SELECTED]);
158 0 : break;
159 : case eColorID_TextSelectForeground:
160 : case eColorID_IMESelectedRawTextForeground:
161 : case eColorID_IMESelectedConvertedTextForeground:
162 : // still used
163 0 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->text[GTK_STATE_SELECTED]);
164 0 : break;
165 : case eColorID_IMERawInputBackground:
166 : case eColorID_IMEConvertedTextBackground:
167 0 : aColor = NS_TRANSPARENT;
168 0 : break;
169 : case eColorID_IMERawInputForeground:
170 : case eColorID_IMEConvertedTextForeground:
171 0 : aColor = NS_SAME_AS_FOREGROUND_COLOR;
172 0 : break;
173 : case eColorID_IMERawInputUnderline:
174 : case eColorID_IMEConvertedTextUnderline:
175 0 : aColor = NS_SAME_AS_FOREGROUND_COLOR;
176 0 : break;
177 : case eColorID_IMESelectedRawTextUnderline:
178 : case eColorID_IMESelectedConvertedTextUnderline:
179 0 : aColor = NS_TRANSPARENT;
180 0 : break;
181 : case eColorID_SpellCheckerUnderline:
182 0 : aColor = NS_RGB(0xff, 0, 0);
183 0 : break;
184 :
185 : // css2 http://www.w3.org/TR/REC-CSS2/ui.html#system-colors
186 : case eColorID_activeborder:
187 : // active window border
188 0 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_NORMAL]);
189 0 : break;
190 : case eColorID_activecaption:
191 : // active window caption background
192 0 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_NORMAL]);
193 0 : break;
194 : case eColorID_appworkspace:
195 : // MDI background color
196 0 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_NORMAL]);
197 0 : break;
198 : case eColorID_background:
199 : // desktop background
200 0 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_NORMAL]);
201 0 : break;
202 : case eColorID_captiontext:
203 : // text in active window caption, size box, and scrollbar arrow box (!)
204 0 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->fg[GTK_STATE_NORMAL]);
205 0 : break;
206 : case eColorID_graytext:
207 : // disabled text in windows, menus, etc.
208 0 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->fg[GTK_STATE_INSENSITIVE]);
209 0 : break;
210 : case eColorID_highlight:
211 : // background of selected item
212 0 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->base[GTK_STATE_SELECTED]);
213 0 : break;
214 : case eColorID_highlighttext:
215 : // text of selected item
216 0 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->text[GTK_STATE_SELECTED]);
217 0 : break;
218 : case eColorID_inactiveborder:
219 : // inactive window border
220 0 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_NORMAL]);
221 0 : break;
222 : case eColorID_inactivecaption:
223 : // inactive window caption
224 0 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_INSENSITIVE]);
225 0 : break;
226 : case eColorID_inactivecaptiontext:
227 : // text in inactive window caption
228 0 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->fg[GTK_STATE_INSENSITIVE]);
229 0 : break;
230 : case eColorID_infobackground:
231 : // tooltip background color
232 0 : aColor = sInfoBackground;
233 0 : break;
234 : case eColorID_infotext:
235 : // tooltip text color
236 0 : aColor = sInfoText;
237 0 : break;
238 : case eColorID_menu:
239 : // menu background
240 0 : aColor = sMenuBackground;
241 0 : break;
242 : case eColorID_menutext:
243 : // menu text
244 0 : aColor = sMenuText;
245 0 : break;
246 : case eColorID_scrollbar:
247 : // scrollbar gray area
248 0 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_ACTIVE]);
249 0 : break;
250 :
251 : case eColorID_threedface:
252 : case eColorID_buttonface:
253 : // 3-D face color
254 0 : aColor = sButtonBackground;
255 0 : break;
256 :
257 : case eColorID_buttontext:
258 : // text on push buttons
259 0 : aColor = sButtonText;
260 0 : break;
261 :
262 : case eColorID_buttonhighlight:
263 : // 3-D highlighted edge color
264 : case eColorID_threedhighlight:
265 : // 3-D highlighted outer edge color
266 0 : aColor = sButtonOuterLightBorder;
267 0 : break;
268 :
269 : case eColorID_threedlightshadow:
270 : // 3-D highlighted inner edge color
271 0 : aColor = sButtonBackground; // always same as background in GTK code
272 0 : break;
273 :
274 : case eColorID_buttonshadow:
275 : // 3-D shadow edge color
276 : case eColorID_threedshadow:
277 : // 3-D shadow inner edge color
278 0 : aColor = sButtonInnerDarkBorder;
279 0 : break;
280 :
281 : case eColorID_threeddarkshadow:
282 : // 3-D shadow outer edge color
283 0 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->black);
284 0 : break;
285 :
286 : case eColorID_window:
287 : case eColorID_windowframe:
288 0 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_NORMAL]);
289 0 : break;
290 :
291 : case eColorID_windowtext:
292 0 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->fg[GTK_STATE_NORMAL]);
293 0 : break;
294 :
295 : case eColorID__moz_eventreerow:
296 : case eColorID__moz_field:
297 0 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->base[GTK_STATE_NORMAL]);
298 0 : break;
299 : case eColorID__moz_fieldtext:
300 0 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->text[GTK_STATE_NORMAL]);
301 0 : break;
302 : case eColorID__moz_dialog:
303 0 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_NORMAL]);
304 0 : break;
305 : case eColorID__moz_dialogtext:
306 0 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->fg[GTK_STATE_NORMAL]);
307 0 : break;
308 : case eColorID__moz_dragtargetzone:
309 0 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_SELECTED]);
310 0 : break;
311 : case eColorID__moz_buttondefault:
312 : // default button border color
313 0 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->black);
314 0 : break;
315 : case eColorID__moz_buttonhoverface:
316 0 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_PRELIGHT]);
317 0 : break;
318 : case eColorID__moz_buttonhovertext:
319 0 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->fg[GTK_STATE_PRELIGHT]);
320 0 : break;
321 : case eColorID__moz_cellhighlight:
322 : case eColorID__moz_html_cellhighlight:
323 0 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->base[GTK_STATE_ACTIVE]);
324 0 : break;
325 : case eColorID__moz_cellhighlighttext:
326 : case eColorID__moz_html_cellhighlighttext:
327 0 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->text[GTK_STATE_ACTIVE]);
328 0 : break;
329 : case eColorID__moz_menuhover:
330 0 : aColor = sMenuHover;
331 0 : break;
332 : case eColorID__moz_menuhovertext:
333 0 : aColor = sMenuHoverText;
334 0 : break;
335 : case eColorID__moz_oddtreerow:
336 0 : aColor = sOddCellBackground;
337 0 : break;
338 : case eColorID__moz_nativehyperlinktext:
339 0 : aColor = sNativeHyperLinkText;
340 0 : break;
341 : case eColorID__moz_comboboxtext:
342 0 : aColor = sComboBoxText;
343 0 : break;
344 : case eColorID__moz_combobox:
345 0 : aColor = sComboBoxBackground;
346 0 : break;
347 : case eColorID__moz_menubartext:
348 0 : aColor = sMenuBarText;
349 0 : break;
350 : case eColorID__moz_menubarhovertext:
351 0 : aColor = sMenuBarHoverText;
352 0 : break;
353 : default:
354 : /* default color is BLACK */
355 0 : aColor = 0;
356 0 : res = NS_ERROR_FAILURE;
357 0 : break;
358 : }
359 :
360 0 : return res;
361 : }
362 :
363 0 : static void darken_gdk_color(GdkColor *src, GdkColor *dest)
364 : {
365 : gdouble red;
366 : gdouble green;
367 : gdouble blue;
368 :
369 0 : red = (gdouble) src->red / 65535.0;
370 0 : green = (gdouble) src->green / 65535.0;
371 0 : blue = (gdouble) src->blue / 65535.0;
372 :
373 0 : red *= 0.93;
374 0 : green *= 0.93;
375 0 : blue *= 0.93;
376 :
377 0 : dest->red = red * 65535.0;
378 0 : dest->green = green * 65535.0;
379 0 : dest->blue = blue * 65535.0;
380 0 : }
381 :
382 0 : static PRInt32 CheckWidgetStyle(GtkWidget* aWidget, const char* aStyle, PRInt32 aResult) {
383 0 : gboolean value = FALSE;
384 0 : gtk_widget_style_get(aWidget, aStyle, &value, NULL);
385 0 : return value ? aResult : 0;
386 : }
387 :
388 0 : static PRInt32 ConvertGTKStepperStyleToMozillaScrollArrowStyle(GtkWidget* aWidget)
389 : {
390 0 : if (!aWidget)
391 0 : return mozilla::LookAndFeel::eScrollArrowStyle_Single;
392 :
393 : return
394 : CheckWidgetStyle(aWidget, "has-backward-stepper",
395 0 : mozilla::LookAndFeel::eScrollArrow_StartBackward) |
396 : CheckWidgetStyle(aWidget, "has-forward-stepper",
397 0 : mozilla::LookAndFeel::eScrollArrow_EndForward) |
398 : CheckWidgetStyle(aWidget, "has-secondary-backward-stepper",
399 0 : mozilla::LookAndFeel::eScrollArrow_EndBackward) |
400 : CheckWidgetStyle(aWidget, "has-secondary-forward-stepper",
401 0 : mozilla::LookAndFeel::eScrollArrow_StartForward);
402 : }
403 :
404 : nsresult
405 0 : nsLookAndFeel::GetIntImpl(IntID aID, PRInt32 &aResult)
406 : {
407 0 : nsresult res = NS_OK;
408 :
409 : // Set these before they can get overrided in the nsXPLookAndFeel.
410 0 : switch (aID) {
411 : case eIntID_ScrollButtonLeftMouseButtonAction:
412 0 : aResult = 0;
413 0 : return NS_OK;
414 : case eIntID_ScrollButtonMiddleMouseButtonAction:
415 0 : aResult = 1;
416 0 : return NS_OK;
417 : case eIntID_ScrollButtonRightMouseButtonAction:
418 0 : aResult = 2;
419 0 : return NS_OK;
420 : default:
421 : break;
422 : }
423 :
424 0 : res = nsXPLookAndFeel::GetIntImpl(aID, aResult);
425 0 : if (NS_SUCCEEDED(res))
426 0 : return res;
427 0 : res = NS_OK;
428 :
429 0 : switch (aID) {
430 : case eIntID_CaretBlinkTime:
431 : {
432 : GtkSettings *settings;
433 : gint blink_time;
434 : gboolean blink;
435 :
436 0 : settings = gtk_settings_get_default ();
437 : g_object_get (settings,
438 : "gtk-cursor-blink-time", &blink_time,
439 : "gtk-cursor-blink", &blink,
440 0 : NULL);
441 :
442 0 : if (blink)
443 0 : aResult = (PRInt32) blink_time;
444 : else
445 0 : aResult = 0;
446 0 : break;
447 : }
448 : case eIntID_CaretWidth:
449 0 : aResult = 1;
450 0 : break;
451 : case eIntID_ShowCaretDuringSelection:
452 0 : aResult = 0;
453 0 : break;
454 : case eIntID_SelectTextfieldsOnKeyFocus:
455 : {
456 : GtkWidget *entry;
457 : GtkSettings *settings;
458 : gboolean select_on_focus;
459 :
460 0 : entry = gtk_entry_new();
461 0 : g_object_ref_sink(entry);
462 0 : settings = gtk_widget_get_settings(entry);
463 : g_object_get(settings,
464 : "gtk-entry-select-on-focus",
465 : &select_on_focus,
466 0 : NULL);
467 :
468 0 : if(select_on_focus)
469 0 : aResult = 1;
470 : else
471 0 : aResult = 0;
472 :
473 0 : gtk_widget_destroy(entry);
474 0 : g_object_unref(entry);
475 : }
476 0 : break;
477 : case eIntID_SubmenuDelay:
478 : {
479 : GtkSettings *settings;
480 : gint delay;
481 :
482 0 : settings = gtk_settings_get_default ();
483 0 : g_object_get (settings, "gtk-menu-popup-delay", &delay, NULL);
484 0 : aResult = (PRInt32) delay;
485 0 : break;
486 : }
487 : case eIntID_TooltipDelay:
488 : {
489 0 : aResult = 500;
490 0 : break;
491 : }
492 : case eIntID_MenusCanOverlapOSBar:
493 : // we want XUL popups to be able to overlap the task bar.
494 0 : aResult = 1;
495 0 : break;
496 : case eIntID_SkipNavigatingDisabledMenuItem:
497 0 : aResult = 1;
498 0 : break;
499 : case eIntID_DragThresholdX:
500 : case eIntID_DragThresholdY:
501 : {
502 0 : GtkWidget* box = gtk_hbox_new(FALSE, 5);
503 0 : gint threshold = 0;
504 0 : g_object_get(gtk_widget_get_settings(box),
505 : "gtk-dnd-drag-threshold", &threshold,
506 0 : NULL);
507 0 : g_object_ref_sink(box);
508 :
509 0 : aResult = threshold;
510 : }
511 0 : break;
512 : case eIntID_ScrollArrowStyle:
513 0 : moz_gtk_init();
514 : aResult =
515 0 : ConvertGTKStepperStyleToMozillaScrollArrowStyle(moz_gtk_get_scrollbar_widget());
516 0 : break;
517 : case eIntID_ScrollSliderStyle:
518 0 : aResult = eScrollThumbStyle_Proportional;
519 0 : break;
520 : case eIntID_TreeOpenDelay:
521 0 : aResult = 1000;
522 0 : break;
523 : case eIntID_TreeCloseDelay:
524 0 : aResult = 1000;
525 0 : break;
526 : case eIntID_TreeLazyScrollDelay:
527 0 : aResult = 150;
528 0 : break;
529 : case eIntID_TreeScrollDelay:
530 0 : aResult = 100;
531 0 : break;
532 : case eIntID_TreeScrollLinesMax:
533 0 : aResult = 3;
534 0 : break;
535 : case eIntID_DWMCompositor:
536 : case eIntID_WindowsClassic:
537 : case eIntID_WindowsDefaultTheme:
538 : case eIntID_WindowsThemeIdentifier:
539 0 : aResult = 0;
540 0 : res = NS_ERROR_NOT_IMPLEMENTED;
541 0 : break;
542 : case eIntID_TouchEnabled:
543 : #ifdef MOZ_PLATFORM_MAEMO
544 : // All Hildon devices are touch-enabled
545 : aResult = 1;
546 : #else
547 0 : aResult = 0;
548 0 : res = NS_ERROR_NOT_IMPLEMENTED;
549 : #endif
550 0 : break;
551 : case eIntID_MaemoClassic:
552 : #ifdef MOZ_PLATFORM_MAEMO
553 : {
554 : aResult = 0;
555 : nsCOMPtr<nsIPropertyBag2> infoService(do_GetService("@mozilla.org/system-info;1"));
556 : if (infoService) {
557 : nsCString deviceType;
558 : nsresult rv = infoService->GetPropertyAsACString(NS_LITERAL_STRING("device"),
559 : deviceType);
560 : if (NS_SUCCEEDED(rv)) {
561 : if (deviceType.EqualsLiteral("Nokia N8xx"))
562 : aResult = 1;
563 : }
564 : }
565 : }
566 : #else
567 0 : aResult = 0;
568 0 : res = NS_ERROR_NOT_IMPLEMENTED;
569 : #endif
570 0 : break;
571 : case eIntID_MacGraphiteTheme:
572 : case eIntID_MacLionTheme:
573 0 : aResult = 0;
574 0 : res = NS_ERROR_NOT_IMPLEMENTED;
575 0 : break;
576 : case eIntID_IMERawInputUnderlineStyle:
577 : case eIntID_IMEConvertedTextUnderlineStyle:
578 0 : aResult = NS_STYLE_TEXT_DECORATION_STYLE_SOLID;
579 0 : break;
580 : case eIntID_IMESelectedRawTextUnderlineStyle:
581 : case eIntID_IMESelectedConvertedTextUnderline:
582 0 : aResult = NS_STYLE_TEXT_DECORATION_STYLE_NONE;
583 0 : break;
584 : case eIntID_SpellCheckerUnderlineStyle:
585 0 : aResult = NS_STYLE_TEXT_DECORATION_STYLE_WAVY;
586 0 : break;
587 : case eIntID_ImagesInMenus:
588 0 : aResult = moz_gtk_images_in_menus();
589 0 : break;
590 : case eIntID_ImagesInButtons:
591 0 : aResult = moz_gtk_images_in_buttons();
592 0 : break;
593 : case eIntID_MenuBarDrag:
594 0 : aResult = sMenuSupportsDrag;
595 0 : break;
596 : case eIntID_ScrollbarButtonAutoRepeatBehavior:
597 0 : aResult = 1;
598 0 : break;
599 : default:
600 0 : aResult = 0;
601 0 : res = NS_ERROR_FAILURE;
602 : }
603 :
604 0 : return res;
605 : }
606 :
607 : nsresult
608 0 : nsLookAndFeel::GetFloatImpl(FloatID aID, float &aResult)
609 : {
610 0 : nsresult res = NS_OK;
611 0 : res = nsXPLookAndFeel::GetFloatImpl(aID, aResult);
612 0 : if (NS_SUCCEEDED(res))
613 0 : return res;
614 0 : res = NS_OK;
615 :
616 0 : switch (aID) {
617 : case eFloatID_IMEUnderlineRelativeSize:
618 0 : aResult = 1.0f;
619 0 : break;
620 : case eFloatID_SpellCheckerUnderlineRelativeSize:
621 0 : aResult = 1.0f;
622 0 : break;
623 : case eFloatID_CaretAspectRatio:
624 0 : aResult = sCaretRatio;
625 0 : break;
626 : default:
627 0 : aResult = -1.0;
628 0 : res = NS_ERROR_FAILURE;
629 : }
630 0 : return res;
631 : }
632 :
633 : #ifdef MOZ_PANGO
634 : static void
635 0 : GetSystemFontInfo(GtkWidget *aWidget,
636 : nsString *aFontName,
637 : gfxFontStyle *aFontStyle)
638 : {
639 0 : GtkSettings *settings = gtk_widget_get_settings(aWidget);
640 :
641 0 : aFontStyle->style = FONT_STYLE_NORMAL;
642 :
643 : gchar *fontname;
644 0 : g_object_get(settings, "gtk-font-name", &fontname, NULL);
645 :
646 : PangoFontDescription *desc;
647 0 : desc = pango_font_description_from_string(fontname);
648 :
649 0 : aFontStyle->systemFont = true;
650 :
651 0 : g_free(fontname);
652 :
653 0 : NS_NAMED_LITERAL_STRING(quote, "\"");
654 0 : NS_ConvertUTF8toUTF16 family(pango_font_description_get_family(desc));
655 0 : *aFontName = quote + family + quote;
656 :
657 0 : aFontStyle->weight = pango_font_description_get_weight(desc);
658 :
659 : // FIXME: Set aFontStyle->stretch correctly!
660 0 : aFontStyle->stretch = NS_FONT_STRETCH_NORMAL;
661 :
662 0 : float size = float(pango_font_description_get_size(desc)) / PANGO_SCALE;
663 :
664 : // |size| is now either pixels or pango-points (not Mozilla-points!)
665 :
666 0 : if (!pango_font_description_get_size_is_absolute(desc)) {
667 : // |size| is in pango-points, so convert to pixels.
668 0 : size *= float(gfxPlatformGtk::GetDPI()) / POINTS_PER_INCH_FLOAT;
669 : }
670 :
671 : // |size| is now pixels
672 :
673 0 : aFontStyle->size = size;
674 :
675 0 : pango_font_description_free(desc);
676 0 : }
677 :
678 : static void
679 0 : GetSystemFontInfo(LookAndFeel::FontID aID,
680 : nsString *aFontName,
681 : gfxFontStyle *aFontStyle)
682 : {
683 0 : if (aID == LookAndFeel::eFont_Widget) {
684 0 : GtkWidget *label = gtk_label_new("M");
685 0 : GtkWidget *parent = gtk_fixed_new();
686 0 : GtkWidget *window = gtk_window_new(GTK_WINDOW_POPUP);
687 :
688 0 : gtk_container_add(GTK_CONTAINER(parent), label);
689 0 : gtk_container_add(GTK_CONTAINER(window), parent);
690 :
691 0 : gtk_widget_ensure_style(label);
692 0 : GetSystemFontInfo(label, aFontName, aFontStyle);
693 0 : gtk_widget_destroy(window); // no unref, windows are different
694 :
695 0 : } else if (aID == LookAndFeel::eFont_Button) {
696 0 : GtkWidget *label = gtk_label_new("M");
697 0 : GtkWidget *parent = gtk_fixed_new();
698 0 : GtkWidget *button = gtk_button_new();
699 0 : GtkWidget *window = gtk_window_new(GTK_WINDOW_POPUP);
700 :
701 0 : gtk_container_add(GTK_CONTAINER(button), label);
702 0 : gtk_container_add(GTK_CONTAINER(parent), button);
703 0 : gtk_container_add(GTK_CONTAINER(window), parent);
704 :
705 0 : gtk_widget_ensure_style(label);
706 0 : GetSystemFontInfo(label, aFontName, aFontStyle);
707 0 : gtk_widget_destroy(window); // no unref, windows are different
708 :
709 0 : } else if (aID == LookAndFeel::eFont_Field) {
710 0 : GtkWidget *entry = gtk_entry_new();
711 0 : GtkWidget *parent = gtk_fixed_new();
712 0 : GtkWidget *window = gtk_window_new(GTK_WINDOW_POPUP);
713 :
714 0 : gtk_container_add(GTK_CONTAINER(parent), entry);
715 0 : gtk_container_add(GTK_CONTAINER(window), parent);
716 :
717 0 : gtk_widget_ensure_style(entry);
718 0 : GetSystemFontInfo(entry, aFontName, aFontStyle);
719 0 : gtk_widget_destroy(window); // no unref, windows are different
720 :
721 : } else {
722 0 : NS_ABORT_IF_FALSE(aID == LookAndFeel::eFont_Menu, "unexpected font ID");
723 0 : GtkWidget *accel_label = gtk_accel_label_new("M");
724 0 : GtkWidget *menuitem = gtk_menu_item_new();
725 0 : GtkWidget *menu = gtk_menu_new();
726 0 : g_object_ref_sink(GTK_OBJECT(menu));
727 :
728 0 : gtk_container_add(GTK_CONTAINER(menuitem), accel_label);
729 0 : gtk_menu_shell_append((GtkMenuShell *)GTK_MENU(menu), menuitem);
730 :
731 0 : gtk_widget_ensure_style(accel_label);
732 0 : GetSystemFontInfo(accel_label, aFontName, aFontStyle);
733 0 : g_object_unref(menu);
734 : }
735 0 : }
736 :
737 : #else // not MOZ_PANGO
738 :
739 : static void
740 : GetSystemFontInfo(LookAndFeel::FontID /*unused */,
741 : nsString *aFontName,
742 : gfxFontStyle *aFontStyle)
743 : {
744 : /* FIXME: DFB FT2 Hardcoding the system font info for now. */
745 : aFontStyle->style = FONT_STYLE_NORMAL;
746 : aFontStyle->weight = 400;
747 : aFontStyle->size = 40/3;
748 : aFontStyle->stretch = NS_FONT_STRETCH_NORMAL;
749 : aFontStyle->systemFont = true;
750 : aFontName->AssignLiteral("\"Sans\"");
751 : }
752 :
753 : #endif // not MOZ_PANGO
754 :
755 : bool
756 0 : nsLookAndFeel::GetFontImpl(FontID aID, nsString& aFontName,
757 : gfxFontStyle& aFontStyle)
758 : {
759 0 : nsString *cachedFontName = NULL;
760 0 : gfxFontStyle *cachedFontStyle = NULL;
761 0 : bool *isCached = NULL;
762 :
763 0 : switch (aID) {
764 : case eFont_Menu: // css2
765 : case eFont_PullDownMenu: // css3
766 0 : cachedFontName = &mMenuFontName;
767 0 : cachedFontStyle = &mMenuFontStyle;
768 0 : isCached = &mMenuFontCached;
769 0 : aID = eFont_Menu;
770 0 : break;
771 :
772 : case eFont_Field: // css3
773 : case eFont_List: // css3
774 0 : cachedFontName = &mFieldFontName;
775 0 : cachedFontStyle = &mFieldFontStyle;
776 0 : isCached = &mFieldFontCached;
777 0 : aID = eFont_Field;
778 0 : break;
779 :
780 : case eFont_Button: // css3
781 0 : cachedFontName = &mButtonFontName;
782 0 : cachedFontStyle = &mButtonFontStyle;
783 0 : isCached = &mButtonFontCached;
784 0 : break;
785 :
786 : case eFont_Caption: // css2
787 : case eFont_Icon: // css2
788 : case eFont_MessageBox: // css2
789 : case eFont_SmallCaption: // css2
790 : case eFont_StatusBar: // css2
791 : case eFont_Window: // css3
792 : case eFont_Document: // css3
793 : case eFont_Workspace: // css3
794 : case eFont_Desktop: // css3
795 : case eFont_Info: // css3
796 : case eFont_Dialog: // css3
797 : case eFont_Tooltips: // moz
798 : case eFont_Widget: // moz
799 0 : cachedFontName = &mDefaultFontName;
800 0 : cachedFontStyle = &mDefaultFontStyle;
801 0 : isCached = &mDefaultFontCached;
802 0 : aID = eFont_Widget;
803 0 : break;
804 : }
805 :
806 0 : if (!*isCached) {
807 0 : GetSystemFontInfo(aID, cachedFontName, cachedFontStyle);
808 0 : *isCached = true;
809 : }
810 :
811 0 : aFontName = *cachedFontName;
812 0 : aFontStyle = *cachedFontStyle;
813 0 : return true;
814 : }
815 :
816 : void
817 0 : nsLookAndFeel::InitLookAndFeel()
818 : {
819 : GtkStyle *style;
820 :
821 : // tooltip foreground and background
822 : style = gtk_rc_get_style_by_paths(gtk_settings_get_default(),
823 : "gtk-tooltips", "GtkWindow",
824 0 : GTK_TYPE_WINDOW);
825 0 : if (style) {
826 0 : sInfoBackground = GDK_COLOR_TO_NS_RGB(style->bg[GTK_STATE_NORMAL]);
827 0 : sInfoText = GDK_COLOR_TO_NS_RGB(style->fg[GTK_STATE_NORMAL]);
828 : }
829 :
830 : // menu foreground & menu background
831 0 : GtkWidget *accel_label = gtk_accel_label_new("M");
832 0 : GtkWidget *menuitem = gtk_menu_item_new();
833 0 : GtkWidget *menu = gtk_menu_new();
834 :
835 0 : g_object_ref_sink(menu);
836 :
837 0 : gtk_container_add(GTK_CONTAINER(menuitem), accel_label);
838 0 : gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
839 :
840 0 : gtk_widget_set_style(accel_label, NULL);
841 0 : gtk_widget_set_style(menu, NULL);
842 0 : gtk_widget_realize(menu);
843 0 : gtk_widget_realize(accel_label);
844 :
845 0 : style = gtk_widget_get_style(accel_label);
846 0 : if (style) {
847 0 : sMenuText = GDK_COLOR_TO_NS_RGB(style->fg[GTK_STATE_NORMAL]);
848 : }
849 :
850 0 : style = gtk_widget_get_style(menu);
851 0 : if (style) {
852 0 : sMenuBackground = GDK_COLOR_TO_NS_RGB(style->bg[GTK_STATE_NORMAL]);
853 : }
854 :
855 0 : style = gtk_widget_get_style(menuitem);
856 0 : if (style) {
857 0 : sMenuHover = GDK_COLOR_TO_NS_RGB(style->bg[GTK_STATE_PRELIGHT]);
858 0 : sMenuHoverText = GDK_COLOR_TO_NS_RGB(style->fg[GTK_STATE_PRELIGHT]);
859 : }
860 :
861 0 : g_object_unref(menu);
862 :
863 :
864 : // button styles
865 0 : GtkWidget *parent = gtk_fixed_new();
866 0 : GtkWidget *button = gtk_button_new();
867 0 : GtkWidget *label = gtk_label_new("M");
868 0 : GtkWidget *combobox = gtk_combo_box_new();
869 0 : GtkWidget *comboboxLabel = gtk_label_new("M");
870 0 : GtkWidget *window = gtk_window_new(GTK_WINDOW_POPUP);
871 0 : GtkWidget *treeView = gtk_tree_view_new();
872 0 : GtkWidget *linkButton = gtk_link_button_new("http://example.com/");
873 0 : GtkWidget *menuBar = gtk_menu_bar_new();
874 0 : GtkWidget *entry = gtk_entry_new();
875 :
876 0 : gtk_container_add(GTK_CONTAINER(button), label);
877 0 : gtk_container_add(GTK_CONTAINER(combobox), comboboxLabel);
878 0 : gtk_container_add(GTK_CONTAINER(parent), button);
879 0 : gtk_container_add(GTK_CONTAINER(parent), treeView);
880 0 : gtk_container_add(GTK_CONTAINER(parent), linkButton);
881 0 : gtk_container_add(GTK_CONTAINER(parent), combobox);
882 0 : gtk_container_add(GTK_CONTAINER(parent), menuBar);
883 0 : gtk_container_add(GTK_CONTAINER(window), parent);
884 0 : gtk_container_add(GTK_CONTAINER(parent), entry);
885 :
886 0 : gtk_widget_set_style(button, NULL);
887 0 : gtk_widget_set_style(label, NULL);
888 0 : gtk_widget_set_style(treeView, NULL);
889 0 : gtk_widget_set_style(linkButton, NULL);
890 0 : gtk_widget_set_style(combobox, NULL);
891 0 : gtk_widget_set_style(comboboxLabel, NULL);
892 0 : gtk_widget_set_style(menuBar, NULL);
893 0 : gtk_widget_set_style(entry, NULL);
894 :
895 0 : gtk_widget_realize(button);
896 0 : gtk_widget_realize(label);
897 0 : gtk_widget_realize(treeView);
898 0 : gtk_widget_realize(linkButton);
899 0 : gtk_widget_realize(combobox);
900 0 : gtk_widget_realize(comboboxLabel);
901 0 : gtk_widget_realize(menuBar);
902 0 : gtk_widget_realize(entry);
903 :
904 0 : style = gtk_widget_get_style(label);
905 0 : if (style) {
906 0 : sButtonText = GDK_COLOR_TO_NS_RGB(style->fg[GTK_STATE_NORMAL]);
907 : }
908 :
909 0 : style = gtk_widget_get_style(comboboxLabel);
910 0 : if (style) {
911 0 : sComboBoxText = GDK_COLOR_TO_NS_RGB(style->fg[GTK_STATE_NORMAL]);
912 : }
913 0 : style = gtk_widget_get_style(combobox);
914 0 : if (style) {
915 0 : sComboBoxBackground = GDK_COLOR_TO_NS_RGB(style->bg[GTK_STATE_NORMAL]);
916 : }
917 :
918 0 : style = gtk_widget_get_style(menuBar);
919 0 : if (style) {
920 0 : sMenuBarText = GDK_COLOR_TO_NS_RGB(style->fg[GTK_STATE_NORMAL]);
921 0 : sMenuBarHoverText = GDK_COLOR_TO_NS_RGB(style->fg[GTK_STATE_SELECTED]);
922 : }
923 :
924 : // Some themes have a unified menu bar, and support window dragging on it
925 0 : gboolean supports_menubar_drag = FALSE;
926 : GParamSpec *param_spec =
927 : gtk_widget_class_find_style_property(GTK_WIDGET_GET_CLASS(menuBar),
928 0 : "window-dragging");
929 0 : if (param_spec) {
930 0 : if (g_type_is_a(G_PARAM_SPEC_VALUE_TYPE(param_spec), G_TYPE_BOOLEAN)) {
931 : gtk_widget_style_get(menuBar,
932 : "window-dragging", &supports_menubar_drag,
933 0 : NULL);
934 : }
935 : }
936 0 : sMenuSupportsDrag = supports_menubar_drag;
937 :
938 : // GTK's guide to fancy odd row background colors:
939 : // 1) Check if a theme explicitly defines an odd row color
940 : // 2) If not, check if it defines an even row color, and darken it
941 : // slightly by a hardcoded value (gtkstyle.c)
942 : // 3) If neither are defined, take the base background color and
943 : // darken that by a hardcoded value
944 : GdkColor colorValue;
945 0 : GdkColor *colorValuePtr = NULL;
946 : gtk_widget_style_get(treeView,
947 : "odd-row-color", &colorValuePtr,
948 0 : NULL);
949 :
950 0 : if (colorValuePtr) {
951 0 : colorValue = *colorValuePtr;
952 : } else {
953 : gtk_widget_style_get(treeView,
954 : "even-row-color", &colorValuePtr,
955 0 : NULL);
956 0 : if (colorValuePtr)
957 0 : darken_gdk_color(colorValuePtr, &colorValue);
958 : else
959 0 : darken_gdk_color(&treeView->style->base[GTK_STATE_NORMAL], &colorValue);
960 : }
961 :
962 0 : sOddCellBackground = GDK_COLOR_TO_NS_RGB(colorValue);
963 0 : if (colorValuePtr)
964 0 : gdk_color_free(colorValuePtr);
965 :
966 0 : style = gtk_widget_get_style(button);
967 0 : if (style) {
968 0 : sButtonBackground = GDK_COLOR_TO_NS_RGB(style->bg[GTK_STATE_NORMAL]);
969 : sButtonOuterLightBorder =
970 0 : GDK_COLOR_TO_NS_RGB(style->light[GTK_STATE_NORMAL]);
971 : sButtonInnerDarkBorder =
972 0 : GDK_COLOR_TO_NS_RGB(style->dark[GTK_STATE_NORMAL]);
973 : }
974 :
975 0 : colorValuePtr = NULL;
976 0 : gtk_widget_style_get(linkButton, "link-color", &colorValuePtr, NULL);
977 0 : if (colorValuePtr) {
978 0 : colorValue = *colorValuePtr; // we can't pass deref pointers to GDK_COLOR_TO_NS_RGB
979 0 : sNativeHyperLinkText = GDK_COLOR_TO_NS_RGB(colorValue);
980 0 : gdk_color_free(colorValuePtr);
981 : } else {
982 0 : sNativeHyperLinkText = NS_RGB(0x00,0x00,0xEE);
983 : }
984 :
985 : // invisible character styles
986 : guint value;
987 0 : g_object_get (entry, "invisible-char", &value, NULL);
988 0 : sInvisibleCharacter = PRUnichar(value);
989 :
990 : // caret styles
991 : gtk_widget_style_get(entry,
992 : "cursor-aspect-ratio", &sCaretRatio,
993 0 : NULL);
994 :
995 0 : gtk_widget_destroy(window);
996 0 : }
997 :
998 : void
999 0 : nsLookAndFeel::InitWidget()
1000 : {
1001 0 : NS_ASSERTION(!mStyle, "already initialized");
1002 : // GtkInvisibles come with a refcount that is not floating
1003 : // (since their initialization code calls g_object_ref_sink) and
1004 : // their destroy code releases that reference (which means they
1005 : // have to be explicitly destroyed, since calling unref enough
1006 : // to cause destruction would lead to *another* unref).
1007 : // However, this combination means that it's actually still ok
1008 : // to use the normal pattern, which is to g_object_ref_sink
1009 : // after construction, and then destroy *and* unref when we're
1010 : // done. (Though we could skip the g_object_ref_sink and the
1011 : // corresponding g_object_unref, but that's particular to
1012 : // GtkInvisibles and GtkWindows.)
1013 0 : GtkWidget *widget = gtk_invisible_new();
1014 0 : g_object_ref_sink(widget); // effectively g_object_ref (see above)
1015 :
1016 0 : gtk_widget_ensure_style(widget);
1017 0 : mStyle = gtk_style_copy(gtk_widget_get_style(widget));
1018 :
1019 0 : gtk_widget_destroy(widget);
1020 0 : g_object_unref(widget);
1021 0 : }
1022 :
1023 : // virtual
1024 : PRUnichar
1025 0 : nsLookAndFeel::GetPasswordCharacterImpl()
1026 : {
1027 0 : return sInvisibleCharacter;
1028 : }
1029 :
1030 : void
1031 0 : nsLookAndFeel::RefreshImpl()
1032 : {
1033 0 : nsXPLookAndFeel::RefreshImpl();
1034 :
1035 0 : mDefaultFontCached = false;
1036 0 : mButtonFontCached = false;
1037 0 : mFieldFontCached = false;
1038 0 : mMenuFontCached = false;
1039 :
1040 0 : g_object_unref(mStyle);
1041 0 : mStyle = nsnull;
1042 :
1043 0 : InitWidget();
1044 0 : InitLookAndFeel();
1045 0 : }
1046 :
1047 : bool
1048 0 : nsLookAndFeel::GetEchoPasswordImpl() {
1049 : #ifdef MOZ_PLATFORM_MAEMO
1050 : return true;
1051 : #else
1052 0 : return false;
1053 : #endif
1054 : }
|