211 lines
6.3 KiB
C++
211 lines
6.3 KiB
C++
/*
|
|
* Copyright (C) 2011, 2013 Igalia S.L.
|
|
*
|
|
* 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 "GtkUtilities.h"
|
|
|
|
#include "GtkVersioning.h"
|
|
#include "IntPoint.h"
|
|
#include <gtk/gtk.h>
|
|
#include <wtf/glib/GUniquePtr.h>
|
|
|
|
#if USE(GTK4) && PLATFORM(X11)
|
|
#include <gdk/x11/gdkx.h>
|
|
#endif
|
|
|
|
namespace WebCore {
|
|
|
|
static IntPoint gtkWindowGetOrigin(GtkWidget* window)
|
|
{
|
|
int x = 0, y = 0;
|
|
|
|
#if USE(GTK4)
|
|
UNUSED_PARAM(window);
|
|
#else
|
|
if (auto* gdkWindow = gtk_widget_get_window(window))
|
|
gdk_window_get_origin(gdkWindow, &x, &y);
|
|
#endif // !USE(GTK4)
|
|
|
|
return IntPoint(x, y);
|
|
}
|
|
|
|
IntPoint convertWidgetPointToScreenPoint(GtkWidget* widget, const IntPoint& point)
|
|
{
|
|
// FIXME: This is actually a very tricky operation and the results of this function should
|
|
// only be thought of as a guess. For instance, sometimes it may not correctly take into
|
|
// account window decorations.
|
|
|
|
GtkWidget* toplevelWidget = gtk_widget_get_toplevel(widget);
|
|
if (!toplevelWidget || !gtk_widget_is_toplevel(toplevelWidget) || !GTK_IS_WINDOW(toplevelWidget))
|
|
return point;
|
|
|
|
#if USE(GTK4)
|
|
double xInWindow, yInWindow;
|
|
#else
|
|
int xInWindow, yInWindow;
|
|
#endif
|
|
gtk_widget_translate_coordinates(widget, toplevelWidget, point.x(), point.y(), &xInWindow, &yInWindow);
|
|
|
|
const auto origin = gtkWindowGetOrigin(toplevelWidget);
|
|
return IntPoint(origin.x() + xInWindow, origin.y() + yInWindow);
|
|
}
|
|
|
|
bool widgetIsOnscreenToplevelWindow(GtkWidget* widget)
|
|
{
|
|
const bool isToplevelWidget = widget && gtk_widget_is_toplevel(widget);
|
|
|
|
#if USE(GTK4)
|
|
// A toplevel widget in GTK4 is always a window, there is no need for further checks.
|
|
return isToplevelWidget;
|
|
#else
|
|
return isToplevelWidget && GTK_IS_WINDOW(widget) && !GTK_IS_OFFSCREEN_WINDOW(widget);
|
|
#endif // USE(GTK4)
|
|
}
|
|
|
|
IntPoint widgetRootCoords(GtkWidget* widget, int x, int y)
|
|
{
|
|
#if USE(GTK4)
|
|
UNUSED_PARAM(widget);
|
|
return { x, y };
|
|
#else
|
|
int xRoot, yRoot;
|
|
gdk_window_get_root_coords(gtk_widget_get_window(widget), x, y, &xRoot, &yRoot);
|
|
return { xRoot, yRoot };
|
|
#endif
|
|
}
|
|
|
|
void widgetDevicePosition(GtkWidget* widget, GdkDevice* device, double* x, double* y, GdkModifierType* state)
|
|
{
|
|
#if USE(GTK4)
|
|
gdk_surface_get_device_position(gtk_native_get_surface(gtk_widget_get_native(widget)), device, x, y, state);
|
|
#else
|
|
int xInt, yInt;
|
|
gdk_window_get_device_position(gtk_widget_get_window(widget), device, &xInt, &yInt, state);
|
|
*x = xInt;
|
|
*y = yInt;
|
|
#endif
|
|
}
|
|
|
|
unsigned widgetKeyvalToKeycode(GtkWidget* widget, unsigned keyval)
|
|
{
|
|
unsigned keycode = 0;
|
|
GUniqueOutPtr<GdkKeymapKey> keys;
|
|
int keysCount;
|
|
auto* display = gtk_widget_get_display(widget);
|
|
|
|
#if USE(GTK4)
|
|
if (gdk_display_map_keyval(display, keyval, &keys.outPtr(), &keysCount) && keysCount)
|
|
keycode = keys.get()[0].keycode;
|
|
#else
|
|
GdkKeymap* keymap = gdk_keymap_get_for_display(display);
|
|
if (gdk_keymap_get_entries_for_keyval(keymap, keyval, &keys.outPtr(), &keysCount) && keysCount)
|
|
keycode = keys.get()[0].keycode;
|
|
#endif
|
|
|
|
return keycode;
|
|
}
|
|
|
|
template<>
|
|
WallTime wallTimeForEvent(const GdkEvent* event)
|
|
{
|
|
// This works if and only if the X server or Wayland compositor happens to
|
|
// be using CLOCK_MONOTONIC for its monotonic time, and so long as
|
|
// g_get_monotonic_time() continues to do so as well, and so long as
|
|
// WTF::MonotonicTime continues to use g_get_monotonic_time().
|
|
#if USE(GTK4)
|
|
auto time = gdk_event_get_time(const_cast<GdkEvent*>(event));
|
|
#else
|
|
auto time = gdk_event_get_time(event);
|
|
#endif
|
|
if (time == GDK_CURRENT_TIME)
|
|
return WallTime::now();
|
|
return MonotonicTime::fromRawSeconds(time / 1000.).approximateWallTime();
|
|
}
|
|
|
|
String defaultGtkSystemFont()
|
|
{
|
|
GUniqueOutPtr<char> fontString;
|
|
g_object_get(gtk_settings_get_default(), "gtk-font-name", &fontString.outPtr(), nullptr);
|
|
// We need to remove the size from the value of the property,
|
|
// which is separated from the font family using a space.
|
|
if (auto* spaceChar = strrchr(fontString.get(), ' '))
|
|
*spaceChar = '\0';
|
|
return String::fromUTF8(fontString.get());
|
|
}
|
|
|
|
unsigned stateModifierForGdkButton(unsigned button)
|
|
{
|
|
return 1 << (8 + button - 1);
|
|
}
|
|
|
|
OptionSet<DragOperation> gdkDragActionToDragOperation(GdkDragAction gdkAction)
|
|
{
|
|
OptionSet<DragOperation> action;
|
|
if (gdkAction & GDK_ACTION_COPY)
|
|
action.add(DragOperation::Copy);
|
|
if (gdkAction & GDK_ACTION_MOVE)
|
|
action.add(DragOperation::Move);
|
|
if (gdkAction & GDK_ACTION_LINK)
|
|
action.add(DragOperation::Link);
|
|
|
|
return action;
|
|
}
|
|
|
|
GdkDragAction dragOperationToGdkDragActions(OptionSet<DragOperation> coreAction)
|
|
{
|
|
unsigned gdkAction = 0;
|
|
|
|
if (coreAction.contains(DragOperation::Copy))
|
|
gdkAction |= GDK_ACTION_COPY;
|
|
if (coreAction.contains(DragOperation::Move))
|
|
gdkAction |= GDK_ACTION_MOVE;
|
|
if (coreAction.contains(DragOperation::Link))
|
|
gdkAction |= GDK_ACTION_LINK;
|
|
|
|
return static_cast<GdkDragAction>(gdkAction);
|
|
}
|
|
|
|
GdkDragAction dragOperationToSingleGdkDragAction(OptionSet<DragOperation> coreAction)
|
|
{
|
|
if (coreAction.contains(DragOperation::Copy))
|
|
return GDK_ACTION_COPY;
|
|
if (coreAction.contains(DragOperation::Move))
|
|
return GDK_ACTION_MOVE;
|
|
if (coreAction.contains(DragOperation::Link))
|
|
return GDK_ACTION_LINK;
|
|
return static_cast<GdkDragAction>(0);
|
|
}
|
|
|
|
void monitorWorkArea(GdkMonitor* monitor, GdkRectangle* area)
|
|
{
|
|
#if USE(GTK4)
|
|
#if PLATFORM(X11)
|
|
if (GDK_IS_X11_MONITOR(monitor)) {
|
|
gdk_x11_monitor_get_workarea(monitor, area);
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
gdk_monitor_get_geometry(monitor, area);
|
|
#else
|
|
gdk_monitor_get_workarea(monitor, area);
|
|
#endif
|
|
}
|
|
|
|
} // namespace WebCore
|