diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:30:52 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:30:52 -0800 |
commit | 8e35f3cfc7fba1d1c829dc557ebad6409cbe16a2 (patch) | |
tree | 11425ea0b299d6fb89c6d3618a22d97d5bf68d0f /WebCore/platform/gtk | |
parent | 648161bb0edfc3d43db63caed5cc5213bc6cb78f (diff) | |
download | external_webkit-8e35f3cfc7fba1d1c829dc557ebad6409cbe16a2.zip external_webkit-8e35f3cfc7fba1d1c829dc557ebad6409cbe16a2.tar.gz external_webkit-8e35f3cfc7fba1d1c829dc557ebad6409cbe16a2.tar.bz2 |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'WebCore/platform/gtk')
43 files changed, 9665 insertions, 0 deletions
diff --git a/WebCore/platform/gtk/ClipboardGtk.cpp b/WebCore/platform/gtk/ClipboardGtk.cpp new file mode 100644 index 0000000..44aa7f7 --- /dev/null +++ b/WebCore/platform/gtk/ClipboardGtk.cpp @@ -0,0 +1,127 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "ClipboardGtk.h" + +#include "NotImplemented.h" +#include "StringHash.h" + +#include "Editor.h" + +namespace WebCore { + +PassRefPtr<Clipboard> Editor::newGeneralClipboard(ClipboardAccessPolicy policy) +{ + return ClipboardGtk::create(policy, false); +} + +ClipboardGtk::ClipboardGtk(ClipboardAccessPolicy policy, bool forDragging) + : Clipboard(policy, forDragging) +{ + notImplemented(); +} + +ClipboardGtk::~ClipboardGtk() +{ + notImplemented(); +} + +void ClipboardGtk::clearData(const String&) +{ + notImplemented(); +} + +void ClipboardGtk::clearAllData() +{ + notImplemented(); +} + +String ClipboardGtk::getData(const String&, bool &success) const +{ + notImplemented(); + success = false; + return String(); +} + +bool ClipboardGtk::setData(const String&, const String&) +{ + notImplemented(); + return false; +} + +HashSet<String> ClipboardGtk::types() const +{ + notImplemented(); + return HashSet<String>(); +} + +IntPoint ClipboardGtk::dragLocation() const +{ + notImplemented(); + return IntPoint(0, 0); +} + +CachedImage* ClipboardGtk::dragImage() const +{ + notImplemented(); + return 0; +} + +void ClipboardGtk::setDragImage(CachedImage*, const IntPoint&) +{ + notImplemented(); +} + +Node* ClipboardGtk::dragImageElement() +{ + notImplemented(); + return 0; +} + +void ClipboardGtk::setDragImageElement(Node*, const IntPoint&) +{ + notImplemented(); +} + +DragImageRef ClipboardGtk::createDragImage(IntPoint&) const +{ + notImplemented(); + return 0; +} + +void ClipboardGtk::declareAndWriteDragImage(Element*, const KURL&, const String&, Frame*) +{ + notImplemented(); +} + +void ClipboardGtk::writeURL(const KURL&, const String&, Frame*) +{ + notImplemented(); +} + +void ClipboardGtk::writeRange(Range*, Frame*) +{ + notImplemented(); +} + +bool ClipboardGtk::hasData() +{ + notImplemented(); + return false; +} + +} diff --git a/WebCore/platform/gtk/ClipboardGtk.h b/WebCore/platform/gtk/ClipboardGtk.h new file mode 100644 index 0000000..b8b4ddf --- /dev/null +++ b/WebCore/platform/gtk/ClipboardGtk.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2007, Holger Hans Peter Freyther + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ClipboardGdk_h +#define ClipboardGdk_h + +#include "Clipboard.h" + +namespace WebCore { + class CachedImage; + + // State available during IE's events for drag and drop and copy/paste + // Created from the EventHandlerGtk to be used by the dom + class ClipboardGtk : public Clipboard { + public: + static PassRefPtr<ClipboardGtk> create(ClipboardAccessPolicy policy, bool isForDragging) + { + return adoptRef(new ClipboardGtk(policy, isForDragging)); + } + virtual ~ClipboardGtk(); + + void clearData(const String&); + void clearAllData(); + String getData(const String&, bool&) const; + bool setData(const String&, const String&); + + HashSet<String> types() const; + IntPoint dragLocation() const; + CachedImage* dragImage() const; + void setDragImage(CachedImage*, const IntPoint&); + Node* dragImageElement(); + void setDragImageElement(Node*, const IntPoint&); + + virtual DragImageRef createDragImage(IntPoint&) const; + virtual void declareAndWriteDragImage(Element*, const KURL&, const String&, Frame*); + virtual void writeURL(const KURL&, const String&, Frame*); + virtual void writeRange(Range*, Frame*); + + virtual bool hasData(); + + private: + ClipboardGtk(ClipboardAccessPolicy, bool); + }; +} + +#endif diff --git a/WebCore/platform/gtk/ContextMenuGtk.cpp b/WebCore/platform/gtk/ContextMenuGtk.cpp new file mode 100644 index 0000000..2365379 --- /dev/null +++ b/WebCore/platform/gtk/ContextMenuGtk.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2007 Holger Hans Peter Freyther + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "ContextMenu.h" + +#include "ContextMenuController.h" + +#include <gtk/gtk.h> + +namespace WebCore { + +// TODO: ref-counting correctness checking. +// See http://bugs.webkit.org/show_bug.cgi?id=16115 + +static void menuItemActivated(GtkMenuItem* item, ContextMenuController* controller) +{ + ContextMenuItem contextItem(item); + controller->contextMenuItemSelected(&contextItem); +} + +ContextMenu::ContextMenu(const HitTestResult& result) + : m_hitTestResult(result) +{ + m_platformDescription = GTK_MENU(gtk_menu_new()); + +#if GLIB_CHECK_VERSION(2,10,0) + g_object_ref_sink(G_OBJECT(m_platformDescription)); +#else + g_object_ref(G_OBJECT(m_platformDescription)); + gtk_object_sink(GTK_OBJECT(m_platformDescription)); +#endif +} + +ContextMenu::~ContextMenu() +{ + if (m_platformDescription) + g_object_unref(m_platformDescription); +} + +void ContextMenu::appendItem(ContextMenuItem& item) +{ + ASSERT(m_platformDescription); + checkOrEnableIfNeeded(item); + + ContextMenuItemType type = item.type(); + GtkMenuItem* platformItem = ContextMenuItem::createNativeMenuItem(item.releasePlatformDescription()); + ASSERT(platformItem); + + if (type == ActionType || type == CheckableActionType) + g_signal_connect(platformItem, "activate", G_CALLBACK(menuItemActivated), controller()); + + gtk_menu_shell_append(GTK_MENU_SHELL(m_platformDescription), GTK_WIDGET(platformItem)); + gtk_widget_show(GTK_WIDGET(platformItem)); +} + +void ContextMenu::setPlatformDescription(PlatformMenuDescription menu) +{ + ASSERT(menu); + if (m_platformDescription) + g_object_unref(m_platformDescription); + + m_platformDescription = menu; + g_object_ref(m_platformDescription); +} + +PlatformMenuDescription ContextMenu::platformDescription() const +{ + return m_platformDescription; +} + +PlatformMenuDescription ContextMenu::releasePlatformDescription() +{ + PlatformMenuDescription description = m_platformDescription; + m_platformDescription = 0; + + return description; +} + +} diff --git a/WebCore/platform/gtk/ContextMenuItemGtk.cpp b/WebCore/platform/gtk/ContextMenuItemGtk.cpp new file mode 100644 index 0000000..84f78c0 --- /dev/null +++ b/WebCore/platform/gtk/ContextMenuItemGtk.cpp @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2007 Holger Hans Peter Freyther + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "ContextMenu.h" +#include "ContextMenuItem.h" +#include "CString.h" +#include "NotImplemented.h" + +#include <gtk/gtk.h> + +#define WEBKIT_CONTEXT_MENU_ACTION "webkit-context-menu" + +namespace WebCore { + +static const char* gtkStockIDFromContextMenuAction(const ContextMenuAction& action) +{ + switch (action) { + case ContextMenuItemTagCopyLinkToClipboard: + case ContextMenuItemTagCopyImageToClipboard: + case ContextMenuItemTagCopy: + return GTK_STOCK_COPY; + case ContextMenuItemTagOpenLinkInNewWindow: + case ContextMenuItemTagOpenImageInNewWindow: + case ContextMenuItemTagOpenFrameInNewWindow: + return GTK_STOCK_OPEN; + case ContextMenuItemTagDownloadLinkToDisk: + case ContextMenuItemTagDownloadImageToDisk: + return GTK_STOCK_SAVE; + case ContextMenuItemTagGoBack: + return GTK_STOCK_GO_BACK; + case ContextMenuItemTagGoForward: + return GTK_STOCK_GO_FORWARD; + case ContextMenuItemTagStop: + return GTK_STOCK_STOP; + case ContextMenuItemTagReload: + return GTK_STOCK_REFRESH; + case ContextMenuItemTagCut: + return GTK_STOCK_CUT; + case ContextMenuItemTagPaste: + return GTK_STOCK_PASTE; + case ContextMenuItemTagDelete: + return GTK_STOCK_DELETE; +#if GTK_CHECK_VERSION(2, 10, 0) + case ContextMenuItemTagSelectAll: + return GTK_STOCK_SELECT_ALL; +#endif + case ContextMenuItemTagSpellingGuess: + return GTK_STOCK_INFO; + case ContextMenuItemTagIgnoreSpelling: + return GTK_STOCK_NO; + case ContextMenuItemTagLearnSpelling: + return GTK_STOCK_OK; + case ContextMenuItemTagOther: + return GTK_STOCK_MISSING_IMAGE; + case ContextMenuItemTagSearchInSpotlight: + return GTK_STOCK_FIND; + case ContextMenuItemTagSearchWeb: + return GTK_STOCK_FIND; + case ContextMenuItemTagOpenWithDefaultApplication: + return GTK_STOCK_OPEN; + case ContextMenuItemPDFZoomIn: + return GTK_STOCK_ZOOM_IN; + case ContextMenuItemPDFZoomOut: + return GTK_STOCK_ZOOM_OUT; + case ContextMenuItemPDFAutoSize: + return GTK_STOCK_ZOOM_FIT; + case ContextMenuItemPDFNextPage: + return GTK_STOCK_GO_FORWARD; + case ContextMenuItemPDFPreviousPage: + return GTK_STOCK_GO_BACK; + // New tags, not part of API + case ContextMenuItemTagOpenLink: + return GTK_STOCK_OPEN; + case ContextMenuItemTagCheckSpelling: + return GTK_STOCK_SPELL_CHECK; + case ContextMenuItemTagFontMenu: + return GTK_STOCK_SELECT_FONT; + case ContextMenuItemTagShowFonts: + return GTK_STOCK_SELECT_FONT; + case ContextMenuItemTagBold: + return GTK_STOCK_BOLD; + case ContextMenuItemTagItalic: + return GTK_STOCK_ITALIC; + case ContextMenuItemTagUnderline: + return GTK_STOCK_UNDERLINE; + case ContextMenuItemTagShowColors: + return GTK_STOCK_SELECT_COLOR; + default: + return NULL; + } +} + +// Extract the ActionType from the menu item +ContextMenuItem::ContextMenuItem(GtkMenuItem* item) + : m_platformDescription() +{ + if (GTK_IS_SEPARATOR_MENU_ITEM(item)) + m_platformDescription.type = SeparatorType; + else if (gtk_menu_item_get_submenu(item)) + m_platformDescription.type = SubmenuType; + else if (GTK_IS_CHECK_MENU_ITEM(item)) { + m_platformDescription.type = CheckableActionType; + m_platformDescription.checked = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(item)); + } else + m_platformDescription.type = ActionType; + + m_platformDescription.action = *static_cast<ContextMenuAction*>(g_object_get_data(G_OBJECT(item), WEBKIT_CONTEXT_MENU_ACTION)); + + m_platformDescription.subMenu = GTK_MENU(gtk_menu_item_get_submenu(item)); + if (m_platformDescription.subMenu) + g_object_ref(m_platformDescription.subMenu); +} + +ContextMenuItem::ContextMenuItem(ContextMenu*) +{ + notImplemented(); +} + +ContextMenuItem::ContextMenuItem(ContextMenuItemType type, ContextMenuAction action, const String& title, ContextMenu* subMenu) +{ + m_platformDescription.type = type; + m_platformDescription.action = action; + m_platformDescription.title = title; + + setSubMenu(subMenu); +} + +ContextMenuItem::~ContextMenuItem() +{ + if (m_platformDescription.subMenu) + g_object_unref(m_platformDescription.subMenu); +} + +GtkMenuItem* ContextMenuItem::createNativeMenuItem(const PlatformMenuItemDescription& menu) +{ + GtkMenuItem* item = 0; + if (menu.type == SeparatorType) + item = GTK_MENU_ITEM(gtk_separator_menu_item_new()); + else { + if (menu.type == CheckableActionType) { + item = GTK_MENU_ITEM(gtk_check_menu_item_new_with_mnemonic(menu.title.utf8().data())); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), menu.checked); + } else { + if (const gchar* stockID = gtkStockIDFromContextMenuAction(menu.action)) { + item = GTK_MENU_ITEM(gtk_image_menu_item_new_with_mnemonic(menu.title.utf8().data())); + GtkWidget* image = gtk_image_new_from_stock(stockID, GTK_ICON_SIZE_MENU); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image); + } else + item = GTK_MENU_ITEM(gtk_menu_item_new_with_mnemonic(menu.title.utf8().data())); + } + + ContextMenuAction* menuAction = static_cast<ContextMenuAction*>(malloc(sizeof(ContextMenuAction*))); + *menuAction = menu.action; + g_object_set_data(G_OBJECT(item), WEBKIT_CONTEXT_MENU_ACTION, menuAction); + + gtk_widget_set_sensitive(GTK_WIDGET(item), menu.enabled); + + if (menu.subMenu) + gtk_menu_item_set_submenu(item, GTK_WIDGET(menu.subMenu)); + } + + return item; +} + +PlatformMenuItemDescription ContextMenuItem::releasePlatformDescription() +{ + PlatformMenuItemDescription description = m_platformDescription; + m_platformDescription = PlatformMenuItemDescription(); + return description; +} + +ContextMenuItemType ContextMenuItem::type() const +{ + return m_platformDescription.type; +} + +void ContextMenuItem::setType(ContextMenuItemType type) +{ + m_platformDescription.type = type; +} + +ContextMenuAction ContextMenuItem::action() const +{ + return m_platformDescription.action; +} + +void ContextMenuItem::setAction(ContextMenuAction action) +{ + m_platformDescription.action = action; +} + +String ContextMenuItem::title() const +{ + notImplemented(); + return String(); +} + +void ContextMenuItem::setTitle(const String&) +{ + notImplemented(); +} + +PlatformMenuDescription ContextMenuItem::platformSubMenu() const +{ + return m_platformDescription.subMenu; +} + +void ContextMenuItem::setSubMenu(ContextMenu* menu) +{ + if (m_platformDescription.subMenu) + g_object_unref(m_platformDescription.subMenu); + + if (!menu) + return; + + m_platformDescription.subMenu = menu->releasePlatformDescription(); + m_platformDescription.type = SubmenuType; + +#if GLIB_CHECK_VERSION(2,10,0) + g_object_ref_sink(G_OBJECT(m_platformDescription.subMenu)); +#else + g_object_ref(G_OBJECT(m_platformDescription.subMenu)); + gtk_object_sink(GTK_OBJECT(m_platformDescription.subMenu)); +#endif +} + +void ContextMenuItem::setChecked(bool shouldCheck) +{ + m_platformDescription.checked = shouldCheck; +} + +void ContextMenuItem::setEnabled(bool shouldEnable) +{ + m_platformDescription.enabled = shouldEnable; +} + +} diff --git a/WebCore/platform/gtk/CursorGtk.cpp b/WebCore/platform/gtk/CursorGtk.cpp new file mode 100644 index 0000000..76f6d00 --- /dev/null +++ b/WebCore/platform/gtk/CursorGtk.cpp @@ -0,0 +1,341 @@ +/* + * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com + * Copyright (C) 2007 Christian Dywan <christian@twotoasts.de> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CursorGtk.h" + +#include "NotImplemented.h" +#include <wtf/Assertions.h> + +#include <gdk/gdk.h> +#include <gtk/gtk.h> + +namespace WebCore { + +static GdkCursor* customCursorNew(CustomCursorType cursorType) +{ + CustomCursor cursor = CustomCursors[cursorType]; + GdkCursor* c = gdk_cursor_new_from_name(gdk_display_get_default(), cursor.name); + if (!c) { + const GdkColor fg = { 0, 0, 0, 0 }; + const GdkColor bg = { 65535, 65535, 65535, 65535 }; + + GdkPixmap* source = gdk_bitmap_create_from_data(NULL, cursor.bits, 32, 32); + GdkPixmap* mask = gdk_bitmap_create_from_data(NULL, cursor.mask_bits, 32, 32); + c = gdk_cursor_new_from_pixmap(source, mask, &fg, &bg, cursor.hot_x, cursor.hot_y); + g_object_unref(source); + g_object_unref(mask); + } + return c; +} + + +Cursor::Cursor(const Cursor& other) + : m_impl(other.m_impl) +{ + if (m_impl) + gdk_cursor_ref(m_impl); +} + +Cursor::Cursor(Image*, const IntPoint&) +{ + notImplemented(); +} + +Cursor::~Cursor() +{ + if (m_impl) + gdk_cursor_unref(m_impl); +} + +Cursor& Cursor::operator=(const Cursor& other) +{ + gdk_cursor_ref(other.m_impl); + gdk_cursor_unref(m_impl); + m_impl = other.m_impl; + return *this; +} + +Cursor::Cursor(GdkCursor* c) + : m_impl(c) +{ + m_impl = c; + ASSERT(c); + gdk_cursor_ref(c); +} + +const Cursor& pointerCursor() +{ + static Cursor c = gdk_cursor_new(GDK_LEFT_PTR); + return c; +} + +const Cursor& crossCursor() +{ + static Cursor c = gdk_cursor_new(GDK_CROSS); + return c; +} + +const Cursor& handCursor() +{ + static Cursor c = gdk_cursor_new(GDK_HAND2); + return c; +} + +const Cursor& moveCursor() +{ + static Cursor c = gdk_cursor_new(GDK_FLEUR); + return c; +} + +const Cursor& iBeamCursor() +{ + static Cursor c = gdk_cursor_new(GDK_XTERM); + return c; +} + +const Cursor& waitCursor() +{ + static Cursor c = gdk_cursor_new(GDK_WATCH); + return c; +} + +const Cursor& helpCursor() +{ + static Cursor c = gdk_cursor_new(GDK_QUESTION_ARROW); + return c; +} + +const Cursor& eastResizeCursor() +{ + static Cursor c = gdk_cursor_new(GDK_RIGHT_SIDE); + return c; +} + +const Cursor& northResizeCursor() +{ + static Cursor c = gdk_cursor_new(GDK_TOP_SIDE); + return c; +} + +const Cursor& northEastResizeCursor() +{ + static Cursor c = gdk_cursor_new(GDK_TOP_RIGHT_CORNER); + return c; +} + +const Cursor& northWestResizeCursor() +{ + static Cursor c = gdk_cursor_new(GDK_TOP_LEFT_CORNER); + return c; +} + +const Cursor& southResizeCursor() +{ + static Cursor c = gdk_cursor_new(GDK_BOTTOM_SIDE); + return c; +} + +const Cursor& southEastResizeCursor() +{ + static Cursor c = gdk_cursor_new(GDK_BOTTOM_RIGHT_CORNER); + return c; +} + +const Cursor& southWestResizeCursor() +{ + static Cursor c = gdk_cursor_new(GDK_BOTTOM_LEFT_CORNER); + return c; +} + +const Cursor& westResizeCursor() +{ + static Cursor c = gdk_cursor_new(GDK_LEFT_SIDE); + return c; +} + +const Cursor& northSouthResizeCursor() +{ + static Cursor c = gdk_cursor_new(GDK_TOP_TEE); + return c; +} + +const Cursor& eastWestResizeCursor() +{ + static Cursor c = gdk_cursor_new(GDK_LEFT_SIDE); + return c; +} + +const Cursor& northEastSouthWestResizeCursor() +{ + static Cursor c = gdk_cursor_new(GDK_SIZING); + return c; +} + +const Cursor& northWestSouthEastResizeCursor() +{ + static Cursor c = gdk_cursor_new(GDK_SIZING); + return c; +} + +const Cursor& columnResizeCursor() +{ + static Cursor c = gdk_cursor_new(GDK_DOUBLE_ARROW); + return c; +} + +const Cursor& rowResizeCursor() +{ + static Cursor c = gdk_cursor_new(GDK_DOUBLE_ARROW); + return c; +} + +const Cursor& middlePanningCursor() +{ + return moveCursor(); +} + +const Cursor& eastPanningCursor() +{ + return eastResizeCursor(); +} + +const Cursor& northPanningCursor() +{ + return northResizeCursor(); +} + +const Cursor& northEastPanningCursor() +{ + return northEastResizeCursor(); +} + +const Cursor& northWestPanningCursor() +{ + return northWestResizeCursor(); +} + +const Cursor& southPanningCursor() +{ + return southResizeCursor(); +} + +const Cursor& southEastPanningCursor() +{ + return southEastResizeCursor(); +} + +const Cursor& southWestPanningCursor() +{ + return southWestResizeCursor(); +} + +const Cursor& westPanningCursor() +{ + return westResizeCursor(); +} + + +const Cursor& verticalTextCursor() +{ + static Cursor c = customCursorNew(CustomCursorVerticalText); + return c; +} + +const Cursor& cellCursor() +{ + notImplemented(); + return pointerCursor(); +} + +const Cursor& contextMenuCursor() +{ + static Cursor c = customCursorNew(CustomCursorContextMenu); + return c; +} + +const Cursor& noDropCursor() +{ + notImplemented(); + return pointerCursor(); +} + +const Cursor& copyCursor() +{ + static Cursor c = customCursorNew(CustomCursorCopy); + return c; +} + +const Cursor& progressCursor() +{ + notImplemented(); + return pointerCursor(); +} + +const Cursor& aliasCursor() +{ + static Cursor c = customCursorNew(CustomCursorAlias); + return c; +} + +const Cursor& noneCursor() +{ + notImplemented(); + return pointerCursor(); +} + +const Cursor& notAllowedCursor() +{ + notImplemented(); + return pointerCursor(); +} + +const Cursor& zoomInCursor() +{ + static Cursor c = customCursorNew(CustomCursorZoomIn); + return c; +} + +const Cursor& zoomOutCursor() +{ + static Cursor c = customCursorNew(CustomCursorZoomOut); + return c; +} + +const Cursor& grabCursor() +{ + notImplemented(); + return pointerCursor(); +} + +const Cursor& grabbingCursor() +{ + notImplemented(); + return pointerCursor(); +} + +} diff --git a/WebCore/platform/gtk/CursorGtk.h b/WebCore/platform/gtk/CursorGtk.h new file mode 100644 index 0000000..73f05a9 --- /dev/null +++ b/WebCore/platform/gtk/CursorGtk.h @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2001 Tim Copperfield <timecop@network.email.ne.jp> + * Copyright (C) 2007 Christian Dywan <christian@twotoasts.de> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef CursorGtk_h +#define CursorGtk_h + +#include "Cursor.h" + +/* + These cursors are copied from Mozilla code: + http://lxr.mozilla.org/mozilla1.8/source/widget/src/gtk2/nsGtkCursors.h +*/ + +/* MOZ_CURSOR_VERTICAL_TEXT */ +static const char moz_vertical_text_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, + 0x06, 0x60, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, + 0x02, 0x40, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +static const char moz_vertical_text_mask_bits[] = { + 0x07, 0xe0, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0x0f, 0xf0, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +/* MOZ_CURSOR_CONTEXT_MENU */ +static const char moz_menu_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, + 0x7c, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0xfd, 0x00, 0x00, + 0xfc, 0xff, 0x00, 0x00, 0x7c, 0x84, 0x00, 0x00, 0x6c, 0xfc, 0x00, 0x00, + 0xc4, 0x84, 0x00, 0x00, 0xc0, 0xfc, 0x00, 0x00, 0x80, 0x85, 0x00, 0x00, + 0x80, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +static const char moz_menu_mask_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, + 0xfe, 0x00, 0x00, 0x00, 0xfe, 0xfd, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, + 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xfe, 0x01, 0x00, + 0xee, 0xff, 0x01, 0x00, 0xe4, 0xff, 0x01, 0x00, 0xc0, 0xff, 0x01, 0x00, + 0xc0, 0xff, 0x01, 0x00, 0x80, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +/* MOZ_CURSOR_COPY */ +static const char moz_copy_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, + 0x7c, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x00, + 0xfc, 0x03, 0x00, 0x00, 0x7c, 0x30, 0x00, 0x00, 0x6c, 0x30, 0x00, 0x00, + 0xc4, 0xfc, 0x00, 0x00, 0xc0, 0xfc, 0x00, 0x00, 0x80, 0x31, 0x00, 0x00, + 0x80, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +static const char moz_copy_mask_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, + 0xfe, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0xfe, 0x03, 0x00, 0x00, + 0xfe, 0x37, 0x00, 0x00, 0xfe, 0x7b, 0x00, 0x00, 0xfe, 0xfc, 0x00, 0x00, + 0xee, 0xff, 0x01, 0x00, 0xe4, 0xff, 0x01, 0x00, 0xc0, 0xff, 0x00, 0x00, + 0xc0, 0x7b, 0x00, 0x00, 0x80, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +/* MOZ_CURSOR_ALIAS */ +static const char moz_alias_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, + 0x7c, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x00, + 0xfc, 0x03, 0x00, 0x00, 0x7c, 0xf0, 0x00, 0x00, 0x6c, 0xe0, 0x00, 0x00, + 0xc4, 0xf0, 0x00, 0x00, 0xc0, 0xb0, 0x00, 0x00, 0x80, 0x19, 0x00, 0x00, + 0x80, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +static const char moz_alias_mask_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, + 0xfe, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0xfe, 0x03, 0x00, 0x00, + 0xfe, 0xf7, 0x00, 0x00, 0xfe, 0xfb, 0x01, 0x00, 0xfe, 0xf0, 0x01, 0x00, + 0xee, 0xf9, 0x01, 0x00, 0xe4, 0xf9, 0x01, 0x00, 0xc0, 0xbf, 0x00, 0x00, + 0xc0, 0x3f, 0x00, 0x00, 0x80, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +/* MOZ_CURSOR_ZOOM_IN */ +static const char moz_zoom_in_bits[] = { + 0xf0, 0x00, 0x00, 0x00, 0x0c, 0x03, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00, + 0x62, 0x04, 0x00, 0x00, 0x61, 0x08, 0x00, 0x00, 0xf9, 0x09, 0x00, 0x00, + 0xf9, 0x09, 0x00, 0x00, 0x61, 0x08, 0x00, 0x00, 0x62, 0x04, 0x00, 0x00, + 0x02, 0x04, 0x00, 0x00, 0x0c, 0x0f, 0x00, 0x00, 0xf0, 0x1c, 0x00, 0x00, + 0x00, 0x38, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +static const char moz_zoom_in_mask_bits[] = { + 0xf0, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, + 0xfe, 0x07, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, + 0xff, 0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, + 0xfe, 0x07, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xf0, 0x1c, 0x00, 0x00, + 0x00, 0x38, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +/* MOZ_CURSOR_ZOOM_OUT */ +static const char moz_zoom_out_bits[] = { + 0xf0, 0x00, 0x00, 0x00, 0x0c, 0x03, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00, + 0x02, 0x04, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0xf9, 0x09, 0x00, 0x00, + 0xf9, 0x09, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00, + 0x02, 0x04, 0x00, 0x00, 0x0c, 0x0f, 0x00, 0x00, 0xf0, 0x1c, 0x00, 0x00, + 0x00, 0x38, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +static const char moz_zoom_out_mask_bits[] = { + 0xf0, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, + 0xfe, 0x07, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, + 0xff, 0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, + 0xfe, 0x07, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xf0, 0x1c, 0x00, 0x00, + 0x00, 0x38, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +enum CustomCursorType { + CustomCursorCopy = 0, + CustomCursorAlias, + CustomCursorContextMenu, + CustomCursorZoomIn, + CustomCursorZoomOut, + CustomCursorVerticalText +} ; + +typedef struct { + const char* name; + const char* bits; + const char* mask_bits; + int hot_x; + int hot_y; +} CustomCursor; + +// create custom pixmap cursor from cursors in nsGTKCursorData.h +static const CustomCursor CustomCursors[] = { + { "copy", moz_copy_bits, moz_copy_mask_bits, 2, 2 }, + { "alias", moz_alias_bits, moz_alias_mask_bits, 2, 2 }, + { "context-menu", moz_menu_bits, moz_menu_mask_bits, 2, 2 }, + { "zoom-in", moz_zoom_in_bits, moz_zoom_in_mask_bits, 6, 6 }, + { "zoom-out", moz_zoom_out_bits, moz_zoom_out_mask_bits, 6, 6 }, + { "vertical-text", moz_vertical_text_bits, moz_vertical_text_mask_bits, 8, 4 }, +}; + +#endif // CursorGtk_h diff --git a/WebCore/platform/gtk/DragDataGtk.cpp b/WebCore/platform/gtk/DragDataGtk.cpp new file mode 100644 index 0000000..69b3161 --- /dev/null +++ b/WebCore/platform/gtk/DragDataGtk.cpp @@ -0,0 +1,86 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "DragData.h" + +#include "Clipboard.h" +#include "Document.h" +#include "DocumentFragment.h" + +namespace WebCore { + +bool DragData::canSmartReplace() const +{ + return false; +} + +bool DragData::containsColor() const +{ + return false; +} + +bool DragData::containsFiles() const +{ + return false; +} + +void DragData::asFilenames(Vector<String>& result) const +{ +} + +bool DragData::containsPlainText() const +{ + return false; +} + +String DragData::asPlainText() const +{ + return String(); +} + +Color DragData::asColor() const +{ + return Color(); +} + +PassRefPtr<Clipboard> DragData::createClipboard(ClipboardAccessPolicy) const +{ + return 0; +} + +bool DragData::containsCompatibleContent() const +{ + return false; +} + +bool DragData::containsURL() const +{ + return false; +} + +String DragData::asURL(String* title) const +{ + return String(); +} + + +PassRefPtr<DocumentFragment> DragData::asFragment(Document*) const +{ + return 0; +} + +} diff --git a/WebCore/platform/gtk/DragImageGtk.cpp b/WebCore/platform/gtk/DragImageGtk.cpp new file mode 100644 index 0000000..4ddae3a --- /dev/null +++ b/WebCore/platform/gtk/DragImageGtk.cpp @@ -0,0 +1,54 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "DragImage.h" + +#include "CachedImage.h" +#include "Image.h" + +namespace WebCore { + +IntSize dragImageSize(DragImageRef) +{ + return IntSize(0, 0); +} + +void deleteDragImage(DragImageRef) +{ +} + +DragImageRef scaleDragImage(DragImageRef image, FloatSize) +{ + return image; +} + +DragImageRef dissolveDragImageToFraction(DragImageRef image, float) +{ + return image; +} + +DragImageRef createDragImageFromImage(Image*) +{ + return 0; +} + +DragImageRef createDragImageIconForCachedImage(CachedImage*) +{ + return 0; +} + +} diff --git a/WebCore/platform/gtk/EventLoopGtk.cpp b/WebCore/platform/gtk/EventLoopGtk.cpp new file mode 100644 index 0000000..4ef7b5c --- /dev/null +++ b/WebCore/platform/gtk/EventLoopGtk.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2008 Nuanti Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "EventLoop.h" + +#include <glib.h> + +namespace WebCore { + +void EventLoop::cycle() +{ + g_main_context_iteration(NULL, FALSE); +} + +} // namespace WebCore diff --git a/WebCore/platform/gtk/FileChooserGtk.cpp b/WebCore/platform/gtk/FileChooserGtk.cpp new file mode 100644 index 0000000..e984718 --- /dev/null +++ b/WebCore/platform/gtk/FileChooserGtk.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2007 Holger Hans Peter Freyther + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "FileChooser.h" + +#include "CString.h" +#include "FileSystem.h" +#include "Icon.h" +#include "LocalizedStrings.h" +#include "StringTruncator.h" + +#include <glib.h> +#include <glib/gi18n.h> +#include <gtk/gtk.h> + +namespace WebCore { + +static bool stringByAdoptingFileSystemRepresentation(gchar* systemFilename, String& result) +{ + if (!systemFilename) + return false; + + result = filenameToString(systemFilename); + g_free(systemFilename); + + return true; +} + +String FileChooser::basenameForWidth(const Font& font, int width) const +{ + if (width <= 0) + return String(); + + String string = fileButtonNoFileSelectedLabel(); + + if (m_filenames.size() == 1) { + gchar* systemFilename = filenameFromString(m_filenames[0]); + gchar* systemBasename = g_path_get_basename(systemFilename); + g_free(systemFilename); + stringByAdoptingFileSystemRepresentation(systemBasename, string); + } else if (m_filenames.size() > 1) + return StringTruncator::rightTruncate(multipleFileUploadText(m_filenames.size()), width, font, false); + + return StringTruncator::centerTruncate(string, width, font, false); +} +} diff --git a/WebCore/platform/gtk/FileSystemGtk.cpp b/WebCore/platform/gtk/FileSystemGtk.cpp new file mode 100644 index 0000000..965cea9 --- /dev/null +++ b/WebCore/platform/gtk/FileSystemGtk.cpp @@ -0,0 +1,267 @@ +/* + * Copyright (C) 2007 Holger Hans Peter Freyther + * Copyright (C) 2008 Collabora, Ltd. + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "FileSystem.h" + +#include "guriescape.h" +#include "NotImplemented.h" +#include "PlatformString.h" +#include "CString.h" + +#include <glib.h> +#include <glib/gstdio.h> +#include <glib/gutils.h> + +#include <unistd.h> + +namespace WebCore { + +/* On linux file names are just raw bytes, so also strings that cannot be encoded in any way + * are valid file names. This mean that we cannot just store a file name as-is in a String + * but we have to escape it. + * On Windows the GLib file name encoding is always UTF-8 so we can optimize this case. */ +String filenameToString(const char* filename) +{ + if (!filename) + return String(); + +#if PLATFORM(WIN_OS) + return String::fromUTF8(filename); +#else + gchar* escapedString = g_uri_escape_string(filename, "/:", false); + String string(escapedString); + g_free(escapedString); + return string; +#endif +} + +char* filenameFromString(const String& string) +{ +#if PLATFORM(WIN_OS) + return g_strdup(string.utf8().data()); +#else + return g_uri_unescape_string(string.utf8().data(), 0); +#endif +} + +// Converts a string to something suitable to be displayed to the user. +String filenameForDisplay(const String& string) +{ +#if PLATFORM(WIN_OS) + return string; +#else + gchar* filename = filenameFromString(string); + gchar* display = g_filename_to_utf8(filename, 0, 0, 0, 0); + g_free(filename); + if (!display) + return string; + + String displayString = String::fromUTF8(display); + g_free(display); + + return displayString; +#endif +} + +bool fileExists(const String& path) +{ + bool result = false; + gchar* filename = filenameFromString(path); + + if (filename) { + result = g_file_test(filename, G_FILE_TEST_EXISTS); + g_free(filename); + } + + return result; +} + +bool deleteFile(const String& path) +{ + bool result = false; + gchar* filename = filenameFromString(path); + + if (filename) { + result = g_remove(filename) == 0; + g_free(filename); + } + + return result; +} + +bool deleteEmptyDirectory(const String& path) +{ + bool result = false; + gchar* filename = filenameFromString(path); + + if (filename) { + result = g_rmdir(filename) == 0; + g_free(filename); + } + + return result; +} + +bool getFileSize(const String& path, long long& resultSize) +{ + gchar* filename = filenameFromString(path); + if (!filename) + return false; + + struct stat statResult; + gint result = g_stat(filename, &statResult); + g_free(filename); + if (result != 0) + return false; + + resultSize = statResult.st_size; + return true; +} + +bool getFileModificationTime(const String& path, time_t& modifiedTime) +{ + gchar* filename = filenameFromString(path); + if (!filename) + return false; + + struct stat statResult; + gint result = g_stat(filename, &statResult); + g_free(filename); + if (result != 0) + return false; + + modifiedTime = statResult.st_mtime; + return true; + +} + +String pathByAppendingComponent(const String& path, const String& component) +{ + if (path.endsWith(G_DIR_SEPARATOR_S)) + return path + component; + else + return path + G_DIR_SEPARATOR_S + component; +} + +bool makeAllDirectories(const String& path) +{ + gchar* filename = filenameFromString(path); + if (!filename) + return false; + + gint result = g_mkdir_with_parents(filename, S_IRWXU); + g_free(filename); + + return result == 0; +} + +String homeDirectoryPath() +{ + return filenameToString(g_get_home_dir()); +} + +String pathGetFileName(const String& pathName) +{ + char* tmpFilename = filenameFromString(pathName); + char* baseName = g_path_get_basename(tmpFilename); + String fileName = String::fromUTF8(baseName); + g_free(baseName); + g_free(tmpFilename); + + return fileName; +} + +String directoryName(const String& path) +{ + notImplemented(); + return String(); +} + +Vector<String> listDirectory(const String& path, const String& filter) +{ + Vector<String> entries; + + gchar* filename = filenameFromString(path); + GDir* dir = g_dir_open(filename, 0, 0); + if (!dir) + return entries; + + GPatternSpec *pspec = g_pattern_spec_new((filter.utf8()).data()); + while (const char* name = g_dir_read_name(dir)) { + if (!g_pattern_match_string(pspec, name)) + continue; + + gchar* entry = g_build_filename(filename, name, NULL); + entries.append(filenameToString(entry)); + g_free(entry); + } + g_dir_close(dir); + g_free(filename); + + return entries; +} + +CString openTemporaryFile(const char* prefix, PlatformFileHandle& handle) +{ + gchar* filename = g_strdup_printf("%sXXXXXX", prefix); + gchar* tempPath = g_build_filename(g_get_tmp_dir(), filename, NULL); + g_free(filename); + + int fileDescriptor = g_mkstemp(tempPath); + if (!isHandleValid(fileDescriptor)) { + LOG_ERROR("Can't create a temporary file."); + g_free(tempPath); + return 0; + } + CString tempFilePath = tempPath; + g_free(tempPath); + + handle = fileDescriptor; + return tempFilePath; +} + +void closeFile(PlatformFileHandle& handle) +{ + if (isHandleValid(handle)) { + close(handle); + handle = invalidPlatformFileHandle; + } +} + +int writeToFile(PlatformFileHandle handle, const char* data, int length) +{ + int totalBytesWritten = 0; + while (totalBytesWritten < length) { + int bytesWritten = write(handle, data, length - totalBytesWritten); + if (bytesWritten < 0) + return -1; + totalBytesWritten += bytesWritten; + } + + return totalBytesWritten; +} + +bool unloadModule(PlatformModule module) +{ + return g_module_close(module); +} +} diff --git a/WebCore/platform/gtk/KURLGtk.cpp b/WebCore/platform/gtk/KURLGtk.cpp new file mode 100644 index 0000000..4858d3e --- /dev/null +++ b/WebCore/platform/gtk/KURLGtk.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2008 Collabora Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "KURL.h" + +#include "CString.h" +#include "FileSystem.h" + +#include <glib.h> + +namespace WebCore { + +String KURL::fileSystemPath() const +{ + gchar* filename = g_filename_from_uri(m_string.utf8().data(), 0, 0); + if (!filename) + return String(); + + String path = filenameToString(filename); + g_free(filename); + return path; +} + +} // namespace WebCore diff --git a/WebCore/platform/gtk/KeyEventGtk.cpp b/WebCore/platform/gtk/KeyEventGtk.cpp new file mode 100644 index 0000000..153ef19 --- /dev/null +++ b/WebCore/platform/gtk/KeyEventGtk.cpp @@ -0,0 +1,550 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com + * Copyright (C) 2007 Holger Hans Peter Freyther + * Copyright (C) 2008 Collabora, Ltd. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "PlatformKeyboardEvent.h" + +#include "KeyboardCodes.h" +#include "NotImplemented.h" +#include "TextEncoding.h" + +#include <gdk/gdk.h> +#include <gdk/gdkkeysyms.h> +#include <gtk/gtkversion.h> + +namespace WebCore { + +// FIXME: This is incomplete. We should change this to mirror +// more like what Firefox does, and generate these switch statements +// at build time. +static String keyIdentifierForGdkKeyCode(guint keyCode) +{ + switch (keyCode) { + case GDK_Menu: + case GDK_Alt_L: + case GDK_Alt_R: + return "Alt"; + case GDK_Clear: + return "Clear"; + case GDK_Down: + return "Down"; + // "End" + case GDK_End: + return "End"; + // "Enter" + case GDK_ISO_Enter: + case GDK_KP_Enter: + case GDK_Return: + return "Enter"; + case GDK_Execute: + return "Execute"; + case GDK_F1: + return "F1"; + case GDK_F2: + return "F2"; + case GDK_F3: + return "F3"; + case GDK_F4: + return "F4"; + case GDK_F5: + return "F5"; + case GDK_F6: + return "F6"; + case GDK_F7: + return "F7"; + case GDK_F8: + return "F8"; + case GDK_F9: + return "F9"; + case GDK_F10: + return "F10"; + case GDK_F11: + return "F11"; + case GDK_F12: + return "F12"; + case GDK_F13: + return "F13"; + case GDK_F14: + return "F14"; + case GDK_F15: + return "F15"; + case GDK_F16: + return "F16"; + case GDK_F17: + return "F17"; + case GDK_F18: + return "F18"; + case GDK_F19: + return "F19"; + case GDK_F20: + return "F20"; + case GDK_F21: + return "F21"; + case GDK_F22: + return "F22"; + case GDK_F23: + return "F23"; + case GDK_F24: + return "F24"; + case GDK_Help: + return "Help"; + case GDK_Home: + return "Home"; + case GDK_Insert: + return "Insert"; + case GDK_Left: + return "Left"; + case GDK_Page_Down: + return "PageDown"; + case GDK_Page_Up: + return "PageUp"; + case GDK_Pause: + return "Pause"; + case GDK_3270_PrintScreen: + return "PrintScreen"; + case GDK_Right: + return "Right"; + case GDK_Select: + return "Select"; + case GDK_Up: + return "Up"; + // Standard says that DEL becomes U+007F. + case GDK_Delete: + return "U+007F"; + case GDK_ISO_Left_Tab: + case GDK_3270_BackTab: + case GDK_Tab: + return "U+0009"; + default: + return String::format("U+%04X", gdk_keyval_to_unicode(gdk_keyval_to_upper(keyCode))); + } +} + +static int windowsKeyCodeForKeyEvent(unsigned int keycode) +{ + switch (keycode) { + case GDK_KP_0: + return VK_NUMPAD0;// (60) Numeric keypad 0 key + case GDK_KP_1: + return VK_NUMPAD1;// (61) Numeric keypad 1 key + case GDK_KP_2: + return VK_NUMPAD2; // (62) Numeric keypad 2 key + case GDK_KP_3: + return VK_NUMPAD3; // (63) Numeric keypad 3 key + case GDK_KP_4: + return VK_NUMPAD4; // (64) Numeric keypad 4 key + case GDK_KP_5: + return VK_NUMPAD5; //(65) Numeric keypad 5 key + case GDK_KP_6: + return VK_NUMPAD6; // (66) Numeric keypad 6 key + case GDK_KP_7: + return VK_NUMPAD7; // (67) Numeric keypad 7 key + case GDK_KP_8: + return VK_NUMPAD8; // (68) Numeric keypad 8 key + case GDK_KP_9: + return VK_NUMPAD9; // (69) Numeric keypad 9 key + case GDK_KP_Multiply: + return VK_MULTIPLY; // (6A) Multiply key + case GDK_KP_Add: + return VK_ADD; // (6B) Add key + case GDK_KP_Subtract: + return VK_SUBTRACT; // (6D) Subtract key + case GDK_KP_Decimal: + return VK_DECIMAL; // (6E) Decimal key + case GDK_KP_Divide: + return VK_DIVIDE; // (6F) Divide key + + case GDK_BackSpace: + return VK_BACK; // (08) BACKSPACE key + case GDK_ISO_Left_Tab: + case GDK_3270_BackTab: + case GDK_Tab: + return VK_TAB; // (09) TAB key + case GDK_Clear: + return VK_CLEAR; // (0C) CLEAR key + case GDK_ISO_Enter: + case GDK_KP_Enter: + case GDK_Return: + return VK_RETURN; //(0D) Return key + case GDK_Shift_L: + case GDK_Shift_R: + return VK_SHIFT; // (10) SHIFT key + case GDK_Control_L: + case GDK_Control_R: + return VK_CONTROL; // (11) CTRL key + case GDK_Menu: + case GDK_Alt_L: + case GDK_Alt_R: + return VK_MENU; // (12) ALT key + + case GDK_Pause: + return VK_PAUSE; // (13) PAUSE key + case GDK_Caps_Lock: + return VK_CAPITAL; // (14) CAPS LOCK key + case GDK_Kana_Lock: + case GDK_Kana_Shift: + return VK_KANA; // (15) Input Method Editor (IME) Kana mode + case GDK_Hangul: + return VK_HANGUL; // VK_HANGUL (15) IME Hangul mode + // VK_JUNJA (17) IME Junja mode + // VK_FINAL (18) IME final mode + case GDK_Hangul_Hanja: + return VK_HANJA; // (19) IME Hanja mode + case GDK_Kanji: + return VK_KANJI; // (19) IME Kanji mode + case GDK_Escape: + return VK_ESCAPE; // (1B) ESC key + // VK_CONVERT (1C) IME convert + // VK_NONCONVERT (1D) IME nonconvert + // VK_ACCEPT (1E) IME accept + // VK_MODECHANGE (1F) IME mode change request + case GDK_space: + return VK_SPACE; // (20) SPACEBAR + case GDK_Page_Up: + return VK_PRIOR; // (21) PAGE UP key + case GDK_Page_Down: + return VK_NEXT; // (22) PAGE DOWN key + case GDK_End: + return VK_END; // (23) END key + case GDK_Home: + return VK_HOME; // (24) HOME key + case GDK_Left: + return VK_LEFT; // (25) LEFT ARROW key + case GDK_Up: + return VK_UP; // (26) UP ARROW key + case GDK_Right: + return VK_RIGHT; // (27) RIGHT ARROW key + case GDK_Down: + return VK_DOWN; // (28) DOWN ARROW key + case GDK_Select: + return VK_SELECT; // (29) SELECT key + case GDK_Print: + return VK_PRINT; // (2A) PRINT key + case GDK_Execute: + return VK_EXECUTE;// (2B) EXECUTE key + //dunno on this + //case GDK_PrintScreen: + // return VK_SNAPSHOT; // (2C) PRINT SCREEN key + case GDK_Insert: + return VK_INSERT; // (2D) INS key + case GDK_Delete: + return VK_DELETE; // (2E) DEL key + case GDK_Help: + return VK_HELP; // (2F) HELP key + case GDK_0: + case GDK_parenleft: + return VK_0; // (30) 0) key + case GDK_1: + return VK_1; // (31) 1 ! key + case GDK_2: + case GDK_at: + return VK_2; // (32) 2 & key + case GDK_3: + case GDK_numbersign: + return VK_3; //case '3': case '#'; + case GDK_4: + case GDK_dollar: // (34) 4 key '$'; + return VK_4; + case GDK_5: + case GDK_percent: + return VK_5; // (35) 5 key '%' + case GDK_6: + case GDK_asciicircum: + return VK_6; // (36) 6 key '^' + case GDK_7: + case GDK_ampersand: + return VK_7; // (37) 7 key case '&' + case GDK_8: + case GDK_asterisk: + return VK_8; // (38) 8 key '*' + case GDK_9: + case GDK_parenright: + return VK_9; // (39) 9 key '(' + case GDK_a: + case GDK_A: + return VK_A; // (41) A key case 'a': case 'A': return 0x41; + case GDK_b: + case GDK_B: + return VK_B; // (42) B key case 'b': case 'B': return 0x42; + case GDK_c: + case GDK_C: + return VK_C; // (43) C key case 'c': case 'C': return 0x43; + case GDK_d: + case GDK_D: + return VK_D; // (44) D key case 'd': case 'D': return 0x44; + case GDK_e: + case GDK_E: + return VK_E; // (45) E key case 'e': case 'E': return 0x45; + case GDK_f: + case GDK_F: + return VK_F; // (46) F key case 'f': case 'F': return 0x46; + case GDK_g: + case GDK_G: + return VK_G; // (47) G key case 'g': case 'G': return 0x47; + case GDK_h: + case GDK_H: + return VK_H; // (48) H key case 'h': case 'H': return 0x48; + case GDK_i: + case GDK_I: + return VK_I; // (49) I key case 'i': case 'I': return 0x49; + case GDK_j: + case GDK_J: + return VK_J; // (4A) J key case 'j': case 'J': return 0x4A; + case GDK_k: + case GDK_K: + return VK_K; // (4B) K key case 'k': case 'K': return 0x4B; + case GDK_l: + case GDK_L: + return VK_L; // (4C) L key case 'l': case 'L': return 0x4C; + case GDK_m: + case GDK_M: + return VK_M; // (4D) M key case 'm': case 'M': return 0x4D; + case GDK_n: + case GDK_N: + return VK_N; // (4E) N key case 'n': case 'N': return 0x4E; + case GDK_o: + case GDK_O: + return VK_O; // (4F) O key case 'o': case 'O': return 0x4F; + case GDK_p: + case GDK_P: + return VK_P; // (50) P key case 'p': case 'P': return 0x50; + case GDK_q: + case GDK_Q: + return VK_Q; // (51) Q key case 'q': case 'Q': return 0x51; + case GDK_r: + case GDK_R: + return VK_R; // (52) R key case 'r': case 'R': return 0x52; + case GDK_s: + case GDK_S: + return VK_S; // (53) S key case 's': case 'S': return 0x53; + case GDK_t: + case GDK_T: + return VK_T; // (54) T key case 't': case 'T': return 0x54; + case GDK_u: + case GDK_U: + return VK_U; // (55) U key case 'u': case 'U': return 0x55; + case GDK_v: + case GDK_V: + return VK_V; // (56) V key case 'v': case 'V': return 0x56; + case GDK_w: + case GDK_W: + return VK_W; // (57) W key case 'w': case 'W': return 0x57; + case GDK_x: + case GDK_X: + return VK_X; // (58) X key case 'x': case 'X': return 0x58; + case GDK_y: + case GDK_Y: + return VK_Y; // (59) Y key case 'y': case 'Y': return 0x59; + case GDK_z: + case GDK_Z: + return VK_Z; // (5A) Z key case 'z': case 'Z': return 0x5A; + case GDK_Meta_L: + return VK_LWIN; // (5B) Left Windows key (Microsoft Natural keyboard) + case GDK_Meta_R: + return VK_RWIN; // (5C) Right Windows key (Natural keyboard) + // VK_APPS (5D) Applications key (Natural keyboard) + // VK_SLEEP (5F) Computer Sleep key + // VK_SEPARATOR (6C) Separator key + // VK_SUBTRACT (6D) Subtract key + // VK_DECIMAL (6E) Decimal key + // VK_DIVIDE (6F) Divide key + // handled by key code above + + case GDK_Num_Lock: + return VK_NUMLOCK; // (90) NUM LOCK key + + case GDK_Scroll_Lock: + return VK_SCROLL; // (91) SCROLL LOCK key + + // VK_LSHIFT (A0) Left SHIFT key + // VK_RSHIFT (A1) Right SHIFT key + // VK_LCONTROL (A2) Left CONTROL key + // VK_RCONTROL (A3) Right CONTROL key + // VK_LMENU (A4) Left MENU key + // VK_RMENU (A5) Right MENU key + // VK_BROWSER_BACK (A6) Windows 2000/XP: Browser Back key + // VK_BROWSER_FORWARD (A7) Windows 2000/XP: Browser Forward key + // VK_BROWSER_REFRESH (A8) Windows 2000/XP: Browser Refresh key + // VK_BROWSER_STOP (A9) Windows 2000/XP: Browser Stop key + // VK_BROWSER_SEARCH (AA) Windows 2000/XP: Browser Search key + // VK_BROWSER_FAVORITES (AB) Windows 2000/XP: Browser Favorites key + // VK_BROWSER_HOME (AC) Windows 2000/XP: Browser Start and Home key + // VK_VOLUME_MUTE (AD) Windows 2000/XP: Volume Mute key + // VK_VOLUME_DOWN (AE) Windows 2000/XP: Volume Down key + // VK_VOLUME_UP (AF) Windows 2000/XP: Volume Up key + // VK_MEDIA_NEXT_TRACK (B0) Windows 2000/XP: Next Track key + // VK_MEDIA_PREV_TRACK (B1) Windows 2000/XP: Previous Track key + // VK_MEDIA_STOP (B2) Windows 2000/XP: Stop Media key + // VK_MEDIA_PLAY_PAUSE (B3) Windows 2000/XP: Play/Pause Media key + // VK_LAUNCH_MAIL (B4) Windows 2000/XP: Start Mail key + // VK_LAUNCH_MEDIA_SELECT (B5) Windows 2000/XP: Select Media key + // VK_LAUNCH_APP1 (B6) Windows 2000/XP: Start Application 1 key + // VK_LAUNCH_APP2 (B7) Windows 2000/XP: Start Application 2 key + + // VK_OEM_1 (BA) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the ';:' key + case GDK_semicolon: + case GDK_colon: + return VK_OEM_1; //case ';': case ':': return 0xBA; + // VK_OEM_PLUS (BB) Windows 2000/XP: For any country/region, the '+' key + case GDK_plus: + case GDK_equal: + return VK_OEM_PLUS; //case '=': case '+': return 0xBB; + // VK_OEM_COMMA (BC) Windows 2000/XP: For any country/region, the ',' key + case GDK_comma: + case GDK_less: + return VK_OEM_COMMA; //case ',': case '<': return 0xBC; + // VK_OEM_MINUS (BD) Windows 2000/XP: For any country/region, the '-' key + case GDK_minus: + case GDK_underscore: + return VK_OEM_MINUS; //case '-': case '_': return 0xBD; + // VK_OEM_PERIOD (BE) Windows 2000/XP: For any country/region, the '.' key + case GDK_period: + case GDK_greater: + return VK_OEM_PERIOD; //case '.': case '>': return 0xBE; + // VK_OEM_2 (BF) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '/?' key + case GDK_slash: + case GDK_question: + return VK_OEM_2; //case '/': case '?': return 0xBF; + // VK_OEM_3 (C0) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '`~' key + case GDK_asciitilde: + case GDK_quoteleft: + return VK_OEM_3; //case '`': case '~': return 0xC0; + // VK_OEM_4 (DB) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '[{' key + case GDK_bracketleft: + case GDK_braceleft: + return VK_OEM_4; //case '[': case '{': return 0xDB; + // VK_OEM_5 (DC) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '\|' key + case GDK_backslash: + case GDK_bar: + return VK_OEM_5; //case '\\': case '|': return 0xDC; + // VK_OEM_6 (DD) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the ']}' key + case GDK_bracketright: + case GDK_braceright: + return VK_OEM_6; // case ']': case '}': return 0xDD; + // VK_OEM_7 (DE) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the 'single-quote/double-quote' key + case GDK_quoteright: + case GDK_quotedbl: + return VK_OEM_7; // case '\'': case '"': return 0xDE; + // VK_OEM_8 (DF) Used for miscellaneous characters; it can vary by keyboard. + // VK_OEM_102 (E2) Windows 2000/XP: Either the angle bracket key or the backslash key on the RT 102-key keyboard + // VK_PROCESSKEY (E5) Windows 95/98/Me, Windows NT 4.0, Windows 2000/XP: IME PROCESS key + // VK_PACKET (E7) Windows 2000/XP: Used to pass Unicode characters as if they were keystrokes. The VK_PACKET key is the low word of a 32-bit Virtual Key value used for non-keyboard input methods. For more information, see Remark in KEYBDINPUT,SendInput, WM_KEYDOWN, and WM_KEYUP + // VK_ATTN (F6) Attn key + // VK_CRSEL (F7) CrSel key + // VK_EXSEL (F8) ExSel key + // VK_EREOF (F9) Erase EOF key + // VK_PLAY (FA) Play key + // VK_ZOOM (FB) Zoom key + // VK_NONAME (FC) Reserved for future use + // VK_PA1 (FD) PA1 key + // VK_OEM_CLEAR (FE) Clear key + default: + return 0; + } + +} + +static String singleCharacterString(guint val) +{ + switch (val) { + case GDK_ISO_Enter: + case GDK_KP_Enter: + case GDK_Return: + return String("\r"); + default: + gunichar c = gdk_keyval_to_unicode(val); + glong nwc; + gunichar2* uchar16 = g_ucs4_to_utf16(&c, 1, 0, &nwc, 0); + + String retVal; + if (uchar16) + retVal = String((UChar*)uchar16, nwc); + else + retVal = String(); + + g_free(uchar16); + + return retVal; + } +} + +// Keep this in sync with the other platform event constructors +// TODO: m_gdkEventKey should be refcounted +PlatformKeyboardEvent::PlatformKeyboardEvent(GdkEventKey* event) + : m_type((event->type == GDK_KEY_RELEASE) ? KeyUp : KeyDown) + , m_text(singleCharacterString(event->keyval)) + , m_unmodifiedText(singleCharacterString(event->keyval)) + , m_keyIdentifier(keyIdentifierForGdkKeyCode(event->keyval)) + , m_autoRepeat(false) + , m_windowsVirtualKeyCode(windowsKeyCodeForKeyEvent(event->keyval)) + , m_nativeVirtualKeyCode(event->keyval) + , m_isKeypad(event->keyval >= GDK_KP_Space && event->keyval <= GDK_KP_9) + , m_shiftKey((event->state & GDK_SHIFT_MASK) || (event->keyval == GDK_3270_BackTab)) + , m_ctrlKey(event->state & GDK_CONTROL_MASK) + , m_altKey(event->state & GDK_MOD1_MASK) +#if GTK_CHECK_VERSION(2,10,0) + , m_metaKey(event->state & GDK_META_MASK) +#else + // GDK_MOD2_MASK doesn't always mean meta so we can't use it + , m_metaKey(false) +#endif + , m_gdkEventKey(event) +{ +} + +void PlatformKeyboardEvent::disambiguateKeyDownEvent(Type type, bool backwardCompatibilityMode) +{ + // Can only change type from KeyDown to RawKeyDown or Char, as we lack information for other conversions. + ASSERT(m_type == KeyDown); + m_type = type; + + if (backwardCompatibilityMode) + return; + + if (type == RawKeyDown) { + m_text = String(); + m_unmodifiedText = String(); + } else { + m_keyIdentifier = String(); + m_windowsVirtualKeyCode = 0; + } +} + +bool PlatformKeyboardEvent::currentCapsLockState() +{ + notImplemented(); + return false; +} + +GdkEventKey* PlatformKeyboardEvent::gdkEventKey() const +{ + return m_gdkEventKey; +} + +} diff --git a/WebCore/platform/gtk/KeyboardCodes.h b/WebCore/platform/gtk/KeyboardCodes.h new file mode 100644 index 0000000..3ad1243 --- /dev/null +++ b/WebCore/platform/gtk/KeyboardCodes.h @@ -0,0 +1,543 @@ +/* + * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef KeyboardCodes_h +#define KeyboardCodes_h + +namespace WebCore { + +// VK_LBUTTON (01) Left mouse button +// VK_RBUTTON (02) Right mouse button +// VK_CANCEL (03) Control-break processing +// VK_MBUTTON (04) Middle mouse button (three-button mouse) +// VK_XBUTTON1 (05) +// VK_XBUTTON2 (06) + +// VK_BACK (08) BACKSPACE key +const int VK_BACK = 0x08; + +// VK_TAB (09) TAB key +const int VK_TAB = 0x09; + +// VK_CLEAR (0C) CLEAR key +const int VK_CLEAR = 0x0C; + +// VK_RETURN (0D) +const int VK_RETURN = 0x0D; + +// VK_SHIFT (10) SHIFT key +const int VK_SHIFT = 0x10; + +// VK_CONTROL (11) CTRL key +const int VK_CONTROL = 0x11; + +// VK_MENU (12) ALT key +const int VK_MENU = 0x12; + +// VK_PAUSE (13) PAUSE key +const int VK_PAUSE = 0x13; + +// VK_CAPITAL (14) CAPS LOCK key +const int VK_CAPITAL = 0x14; + +// VK_KANA (15) Input Method Editor (IME) Kana mode +const int VK_KANA = 0x15; + +// VK_HANGUEL (15) IME Hanguel mode (maintained for compatibility; use VK_HANGUL) +// VK_HANGUL (15) IME Hangul mode +const int VK_HANGUL = 0x15; + +// VK_JUNJA (17) IME Junja mode +const int VK_JUNJA = 0x17; + +// VK_FINAL (18) IME final mode +const int VK_FINAL = 0x18; + +// VK_HANJA (19) IME Hanja mode +const int VK_HANJA = 0x19; + +// VK_KANJI (19) IME Kanji mode +const int VK_KANJI = 0x19; + +// VK_ESCAPE (1B) ESC key +const int VK_ESCAPE = 0x1B; + +// VK_CONVERT (1C) IME convert +const int VK_CONVERT = 0x1C; + +// VK_NONCONVERT (1D) IME nonconvert +const int VK_NONCONVERT = 0x1D; + +// VK_ACCEPT (1E) IME accept +const int VK_ACCEPT = 0x1E; + +// VK_MODECHANGE (1F) IME mode change request +const int VK_MODECHANGE = 0x1F; + +// VK_SPACE (20) SPACEBAR +const int VK_SPACE = 0x20; + +// VK_PRIOR (21) PAGE UP key +const int VK_PRIOR = 0x21; + +// VK_NEXT (22) PAGE DOWN key +const int VK_NEXT = 0x22; + +// VK_END (23) END key +const int VK_END = 0x23; + +// VK_HOME (24) HOME key +const int VK_HOME = 0x24; + +// VK_LEFT (25) LEFT ARROW key +const int VK_LEFT = 0x25; + +// VK_UP (26) UP ARROW key +const int VK_UP = 0x26; + +// VK_RIGHT (27) RIGHT ARROW key +const int VK_RIGHT = 0x27; + +// VK_DOWN (28) DOWN ARROW key +const int VK_DOWN = 0x28; + +// VK_SELECT (29) SELECT key +const int VK_SELECT = 0x29; + +// VK_PRINT (2A) PRINT key +const int VK_PRINT = 0x2A; + +// VK_EXECUTE (2B) EXECUTE key +const int VK_EXECUTE = 0x2B; + +// VK_SNAPSHOT (2C) PRINT SCREEN key +const int VK_SNAPSHOT = 0x2C; + +// VK_INSERT (2D) INS key +const int VK_INSERT = 0x2D; + +// VK_DELETE (2E) DEL key +const int VK_DELETE = 0x2E; + +// VK_HELP (2F) HELP key +const int VK_HELP = 0x2F; + +// (30) 0 key +const int VK_0 = 0x30; + +// (31) 1 key +const int VK_1 = 0x31; + +// (32) 2 key +const int VK_2 = 0x32; + +// (33) 3 key +const int VK_3 = 0x33; + +// (34) 4 key +const int VK_4 = 0x34; + +// (35) 5 key; + +const int VK_5 = 0x35; + +// (36) 6 key +const int VK_6 = 0x36; + +// (37) 7 key +const int VK_7 = 0x37; + +// (38) 8 key +const int VK_8 = 0x38; + +// (39) 9 key +const int VK_9 = 0x39; + +// (41) A key +const int VK_A = 0x41; + +// (42) B key +const int VK_B = 0x42; + +// (43) C key +const int VK_C = 0x43; + +// (44) D key +const int VK_D = 0x44; + +// (45) E key +const int VK_E = 0x45; + +// (46) F key +const int VK_F = 0x46; + +// (47) G key +const int VK_G = 0x47; + +// (48) H key +const int VK_H = 0x48; + +// (49) I key +const int VK_I = 0x49; + +// (4A) J key +const int VK_J = 0x4A; + +// (4B) K key +const int VK_K = 0x4B; + +// (4C) L key +const int VK_L = 0x4C; + +// (4D) M key +const int VK_M = 0x4D; + +// (4E) N key +const int VK_N = 0x4E; + +// (4F) O key +const int VK_O = 0x4F; + +// (50) P key +const int VK_P = 0x50; + +// (51) Q key +const int VK_Q = 0x51; + +// (52) R key +const int VK_R = 0x52; + +// (53) S key +const int VK_S = 0x53; + +// (54) T key +const int VK_T = 0x54; + +// (55) U key +const int VK_U = 0x55; + +// (56) V key +const int VK_V = 0x56; + +// (57) W key +const int VK_W = 0x57; + +// (58) X key +const int VK_X = 0x58; + +// (59) Y key +const int VK_Y = 0x59; + +// (5A) Z key +const int VK_Z = 0x5A; + +// VK_LWIN (5B) Left Windows key (Microsoft Natural keyboard) +const int VK_LWIN = 0x5B; + +// VK_RWIN (5C) Right Windows key (Natural keyboard) +const int VK_RWIN = 0x5C; + +// VK_APPS (5D) Applications key (Natural keyboard) +const int VK_APPS = 0x5D; + +// VK_SLEEP (5F) Computer Sleep key +const int VK_SLEEP = 0x5F; + +// VK_NUMPAD0 (60) Numeric keypad 0 key +const int VK_NUMPAD0 = 0x60; + +// VK_NUMPAD1 (61) Numeric keypad 1 key +const int VK_NUMPAD1 = 0x61; + +// VK_NUMPAD2 (62) Numeric keypad 2 key +const int VK_NUMPAD2 = 0x62; + +// VK_NUMPAD3 (63) Numeric keypad 3 key +const int VK_NUMPAD3 = 0x63; + +// VK_NUMPAD4 (64) Numeric keypad 4 key +const int VK_NUMPAD4 = 0x64; + +// VK_NUMPAD5 (65) Numeric keypad 5 key +const int VK_NUMPAD5 = 0x65; + +// VK_NUMPAD6 (66) Numeric keypad 6 key +const int VK_NUMPAD6 = 0x66; + +// VK_NUMPAD7 (67) Numeric keypad 7 key +const int VK_NUMPAD7 = 0x67; + +// VK_NUMPAD8 (68) Numeric keypad 8 key +const int VK_NUMPAD8 = 0x68; + +// VK_NUMPAD9 (69) Numeric keypad 9 key +const int VK_NUMPAD9 = 0x69; + +// VK_MULTIPLY (6A) Multiply key +const int VK_MULTIPLY = 0x6A; + +// VK_ADD (6B) Add key +const int VK_ADD = 0x6B; + +// VK_SEPARATOR (6C) Separator key +const int VK_SEPARATOR = 0x6C; + +// VK_SUBTRACT (6D) Subtract key +const int VK_SUBTRACT = 0x6D; + +// VK_DECIMAL (6E) Decimal key +const int VK_DECIMAL = 0x6E; + +// VK_DIVIDE (6F) Divide key +const int VK_DIVIDE = 0x6F; + +// VK_F1 (70) F1 key +const int VK_F1 = 0x70; + +// VK_F2 (71) F2 key +const int VK_F2 = 0x71; + +// VK_F3 (72) F3 key +const int VK_F3 = 0x72; + +// VK_F4 (73) F4 key +const int VK_F4 = 0x73; + +// VK_F5 (74) F5 key +const int VK_F5 = 0x74; + +// VK_F6 (75) F6 key +const int VK_F6 = 0x75; + +// VK_F7 (76) F7 key +const int VK_F7 = 0x76; + +// VK_F8 (77) F8 key +const int VK_F8 = 0x77; + +// VK_F9 (78) F9 key +const int VK_F9 = 0x78; + +// VK_F10 (79) F10 key +const int VK_F10 = 0x79; + +// VK_F11 (7A) F11 key +const int VK_F11 = 0x7A; + +// VK_F12 (7B) F12 key +const int VK_F12 = 0x7B; + +// VK_F13 (7C) F13 key +const int VK_F13 = 0x7C; + +// VK_F14 (7D) F14 key +const int VK_F14 = 0x7D; + +// VK_F15 (7E) F15 key +const int VK_F15 = 0x7E; + +// VK_F16 (7F) F16 key +const int VK_F16 = 0x7F; + +// VK_F17 (80H) F17 key +const int VK_F17 = 0x80; + +// VK_F18 (81H) F18 key +const int VK_F18 = 0x81; + +// VK_F19 (82H) F19 key +const int VK_F19 = 0x82; + +// VK_F20 (83H) F20 key +const int VK_F20 = 0x83; + +// VK_F21 (84H) F21 key +const int VK_F21 = 0x84; + +// VK_F22 (85H) F22 key +const int VK_F22 = 0x85; + +// VK_F23 (86H) F23 key +const int VK_F23 = 0x86; + +// VK_F24 (87H) F24 key +const int VK_F24 = 0x87; + +// VK_NUMLOCK (90) NUM LOCK key +const int VK_NUMLOCK = 0x90; + +// VK_SCROLL (91) SCROLL LOCK key +const int VK_SCROLL = 0x91; + +// VK_LSHIFT (A0) Left SHIFT key +const int VK_LSHIFT = 0xA0; + +// VK_RSHIFT (A1) Right SHIFT key +const int VK_RSHIFT = 0xA1; + +// VK_LCONTROL (A2) Left CONTROL key +const int VK_LCONTROL = 0xA2; + +// VK_RCONTROL (A3) Right CONTROL key +const int VK_RCONTROL = 0xA3; + +// VK_LMENU (A4) Left MENU key +const int VK_LMENU = 0xA4; + +// VK_RMENU (A5) Right MENU key +const int VK_RMENU = 0xA5; + +// VK_BROWSER_BACK (A6) Windows 2000/XP: Browser Back key +const int VK_BROWSER_BACK = 0xA6; + +// VK_BROWSER_FORWARD (A7) Windows 2000/XP: Browser Forward key +const int VK_BROWSER_FORWARD = 0xA7; + +// VK_BROWSER_REFRESH (A8) Windows 2000/XP: Browser Refresh key +const int VK_BROWSER_REFRESH = 0xA8; + +// VK_BROWSER_STOP (A9) Windows 2000/XP: Browser Stop key +const int VK_BROWSER_STOP = 0xA9; + +// VK_BROWSER_SEARCH (AA) Windows 2000/XP: Browser Search key +const int VK_BROWSER_SEARCH = 0xAA; + +// VK_BROWSER_FAVORITES (AB) Windows 2000/XP: Browser Favorites key +const int VK_BROWSER_FAVORITES = 0xAB; + +// VK_BROWSER_HOME (AC) Windows 2000/XP: Browser Start and Home key +const int VK_BROWSER_HOME = 0xAC; + +// VK_VOLUME_MUTE (AD) Windows 2000/XP: Volume Mute key +const int VK_VOLUME_MUTE = 0xAD; + +// VK_VOLUME_DOWN (AE) Windows 2000/XP: Volume Down key +const int VK_VOLUME_DOWN = 0xAE; + +// VK_VOLUME_UP (AF) Windows 2000/XP: Volume Up key +const int VK_VOLUME_UP = 0xAF; + +// VK_MEDIA_NEXT_TRACK (B0) Windows 2000/XP: Next Track key +const int VK_MEDIA_NEXT_TRACK = 0xB0; + +// VK_MEDIA_PREV_TRACK (B1) Windows 2000/XP: Previous Track key +const int VK_MEDIA_PREV_TRACK = 0xB1; + +// VK_MEDIA_STOP (B2) Windows 2000/XP: Stop Media key +const int VK_MEDIA_STOP = 0xB2; + +// VK_MEDIA_PLAY_PAUSE (B3) Windows 2000/XP: Play/Pause Media key +const int VK_MEDIA_PLAY_PAUSE = 0xB3; + +// VK_LAUNCH_MAIL (B4) Windows 2000/XP: Start Mail key +const int VK_MEDIA_LAUNCH_MAIL = 0xB4; + +// VK_LAUNCH_MEDIA_SELECT (B5) Windows 2000/XP: Select Media key +const int VK_MEDIA_LAUNCH_MEDIA_SELECT = 0xB5; + +// VK_LAUNCH_APP1 (B6) Windows 2000/XP: Start Application 1 key +const int VK_MEDIA_LAUNCH_APP1 = 0xB6; + +// VK_LAUNCH_APP2 (B7) Windows 2000/XP: Start Application 2 key +const int VK_MEDIA_LAUNCH_APP2 = 0xB7; + +// VK_OEM_1 (BA) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the ';:' key +const int VK_OEM_1 = 0xBA; + +// VK_OEM_PLUS (BB) Windows 2000/XP: For any country/region, the '+' key +const int VK_OEM_PLUS = 0xBB; + +// VK_OEM_COMMA (BC) Windows 2000/XP: For any country/region, the ',' key +const int VK_OEM_COMMA = 0xBC; + +// VK_OEM_MINUS (BD) Windows 2000/XP: For any country/region, the '-' key +const int VK_OEM_MINUS = 0xBD; + +// VK_OEM_PERIOD (BE) Windows 2000/XP: For any country/region, the '.' key +const int VK_OEM_PERIOD = 0xBE; + +// VK_OEM_2 (BF) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '/?' key +const int VK_OEM_2 = 0xBF; + +// VK_OEM_3 (C0) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '`~' key +const int VK_OEM_3 = 0xC0; + +// VK_OEM_4 (DB) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '[{' key +const int VK_OEM_4 = 0xDB; + +// VK_OEM_5 (DC) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '\|' key +const int VK_OEM_5 = 0xDC; + +// VK_OEM_6 (DD) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the ']}' key +const int VK_OEM_6 = 0xDD; + +// VK_OEM_7 (DE) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the 'single-quote/double-quote' key +const int VK_OEM_7 = 0xDE; + +// VK_OEM_8 (DF) Used for miscellaneous characters; it can vary by keyboard. +const int VK_OEM_8 = 0xDF; + +// VK_OEM_102 (E2) Windows 2000/XP: Either the angle bracket key or the backslash key on the RT 102-key keyboard +const int VK_OEM_102 = 0xE2; + +// VK_PROCESSKEY (E5) Windows 95/98/Me, Windows NT 4.0, Windows 2000/XP: IME PROCESS key +const int VK_PROCESSKEY = 0xE5; + +// VK_PACKET (E7) Windows 2000/XP: Used to pass Unicode characters as if they were keystrokes. The VK_PACKET key is the low word of a 32-bit Virtual Key value used for non-keyboard input methods. For more information, see Remark in KEYBDINPUT,SendInput, WM_KEYDOWN, and WM_KEYUP +const int VK_PACKET = 0xE7; + +// VK_ATTN (F6) Attn key +const int VK_ATTN = 0xF6; + +// VK_CRSEL (F7) CrSel key +const int VK_CRSEL = 0xF7; + +// VK_EXSEL (F8) ExSel key +const int VK_EXSEL = 0xF8; + +// VK_EREOF (F9) Erase EOF key +const int VK_EREOF = 0xF9; + +// VK_PLAY (FA) Play key +const int VK_PLAY = 0xFA; + +// VK_ZOOM (FB) Zoom key +const int VK_ZOOM = 0xFB; + +// VK_NONAME (FC) Reserved for future use +const int VK_NONAME = 0xFC; + +// VK_PA1 (FD) PA1 key +const int VK_PA1 = 0xFD; + +// VK_OEM_CLEAR (FE) Clear key +const int VK_OEM_CLEAR = 0xFE; + +const int VK_UNKNOWN = 0; + +} + +#endif diff --git a/WebCore/platform/gtk/Language.cpp b/WebCore/platform/gtk/Language.cpp new file mode 100644 index 0000000..6ae7305 --- /dev/null +++ b/WebCore/platform/gtk/Language.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "Language.h" + +#include "CString.h" +#include "PlatformString.h" + +#include <gtk/gtk.h> +#include <pango/pango.h> + +#if !defined(PANGO_VERSION_CHECK) +// PANGO_VERSION_CHECK() and pango_language_get_default() appeared in 1.5.2 +#include <locale.h> + +static gchar * +_pango_get_lc_ctype (void) +{ + return g_strdup (setlocale (LC_CTYPE, NULL)); +} + +static PangoLanguage * +pango_language_get_default (void) +{ + static PangoLanguage *result = NULL; + if (G_UNLIKELY (!result)) + { + gchar *lang = _pango_get_lc_ctype (); + result = pango_language_from_string (lang); + g_free (lang); + } + return result; +} +#endif + +namespace WebCore { + +String defaultLanguage() +{ + return pango_language_to_string(gtk_get_default_language()); +} + +} diff --git a/WebCore/platform/gtk/LocalizedStringsGtk.cpp b/WebCore/platform/gtk/LocalizedStringsGtk.cpp new file mode 100644 index 0000000..52d4f5f --- /dev/null +++ b/WebCore/platform/gtk/LocalizedStringsGtk.cpp @@ -0,0 +1,346 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com + * Copyright (C) 2007 Holger Hans Peter Freyther + * Copyright (C) 2008 Christian Dywan <christian@imendio.com> + * Copyright (C) 2008 Nuanti Ltd. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include "LocalizedStrings.h" +#include "NotImplemented.h" +#include "PlatformString.h" + +#include <gtk/gtk.h> +#include <glib/gi18n.h> + +namespace WebCore { + +static const char* gtkStockLabel(const char* stockID) +{ + GtkStockItem item; + if (!gtk_stock_lookup(stockID, &item)) + return stockID; + return item.label; +} + +String submitButtonDefaultLabel() +{ + return String::fromUTF8(_("Submit")); +} + +String inputElementAltText() +{ + return String::fromUTF8(_("Submit")); +} + +String resetButtonDefaultLabel() +{ + return String::fromUTF8(_("Reset")); +} + +String searchableIndexIntroduction() +{ + return String::fromUTF8(_("_Searchable Index")); +} + +String fileButtonChooseFileLabel() +{ + return String::fromUTF8(_("Choose File")); +} + +String fileButtonNoFileSelectedLabel() +{ + return String::fromUTF8(_("(None)")); +} + +String contextMenuItemTagOpenLinkInNewWindow() +{ + return String::fromUTF8(_("Open Link in New _Window")); +} + +String contextMenuItemTagDownloadLinkToDisk() +{ + return String::fromUTF8(_("_Download Linked File")); +} + +String contextMenuItemTagCopyLinkToClipboard() +{ + return String::fromUTF8(_("Copy Link Loc_ation")); +} + +String contextMenuItemTagOpenImageInNewWindow() +{ + return String::fromUTF8(_("Open _Image in New Window")); +} + +String contextMenuItemTagDownloadImageToDisk() +{ + return String::fromUTF8(_("Sa_ve Image As")); +} + +String contextMenuItemTagCopyImageToClipboard() +{ + return String::fromUTF8(_("Cop_y Image")); +} + +String contextMenuItemTagOpenFrameInNewWindow() +{ + return String::fromUTF8(_("Open _Frame in New Window")); +} + +String contextMenuItemTagCopy() +{ + static String stockLabel = String::fromUTF8(gtkStockLabel(GTK_STOCK_COPY)); + return stockLabel; +} + +String contextMenuItemTagDelete() +{ + static String stockLabel = String::fromUTF8(gtkStockLabel(GTK_STOCK_DELETE)); + return stockLabel; +} + +String contextMenuItemTagSelectAll() +{ +#if GTK_CHECK_VERSION(2,10,0) + static String stockLabel = String::fromUTF8(gtkStockLabel(GTK_STOCK_SELECT_ALL)); +#else + static String stockLabel = String::fromUTF8(_("Select _All")); +#endif + return stockLabel; +} + +String contextMenuItemTagUnicode() +{ + return String::fromUTF8(_("_Insert Unicode Control Character")); +} + +String contextMenuItemTagInputMethods() +{ + return String::fromUTF8(_("Input _Methods")); +} + +String contextMenuItemTagGoBack() +{ + static String stockLabel = String::fromUTF8(gtkStockLabel(GTK_STOCK_GO_BACK)); + return stockLabel; +} + +String contextMenuItemTagGoForward() +{ + static String stockLabel = String::fromUTF8(gtkStockLabel(GTK_STOCK_GO_FORWARD)); + return stockLabel; +} + +String contextMenuItemTagStop() +{ + static String stockLabel = String::fromUTF8(gtkStockLabel(GTK_STOCK_STOP)); + return stockLabel; +} + +String contextMenuItemTagReload() +{ + return String::fromUTF8(_("_Reload")); +} + +String contextMenuItemTagCut() +{ + static String stockLabel = String::fromUTF8(gtkStockLabel(GTK_STOCK_CUT)); + return stockLabel; +} + +String contextMenuItemTagPaste() +{ + static String stockLabel = String::fromUTF8(gtkStockLabel(GTK_STOCK_PASTE)); + return stockLabel; +} + +String contextMenuItemTagNoGuessesFound() +{ + return String::fromUTF8(_("No Guesses Found")); +} + +String contextMenuItemTagIgnoreSpelling() +{ + return String::fromUTF8(_("_Ignore Spelling")); +} + +String contextMenuItemTagLearnSpelling() +{ + return String::fromUTF8(_("_Learn Spelling")); +} + +String contextMenuItemTagSearchWeb() +{ + return String::fromUTF8(_("_Search the Web")); +} + +String contextMenuItemTagLookUpInDictionary() +{ + return String::fromUTF8(_("_Look Up in Dictionary")); +} + +String contextMenuItemTagOpenLink() +{ + return String::fromUTF8(_("_Open Link")); +} + +String contextMenuItemTagIgnoreGrammar() +{ + return String::fromUTF8(_("Ignore _Grammar")); +} + +String contextMenuItemTagSpellingMenu() +{ + return String::fromUTF8(_("Spelling and _Grammar")); +} + +String contextMenuItemTagShowSpellingPanel(bool show) +{ + return String::fromUTF8(show ? _("_Show Spelling and Grammar") : _("_Hide Spelling and Grammar")); +} + +String contextMenuItemTagCheckSpelling() +{ + return String::fromUTF8(_("_Check Document Now")); +} + +String contextMenuItemTagCheckSpellingWhileTyping() +{ + return String::fromUTF8(_("Check Spelling While _Typing")); +} + +String contextMenuItemTagCheckGrammarWithSpelling() +{ + return String::fromUTF8(_("Check _Grammar With Spelling")); +} + +String contextMenuItemTagFontMenu() +{ + return String::fromUTF8(_("_Font")); +} + +String contextMenuItemTagBold() +{ + static String stockLabel = String::fromUTF8(gtkStockLabel(GTK_STOCK_BOLD)); + return stockLabel; +} + +String contextMenuItemTagItalic() +{ + static String stockLabel = String::fromUTF8(gtkStockLabel(GTK_STOCK_ITALIC)); + return stockLabel; +} + +String contextMenuItemTagUnderline() +{ + static String stockLabel = String::fromUTF8(gtkStockLabel(GTK_STOCK_UNDERLINE)); + return stockLabel; +} + +String contextMenuItemTagOutline() +{ + return String::fromUTF8(_("_Outline")); +} + +String contextMenuItemTagInspectElement() +{ + return String::fromUTF8(_("Inspect _Element")); +} + +String searchMenuNoRecentSearchesText() +{ + return String::fromUTF8(_("No recent searches")); +} + +String searchMenuRecentSearchesText() +{ + return String::fromUTF8(_("Recent searches")); +} + +String searchMenuClearRecentSearchesText() +{ + return String::fromUTF8(_("_Clear recent searches")); +} + +String AXDefinitionListTermText() +{ + return String::fromUTF8(_("term")); +} + +String AXDefinitionListDefinitionText() +{ + return String::fromUTF8(_("definition")); +} + +String AXButtonActionVerb() +{ + return String::fromUTF8(_("press")); +} + +String AXRadioButtonActionVerb() +{ + return String::fromUTF8(_("select")); +} + +String AXTextFieldActionVerb() +{ + return String::fromUTF8(_("activate")); +} + +String AXCheckedCheckBoxActionVerb() +{ + return String::fromUTF8(_("uncheck")); +} + +String AXUncheckedCheckBoxActionVerb() +{ + return String::fromUTF8(_("check")); +} + +String AXLinkActionVerb() +{ + return String::fromUTF8(_("jump")); +} + +String multipleFileUploadText(unsigned numberOfFiles) +{ + // FIXME: If this file gets localized, this should really be localized as one string with a wildcard for the number. + return String::number(numberOfFiles) + String::fromUTF8(_(" files")); +} + +String unknownFileSizeText() +{ + return String::fromUTF8(_("Unknown")); +} + +String imageTitle(const String& filename, const IntSize& size) +{ + notImplemented(); + return String(); +} + +} diff --git a/WebCore/platform/gtk/LoggingGtk.cpp b/WebCore/platform/gtk/LoggingGtk.cpp new file mode 100644 index 0000000..5bc1559 --- /dev/null +++ b/WebCore/platform/gtk/LoggingGtk.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "Logging.h" + +namespace WebCore { + +void InitializeLoggingChannelsIfNecessary() +{ + // FIXME: Add a way for the user to specify which + // logs he/she would like turned on. + LogNotYetImplemented.state = WTFLogChannelOn; +} + +} // namespace WebCore diff --git a/WebCore/platform/gtk/MIMETypeRegistryGtk.cpp b/WebCore/platform/gtk/MIMETypeRegistryGtk.cpp new file mode 100644 index 0000000..20fe0cb --- /dev/null +++ b/WebCore/platform/gtk/MIMETypeRegistryGtk.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2006 Zack Rusin <zack@kde.org> + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "MIMETypeRegistry.h" + +namespace WebCore { + +struct ExtensionMap { + const char* extension; + const char* mimeType; +}; + +static const ExtensionMap extensionMap [] = { + { "bmp", "image/bmp" }, + { "css", "text/css" }, + { "gif", "image/gif" }, + { "html", "text/html" }, + { "ico", "image/x-icon" }, + { "jpeg", "image/jpeg" }, + { "jpg", "image/jpeg" }, + { "js", "application/x-javascript" }, + { "pdf", "application/pdf" }, + { "png", "image/png" }, + { "rss", "application/rss+xml" }, + { "svg", "image/svg+xml" }, + { "text", "text/plain" }, + { "txt", "text/plain" }, + { "xbm", "image/x-xbitmap" }, + { "xml", "text/xml" }, + { "xsl", "text/xsl" }, + { "xhtml", "application/xhtml+xml" }, + { 0, 0 } +}; + +String MIMETypeRegistry::getMIMETypeForExtension(const String &ext) +{ + String s = ext.lower(); + const ExtensionMap *e = extensionMap; + while (e->extension) { + if (s == e->extension) + return e->mimeType; + ++e; + } + + return String(); +} + +} diff --git a/WebCore/platform/gtk/MouseEventGtk.cpp b/WebCore/platform/gtk/MouseEventGtk.cpp new file mode 100644 index 0000000..f441f00 --- /dev/null +++ b/WebCore/platform/gtk/MouseEventGtk.cpp @@ -0,0 +1,112 @@ +/* +* Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY +* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR +* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "config.h" +#include "PlatformMouseEvent.h" + +#include "SystemTime.h" +#include "Assertions.h" + +#include <gdk/gdk.h> +#include <gtk/gtkversion.h> + +namespace WebCore { + +// FIXME: Would be even better to figure out which modifier is Alt instead of always using GDK_MOD1_MASK. + +// Keep this in sync with the other platform event constructors +PlatformMouseEvent::PlatformMouseEvent(GdkEventButton* event) +{ + m_timestamp = event->time; + m_position = IntPoint((int)event->x, (int)event->y); + m_globalPosition = IntPoint((int)event->x_root, (int)event->y_root); + m_shiftKey = event->state & GDK_SHIFT_MASK; + m_ctrlKey = event->state & GDK_CONTROL_MASK; + m_altKey = event->state & GDK_MOD1_MASK; +#if GTK_CHECK_VERSION(2,10,0) + m_metaKey = event->state & GDK_META_MASK; +#else + // GDK_MOD2_MASK doesn't always mean meta so we can't use it + m_metaKey = false; +#endif + + switch (event->type) { + case GDK_BUTTON_PRESS: + case GDK_2BUTTON_PRESS: + case GDK_3BUTTON_PRESS: + case GDK_BUTTON_RELEASE: + m_eventType = MouseEventPressed; + if (event->type == GDK_BUTTON_RELEASE) { + m_eventType = MouseEventReleased; + m_clickCount = 0; + } else if (event->type == GDK_BUTTON_PRESS) + m_clickCount = 1; + else if (event->type == GDK_2BUTTON_PRESS) + m_clickCount = 2; + else if (event->type == GDK_3BUTTON_PRESS) + m_clickCount = 3; + + if (event->button == 1) + m_button = LeftButton; + else if (event->button == 2) + m_button = MiddleButton; + else if (event->button == 3) + m_button = RightButton; + break; + + default: + ASSERT_NOT_REACHED(); + }; +} + +PlatformMouseEvent::PlatformMouseEvent(GdkEventMotion* motion) +{ + m_timestamp = motion->time; + m_position = IntPoint((int)motion->x, (int)motion->y); + m_globalPosition = IntPoint((int)motion->x_root, (int)motion->y_root); + m_shiftKey = motion->state & GDK_SHIFT_MASK; + m_ctrlKey = motion->state & GDK_CONTROL_MASK; + m_altKey = motion->state & GDK_MOD1_MASK; + m_metaKey = motion->state & GDK_MOD2_MASK; + + switch (motion->type) { + case GDK_MOTION_NOTIFY: + m_eventType = MouseEventMoved; + m_button = NoButton; + m_clickCount = 0; + break; + default: + ASSERT_NOT_REACHED(); + }; + + if (motion->state & GDK_BUTTON1_MASK) + m_button = LeftButton; + else if (motion->state & GDK_BUTTON2_MASK) + m_button = MiddleButton; + else if (motion->state & GDK_BUTTON3_MASK) + m_button = RightButton; +} +} diff --git a/WebCore/platform/gtk/PasteboardGtk.cpp b/WebCore/platform/gtk/PasteboardGtk.cpp new file mode 100644 index 0000000..15a7e64 --- /dev/null +++ b/WebCore/platform/gtk/PasteboardGtk.cpp @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2007 Holger Hans Peter Freyther + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "Pasteboard.h" + +#include "CString.h" +#include "DocumentFragment.h" +#include "Frame.h" +#include "NotImplemented.h" +#include "PlatformString.h" +#include "Image.h" +#include "RenderImage.h" +#include "KURL.h" +#include "markup.h" + +#include <gtk/gtk.h> + +namespace WebCore { + +/* FIXME: we must get rid of this and use the enum in webkitwebview.h someway */ +typedef enum +{ + WEBKIT_WEB_VIEW_TARGET_INFO_HTML = - 1, + WEBKIT_WEB_VIEW_TARGET_INFO_TEXT = - 2 +} WebKitWebViewTargetInfo; + +class PasteboardSelectionData { +public: + PasteboardSelectionData(gchar* text, gchar* markup) + : m_text(text) + , m_markup(markup) { } + + ~PasteboardSelectionData() { + g_free(m_text); + g_free(m_markup); + } + + const gchar* text() const { return m_text; } + const gchar* markup() const { return m_markup; } + +private: + gchar* m_text; + gchar* m_markup; +}; + +static void clipboard_get_contents_cb(GtkClipboard *clipboard, GtkSelectionData *selection_data, + guint info, gpointer data) { + PasteboardSelectionData* clipboardData = reinterpret_cast<PasteboardSelectionData*>(data); + ASSERT(clipboardData); + if ((gint)info == WEBKIT_WEB_VIEW_TARGET_INFO_HTML) { + gtk_selection_data_set(selection_data, selection_data->target, 8, + reinterpret_cast<const guchar*>(clipboardData->markup()), + g_utf8_strlen(clipboardData->markup(), -1)); + } else + gtk_selection_data_set_text(selection_data, clipboardData->text(), -1); +} + +static void clipboard_clear_contents_cb(GtkClipboard *clipboard, gpointer data) { + PasteboardSelectionData* clipboardData = reinterpret_cast<PasteboardSelectionData*>(data); + ASSERT(clipboardData); + delete clipboardData; +} + + +Pasteboard* Pasteboard::generalPasteboard() +{ + static Pasteboard* pasteboard = new Pasteboard(); + return pasteboard; +} + +Pasteboard::Pasteboard() +{ + notImplemented(); +} + +Pasteboard::~Pasteboard() +{ + delete m_helper; +} + +void Pasteboard::setHelper(PasteboardHelper* helper) +{ + m_helper = helper; +} + +void Pasteboard::writeSelection(Range* selectedRange, bool canSmartCopyOrDelete, Frame* frame) +{ + GtkClipboard* clipboard = m_helper->getClipboard(frame); +#if GTK_CHECK_VERSION(2,10,0) + gchar* text = g_strdup(frame->selectedText().utf8().data()); + gchar* markup = g_strdup(createMarkup(selectedRange, 0, AnnotateForInterchange).utf8().data()); + PasteboardSelectionData* data = new PasteboardSelectionData(text, markup); + + gint n_targets; + GtkTargetEntry* targets = gtk_target_table_new_from_list(m_helper->getCopyTargetList(frame), &n_targets); + gtk_clipboard_set_with_data(clipboard, targets, n_targets, + clipboard_get_contents_cb, clipboard_clear_contents_cb, data); + gtk_target_table_free(targets, n_targets); +#else + gtk_clipboard_set_text(clipboard, frame->selectedText().utf8().data(), frame->selectedText().utf8().length()); +#endif +} + +void Pasteboard::writeURL(const KURL& url, const String&, Frame* frame) +{ + if (url.isEmpty()) + return; + + GtkClipboard* clipboard = m_helper->getClipboard(frame); + gtk_clipboard_set_text(clipboard, url.string().utf8().data(), url.string().utf8().length()); +} + +void Pasteboard::writeImage(Node* node, const KURL&, const String&) +{ + // TODO: Enable this when Image gets GdkPixbuf support + + /* + GtkClipboard* clipboard = gtk_clipboard_get_for_display(gdk_display_get_default(), GDK_SELECTION_CLIPBOARD); + + ASSERT(node && node->renderer() && node->renderer()->isImage()); + RenderImage* renderer = static_cast<RenderImage*>(node->renderer()); + CachedImage* cachedImage = static_cast<CachedImage*>(renderer->cachedImage()); + ASSERT(cachedImage); + Image* image = cachedImage->image(); + ASSERT(image); + + gtk_clipboard_set_image(clipboard, image->pixbuf()); + */ + + notImplemented(); +} + +void Pasteboard::clear() +{ + GtkClipboard* clipboard = gtk_clipboard_get_for_display(gdk_display_get_default(), GDK_SELECTION_CLIPBOARD); + + gtk_clipboard_clear(clipboard); +} + +bool Pasteboard::canSmartReplace() +{ + notImplemented(); + return false; +} + +PassRefPtr<DocumentFragment> Pasteboard::documentFragment(Frame* frame, PassRefPtr<Range> context, + bool allowPlainText, bool& chosePlainText) +{ +#if GTK_CHECK_VERSION(2,10,0) + GdkAtom textHtml = gdk_atom_intern_static_string("text/html"); +#else + GdkAtom textHtml = gdk_atom_intern("text/html", false); +#endif + GtkClipboard* clipboard = m_helper->getClipboard(frame); + chosePlainText = false; + + if (GtkSelectionData* data = gtk_clipboard_wait_for_contents(clipboard, textHtml)) { + ASSERT(data->data); + String html = String::fromUTF8(reinterpret_cast<gchar*>(data->data), data->length * data->format / 8); + gtk_selection_data_free(data); + + if (!html.isEmpty()) { + RefPtr<DocumentFragment> fragment = createFragmentFromMarkup(frame->document(), html, ""); + if (fragment) + return fragment.release(); + } + } + + if (!allowPlainText) + return 0; + + if (gchar* utf8 = gtk_clipboard_wait_for_text(clipboard)) { + String text = String::fromUTF8(utf8); + g_free(utf8); + + chosePlainText = true; + RefPtr<DocumentFragment> fragment = createFragmentFromText(context.get(), text); + if (fragment) + return fragment.release(); + } + + return 0; +} + +String Pasteboard::plainText(Frame* frame) +{ + GtkClipboard* clipboard = m_helper->getClipboard(frame); + + gchar* utf8 = gtk_clipboard_wait_for_text(clipboard); + + if (!utf8) + return String(); + + String text = String::fromUTF8(utf8); + g_free(utf8); + + return text; +} + +} diff --git a/WebCore/platform/gtk/PasteboardHelper.h b/WebCore/platform/gtk/PasteboardHelper.h new file mode 100644 index 0000000..6bdc05e --- /dev/null +++ b/WebCore/platform/gtk/PasteboardHelper.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2007 Luca Bruno <lethalman88@gmail.com> + * All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef PasteboardHelper_h +#define PasteboardHelper_h + +/* + * FIXME: this is for WebCore support and must be removed once + * a better solution is found + */ + +#include "Frame.h" + +#include <gtk/gtk.h> + +namespace WebCore { + +class PasteboardHelper { +public: + virtual ~PasteboardHelper() {}; + + virtual GtkClipboard* getClipboard(Frame*) const = 0; + virtual GtkTargetList* getCopyTargetList(Frame*) const = 0; + virtual GtkTargetList* getPasteTargetList(Frame*) const = 0; +}; + +} + +#endif // PasteboardHelper_h diff --git a/WebCore/platform/gtk/PlatformScreenGtk.cpp b/WebCore/platform/gtk/PlatformScreenGtk.cpp new file mode 100644 index 0000000..9788253 --- /dev/null +++ b/WebCore/platform/gtk/PlatformScreenGtk.cpp @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com + * Copyright (C) 2008 Christian Dywan <christian@imendio.com> + * Copyright (C) 2008 Collabora Ltd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "PlatformScreen.h" + +#include "HostWindow.h" +#include "NotImplemented.h" +#include "ScrollView.h" +#include "Widget.h" + +#include <gtk/gtk.h> + +#if PLATFORM(X11) +#include <gdk/gdkx.h> +#include <X11/Xatom.h> +#endif + +namespace WebCore { + +int screenDepth(Widget* widget) +{ + GtkWidget* container = GTK_WIDGET(widget->root()->hostWindow()->platformWindow()); + if (!container) + return 24; + + GdkVisual* visual = gdk_drawable_get_visual(GDK_DRAWABLE(GTK_WIDGET(widget->root()->hostWindow()->platformWindow())->window)); + return visual->depth; +} + +int screenDepthPerComponent(Widget* widget) +{ + GtkWidget* container = GTK_WIDGET(widget->root()->hostWindow()->platformWindow()); + if (!container) + return 8; + + GdkVisual* visual = gdk_drawable_get_visual(GDK_DRAWABLE(GTK_WIDGET(widget->root()->hostWindow()->platformWindow())->window)); + return visual->bits_per_rgb; +} + +bool screenIsMonochrome(Widget* widget) +{ + GtkWidget* container = GTK_WIDGET(widget->root()->hostWindow()->platformWindow()); + if (!container) + return false; + + return screenDepth(widget) < 2; +} + +FloatRect screenRect(Widget* widget) +{ + GtkWidget* container = GTK_WIDGET(widget->root()->hostWindow()->platformWindow()); + if (!container) + return FloatRect(); + + GdkScreen* screen = gtk_widget_has_screen(container) ? gtk_widget_get_screen(container) : gdk_screen_get_default(); + if (!screen) + return FloatRect(); + + gint monitor = gdk_screen_get_monitor_at_window(screen, GTK_WIDGET(container)->window); + GdkRectangle geometry; + gdk_screen_get_monitor_geometry(screen, monitor, &geometry); + + return FloatRect(geometry.x, geometry.y, geometry.width, geometry.height); +} + +FloatRect screenAvailableRect(Widget* widget) +{ +#if PLATFORM(X11) + GtkWidget* container = GTK_WIDGET(widget->root()->hostWindow()->platformWindow()); + if (!container) + return FloatRect(); + + if (!GTK_WIDGET_REALIZED(container)) + return screenRect(widget); + + GdkDrawable* rootWindow = GDK_DRAWABLE(gtk_widget_get_root_window(container)); + GdkDisplay* display = gdk_drawable_get_display(rootWindow); + Atom xproperty = gdk_x11_get_xatom_by_name_for_display(display, "_NET_WORKAREA"); + + Atom retType; + int retFormat; + long *workAreaPos = NULL; + unsigned long retNItems; + unsigned long retAfter; + int xRes = XGetWindowProperty(GDK_DISPLAY_XDISPLAY(display), GDK_WINDOW_XWINDOW(rootWindow), xproperty, + 0, 4, FALSE, XA_CARDINAL, &retType, &retFormat, &retNItems, &retAfter, (guchar**)&workAreaPos); + + FloatRect rect; + if (xRes == Success && workAreaPos != NULL && retType == XA_CARDINAL && retNItems == 4 && retFormat == 32) { + rect = FloatRect(workAreaPos[0], workAreaPos[1], workAreaPos[2], workAreaPos[3]); + // rect contains the available space in the whole screen not just in the monitor + // containing the widget, so we intersect it with the monitor rectangle. + rect.intersect(screenRect(widget)); + } else + rect = screenRect(widget); + + if (workAreaPos) + XFree(workAreaPos); + + return rect; +#else + return screenRect(widget); +#endif +} + +} // namespace WebCore diff --git a/WebCore/platform/gtk/PopupMenuGtk.cpp b/WebCore/platform/gtk/PopupMenuGtk.cpp new file mode 100644 index 0000000..85c5aa0 --- /dev/null +++ b/WebCore/platform/gtk/PopupMenuGtk.cpp @@ -0,0 +1,160 @@ +/* + * This file is part of the popup menu implementation for <select> elements in WebCore. + * + * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com + * Copyright (C) 2008 Collabora Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "PopupMenu.h" + +#include "CString.h" +#include "FrameView.h" +#include "HostWindow.h" +#include "NotImplemented.h" +#include "PlatformString.h" +#include <gtk/gtk.h> + +namespace WebCore { + +PopupMenu::PopupMenu(PopupMenuClient* client) + : m_popupClient(client) + , m_popup(0) +{ +} + +PopupMenu::~PopupMenu() +{ + if (m_popup) + g_object_unref(m_popup); +} + +void PopupMenu::show(const IntRect& rect, FrameView* view, int index) +{ + ASSERT(client()); + + if (!m_popup) { + m_popup = GTK_MENU(gtk_menu_new()); +#if GLIB_CHECK_VERSION(2,10,0) + g_object_ref_sink(G_OBJECT(m_popup)); +#else + g_object_ref(G_OBJECT(m_popup)); + gtk_object_sink(GTK_OBJECT(m_popup)); +#endif + g_signal_connect(m_popup, "unmap", G_CALLBACK(menuUnmapped), this); + } else + gtk_container_foreach(GTK_CONTAINER(m_popup), reinterpret_cast<GtkCallback>(menuRemoveItem), this); + + int x, y; + gdk_window_get_origin(GTK_WIDGET(view->hostWindow()->platformWindow())->window, &x, &y); + m_menuPosition = view->contentsToWindow(rect.location()); + m_menuPosition = IntPoint(m_menuPosition.x() + x, m_menuPosition.y() + y + rect.height()); + m_indexMap.clear(); + + const int size = client()->listSize(); + for (int i = 0; i < size; ++i) { + GtkWidget* item; + if (client()->itemIsSeparator(i)) + item = gtk_separator_menu_item_new(); + else + item = gtk_menu_item_new_with_label(client()->itemText(i).utf8().data()); + + m_indexMap.add(item, i); + g_signal_connect(item, "activate", G_CALLBACK(menuItemActivated), this); + + // FIXME: Apply the PopupMenuStyle from client()->itemStyle(i) + gtk_widget_set_sensitive(item, client()->itemIsEnabled(i)); + gtk_menu_shell_append(GTK_MENU_SHELL(m_popup), item); + gtk_widget_show(item); + } + + gtk_menu_set_active(m_popup, index); + + + // The size calls are directly copied from gtkcombobox.c which is LGPL + GtkRequisition requisition; + gtk_widget_set_size_request(GTK_WIDGET(m_popup), -1, -1); + gtk_widget_size_request(GTK_WIDGET(m_popup), &requisition); + gtk_widget_set_size_request(GTK_WIDGET(m_popup), MAX(rect.width(), requisition.width), -1); + + GList* children = GTK_MENU_SHELL(m_popup)->children; + if (size) + for (int i = 0; i < size; i++) { + if (i > index) + break; + + GtkWidget* item = reinterpret_cast<GtkWidget*>(children->data); + GtkRequisition itemRequisition; + gtk_widget_get_child_requisition(item, &itemRequisition); + m_menuPosition.setY(m_menuPosition.y() - itemRequisition.height); + + children = g_list_next(children); + } + else + // Center vertically the empty popup in the combo box area + m_menuPosition.setY(m_menuPosition.y() - rect.height() / 2); + + gtk_menu_popup(m_popup, NULL, NULL, reinterpret_cast<GtkMenuPositionFunc>(menuPositionFunction), this, 0, gtk_get_current_event_time()); +} + +void PopupMenu::hide() +{ + ASSERT(m_popup); + gtk_menu_popdown(m_popup); +} + +void PopupMenu::updateFromElement() +{ + client()->setTextFromItem(client()->selectedIndex()); +} + +bool PopupMenu::itemWritingDirectionIsNatural() +{ + return true; +} + +void PopupMenu::menuItemActivated(GtkMenuItem* item, PopupMenu* that) +{ + ASSERT(that->client()); + ASSERT(that->m_indexMap.contains(GTK_WIDGET(item))); + that->client()->valueChanged(that->m_indexMap.get(GTK_WIDGET(item))); +} + +void PopupMenu::menuUnmapped(GtkWidget*, PopupMenu* that) +{ + ASSERT(that->client()); + that->client()->hidePopup(); +} + +void PopupMenu::menuPositionFunction(GtkMenu*, gint* x, gint* y, gboolean* pushIn, PopupMenu* that) +{ + *x = that->m_menuPosition.x(); + *y = that->m_menuPosition.y(); + *pushIn = true; +} + +void PopupMenu::menuRemoveItem(GtkWidget* widget, PopupMenu* that) +{ + ASSERT(that->m_popup); + gtk_container_remove(GTK_CONTAINER(that->m_popup), widget); +} + +} + diff --git a/WebCore/platform/gtk/RenderThemeGtk.cpp b/WebCore/platform/gtk/RenderThemeGtk.cpp new file mode 100644 index 0000000..bf8b8d7 --- /dev/null +++ b/WebCore/platform/gtk/RenderThemeGtk.cpp @@ -0,0 +1,478 @@ +/* + * Copyright (C) 2007 Apple Inc. + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * Copyright (C) 2008 Collabora Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "RenderThemeGtk.h" + +#include "AffineTransform.h" +#include "GraphicsContext.h" +#include "NotImplemented.h" +#include "RenderObject.h" +#include "gtkdrawing.h" + +#include <gdk/gdk.h> + +namespace WebCore { + +RenderTheme* theme() +{ + static RenderThemeGtk gtkTheme; + return >kTheme; +} + +static bool mozGtkInitialized = false; + +RenderThemeGtk::RenderThemeGtk() + : m_gtkWindow(0) + , m_gtkContainer(0) + , m_gtkEntry(0) + , m_gtkTreeView(0) +{ + if (!mozGtkInitialized) { + mozGtkInitialized = true; + moz_gtk_init(); + } +} + +static bool supportsFocus(ControlPart appearance) +{ + switch (appearance) { + case PushButtonPart: + case ButtonPart: + case TextFieldPart: + case TextAreaPart: + case SearchFieldPart: + case MenulistPart: + case RadioPart: + case CheckboxPart: + return true; + default: + return false; + } +} + +bool RenderThemeGtk::supportsFocusRing(const RenderStyle* style) const +{ + return supportsFocus(style->appearance()); +} + +bool RenderThemeGtk::controlSupportsTints(const RenderObject* o) const +{ + return isEnabled(o); +} + +int RenderThemeGtk::baselinePosition(const RenderObject* o) const +{ + // FIXME: This strategy is possibly incorrect for the GTK+ port. + if (o->style()->appearance() == CheckboxPart || + o->style()->appearance() == RadioPart) + return o->marginTop() + o->height() - 2; + return RenderTheme::baselinePosition(o); +} + +static GtkTextDirection gtkTextDirection(TextDirection direction) +{ + switch (direction) { + case RTL: + return GTK_TEXT_DIR_RTL; + case LTR: + return GTK_TEXT_DIR_LTR; + default: + return GTK_TEXT_DIR_NONE; + } +} + +static void adjustMozStyle(RenderStyle* style, GtkThemeWidgetType type) +{ + gint left, top, right, bottom; + GtkTextDirection direction = gtkTextDirection(style->direction()); + gboolean inhtml = true; + + if (moz_gtk_get_widget_border(type, &left, &top, &right, &bottom, direction, inhtml) != MOZ_GTK_SUCCESS) + return; + + // FIXME: This approach is likely to be incorrect. See other ports and layout tests to see the problem. + const int xpadding = 1; + const int ypadding = 1; + + style->setPaddingLeft(Length(xpadding + left, Fixed)); + style->setPaddingTop(Length(ypadding + top, Fixed)); + style->setPaddingRight(Length(xpadding + right, Fixed)); + style->setPaddingBottom(Length(ypadding + bottom, Fixed)); +} + +static void setMozState(RenderTheme* theme, GtkWidgetState* state, RenderObject* o) +{ + state->active = theme->isPressed(o); + state->focused = theme->isFocused(o); + state->inHover = theme->isHovered(o); + // FIXME: Disabled does not always give the correct appearance for ReadOnly + state->disabled = !theme->isEnabled(o) || theme->isReadOnlyControl(o); + state->isDefault = false; + state->canDefault = false; + state->depressed = false; +} + +static bool paintMozWidget(RenderTheme* theme, GtkThemeWidgetType type, RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) +{ + // No GdkWindow to render to, so return true to fall back + if (!i.context->gdkDrawable()) + return true; + + // Painting is disabled so just claim to have succeeded + if (i.context->paintingDisabled()) + return false; + + GtkWidgetState mozState; + setMozState(theme, &mozState, o); + + int flags; + + // We might want to make setting flags the caller's job at some point rather than doing it here. + switch (type) { + case MOZ_GTK_BUTTON: + flags = GTK_RELIEF_NORMAL; + break; + case MOZ_GTK_CHECKBUTTON: + case MOZ_GTK_RADIOBUTTON: + flags = theme->isChecked(o); + break; + default: + flags = 0; + break; + } + + AffineTransform ctm = i.context->getCTM(); + + IntPoint pos = ctm.mapPoint(rect.location()); + GdkRectangle gdkRect = IntRect(pos.x(), pos.y(), rect.width(), rect.height()); + GtkTextDirection direction = gtkTextDirection(o->style()->direction()); + +#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,4,0) + // Find the clip rectangle + cairo_t *cr = i.context->platformContext(); + double clipX1, clipX2, clipY1, clipY2; + cairo_clip_extents(cr, &clipX1, &clipY1, &clipX2, &clipY2); + + GdkRectangle gdkClipRect; + gdkClipRect.width = clipX2 - clipX1; + gdkClipRect.height = clipY2 - clipY1; + IntPoint clipPos = ctm.mapPoint(IntPoint(clipX1, clipY1)); + gdkClipRect.x = clipPos.x(); + gdkClipRect.y = clipPos.y(); + + gdk_rectangle_intersect(&gdkRect, &gdkClipRect, &gdkClipRect); +#else + GdkRectangle gdkClipRect = gdkRect; +#endif + + return moz_gtk_widget_paint(type, i.context->gdkDrawable(), &gdkRect, &gdkClipRect, &mozState, flags, direction) != MOZ_GTK_SUCCESS; +} + +static void setButtonPadding(RenderStyle* style) +{ + // FIXME: This looks incorrect. + const int padding = 8; + style->setPaddingLeft(Length(padding, Fixed)); + style->setPaddingRight(Length(padding, Fixed)); + style->setPaddingTop(Length(padding / 2, Fixed)); + style->setPaddingBottom(Length(padding / 2, Fixed)); +} + +static void setToggleSize(RenderStyle* style, ControlPart appearance) +{ + // The width and height are both specified, so we shouldn't change them. + if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto()) + return; + + // FIXME: This is probably not correct use of indicator_size and indicator_spacing. + gint indicator_size, indicator_spacing; + + switch (appearance) { + case CheckboxPart: + if (moz_gtk_checkbox_get_metrics(&indicator_size, &indicator_spacing) != MOZ_GTK_SUCCESS) + return; + break; + case RadioPart: + if (moz_gtk_radio_get_metrics(&indicator_size, &indicator_spacing) != MOZ_GTK_SUCCESS) + return; + break; + default: + return; + } + + // Other ports hard-code this to 13, but GTK+ users tend to demand the native look. + // It could be made a configuration option values other than 13 actually break site compatibility. + int length = indicator_size + indicator_spacing; + if (style->width().isIntrinsicOrAuto()) + style->setWidth(Length(length, Fixed)); + + if (style->height().isAuto()) + style->setHeight(Length(length, Fixed)); +} + +void RenderThemeGtk::setCheckboxSize(RenderStyle* style) const +{ + setToggleSize(style, RadioPart); +} + +bool RenderThemeGtk::paintCheckbox(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) +{ + return paintMozWidget(this, MOZ_GTK_CHECKBUTTON, o, i, rect); +} + +void RenderThemeGtk::setRadioSize(RenderStyle* style) const +{ + setToggleSize(style, RadioPart); +} + +bool RenderThemeGtk::paintRadio(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) +{ + return paintMozWidget(this, MOZ_GTK_RADIOBUTTON, o, i, rect); +} + +void RenderThemeGtk::adjustButtonStyle(CSSStyleSelector* selector, RenderStyle* style, WebCore::Element* e) const +{ + // FIXME: Is this condition necessary? + if (style->appearance() == PushButtonPart) { + style->resetBorder(); + style->setHeight(Length(Auto)); + style->setWhiteSpace(PRE); + setButtonPadding(style); + } else { + // FIXME: This should not be hard-coded. + style->setMinHeight(Length(14, Fixed)); + style->resetBorderTop(); + style->resetBorderBottom(); + } +} + +bool RenderThemeGtk::paintButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) +{ + return paintMozWidget(this, MOZ_GTK_BUTTON, o, i, rect); +} + +void RenderThemeGtk::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, WebCore::Element* e) const +{ + style->resetBorder(); + style->resetPadding(); + style->setHeight(Length(Auto)); + style->setWhiteSpace(PRE); + adjustMozStyle(style, MOZ_GTK_DROPDOWN); +} + +bool RenderThemeGtk::paintMenuList(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) +{ + return paintMozWidget(this, MOZ_GTK_DROPDOWN, o, i, rect); +} + +void RenderThemeGtk::adjustTextFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +{ + style->resetBorder(); + style->resetPadding(); + style->setHeight(Length(Auto)); + style->setWhiteSpace(PRE); + adjustMozStyle(style, MOZ_GTK_ENTRY); +} + +bool RenderThemeGtk::paintTextField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) +{ + return paintMozWidget(this, MOZ_GTK_ENTRY, o, i, rect); +} + +void RenderThemeGtk::adjustTextAreaStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +{ + adjustTextFieldStyle(selector, style, e); +} + +bool RenderThemeGtk::paintTextArea(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) +{ + return paintTextField(o, i, r); +} + +void RenderThemeGtk::adjustSearchFieldResultsButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +{ + adjustSearchFieldCancelButtonStyle(selector, style, e); +} + +bool RenderThemeGtk::paintSearchFieldResultsButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) +{ + return paintMozWidget(this, MOZ_GTK_DROPDOWN_ARROW, o, i, rect); +} + +void RenderThemeGtk::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +{ + style->resetBorder(); + style->resetPadding(); + + // FIXME: This should not be hard-coded. + IntSize size = IntSize(14, 14); + style->setWidth(Length(size.width(), Fixed)); + style->setHeight(Length(size.height(), Fixed)); +} + +bool RenderThemeGtk::paintSearchFieldResultsDecoration(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) +{ + return paintMozWidget(this, MOZ_GTK_CHECKMENUITEM, o, i, rect); +} + +void RenderThemeGtk::adjustSearchFieldCancelButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +{ + style->resetBorder(); + style->resetPadding(); + + // FIXME: This should not be hard-coded. + IntSize size = IntSize(14, 14); + style->setWidth(Length(size.width(), Fixed)); + style->setHeight(Length(size.height(), Fixed)); +} + +bool RenderThemeGtk::paintSearchFieldCancelButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) +{ + return paintMozWidget(this, MOZ_GTK_CHECKMENUITEM, o, i, rect); +} + +void RenderThemeGtk::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +{ + adjustTextFieldStyle(selector, style, e); +} + +bool RenderThemeGtk::paintSearchField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& rect) +{ + return paintTextField(o, i, rect); +} + +Color RenderThemeGtk::platformActiveSelectionBackgroundColor() const +{ + GtkWidget* widget = gtkEntry(); + return widget->style->base[GTK_STATE_SELECTED]; +} + +Color RenderThemeGtk::platformInactiveSelectionBackgroundColor() const +{ + GtkWidget* widget = gtkEntry(); + return widget->style->base[GTK_STATE_ACTIVE]; +} + +Color RenderThemeGtk::platformActiveSelectionForegroundColor() const +{ + GtkWidget* widget = gtkEntry(); + return widget->style->text[GTK_STATE_SELECTED]; +} + +Color RenderThemeGtk::platformInactiveSelectionForegroundColor() const +{ + GtkWidget* widget = gtkEntry(); + return widget->style->text[GTK_STATE_ACTIVE]; +} + +Color RenderThemeGtk::activeListBoxSelectionBackgroundColor() const +{ + GtkWidget* widget = gtkTreeView(); + return widget->style->base[GTK_STATE_SELECTED]; +} + +Color RenderThemeGtk::inactiveListBoxSelectionBackgroundColor() const +{ + GtkWidget* widget = gtkTreeView(); + return widget->style->base[GTK_STATE_ACTIVE]; +} + +Color RenderThemeGtk::activeListBoxSelectionForegroundColor() const +{ + GtkWidget* widget = gtkTreeView(); + return widget->style->text[GTK_STATE_SELECTED]; +} + +Color RenderThemeGtk::inactiveListBoxSelectionForegroundColor() const +{ + GtkWidget* widget = gtkTreeView(); + return widget->style->text[GTK_STATE_ACTIVE]; +} + +double RenderThemeGtk::caretBlinkFrequency() const +{ + GtkSettings* settings = gtk_settings_get_default(); + + gboolean shouldBlink; + gint time; + + g_object_get(settings, "gtk-cursor-blink", &shouldBlink, "gtk-cursor-blink-time", &time, NULL); + + if (!shouldBlink) + return 0; + + return time / 2000.; +} + +void RenderThemeGtk::systemFont(int, FontDescription&) const +{ + // If you remove this notImplemented(), replace it with an comment that explains why. + notImplemented(); +} + +static void gtkStyleSetCallback(GtkWidget* widget, GtkStyle* previous, RenderTheme* renderTheme) +{ + // FIXME: Make sure this function doesn't get called many times for a single GTK+ style change signal. + renderTheme->platformColorsDidChange(); +} + +GtkContainer* RenderThemeGtk::gtkContainer() const +{ + if (m_gtkContainer) + return m_gtkContainer; + + m_gtkWindow = gtk_window_new(GTK_WINDOW_POPUP); + m_gtkContainer = GTK_CONTAINER(gtk_fixed_new()); + gtk_container_add(GTK_CONTAINER(m_gtkWindow), GTK_WIDGET(m_gtkContainer)); + gtk_widget_realize(m_gtkWindow); + + return m_gtkContainer; +} + +GtkWidget* RenderThemeGtk::gtkEntry() const +{ + if (m_gtkEntry) + return m_gtkEntry; + + m_gtkEntry = gtk_entry_new(); + g_signal_connect(m_gtkEntry, "style-set", G_CALLBACK(gtkStyleSetCallback), theme()); + gtk_container_add(gtkContainer(), m_gtkEntry); + gtk_widget_realize(m_gtkEntry); + + return m_gtkEntry; +} + +GtkWidget* RenderThemeGtk::gtkTreeView() const +{ + if (m_gtkTreeView) + return m_gtkTreeView; + + m_gtkTreeView = gtk_tree_view_new(); + g_signal_connect(m_gtkTreeView, "style-set", G_CALLBACK(gtkStyleSetCallback), theme()); + gtk_container_add(gtkContainer(), m_gtkTreeView); + gtk_widget_realize(m_gtkTreeView); + + return m_gtkTreeView; +} + +} diff --git a/WebCore/platform/gtk/RenderThemeGtk.h b/WebCore/platform/gtk/RenderThemeGtk.h new file mode 100644 index 0000000..dda8bc8 --- /dev/null +++ b/WebCore/platform/gtk/RenderThemeGtk.h @@ -0,0 +1,128 @@ +/* + * This file is part of the WebKit project. + * + * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com + * Copyright (C) 2007 Holger Hans Peter Freyther + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef RenderThemeGdk_h +#define RenderThemeGdk_h + +#include "RenderTheme.h" + +#include <gtk/gtk.h> + +namespace WebCore { + +class RenderThemeGtk : public RenderTheme { +public: + RenderThemeGtk(); + + // A method asking if the theme's controls actually care about redrawing when hovered. + virtual bool supportsHover(const RenderStyle* style) const { return true; } + + // A method asking if the theme is able to draw the focus ring. + virtual bool supportsFocusRing(const RenderStyle*) const; + + // A method asking if the control changes its tint when the window has focus or not. + virtual bool controlSupportsTints(const RenderObject*) const; + + // A general method asking if any control tinting is supported at all. + virtual bool supportsControlTints() const { return true; } + + // A method to obtain the baseline position for a "leaf" control. This will only be used if a baseline + // position cannot be determined by examining child content. Checkboxes and radio buttons are examples of + // controls that need to do this. + virtual int baselinePosition(const RenderObject*) const; + + // The platform selection color. + virtual Color platformActiveSelectionBackgroundColor() const; + virtual Color platformInactiveSelectionBackgroundColor() const; + virtual Color platformActiveSelectionForegroundColor() const; + virtual Color platformInactiveSelectionForegroundColor() const; + + // List Box selection color + virtual Color activeListBoxSelectionBackgroundColor() const; + virtual Color activeListBoxSelectionForegroundColor() const; + virtual Color inactiveListBoxSelectionBackgroundColor() const; + virtual Color inactiveListBoxSelectionForegroundColor() const; + + virtual double caretBlinkFrequency() const; + + // System fonts. + virtual void systemFont(int propId, FontDescription&) const; + +protected: + virtual bool paintCheckbox(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r); + virtual void setCheckboxSize(RenderStyle* style) const; + + virtual bool paintRadio(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r); + virtual void setRadioSize(RenderStyle* style) const; + + virtual void adjustButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual bool paintButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + + virtual void adjustTextFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual bool paintTextField(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + + virtual void adjustTextAreaStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual bool paintTextArea(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + + virtual void adjustMenuListStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual bool paintMenuList(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + + virtual void adjustSearchFieldResultsDecorationStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual bool paintSearchFieldResultsDecoration(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + + virtual void adjustSearchFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual bool paintSearchField(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + + virtual void adjustSearchFieldResultsButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual bool paintSearchFieldResultsButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + + virtual void adjustSearchFieldCancelButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual bool paintSearchFieldCancelButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + + +private: + /* + * hold the state + */ + GtkWidget* gtkEntry() const; + GtkWidget* gtkTreeView() const; + + /* + * unmapped GdkWindow having a container. This is holding all + * our fake widgets + */ + GtkContainer* gtkContainer() const; + +private: + mutable GtkWidget* m_gtkWindow; + mutable GtkContainer* m_gtkContainer; + mutable GtkWidget* m_gtkEntry; + mutable GtkWidget* m_gtkTreeView; +}; + +} + +#endif diff --git a/WebCore/platform/gtk/ScrollViewGtk.cpp b/WebCore/platform/gtk/ScrollViewGtk.cpp new file mode 100644 index 0000000..e1316ee --- /dev/null +++ b/WebCore/platform/gtk/ScrollViewGtk.cpp @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2006, 2007, 2008 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com + * Copyright (C) 2007 Holger Hans Peter Freyther + * Copyright (C) 2008 Collabora Ltd. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ScrollView.h" + +#include "FloatRect.h" +#include "GraphicsContext.h" +#include "HostWindow.h" +#include "IntRect.h" +#include "NotImplemented.h" +#include "PlatformMouseEvent.h" +#include "PlatformWheelEvent.h" +#include "ScrollbarGtk.h" +#include "ScrollbarTheme.h" + +#include <gtk/gtk.h> + +using namespace std; + +namespace WebCore { + +static void adjustmentChanged(GtkAdjustment* adjustment, gpointer _that) +{ + ScrollView* that = reinterpret_cast<ScrollView*>(_that); + + // Figure out if we really moved. + IntSize newOffset = that->scrollOffset(); + if (adjustment == that->m_horizontalAdjustment) + newOffset.setWidth(static_cast<int>(gtk_adjustment_get_value(adjustment))); + else if (adjustment == that->m_verticalAdjustment) + newOffset.setHeight(static_cast<int>(gtk_adjustment_get_value(adjustment))); + + IntSize scrollDelta = newOffset - that->scrollOffset(); + if (scrollDelta == IntSize()) + return; + that->setScrollOffset(newOffset); + + if (that->scrollbarsSuppressed()) + return; + + that->scrollContents(scrollDelta); +} + +void ScrollView::platformInit() +{ + m_horizontalAdjustment = 0; + m_verticalAdjustment = 0; +} + +void ScrollView::platformDestroy() +{ + if (m_horizontalAdjustment) { + g_signal_handlers_disconnect_by_func(G_OBJECT(m_horizontalAdjustment), (gpointer)adjustmentChanged, this); + g_object_unref(m_horizontalAdjustment); + } + + if (m_verticalAdjustment) { + g_signal_handlers_disconnect_by_func(G_OBJECT(m_verticalAdjustment), (gpointer)adjustmentChanged, this); + g_object_unref(m_verticalAdjustment); + } +} + +/* + * The following is assumed: + * (hadj && vadj) || (!hadj && !vadj) + */ +void ScrollView::setGtkAdjustments(GtkAdjustment* hadj, GtkAdjustment* vadj) +{ + ASSERT(!hadj == !vadj); + + if (m_horizontalAdjustment) { + g_signal_handlers_disconnect_by_func(G_OBJECT(m_horizontalAdjustment), (gpointer)adjustmentChanged, this); + g_signal_handlers_disconnect_by_func(G_OBJECT(m_verticalAdjustment), (gpointer)adjustmentChanged, this); + g_object_unref(m_horizontalAdjustment); + g_object_unref(m_verticalAdjustment); + } + + m_horizontalAdjustment = hadj; + m_verticalAdjustment = vadj; + + if (m_horizontalAdjustment) { + g_signal_connect(m_horizontalAdjustment, "value-changed", G_CALLBACK(adjustmentChanged), this); + g_signal_connect(m_verticalAdjustment, "value-changed", G_CALLBACK(adjustmentChanged), this); + + /* + * disable the scrollbars (if we have any) as the GtkAdjustment over + */ + setHasVerticalScrollbar(false); + setHasHorizontalScrollbar(false); + + g_object_ref(m_horizontalAdjustment); + g_object_ref(m_verticalAdjustment); + } + + updateScrollbars(m_scrollOffset); +} + +void ScrollView::platformAddChild(Widget* child) +{ + if (!GTK_IS_SOCKET(child->platformWidget())) + gtk_container_add(GTK_CONTAINER(hostWindow()->platformWindow()), child->platformWidget()); +} + +void ScrollView::platformRemoveChild(Widget* child) +{ + GtkWidget* parent; + + // HostWindow can be NULL here. If that's the case + // let's grab the child's parent instead. + if (hostWindow()) + parent = GTK_WIDGET(hostWindow()->platformWindow()); + else + parent = GTK_WIDGET(child->platformWidget()->parent); + + if (GTK_IS_CONTAINER(parent) && parent == child->platformWidget()->parent) + gtk_container_remove(GTK_CONTAINER(parent), child->platformWidget()); +} + +bool ScrollView::platformHandleHorizontalAdjustment(const IntSize& scroll) +{ + if (m_horizontalAdjustment) { + m_horizontalAdjustment->page_size = visibleWidth(); + m_horizontalAdjustment->step_increment = visibleWidth() / 10.0; + m_horizontalAdjustment->page_increment = visibleWidth() * 0.9; + m_horizontalAdjustment->lower = 0; + m_horizontalAdjustment->upper = contentsWidth(); + gtk_adjustment_changed(m_horizontalAdjustment); + + if (m_scrollOffset.width() != scroll.width()) { + m_horizontalAdjustment->value = scroll.width(); + gtk_adjustment_value_changed(m_horizontalAdjustment); + } + return true; + } + return false; +} + +bool ScrollView::platformHandleVerticalAdjustment(const IntSize& scroll) +{ + if (m_verticalAdjustment) { + m_verticalAdjustment->page_size = visibleHeight(); + m_verticalAdjustment->step_increment = visibleHeight() / 10.0; + m_verticalAdjustment->page_increment = visibleHeight() * 0.9; + m_verticalAdjustment->lower = 0; + m_verticalAdjustment->upper = contentsHeight(); + gtk_adjustment_changed(m_verticalAdjustment); + + if (m_scrollOffset.height() != scroll.height()) { + m_verticalAdjustment->value = scroll.height(); + gtk_adjustment_value_changed(m_verticalAdjustment); + } + return true; + } + return false; +} + +bool ScrollView::platformHasHorizontalAdjustment() const +{ + return m_horizontalAdjustment != 0; +} + +bool ScrollView::platformHasVerticalAdjustment() const +{ + return m_verticalAdjustment != 0; +} + +} diff --git a/WebCore/platform/gtk/ScrollbarGtk.cpp b/WebCore/platform/gtk/ScrollbarGtk.cpp new file mode 100644 index 0000000..099895d --- /dev/null +++ b/WebCore/platform/gtk/ScrollbarGtk.cpp @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2007 Holger Hans Peter Freyther zecke@selfish.org + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "ScrollbarGtk.h" + +#include "IntRect.h" +#include "GraphicsContext.h" +#include "FrameView.h" +#include "NotImplemented.h" +#include "ScrollbarTheme.h" +#include "gtkdrawing.h" + +#include <gtk/gtk.h> + +using namespace WebCore; + +PassRefPtr<Scrollbar> Scrollbar::createNativeScrollbar(ScrollbarClient* client, ScrollbarOrientation orientation, ScrollbarControlSize size) +{ + return adoptRef(new ScrollbarGtk(client, orientation, size)); +} + +static gboolean gtkScrollEventCallback(GtkWidget* widget, GdkEventScroll* event, ScrollbarGtk*) +{ + /* Scroll only if our parent rejects the scroll event. The rationale for + * this is that we want the main frame to scroll when we move the mouse + * wheel over a child scrollbar in most cases. */ + return gtk_widget_event(gtk_widget_get_parent(widget), reinterpret_cast<GdkEvent*>(event)); +} + +ScrollbarGtk::ScrollbarGtk(ScrollbarClient* client, ScrollbarOrientation orientation, + ScrollbarControlSize controlSize) + : Scrollbar(client, orientation, controlSize) + , m_adjustment(GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 0.0, 0.0, 0.0, 0.0))) +{ + GtkScrollbar* scrollBar = orientation == HorizontalScrollbar ? + GTK_SCROLLBAR(::gtk_hscrollbar_new(m_adjustment)) : + GTK_SCROLLBAR(::gtk_vscrollbar_new(m_adjustment)); + gtk_widget_show(GTK_WIDGET(scrollBar)); + g_object_ref(G_OBJECT(scrollBar)); + g_signal_connect(G_OBJECT(scrollBar), "value-changed", G_CALLBACK(ScrollbarGtk::gtkValueChanged), this); + g_signal_connect(G_OBJECT(scrollBar), "scroll-event", G_CALLBACK(gtkScrollEventCallback), this); + + setPlatformWidget(GTK_WIDGET(scrollBar)); + + /* + * assign a sane default width and height to the Scrollbar, otherwise + * we will end up with a 0 width scrollbar. + */ + resize(ScrollbarTheme::nativeTheme()->scrollbarThickness(), + ScrollbarTheme::nativeTheme()->scrollbarThickness()); +} + +ScrollbarGtk::~ScrollbarGtk() +{ + /* + * the Widget does not take over ownership. + */ + g_signal_handlers_disconnect_by_func(G_OBJECT(platformWidget()), (gpointer)ScrollbarGtk::gtkValueChanged, this); + g_signal_handlers_disconnect_by_func(G_OBJECT(platformWidget()), (gpointer)gtkScrollEventCallback, this); + g_object_unref(G_OBJECT(platformWidget())); +} + +void ScrollbarGtk::frameRectsChanged() const +{ + if (!parent() || !parent()->isScrollViewScrollbar(this)) + return; + + IntPoint loc = parent()->convertToContainingWindow(frameRect().location()); + + // Don't allow the allocation size to be negative + IntSize sz = frameRect().size(); + sz.clampNegativeToZero(); + + GtkAllocation allocation = { loc.x(), loc.y(), sz.width(), sz.height() }; + gtk_widget_size_allocate(platformWidget(), &allocation); +} + +void ScrollbarGtk::updateThumbPosition() +{ + if (m_adjustment->value != m_currentPos) { + m_adjustment->value = m_currentPos; + gtk_adjustment_value_changed(m_adjustment); + } +} + +void ScrollbarGtk::updateThumbProportion() +{ + m_adjustment->step_increment = m_lineStep; + m_adjustment->page_increment = m_pageStep; + m_adjustment->page_size = m_visibleSize; + m_adjustment->upper = m_totalSize; + gtk_adjustment_changed(m_adjustment); +} + +void ScrollbarGtk::setFrameRect(const IntRect& rect) +{ + Widget::setFrameRect(rect); + frameRectsChanged(); +} + +void ScrollbarGtk::frameRectsChanged() +{ + if (!parent()) + return; + + ASSERT(parent()->isFrameView()); + + FrameView* frameView = static_cast<FrameView*>(parent()); + IntRect windowRect = IntRect(frameView->contentsToWindow(frameRect().location()), frameRect().size()); + + IntSize sz = frameRect().size(); + sz.clampNegativeToZero(); + + GtkAllocation allocation = { windowRect.x(), windowRect.y(), sz.width(), sz.height() }; + gtk_widget_size_allocate(platformWidget(), &allocation); +} + +void ScrollbarGtk::gtkValueChanged(GtkAdjustment*, ScrollbarGtk* that) +{ + that->setValue(static_cast<int>(gtk_adjustment_get_value(that->m_adjustment))); +} + +void ScrollbarGtk::setEnabled(bool shouldEnable) +{ + if (enabled() == shouldEnable) + return; + + Scrollbar::setEnabled(shouldEnable); + if (platformWidget()) + gtk_widget_set_sensitive(platformWidget(), shouldEnable); +} + + + diff --git a/WebCore/platform/gtk/ScrollbarGtk.h b/WebCore/platform/gtk/ScrollbarGtk.h new file mode 100644 index 0000000..50e9184 --- /dev/null +++ b/WebCore/platform/gtk/ScrollbarGtk.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2004, 2006, 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ScrollbarGtk_h +#define ScrollbarGtk_h + +#include "Scrollbar.h" +#include <wtf/PassRefPtr.h> + +typedef struct _GtkAdjustment GtkAdjustment; + +namespace WebCore { + +class ScrollbarGtk : public Scrollbar { +public: + friend class Scrollbar; + + virtual ~ScrollbarGtk(); + + virtual void setFrameRect(const IntRect&); + + virtual bool handleMouseMoveEvent(const PlatformMouseEvent&) { return false; } + virtual bool handleMouseOutEvent(const PlatformMouseEvent&) { return false; } + virtual bool handleMousePressEvent(const PlatformMouseEvent&) { return false; } + virtual bool handleMouseReleaseEvent(const PlatformMouseEvent&) { return false; } + + virtual void setEnabled(bool); + + virtual void frameRectsChanged() const; + +protected: + ScrollbarGtk(ScrollbarClient*, ScrollbarOrientation, ScrollbarControlSize); + + virtual void updateThumbPosition(); + virtual void updateThumbProportion(); + virtual void frameRectsChanged(); + +private: + static void gtkValueChanged(GtkAdjustment*, ScrollbarGtk*); + GtkAdjustment* m_adjustment; +}; + +} + +#endif // ScrollbarGtk_h diff --git a/WebCore/platform/gtk/ScrollbarThemeGtk.cpp b/WebCore/platform/gtk/ScrollbarThemeGtk.cpp new file mode 100644 index 0000000..fee2c70 --- /dev/null +++ b/WebCore/platform/gtk/ScrollbarThemeGtk.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ScrollbarThemeGtk.h" + +#include "gtkdrawing.h" +#include <gtk/gtk.h> + +namespace WebCore { + +ScrollbarTheme* ScrollbarTheme::nativeTheme() +{ + static ScrollbarThemeGtk theme; + return &theme; +} + +ScrollbarThemeGtk::~ScrollbarThemeGtk() +{ +} + +int ScrollbarThemeGtk::scrollbarThickness(ScrollbarControlSize controlSize) +{ + static int size; + if (!size) { + MozGtkScrollbarMetrics metrics; + moz_gtk_get_scrollbar_metrics(&metrics); + size = metrics.slider_width; + } + return size; +} + +} + diff --git a/WebCore/platform/gtk/ScrollbarThemeGtk.h b/WebCore/platform/gtk/ScrollbarThemeGtk.h new file mode 100644 index 0000000..21ccb43 --- /dev/null +++ b/WebCore/platform/gtk/ScrollbarThemeGtk.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ScrollbarThemeGtk_h +#define ScrollbarThemeGtk_h + +#include "ScrollbarTheme.h" + +namespace WebCore { + +class ScrollbarThemeGtk : public ScrollbarTheme { +public: + virtual ~ScrollbarThemeGtk(); + + virtual int scrollbarThickness(ScrollbarControlSize = RegularScrollbar); +}; + +} +#endif diff --git a/WebCore/platform/gtk/SearchPopupMenuGtk.cpp b/WebCore/platform/gtk/SearchPopupMenuGtk.cpp new file mode 100644 index 0000000..fbaa527 --- /dev/null +++ b/WebCore/platform/gtk/SearchPopupMenuGtk.cpp @@ -0,0 +1,46 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "SearchPopupMenu.h" + +#include "NotImplemented.h" + +namespace WebCore { + +SearchPopupMenu::SearchPopupMenu(PopupMenuClient* client) + : PopupMenu(client) +{ + notImplemented(); +} + +void SearchPopupMenu::saveRecentSearches(const AtomicString&, const Vector<String>&) +{ + notImplemented(); +} + +void SearchPopupMenu::loadRecentSearches(const AtomicString&, Vector<String>&) +{ + notImplemented(); +} + +bool SearchPopupMenu::enabled() +{ + notImplemented(); + return false; +} + +} diff --git a/WebCore/platform/gtk/SharedBufferGtk.cpp b/WebCore/platform/gtk/SharedBufferGtk.cpp new file mode 100644 index 0000000..783fec6 --- /dev/null +++ b/WebCore/platform/gtk/SharedBufferGtk.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2008 Collabora Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "SharedBuffer.h" + +#include "CString.h" +#include "FileSystem.h" + +#include <glib.h> + + +namespace WebCore { + +PassRefPtr<SharedBuffer> SharedBuffer::createWithContentsOfFile(const String& filePath) +{ + if (filePath.isEmpty()) + return 0; + + gchar* filename = filenameFromString(filePath); + gchar* contents; + gsize size; + GError* error = 0; + if (!g_file_get_contents(filename, &contents, &size, &error)) { + LOG_ERROR("Failed to fully read contents of file %s - %s", filenameForDisplay(filePath).utf8().data(), error->message); + g_error_free(error); + g_free(filename); + return 0; + } + + RefPtr<SharedBuffer> result = SharedBuffer::create(contents, size); + g_free(filename); + g_free(contents); + + return result.release(); +} + +} // namespace WebCore diff --git a/WebCore/platform/gtk/SharedTimerGtk.cpp b/WebCore/platform/gtk/SharedTimerGtk.cpp new file mode 100644 index 0000000..e0a5b60 --- /dev/null +++ b/WebCore/platform/gtk/SharedTimerGtk.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "SharedTimer.h" + +#include "SystemTime.h" +#include <wtf/Assertions.h> +#include <glib.h> + +namespace WebCore { + +static guint sharedTimer; +static void (*sharedTimerFiredFunction)(); + +void setSharedTimerFiredFunction(void (*f)()) +{ + sharedTimerFiredFunction = f; +} + +static gboolean timeout_cb(gpointer) +{ + if (sharedTimerFiredFunction) + sharedTimerFiredFunction(); + return FALSE; +} + +void setSharedTimerFireTime(double fireTime) +{ + ASSERT(sharedTimerFiredFunction); + + double interval = fireTime - currentTime(); + guint intervalInMS; + if (interval < 0) + intervalInMS = 0; + else { + interval *= 1000; + intervalInMS = (guint)interval; + } + + stopSharedTimer(); + if (intervalInMS == 0) + sharedTimer = g_idle_add(timeout_cb, NULL); + else + sharedTimer = g_timeout_add_full(G_PRIORITY_DEFAULT, intervalInMS, timeout_cb, NULL, NULL); +} + +void stopSharedTimer() +{ + gboolean s = FALSE; + if (sharedTimer == 0) + return; + + s = g_source_remove(sharedTimer); + ASSERT(s); + sharedTimer = 0; +} + +} diff --git a/WebCore/platform/gtk/SoundGtk.cpp b/WebCore/platform/gtk/SoundGtk.cpp new file mode 100644 index 0000000..2f7316c --- /dev/null +++ b/WebCore/platform/gtk/SoundGtk.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#include "Sound.h" + +#include <gdk/gdk.h> + +namespace WebCore { + +void systemBeep() +{ + gdk_beep(); +} + +} + +// vim: ts=4 sw=4 et diff --git a/WebCore/platform/gtk/SystemTimeGtk.cpp b/WebCore/platform/gtk/SystemTimeGtk.cpp new file mode 100644 index 0000000..9d26d41 --- /dev/null +++ b/WebCore/platform/gtk/SystemTimeGtk.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include <glib.h> + +namespace WebCore { + +double currentTime() +{ + GTimeVal now; + g_get_current_time(&now); + return static_cast<double>(now.tv_sec) + static_cast<double>(now.tv_usec / 1000000.0); +} + +} diff --git a/WebCore/platform/gtk/SystemTimeLinux.cpp b/WebCore/platform/gtk/SystemTimeLinux.cpp new file mode 100644 index 0000000..45caddd --- /dev/null +++ b/WebCore/platform/gtk/SystemTimeLinux.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "SystemTime.h" + +#include <sys/time.h> + +namespace WebCore { + +double currentTime() +{ + struct timeval aTimeval; + struct timezone aTimezone; + + gettimeofday( &aTimeval, &aTimezone ); + return (double)aTimeval.tv_sec + (double)(aTimeval.tv_usec / 1000000.0 ); +} + +} diff --git a/WebCore/platform/gtk/TemporaryLinkStubs.cpp b/WebCore/platform/gtk/TemporaryLinkStubs.cpp new file mode 100644 index 0000000..5093794 --- /dev/null +++ b/WebCore/platform/gtk/TemporaryLinkStubs.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include "AXObjectCache.h" +#include "DNS.h" +#include "Editor.h" +#include "FrameView.h" +#include "FTPDirectoryDocument.h" +#include "NotImplemented.h" +#include "PluginView.h" +#include <float.h> + +using namespace WebCore; + +// This function loads resources from WebKit +// This does not belong here and I'm not sure where +// it should go +// I don't know what the plans or design is +// for none code resources +Vector<char> loadResourceIntoArray(const char* resourceName) +{ + Vector<char> resource; + //if (strcmp(resourceName,"missingImage") == 0) { + //} + return resource; +} + + +/********************************************************/ +/* Completely empty stubs (mostly to allow DRT to run): */ +/********************************************************/ + +void PluginView::invalidateRegion(NPRegion) { notImplemented(); } + +Color WebCore::focusRingColor() { return Color(); } + +namespace WebCore { +void getSupportedKeySizes(Vector<String>&) { notImplemented(); } +String signedPublicKeyAndChallengeString(unsigned keySizeIndex, const String &challengeString, const KURL &url) { return String(); } +float userIdleTime() { notImplemented(); return FLT_MAX; } // return an arbitrarily high userIdleTime so that releasing pages from the page cache isn't postponed + +} diff --git a/WebCore/platform/gtk/WheelEventGtk.cpp b/WebCore/platform/gtk/WheelEventGtk.cpp new file mode 100644 index 0000000..fbe31f7 --- /dev/null +++ b/WebCore/platform/gtk/WheelEventGtk.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "PlatformWheelEvent.h" + +#include <gdk/gdk.h> +#include <gtk/gtkversion.h> + +namespace WebCore { + +// Keep this in sync with the other platform event constructors +PlatformWheelEvent::PlatformWheelEvent(GdkEventScroll* event) +{ + static const float delta = 1; + + m_deltaX = 0; + m_deltaY = 0; + + // Docs say an upwards scroll (away from the user) has a positive delta + switch (event->direction) { + case GDK_SCROLL_UP: + m_deltaY = delta; + break; + case GDK_SCROLL_DOWN: + m_deltaY = -delta; + break; + case GDK_SCROLL_LEFT: + m_deltaX = -delta; + break; + case GDK_SCROLL_RIGHT: + m_deltaX = delta; + break; + } + + m_position = IntPoint((int)event->x, (int)event->y); + m_globalPosition = IntPoint((int)event->x_root, (int)event->y_root); + m_granularity = ScrollByLineWheelEvent; + m_isAccepted = false; + m_shiftKey = event->state & GDK_SHIFT_MASK; + m_ctrlKey = event->state & GDK_CONTROL_MASK; + m_altKey = event->state & GDK_MOD1_MASK; +#if GTK_CHECK_VERSION(2,10,0) + m_metaKey = event->state & GDK_META_MASK; +#else + // GDK_MOD2_MASK doesn't always mean meta so we can't use it + m_metaKey = false; +#endif + + // FIXME: retrieve the user setting for the number of lines to scroll on each wheel event + m_deltaX *= horizontalLineMultiplier(); + m_deltaY *= verticalLineMultiplier(); +} + +} diff --git a/WebCore/platform/gtk/WidgetGtk.cpp b/WebCore/platform/gtk/WidgetGtk.cpp new file mode 100644 index 0000000..82fed74 --- /dev/null +++ b/WebCore/platform/gtk/WidgetGtk.cpp @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com + * Copyright (C) 2007 Holger Hans Peter Freyther + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Widget.h" + +#include "Cursor.h" +#include "FrameView.h" +#include "GraphicsContext.h" +#include "HostWindow.h" +#include "IntRect.h" +#include "NotImplemented.h" +#include "RenderObject.h" + +#include <gdk/gdk.h> +#include <gtk/gtk.h> + +namespace WebCore { + +class WidgetPrivate { +public: + GdkCursor* cursor; +}; + +Widget::Widget(PlatformWidget widget) + : m_data(new WidgetPrivate) +{ + init(widget); + m_data->cursor = 0; +} + +Widget::~Widget() +{ + ASSERT(!parent()); + releasePlatformWidget(); + delete m_data; +} + +void Widget::setFocus() +{ + gtk_widget_grab_focus(platformWidget() ? platformWidget() : GTK_WIDGET(root()->hostWindow()->platformWindow())); +} + +Cursor Widget::cursor() +{ + return Cursor(m_data->cursor); +} + +static GdkDrawable* gdkDrawable(PlatformWidget widget) +{ + return widget ? widget->window : 0; +} + +void Widget::setCursor(const Cursor& cursor) +{ + GdkCursor* pcur = cursor.impl(); + + // http://bugs.webkit.org/show_bug.cgi?id=16388 + // [GTK] Widget::setCursor() gets called frequently + // + // gdk_window_set_cursor() in certain GDK backends seems to be an + // expensive operation, so avoid it if possible. + + if (pcur == m_data->cursor) + return; + + gdk_window_set_cursor(gdkDrawable(platformWidget()) ? GDK_WINDOW(gdkDrawable(platformWidget())) : GTK_WIDGET(root()->hostWindow()->platformWindow())->window, pcur); + m_data->cursor = pcur; +} + +void Widget::show() +{ + if (!platformWidget()) + return; + gtk_widget_show(platformWidget()); +} + +void Widget::hide() +{ + if (!platformWidget()) + return; + gtk_widget_hide(platformWidget()); +} + +/* + * Strategy to painting a Widget: + * 1.) do not paint if there is no GtkWidget set + * 2.) We assume that GTK_NO_WINDOW is set and that frameRectsChanged positioned + * the widget correctly. ATM we do not honor the GraphicsContext translation. + */ +void Widget::paint(GraphicsContext* context, const IntRect&) +{ + if (!platformWidget()) + return; + + if (!context->gdkExposeEvent()) + return; + + GtkWidget* widget = platformWidget(); + ASSERT(GTK_WIDGET_NO_WINDOW(widget)); + + GdkEvent* event = gdk_event_new(GDK_EXPOSE); + event->expose = *context->gdkExposeEvent(); + event->expose.region = gtk_widget_region_intersect(widget, event->expose.region); + + /* + * This will be unref'ed by gdk_event_free. + */ + g_object_ref(event->expose.window); + + /* + * If we are going to paint do the translation and GtkAllocation manipulation. + */ + if (!gdk_region_empty(event->expose.region)) { + gdk_region_get_clipbox(event->expose.region, &event->expose.area); + gtk_widget_send_expose(widget, event); + } + + gdk_event_free(event); +} + +void Widget::setIsSelected(bool) +{ + notImplemented(); +} + +IntRect Widget::frameRect() const +{ + return m_frame; +} + +void Widget::setFrameRect(const IntRect& rect) +{ + m_frame = rect; +} + +void Widget::releasePlatformWidget() +{ + if (!platformWidget()) + return; + g_object_unref(platformWidget()); +} + +void Widget::retainPlatformWidget() +{ + if (!platformWidget()) + return; +#if GLIB_CHECK_VERSION(2,10,0) + g_object_ref_sink(platformWidget()); +#else + g_object_ref(platformWidget()); + gtk_object_sink(GTK_OBJECT(platformWidget())); +#endif +} + +} diff --git a/WebCore/platform/gtk/gtk2drawing.c b/WebCore/platform/gtk/gtk2drawing.c new file mode 100644 index 0000000..83b4cb4 --- /dev/null +++ b/WebCore/platform/gtk/gtk2drawing.c @@ -0,0 +1,3311 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brian Ryner <bryner@brianryner.com> (Original Author) + * Pierre Chanial <p_ch@verizon.net> + * Michael Ventnor <m.ventnor@gmail.com> + * Alp Toker <alp@nuanti.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* + * This file contains painting functions for each of the gtk2 widgets. + * Adapted from the gtkdrawing.c, and gtk+2.0 source. + */ + +#include <gtk/gtk.h> +#include <gdk/gdkprivate.h> +#include <string.h> +#include "gtkdrawing.h" + +#include <math.h> + +#define XTHICKNESS(style) (style->xthickness) +#define YTHICKNESS(style) (style->ythickness) +#define WINDOW_IS_MAPPED(window) ((window) && GDK_IS_WINDOW(window) && gdk_window_is_visible(window)) + +static GtkWidget* gProtoWindow; +static GtkWidget* gButtonWidget; +static GtkWidget* gToggleButtonWidget; +static GtkWidget* gButtonArrowWidget; +static GtkWidget* gCheckboxWidget; +static GtkWidget* gRadiobuttonWidget; +static GtkWidget* gHorizScrollbarWidget; +static GtkWidget* gVertScrollbarWidget; +static GtkWidget* gSpinWidget; +static GtkWidget* gHScaleWidget; +static GtkWidget* gVScaleWidget; +static GtkWidget* gEntryWidget; +static GtkWidget* gComboBoxWidget; +static GtkWidget* gComboBoxButtonWidget; +static GtkWidget* gComboBoxArrowWidget; +static GtkWidget* gComboBoxSeparatorWidget; +static GtkWidget* gComboBoxEntryWidget; +static GtkWidget* gComboBoxEntryTextareaWidget; +static GtkWidget* gComboBoxEntryButtonWidget; +static GtkWidget* gComboBoxEntryArrowWidget; +static GtkWidget* gHandleBoxWidget; +static GtkWidget* gToolbarWidget; +static GtkWidget* gFrameWidget; +static GtkWidget* gStatusbarWidget; +static GtkWidget* gProgressWidget; +static GtkWidget* gTabWidget; +static GtkWidget* gTooltipWidget; +static GtkWidget* gMenuBarWidget; +static GtkWidget* gMenuBarItemWidget; +static GtkWidget* gMenuPopupWidget; +static GtkWidget* gMenuItemWidget; +static GtkWidget* gImageMenuItemWidget; +static GtkWidget* gCheckMenuItemWidget; +static GtkWidget* gTreeViewWidget; +static GtkWidget* gMiddleTreeViewColumn; +static GtkWidget* gTreeHeaderCellWidget; +static GtkWidget* gTreeHeaderSortArrowWidget; +static GtkWidget* gExpanderWidget; +static GtkWidget* gToolbarSeparatorWidget; +static GtkWidget* gMenuSeparatorWidget; +static GtkWidget* gHPanedWidget; +static GtkWidget* gVPanedWidget; +static GtkWidget* gScrolledWindowWidget; + +static style_prop_t style_prop_func; +static gboolean have_arrow_scaling; +static gboolean have_2_10; +static gboolean is_initialized; + +/* Because we have such an unconventional way of drawing widgets, signal to the GTK theme engine + that they are drawing for Mozilla instead of a conventional GTK app so they can do any specific + things they may want to do. */ +static void +moz_gtk_set_widget_name(GtkWidget* widget) +{ + gtk_widget_set_name(widget, "MozillaGtkWidget"); +} + +gint +moz_gtk_enable_style_props(style_prop_t styleGetProp) +{ + style_prop_func = styleGetProp; + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_window_widget() +{ + if (!gProtoWindow) { + gProtoWindow = gtk_window_new(GTK_WINDOW_POPUP); + gtk_widget_realize(gProtoWindow); + moz_gtk_set_widget_name(gProtoWindow); + } + return MOZ_GTK_SUCCESS; +} + +static gint +setup_widget_prototype(GtkWidget* widget) +{ + static GtkWidget* protoLayout; + ensure_window_widget(); + if (!protoLayout) { + protoLayout = gtk_fixed_new(); + gtk_container_add(GTK_CONTAINER(gProtoWindow), protoLayout); + } + + gtk_container_add(GTK_CONTAINER(protoLayout), widget); + gtk_widget_realize(widget); + g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", TRUE); + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_button_widget() +{ + if (!gButtonWidget) { + gButtonWidget = gtk_button_new_with_label("M"); + setup_widget_prototype(gButtonWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_hpaned_widget() +{ + if (!gHPanedWidget) { + gHPanedWidget = gtk_hpaned_new(); + setup_widget_prototype(gHPanedWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_vpaned_widget() +{ + if (!gVPanedWidget) { + gVPanedWidget = gtk_vpaned_new(); + setup_widget_prototype(gVPanedWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_toggle_button_widget() +{ + if (!gToggleButtonWidget) { + gToggleButtonWidget = gtk_toggle_button_new(); + setup_widget_prototype(gToggleButtonWidget); + /* toggle button must be set active to get the right style on hover. */ + GTK_TOGGLE_BUTTON(gToggleButtonWidget)->active = TRUE; + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_button_arrow_widget() +{ + if (!gButtonArrowWidget) { + ensure_toggle_button_widget(); + + gButtonArrowWidget = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_OUT); + gtk_container_add(GTK_CONTAINER(gToggleButtonWidget), gButtonArrowWidget); + gtk_widget_realize(gButtonArrowWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_checkbox_widget() +{ + if (!gCheckboxWidget) { + gCheckboxWidget = gtk_check_button_new_with_label("M"); + setup_widget_prototype(gCheckboxWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_radiobutton_widget() +{ + if (!gRadiobuttonWidget) { + gRadiobuttonWidget = gtk_radio_button_new_with_label(NULL, "M"); + setup_widget_prototype(gRadiobuttonWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_scrollbar_widget() +{ + if (!gVertScrollbarWidget) { + gVertScrollbarWidget = gtk_vscrollbar_new(NULL); + setup_widget_prototype(gVertScrollbarWidget); + } + if (!gHorizScrollbarWidget) { + gHorizScrollbarWidget = gtk_hscrollbar_new(NULL); + setup_widget_prototype(gHorizScrollbarWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_spin_widget() +{ + if (!gSpinWidget) { + gSpinWidget = gtk_spin_button_new(NULL, 1, 0); + setup_widget_prototype(gSpinWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_scale_widget() +{ + if (!gHScaleWidget) { + gHScaleWidget = gtk_hscale_new(NULL); + setup_widget_prototype(gHScaleWidget); + } + if (!gVScaleWidget) { + gVScaleWidget = gtk_vscale_new(NULL); + setup_widget_prototype(gVScaleWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_entry_widget() +{ + if (!gEntryWidget) { + gEntryWidget = gtk_entry_new(); + setup_widget_prototype(gEntryWidget); + } + return MOZ_GTK_SUCCESS; +} + +/* We need to have pointers to the inner widgets (button, separator, arrow) + * of the ComboBox to get the correct rendering from theme engines which + * special cases their look. Since the inner layout can change, we ask GTK + * to NULL our pointers when they are about to become invalid because the + * corresponding widgets don't exist anymore. It's the role of + * g_object_add_weak_pointer(). + * Note that if we don't find the inner widgets (which shouldn't happen), we + * fallback to use generic "non-inner" widgets, and they don't need that kind + * of weak pointer since they are explicit children of gProtoWindow and as + * such GTK holds a strong reference to them. */ +static void +moz_gtk_get_combo_box_inner_button(GtkWidget *widget, gpointer client_data) +{ + if (GTK_IS_TOGGLE_BUTTON(widget)) { + gComboBoxButtonWidget = widget; + g_object_add_weak_pointer(G_OBJECT(widget), + (gpointer) &gComboBoxButtonWidget); + gtk_widget_realize(widget); + g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", TRUE); + } +} + +static void +moz_gtk_get_combo_box_button_inner_widgets(GtkWidget *widget, + gpointer client_data) +{ + if (GTK_IS_SEPARATOR(widget)) { + gComboBoxSeparatorWidget = widget; + g_object_add_weak_pointer(G_OBJECT(widget), + (gpointer) &gComboBoxSeparatorWidget); + } else if (GTK_IS_ARROW(widget)) { + gComboBoxArrowWidget = widget; + g_object_add_weak_pointer(G_OBJECT(widget), + (gpointer) &gComboBoxArrowWidget); + } else + return; + gtk_widget_realize(widget); + g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", TRUE); +} + +static gint +ensure_combo_box_widgets() +{ + GtkWidget* buttonChild; + + if (gComboBoxButtonWidget && gComboBoxArrowWidget) + return MOZ_GTK_SUCCESS; + + /* Create a ComboBox if needed */ + if (!gComboBoxWidget) { + gComboBoxWidget = gtk_combo_box_new(); + setup_widget_prototype(gComboBoxWidget); + } + + /* Get its inner Button */ + gtk_container_forall(GTK_CONTAINER(gComboBoxWidget), + moz_gtk_get_combo_box_inner_button, + NULL); + + if (gComboBoxButtonWidget) { + /* Get the widgets inside the Button */ + buttonChild = GTK_BIN(gComboBoxButtonWidget)->child; + if (GTK_IS_HBOX(buttonChild)) { + /* appears-as-list = FALSE, cell-view = TRUE; the button + * contains an hbox. This hbox is there because the ComboBox + * needs to place a cell renderer, a separator, and an arrow in + * the button when appears-as-list is FALSE. */ + gtk_container_forall(GTK_CONTAINER(buttonChild), + moz_gtk_get_combo_box_button_inner_widgets, + NULL); + } else if(GTK_IS_ARROW(buttonChild)) { + /* appears-as-list = TRUE, or cell-view = FALSE; + * the button only contains an arrow */ + gComboBoxArrowWidget = buttonChild; + g_object_add_weak_pointer(G_OBJECT(buttonChild), (gpointer) + &gComboBoxArrowWidget); + gtk_widget_realize(gComboBoxArrowWidget); + g_object_set_data(G_OBJECT(gComboBoxArrowWidget), + "transparent-bg-hint", TRUE); + } + } else { + /* Shouldn't be reached with current internal gtk implementation; we + * use a generic toggle button as last resort fallback to avoid + * crashing. */ + ensure_toggle_button_widget(); + gComboBoxButtonWidget = gToggleButtonWidget; + } + + if (!gComboBoxArrowWidget) { + /* Shouldn't be reached with current internal gtk implementation; + * we gButtonArrowWidget as last resort fallback to avoid + * crashing. */ + ensure_button_arrow_widget(); + gComboBoxArrowWidget = gButtonArrowWidget; + } + + /* We don't test the validity of gComboBoxSeparatorWidget since there + * is none when "appears-as-list" = TRUE or "cell-view" = FALSE; if it + * is invalid we just won't paint it. */ + + return MOZ_GTK_SUCCESS; +} + +/* We need to have pointers to the inner widgets (entry, button, arrow) of + * the ComboBoxEntry to get the correct rendering from theme engines which + * special cases their look. Since the inner layout can change, we ask GTK + * to NULL our pointers when they are about to become invalid because the + * corresponding widgets don't exist anymore. It's the role of + * g_object_add_weak_pointer(). + * Note that if we don't find the inner widgets (which shouldn't happen), we + * fallback to use generic "non-inner" widgets, and they don't need that kind + * of weak pointer since they are explicit children of gProtoWindow and as + * such GTK holds a strong reference to them. */ +static void +moz_gtk_get_combo_box_entry_inner_widgets(GtkWidget *widget, + gpointer client_data) +{ + if (GTK_IS_TOGGLE_BUTTON(widget)) { + gComboBoxEntryButtonWidget = widget; + g_object_add_weak_pointer(G_OBJECT(widget), + (gpointer) &gComboBoxEntryButtonWidget); + } else if (GTK_IS_ENTRY(widget)) { + gComboBoxEntryTextareaWidget = widget; + g_object_add_weak_pointer(G_OBJECT(widget), + (gpointer) &gComboBoxEntryTextareaWidget); + } else + return; + gtk_widget_realize(widget); + g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", TRUE); +} + +static void +moz_gtk_get_combo_box_entry_arrow(GtkWidget *widget, gpointer client_data) +{ + if (GTK_IS_ARROW(widget)) { + gComboBoxEntryArrowWidget = widget; + g_object_add_weak_pointer(G_OBJECT(widget), + (gpointer) &gComboBoxEntryArrowWidget); + gtk_widget_realize(widget); + g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", TRUE); + } +} + +static gint +ensure_combo_box_entry_widgets() +{ + GtkWidget* buttonChild; + + if (gComboBoxEntryTextareaWidget && + gComboBoxEntryButtonWidget && + gComboBoxEntryArrowWidget) + return MOZ_GTK_SUCCESS; + + /* Create a ComboBoxEntry if needed */ + if (!gComboBoxEntryWidget) { + gComboBoxEntryWidget = gtk_combo_box_entry_new(); + setup_widget_prototype(gComboBoxEntryWidget); + } + + /* Get its inner Entry and Button */ + gtk_container_forall(GTK_CONTAINER(gComboBoxEntryWidget), + moz_gtk_get_combo_box_entry_inner_widgets, + NULL); + + if (!gComboBoxEntryTextareaWidget) { + ensure_entry_widget(); + gComboBoxEntryTextareaWidget = gEntryWidget; + } + + if (gComboBoxEntryButtonWidget) { + /* Get the Arrow inside the Button */ + buttonChild = GTK_BIN(gComboBoxEntryButtonWidget)->child; + if (GTK_IS_HBOX(buttonChild)) { + /* appears-as-list = FALSE, cell-view = TRUE; the button + * contains an hbox. This hbox is there because ComboBoxEntry + * inherits from ComboBox which needs to place a cell renderer, + * a separator, and an arrow in the button when appears-as-list + * is FALSE. Here the hbox should only contain an arrow, since + * a ComboBoxEntry doesn't need all those widgets in the + * button. */ + gtk_container_forall(GTK_CONTAINER(buttonChild), + moz_gtk_get_combo_box_entry_arrow, + NULL); + } else if(GTK_IS_ARROW(buttonChild)) { + /* appears-as-list = TRUE, or cell-view = FALSE; + * the button only contains an arrow */ + gComboBoxEntryArrowWidget = buttonChild; + g_object_add_weak_pointer(G_OBJECT(buttonChild), (gpointer) + &gComboBoxEntryArrowWidget); + gtk_widget_realize(gComboBoxEntryArrowWidget); + g_object_set_data(G_OBJECT(gComboBoxEntryArrowWidget), + "transparent-bg-hint", TRUE); + } + } else { + /* Shouldn't be reached with current internal gtk implementation; + * we use a generic toggle button as last resort fallback to avoid + * crashing. */ + ensure_toggle_button_widget(); + gComboBoxEntryButtonWidget = gToggleButtonWidget; + } + + if (!gComboBoxEntryArrowWidget) { + /* Shouldn't be reached with current internal gtk implementation; + * we gButtonArrowWidget as last resort fallback to avoid + * crashing. */ + ensure_button_arrow_widget(); + gComboBoxEntryArrowWidget = gButtonArrowWidget; + } + + return MOZ_GTK_SUCCESS; +} + + +static gint +ensure_handlebox_widget() +{ + if (!gHandleBoxWidget) { + gHandleBoxWidget = gtk_handle_box_new(); + setup_widget_prototype(gHandleBoxWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_toolbar_widget() +{ + if (!gToolbarWidget) { + ensure_handlebox_widget(); + gToolbarWidget = gtk_toolbar_new(); + gtk_container_add(GTK_CONTAINER(gHandleBoxWidget), gToolbarWidget); + gtk_widget_realize(gToolbarWidget); + g_object_set_data(G_OBJECT(gToolbarWidget), "transparent-bg-hint", TRUE); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_toolbar_separator_widget() +{ + if (!gToolbarSeparatorWidget) { + ensure_toolbar_widget(); + gToolbarSeparatorWidget = GTK_WIDGET(gtk_separator_tool_item_new()); + setup_widget_prototype(gToolbarSeparatorWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_tooltip_widget() +{ + if (!gTooltipWidget) { + gTooltipWidget = gtk_window_new(GTK_WINDOW_POPUP); + gtk_widget_realize(gTooltipWidget); + moz_gtk_set_widget_name(gTooltipWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_tab_widget() +{ + if (!gTabWidget) { + gTabWidget = gtk_notebook_new(); + setup_widget_prototype(gTabWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_progress_widget() +{ + if (!gProgressWidget) { + gProgressWidget = gtk_progress_bar_new(); + setup_widget_prototype(gProgressWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_statusbar_widget() +{ + if (!gStatusbarWidget) { + gStatusbarWidget = gtk_statusbar_new(); + setup_widget_prototype(gStatusbarWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_frame_widget() +{ + if (!gFrameWidget) { + ensure_statusbar_widget(); + gFrameWidget = gtk_frame_new(NULL); + gtk_container_add(GTK_CONTAINER(gStatusbarWidget), gFrameWidget); + gtk_widget_realize(gFrameWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_menu_bar_widget() +{ + if (!gMenuBarWidget) { + gMenuBarWidget = gtk_menu_bar_new(); + setup_widget_prototype(gMenuBarWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_menu_bar_item_widget() +{ + if (!gMenuBarItemWidget) { + ensure_menu_bar_widget(); + gMenuBarItemWidget = gtk_menu_item_new(); + gtk_menu_shell_append(GTK_MENU_SHELL(gMenuBarWidget), + gMenuBarItemWidget); + gtk_widget_realize(gMenuBarItemWidget); + g_object_set_data(G_OBJECT(gMenuBarItemWidget), + "transparent-bg-hint", TRUE); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_menu_popup_widget() +{ + if (!gMenuPopupWidget) { + ensure_menu_bar_item_widget(); + gMenuPopupWidget = gtk_menu_new(); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(gMenuBarItemWidget), + gMenuPopupWidget); + gtk_widget_realize(gMenuPopupWidget); + g_object_set_data(G_OBJECT(gMenuPopupWidget), + "transparent-bg-hint", TRUE); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_menu_item_widget() +{ + if (!gMenuItemWidget) { + ensure_menu_popup_widget(); + gMenuItemWidget = gtk_menu_item_new_with_label("M"); + gtk_menu_shell_append(GTK_MENU_SHELL(gMenuPopupWidget), + gMenuItemWidget); + gtk_widget_realize(gMenuItemWidget); + g_object_set_data(G_OBJECT(gMenuItemWidget), + "transparent-bg-hint", TRUE); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_image_menu_item_widget() +{ + if (!gImageMenuItemWidget) { + ensure_menu_popup_widget(); + gImageMenuItemWidget = gtk_image_menu_item_new(); + gtk_menu_shell_append(GTK_MENU_SHELL(gMenuPopupWidget), + gImageMenuItemWidget); + gtk_widget_realize(gImageMenuItemWidget); + g_object_set_data(G_OBJECT(gImageMenuItemWidget), + "transparent-bg-hint", TRUE); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_menu_separator_widget() +{ + if (!gMenuSeparatorWidget) { + ensure_menu_popup_widget(); + gMenuSeparatorWidget = gtk_separator_menu_item_new(); + gtk_menu_shell_append(GTK_MENU_SHELL(gMenuPopupWidget), + gMenuSeparatorWidget); + gtk_widget_realize(gMenuSeparatorWidget); + g_object_set_data(G_OBJECT(gMenuSeparatorWidget), + "transparent-bg-hint", TRUE); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_check_menu_item_widget() +{ + if (!gCheckMenuItemWidget) { + ensure_menu_popup_widget(); + gCheckMenuItemWidget = gtk_check_menu_item_new_with_label("M"); + gtk_menu_shell_append(GTK_MENU_SHELL(gMenuPopupWidget), + gCheckMenuItemWidget); + gtk_widget_realize(gCheckMenuItemWidget); + g_object_set_data(G_OBJECT(gCheckMenuItemWidget), + "transparent-bg-hint", TRUE); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_tree_view_widget() +{ + if (!gTreeViewWidget) { + gTreeViewWidget = gtk_tree_view_new(); + setup_widget_prototype(gTreeViewWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_tree_header_cell_widget() +{ + if(!gTreeHeaderCellWidget) { + /* + * Some GTK engines paint the first and last cell + * of a TreeView header with a highlight. + * Since we do not know where our widget will be relative + * to the other buttons in the TreeView header, we must + * paint it as a button that is between two others, + * thus ensuring it is neither the first or last button + * in the header. + * GTK doesn't give us a way to do this explicitly, + * so we must paint with a button that is between two + * others. + */ + + GtkTreeViewColumn* firstTreeViewColumn; + GtkTreeViewColumn* lastTreeViewColumn; + + ensure_tree_view_widget(); + + /* Create and append our three columns */ + firstTreeViewColumn = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(firstTreeViewColumn, "M"); + gtk_tree_view_append_column(GTK_TREE_VIEW(gTreeViewWidget), firstTreeViewColumn); + + gMiddleTreeViewColumn = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(GTK_TREE_VIEW_COLUMN(gMiddleTreeViewColumn), "M"); + gtk_tree_view_append_column(GTK_TREE_VIEW(gTreeViewWidget), + GTK_TREE_VIEW_COLUMN(gMiddleTreeViewColumn)); + + lastTreeViewColumn = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(lastTreeViewColumn, "M"); + gtk_tree_view_append_column(GTK_TREE_VIEW(gTreeViewWidget), lastTreeViewColumn); + + /* Use the middle column's header for our button */ + gTreeHeaderCellWidget = GTK_TREE_VIEW_COLUMN(gMiddleTreeViewColumn)->button; + gTreeHeaderSortArrowWidget = GTK_TREE_VIEW_COLUMN(gMiddleTreeViewColumn)->arrow; + g_object_set_data(G_OBJECT(gTreeHeaderCellWidget), + "transparent-bg-hint", TRUE); + g_object_set_data(G_OBJECT(gTreeHeaderSortArrowWidget), + "transparent-bg-hint", TRUE); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_expander_widget() +{ + if (!gExpanderWidget) { + gExpanderWidget = gtk_expander_new("M"); + setup_widget_prototype(gExpanderWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_scrolled_window_widget() +{ + if (!gScrolledWindowWidget) { + gScrolledWindowWidget = gtk_scrolled_window_new(NULL, NULL); + setup_widget_prototype(gScrolledWindowWidget); + } + return MOZ_GTK_SUCCESS; +} + +static GtkStateType +ConvertGtkState(GtkWidgetState* state) +{ + if (state->disabled) + return GTK_STATE_INSENSITIVE; + else if (state->depressed) + return (state->inHover ? GTK_STATE_PRELIGHT : GTK_STATE_ACTIVE); + else if (state->inHover) + return (state->active ? GTK_STATE_ACTIVE : GTK_STATE_PRELIGHT); + else + return GTK_STATE_NORMAL; +} + +static gint +TSOffsetStyleGCArray(GdkGC** gcs, gint xorigin, gint yorigin) +{ + int i; + /* there are 5 gc's in each array, for each of the widget states */ + for (i = 0; i < 5; ++i) + gdk_gc_set_ts_origin(gcs[i], xorigin, yorigin); + return MOZ_GTK_SUCCESS; +} + +static gint +TSOffsetStyleGCs(GtkStyle* style, gint xorigin, gint yorigin) +{ + TSOffsetStyleGCArray(style->fg_gc, xorigin, yorigin); + TSOffsetStyleGCArray(style->bg_gc, xorigin, yorigin); + TSOffsetStyleGCArray(style->light_gc, xorigin, yorigin); + TSOffsetStyleGCArray(style->dark_gc, xorigin, yorigin); + TSOffsetStyleGCArray(style->mid_gc, xorigin, yorigin); + TSOffsetStyleGCArray(style->text_gc, xorigin, yorigin); + TSOffsetStyleGCArray(style->base_gc, xorigin, yorigin); + gdk_gc_set_ts_origin(style->black_gc, xorigin, yorigin); + gdk_gc_set_ts_origin(style->white_gc, xorigin, yorigin); + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_button_paint(GdkDrawable* drawable, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + GtkReliefStyle relief, GtkWidget* widget, + GtkTextDirection direction) +{ + GtkShadowType shadow_type; + GtkStyle* style = widget->style; + GtkStateType button_state = ConvertGtkState(state); + gint x = rect->x, y=rect->y, width=rect->width, height=rect->height; + + gboolean interior_focus; + gint focus_width, focus_pad; + + moz_gtk_widget_get_focus(widget, &interior_focus, &focus_width, &focus_pad); + + if (WINDOW_IS_MAPPED(drawable)) { + gdk_window_set_back_pixmap(drawable, NULL, TRUE); + gdk_window_clear_area(drawable, cliprect->x, cliprect->y, + cliprect->width, cliprect->height); + } + + gtk_widget_set_state(widget, button_state); + gtk_widget_set_direction(widget, direction); + + if (state->isDefault) + GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_DEFAULT); + + GTK_BUTTON(widget)->relief = relief; + + /* Some theme engines love to cause us pain in that gtk_paint_focus is a + no-op on buttons and button-like widgets. They only listen to this flag. */ + if (state->focused && !state->disabled) + GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS); + + if (!interior_focus && state->focused) { + x += focus_width + focus_pad; + y += focus_width + focus_pad; + width -= 2 * (focus_width + focus_pad); + height -= 2 * (focus_width + focus_pad); + } + + shadow_type = button_state == GTK_STATE_ACTIVE || + state->depressed ? GTK_SHADOW_IN : GTK_SHADOW_OUT; + + if (state->isDefault && relief == GTK_RELIEF_NORMAL) { + gtk_paint_box(style, drawable, button_state, shadow_type, cliprect, + widget, "buttondefault", x, y, width, height); + } + + if (relief != GTK_RELIEF_NONE || state->depressed || + (button_state != GTK_STATE_NORMAL && + button_state != GTK_STATE_INSENSITIVE)) { + TSOffsetStyleGCs(style, x, y); + /* the following line can trigger an assertion (Crux theme) + file ../../gdk/gdkwindow.c: line 1846 (gdk_window_clear_area): + assertion `GDK_IS_WINDOW (window)' failed */ + gtk_paint_box(style, drawable, button_state, shadow_type, cliprect, + widget, "button", x, y, width, height); + } + + if (state->focused) { + if (interior_focus) { + x += widget->style->xthickness + focus_pad; + y += widget->style->ythickness + focus_pad; + width -= 2 * (widget->style->xthickness + focus_pad); + height -= 2 * (widget->style->ythickness + focus_pad); + } else { + x -= focus_width + focus_pad; + y -= focus_width + focus_pad; + width += 2 * (focus_width + focus_pad); + height += 2 * (focus_width + focus_pad); + } + + TSOffsetStyleGCs(style, x, y); + gtk_paint_focus(style, drawable, button_state, cliprect, + widget, "button", x, y, width, height); + } + + GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_DEFAULT); + GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_FOCUS); + return MOZ_GTK_SUCCESS; +} + +gint +moz_gtk_init() +{ + GtkWidgetClass *entry_class; + + is_initialized = TRUE; + have_arrow_scaling = (gtk_major_version > 2 || + (gtk_major_version == 2 && gtk_minor_version >= 12)); + + have_2_10 = (gtk_major_version > 2 || + (gtk_major_version == 2 && gtk_minor_version >= 10)); + + /* Add style property to GtkEntry. + * Adding the style property to the normal GtkEntry class means that it + * will work without issues inside GtkComboBox and for Spinbuttons. */ + entry_class = g_type_class_ref(GTK_TYPE_ENTRY); + gtk_widget_class_install_style_property(entry_class, + g_param_spec_boolean("honors-transparent-bg-hint", + "Transparent BG enabling flag", + "If TRUE, the theme is able to draw the GtkEntry on non-prefilled background.", + FALSE, + G_PARAM_READWRITE)); + + return MOZ_GTK_SUCCESS; +} + +gint +moz_gtk_checkbox_get_metrics(gint* indicator_size, gint* indicator_spacing) +{ + ensure_checkbox_widget(); + + gtk_widget_style_get (gCheckboxWidget, + "indicator_size", indicator_size, + "indicator_spacing", indicator_spacing, + NULL); + + return MOZ_GTK_SUCCESS; +} + +gint +moz_gtk_radio_get_metrics(gint* indicator_size, gint* indicator_spacing) +{ + ensure_radiobutton_widget(); + + gtk_widget_style_get (gRadiobuttonWidget, + "indicator_size", indicator_size, + "indicator_spacing", indicator_spacing, + NULL); + + return MOZ_GTK_SUCCESS; +} + +gint +moz_gtk_widget_get_focus(GtkWidget* widget, gboolean* interior_focus, + gint* focus_width, gint* focus_pad) +{ + gtk_widget_style_get (widget, + "interior-focus", interior_focus, + "focus-line-width", focus_width, + "focus-padding", focus_pad, + NULL); + + return MOZ_GTK_SUCCESS; +} + +gint +moz_gtk_splitter_get_metrics(gint orientation, gint* size) +{ + if (orientation == GTK_ORIENTATION_HORIZONTAL) { + ensure_hpaned_widget(); + gtk_widget_style_get(gHPanedWidget, "handle_size", size, NULL); + } else { + ensure_vpaned_widget(); + gtk_widget_style_get(gVPanedWidget, "handle_size", size, NULL); + } + return MOZ_GTK_SUCCESS; +} + +gint +moz_gtk_button_get_inner_border(GtkWidget* widget, GtkBorder* inner_border) +{ + static const GtkBorder default_inner_border = { 1, 1, 1, 1 }; + GtkBorder *tmp_border = NULL; + + if (have_2_10) + gtk_widget_style_get (widget, "inner-border", &tmp_border, NULL); + + if (tmp_border) { + *inner_border = *tmp_border; + gtk_border_free(tmp_border); + } + else + *inner_border = default_inner_border; + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_toggle_paint(GdkDrawable* drawable, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + gboolean selected, gboolean isradio, + GtkTextDirection direction) +{ + GtkStateType state_type = ConvertGtkState(state); + GtkShadowType shadow_type = (selected)?GTK_SHADOW_IN:GTK_SHADOW_OUT; + gint indicator_size, indicator_spacing; + gint x, y, width, height; + gint focus_x, focus_y, focus_width, focus_height; + GtkWidget *w; + GtkStyle *style; + + if (isradio) { + moz_gtk_radio_get_metrics(&indicator_size, &indicator_spacing); + w = gRadiobuttonWidget; + } else { + moz_gtk_checkbox_get_metrics(&indicator_size, &indicator_spacing); + w = gCheckboxWidget; + } + + /* + * vertically center in the box, since XUL sometimes ignores our + * GetMinimumWidgetSize in the vertical dimension + */ + x = rect->x; + y = rect->y + (rect->height - indicator_size) / 2; + width = indicator_size; + height = indicator_size; + + focus_x = x - indicator_spacing; + focus_y = y - indicator_spacing; + focus_width = width + 2 * indicator_spacing; + focus_height = height + 2 * indicator_spacing; + + style = w->style; + TSOffsetStyleGCs(style, x, y); + + gtk_widget_set_sensitive(w, !state->disabled); + gtk_widget_set_direction(w, direction); + GTK_TOGGLE_BUTTON(w)->active = selected; + + if (isradio) { + gtk_paint_option(style, drawable, state_type, shadow_type, cliprect, + gRadiobuttonWidget, "radiobutton", x, y, + width, height); + if (state->focused) { + gtk_paint_focus(style, drawable, GTK_STATE_ACTIVE, cliprect, + gRadiobuttonWidget, "radiobutton", focus_x, focus_y, + focus_width, focus_height); + } + } + else { + gtk_paint_check(style, drawable, state_type, shadow_type, cliprect, + gCheckboxWidget, "checkbutton", x, y, width, height); + if (state->focused) { + gtk_paint_focus(style, drawable, GTK_STATE_ACTIVE, cliprect, + gCheckboxWidget, "checkbutton", focus_x, focus_y, + focus_width, focus_height); + } + } + + return MOZ_GTK_SUCCESS; +} + +static gint +calculate_button_inner_rect(GtkWidget* button, GdkRectangle* rect, + GdkRectangle* inner_rect, + GtkTextDirection direction, + gboolean ignore_focus) +{ + GtkBorder inner_border; + gboolean interior_focus; + gint focus_width, focus_pad; + GtkStyle* style; + + style = button->style; + + /* This mirrors gtkbutton's child positioning */ + moz_gtk_button_get_inner_border(button, &inner_border); + moz_gtk_widget_get_focus(button, &interior_focus, + &focus_width, &focus_pad); + + if (ignore_focus) + focus_width = focus_pad = 0; + + inner_rect->x = rect->x + XTHICKNESS(style) + focus_width + focus_pad; + inner_rect->x += direction == GTK_TEXT_DIR_LTR ? + inner_border.left : inner_border.right; + inner_rect->y = rect->y + inner_border.top + YTHICKNESS(style) + + focus_width + focus_pad; + inner_rect->width = MAX(1, rect->width - inner_border.left - + inner_border.right - (XTHICKNESS(style) + focus_pad + focus_width) * 2); + inner_rect->height = MAX(1, rect->height - inner_border.top - + inner_border.bottom - (YTHICKNESS(style) + focus_pad + focus_width) * 2); + + return MOZ_GTK_SUCCESS; +} + + +static gint +calculate_arrow_rect(GtkWidget* arrow, GdkRectangle* rect, + GdkRectangle* arrow_rect, GtkTextDirection direction) +{ + /* defined in gtkarrow.c */ + gfloat arrow_scaling = 0.7; + gfloat xalign, xpad; + gint extent; + GtkMisc* misc = GTK_MISC(arrow); + + if (have_arrow_scaling) + gtk_widget_style_get(arrow, "arrow_scaling", &arrow_scaling, NULL); + + extent = MIN((rect->width - misc->xpad * 2), + (rect->height - misc->ypad * 2)) * arrow_scaling; + + xalign = direction == GTK_TEXT_DIR_LTR ? misc->xalign : 1.0 - misc->xalign; + xpad = misc->xpad + (rect->width - extent) * xalign; + + arrow_rect->x = direction == GTK_TEXT_DIR_LTR ? + floor(rect->x + xpad) : ceil(rect->x + xpad); + arrow_rect->y = floor(rect->y + misc->ypad + + ((rect->height - extent) * misc->yalign)); + + arrow_rect->width = arrow_rect->height = extent; + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_scrollbar_button_paint(GdkDrawable* drawable, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + GtkScrollbarButtonFlags flags, + GtkTextDirection direction) +{ + GtkStateType state_type = ConvertGtkState(state); + GtkShadowType shadow_type = (state->active) ? + GTK_SHADOW_IN : GTK_SHADOW_OUT; + GdkRectangle arrow_rect; + GtkStyle* style; + GtkWidget *scrollbar; + GtkArrowType arrow_type; + gint arrow_displacement_x, arrow_displacement_y; + const char* detail = (flags & MOZ_GTK_STEPPER_VERTICAL) ? + "vscrollbar" : "hscrollbar"; + + ensure_scrollbar_widget(); + + if (flags & MOZ_GTK_STEPPER_VERTICAL) + scrollbar = gVertScrollbarWidget; + else + scrollbar = gHorizScrollbarWidget; + + gtk_widget_set_direction(scrollbar, direction); + + /* Some theme engines (i.e., ClearLooks) check the scrollbar's allocation + to determine where it should paint rounded corners on the buttons. + We need to trick them into drawing the buttons the way we want them. */ + + scrollbar->allocation.x = rect->x; + scrollbar->allocation.y = rect->y; + scrollbar->allocation.width = rect->width; + scrollbar->allocation.height = rect->height; + + if (flags & MOZ_GTK_STEPPER_VERTICAL) { + scrollbar->allocation.height *= 5; + if (flags & MOZ_GTK_STEPPER_DOWN) { + arrow_type = GTK_ARROW_DOWN; + if (flags & MOZ_GTK_STEPPER_BOTTOM) + scrollbar->allocation.y -= 4 * rect->height; + else + scrollbar->allocation.y -= rect->height; + + } else { + arrow_type = GTK_ARROW_UP; + if (flags & MOZ_GTK_STEPPER_BOTTOM) + scrollbar->allocation.y -= 3 * rect->height; + } + } else { + scrollbar->allocation.width *= 5; + if (flags & MOZ_GTK_STEPPER_DOWN) { + arrow_type = GTK_ARROW_RIGHT; + if (flags & MOZ_GTK_STEPPER_BOTTOM) + scrollbar->allocation.x -= 4 * rect->width; + else + scrollbar->allocation.x -= rect->width; + } else { + arrow_type = GTK_ARROW_LEFT; + if (flags & MOZ_GTK_STEPPER_BOTTOM) + scrollbar->allocation.x -= 3 * rect->width; + } + } + + style = scrollbar->style; + + TSOffsetStyleGCs(style, rect->x, rect->y); + + gtk_paint_box(style, drawable, state_type, shadow_type, cliprect, + scrollbar, detail, rect->x, rect->y, + rect->width, rect->height); + + arrow_rect.width = rect->width / 2; + arrow_rect.height = rect->height / 2; + arrow_rect.x = rect->x + (rect->width - arrow_rect.width) / 2; + arrow_rect.y = rect->y + (rect->height - arrow_rect.height) / 2; + + if (state_type == GTK_STATE_ACTIVE) { + gtk_widget_style_get(scrollbar, + "arrow-displacement-x", &arrow_displacement_x, + "arrow-displacement-y", &arrow_displacement_y, + NULL); + + arrow_rect.x += arrow_displacement_x; + arrow_rect.y += arrow_displacement_y; + } + + gtk_paint_arrow(style, drawable, state_type, shadow_type, cliprect, + scrollbar, detail, arrow_type, TRUE, arrow_rect.x, + arrow_rect.y, arrow_rect.width, arrow_rect.height); + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_scrollbar_trough_paint(GtkThemeWidgetType widget, + GdkDrawable* drawable, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + GtkTextDirection direction) +{ + GtkStyle* style; + GtkScrollbar *scrollbar; + + ensure_scrollbar_widget(); + + if (widget == MOZ_GTK_SCROLLBAR_TRACK_HORIZONTAL) + scrollbar = GTK_SCROLLBAR(gHorizScrollbarWidget); + else + scrollbar = GTK_SCROLLBAR(gVertScrollbarWidget); + + gtk_widget_set_direction(GTK_WIDGET(scrollbar), direction); + + style = GTK_WIDGET(scrollbar)->style; + + TSOffsetStyleGCs(style, rect->x, rect->y); + gtk_style_apply_default_background(style, drawable, TRUE, GTK_STATE_ACTIVE, + cliprect, rect->x, rect->y, + rect->width, rect->height); + + gtk_paint_box(style, drawable, GTK_STATE_ACTIVE, GTK_SHADOW_IN, cliprect, + GTK_WIDGET(scrollbar), "trough", rect->x, rect->y, + rect->width, rect->height); + + if (state->focused) { + gtk_paint_focus(style, drawable, GTK_STATE_ACTIVE, cliprect, + GTK_WIDGET(scrollbar), "trough", + rect->x, rect->y, rect->width, rect->height); + } + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_scrollbar_thumb_paint(GtkThemeWidgetType widget, + GdkDrawable* drawable, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + GtkTextDirection direction) +{ + GtkStateType state_type = (state->inHover || state->active) ? + GTK_STATE_PRELIGHT : GTK_STATE_NORMAL; + GtkShadowType shadow_type = GTK_SHADOW_OUT; + GtkStyle* style; + GtkScrollbar *scrollbar; + GtkAdjustment *adj; + gboolean activate_slider; + + ensure_scrollbar_widget(); + + if (widget == MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL) + scrollbar = GTK_SCROLLBAR(gHorizScrollbarWidget); + else + scrollbar = GTK_SCROLLBAR(gVertScrollbarWidget); + + gtk_widget_set_direction(GTK_WIDGET(scrollbar), direction); + + /* Make sure to set the scrollbar range before painting so that + everything is drawn properly. At least the bluecurve (and + maybe other) themes don't draw the top or bottom black line + surrounding the scrollbar if the theme thinks that it's butted + up against the scrollbar arrows. Note the increases of the + clip rect below. */ + /* Changing the cliprect is pretty bogus. This lets themes draw + outside the frame, which means we don't invalidate them + correctly. See bug 297508. But some themes do seem to need + it. So we modify the frame's overflow area to account for what + we're doing here; see nsNativeThemeGTK::GetWidgetOverflow. */ + adj = gtk_range_get_adjustment(GTK_RANGE(scrollbar)); + + if (widget == MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL) { + cliprect->x -= 1; + cliprect->width += 2; + adj->page_size = rect->width; + } + else { + cliprect->y -= 1; + cliprect->height += 2; + adj->page_size = rect->height; + } + + adj->lower = 0; + adj->value = state->curpos; + adj->upper = state->maxpos; + gtk_adjustment_changed(adj); + + style = GTK_WIDGET(scrollbar)->style; + + gtk_widget_style_get(GTK_WIDGET(scrollbar), "activate-slider", + &activate_slider, NULL); + + if (activate_slider && state->active) { + shadow_type = GTK_SHADOW_IN; + state_type = GTK_STATE_ACTIVE; + } + + TSOffsetStyleGCs(style, rect->x, rect->y); + + gtk_paint_slider(style, drawable, state_type, shadow_type, cliprect, + GTK_WIDGET(scrollbar), "slider", rect->x, rect->y, + rect->width, rect->height, + (widget == MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL) ? + GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL); + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_spin_paint(GdkDrawable* drawable, GdkRectangle* rect, + GtkTextDirection direction) +{ + GtkStyle* style; + + ensure_spin_widget(); + gtk_widget_set_direction(gSpinWidget, direction); + style = gSpinWidget->style; + + TSOffsetStyleGCs(style, rect->x, rect->y); + gtk_paint_box(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_IN, NULL, + gSpinWidget, "spinbutton", + rect->x, rect->y, rect->width, rect->height); + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_spin_updown_paint(GdkDrawable* drawable, GdkRectangle* rect, + gboolean isDown, GtkWidgetState* state, + GtkTextDirection direction) +{ + GdkRectangle arrow_rect; + GtkStateType state_type = ConvertGtkState(state); + GtkShadowType shadow_type = state_type == GTK_STATE_ACTIVE ? + GTK_SHADOW_IN : GTK_SHADOW_OUT; + GtkStyle* style; + + ensure_spin_widget(); + style = gSpinWidget->style; + gtk_widget_set_direction(gSpinWidget, direction); + + TSOffsetStyleGCs(style, rect->x, rect->y); + gtk_paint_box(style, drawable, state_type, shadow_type, NULL, gSpinWidget, + isDown ? "spinbutton_down" : "spinbutton_up", + rect->x, rect->y, rect->width, rect->height); + + /* hard code these values */ + arrow_rect.width = 6; + arrow_rect.height = 6; + arrow_rect.x = rect->x + (rect->width - arrow_rect.width) / 2; + arrow_rect.y = rect->y + (rect->height - arrow_rect.height) / 2; + arrow_rect.y += isDown ? -1 : 1; + + gtk_paint_arrow(style, drawable, state_type, shadow_type, NULL, + gSpinWidget, "spinbutton", + isDown ? GTK_ARROW_DOWN : GTK_ARROW_UP, TRUE, + arrow_rect.x, arrow_rect.y, + arrow_rect.width, arrow_rect.height); + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_scale_paint(GdkDrawable* drawable, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + GtkOrientation flags, GtkTextDirection direction) +{ + gint x = 0, y = 0; + GtkStateType state_type = ConvertGtkState(state); + GtkStyle* style; + GtkWidget* widget; + + ensure_scale_widget(); + widget = ((flags == GTK_ORIENTATION_HORIZONTAL) ? gHScaleWidget : gVScaleWidget); + gtk_widget_set_direction(widget, direction); + + style = widget->style; + + if (flags == GTK_ORIENTATION_HORIZONTAL) { + x = XTHICKNESS(style); + y++; + } + else { + x++; + y = YTHICKNESS(style); + } + + TSOffsetStyleGCs(style, rect->x, rect->y); + gtk_style_apply_default_background(style, drawable, TRUE, GTK_STATE_NORMAL, + cliprect, rect->x, rect->y, + rect->width, rect->height); + + gtk_paint_box(style, drawable, GTK_STATE_ACTIVE, GTK_SHADOW_IN, cliprect, + widget, "trough", rect->x + x, rect->y + y, + rect->width - 2*x, rect->height - 2*y); + + if (state->focused) + gtk_paint_focus(style, drawable, state_type, cliprect, widget, "trough", + rect->x, rect->y, rect->width, rect->height); + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_scale_thumb_paint(GdkDrawable* drawable, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + GtkOrientation flags, GtkTextDirection direction) +{ + GtkStateType state_type = ConvertGtkState(state); + GtkStyle* style; + GtkWidget* widget; + gint thumb_width, thumb_height, x, y; + + ensure_scale_widget(); + widget = ((flags == GTK_ORIENTATION_HORIZONTAL) ? gHScaleWidget : gVScaleWidget); + gtk_widget_set_direction(widget, direction); + + style = widget->style; + + /* determine the thumb size, and position the thumb in the center in the opposite axis */ + if (flags == GTK_ORIENTATION_HORIZONTAL) { + moz_gtk_get_scalethumb_metrics(GTK_ORIENTATION_HORIZONTAL, &thumb_width, &thumb_height); + x = rect->x; + y = rect->y + (rect->height - thumb_height) / 2; + } + else { + moz_gtk_get_scalethumb_metrics(GTK_ORIENTATION_VERTICAL, &thumb_height, &thumb_width); + x = rect->x + (rect->width - thumb_width) / 2; + y = rect->y; + } + + TSOffsetStyleGCs(style, rect->x, rect->y); + gtk_paint_slider(style, drawable, state_type, GTK_SHADOW_OUT, cliprect, + widget, (flags == GTK_ORIENTATION_HORIZONTAL) ? "hscale" : "vscale", + x, y, thumb_width, thumb_height, flags); + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_gripper_paint(GdkDrawable* drawable, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + GtkTextDirection direction) +{ + GtkStateType state_type = ConvertGtkState(state); + GtkShadowType shadow_type; + GtkStyle* style; + + ensure_handlebox_widget(); + gtk_widget_set_direction(gHandleBoxWidget, direction); + + style = gHandleBoxWidget->style; + shadow_type = GTK_HANDLE_BOX(gHandleBoxWidget)->shadow_type; + + TSOffsetStyleGCs(style, rect->x, rect->y); + gtk_paint_box(style, drawable, state_type, shadow_type, cliprect, + gHandleBoxWidget, "handlebox_bin", rect->x, rect->y, + rect->width, rect->height); + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_hpaned_paint(GdkDrawable* drawable, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state) +{ + GtkStateType hpaned_state = ConvertGtkState(state); + + ensure_hpaned_widget(); + gtk_paint_handle(gHPanedWidget->style, drawable, hpaned_state, + GTK_SHADOW_NONE, cliprect, gHPanedWidget, "paned", + rect->x, rect->y, rect->width, rect->height, + GTK_ORIENTATION_VERTICAL); + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_vpaned_paint(GdkDrawable* drawable, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state) +{ + GtkStateType vpaned_state = ConvertGtkState(state); + + ensure_vpaned_widget(); + gtk_paint_handle(gVPanedWidget->style, drawable, vpaned_state, + GTK_SHADOW_NONE, cliprect, gVPanedWidget, "paned", + rect->x, rect->y, rect->width, rect->height, + GTK_ORIENTATION_HORIZONTAL); + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_caret_paint(GdkDrawable* drawable, GdkRectangle* rect, + GdkRectangle* cliprect, GtkTextDirection direction) +{ + ensure_entry_widget(); + gtk_draw_insertion_cursor(gEntryWidget, drawable, cliprect, + rect, TRUE, direction, FALSE); + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_entry_paint(GdkDrawable* drawable, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + GtkWidget* widget, GtkTextDirection direction) +{ + GtkStateType bg_state = state->disabled ? + GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL; + gint x, y, width = rect->width, height = rect->height; + GtkStyle* style; + gboolean interior_focus; + gboolean theme_honors_transparency = FALSE; + gint focus_width; + + gtk_widget_set_direction(widget, direction); + + style = widget->style; + + gtk_widget_style_get(widget, + "interior-focus", &interior_focus, + "focus-line-width", &focus_width, + "honors-transparent-bg-hint", &theme_honors_transparency, + NULL); + + /* gtkentry.c uses two windows, one for the entire widget and one for the + * text area inside it. The background of both windows is set to the "base" + * color of the new state in gtk_entry_state_changed, but only the inner + * textarea window uses gtk_paint_flat_box when exposed */ + + TSOffsetStyleGCs(style, rect->x, rect->y); + + /* This gets us a lovely greyish disabledish look */ + gtk_widget_set_sensitive(widget, !state->disabled); + + /* GTK fills the outer widget window with the base color before drawing the widget. + * Some older themes rely on this behavior, but many themes nowadays use rounded + * corners on their widgets. While most GTK apps are blissfully unaware of this + * problem due to their use of the default window background, we render widgets on + * many kinds of backgrounds on the web. + * If the theme is able to cope with transparency, then we can skip pre-filling + * and notify the theme it will paint directly on the canvas. */ + if (theme_honors_transparency) { + g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", TRUE); + } else { + gdk_draw_rectangle(drawable, style->base_gc[bg_state], TRUE, + cliprect->x, cliprect->y, cliprect->width, cliprect->height); + g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", FALSE); + } + + /* Get the position of the inner window, see _gtk_entry_get_borders */ + x = XTHICKNESS(style); + y = YTHICKNESS(style); + + if (!interior_focus) { + x += focus_width; + y += focus_width; + } + + /* Simulate an expose of the inner window */ + gtk_paint_flat_box(style, drawable, bg_state, GTK_SHADOW_NONE, + cliprect, widget, "entry_bg", rect->x + x, + rect->y + y, rect->width - 2*x, rect->height - 2*y); + + /* Now paint the shadow and focus border. + * We do like in gtk_entry_draw_frame, we first draw the shadow, a tad + * smaller when focused if the focus is not interior, then the focus. */ + x = rect->x; + y = rect->y; + + if (state->focused && !state->disabled) { + /* This will get us the lit borders that focused textboxes enjoy on + * some themes. */ + GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS); + + if (!interior_focus) { + /* Indent the border a little bit if we have exterior focus + (this is what GTK does to draw native entries) */ + x += focus_width; + y += focus_width; + width -= 2 * focus_width; + height -= 2 * focus_width; + } + } + + gtk_paint_shadow(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_IN, + cliprect, widget, "entry", x, y, width, height); + + if (state->focused && !state->disabled) { + if (!interior_focus) { + gtk_paint_focus(style, drawable, GTK_STATE_NORMAL, cliprect, + widget, "entry", + rect->x, rect->y, rect->width, rect->height); + } + + /* Now unset the focus flag. We don't want other entries to look + * like they're focused too! */ + GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_FOCUS); + } + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_treeview_paint(GdkDrawable* drawable, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + GtkTextDirection direction) +{ + gint xthickness, ythickness; + + GtkStyle *style; + GtkStateType state_type; + + ensure_tree_view_widget(); + ensure_scrolled_window_widget(); + + gtk_widget_set_direction(gTreeViewWidget, direction); + gtk_widget_set_direction(gScrolledWindowWidget, direction); + + /* only handle disabled and normal states, otherwise the whole background + * area will be painted differently with other states */ + state_type = state->disabled ? GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL; + + /* In GTK the treeview sets the background of the window + * which contains the cells to the treeview base color. + * If we don't set it here the background color will not be correct.*/ + gtk_widget_modify_bg(gTreeViewWidget, state_type, + &gTreeViewWidget->style->base[state_type]); + + style = gScrolledWindowWidget->style; + xthickness = XTHICKNESS(style); + ythickness = YTHICKNESS(style); + + TSOffsetStyleGCs(gTreeViewWidget->style, rect->x, rect->y); + TSOffsetStyleGCs(style, rect->x, rect->y); + + gtk_paint_flat_box(gTreeViewWidget->style, drawable, state_type, + GTK_SHADOW_NONE, cliprect, gTreeViewWidget, "treeview", + rect->x + xthickness, rect->y + ythickness, + rect->width - 2 * xthickness, + rect->height - 2 * ythickness); + + gtk_paint_shadow(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_IN, + cliprect, gScrolledWindowWidget, "scrolled_window", + rect->x, rect->y, rect->width, rect->height); + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_tree_header_cell_paint(GdkDrawable* drawable, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + gboolean isSorted, GtkTextDirection direction) +{ + gtk_tree_view_column_set_sort_indicator(GTK_TREE_VIEW_COLUMN(gMiddleTreeViewColumn), + isSorted); + + moz_gtk_button_paint(drawable, rect, cliprect, state, GTK_RELIEF_NORMAL, + gTreeHeaderCellWidget, direction); + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_tree_header_sort_arrow_paint(GdkDrawable* drawable, GdkRectangle* rect, + GdkRectangle* cliprect, + GtkWidgetState* state, GtkArrowType flags, + GtkTextDirection direction) +{ + GdkRectangle arrow_rect; + GtkStateType state_type = ConvertGtkState(state); + GtkShadowType shadow_type = GTK_SHADOW_IN; + GtkArrowType arrow_type = flags; + GtkStyle* style; + + ensure_tree_header_cell_widget(); + gtk_widget_set_direction(gTreeHeaderSortArrowWidget, direction); + + /* hard code these values */ + arrow_rect.width = 11; + arrow_rect.height = 11; + arrow_rect.x = rect->x + (rect->width - arrow_rect.width) / 2; + arrow_rect.y = rect->y + (rect->height - arrow_rect.height) / 2; + + style = gTreeHeaderSortArrowWidget->style; + TSOffsetStyleGCs(style, arrow_rect.x, arrow_rect.y); + + gtk_paint_arrow(style, drawable, state_type, shadow_type, cliprect, + gTreeHeaderSortArrowWidget, "arrow", arrow_type, TRUE, + arrow_rect.x, arrow_rect.y, + arrow_rect.width, arrow_rect.height); + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_treeview_expander_paint(GdkDrawable* drawable, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + GtkExpanderStyle expander_state, + GtkTextDirection direction) +{ + GtkStyle *style; + GtkStateType state_type; + + ensure_tree_view_widget(); + gtk_widget_set_direction(gTreeViewWidget, direction); + + style = gTreeViewWidget->style; + + /* Because the frame we get is of the entire treeview, we can't get the precise + * event state of one expander, thus rendering hover and active feedback useless. */ + state_type = state->disabled ? GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL; + + TSOffsetStyleGCs(style, rect->x, rect->y); + gtk_paint_expander(style, drawable, state_type, cliprect, gTreeViewWidget, "treeview", + rect->x + rect->width / 2, rect->y + rect->height / 2, expander_state); + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_expander_paint(GdkDrawable* drawable, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + GtkExpanderStyle expander_state, + GtkTextDirection direction) +{ + GtkStyle *style; + GtkStateType state_type = ConvertGtkState(state); + + ensure_expander_widget(); + gtk_widget_set_direction(gExpanderWidget, direction); + + style = gExpanderWidget->style; + + TSOffsetStyleGCs(style, rect->x, rect->y); + gtk_paint_expander(style, drawable, state_type, cliprect, gExpanderWidget, "expander", + rect->x + rect->width / 2, rect->y + rect->height / 2, expander_state); + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_combo_box_paint(GdkDrawable* drawable, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + gboolean ishtml, GtkTextDirection direction) +{ + GdkRectangle arrow_rect, real_arrow_rect; + gint arrow_size, separator_width = 0; + gboolean wide_separators = FALSE; + GtkStateType state_type = ConvertGtkState(state); + GtkShadowType shadow_type = state->active ? GTK_SHADOW_IN : GTK_SHADOW_OUT; + GtkStyle* style; + GtkRequisition arrow_req; + + ensure_combo_box_widgets(); + + /* Also sets the direction on gComboBoxButtonWidget, which is then + * inherited by the separator and arrow */ + moz_gtk_button_paint(drawable, rect, cliprect, state, GTK_RELIEF_NORMAL, + gComboBoxButtonWidget, direction); + + calculate_button_inner_rect(gComboBoxButtonWidget, + rect, &arrow_rect, direction, ishtml); + /* Now arrow_rect contains the inner rect ; we want to correct the width + * to what the arrow needs (see gtk_combo_box_size_allocate) */ + gtk_widget_size_request(gComboBoxArrowWidget, &arrow_req); + if (direction == GTK_TEXT_DIR_LTR) + arrow_rect.x += arrow_rect.width - arrow_req.width; + arrow_rect.width = arrow_req.width; + + calculate_arrow_rect(gComboBoxArrowWidget, + &arrow_rect, &real_arrow_rect, direction); + + style = gComboBoxArrowWidget->style; + TSOffsetStyleGCs(style, rect->x, rect->y); + + gtk_widget_size_allocate(gComboBoxWidget, rect); + + gtk_paint_arrow(style, drawable, state_type, shadow_type, cliprect, + gComboBoxArrowWidget, "arrow", GTK_ARROW_DOWN, TRUE, + real_arrow_rect.x, real_arrow_rect.y, + real_arrow_rect.width, real_arrow_rect.height); + + + /* If there is no separator in the theme, there's nothing left to do. */ + if (!gComboBoxSeparatorWidget) + return MOZ_GTK_SUCCESS; + + style = gComboBoxSeparatorWidget->style; + TSOffsetStyleGCs(style, rect->x, rect->y); + + if (have_2_10) + gtk_widget_style_get(gComboBoxSeparatorWidget, + "wide-separators", &wide_separators, + "separator-width", &separator_width, + NULL); + + if (wide_separators) { + if (direction == GTK_TEXT_DIR_LTR) + arrow_rect.x -= separator_width; + else + arrow_rect.x += arrow_rect.width; + + gtk_paint_box(style, drawable, + GTK_STATE_NORMAL, GTK_SHADOW_ETCHED_OUT, + cliprect, gComboBoxSeparatorWidget, "vseparator", + arrow_rect.x, arrow_rect.y, + separator_width, arrow_rect.height); + } else { + if (direction == GTK_TEXT_DIR_LTR) + arrow_rect.x -= XTHICKNESS(style); + else + arrow_rect.x += arrow_rect.width; + + gtk_paint_vline(style, drawable, GTK_STATE_NORMAL, cliprect, + gComboBoxSeparatorWidget, "vseparator", + arrow_rect.y, arrow_rect.y + arrow_rect.height, + arrow_rect.x); + } + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_downarrow_paint(GdkDrawable* drawable, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state) +{ + GtkStyle* style; + GtkStateType state_type = ConvertGtkState(state); + GtkShadowType shadow_type = state->active ? GTK_SHADOW_IN : GTK_SHADOW_OUT; + GdkRectangle arrow_rect; + + ensure_button_arrow_widget(); + style = gButtonArrowWidget->style; + + calculate_arrow_rect(gButtonArrowWidget, rect, &arrow_rect, + GTK_TEXT_DIR_LTR); + + TSOffsetStyleGCs(style, arrow_rect.x, arrow_rect.y); + gtk_paint_arrow(style, drawable, state_type, shadow_type, cliprect, + gButtonArrowWidget, "arrow", GTK_ARROW_DOWN, TRUE, + arrow_rect.x, arrow_rect.y, arrow_rect.width, arrow_rect.height); + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_combo_box_entry_button_paint(GdkDrawable* drawable, GdkRectangle* rect, + GdkRectangle* cliprect, + GtkWidgetState* state, + gboolean input_focus, + GtkTextDirection direction) +{ + gint x_displacement, y_displacement; + GdkRectangle arrow_rect, real_arrow_rect; + GtkStateType state_type = ConvertGtkState(state); + GtkShadowType shadow_type = state->active ? GTK_SHADOW_IN : GTK_SHADOW_OUT; + GtkStyle* style; + + ensure_combo_box_entry_widgets(); + + if (input_focus) { + /* Some themes draw a complementary focus ring for the dropdown button + * when the dropdown entry has focus */ + GTK_WIDGET_SET_FLAGS(gComboBoxEntryTextareaWidget, GTK_HAS_FOCUS); + } + + moz_gtk_button_paint(drawable, rect, cliprect, state, GTK_RELIEF_NORMAL, + gComboBoxEntryButtonWidget, direction); + + if (input_focus) + GTK_WIDGET_UNSET_FLAGS(gComboBoxEntryTextareaWidget, GTK_HAS_FOCUS); + + calculate_button_inner_rect(gComboBoxEntryButtonWidget, + rect, &arrow_rect, direction, FALSE); + if (state_type == GTK_STATE_ACTIVE) { + gtk_widget_style_get(gComboBoxEntryButtonWidget, + "child-displacement-x", &x_displacement, + "child-displacement-y", &y_displacement, + NULL); + arrow_rect.x += x_displacement; + arrow_rect.y += y_displacement; + } + + calculate_arrow_rect(gComboBoxEntryArrowWidget, + &arrow_rect, &real_arrow_rect, direction); + + style = gComboBoxEntryArrowWidget->style; + TSOffsetStyleGCs(style, real_arrow_rect.x, real_arrow_rect.y); + + gtk_paint_arrow(style, drawable, state_type, shadow_type, cliprect, + gComboBoxEntryArrowWidget, "arrow", GTK_ARROW_DOWN, TRUE, + real_arrow_rect.x, real_arrow_rect.y, + real_arrow_rect.width, real_arrow_rect.height); + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_container_paint(GdkDrawable* drawable, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + gboolean isradio, GtkTextDirection direction) +{ + GtkStateType state_type = ConvertGtkState(state); + GtkStyle* style; + GtkWidget *widget; + gboolean interior_focus; + gint focus_width, focus_pad; + + if (isradio) { + ensure_radiobutton_widget(); + widget = gRadiobuttonWidget; + } else { + ensure_checkbox_widget(); + widget = gCheckboxWidget; + } + gtk_widget_set_direction(widget, direction); + + style = widget->style; + moz_gtk_widget_get_focus(widget, &interior_focus, &focus_width, + &focus_pad); + + TSOffsetStyleGCs(style, rect->x, rect->y); + + /* The detail argument for the gtk_paint_* calls below are "checkbutton" + even for radio buttons, to match what gtk does. */ + + /* this is for drawing a prelight box */ + if (state_type == GTK_STATE_PRELIGHT || state_type == GTK_STATE_ACTIVE) { + gtk_paint_flat_box(style, drawable, GTK_STATE_PRELIGHT, + GTK_SHADOW_ETCHED_OUT, cliprect, widget, + "checkbutton", + rect->x, rect->y, rect->width, rect->height); + } + + if (state_type != GTK_STATE_NORMAL && state_type != GTK_STATE_PRELIGHT) + state_type = GTK_STATE_NORMAL; + + if (state->focused && !interior_focus) { + gtk_paint_focus(style, drawable, state_type, cliprect, widget, + "checkbutton", + rect->x, rect->y, rect->width, rect->height); + } + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_toggle_label_paint(GdkDrawable* drawable, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + gboolean isradio, GtkTextDirection direction) +{ + GtkStateType state_type; + GtkStyle *style; + GtkWidget *widget; + gboolean interior_focus; + + if (!state->focused) + return MOZ_GTK_SUCCESS; + + if (isradio) { + ensure_radiobutton_widget(); + widget = gRadiobuttonWidget; + } else { + ensure_checkbox_widget(); + widget = gCheckboxWidget; + } + gtk_widget_set_direction(widget, direction); + + gtk_widget_style_get(widget, "interior-focus", &interior_focus, NULL); + if (!interior_focus) + return MOZ_GTK_SUCCESS; + + state_type = ConvertGtkState(state); + + style = widget->style; + TSOffsetStyleGCs(style, rect->x, rect->y); + + /* Always "checkbutton" to match gtkcheckbutton.c */ + gtk_paint_focus(style, drawable, state_type, cliprect, widget, + "checkbutton", + rect->x, rect->y, rect->width, rect->height); + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_toolbar_paint(GdkDrawable* drawable, GdkRectangle* rect, + GdkRectangle* cliprect, GtkTextDirection direction) +{ + GtkStyle* style; + GtkShadowType shadow_type; + + ensure_toolbar_widget(); + gtk_widget_set_direction(gToolbarWidget, direction); + + style = gToolbarWidget->style; + + TSOffsetStyleGCs(style, rect->x, rect->y); + + gtk_style_apply_default_background(style, drawable, TRUE, + GTK_STATE_NORMAL, + cliprect, rect->x, rect->y, + rect->width, rect->height); + + gtk_widget_style_get(gToolbarWidget, "shadow-type", &shadow_type, NULL); + + gtk_paint_box (style, drawable, GTK_STATE_NORMAL, shadow_type, + cliprect, gToolbarWidget, "toolbar", + rect->x, rect->y, rect->width, rect->height); + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_toolbar_separator_paint(GdkDrawable* drawable, GdkRectangle* rect, + GdkRectangle* cliprect, + GtkTextDirection direction) +{ + GtkStyle* style; + gint separator_width = 0; + gint paint_width; + gboolean wide_separators = FALSE; + + /* Defined as constants in GTK+ 2.10.14 */ + const double start_fraction = 0.2; + const double end_fraction = 0.8; + + ensure_toolbar_separator_widget(); + gtk_widget_set_direction(gToolbarSeparatorWidget, direction); + + style = gToolbarSeparatorWidget->style; + + if (have_2_10) + gtk_widget_style_get(gToolbarWidget, + "wide-separators", &wide_separators, + "separator-width", &separator_width, + NULL); + + TSOffsetStyleGCs(style, rect->x, rect->y); + + if (wide_separators) { + if (separator_width > rect->width) + separator_width = rect->width; + + gtk_paint_box(style, drawable, + GTK_STATE_NORMAL, GTK_SHADOW_ETCHED_OUT, + cliprect, gToolbarWidget, "vseparator", + rect->x + (rect->width - separator_width) / 2, + rect->y + rect->height * start_fraction, + separator_width, + rect->height * (end_fraction - start_fraction)); + + } else { + paint_width = style->xthickness; + + if (paint_width > rect->width) + paint_width = rect->width; + + gtk_paint_vline(style, drawable, + GTK_STATE_NORMAL, cliprect, gToolbarSeparatorWidget, + "toolbar", + rect->y + rect->height * start_fraction, + rect->y + rect->height * end_fraction, + rect->x + (rect->width - paint_width) / 2); + } + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_tooltip_paint(GdkDrawable* drawable, GdkRectangle* rect, + GdkRectangle* cliprect, GtkTextDirection direction) +{ + GtkStyle* style; + + ensure_tooltip_widget(); + gtk_widget_set_direction(gTooltipWidget, direction); + + style = gtk_rc_get_style_by_paths(gtk_settings_get_default(), + "gtk-tooltips", "GtkWindow", + GTK_TYPE_WINDOW); + + style = gtk_style_attach(style, gTooltipWidget->window); + TSOffsetStyleGCs(style, rect->x, rect->y); + gtk_paint_flat_box(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_OUT, + cliprect, gTooltipWidget, "tooltip", + rect->x, rect->y, rect->width, rect->height); + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_resizer_paint(GdkDrawable* drawable, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + GtkTextDirection direction) +{ + GtkStyle* style; + GtkStateType state_type = ConvertGtkState(state); + + ensure_window_widget(); + gtk_widget_set_direction(gProtoWindow, direction); + + style = gProtoWindow->style; + + TSOffsetStyleGCs(style, rect->x, rect->y); + + gtk_paint_resize_grip(style, drawable, state_type, cliprect, gProtoWindow, + NULL, (direction == GTK_TEXT_DIR_LTR) ? + GDK_WINDOW_EDGE_SOUTH_EAST : + GDK_WINDOW_EDGE_SOUTH_WEST, + rect->x, rect->y, rect->width, rect->height); + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_frame_paint(GdkDrawable* drawable, GdkRectangle* rect, + GdkRectangle* cliprect, GtkTextDirection direction) +{ + GtkStyle* style; + GtkShadowType shadow_type; + + ensure_frame_widget(); + gtk_widget_set_direction(gFrameWidget, direction); + + style = gFrameWidget->style; + + gtk_widget_style_get(gStatusbarWidget, "shadow-type", &shadow_type, NULL); + + TSOffsetStyleGCs(style, rect->x, rect->y); + gtk_paint_shadow(style, drawable, GTK_STATE_NORMAL, shadow_type, + cliprect, gFrameWidget, "frame", rect->x, rect->y, + rect->width, rect->height); + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_progressbar_paint(GdkDrawable* drawable, GdkRectangle* rect, + GdkRectangle* cliprect, GtkTextDirection direction) +{ + GtkStyle* style; + + ensure_progress_widget(); + gtk_widget_set_direction(gProgressWidget, direction); + + style = gProgressWidget->style; + + TSOffsetStyleGCs(style, rect->x, rect->y); + gtk_paint_box(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_IN, + cliprect, gProgressWidget, "trough", rect->x, rect->y, + rect->width, rect->height); + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_progress_chunk_paint(GdkDrawable* drawable, GdkRectangle* rect, + GdkRectangle* cliprect, GtkTextDirection direction) +{ + GtkStyle* style; + + ensure_progress_widget(); + gtk_widget_set_direction(gProgressWidget, direction); + + style = gProgressWidget->style; + + TSOffsetStyleGCs(style, rect->x, rect->y); + gtk_paint_box(style, drawable, GTK_STATE_PRELIGHT, GTK_SHADOW_OUT, + cliprect, gProgressWidget, "bar", rect->x, rect->y, + rect->width, rect->height); + + return MOZ_GTK_SUCCESS; +} + +gint +moz_gtk_get_tab_thickness(void) +{ + ensure_tab_widget(); + if (YTHICKNESS(gTabWidget->style) < 2) + return 2; /* some themes don't set ythickness correctly */ + + return YTHICKNESS(gTabWidget->style); +} + +static gint +moz_gtk_tab_paint(GdkDrawable* drawable, GdkRectangle* rect, + GdkRectangle* cliprect, GtkTabFlags flags, + GtkTextDirection direction) +{ + /* When the tab isn't selected, we just draw a notebook extension. + * When it is selected, we overwrite the adjacent border of the tabpanel + * touching the tab with a pierced border (called "the gap") to make the + * tab appear physically attached to the tabpanel; see details below. */ + + GtkStyle* style; + + ensure_tab_widget(); + gtk_widget_set_direction(gTabWidget, direction); + + style = gTabWidget->style; + TSOffsetStyleGCs(style, rect->x, rect->y); + + if ((flags & MOZ_GTK_TAB_SELECTED) == 0) { + /* Only draw the tab */ + gtk_paint_extension(style, drawable, GTK_STATE_ACTIVE, GTK_SHADOW_OUT, + cliprect, gTabWidget, "tab", + rect->x, rect->y, rect->width, rect->height, + (flags & MOZ_GTK_TAB_BOTTOM) ? + GTK_POS_TOP : GTK_POS_BOTTOM ); + } else { + /* Draw the tab and the gap + * We want the gap to be positionned exactly on the tabpanel top + * border; since tabbox.css may set a negative margin so that the tab + * frame rect already overlaps the tabpanel frame rect, we need to take + * that into account when drawing. To that effect, nsNativeThemeGTK + * passes us this negative margin (bmargin in the graphic below) in the + * lowest bits of |flags|. We use it to set gap_voffset, the distance + * between the top of the gap and the bottom of the tab (resp. the + * bottom of the gap and the top of the tab when we draw a bottom tab), + * while ensuring that the gap always touches the border of the tab, + * i.e. 0 <= gap_voffset <= gap_height, to avoid surprinsing results + * with big negative or positive margins. + * Here is a graphical explanation in the case of top tabs: + * ___________________________ + * / \ + * | T A B | + * ----------|. . . . . . . . . . . . . . .|----- top of tabpanel + * : ^ bmargin : ^ + * : | (-negative margin, : | + * bottom : v passed in flags) : | gap_height + * of -> :.............................: | (the size of the + * the tab . part of the gap . | tabpanel top border) + * . outside of the tab . v + * ---------------------------------------------- + * + * To draw the gap, we use gtk_paint_box_gap(), see comment in + * moz_gtk_tabpanels_paint(). This box_gap is made 3 * gap_height tall, + * which should suffice to ensure that the only visible border is the + * pierced one. If the tab is in the middle, we make the box_gap begin + * a bit to the left of the tab and end a bit to the right, adjusting + * the gap position so it still is under the tab, because we want the + * rendering of a gap in the middle of a tabpanel. This is the role of + * the gints gap_{l,r}_offset. On the contrary, if the tab is the + * first, we align the start border of the box_gap with the start + * border of the tab (left if LTR, right if RTL), by setting the + * appropriate offset to 0.*/ + gint gap_loffset, gap_roffset, gap_voffset, gap_height; + + /* Get height needed by the gap */ + gap_height = moz_gtk_get_tab_thickness(); + + /* Extract gap_voffset from the first bits of flags */ + gap_voffset = flags & MOZ_GTK_TAB_MARGIN_MASK; + if (gap_voffset > gap_height) + gap_voffset = gap_height; + + /* Set gap_{l,r}_offset to appropriate values */ + gap_loffset = gap_roffset = 20; /* should be enough */ + if (flags & MOZ_GTK_TAB_FIRST) { + if (direction == GTK_TEXT_DIR_RTL) + gap_roffset = 0; + else + gap_loffset = 0; + } + + if (flags & MOZ_GTK_TAB_BOTTOM) { + /* Enlarge the cliprect to have room for the full gap height */ + cliprect->height += gap_height - gap_voffset; + cliprect->y -= gap_height - gap_voffset; + + /* Draw the tab */ + gtk_paint_extension(style, drawable, GTK_STATE_NORMAL, + GTK_SHADOW_OUT, cliprect, gTabWidget, "tab", + rect->x, rect->y + gap_voffset, rect->width, + rect->height - gap_voffset, GTK_POS_TOP); + + /* Draw the gap; erase with background color before painting in + * case theme does not */ + gtk_style_apply_default_background(style, drawable, TRUE, + GTK_STATE_NORMAL, cliprect, + rect->x, + rect->y + gap_voffset + - gap_height, + rect->width, gap_height); + gtk_paint_box_gap(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_OUT, + cliprect, gTabWidget, "notebook", + rect->x - gap_loffset, + rect->y + gap_voffset - 3 * gap_height, + rect->width + gap_loffset + gap_roffset, + 3 * gap_height, GTK_POS_BOTTOM, + gap_loffset, rect->width); + } else { + /* Enlarge the cliprect to have room for the full gap height */ + cliprect->height += gap_height - gap_voffset; + + /* Draw the tab */ + gtk_paint_extension(style, drawable, GTK_STATE_NORMAL, + GTK_SHADOW_OUT, cliprect, gTabWidget, "tab", + rect->x, rect->y, rect->width, + rect->height - gap_voffset, GTK_POS_BOTTOM); + + /* Draw the gap; erase with background color before painting in + * case theme does not */ + gtk_style_apply_default_background(style, drawable, TRUE, + GTK_STATE_NORMAL, cliprect, + rect->x, + rect->y + rect->height + - gap_voffset, + rect->width, gap_height); + gtk_paint_box_gap(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_OUT, + cliprect, gTabWidget, "notebook", + rect->x - gap_loffset, + rect->y + rect->height - gap_voffset, + rect->width + gap_loffset + gap_roffset, + 3 * gap_height, GTK_POS_TOP, + gap_loffset, rect->width); + } + + } + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_tabpanels_paint(GdkDrawable* drawable, GdkRectangle* rect, + GdkRectangle* cliprect, GtkTextDirection direction) +{ + /* We use gtk_paint_box_gap() to draw the tabpanels widget. gtk_paint_box() + * draws an all-purpose box, which a lot of themes render differently. + * A zero-width gap is still visible in most themes, so we hide it to the + * left (10px should be enough) */ + GtkStyle* style; + + ensure_tab_widget(); + gtk_widget_set_direction(gTabWidget, direction); + + style = gTabWidget->style; + + TSOffsetStyleGCs(style, rect->x, rect->y); + gtk_paint_box_gap(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_OUT, + cliprect, gTabWidget, "notebook", rect->x, rect->y, + rect->width, rect->height, + GTK_POS_TOP, -10, 0); + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_tab_scroll_arrow_paint(GdkDrawable* drawable, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + GtkArrowType arrow_type, + GtkTextDirection direction) +{ + GtkStateType state_type = ConvertGtkState(state); + GtkShadowType shadow_type = state->active ? GTK_SHADOW_IN : GTK_SHADOW_OUT; + GtkStyle* style; + gint arrow_size = MIN(rect->width, rect->height); + gint x = rect->x + (rect->width - arrow_size) / 2; + gint y = rect->y + (rect->height - arrow_size) / 2; + + ensure_tab_widget(); + + style = gTabWidget->style; + TSOffsetStyleGCs(style, rect->x, rect->y); + + if (direction == GTK_TEXT_DIR_RTL) { + arrow_type = (arrow_type == GTK_ARROW_LEFT) ? + GTK_ARROW_RIGHT : GTK_ARROW_LEFT; + } + + gtk_paint_arrow(style, drawable, state_type, shadow_type, NULL, + gTabWidget, "notebook", arrow_type, TRUE, + x, y, arrow_size, arrow_size); + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_menu_bar_paint(GdkDrawable* drawable, GdkRectangle* rect, + GdkRectangle* cliprect, GtkTextDirection direction) +{ + GtkStyle* style; + GtkShadowType shadow_type; + ensure_menu_bar_widget(); + gtk_widget_set_direction(gMenuBarWidget, direction); + + gtk_widget_style_get(gMenuBarWidget, "shadow-type", &shadow_type, NULL); + + style = gMenuBarWidget->style; + + TSOffsetStyleGCs(style, rect->x, rect->y); + gtk_style_apply_default_background(style, drawable, TRUE, GTK_STATE_NORMAL, + cliprect, rect->x, rect->y, + rect->width, rect->height); + + gtk_paint_box(style, drawable, GTK_STATE_NORMAL, shadow_type, + cliprect, gMenuBarWidget, "menubar", rect->x, rect->y, + rect->width, rect->height); + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_menu_popup_paint(GdkDrawable* drawable, GdkRectangle* rect, + GdkRectangle* cliprect, GtkTextDirection direction) +{ + GtkStyle* style; + ensure_menu_popup_widget(); + gtk_widget_set_direction(gMenuPopupWidget, direction); + + style = gMenuPopupWidget->style; + + TSOffsetStyleGCs(style, rect->x, rect->y); + gtk_style_apply_default_background(style, drawable, TRUE, GTK_STATE_NORMAL, + cliprect, rect->x, rect->y, + rect->width, rect->height); + gtk_paint_box(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_OUT, + cliprect, gMenuPopupWidget, "menu", + rect->x, rect->y, rect->width, rect->height); + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_menu_separator_paint(GdkDrawable* drawable, GdkRectangle* rect, + GdkRectangle* cliprect, GtkTextDirection direction) +{ + GtkStyle* style; + gboolean wide_separators = FALSE; + gint separator_height = 0; + guint horizontal_padding = 0; + gint paint_height; + + ensure_menu_separator_widget(); + gtk_widget_set_direction(gMenuSeparatorWidget, direction); + + style = gMenuSeparatorWidget->style; + + if (have_2_10) + gtk_widget_style_get(gMenuSeparatorWidget, + "wide-separators", &wide_separators, + "separator-height", &separator_height, + NULL); + + gtk_widget_style_get(gMenuSeparatorWidget, + "horizontal-padding", &horizontal_padding, + NULL); + + TSOffsetStyleGCs(style, rect->x, rect->y); + + if (wide_separators) { + if (separator_height > rect->height) + separator_height = rect->height; + + gtk_paint_box(style, drawable, + GTK_STATE_NORMAL, GTK_SHADOW_ETCHED_OUT, + cliprect, gMenuSeparatorWidget, "hseparator", + rect->x + horizontal_padding + style->xthickness, + rect->y + (rect->height - separator_height - style->ythickness) / 2, + rect->width - 2 * (horizontal_padding + style->xthickness), + separator_height); + } else { + paint_height = style->ythickness; + if (paint_height > rect->height) + paint_height = rect->height; + + gtk_paint_hline(style, drawable, + GTK_STATE_NORMAL, cliprect, gMenuSeparatorWidget, + "menuitem", + rect->x + horizontal_padding + style->xthickness, + rect->x + rect->width - horizontal_padding - style->xthickness - 1, + rect->y + (rect->height - style->ythickness) / 2); + } + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_menu_item_paint(GdkDrawable* drawable, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + gint flags, GtkTextDirection direction) +{ + GtkStyle* style; + GtkShadowType shadow_type; + GtkWidget* item_widget; + + if (state->inHover && !state->disabled) { + if (flags & MOZ_TOPLEVEL_MENU_ITEM) { + ensure_menu_bar_item_widget(); + item_widget = gMenuBarItemWidget; + } else { + ensure_menu_item_widget(); + item_widget = gMenuItemWidget; + } + gtk_widget_set_direction(item_widget, direction); + + style = item_widget->style; + TSOffsetStyleGCs(style, rect->x, rect->y); + + gtk_widget_style_get(item_widget, "selected-shadow-type", + &shadow_type, NULL); + + gtk_paint_box(style, drawable, GTK_STATE_PRELIGHT, shadow_type, + cliprect, item_widget, "menuitem", rect->x, rect->y, + rect->width, rect->height); + } + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_menu_arrow_paint(GdkDrawable* drawable, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + GtkTextDirection direction) +{ + GtkStyle* style; + GtkStateType state_type = ConvertGtkState(state); + + ensure_menu_item_widget(); + gtk_widget_set_direction(gMenuItemWidget, direction); + + style = gMenuItemWidget->style; + + TSOffsetStyleGCs(style, rect->x, rect->y); + gtk_paint_arrow(style, drawable, state_type, + (state_type == GTK_STATE_PRELIGHT) ? GTK_SHADOW_IN : GTK_SHADOW_OUT, + cliprect, gMenuItemWidget, "menuitem", + (direction == GTK_TEXT_DIR_LTR) ? GTK_ARROW_RIGHT : GTK_ARROW_LEFT, + TRUE, rect->x, rect->y, rect->width, rect->height); + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_check_menu_item_paint(GdkDrawable* drawable, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + gboolean checked, gboolean isradio, + GtkTextDirection direction) +{ + GtkStateType state_type = ConvertGtkState(state); + GtkStyle* style; + GtkShadowType shadow_type = (checked)?GTK_SHADOW_IN:GTK_SHADOW_OUT; + gint offset; + gint indicator_size; + gint x, y; + + moz_gtk_menu_item_paint(drawable, rect, cliprect, state, FALSE, direction); + + ensure_check_menu_item_widget(); + gtk_widget_set_direction(gCheckMenuItemWidget, direction); + + gtk_widget_style_get (gCheckMenuItemWidget, + "indicator-size", &indicator_size, + NULL); + + if (checked || GTK_CHECK_MENU_ITEM(gCheckMenuItemWidget)->always_show_toggle) { + style = gCheckMenuItemWidget->style; + + offset = GTK_CONTAINER(gCheckMenuItemWidget)->border_width + + gCheckMenuItemWidget->style->xthickness + 2; + + /* while normally this "3" would be the horizontal-padding style value, passing it to Gecko + as the value of menuitem padding causes problems with dropdowns (bug 406129), so in the menu.css + file this is hardcoded as 3px. Yes it sucks, but we don't really have a choice. */ + x = (direction == GTK_TEXT_DIR_RTL) ? + rect->width - indicator_size - offset - 3: rect->x + offset + 3; + y = rect->y + (rect->height - indicator_size) / 2; + + TSOffsetStyleGCs(style, x, y); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gCheckMenuItemWidget), + checked); + + if (isradio) { + gtk_paint_option(style, drawable, state_type, shadow_type, cliprect, + gCheckMenuItemWidget, "option", + x, y, indicator_size, indicator_size); + } else { + gtk_paint_check(style, drawable, state_type, shadow_type, cliprect, + gCheckMenuItemWidget, "check", + x, y, indicator_size, indicator_size); + } + } + + return MOZ_GTK_SUCCESS; +} + +static gint +moz_gtk_window_paint(GdkDrawable* drawable, GdkRectangle* rect, + GdkRectangle* cliprect, GtkTextDirection direction) +{ + GtkStyle* style; + + ensure_window_widget(); + gtk_widget_set_direction(gProtoWindow, direction); + + style = gProtoWindow->style; + + TSOffsetStyleGCs(style, rect->x, rect->y); + gtk_style_apply_default_background(style, drawable, TRUE, + GTK_STATE_NORMAL, + cliprect, rect->x, rect->y, + rect->width, rect->height); + return MOZ_GTK_SUCCESS; +} + +gint +moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top, + gint* right, gint* bottom, GtkTextDirection direction, + gboolean inhtml) +{ + GtkWidget* w; + + switch (widget) { + case MOZ_GTK_BUTTON: + { + GtkBorder inner_border; + gboolean interior_focus; + gint focus_width, focus_pad; + + ensure_button_widget(); + *left = *top = *right = *bottom = GTK_CONTAINER(gButtonWidget)->border_width; + + /* Don't add this padding in HTML, otherwise the buttons will + become too big and stuff the layout. */ + if (!inhtml) { + moz_gtk_widget_get_focus(gButtonWidget, &interior_focus, &focus_width, &focus_pad); + moz_gtk_button_get_inner_border(gButtonWidget, &inner_border); + *left += focus_width + focus_pad + inner_border.left; + *right += focus_width + focus_pad + inner_border.right; + *top += focus_width + focus_pad + inner_border.top; + *bottom += focus_width + focus_pad + inner_border.bottom; + } + + *left += gButtonWidget->style->xthickness; + *right += gButtonWidget->style->xthickness; + *top += gButtonWidget->style->ythickness; + *bottom += gButtonWidget->style->ythickness; + return MOZ_GTK_SUCCESS; + } + case MOZ_GTK_ENTRY: + ensure_entry_widget(); + w = gEntryWidget; + break; + case MOZ_GTK_TREEVIEW: + ensure_tree_view_widget(); + w = gTreeViewWidget; + break; + case MOZ_GTK_TREE_HEADER_CELL: + { + /* A Tree Header in GTK is just a different styled button + * It must be placed in a TreeView for getting the correct style + * assigned. + * That is why the following code is the same as for MOZ_GTK_BUTTON. + * */ + + GtkBorder inner_border; + gboolean interior_focus; + gint focus_width, focus_pad; + + ensure_tree_header_cell_widget(); + *left = *top = *right = *bottom = GTK_CONTAINER(gTreeHeaderCellWidget)->border_width; + + moz_gtk_widget_get_focus(gTreeHeaderCellWidget, &interior_focus, &focus_width, &focus_pad); + moz_gtk_button_get_inner_border(gTreeHeaderCellWidget, &inner_border); + *left += focus_width + focus_pad + inner_border.left; + *right += focus_width + focus_pad + inner_border.right; + *top += focus_width + focus_pad + inner_border.top; + *bottom += focus_width + focus_pad + inner_border.bottom; + + *left += gTreeHeaderCellWidget->style->xthickness; + *right += gTreeHeaderCellWidget->style->xthickness; + *top += gTreeHeaderCellWidget->style->ythickness; + *bottom += gTreeHeaderCellWidget->style->ythickness; + return MOZ_GTK_SUCCESS; + } + case MOZ_GTK_TREE_HEADER_SORTARROW: + ensure_tree_header_cell_widget(); + w = gTreeHeaderSortArrowWidget; + break; + case MOZ_GTK_DROPDOWN_ENTRY: + ensure_combo_box_entry_widgets(); + w = gComboBoxEntryTextareaWidget; + break; + case MOZ_GTK_DROPDOWN_ARROW: + ensure_combo_box_entry_widgets(); + w = gComboBoxEntryButtonWidget; + break; + case MOZ_GTK_DROPDOWN: + { + /* We need to account for the arrow on the dropdown, so text + * doesn't come too close to the arrow, or in some cases spill + * into the arrow. */ + gboolean ignored_interior_focus, wide_separators = FALSE; + gint focus_width, focus_pad, separator_width; + GtkRequisition arrow_req; + + ensure_combo_box_widgets(); + + *left = GTK_CONTAINER(gComboBoxButtonWidget)->border_width; + + if (!inhtml) { + moz_gtk_widget_get_focus(gComboBoxButtonWidget, + &ignored_interior_focus, + &focus_width, &focus_pad); + *left += focus_width + focus_pad; + } + + *top = *left + gComboBoxButtonWidget->style->ythickness; + *left += gComboBoxButtonWidget->style->xthickness; + + *right = *left; *bottom = *top; + + /* If there is no separator, don't try to count its width. */ + separator_width = 0; + if (gComboBoxSeparatorWidget) { + if (have_2_10) + gtk_widget_style_get(gComboBoxSeparatorWidget, + "wide-separators", &wide_separators, + "separator-width", &separator_width, + NULL); + + if (!wide_separators) + separator_width = + XTHICKNESS(gComboBoxSeparatorWidget->style); + } + + gtk_widget_size_request(gComboBoxArrowWidget, &arrow_req); + + if (direction == GTK_TEXT_DIR_RTL) + *left += separator_width + arrow_req.width; + else + *right += separator_width + arrow_req.width; + + return MOZ_GTK_SUCCESS; + } + case MOZ_GTK_TABPANELS: + ensure_tab_widget(); + w = gTabWidget; + break; + case MOZ_GTK_PROGRESSBAR: + ensure_progress_widget(); + w = gProgressWidget; + break; + case MOZ_GTK_SPINBUTTON_ENTRY: + case MOZ_GTK_SPINBUTTON_UP: + case MOZ_GTK_SPINBUTTON_DOWN: + ensure_spin_widget(); + w = gSpinWidget; + break; + case MOZ_GTK_SCALE_HORIZONTAL: + ensure_scale_widget(); + w = gHScaleWidget; + break; + case MOZ_GTK_SCALE_VERTICAL: + ensure_scale_widget(); + w = gVScaleWidget; + break; + case MOZ_GTK_FRAME: + ensure_frame_widget(); + w = gFrameWidget; + break; + case MOZ_GTK_CHECKBUTTON_LABEL: + case MOZ_GTK_RADIOBUTTON_LABEL: + { + gboolean interior_focus; + gint focus_width, focus_pad; + + /* If the focus is interior, then the label has a border of + (focus_width + focus_pad). */ + if (widget == MOZ_GTK_CHECKBUTTON_LABEL) { + ensure_checkbox_widget(); + moz_gtk_widget_get_focus(gCheckboxWidget, &interior_focus, + &focus_width, &focus_pad); + } + else { + ensure_radiobutton_widget(); + moz_gtk_widget_get_focus(gRadiobuttonWidget, &interior_focus, + &focus_width, &focus_pad); + } + + if (interior_focus) + *left = *top = *right = *bottom = (focus_width + focus_pad); + else + *left = *top = *right = *bottom = 0; + + return MOZ_GTK_SUCCESS; + } + + case MOZ_GTK_CHECKBUTTON_CONTAINER: + case MOZ_GTK_RADIOBUTTON_CONTAINER: + { + gboolean interior_focus; + gint focus_width, focus_pad; + + /* If the focus is _not_ interior, then the container has a border + of (focus_width + focus_pad). */ + if (widget == MOZ_GTK_CHECKBUTTON_CONTAINER) { + ensure_checkbox_widget(); + moz_gtk_widget_get_focus(gCheckboxWidget, &interior_focus, + &focus_width, &focus_pad); + w = gCheckboxWidget; + } else { + ensure_radiobutton_widget(); + moz_gtk_widget_get_focus(gRadiobuttonWidget, &interior_focus, + &focus_width, &focus_pad); + w = gRadiobuttonWidget; + } + + *left = *top = *right = *bottom = GTK_CONTAINER(w)->border_width; + + if (!interior_focus) { + *left += (focus_width + focus_pad); + *right += (focus_width + focus_pad); + *top += (focus_width + focus_pad); + *bottom += (focus_width + focus_pad); + } + + return MOZ_GTK_SUCCESS; + } + case MOZ_GTK_MENUPOPUP: + ensure_menu_popup_widget(); + w = gMenuPopupWidget; + break; + case MOZ_GTK_MENUITEM: + ensure_menu_item_widget(); + ensure_menu_bar_item_widget(); + w = gMenuItemWidget; + break; + case MOZ_GTK_CHECKMENUITEM: + case MOZ_GTK_RADIOMENUITEM: + ensure_check_menu_item_widget(); + w = gCheckMenuItemWidget; + break; + case MOZ_GTK_TAB: + ensure_tab_widget(); + w = gTabWidget; + break; + /* These widgets have no borders, since they are not containers. */ + case MOZ_GTK_SPLITTER_HORIZONTAL: + case MOZ_GTK_SPLITTER_VERTICAL: + case MOZ_GTK_CHECKBUTTON: + case MOZ_GTK_RADIOBUTTON: + case MOZ_GTK_SCROLLBAR_BUTTON: + case MOZ_GTK_SCROLLBAR_TRACK_HORIZONTAL: + case MOZ_GTK_SCROLLBAR_TRACK_VERTICAL: + case MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL: + case MOZ_GTK_SCROLLBAR_THUMB_VERTICAL: + case MOZ_GTK_SCALE_THUMB_HORIZONTAL: + case MOZ_GTK_SCALE_THUMB_VERTICAL: + case MOZ_GTK_GRIPPER: + case MOZ_GTK_PROGRESS_CHUNK: + case MOZ_GTK_EXPANDER: + case MOZ_GTK_TREEVIEW_EXPANDER: + case MOZ_GTK_TOOLBAR_SEPARATOR: + case MOZ_GTK_MENUSEPARATOR: + /* These widgets have no borders.*/ + case MOZ_GTK_SPINBUTTON: + case MOZ_GTK_TOOLTIP: + case MOZ_GTK_WINDOW: + case MOZ_GTK_RESIZER: + case MOZ_GTK_MENUARROW: + case MOZ_GTK_TOOLBARBUTTON_ARROW: + case MOZ_GTK_TOOLBAR: + case MOZ_GTK_MENUBAR: + case MOZ_GTK_TAB_SCROLLARROW: + case MOZ_GTK_ENTRY_CARET: + *left = *top = *right = *bottom = 0; + return MOZ_GTK_SUCCESS; + default: + g_warning("Unsupported widget type: %d", widget); + return MOZ_GTK_UNKNOWN_WIDGET; + } + + *right = *left = XTHICKNESS(w->style); + *bottom = *top = YTHICKNESS(w->style); + + return MOZ_GTK_SUCCESS; +} + +gint +moz_gtk_get_combo_box_entry_button_size(gint* width, gint* height) +{ + /* + * We get the requisition of the drop down button, which includes + * all padding, border and focus line widths the button uses, + * as well as the minimum arrow size and its padding + * */ + GtkRequisition requisition; + ensure_combo_box_entry_widgets(); + + gtk_widget_size_request(gComboBoxEntryButtonWidget, &requisition); + *width = requisition.width; + *height = requisition.height; + + return MOZ_GTK_SUCCESS; +} + +gint +moz_gtk_get_tab_scroll_arrow_size(gint* width, gint* height) +{ + gint arrow_size = 16; + + ensure_tab_widget(); + if (have_2_10) + gtk_widget_style_get(gTabWidget, + "scroll-arrow-hlength", &arrow_size, + NULL); + + *height = *width = arrow_size; + + return MOZ_GTK_SUCCESS; +} + +gint +moz_gtk_get_downarrow_size(gint* width, gint* height) +{ + GtkRequisition requisition; + ensure_button_arrow_widget(); + + gtk_widget_size_request(gButtonArrowWidget, &requisition); + *width = requisition.width; + *height = requisition.height; + + return MOZ_GTK_SUCCESS; +} + +gint +moz_gtk_get_toolbar_separator_width(gint* size) +{ + gboolean wide_separators = FALSE; + gint separator_width = 0; + GtkStyle* style; + + ensure_toolbar_widget(); + + style = gToolbarWidget->style; + + if (have_2_10) + gtk_widget_style_get(gToolbarWidget, + "wide-separators", &wide_separators, + "separator-width", &separator_width, + NULL); + + gtk_widget_style_get(gToolbarWidget, + "space-size", size, + NULL); + + /* Just in case... */ + *size = MAX(*size, (wide_separators ? separator_width : style->xthickness)); + + return MOZ_GTK_SUCCESS; +} + +gint +moz_gtk_get_expander_size(gint* size) +{ + ensure_expander_widget(); + gtk_widget_style_get(gExpanderWidget, + "expander-size", size, + NULL); + + return MOZ_GTK_SUCCESS; +} + +gint +moz_gtk_get_treeview_expander_size(gint* size) +{ + ensure_tree_view_widget(); + gtk_widget_style_get(gTreeViewWidget, + "expander-size", size, + NULL); + + return MOZ_GTK_SUCCESS; +} + +gint +moz_gtk_get_menu_separator_height(gint *size) +{ + gboolean wide_separators = FALSE; + gint separator_height = 0; + + ensure_menu_separator_widget(); + + if (have_2_10) + gtk_widget_style_get(gMenuSeparatorWidget, + "wide-separators", &wide_separators, + "separator-height", &separator_height, + NULL); + + if (wide_separators) + *size = separator_height + gMenuSeparatorWidget->style->ythickness; + else + *size = gMenuSeparatorWidget->style->ythickness * 2; + + return MOZ_GTK_SUCCESS; +} + +gint +moz_gtk_get_scalethumb_metrics(GtkOrientation orient, gint* thumb_length, gint* thumb_height) +{ + GtkWidget* widget; + + ensure_scale_widget(); + widget = ((orient == GTK_ORIENTATION_HORIZONTAL) ? gHScaleWidget : gVScaleWidget); + + gtk_widget_style_get (widget, + "slider_length", thumb_length, + "slider_width", thumb_height, + NULL); + + return MOZ_GTK_SUCCESS; +} + +gint +moz_gtk_get_scrollbar_metrics(MozGtkScrollbarMetrics *metrics) +{ + ensure_scrollbar_widget(); + + gtk_widget_style_get (gHorizScrollbarWidget, + "slider_width", &metrics->slider_width, + "trough_border", &metrics->trough_border, + "stepper_size", &metrics->stepper_size, + "stepper_spacing", &metrics->stepper_spacing, + NULL); + + metrics->min_slider_size = + GTK_RANGE(gHorizScrollbarWidget)->min_slider_size; + + return MOZ_GTK_SUCCESS; +} + +gboolean +moz_gtk_images_in_menus() +{ + gboolean result; + GtkSettings* settings; + + ensure_image_menu_item_widget(); + settings = gtk_widget_get_settings(gImageMenuItemWidget); + + g_object_get(settings, "gtk-menu-images", &result, NULL); + return result; +} + +gint +moz_gtk_widget_paint(GtkThemeWidgetType widget, GdkDrawable* drawable, + GdkRectangle* rect, GdkRectangle* cliprect, + GtkWidgetState* state, gint flags, + GtkTextDirection direction) +{ + switch (widget) { + case MOZ_GTK_BUTTON: + if (state->depressed) { + ensure_toggle_button_widget(); + return moz_gtk_button_paint(drawable, rect, cliprect, state, + (GtkReliefStyle) flags, + gToggleButtonWidget, direction); + } + ensure_button_widget(); + return moz_gtk_button_paint(drawable, rect, cliprect, state, + (GtkReliefStyle) flags, gButtonWidget, + direction); + break; + case MOZ_GTK_CHECKBUTTON: + case MOZ_GTK_RADIOBUTTON: + return moz_gtk_toggle_paint(drawable, rect, cliprect, state, + (gboolean) flags, + (widget == MOZ_GTK_RADIOBUTTON), + direction); + break; + case MOZ_GTK_SCROLLBAR_BUTTON: + return moz_gtk_scrollbar_button_paint(drawable, rect, cliprect, state, + (GtkScrollbarButtonFlags) flags, + direction); + break; + case MOZ_GTK_SCROLLBAR_TRACK_HORIZONTAL: + case MOZ_GTK_SCROLLBAR_TRACK_VERTICAL: + return moz_gtk_scrollbar_trough_paint(widget, drawable, rect, + cliprect, state, direction); + break; + case MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL: + case MOZ_GTK_SCROLLBAR_THUMB_VERTICAL: + return moz_gtk_scrollbar_thumb_paint(widget, drawable, rect, + cliprect, state, direction); + break; + case MOZ_GTK_SCALE_HORIZONTAL: + case MOZ_GTK_SCALE_VERTICAL: + return moz_gtk_scale_paint(drawable, rect, cliprect, state, + (GtkOrientation) flags, direction); + break; + case MOZ_GTK_SCALE_THUMB_HORIZONTAL: + case MOZ_GTK_SCALE_THUMB_VERTICAL: + return moz_gtk_scale_thumb_paint(drawable, rect, cliprect, state, + (GtkOrientation) flags, direction); + break; + case MOZ_GTK_SPINBUTTON: + return moz_gtk_spin_paint(drawable, rect, direction); + break; + case MOZ_GTK_SPINBUTTON_UP: + case MOZ_GTK_SPINBUTTON_DOWN: + return moz_gtk_spin_updown_paint(drawable, rect, + (widget == MOZ_GTK_SPINBUTTON_DOWN), + state, direction); + break; + case MOZ_GTK_SPINBUTTON_ENTRY: + ensure_spin_widget(); + return moz_gtk_entry_paint(drawable, rect, cliprect, state, + gSpinWidget, direction); + break; + case MOZ_GTK_GRIPPER: + return moz_gtk_gripper_paint(drawable, rect, cliprect, state, + direction); + break; + case MOZ_GTK_TREEVIEW: + return moz_gtk_treeview_paint(drawable, rect, cliprect, state, + direction); + break; + case MOZ_GTK_TREE_HEADER_CELL: + return moz_gtk_tree_header_cell_paint(drawable, rect, cliprect, state, + flags, direction); + break; + case MOZ_GTK_TREE_HEADER_SORTARROW: + return moz_gtk_tree_header_sort_arrow_paint(drawable, rect, cliprect, + state, + (GtkArrowType) flags, + direction); + break; + case MOZ_GTK_TREEVIEW_EXPANDER: + return moz_gtk_treeview_expander_paint(drawable, rect, cliprect, state, + (GtkExpanderStyle) flags, direction); + break; + case MOZ_GTK_EXPANDER: + return moz_gtk_expander_paint(drawable, rect, cliprect, state, + (GtkExpanderStyle) flags, direction); + break; + case MOZ_GTK_ENTRY: + ensure_entry_widget(); + return moz_gtk_entry_paint(drawable, rect, cliprect, state, + gEntryWidget, direction); + break; + case MOZ_GTK_ENTRY_CARET: + return moz_gtk_caret_paint(drawable, rect, cliprect, direction); + break; + case MOZ_GTK_DROPDOWN: + return moz_gtk_combo_box_paint(drawable, rect, cliprect, state, + (gboolean) flags, direction); + break; + case MOZ_GTK_DROPDOWN_ARROW: + return moz_gtk_combo_box_entry_button_paint(drawable, rect, cliprect, + state, flags, direction); + break; + case MOZ_GTK_DROPDOWN_ENTRY: + ensure_combo_box_entry_widgets(); + return moz_gtk_entry_paint(drawable, rect, cliprect, state, + gComboBoxEntryTextareaWidget, direction); + break; + case MOZ_GTK_CHECKBUTTON_CONTAINER: + case MOZ_GTK_RADIOBUTTON_CONTAINER: + return moz_gtk_container_paint(drawable, rect, cliprect, state, + (widget == MOZ_GTK_RADIOBUTTON_CONTAINER), + direction); + break; + case MOZ_GTK_CHECKBUTTON_LABEL: + case MOZ_GTK_RADIOBUTTON_LABEL: + return moz_gtk_toggle_label_paint(drawable, rect, cliprect, state, + (widget == MOZ_GTK_RADIOBUTTON_LABEL), + direction); + break; + case MOZ_GTK_TOOLBAR: + return moz_gtk_toolbar_paint(drawable, rect, cliprect, direction); + break; + case MOZ_GTK_TOOLBAR_SEPARATOR: + return moz_gtk_toolbar_separator_paint(drawable, rect, cliprect, + direction); + break; + case MOZ_GTK_TOOLTIP: + return moz_gtk_tooltip_paint(drawable, rect, cliprect, direction); + break; + case MOZ_GTK_FRAME: + return moz_gtk_frame_paint(drawable, rect, cliprect, direction); + break; + case MOZ_GTK_RESIZER: + return moz_gtk_resizer_paint(drawable, rect, cliprect, state, + direction); + break; + case MOZ_GTK_PROGRESSBAR: + return moz_gtk_progressbar_paint(drawable, rect, cliprect, direction); + break; + case MOZ_GTK_PROGRESS_CHUNK: + return moz_gtk_progress_chunk_paint(drawable, rect, cliprect, + direction); + break; + case MOZ_GTK_TAB: + return moz_gtk_tab_paint(drawable, rect, cliprect, + (GtkTabFlags) flags, direction); + break; + case MOZ_GTK_TABPANELS: + return moz_gtk_tabpanels_paint(drawable, rect, cliprect, direction); + break; + case MOZ_GTK_TAB_SCROLLARROW: + return moz_gtk_tab_scroll_arrow_paint(drawable, rect, cliprect, state, + (GtkArrowType) flags, direction); + break; + case MOZ_GTK_MENUBAR: + return moz_gtk_menu_bar_paint(drawable, rect, cliprect, direction); + break; + case MOZ_GTK_MENUPOPUP: + return moz_gtk_menu_popup_paint(drawable, rect, cliprect, direction); + break; + case MOZ_GTK_MENUSEPARATOR: + return moz_gtk_menu_separator_paint(drawable, rect, cliprect, + direction); + break; + case MOZ_GTK_MENUITEM: + return moz_gtk_menu_item_paint(drawable, rect, cliprect, state, flags, + direction); + break; + case MOZ_GTK_MENUARROW: + return moz_gtk_menu_arrow_paint(drawable, rect, cliprect, state, + direction); + break; + case MOZ_GTK_TOOLBARBUTTON_ARROW: + return moz_gtk_downarrow_paint(drawable, rect, cliprect, state); + break; + case MOZ_GTK_CHECKMENUITEM: + case MOZ_GTK_RADIOMENUITEM: + return moz_gtk_check_menu_item_paint(drawable, rect, cliprect, state, + (gboolean) flags, + (widget == MOZ_GTK_RADIOMENUITEM), + direction); + break; + case MOZ_GTK_SPLITTER_HORIZONTAL: + return moz_gtk_vpaned_paint(drawable, rect, cliprect, state); + break; + case MOZ_GTK_SPLITTER_VERTICAL: + return moz_gtk_hpaned_paint(drawable, rect, cliprect, state); + break; + case MOZ_GTK_WINDOW: + return moz_gtk_window_paint(drawable, rect, cliprect, direction); + break; + default: + g_warning("Unknown widget type: %d", widget); + } + + return MOZ_GTK_UNKNOWN_WIDGET; +} + +GtkWidget* moz_gtk_get_scrollbar_widget(void) +{ + if (!is_initialized) + return NULL; + ensure_scrollbar_widget(); + return gHorizScrollbarWidget; +} + +gint +moz_gtk_shutdown() +{ + GtkWidgetClass *entry_class; + + if (gTooltipWidget) + gtk_widget_destroy(gTooltipWidget); + /* This will destroy all of our widgets */ + if (gProtoWindow) + gtk_widget_destroy(gProtoWindow); + + gProtoWindow = NULL; + gButtonWidget = NULL; + gToggleButtonWidget = NULL; + gButtonArrowWidget = NULL; + gCheckboxWidget = NULL; + gRadiobuttonWidget = NULL; + gHorizScrollbarWidget = NULL; + gVertScrollbarWidget = NULL; + gSpinWidget = NULL; + gHScaleWidget = NULL; + gVScaleWidget = NULL; + gEntryWidget = NULL; + gComboBoxWidget = NULL; + gComboBoxButtonWidget = NULL; + gComboBoxSeparatorWidget = NULL; + gComboBoxArrowWidget = NULL; + gComboBoxEntryWidget = NULL; + gComboBoxEntryButtonWidget = NULL; + gComboBoxEntryArrowWidget = NULL; + gComboBoxEntryTextareaWidget = NULL; + gHandleBoxWidget = NULL; + gToolbarWidget = NULL; + gStatusbarWidget = NULL; + gFrameWidget = NULL; + gProgressWidget = NULL; + gTabWidget = NULL; + gTooltipWidget = NULL; + gMenuBarWidget = NULL; + gMenuBarItemWidget = NULL; + gMenuPopupWidget = NULL; + gMenuItemWidget = NULL; + gImageMenuItemWidget = NULL; + gCheckMenuItemWidget = NULL; + gTreeViewWidget = NULL; + gMiddleTreeViewColumn = NULL; + gTreeHeaderCellWidget = NULL; + gTreeHeaderSortArrowWidget = NULL; + gExpanderWidget = NULL; + gToolbarSeparatorWidget = NULL; + gMenuSeparatorWidget = NULL; + gHPanedWidget = NULL; + gVPanedWidget = NULL; + gScrolledWindowWidget = NULL; + + entry_class = g_type_class_peek(GTK_TYPE_ENTRY); + g_type_class_unref(entry_class); + + is_initialized = FALSE; + + return MOZ_GTK_SUCCESS; +} diff --git a/WebCore/platform/gtk/gtkdrawing.h b/WebCore/platform/gtk/gtkdrawing.h new file mode 100644 index 0000000..6e44d4a --- /dev/null +++ b/WebCore/platform/gtk/gtkdrawing.h @@ -0,0 +1,428 @@ +/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brian Ryner <bryner@brianryner.com> (Original Author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/** + * gtkdrawing.h: GTK widget rendering utilities + * + * gtkdrawing provides an API for rendering GTK widgets in the + * current theme to a pixmap or window, without requiring an actual + * widget instantiation, similar to the Macintosh Appearance Manager + * or Windows XP's DrawThemeBackground() API. + */ + +#ifndef _GTK_DRAWING_H_ +#define _GTK_DRAWING_H_ + +#include <gdk/gdk.h> +#include <gtk/gtkstyle.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/*** type definitions ***/ +typedef struct { + guint8 active; + guint8 focused; + guint8 inHover; + guint8 disabled; + guint8 isDefault; + guint8 canDefault; + /* The depressed state is for buttons which remain active for a longer period: + * activated toggle buttons or buttons showing a popup menu. */ + guint8 depressed; + gint32 curpos; /* curpos and maxpos are used for scrollbars */ + gint32 maxpos; +} GtkWidgetState; + +typedef struct { + gint slider_width; + gint trough_border; + gint stepper_size; + gint stepper_spacing; + gint min_slider_size; +} MozGtkScrollbarMetrics; + +typedef enum { + MOZ_GTK_STEPPER_DOWN = 1 << 0, + MOZ_GTK_STEPPER_BOTTOM = 1 << 1, + MOZ_GTK_STEPPER_VERTICAL = 1 << 2 +} GtkScrollbarButtonFlags; + +/** flags for tab state **/ +typedef enum { + /* first eight bits are used to pass a margin */ + MOZ_GTK_TAB_MARGIN_MASK = 0xFF, + /* bottom tabs */ + MOZ_GTK_TAB_BOTTOM = 1 << 8, + /* the first tab in the group */ + MOZ_GTK_TAB_FIRST = 1 << 9, + /* the selected tab */ + MOZ_GTK_TAB_SELECTED = 1 << 10 +} GtkTabFlags; + +/** flags for menuitems **/ +typedef enum { + /* menuitem is part of the menubar */ + MOZ_TOPLEVEL_MENU_ITEM = 1 << 0 +} GtkMenuItemFlags; + +/* function type for moz_gtk_enable_style_props */ +typedef gint (*style_prop_t)(GtkStyle*, const gchar*, gint); + +/*** result/error codes ***/ +#define MOZ_GTK_SUCCESS 0 +#define MOZ_GTK_UNKNOWN_WIDGET -1 +#define MOZ_GTK_UNSAFE_THEME -2 + +/*** widget type constants ***/ +typedef enum { + /* Paints a GtkButton. flags is a GtkReliefStyle. */ + MOZ_GTK_BUTTON, + /* Paints a GtkCheckButton. flags is a boolean, 1=checked, 0=not checked. */ + MOZ_GTK_CHECKBUTTON, + /* Paints a GtkRadioButton. flags is a boolean, 1=checked, 0=not checked. */ + MOZ_GTK_RADIOBUTTON, + /** + * Paints the button of a GtkScrollbar. flags is a GtkArrowType giving + * the arrow direction. + */ + MOZ_GTK_SCROLLBAR_BUTTON, + /* Paints the trough (track) of a GtkScrollbar. */ + MOZ_GTK_SCROLLBAR_TRACK_HORIZONTAL, + MOZ_GTK_SCROLLBAR_TRACK_VERTICAL, + /* Paints the slider (thumb) of a GtkScrollbar. */ + MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL, + MOZ_GTK_SCROLLBAR_THUMB_VERTICAL, + /* Paints a GtkScale. */ + MOZ_GTK_SCALE_HORIZONTAL, + MOZ_GTK_SCALE_VERTICAL, + /* Paints a GtkScale thumb. */ + MOZ_GTK_SCALE_THUMB_HORIZONTAL, + MOZ_GTK_SCALE_THUMB_VERTICAL, + /* Paints a GtkSpinButton */ + MOZ_GTK_SPINBUTTON, + MOZ_GTK_SPINBUTTON_UP, + MOZ_GTK_SPINBUTTON_DOWN, + MOZ_GTK_SPINBUTTON_ENTRY, + /* Paints the gripper of a GtkHandleBox. */ + MOZ_GTK_GRIPPER, + /* Paints a GtkEntry. */ + MOZ_GTK_ENTRY, + /* Paints the native caret (or in GTK-speak: insertion cursor) */ + MOZ_GTK_ENTRY_CARET, + /* Paints a GtkOptionMenu. */ + MOZ_GTK_DROPDOWN, + /* Paints a dropdown arrow (a GtkButton containing a down GtkArrow). */ + MOZ_GTK_DROPDOWN_ARROW, + /* Paints an entry in an editable option menu */ + MOZ_GTK_DROPDOWN_ENTRY, + /* Paints the container part of a GtkCheckButton. */ + MOZ_GTK_CHECKBUTTON_CONTAINER, + /* Paints the container part of a GtkRadioButton. */ + MOZ_GTK_RADIOBUTTON_CONTAINER, + /* Paints the label of a GtkCheckButton (focus outline) */ + MOZ_GTK_CHECKBUTTON_LABEL, + /* Paints the label of a GtkRadioButton (focus outline) */ + MOZ_GTK_RADIOBUTTON_LABEL, + /* Paints the background of a GtkHandleBox. */ + MOZ_GTK_TOOLBAR, + /* Paints a toolbar separator */ + MOZ_GTK_TOOLBAR_SEPARATOR, + /* Paints a GtkToolTip */ + MOZ_GTK_TOOLTIP, + /* Paints a GtkFrame (e.g. a status bar panel). */ + MOZ_GTK_FRAME, + /* Paints a resize grip for a GtkWindow */ + MOZ_GTK_RESIZER, + /* Paints a GtkProgressBar. */ + MOZ_GTK_PROGRESSBAR, + /* Paints a progress chunk of a GtkProgressBar. */ + MOZ_GTK_PROGRESS_CHUNK, + /* Paints a tab of a GtkNotebook. flags is a GtkTabFlags, defined above. */ + MOZ_GTK_TAB, + /* Paints the background and border of a GtkNotebook. */ + MOZ_GTK_TABPANELS, + /* Paints a GtkArrow for a GtkNotebook. flags is a GtkArrowType. */ + MOZ_GTK_TAB_SCROLLARROW, + /* Paints the background and border of a GtkTreeView */ + MOZ_GTK_TREEVIEW, + /* Paints treeheader cells */ + MOZ_GTK_TREE_HEADER_CELL, + /* Paints sort arrows in treeheader cells */ + MOZ_GTK_TREE_HEADER_SORTARROW, + /* Paints an expander for a GtkTreeView */ + MOZ_GTK_TREEVIEW_EXPANDER, + /* Paints a GtkExpander */ + MOZ_GTK_EXPANDER, + /* Paints the background of the menu bar. */ + MOZ_GTK_MENUBAR, + /* Paints the background of menus, context menus. */ + MOZ_GTK_MENUPOPUP, + /* Paints the arrow of menuitems that contain submenus */ + MOZ_GTK_MENUARROW, + /* Paints an arrow that points down */ + MOZ_GTK_TOOLBARBUTTON_ARROW, + /* Paints items of menubar and popups. */ + MOZ_GTK_MENUITEM, + MOZ_GTK_CHECKMENUITEM, + MOZ_GTK_RADIOMENUITEM, + MOZ_GTK_MENUSEPARATOR, + /* Paints a GtkVPaned separator */ + MOZ_GTK_SPLITTER_HORIZONTAL, + /* Paints a GtkHPaned separator */ + MOZ_GTK_SPLITTER_VERTICAL, + /* Paints the background of a window, dialog or page. */ + MOZ_GTK_WINDOW +} GtkThemeWidgetType; + +/*** General library functions ***/ +/** + * Initializes the drawing library. You must call this function + * prior to using any other functionality. + * returns: MOZ_GTK_SUCCESS if there were no errors + * MOZ_GTK_UNSAFE_THEME if the current theme engine is known + * to crash with gtkdrawing. + */ +gint moz_gtk_init(); + +/** + * Enable GTK+ 1.2.9+ theme enhancements. You must provide a pointer + * to the GTK+ 1.2.9+ function "gtk_style_get_prop_experimental". + * styleGetProp: pointer to gtk_style_get_prop_experimental + * + * returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise + */ +gint moz_gtk_enable_style_props(style_prop_t styleGetProp); + +/** + * Perform cleanup of the drawing library. You should call this function + * when your program exits, or you no longer need the library. + * + * returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise + */ +gint moz_gtk_shutdown(); + + +/*** Widget drawing ***/ +/** + * Paint a widget in the current theme. + * widget: a constant giving the widget to paint + * rect: the bounding rectangle for the widget + * cliprect: a clipprect rectangle for this painting operation + * state: the state of the widget. ignored for some widgets. + * flags: widget-dependant flags; see the GtkThemeWidgetType definition. + * direction: the text direction, to draw the widget correctly LTR and RTL. + */ +gint +moz_gtk_widget_paint(GtkThemeWidgetType widget, GdkDrawable* drawable, + GdkRectangle* rect, GdkRectangle* cliprect, + GtkWidgetState* state, gint flags, + GtkTextDirection direction); + + +/*** Widget metrics ***/ +/** + * Get the border size of a widget + * left/right: [OUT] the widget's left/right border + * top/bottom: [OUT] the widget's top/bottom border + * direction: the text direction for the widget + * inhtml: boolean indicating whether this widget will be drawn as a HTML form control, + * in order to workaround a size issue (MOZ_GTK_BUTTON only, ignored otherwise) + * + * returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise + */ +gint moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top, + gint* right, gint* bottom, GtkTextDirection direction, + gboolean inhtml); + +/** + * Get the desired size of a GtkCheckButton + * indicator_size: [OUT] the indicator size + * indicator_spacing: [OUT] the spacing between the indicator and its + * container + * + * returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise + */ +gint +moz_gtk_checkbox_get_metrics(gint* indicator_size, gint* indicator_spacing); + +/** + * Get the desired size of a GtkRadioButton + * indicator_size: [OUT] the indicator size + * indicator_spacing: [OUT] the spacing between the indicator and its + * container + * + * returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise + */ +gint +moz_gtk_radio_get_metrics(gint* indicator_size, gint* indicator_spacing); + +/** + * Get the inner-border value for a GtkButton widget (button or tree header) + * widget: [IN] the widget to get the border value for + * inner_border: [OUT] the inner border + * + * returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise + */ +gint +moz_gtk_button_get_inner_border(GtkWidget* widget, GtkBorder* inner_border); + +/** Get the focus metrics for a treeheadercell, button, checkbox, or radio button. + * widget: [IN] the widget to get the focus metrics for + * interior_focus: [OUT] whether the focus is drawn around the + * label (TRUE) or around the whole container (FALSE) + * focus_width: [OUT] the width of the focus line + * focus_pad: [OUT] the padding between the focus line and children + * + * returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise + */ +gint +moz_gtk_widget_get_focus(GtkWidget* widget, gboolean* interior_focus, + gint* focus_width, gint* focus_pad); + +/** + * Get the desired size of a GtkScale thumb + * orient: [IN] the scale orientation + * thumb_length: [OUT] the length of the thumb + * thumb_height: [OUT] the height of the thumb + * + * returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise + */ +gint +moz_gtk_get_scalethumb_metrics(GtkOrientation orient, gint* thumb_length, gint* thumb_height); + +/** + * Get the desired metrics for a GtkScrollbar + * metrics: [IN] struct which will contain the metrics + * + * returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise + */ +gint +moz_gtk_get_scrollbar_metrics(MozGtkScrollbarMetrics* metrics); + +/** + * Get the desired size of a dropdown arrow button + * width: [OUT] the desired width + * height: [OUT] the desired height + * + * returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise + */ +gint moz_gtk_get_combo_box_entry_button_size(gint* width, gint* height); + +/** + * Get the desired size of a scroll arrow widget + * width: [OUT] the desired width + * height: [OUT] the desired height + * + * returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise + */ +gint moz_gtk_get_tab_scroll_arrow_size(gint* width, gint* height); + +/** + * Get the desired size of a toolbar button dropdown arrow + * width: [OUT] the desired width + * height: [OUT] the desired height + * + * returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise + */ +gint moz_gtk_get_downarrow_size(gint* width, gint* height); + +/** + * Get the desired size of a toolbar separator + * size: [OUT] the desired width + * + * returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise + */ +gint moz_gtk_get_toolbar_separator_width(gint* size); + +/** + * Get the size of a regular GTK expander that shows/hides content + * size: [OUT] the size of the GTK expander, size = width = height. + * + * returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise + */ +gint moz_gtk_get_expander_size(gint* size); + +/** + * Get the size of a treeview's expander (we call them twisties) + * size: [OUT] the size of the GTK expander, size = width = height. + * + * returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise + */ +gint moz_gtk_get_treeview_expander_size(gint* size); + +/** + * Get the desired height of a menu separator + * size: [OUT] the desired height + * + * returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise + */ +gint moz_gtk_get_menu_separator_height(gint* size); + +/** + * Get the desired size of a splitter + * orientation: [IN] GTK_ORIENTATION_HORIZONTAL or GTK_ORIENTATION_VERTICAL + * size: [OUT] width or height of the splitter handle + * + * returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise + */ +gint moz_gtk_splitter_get_metrics(gint orientation, gint* size); + +/** + * Retrieve an actual GTK scrollbar widget for style analysis. It will not + * be modified. + */ +GtkWidget* moz_gtk_get_scrollbar_widget(void); + +/** + * Get the YTHICKNESS of a tab (notebook extension). + */ +gint moz_gtk_get_tab_thickness(void); + +/** + * Get a boolean which indicates whether or not to use images in menus. + * If TRUE, use images in menus. + */ +gboolean moz_gtk_images_in_menus(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/WebCore/platform/gtk/guriescape.c b/WebCore/platform/gtk/guriescape.c new file mode 100644 index 0000000..0792587 --- /dev/null +++ b/WebCore/platform/gtk/guriescape.c @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2008 Collabora, Ltd. + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * Copyright (C) 1997-2000 The GLib Team + * Copyright (C) 2006-2007 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "guriescape.h" + +#include <string.h> + +#if !PLATFORM(WIN_OS) && !GLIB_CHECK_VERSION(2,16,0) + +/* is_valid, gunichar_ok and g_string_append_uri_escaped were copied for glib/gstring.c + * in the glib package. + * + * Original copyright: + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * Modified by the GLib Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GLib Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + * + * Please don't change the indentation so it's easier to update these functions + * if they are changed in glib. + */ +static gboolean +is_valid (char c, const char *reserved_chars_allowed) +{ + if (g_ascii_isalnum (c) || + c == '-' || + c == '.' || + c == '_' || + c == '~') + return TRUE; + + if (reserved_chars_allowed && + strchr (reserved_chars_allowed, c) != NULL) + return TRUE; + + return FALSE; +} + +static gboolean +gunichar_ok (gunichar c) +{ + return + (c != (gunichar) -2) && + (c != (gunichar) -1); +} + +static GString * +_webcore_g_string_append_uri_escaped (GString *string, + const char *unescaped, + const char *reserved_chars_allowed, + gboolean allow_utf8) +{ + unsigned char c; + const char *end; + static const gchar hex[16] = "0123456789ABCDEF"; + + g_return_val_if_fail (string != NULL, NULL); + g_return_val_if_fail (unescaped != NULL, NULL); + + end = unescaped + strlen (unescaped); + + while ((c = *unescaped) != 0) + { + if (c >= 0x80 && allow_utf8 && + gunichar_ok (g_utf8_get_char_validated (unescaped, end - unescaped))) + { + int len = g_utf8_skip [c]; + g_string_append_len (string, unescaped, len); + unescaped += len; + } + else if (is_valid (c, reserved_chars_allowed)) + { + g_string_append_c (string, c); + unescaped++; + } + else + { + g_string_append_c (string, '%'); + g_string_append_c (string, hex[((guchar)c) >> 4]); + g_string_append_c (string, hex[((guchar)c) & 0xf]); + unescaped++; + } + } + + return string; +} + +/* g_uri_escape_string, unescape_character, g_uri_unescape_segment and + * g_uri_unescape_string were copied for glib/gurifuncs.c in the glib package + * and prefixed with _webcore (if necessary) to avoid exporting a symbol with + * the "g_" prefix. + * + * Original copyright: + * Copyright (C) 2006-2007 Red Hat, Inc. + * Author: Alexander Larsson <alexl@redhat.com> + * + * Please don't change the indentation so it's easier to update this function + * if it's changed in glib. + */ +char * +_webcore_g_uri_escape_string (const char *unescaped, + const char *reserved_chars_allowed, + gboolean allow_utf8) +{ + GString *s; + + g_return_val_if_fail (unescaped != NULL, NULL); + + s = g_string_sized_new (strlen (unescaped) + 10); + + _webcore_g_string_append_uri_escaped (s, unescaped, reserved_chars_allowed, allow_utf8); + + return g_string_free (s, FALSE); +} + +static int +unescape_character (const char *scanner) +{ + int first_digit; + int second_digit; + + first_digit = g_ascii_xdigit_value (*scanner++); + if (first_digit < 0) + return -1; + + second_digit = g_ascii_xdigit_value (*scanner++); + if (second_digit < 0) + return -1; + + return (first_digit << 4) | second_digit; +} + + + +static char * +_webcore_g_uri_unescape_segment (const char *escaped_string, + const char *escaped_string_end, + const char *illegal_characters) +{ + const char *in; + char *out, *result; + gint character; + + if (escaped_string == NULL) + return NULL; + + if (escaped_string_end == NULL) + escaped_string_end = escaped_string + strlen (escaped_string); + + result = g_malloc (escaped_string_end - escaped_string + 1); + + out = result; + for (in = escaped_string; in < escaped_string_end; in++) + { + character = *in; + + if (*in == '%') + { + in++; + + if (escaped_string_end - in < 2) + { + /* Invalid escaped char (to short) */ + g_free (result); + return NULL; + } + + character = unescape_character (in); + + /* Check for an illegal character. We consider '\0' illegal here. */ + if (character <= 0 || + (illegal_characters != NULL && + strchr (illegal_characters, (char)character) != NULL)) + { + g_free (result); + return NULL; + } + + in++; /* The other char will be eaten in the loop header */ + } + *out++ = (char)character; + } + + *out = '\0'; + + return result; +} + + +char * +_webcore_g_uri_unescape_string (const char *escaped_string, + const char *illegal_characters) +{ + return _webcore_g_uri_unescape_segment (escaped_string, NULL, illegal_characters); +} + +#endif /* #if !PLATFORM(WIN_OS) && !GLIB_CHECK_VERSION(2,16,0) */ diff --git a/WebCore/platform/gtk/guriescape.h b/WebCore/platform/gtk/guriescape.h new file mode 100644 index 0000000..8c6662a --- /dev/null +++ b/WebCore/platform/gtk/guriescape.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2008 Collabora, Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef guriescape_h +#define guriescape_h + +#include <glib.h> +#include <wtf/Platform.h> + +G_BEGIN_DECLS + +#if !PLATFORM(WIN_OS) && !GLIB_CHECK_VERSION(2,16,0) + +#define g_uri_escape_string _webcore_g_uri_escape_string +#define g_uri_unescape_string _webcore_g_uri_unescape_string + +char *_webcore_g_uri_escape_string (const char *unescaped, + const char *reserved_chars_allowed, + gboolean allow_utf8); + +char *_webcore_g_uri_unescape_string (const char *escaped_string, + const char *illegal_characters); + +#endif + +G_END_DECLS + +#endif /* guriescape_h */ |