/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim:expandtab:shiftwidth=2:tabstop=2: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "MozContainer.h" #include #include #include #include "mozilla/WidgetUtilsGtk.h" #include "nsWindow.h" #ifdef MOZ_LOGGING # include "mozilla/Logging.h" # include "nsTArray.h" # include "Units.h" extern mozilla::LazyLogModule gWidgetLog; # define LOGCONTAINER(args) MOZ_LOG(gWidgetLog, mozilla::LogLevel::Debug, args) #else # define LOGCONTAINER(args) #endif /* MOZ_LOGGING */ /* init methods */ void moz_container_class_init(MozContainerClass* klass); static void moz_container_init(MozContainer* container); /* widget class methods */ static void moz_container_map(GtkWidget* widget); void moz_container_unmap(GtkWidget* widget); static void moz_container_size_allocate(GtkWidget* widget, GtkAllocation* allocation); static void moz_container_realize(GtkWidget* widget); static void moz_container_unrealize(GtkWidget* widget); /* public methods */ GType moz_container_get_type(void) { static GType moz_container_type = 0; if (!moz_container_type) { static GTypeInfo moz_container_info = { sizeof(MozContainerClass), /* class_size */ NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc)moz_container_class_init, /* class_init */ NULL, /* class_destroy */ NULL, /* class_data */ sizeof(MozContainer), /* instance_size */ 0, /* n_preallocs */ (GInstanceInitFunc)moz_container_init, /* instance_init */ NULL, /* value_table */ }; moz_container_type = g_type_register_static(GTK_TYPE_CONTAINER, "MozContainer", &moz_container_info, static_cast(0)); } return moz_container_type; } GtkWidget* moz_container_new(void) { MozContainer* container; container = static_cast(g_object_new(MOZ_CONTAINER_TYPE, nullptr)); return GTK_WIDGET(container); } static void moz_container_destroy(GtkWidget* widget) { auto* container = MOZ_CONTAINER(widget); if (container->destroyed) { return; // The destroy signal may run multiple times. } LOGCONTAINER(("moz_container_destroy() [%p]\n", (void*)moz_container_get_nsWindow(MOZ_CONTAINER(widget)))); container->destroyed = TRUE; container->data.~Data(); } void moz_container_class_init(MozContainerClass* klass) { /*GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass); */ GtkWidgetClass* widget_class = GTK_WIDGET_CLASS(klass); widget_class->map = moz_container_map; widget_class->realize = moz_container_realize; widget_class->unrealize = moz_container_unrealize; widget_class->destroy = moz_container_destroy; #ifdef MOZ_WAYLAND if (mozilla::widget::GdkIsWaylandDisplay()) { widget_class->size_allocate = moz_container_wayland_size_allocate; widget_class->map_event = moz_container_wayland_map_event; widget_class->unmap = moz_container_wayland_unmap; } else { #endif widget_class->size_allocate = moz_container_size_allocate; widget_class->unmap = moz_container_unmap; #ifdef MOZ_WAYLAND } #endif } void moz_container_init(MozContainer* container) { container->destroyed = FALSE; new (&container->data) MozContainer::Data(); gtk_widget_set_can_focus(GTK_WIDGET(container), TRUE); gtk_widget_set_redraw_on_allocate(GTK_WIDGET(container), FALSE); LOGCONTAINER(("%s [%p]\n", __FUNCTION__, (void*)moz_container_get_nsWindow(container))); } void moz_container_map(GtkWidget* widget) { MozContainer* container; g_return_if_fail(IS_MOZ_CONTAINER(widget)); container = MOZ_CONTAINER(widget); LOGCONTAINER(("moz_container_map() [%p]", (void*)moz_container_get_nsWindow(container))); gtk_widget_set_mapped(widget, TRUE); if (gtk_widget_get_has_window(widget)) { gdk_window_show(gtk_widget_get_window(widget)); } // Enable rendering to nsWindow/MozContainer nsWindow* window = moz_container_get_nsWindow(MOZ_CONTAINER(widget)); window->OnMap(); } void moz_container_unmap(GtkWidget* widget) { g_return_if_fail(IS_MOZ_CONTAINER(widget)); LOGCONTAINER(("moz_container_unmap() [%p]", (void*)moz_container_get_nsWindow(MOZ_CONTAINER(widget)))); // Disable rendering to nsWindow/MozContainer before we really unmap it. nsWindow* window = moz_container_get_nsWindow(MOZ_CONTAINER(widget)); window->OnUnmap(); gtk_widget_set_mapped(widget, FALSE); if (gtk_widget_get_has_window(widget)) { gdk_window_hide(gtk_widget_get_window(widget)); } } void moz_container_realize(GtkWidget* widget) { GdkWindow* parent = gtk_widget_get_parent_window(widget); GdkWindow* window; gtk_widget_set_realized(widget, TRUE); GdkWindowAttr attributes; gint attributes_mask = GDK_WA_VISUAL | GDK_WA_X | GDK_WA_Y; GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); attributes.event_mask = gtk_widget_get_events(widget); attributes.x = allocation.x; attributes.y = allocation.y; attributes.width = allocation.width; attributes.height = allocation.height; attributes.wclass = GDK_INPUT_OUTPUT; attributes.window_type = GDK_WINDOW_CHILD; MozContainer* container = MOZ_CONTAINER(widget); attributes.visual = container->data.force_default_visual ? gdk_screen_get_system_visual(gtk_widget_get_screen(widget)) : gtk_widget_get_visual(widget); window = gdk_window_new(parent, &attributes, attributes_mask); LOGCONTAINER(("moz_container_realize() [%p] GdkWindow %p\n", (void*)moz_container_get_nsWindow(container), (void*)window)); gtk_widget_register_window(widget, window); gtk_widget_set_window(widget, window); } void moz_container_unrealize(GtkWidget* widget) { GdkWindow* window = gtk_widget_get_window(widget); LOGCONTAINER(("moz_container_unrealize() [%p] GdkWindow %p\n", (void*)moz_container_get_nsWindow(MOZ_CONTAINER(widget)), (void*)window)); if (gtk_widget_get_mapped(widget)) { gtk_widget_unmap(widget); } gtk_widget_unregister_window(widget, window); gtk_widget_set_window(widget, nullptr); gdk_window_destroy(window); gtk_widget_set_realized(widget, false); } void moz_container_size_allocate(GtkWidget* widget, GtkAllocation* allocation) { GtkAllocation tmp_allocation; g_return_if_fail(IS_MOZ_CONTAINER(widget)); LOGCONTAINER(("moz_container_size_allocate [%p] %d,%d -> %d x %d\n", (void*)moz_container_get_nsWindow(MOZ_CONTAINER(widget)), allocation->x, allocation->y, allocation->width, allocation->height)); /* short circuit if you can */ gtk_widget_get_allocation(widget, &tmp_allocation); if (tmp_allocation.x == allocation->x && tmp_allocation.y == allocation->y && tmp_allocation.width == allocation->width && tmp_allocation.height == allocation->height) { return; } gtk_widget_set_allocation(widget, allocation); if (gtk_widget_get_has_window(widget) && gtk_widget_get_realized(widget)) { gdk_window_move_resize(gtk_widget_get_window(widget), allocation->x, allocation->y, allocation->width, allocation->height); } } void moz_container_force_default_visual(MozContainer* container) { container->data.force_default_visual = true; } nsWindow* moz_container_get_nsWindow(MozContainer* container) { gpointer user_data = g_object_get_data(G_OBJECT(container), "nsWindow"); return static_cast(user_data); } #undef LOGCONTAINER