1/* 2 * Copyright (C) 2011 Igalia S.L. 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18 19#include "config.h" 20#include "GtkAdjustmentWatcher.h" 21 22#include "Frame.h" 23#include "FrameView.h" 24#include "Page.h" 25#include "Scrollbar.h" 26#include "webkitwebviewprivate.h" 27#include <gtk/gtk.h> 28 29using namespace WebCore; 30 31namespace WebKit { 32 33GtkAdjustmentWatcher::GtkAdjustmentWatcher(WebKitWebView* webView) 34 : m_webView(webView) 35 , m_scrollbarsDisabled(false) 36 , m_handlingGtkAdjustmentChange(false) 37 , m_updateAdjustmentCallbackId(0) 38{ 39} 40 41GtkAdjustmentWatcher::~GtkAdjustmentWatcher() 42{ 43 if (m_updateAdjustmentCallbackId) 44 g_source_remove(m_updateAdjustmentCallbackId); 45} 46 47static void updateAdjustmentFromScrollbar(GtkAdjustment* adjustment, Scrollbar* scrollbar) 48{ 49 if (!adjustment) 50 return; 51 if (!scrollbar) { 52 gtk_adjustment_configure(adjustment, 0, 0, 0, 0, 0, 0); // These are the settings which remove the scrollbar. 53 return; 54 } 55 gtk_adjustment_configure(adjustment, scrollbar->value(), 0, scrollbar->totalSize(), 56 scrollbar->lineStep(), scrollbar->pageStep(), scrollbar->visibleSize()); 57} 58 59void GtkAdjustmentWatcher::updateAdjustmentsFromScrollbars() 60{ 61 if (m_scrollbarsDisabled) 62 return; 63 if (m_handlingGtkAdjustmentChange) 64 return; 65 if (!core(m_webView) || !core(m_webView)->mainFrame()) 66 return; 67 68 FrameView* frameView = core(m_webView)->mainFrame()->view(); 69 updateAdjustmentFromScrollbar(m_horizontalAdjustment.get(), frameView->horizontalScrollbar()); 70 updateAdjustmentFromScrollbar(m_verticalAdjustment.get(), frameView->verticalScrollbar()); 71 m_updateAdjustmentCallbackId = 0; 72} 73 74static gboolean updateAdjustmentCallback(GtkAdjustmentWatcher* watcher) 75{ 76 watcher->updateAdjustmentsFromScrollbars(); 77 return FALSE; 78} 79 80void GtkAdjustmentWatcher::updateAdjustmentsFromScrollbarsLater() const 81{ 82 // We've already scheduled an update. No need to schedule another. 83 if (m_updateAdjustmentCallbackId || m_scrollbarsDisabled) 84 return; 85 86 // The fact that this method was called means that we need to update the scrollbars, but at the 87 // time of invocation they are not updated to reflect the scroll yet. We set a short timeout 88 // here, which means that they will be updated as soon as WebKit returns to the main loop. 89 m_updateAdjustmentCallbackId = g_timeout_add(0, reinterpret_cast<GSourceFunc>(updateAdjustmentCallback), 90 const_cast<void*>(static_cast<const void*>(this))); 91} 92 93static void adjustmentValueChangedCallback(GtkAdjustment* adjustment, GtkAdjustmentWatcher* watcher) 94{ 95 watcher->adjustmentValueChanged(adjustment); 96} 97 98static void setAdjustment(GtkAdjustmentWatcher* watcher, GRefPtr<GtkAdjustment>& adjustmentMember, GtkAdjustment* newAdjustment) 99{ 100 if (adjustmentMember) { 101 g_signal_handlers_disconnect_by_func(adjustmentMember.get(), 102 reinterpret_cast<void*>(adjustmentValueChangedCallback), watcher); 103 } 104 105 adjustmentMember = newAdjustment; 106 if (newAdjustment) 107 g_signal_connect(newAdjustment, "value-changed", G_CALLBACK(adjustmentValueChangedCallback), watcher); 108} 109 110void GtkAdjustmentWatcher::setHorizontalAdjustment(GtkAdjustment* newAdjustment) 111{ 112 setAdjustment(this, m_horizontalAdjustment, newAdjustment); 113} 114 115void GtkAdjustmentWatcher::setVerticalAdjustment(GtkAdjustment* newAdjustment) 116{ 117 setAdjustment(this, m_verticalAdjustment, newAdjustment); 118} 119 120void GtkAdjustmentWatcher::adjustmentValueChanged(GtkAdjustment* adjustment) 121{ 122 FrameView* frameView = core(m_webView)->mainFrame()->view(); 123 Scrollbar* scrollbar = (adjustment == m_horizontalAdjustment.get()) ? 124 frameView->horizontalScrollbar() : frameView->verticalScrollbar(); 125 if (!scrollbar) 126 return; 127 128 int newValue = static_cast<int>(gtk_adjustment_get_value(adjustment)); 129 if (newValue != scrollbar->value()) { 130 m_handlingGtkAdjustmentChange = true; 131 frameView->scrollToOffsetWithoutAnimation(scrollbar->orientation(), newValue); 132 m_handlingGtkAdjustmentChange = false; 133 } 134} 135 136void GtkAdjustmentWatcher::disableAllScrollbars() 137{ 138 updateAdjustmentFromScrollbar(m_horizontalAdjustment.get(), 0); 139 updateAdjustmentFromScrollbar(m_verticalAdjustment.get(), 0); 140 m_scrollbarsDisabled = true; 141} 142 143void GtkAdjustmentWatcher::enableAllScrollbars() 144{ 145 m_scrollbarsDisabled = false; 146 updateAdjustmentsFromScrollbars(); 147} 148 149} // namespace WebKit 150 151