forked from AuroraMiddleware/gtk
2500 lines
74 KiB
C
2500 lines
74 KiB
C
/*
|
|
* Copyright © 2014 Canonical 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, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <inttypes.h>
|
|
#include <math.h>
|
|
|
|
#include "config.h"
|
|
|
|
#include "gdk.h"
|
|
#include "gdkmir.h"
|
|
#include "gdkmir-private.h"
|
|
|
|
#include "gdkwindowimpl.h"
|
|
#include "gdkinternals.h"
|
|
#include "gdkintl.h"
|
|
#include "gdkdisplayprivate.h"
|
|
#include "gdkdeviceprivate.h"
|
|
|
|
#define GDK_MIR_WINDOW_IMPL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_WINDOW_IMPL_MIR, GdkMirWindowImplClass))
|
|
#define GDK_IS_WINDOW_IMPL_MIR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_WINDOW_IMPL_MIR))
|
|
#define GDK_MIR_WINDOW_IMPL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_WINDOW_IMPL_MIR, GdkMirWindowImplClass))
|
|
|
|
#define MAX_EGL_ATTRS 30
|
|
|
|
typedef struct
|
|
{
|
|
GdkAtom type;
|
|
GArray *array;
|
|
} GdkMirProperty;
|
|
|
|
static GdkMirProperty *
|
|
gdk_mir_property_new (GdkAtom type,
|
|
guint format,
|
|
guint capacity)
|
|
{
|
|
GdkMirProperty *property = g_slice_new (GdkMirProperty);
|
|
|
|
property->type = type;
|
|
property->array = g_array_sized_new (TRUE, FALSE, format, capacity);
|
|
|
|
return property;
|
|
}
|
|
|
|
static void
|
|
gdk_mir_property_free (gpointer data)
|
|
{
|
|
GdkMirProperty *property = data;
|
|
|
|
if (!property)
|
|
return;
|
|
|
|
g_array_unref (property->array);
|
|
g_slice_free (GdkMirProperty, property);
|
|
}
|
|
|
|
typedef struct _GdkMirWindowImplClass GdkMirWindowImplClass;
|
|
|
|
struct _GdkMirWindowImpl
|
|
{
|
|
GdkWindowImpl parent_instance;
|
|
|
|
GHashTable *properties;
|
|
|
|
/* Window we are temporary for */
|
|
GdkWindow *transient_for;
|
|
gint transient_x;
|
|
gint transient_y;
|
|
|
|
/* gdk_window_move_to_rect */
|
|
gboolean has_rect;
|
|
GdkRectangle rect;
|
|
MirRectangle mir_rect;
|
|
MirPlacementGravity rect_anchor;
|
|
MirPlacementGravity window_anchor;
|
|
MirPlacementHints anchor_hints;
|
|
gint rect_anchor_dx;
|
|
gint rect_anchor_dy;
|
|
|
|
/* Desired window attributes */
|
|
GdkWindowTypeHint type_hint;
|
|
MirWindowState window_state;
|
|
gboolean modal;
|
|
|
|
/* Pattern for background */
|
|
cairo_pattern_t *background;
|
|
|
|
/* Current button state for checking which buttons are being pressed / released */
|
|
gdouble x;
|
|
gdouble y;
|
|
guint button_state;
|
|
|
|
GdkDisplay *display;
|
|
|
|
/* Window being rendered to (only exists when visible) */
|
|
MirWindow *mir_window;
|
|
MirBufferStream *buffer_stream;
|
|
MirBufferUsage buffer_usage;
|
|
|
|
/* Cairo context for current frame */
|
|
cairo_surface_t *cairo_surface;
|
|
|
|
gchar *title;
|
|
|
|
GdkGeometry geometry_hints;
|
|
GdkWindowHints geometry_mask;
|
|
|
|
/* Egl surface for the current mir window */
|
|
EGLSurface egl_surface;
|
|
|
|
/* Dummy MIR and EGL surfaces */
|
|
EGLSurface dummy_egl_surface;
|
|
|
|
/* TRUE if the window can be seen */
|
|
gboolean visible;
|
|
|
|
/* TRUE if cursor is inside this window */
|
|
gboolean cursor_inside;
|
|
|
|
gboolean pending_spec_update;
|
|
gint output_scale;
|
|
};
|
|
|
|
struct _GdkMirWindowImplClass
|
|
{
|
|
GdkWindowImplClass parent_class;
|
|
};
|
|
|
|
G_DEFINE_TYPE (GdkMirWindowImpl, gdk_mir_window_impl, GDK_TYPE_WINDOW_IMPL)
|
|
|
|
static cairo_surface_t *gdk_mir_window_impl_ref_cairo_surface (GdkWindow *window);
|
|
static void ensure_mir_window (GdkWindow *window);
|
|
|
|
static gboolean
|
|
type_hint_differs (GdkWindowTypeHint lhs, GdkWindowTypeHint rhs)
|
|
{
|
|
if (lhs == rhs)
|
|
return FALSE;
|
|
|
|
switch (lhs)
|
|
{
|
|
case GDK_WINDOW_TYPE_HINT_DIALOG:
|
|
case GDK_WINDOW_TYPE_HINT_DOCK:
|
|
return rhs != GDK_WINDOW_TYPE_HINT_DIALOG &&
|
|
rhs != GDK_WINDOW_TYPE_HINT_DOCK;
|
|
case GDK_WINDOW_TYPE_HINT_MENU:
|
|
case GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU:
|
|
case GDK_WINDOW_TYPE_HINT_POPUP_MENU:
|
|
case GDK_WINDOW_TYPE_HINT_TOOLBAR:
|
|
case GDK_WINDOW_TYPE_HINT_COMBO:
|
|
case GDK_WINDOW_TYPE_HINT_DND:
|
|
case GDK_WINDOW_TYPE_HINT_TOOLTIP:
|
|
case GDK_WINDOW_TYPE_HINT_NOTIFICATION:
|
|
return rhs != GDK_WINDOW_TYPE_HINT_MENU &&
|
|
rhs != GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU &&
|
|
rhs != GDK_WINDOW_TYPE_HINT_POPUP_MENU &&
|
|
rhs != GDK_WINDOW_TYPE_HINT_TOOLBAR &&
|
|
rhs != GDK_WINDOW_TYPE_HINT_COMBO &&
|
|
rhs != GDK_WINDOW_TYPE_HINT_DND &&
|
|
rhs != GDK_WINDOW_TYPE_HINT_TOOLTIP &&
|
|
rhs != GDK_WINDOW_TYPE_HINT_NOTIFICATION;
|
|
case GDK_WINDOW_TYPE_HINT_SPLASHSCREEN:
|
|
case GDK_WINDOW_TYPE_HINT_UTILITY:
|
|
return rhs != GDK_WINDOW_TYPE_HINT_SPLASHSCREEN &&
|
|
rhs != GDK_WINDOW_TYPE_HINT_UTILITY;
|
|
case GDK_WINDOW_TYPE_HINT_NORMAL:
|
|
case GDK_WINDOW_TYPE_HINT_DESKTOP:
|
|
default:
|
|
return rhs != GDK_WINDOW_TYPE_HINT_NORMAL &&
|
|
rhs != GDK_WINDOW_TYPE_HINT_DESKTOP;
|
|
}
|
|
}
|
|
|
|
static void
|
|
drop_cairo_surface (GdkWindow *window)
|
|
{
|
|
GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
|
|
|
|
g_clear_pointer (&impl->cairo_surface, cairo_surface_destroy);
|
|
}
|
|
|
|
static const gchar *
|
|
get_default_title (void)
|
|
{
|
|
const char *title;
|
|
|
|
title = g_get_application_name ();
|
|
if (!title)
|
|
title = g_get_prgname ();
|
|
if (!title)
|
|
title = "";
|
|
|
|
return title;
|
|
}
|
|
|
|
GdkWindowImpl *
|
|
_gdk_mir_window_impl_new (GdkDisplay *display, GdkWindow *window, GdkWindowAttr *attributes, gint attributes_mask)
|
|
{
|
|
GdkMirWindowImpl *impl = g_object_new (GDK_TYPE_MIR_WINDOW_IMPL, NULL);
|
|
|
|
impl->display = display;
|
|
|
|
if (attributes && attributes_mask & GDK_WA_TITLE)
|
|
impl->title = g_strdup (attributes->title);
|
|
else
|
|
impl->title = g_strdup (get_default_title ());
|
|
|
|
if (attributes && attributes_mask & GDK_WA_TYPE_HINT)
|
|
impl->type_hint = attributes->type_hint;
|
|
|
|
impl->pending_spec_update = TRUE;
|
|
|
|
return (GdkWindowImpl *) impl;
|
|
}
|
|
|
|
void
|
|
_gdk_mir_window_impl_set_window_state (GdkMirWindowImpl *impl,
|
|
MirWindowState state)
|
|
{
|
|
impl->window_state = state;
|
|
}
|
|
|
|
void
|
|
_gdk_mir_window_impl_set_window_type (GdkMirWindowImpl *impl,
|
|
MirWindowType type)
|
|
{
|
|
}
|
|
|
|
void
|
|
_gdk_mir_window_impl_set_cursor_state (GdkMirWindowImpl *impl,
|
|
gdouble x,
|
|
gdouble y,
|
|
gboolean cursor_inside,
|
|
guint button_state)
|
|
{
|
|
impl->x = x;
|
|
impl->y = y;
|
|
impl->cursor_inside = cursor_inside;
|
|
impl->button_state = button_state;
|
|
}
|
|
|
|
void
|
|
_gdk_mir_window_impl_get_cursor_state (GdkMirWindowImpl *impl,
|
|
gdouble *x,
|
|
gdouble *y,
|
|
gboolean *cursor_inside,
|
|
guint *button_state)
|
|
{
|
|
if (x)
|
|
*x = impl->x;
|
|
if (y)
|
|
*y = impl->y;
|
|
if (cursor_inside)
|
|
*cursor_inside = impl->cursor_inside;
|
|
if (button_state)
|
|
*button_state = impl->button_state;
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_init (GdkMirWindowImpl *impl)
|
|
{
|
|
impl->properties = g_hash_table_new_full (NULL, NULL, NULL, gdk_mir_property_free);
|
|
impl->type_hint = GDK_WINDOW_TYPE_HINT_NORMAL;
|
|
impl->window_state = mir_window_state_unknown;
|
|
impl->output_scale = 1;
|
|
}
|
|
|
|
static void
|
|
set_window_state (GdkMirWindowImpl *impl,
|
|
MirWindowState state)
|
|
{
|
|
MirConnection *connection = gdk_mir_display_get_mir_connection (impl->display);
|
|
MirWindowSpec *spec;
|
|
|
|
if (state == impl->window_state)
|
|
return;
|
|
|
|
impl->window_state = state;
|
|
|
|
if (impl->mir_window && !impl->pending_spec_update)
|
|
{
|
|
spec = mir_create_window_spec (connection);
|
|
mir_window_spec_set_state (spec, state);
|
|
mir_window_apply_spec (impl->mir_window, spec);
|
|
mir_window_spec_release (spec);
|
|
}
|
|
}
|
|
|
|
static void
|
|
event_cb (MirWindow *mir_window,
|
|
const MirEvent *event,
|
|
void *context)
|
|
{
|
|
_gdk_mir_event_source_queue (context, event);
|
|
}
|
|
|
|
static MirWindowSpec *
|
|
create_window_type_spec (GdkDisplay *display,
|
|
GdkWindow *parent,
|
|
gint x,
|
|
gint y,
|
|
gint width,
|
|
gint height,
|
|
gboolean modal,
|
|
GdkWindowTypeHint type,
|
|
MirBufferUsage buffer_usage)
|
|
{
|
|
MirConnection *connection = gdk_mir_display_get_mir_connection (display);
|
|
MirWindow *parent_mir_window = NULL;
|
|
MirPixelFormat format;
|
|
MirRectangle rect;
|
|
MirWindowSpec *spec;
|
|
|
|
if (parent && parent->impl)
|
|
{
|
|
ensure_mir_window (parent);
|
|
parent_mir_window = GDK_MIR_WINDOW_IMPL (parent->impl)->mir_window;
|
|
}
|
|
|
|
if (!parent_mir_window)
|
|
{
|
|
switch (type)
|
|
{
|
|
case GDK_WINDOW_TYPE_HINT_SPLASHSCREEN:
|
|
case GDK_WINDOW_TYPE_HINT_UTILITY:
|
|
type = GDK_WINDOW_TYPE_HINT_DIALOG;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
format = _gdk_mir_display_get_pixel_format (display, buffer_usage);
|
|
|
|
rect.left = x;
|
|
rect.top = y;
|
|
rect.width = 1;
|
|
rect.height = 1;
|
|
|
|
switch (type)
|
|
{
|
|
case GDK_WINDOW_TYPE_HINT_DIALOG:
|
|
if (modal)
|
|
spec = mir_create_modal_dialog_window_spec (connection,
|
|
width,
|
|
height,
|
|
parent_mir_window);
|
|
else
|
|
spec = mir_create_dialog_window_spec (connection,
|
|
width,
|
|
height);
|
|
break;
|
|
case GDK_WINDOW_TYPE_HINT_DOCK:
|
|
spec = mir_create_dialog_window_spec (connection,
|
|
width,
|
|
height);
|
|
break;
|
|
case GDK_WINDOW_TYPE_HINT_MENU:
|
|
case GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU:
|
|
case GDK_WINDOW_TYPE_HINT_POPUP_MENU:
|
|
case GDK_WINDOW_TYPE_HINT_TOOLBAR:
|
|
case GDK_WINDOW_TYPE_HINT_COMBO:
|
|
case GDK_WINDOW_TYPE_HINT_DND:
|
|
case GDK_WINDOW_TYPE_HINT_TOOLTIP:
|
|
case GDK_WINDOW_TYPE_HINT_NOTIFICATION:
|
|
spec = mir_create_menu_window_spec (connection,
|
|
width,
|
|
height,
|
|
parent_mir_window,
|
|
&rect,
|
|
0);
|
|
break;
|
|
case GDK_WINDOW_TYPE_HINT_SPLASHSCREEN:
|
|
case GDK_WINDOW_TYPE_HINT_UTILITY:
|
|
spec = mir_create_modal_dialog_window_spec (connection,
|
|
width,
|
|
height,
|
|
parent_mir_window);
|
|
break;
|
|
case GDK_WINDOW_TYPE_HINT_NORMAL:
|
|
case GDK_WINDOW_TYPE_HINT_DESKTOP:
|
|
default:
|
|
spec = mir_create_normal_window_spec (connection,
|
|
width,
|
|
height);
|
|
break;
|
|
}
|
|
|
|
mir_window_spec_set_pixel_format (spec, format);
|
|
|
|
return spec;
|
|
}
|
|
|
|
static void
|
|
apply_geometry_hints (MirWindowSpec *spec,
|
|
GdkMirWindowImpl *impl)
|
|
{
|
|
if (impl->geometry_mask & GDK_HINT_RESIZE_INC)
|
|
{
|
|
mir_window_spec_set_width_increment (spec, impl->geometry_hints.width_inc);
|
|
mir_window_spec_set_height_increment (spec, impl->geometry_hints.height_inc);
|
|
}
|
|
if (impl->geometry_mask & GDK_HINT_MIN_SIZE)
|
|
{
|
|
mir_window_spec_set_min_width (spec, impl->geometry_hints.min_width);
|
|
mir_window_spec_set_min_height (spec, impl->geometry_hints.min_height);
|
|
}
|
|
if (impl->geometry_mask & GDK_HINT_MAX_SIZE)
|
|
{
|
|
mir_window_spec_set_max_width (spec, impl->geometry_hints.max_width);
|
|
mir_window_spec_set_max_height (spec, impl->geometry_hints.max_height);
|
|
}
|
|
if (impl->geometry_mask & GDK_HINT_ASPECT)
|
|
{
|
|
mir_window_spec_set_min_aspect_ratio (spec, (guint) 1000 * impl->geometry_hints.min_aspect, 1000);
|
|
mir_window_spec_set_max_aspect_ratio (spec, (guint) 1000 * impl->geometry_hints.max_aspect, 1000);
|
|
}
|
|
}
|
|
|
|
static MirWindowSpec *
|
|
create_spec (GdkWindow *window,
|
|
GdkMirWindowImpl *impl)
|
|
{
|
|
MirWindowSpec *spec = NULL;
|
|
GdkWindow *parent;
|
|
MirRectangle rect;
|
|
|
|
spec = create_window_type_spec (impl->display,
|
|
impl->transient_for,
|
|
impl->transient_x,
|
|
impl->transient_y,
|
|
window->width,
|
|
window->height,
|
|
impl->modal,
|
|
impl->type_hint,
|
|
impl->buffer_usage);
|
|
|
|
mir_window_spec_set_name (spec, impl->title);
|
|
mir_window_spec_set_buffer_usage (spec, impl->buffer_usage);
|
|
|
|
apply_geometry_hints (spec, impl);
|
|
|
|
if (impl->has_rect)
|
|
{
|
|
impl->mir_rect.left = impl->rect.x;
|
|
impl->mir_rect.top = impl->rect.y;
|
|
impl->mir_rect.width = impl->rect.width;
|
|
impl->mir_rect.height = impl->rect.height;
|
|
|
|
parent = impl->transient_for;
|
|
|
|
while (parent && !gdk_window_has_native (parent))
|
|
{
|
|
impl->mir_rect.left += parent->x;
|
|
impl->mir_rect.top += parent->y;
|
|
|
|
parent = gdk_window_get_parent (parent);
|
|
}
|
|
|
|
mir_window_spec_set_placement (spec,
|
|
&impl->mir_rect,
|
|
impl->rect_anchor,
|
|
impl->window_anchor,
|
|
impl->anchor_hints,
|
|
impl->rect_anchor_dx,
|
|
impl->rect_anchor_dy);
|
|
}
|
|
else
|
|
{
|
|
switch (impl->type_hint)
|
|
{
|
|
case GDK_WINDOW_TYPE_HINT_MENU:
|
|
case GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU:
|
|
case GDK_WINDOW_TYPE_HINT_POPUP_MENU:
|
|
case GDK_WINDOW_TYPE_HINT_TOOLBAR:
|
|
case GDK_WINDOW_TYPE_HINT_COMBO:
|
|
case GDK_WINDOW_TYPE_HINT_DND:
|
|
case GDK_WINDOW_TYPE_HINT_TOOLTIP:
|
|
case GDK_WINDOW_TYPE_HINT_NOTIFICATION:
|
|
rect.left = impl->transient_x;
|
|
rect.top = impl->transient_y;
|
|
rect.width = 1;
|
|
rect.height = 1;
|
|
|
|
mir_window_spec_set_placement (spec,
|
|
&rect,
|
|
mir_placement_gravity_southeast,
|
|
mir_placement_gravity_northwest,
|
|
(mir_placement_hints_flip_x |
|
|
mir_placement_hints_flip_y |
|
|
mir_placement_hints_slide_x |
|
|
mir_placement_hints_slide_y |
|
|
mir_placement_hints_resize_x |
|
|
mir_placement_hints_resize_y),
|
|
-window->shadow_left,
|
|
-window->shadow_top);
|
|
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return spec;
|
|
}
|
|
|
|
static void
|
|
update_window_spec (GdkWindow *window)
|
|
{
|
|
GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
|
|
MirWindowSpec *spec;
|
|
|
|
if (!impl->mir_window)
|
|
return;
|
|
|
|
spec = create_spec (window, impl);
|
|
|
|
mir_window_apply_spec (impl->mir_window, spec);
|
|
mir_window_spec_release (spec);
|
|
|
|
impl->pending_spec_update = FALSE;
|
|
impl->buffer_stream = mir_window_get_buffer_stream (impl->mir_window);
|
|
}
|
|
|
|
static GdkDevice *
|
|
get_pointer (GdkWindow *window)
|
|
{
|
|
GdkDisplay *display;
|
|
GdkSeat *seat;
|
|
GdkDevice *pointer;
|
|
|
|
display = gdk_window_get_display (window);
|
|
seat = gdk_display_get_default_seat (display);
|
|
pointer = gdk_seat_get_pointer (seat);
|
|
|
|
return pointer;
|
|
}
|
|
|
|
static void
|
|
send_event (GdkWindow *window, GdkDevice *device, GdkEvent *event)
|
|
{
|
|
GdkDisplay *display;
|
|
GList *node;
|
|
|
|
display = gdk_window_get_display (window);
|
|
gdk_event_set_device (event, device);
|
|
gdk_event_set_source_device (event, device);
|
|
gdk_event_set_screen (event, gdk_display_get_default_screen (display));
|
|
event->any.window = g_object_ref (window);
|
|
|
|
node = _gdk_event_queue_append (display, event);
|
|
_gdk_windowing_got_event (display, node, event, _gdk_display_get_next_serial (display));
|
|
}
|
|
|
|
static void
|
|
generate_configure_event (GdkWindow *window,
|
|
gint width,
|
|
gint height)
|
|
{
|
|
GdkEvent *event;
|
|
|
|
event = gdk_event_new (GDK_CONFIGURE);
|
|
event->configure.send_event = FALSE;
|
|
event->configure.width = width;
|
|
event->configure.height = height;
|
|
|
|
send_event (window, get_pointer (window), event);
|
|
}
|
|
|
|
static void
|
|
synthesize_resize (GdkWindow *window)
|
|
{
|
|
GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
|
|
MirWindowParameters params;
|
|
|
|
if (!impl->mir_window)
|
|
return;
|
|
|
|
mir_window_get_parameters (impl->mir_window, ¶ms);
|
|
|
|
window->width = params.width;
|
|
window->height = params.height;
|
|
|
|
_gdk_window_update_size (window);
|
|
|
|
generate_configure_event (window, window->width, window->height);
|
|
}
|
|
|
|
static void
|
|
maybe_synthesize_resize (GdkWindow *window)
|
|
{
|
|
GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
|
|
MirWindowParameters params;
|
|
|
|
if (!impl->mir_window)
|
|
return;
|
|
|
|
mir_window_get_parameters (impl->mir_window, ¶ms);
|
|
|
|
if (params.width != window->width || params.height != window->height)
|
|
{
|
|
window->width = params.width;
|
|
window->height = params.height;
|
|
|
|
_gdk_window_update_size (window);
|
|
|
|
generate_configure_event (window, window->width, window->height);
|
|
}
|
|
}
|
|
|
|
static void
|
|
ensure_mir_window_full (GdkWindow *window,
|
|
MirBufferUsage buffer_usage)
|
|
{
|
|
GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
|
|
GdkMirWindowReference *window_ref;
|
|
MirWindowSpec *spec;
|
|
|
|
if (window->input_only)
|
|
return;
|
|
|
|
if (impl->mir_window)
|
|
{
|
|
if (impl->pending_spec_update)
|
|
update_window_spec (window);
|
|
return;
|
|
}
|
|
|
|
/* no destroy notify -- we must leak for now
|
|
* https://bugs.launchpad.net/mir/+bug/1324100
|
|
*/
|
|
window_ref = _gdk_mir_event_source_get_window_reference (window);
|
|
impl->buffer_usage = buffer_usage;
|
|
|
|
spec = create_spec (window, impl);
|
|
|
|
impl->mir_window = mir_create_window_sync (spec);
|
|
|
|
mir_window_spec_release (spec);
|
|
|
|
impl->pending_spec_update = FALSE;
|
|
impl->buffer_stream = mir_window_get_buffer_stream (impl->mir_window);
|
|
|
|
synthesize_resize (window);
|
|
|
|
/* FIXME: Ignore some events until shown */
|
|
mir_window_set_event_handler (impl->mir_window, event_cb, window_ref);
|
|
}
|
|
|
|
static void
|
|
ensure_mir_window (GdkWindow *window)
|
|
{
|
|
ensure_mir_window_full (window,
|
|
window->gl_paint_context ?
|
|
mir_buffer_usage_hardware :
|
|
mir_buffer_usage_software);
|
|
}
|
|
|
|
static void
|
|
ensure_no_mir_window (GdkWindow *window)
|
|
{
|
|
GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
|
|
|
|
if (impl->cairo_surface)
|
|
{
|
|
cairo_surface_finish (impl->cairo_surface);
|
|
g_clear_pointer (&impl->cairo_surface, cairo_surface_destroy);
|
|
}
|
|
|
|
if (window->gl_paint_context)
|
|
{
|
|
GdkDisplay *display = gdk_window_get_display (window);
|
|
EGLDisplay egl_display = _gdk_mir_display_get_egl_display (display);
|
|
|
|
if (impl->egl_surface)
|
|
{
|
|
eglDestroySurface (egl_display, impl->egl_surface);
|
|
impl->egl_surface = NULL;
|
|
}
|
|
|
|
if (impl->dummy_egl_surface)
|
|
{
|
|
eglDestroySurface (egl_display, impl->dummy_egl_surface);
|
|
impl->dummy_egl_surface = NULL;
|
|
}
|
|
}
|
|
|
|
g_clear_pointer (&impl->mir_window, mir_window_release_sync);
|
|
}
|
|
|
|
static void
|
|
send_buffer (GdkWindow *window)
|
|
{
|
|
GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
|
|
|
|
/* Send the completed buffer to Mir */
|
|
if (impl->mir_window)
|
|
mir_buffer_stream_swap_buffers_sync (mir_window_get_buffer_stream (impl->mir_window));
|
|
|
|
/* The Cairo context is no longer valid */
|
|
g_clear_pointer (&impl->cairo_surface, cairo_surface_destroy);
|
|
if (impl->pending_spec_update)
|
|
update_window_spec (window);
|
|
|
|
impl->pending_spec_update = FALSE;
|
|
|
|
maybe_synthesize_resize (window);
|
|
}
|
|
|
|
static cairo_surface_t *
|
|
gdk_mir_window_impl_ref_cairo_surface (GdkWindow *window)
|
|
{
|
|
GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
|
|
MirGraphicsRegion region;
|
|
cairo_format_t pixel_format = CAIRO_FORMAT_ARGB32;
|
|
cairo_surface_t *cairo_surface;
|
|
cairo_t *c;
|
|
|
|
if (impl->cairo_surface)
|
|
{
|
|
cairo_surface_reference (impl->cairo_surface);
|
|
return impl->cairo_surface;
|
|
}
|
|
|
|
ensure_mir_window (window);
|
|
|
|
if (!impl->mir_window)
|
|
return NULL;
|
|
|
|
if (window->gl_paint_context)
|
|
{
|
|
cairo_surface = cairo_image_surface_create (pixel_format, window->width, window->height);
|
|
cairo_surface_set_device_scale (cairo_surface, (double) impl->output_scale, (double) impl->output_scale);
|
|
}
|
|
else if (impl->visible)
|
|
{
|
|
mir_buffer_stream_get_graphics_region (mir_window_get_buffer_stream (impl->mir_window), ®ion);
|
|
|
|
switch (region.pixel_format)
|
|
{
|
|
case mir_pixel_format_abgr_8888:
|
|
g_warning ("pixel format ABGR 8888 not supported, using ARGB 8888");
|
|
pixel_format = CAIRO_FORMAT_ARGB32;
|
|
break;
|
|
case mir_pixel_format_xbgr_8888:
|
|
g_warning ("pixel format XBGR 8888 not supported, using XRGB 8888");
|
|
pixel_format = CAIRO_FORMAT_RGB24;
|
|
break;
|
|
case mir_pixel_format_argb_8888:
|
|
pixel_format = CAIRO_FORMAT_ARGB32;
|
|
break;
|
|
case mir_pixel_format_xrgb_8888:
|
|
pixel_format = CAIRO_FORMAT_RGB24;
|
|
break;
|
|
case mir_pixel_format_bgr_888:
|
|
g_error ("pixel format BGR 888 not supported");
|
|
break;
|
|
case mir_pixel_format_rgb_888:
|
|
g_error ("pixel format RGB 888 not supported");
|
|
break;
|
|
case mir_pixel_format_rgb_565:
|
|
pixel_format = CAIRO_FORMAT_RGB16_565;
|
|
break;
|
|
case mir_pixel_format_rgba_5551:
|
|
g_error ("pixel format RGBA 5551 not supported");
|
|
break;
|
|
case mir_pixel_format_rgba_4444:
|
|
g_error ("pixel format RGBA 4444 not supported");
|
|
break;
|
|
default:
|
|
g_error ("unknown pixel format");
|
|
break;
|
|
}
|
|
|
|
cairo_surface = cairo_image_surface_create_for_data ((unsigned char *) region.vaddr,
|
|
pixel_format,
|
|
region.width,
|
|
region.height,
|
|
region.stride);
|
|
cairo_surface_set_device_scale (cairo_surface, (double) impl->output_scale, (double) impl->output_scale);
|
|
}
|
|
else
|
|
cairo_surface = cairo_image_surface_create (pixel_format, 0, 0);
|
|
|
|
impl->cairo_surface = cairo_surface_reference (cairo_surface);
|
|
|
|
/* Draw background */
|
|
if (impl->background)
|
|
{
|
|
c = cairo_create (impl->cairo_surface);
|
|
cairo_set_source (c, impl->background);
|
|
cairo_paint (c);
|
|
cairo_destroy (c);
|
|
}
|
|
|
|
return cairo_surface;
|
|
}
|
|
|
|
static cairo_surface_t *
|
|
gdk_mir_window_impl_create_similar_image_surface (GdkWindow *window,
|
|
cairo_format_t format,
|
|
int width,
|
|
int height)
|
|
{
|
|
return cairo_image_surface_create (format, width, height);
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_finalize (GObject *object)
|
|
{
|
|
GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (object);
|
|
|
|
g_free (impl->title);
|
|
|
|
g_clear_pointer (&impl->background, cairo_pattern_destroy);
|
|
g_clear_pointer (&impl->mir_window, mir_window_release_sync);
|
|
g_clear_pointer (&impl->cairo_surface, cairo_surface_destroy);
|
|
g_clear_pointer (&impl->properties, g_hash_table_unref);
|
|
|
|
G_OBJECT_CLASS (gdk_mir_window_impl_parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_show (GdkWindow *window,
|
|
gboolean already_mapped)
|
|
{
|
|
GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
|
|
cairo_surface_t *s;
|
|
|
|
impl->visible = TRUE;
|
|
set_window_state (impl, mir_window_state_restored);
|
|
|
|
/* Make sure there's a window to see */
|
|
ensure_mir_window (window);
|
|
|
|
if (!window->gl_paint_context)
|
|
{
|
|
/* Make sure something is rendered and then show first frame */
|
|
s = gdk_mir_window_impl_ref_cairo_surface (window);
|
|
send_buffer (window);
|
|
cairo_surface_destroy (s);
|
|
}
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_hide (GdkWindow *window)
|
|
{
|
|
GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
|
|
|
|
impl->cursor_inside = FALSE;
|
|
impl->visible = FALSE;
|
|
|
|
set_window_state (impl, mir_window_state_hidden);
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_withdraw (GdkWindow *window)
|
|
{
|
|
GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
|
|
|
|
impl->cursor_inside = FALSE;
|
|
impl->visible = FALSE;
|
|
|
|
set_window_state (impl, mir_window_state_hidden);
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_raise (GdkWindow *window)
|
|
{
|
|
/* We don't support client window stacking */
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_lower (GdkWindow *window)
|
|
{
|
|
/* We don't support client window stacking */
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_restack_under (GdkWindow *window,
|
|
GList *native_siblings)
|
|
{
|
|
/* We don't support client window stacking */
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_restack_toplevel (GdkWindow *window,
|
|
GdkWindow *sibling,
|
|
gboolean above)
|
|
{
|
|
/* We don't support client window stacking */
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_move_resize (GdkWindow *window,
|
|
gboolean with_move,
|
|
gint x,
|
|
gint y,
|
|
gint width,
|
|
gint height)
|
|
{
|
|
GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
|
|
|
|
/* If resize requested then rebuild window */
|
|
if (width >= 0 && (window->width != width || window->height != height))
|
|
{
|
|
/* We accept any resize */
|
|
window->width = width;
|
|
window->height = height;
|
|
impl->pending_spec_update = TRUE;
|
|
}
|
|
|
|
/* Transient windows can move wherever they want */
|
|
if (with_move)
|
|
{
|
|
if (impl->has_rect || x != impl->transient_x || y != impl->transient_y)
|
|
{
|
|
impl->has_rect = FALSE;
|
|
impl->transient_x = x;
|
|
impl->transient_y = y;
|
|
if (!impl->pending_spec_update && impl->mir_window)
|
|
update_window_spec (window);
|
|
}
|
|
}
|
|
}
|
|
|
|
static MirPlacementGravity
|
|
get_mir_placement_gravity (GdkGravity gravity)
|
|
{
|
|
switch (gravity)
|
|
{
|
|
case GDK_GRAVITY_STATIC:
|
|
case GDK_GRAVITY_NORTH_WEST:
|
|
return mir_placement_gravity_northwest;
|
|
case GDK_GRAVITY_NORTH:
|
|
return mir_placement_gravity_north;
|
|
case GDK_GRAVITY_NORTH_EAST:
|
|
return mir_placement_gravity_northeast;
|
|
case GDK_GRAVITY_WEST:
|
|
return mir_placement_gravity_west;
|
|
case GDK_GRAVITY_CENTER:
|
|
return mir_placement_gravity_center;
|
|
case GDK_GRAVITY_EAST:
|
|
return mir_placement_gravity_east;
|
|
case GDK_GRAVITY_SOUTH_WEST:
|
|
return mir_placement_gravity_southwest;
|
|
case GDK_GRAVITY_SOUTH:
|
|
return mir_placement_gravity_south;
|
|
case GDK_GRAVITY_SOUTH_EAST:
|
|
return mir_placement_gravity_southeast;
|
|
}
|
|
|
|
g_warn_if_reached ();
|
|
|
|
return mir_placement_gravity_center;
|
|
}
|
|
|
|
static MirPlacementHints
|
|
get_mir_placement_hints (GdkAnchorHints hints)
|
|
{
|
|
MirPlacementHints mir_hints = 0;
|
|
|
|
if (hints & GDK_ANCHOR_FLIP_X)
|
|
mir_hints |= mir_placement_hints_flip_x;
|
|
|
|
if (hints & GDK_ANCHOR_FLIP_Y)
|
|
mir_hints |= mir_placement_hints_flip_y;
|
|
|
|
if (hints & GDK_ANCHOR_SLIDE_X)
|
|
mir_hints |= mir_placement_hints_slide_x;
|
|
|
|
if (hints & GDK_ANCHOR_SLIDE_Y)
|
|
mir_hints |= mir_placement_hints_slide_y;
|
|
|
|
if (hints & GDK_ANCHOR_RESIZE_X)
|
|
mir_hints |= mir_placement_hints_resize_x;
|
|
|
|
if (hints & GDK_ANCHOR_RESIZE_Y)
|
|
mir_hints |= mir_placement_hints_resize_y;
|
|
|
|
return mir_hints;
|
|
}
|
|
|
|
static gint
|
|
get_window_shadow_dx (GdkWindow *window,
|
|
GdkGravity window_anchor)
|
|
{
|
|
switch (window_anchor)
|
|
{
|
|
case GDK_GRAVITY_STATIC:
|
|
case GDK_GRAVITY_NORTH_WEST:
|
|
case GDK_GRAVITY_WEST:
|
|
case GDK_GRAVITY_SOUTH_WEST:
|
|
return -window->shadow_left;
|
|
|
|
case GDK_GRAVITY_NORTH:
|
|
case GDK_GRAVITY_CENTER:
|
|
case GDK_GRAVITY_SOUTH:
|
|
return (window->shadow_right - window->shadow_left) / 2;
|
|
|
|
case GDK_GRAVITY_NORTH_EAST:
|
|
case GDK_GRAVITY_EAST:
|
|
case GDK_GRAVITY_SOUTH_EAST:
|
|
return window->shadow_right;
|
|
}
|
|
|
|
g_warn_if_reached ();
|
|
|
|
return 0;
|
|
}
|
|
|
|
static gint
|
|
get_window_shadow_dy (GdkWindow *window,
|
|
GdkGravity window_anchor)
|
|
{
|
|
switch (window_anchor)
|
|
{
|
|
case GDK_GRAVITY_STATIC:
|
|
case GDK_GRAVITY_NORTH_WEST:
|
|
case GDK_GRAVITY_NORTH:
|
|
case GDK_GRAVITY_NORTH_EAST:
|
|
return -window->shadow_top;
|
|
|
|
case GDK_GRAVITY_WEST:
|
|
case GDK_GRAVITY_CENTER:
|
|
case GDK_GRAVITY_EAST:
|
|
return (window->shadow_bottom - window->shadow_top) / 2;
|
|
|
|
case GDK_GRAVITY_SOUTH_WEST:
|
|
case GDK_GRAVITY_SOUTH:
|
|
case GDK_GRAVITY_SOUTH_EAST:
|
|
return window->shadow_bottom;
|
|
}
|
|
|
|
g_warn_if_reached ();
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_move_to_rect (GdkWindow *window,
|
|
const GdkRectangle *rect,
|
|
GdkGravity rect_anchor,
|
|
GdkGravity window_anchor,
|
|
GdkAnchorHints anchor_hints,
|
|
gint rect_anchor_dx,
|
|
gint rect_anchor_dy)
|
|
{
|
|
GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
|
|
|
|
impl->has_rect = TRUE;
|
|
impl->rect = *rect;
|
|
impl->rect_anchor = get_mir_placement_gravity (rect_anchor);
|
|
impl->window_anchor = get_mir_placement_gravity (window_anchor);
|
|
impl->anchor_hints = get_mir_placement_hints (anchor_hints);
|
|
impl->rect_anchor_dx = rect_anchor_dx + get_window_shadow_dx (window, window_anchor);
|
|
impl->rect_anchor_dy = rect_anchor_dy + get_window_shadow_dy (window, window_anchor);
|
|
|
|
if (impl->mir_window && !impl->pending_spec_update)
|
|
update_window_spec (window);
|
|
}
|
|
|
|
static gint
|
|
get_mir_placement_gravity_x (MirPlacementGravity gravity)
|
|
{
|
|
switch (gravity)
|
|
{
|
|
case mir_placement_gravity_west:
|
|
case mir_placement_gravity_northwest:
|
|
case mir_placement_gravity_southwest:
|
|
return 0;
|
|
|
|
case mir_placement_gravity_center:
|
|
case mir_placement_gravity_north:
|
|
case mir_placement_gravity_south:
|
|
return 1;
|
|
|
|
case mir_placement_gravity_east:
|
|
case mir_placement_gravity_northeast:
|
|
case mir_placement_gravity_southeast:
|
|
return 2;
|
|
}
|
|
|
|
g_warn_if_reached ();
|
|
|
|
return 1;
|
|
}
|
|
|
|
static gint
|
|
get_mir_placement_gravity_y (MirPlacementGravity gravity)
|
|
{
|
|
switch (gravity)
|
|
{
|
|
case mir_placement_gravity_north:
|
|
case mir_placement_gravity_northwest:
|
|
case mir_placement_gravity_northeast:
|
|
return 0;
|
|
|
|
case mir_placement_gravity_center:
|
|
case mir_placement_gravity_west:
|
|
case mir_placement_gravity_east:
|
|
return 1;
|
|
|
|
case mir_placement_gravity_south:
|
|
case mir_placement_gravity_southwest:
|
|
case mir_placement_gravity_southeast:
|
|
return 2;
|
|
}
|
|
|
|
g_warn_if_reached ();
|
|
|
|
return 1;
|
|
}
|
|
|
|
static GdkRectangle
|
|
get_unflipped_rect (const GdkRectangle *rect,
|
|
gint width,
|
|
gint height,
|
|
MirPlacementGravity rect_anchor,
|
|
MirPlacementGravity window_anchor,
|
|
gint rect_anchor_dx,
|
|
gint rect_anchor_dy)
|
|
{
|
|
GdkRectangle unflipped_rect;
|
|
|
|
unflipped_rect.x = rect->x;
|
|
unflipped_rect.x += rect->width * get_mir_placement_gravity_x (rect_anchor) / 2;
|
|
unflipped_rect.x -= width * get_mir_placement_gravity_x (window_anchor) / 2;
|
|
unflipped_rect.x += rect_anchor_dx;
|
|
unflipped_rect.y = rect->y;
|
|
unflipped_rect.y += rect->height * get_mir_placement_gravity_y (rect_anchor) / 2;
|
|
unflipped_rect.y -= height * get_mir_placement_gravity_y (window_anchor) / 2;
|
|
unflipped_rect.y += rect_anchor_dy;
|
|
unflipped_rect.width = width;
|
|
unflipped_rect.height = height;
|
|
|
|
return unflipped_rect;
|
|
}
|
|
|
|
static MirPlacementGravity
|
|
get_opposite_mir_placement_gravity (MirPlacementGravity gravity)
|
|
{
|
|
switch (gravity)
|
|
{
|
|
case mir_placement_gravity_center:
|
|
return mir_placement_gravity_center;
|
|
case mir_placement_gravity_west:
|
|
return mir_placement_gravity_east;
|
|
case mir_placement_gravity_east:
|
|
return mir_placement_gravity_west;
|
|
case mir_placement_gravity_north:
|
|
return mir_placement_gravity_south;
|
|
case mir_placement_gravity_south:
|
|
return mir_placement_gravity_north;
|
|
case mir_placement_gravity_northwest:
|
|
return mir_placement_gravity_southeast;
|
|
case mir_placement_gravity_northeast:
|
|
return mir_placement_gravity_southwest;
|
|
case mir_placement_gravity_southwest:
|
|
return mir_placement_gravity_northeast;
|
|
case mir_placement_gravity_southeast:
|
|
return mir_placement_gravity_northwest;
|
|
}
|
|
|
|
g_warn_if_reached ();
|
|
|
|
return gravity;
|
|
}
|
|
|
|
static gint
|
|
get_anchor_x (const GdkRectangle *rect,
|
|
MirPlacementGravity anchor)
|
|
{
|
|
return rect->x + rect->width * get_mir_placement_gravity_x (anchor) / 2;
|
|
}
|
|
|
|
static gint
|
|
get_anchor_y (const GdkRectangle *rect,
|
|
MirPlacementGravity anchor)
|
|
{
|
|
return rect->y + rect->height * get_mir_placement_gravity_y (anchor) / 2;
|
|
}
|
|
|
|
void
|
|
_gdk_mir_window_set_final_rect (GdkWindow *window,
|
|
MirRectangle rect)
|
|
{
|
|
GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
|
|
GdkRectangle best_rect;
|
|
GdkRectangle worst_rect;
|
|
GdkRectangle flipped_rect;
|
|
GdkRectangle final_rect;
|
|
gboolean flipped_x = FALSE;
|
|
gboolean flipped_y = FALSE;
|
|
gint test_position;
|
|
gint final_position;
|
|
gint unflipped_offset;
|
|
gint flipped_offset;
|
|
|
|
if (!impl->has_rect)
|
|
return;
|
|
|
|
best_rect = get_unflipped_rect (&impl->rect,
|
|
window->width,
|
|
window->height,
|
|
impl->rect_anchor,
|
|
impl->window_anchor,
|
|
impl->rect_anchor_dx,
|
|
impl->rect_anchor_dy);
|
|
|
|
worst_rect = get_unflipped_rect (&impl->rect,
|
|
window->width,
|
|
window->height,
|
|
get_opposite_mir_placement_gravity (impl->rect_anchor),
|
|
get_opposite_mir_placement_gravity (impl->window_anchor),
|
|
-impl->rect_anchor_dx,
|
|
-impl->rect_anchor_dy);
|
|
|
|
flipped_rect.x = best_rect.x;
|
|
flipped_rect.y = best_rect.y;
|
|
flipped_rect.width = window->width;
|
|
flipped_rect.height = window->height;
|
|
|
|
final_rect.x = rect.left - (impl->mir_rect.left - impl->rect.x);
|
|
final_rect.y = rect.top - (impl->mir_rect.top - impl->rect.y);
|
|
final_rect.width = rect.width;
|
|
final_rect.height = rect.height;
|
|
|
|
if (impl->anchor_hints & mir_placement_hints_flip_x)
|
|
{
|
|
test_position = get_anchor_x (&best_rect, impl->window_anchor);
|
|
final_position = get_anchor_x (&final_rect, impl->window_anchor);
|
|
unflipped_offset = final_position - test_position;
|
|
|
|
test_position = get_anchor_x (&worst_rect, get_opposite_mir_placement_gravity (impl->window_anchor));
|
|
final_position = get_anchor_x (&final_rect, get_opposite_mir_placement_gravity (impl->window_anchor));
|
|
flipped_offset = final_position - test_position;
|
|
|
|
if (ABS (flipped_offset) < ABS (unflipped_offset))
|
|
{
|
|
flipped_rect.x = worst_rect.x;
|
|
flipped_x = TRUE;
|
|
}
|
|
}
|
|
|
|
if (impl->anchor_hints & mir_placement_hints_flip_y)
|
|
{
|
|
test_position = get_anchor_y (&best_rect, impl->window_anchor);
|
|
final_position = get_anchor_y (&final_rect, impl->window_anchor);
|
|
unflipped_offset = final_position - test_position;
|
|
|
|
test_position = get_anchor_y (&worst_rect, get_opposite_mir_placement_gravity (impl->window_anchor));
|
|
final_position = get_anchor_y (&final_rect, get_opposite_mir_placement_gravity (impl->window_anchor));
|
|
flipped_offset = final_position - test_position;
|
|
|
|
if (ABS (flipped_offset) < ABS (unflipped_offset))
|
|
{
|
|
flipped_rect.y = worst_rect.y;
|
|
flipped_y = TRUE;
|
|
}
|
|
}
|
|
|
|
g_signal_emit_by_name (window,
|
|
"moved-to-rect",
|
|
&flipped_rect,
|
|
&final_rect,
|
|
flipped_x,
|
|
flipped_y);
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_set_background (GdkWindow *window,
|
|
cairo_pattern_t *pattern)
|
|
{
|
|
GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
|
|
|
|
if (impl->background)
|
|
cairo_pattern_destroy (impl->background);
|
|
impl->background = cairo_pattern_reference (pattern);
|
|
}
|
|
|
|
static GdkEventMask
|
|
gdk_mir_window_impl_get_events (GdkWindow *window)
|
|
{
|
|
return window->event_mask;
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_set_events (GdkWindow *window,
|
|
GdkEventMask event_mask)
|
|
{
|
|
/* We send all events and let GDK decide */
|
|
}
|
|
|
|
static gboolean
|
|
gdk_mir_window_impl_reparent (GdkWindow *window,
|
|
GdkWindow *new_parent,
|
|
gint x,
|
|
gint y)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_set_device_cursor (GdkWindow *window,
|
|
GdkDevice *device,
|
|
GdkCursor *cursor)
|
|
{
|
|
GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
|
|
MirConnection *connection = gdk_mir_display_get_mir_connection (impl->display);
|
|
MirWindowSpec *spec;
|
|
const gchar *cursor_name;
|
|
|
|
if (cursor)
|
|
cursor_name = _gdk_mir_cursor_get_name (cursor);
|
|
else
|
|
cursor_name = mir_default_cursor_name;
|
|
|
|
spec = mir_create_window_spec (connection);
|
|
mir_window_spec_set_cursor_name (spec, cursor_name);
|
|
mir_window_apply_spec (impl->mir_window, spec);
|
|
mir_window_spec_release (spec);
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_get_geometry (GdkWindow *window,
|
|
gint *x,
|
|
gint *y,
|
|
gint *width,
|
|
gint *height)
|
|
{
|
|
if (x)
|
|
*x = 0; // FIXME
|
|
if (y)
|
|
*y = 0; // FIXME
|
|
if (width)
|
|
*width = window->width;
|
|
if (height)
|
|
*height = window->height;
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_get_root_coords (GdkWindow *window,
|
|
gint x,
|
|
gint y,
|
|
gint *root_x,
|
|
gint *root_y)
|
|
{
|
|
if (root_x)
|
|
*root_x = x; // FIXME
|
|
if (root_y)
|
|
*root_y = y; // FIXME
|
|
}
|
|
|
|
static gboolean
|
|
gdk_mir_window_impl_get_device_state (GdkWindow *window,
|
|
GdkDevice *device,
|
|
gdouble *x,
|
|
gdouble *y,
|
|
GdkModifierType *mask)
|
|
{
|
|
GdkWindow *child;
|
|
|
|
_gdk_device_query_state (device, window, NULL, &child, NULL, NULL, x, y, mask);
|
|
|
|
return child != NULL;
|
|
}
|
|
|
|
static gboolean
|
|
gdk_mir_window_impl_begin_paint (GdkWindow *window)
|
|
{
|
|
/* Indicate we are ready to be drawn onto directly? */
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_end_paint (GdkWindow *window)
|
|
{
|
|
GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
|
|
|
|
if (impl->visible && !window->current_paint.use_gl)
|
|
send_buffer (window);
|
|
}
|
|
|
|
static cairo_region_t *
|
|
gdk_mir_window_impl_get_shape (GdkWindow *window)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
static cairo_region_t *
|
|
gdk_mir_window_impl_get_input_shape (GdkWindow *window)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_shape_combine_region (GdkWindow *window,
|
|
const cairo_region_t *shape_region,
|
|
gint offset_x,
|
|
gint offset_y)
|
|
{
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_input_shape_combine_region (GdkWindow *window,
|
|
const cairo_region_t *shape_region,
|
|
gint offset_x,
|
|
gint offset_y)
|
|
{
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_destroy (GdkWindow *window,
|
|
gboolean recursing,
|
|
gboolean foreign_destroy)
|
|
{
|
|
GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
|
|
|
|
impl->visible = FALSE;
|
|
ensure_no_mir_window (window);
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_destroy_foreign (GdkWindow *window)
|
|
{
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_focus (GdkWindow *window,
|
|
guint32 timestamp)
|
|
{
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_set_type_hint (GdkWindow *window,
|
|
GdkWindowTypeHint hint)
|
|
{
|
|
GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
|
|
|
|
if (type_hint_differs (hint, impl->type_hint))
|
|
{
|
|
impl->type_hint = hint;
|
|
|
|
if (impl->mir_window && !impl->pending_spec_update)
|
|
update_window_spec (window);
|
|
}
|
|
}
|
|
|
|
static GdkWindowTypeHint
|
|
gdk_mir_window_impl_get_type_hint (GdkWindow *window)
|
|
{
|
|
GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
|
|
|
|
return impl->type_hint;
|
|
}
|
|
|
|
void
|
|
gdk_mir_window_impl_set_modal_hint (GdkWindow *window,
|
|
gboolean modal)
|
|
{
|
|
GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
|
|
|
|
if (modal != impl->modal)
|
|
{
|
|
impl->modal = modal;
|
|
|
|
if (impl->mir_window && !impl->pending_spec_update)
|
|
update_window_spec (window);
|
|
}
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_set_skip_taskbar_hint (GdkWindow *window,
|
|
gboolean skips_taskbar)
|
|
{
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_set_skip_pager_hint (GdkWindow *window,
|
|
gboolean skips_pager)
|
|
{
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_set_urgency_hint (GdkWindow *window,
|
|
gboolean urgent)
|
|
{
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_set_geometry_hints (GdkWindow *window,
|
|
const GdkGeometry *geometry,
|
|
GdkWindowHints geom_mask)
|
|
{
|
|
GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
|
|
MirConnection *connection = gdk_mir_display_get_mir_connection (impl->display);
|
|
MirWindowSpec *spec;
|
|
|
|
impl->geometry_hints = *geometry;
|
|
impl->geometry_mask = geom_mask;
|
|
|
|
if (impl->mir_window && !impl->pending_spec_update)
|
|
{
|
|
spec = mir_create_window_spec (connection);
|
|
apply_geometry_hints (spec, impl);
|
|
mir_window_apply_spec (impl->mir_window, spec);
|
|
mir_window_spec_release (spec);
|
|
}
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_set_title (GdkWindow *window,
|
|
const gchar *title)
|
|
{
|
|
GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
|
|
MirConnection *connection = gdk_mir_display_get_mir_connection (impl->display);
|
|
MirWindowSpec *spec;
|
|
|
|
g_free (impl->title);
|
|
impl->title = g_strdup (title);
|
|
|
|
if (impl->mir_window && !impl->pending_spec_update)
|
|
{
|
|
spec = mir_create_window_spec (connection);
|
|
mir_window_spec_set_name (spec, impl->title);
|
|
mir_window_apply_spec (impl->mir_window, spec);
|
|
mir_window_spec_release (spec);
|
|
}
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_set_role (GdkWindow *window,
|
|
const gchar *role)
|
|
{
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_set_startup_id (GdkWindow *window,
|
|
const gchar *startup_id)
|
|
{
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_set_transient_for (GdkWindow *window,
|
|
GdkWindow *parent)
|
|
{
|
|
GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
|
|
|
|
if (impl->transient_for == parent)
|
|
return;
|
|
|
|
/* Link this window to the parent */
|
|
impl->transient_for = parent;
|
|
|
|
if (impl->mir_window && !impl->pending_spec_update)
|
|
update_window_spec (window);
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_get_frame_extents (GdkWindow *window,
|
|
GdkRectangle *rect)
|
|
{
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_set_override_redirect (GdkWindow *window,
|
|
gboolean override_redirect)
|
|
{
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_set_accept_focus (GdkWindow *window,
|
|
gboolean accept_focus)
|
|
{
|
|
/* Mir clients cannot control focus */
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_set_focus_on_map (GdkWindow *window,
|
|
gboolean focus_on_map)
|
|
{
|
|
/* Mir clients cannot control focus */
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_set_icon_list (GdkWindow *window,
|
|
GList *pixbufs)
|
|
{
|
|
// ??
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_set_icon_name (GdkWindow *window,
|
|
const gchar *name)
|
|
{
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_iconify (GdkWindow *window)
|
|
{
|
|
/* We don't support iconification */
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_deiconify (GdkWindow *window)
|
|
{
|
|
/* We don't support iconification */
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_stick (GdkWindow *window)
|
|
{
|
|
/* We do not support stick/unstick in Mir */
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_unstick (GdkWindow *window)
|
|
{
|
|
/* We do not support stick/unstick in Mir */
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_maximize (GdkWindow *window)
|
|
{
|
|
set_window_state (GDK_MIR_WINDOW_IMPL (window->impl), mir_window_state_maximized);
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_unmaximize (GdkWindow *window)
|
|
{
|
|
set_window_state (GDK_MIR_WINDOW_IMPL (window->impl), mir_window_state_restored);
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_fullscreen (GdkWindow *window)
|
|
{
|
|
set_window_state (GDK_MIR_WINDOW_IMPL (window->impl), mir_window_state_fullscreen);
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_apply_fullscreen_mode (GdkWindow *window)
|
|
{
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_unfullscreen (GdkWindow *window)
|
|
{
|
|
set_window_state (GDK_MIR_WINDOW_IMPL (window->impl), mir_window_state_restored);
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_set_keep_above (GdkWindow *window,
|
|
gboolean setting)
|
|
{
|
|
/* We do not support keep above/below in Mir */
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_set_keep_below (GdkWindow *window,
|
|
gboolean setting)
|
|
{
|
|
/* We do not support keep above/below in Mir */
|
|
}
|
|
|
|
static GdkWindow *
|
|
gdk_mir_window_impl_get_group (GdkWindow *window)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_set_group (GdkWindow *window,
|
|
GdkWindow *leader)
|
|
{
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_set_decorations (GdkWindow *window,
|
|
GdkWMDecoration decorations)
|
|
{
|
|
}
|
|
|
|
static gboolean
|
|
gdk_mir_window_impl_get_decorations (GdkWindow *window,
|
|
GdkWMDecoration *decorations)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_set_functions (GdkWindow *window,
|
|
GdkWMFunction functions)
|
|
{
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_begin_resize_drag (GdkWindow *window,
|
|
GdkWindowEdge edge,
|
|
GdkDevice *device,
|
|
gint button,
|
|
gint root_x,
|
|
gint root_y,
|
|
guint32 timestamp)
|
|
{
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_begin_move_drag (GdkWindow *window,
|
|
GdkDevice *device,
|
|
gint button,
|
|
gint root_x,
|
|
gint root_y,
|
|
guint32 timestamp)
|
|
{
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_enable_synchronized_configure (GdkWindow *window)
|
|
{
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_configure_finished (GdkWindow *window)
|
|
{
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_set_opacity (GdkWindow *window,
|
|
gdouble opacity)
|
|
{
|
|
// FIXME
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_set_composited (GdkWindow *window,
|
|
gboolean composited)
|
|
{
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_destroy_notify (GdkWindow *window)
|
|
{
|
|
}
|
|
|
|
static GdkDragProtocol
|
|
gdk_mir_window_impl_get_drag_protocol (GdkWindow *window,
|
|
GdkWindow **target)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_register_dnd (GdkWindow *window)
|
|
{
|
|
}
|
|
|
|
static GdkDragContext *
|
|
gdk_mir_window_impl_drag_begin (GdkWindow *window,
|
|
GdkDevice *device,
|
|
GList *targets,
|
|
gint x_root,
|
|
gint y_root)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_process_updates_recurse (GdkWindow *window,
|
|
cairo_region_t *region)
|
|
{
|
|
cairo_rectangle_int_t rectangle;
|
|
|
|
/* We redraw the whole region, but we should track the buffers and only redraw what has changed since we sent this buffer */
|
|
rectangle.x = 0;
|
|
rectangle.y = 0;
|
|
rectangle.width = window->width;
|
|
rectangle.height = window->height;
|
|
cairo_region_union_rectangle (region, &rectangle);
|
|
|
|
_gdk_window_process_updates_recurse (window, region);
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_sync_rendering (GdkWindow *window)
|
|
{
|
|
// FIXME: Only used for benchmarking
|
|
}
|
|
|
|
static gboolean
|
|
gdk_mir_window_impl_simulate_key (GdkWindow *window,
|
|
gint x,
|
|
gint y,
|
|
guint keyval,
|
|
GdkModifierType modifiers,
|
|
GdkEventType key_pressrelease)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
gdk_mir_window_impl_simulate_button (GdkWindow *window,
|
|
gint x,
|
|
gint y,
|
|
guint button,
|
|
GdkModifierType modifiers,
|
|
GdkEventType button_pressrelease)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
gdk_mir_window_impl_get_property (GdkWindow *window,
|
|
GdkAtom property,
|
|
GdkAtom type,
|
|
gulong offset,
|
|
gulong length,
|
|
gint pdelete,
|
|
GdkAtom *actual_type,
|
|
gint *actual_format,
|
|
gint *actual_length,
|
|
guchar **data)
|
|
{
|
|
GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
|
|
GdkMirProperty *mir_property;
|
|
GdkAtom dummy_actual_type;
|
|
gint dummy_actual_format;
|
|
gint dummy_actual_length;
|
|
guint width;
|
|
|
|
if (!actual_type)
|
|
actual_type = &dummy_actual_type;
|
|
if (!actual_format)
|
|
actual_format = &dummy_actual_format;
|
|
if (!actual_length)
|
|
actual_length = &dummy_actual_length;
|
|
|
|
*actual_type = GDK_NONE;
|
|
*actual_format = 0;
|
|
*actual_length = 0;
|
|
|
|
if (data)
|
|
*data = NULL;
|
|
|
|
mir_property = g_hash_table_lookup (impl->properties, property);
|
|
|
|
if (!mir_property)
|
|
return FALSE;
|
|
|
|
width = g_array_get_element_size (mir_property->array);
|
|
*actual_type = mir_property->type;
|
|
*actual_format = 8 * width;
|
|
|
|
/* ICCCM 2.7: GdkAtoms can be 64-bit, but ATOMs and ATOM_PAIRs have format 32 */
|
|
if (*actual_type == GDK_SELECTION_TYPE_ATOM || *actual_type == gdk_atom_intern_static_string ("ATOM_PAIR"))
|
|
*actual_format = 32;
|
|
|
|
if (type != GDK_NONE && type != mir_property->type)
|
|
return FALSE;
|
|
|
|
offset *= 4;
|
|
|
|
/* round up to next nearest multiple of width */
|
|
if (length < G_MAXULONG - width + 1)
|
|
length = (length - 1 + width) / width * width;
|
|
else
|
|
length = G_MAXULONG / width * width;
|
|
|
|
/* we're skipping the first offset bytes */
|
|
if (length > mir_property->array->len * width - offset)
|
|
length = mir_property->array->len * width - offset;
|
|
|
|
/* leave room for null terminator */
|
|
if (length > G_MAXULONG - width)
|
|
length -= width;
|
|
|
|
*actual_length = length;
|
|
|
|
if (data)
|
|
{
|
|
*data = g_memdup (mir_property->array->data + offset, length + width);
|
|
memset (*data + length, 0, width);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
request_targets (GdkWindow *window,
|
|
const GdkAtom *available_targets,
|
|
gint n_available_targets)
|
|
{
|
|
GArray *requested_targets;
|
|
GdkAtom target_pair[2];
|
|
gchar *target_location;
|
|
GdkEvent *event;
|
|
gint i;
|
|
|
|
requested_targets = g_array_sized_new (TRUE, FALSE, sizeof (GdkAtom), 2 * n_available_targets);
|
|
|
|
for (i = 0; i < n_available_targets; i++)
|
|
{
|
|
target_pair[0] = available_targets[i];
|
|
|
|
if (target_pair[0] == gdk_atom_intern_static_string ("TIMESTAMP") ||
|
|
target_pair[0] == gdk_atom_intern_static_string ("TARGETS") ||
|
|
target_pair[0] == gdk_atom_intern_static_string ("MULTIPLE") ||
|
|
target_pair[0] == gdk_atom_intern_static_string ("SAVE_TARGETS"))
|
|
continue;
|
|
|
|
target_location = g_strdup_printf ("REQUESTED_TARGET_U%u", requested_targets->len / 2);
|
|
target_pair[1] = gdk_atom_intern (target_location, FALSE);
|
|
g_free (target_location);
|
|
|
|
g_array_append_vals (requested_targets, target_pair, 2);
|
|
}
|
|
|
|
gdk_property_delete (window, gdk_atom_intern_static_string ("AVAILABLE_TARGETS"));
|
|
gdk_property_delete (window, gdk_atom_intern_static_string ("REQUESTED_TARGETS"));
|
|
|
|
gdk_property_change (window,
|
|
gdk_atom_intern_static_string ("REQUESTED_TARGETS"),
|
|
GDK_SELECTION_TYPE_ATOM,
|
|
8 * sizeof (GdkAtom),
|
|
GDK_PROP_MODE_REPLACE,
|
|
(const guchar *) requested_targets->data,
|
|
requested_targets->len);
|
|
|
|
g_array_unref (requested_targets);
|
|
|
|
event = gdk_event_new (GDK_SELECTION_REQUEST);
|
|
event->selection.window = g_object_ref (window);
|
|
event->selection.send_event = FALSE;
|
|
event->selection.selection = GDK_SELECTION_CLIPBOARD;
|
|
event->selection.target = gdk_atom_intern_static_string ("MULTIPLE");
|
|
event->selection.property = gdk_atom_intern_static_string ("REQUESTED_TARGETS");
|
|
event->selection.time = GDK_CURRENT_TIME;
|
|
event->selection.requestor = g_object_ref (window);
|
|
|
|
gdk_event_put (event);
|
|
gdk_event_free (event);
|
|
}
|
|
|
|
static void
|
|
create_paste (GdkWindow *window,
|
|
const GdkAtom *requested_targets,
|
|
gint n_requested_targets)
|
|
{
|
|
GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
|
|
GPtrArray *paste_formats;
|
|
GArray *paste_header;
|
|
GByteArray *paste_data;
|
|
gint sizes[4];
|
|
GdkMirProperty *mir_property;
|
|
const gchar *paste_format;
|
|
gint i;
|
|
|
|
paste_formats = g_ptr_array_new_full (n_requested_targets, g_free);
|
|
paste_header = g_array_sized_new (FALSE, FALSE, sizeof (gint), 1 + 4 * n_requested_targets);
|
|
paste_data = g_byte_array_new ();
|
|
|
|
g_array_append_val (paste_header, sizes[0]);
|
|
|
|
for (i = 0; i < n_requested_targets; i++)
|
|
{
|
|
if (requested_targets[i] == GDK_NONE)
|
|
continue;
|
|
|
|
mir_property = g_hash_table_lookup (impl->properties, requested_targets[i]);
|
|
|
|
if (!mir_property)
|
|
continue;
|
|
|
|
paste_format = _gdk_atom_name_const (mir_property->type);
|
|
|
|
/* skip non-MIME targets */
|
|
if (!strchr (paste_format, '/'))
|
|
{
|
|
g_hash_table_remove (impl->properties, requested_targets[i]);
|
|
continue;
|
|
}
|
|
|
|
sizes[0] = paste_data->len;
|
|
sizes[1] = strlen (paste_format);
|
|
sizes[2] = sizes[0] + sizes[1];
|
|
sizes[3] = mir_property->array->len * g_array_get_element_size (mir_property->array);
|
|
|
|
g_ptr_array_add (paste_formats, g_strdup (paste_format));
|
|
g_array_append_vals (paste_header, sizes, 4);
|
|
g_byte_array_append (paste_data, (const guint8 *) paste_format, sizes[1]);
|
|
g_byte_array_append (paste_data, (const guint8 *) mir_property->array->data, sizes[3]);
|
|
|
|
g_hash_table_remove (impl->properties, requested_targets[i]);
|
|
}
|
|
|
|
gdk_property_delete (window, gdk_atom_intern_static_string ("REQUESTED_TARGETS"));
|
|
|
|
g_array_index (paste_header, gint, 0) = paste_formats->len;
|
|
|
|
for (i = 0; i < paste_formats->len; i++)
|
|
{
|
|
g_array_index (paste_header, gint, 1 + 4 * i) += paste_header->len * sizeof (gint);
|
|
g_array_index (paste_header, gint, 3 + 4 * i) += paste_header->len * sizeof (gint);
|
|
}
|
|
|
|
g_byte_array_prepend (paste_data,
|
|
(const guint8 *) paste_header->data,
|
|
paste_header->len * g_array_get_element_size (paste_header));
|
|
|
|
g_ptr_array_add (paste_formats, NULL);
|
|
|
|
_gdk_mir_display_create_paste (gdk_window_get_display (window),
|
|
(const gchar * const *) paste_formats->pdata,
|
|
paste_data->data,
|
|
paste_data->len);
|
|
|
|
g_byte_array_unref (paste_data);
|
|
g_array_unref (paste_header);
|
|
g_ptr_array_unref (paste_formats);
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_change_property (GdkWindow *window,
|
|
GdkAtom property,
|
|
GdkAtom type,
|
|
gint format,
|
|
GdkPropMode mode,
|
|
const guchar *data,
|
|
gint n_elements)
|
|
{
|
|
GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
|
|
GdkMirProperty *mir_property;
|
|
gboolean existed;
|
|
GdkEvent *event;
|
|
|
|
/* ICCCM 2.7: ATOMs and ATOM_PAIRs have format 32, but GdkAtoms can be 64-bit */
|
|
if (type == GDK_SELECTION_TYPE_ATOM || type == gdk_atom_intern_static_string ("ATOM_PAIR"))
|
|
format = 8 * sizeof (GdkAtom);
|
|
|
|
if (mode != GDK_PROP_MODE_REPLACE)
|
|
{
|
|
mir_property = g_hash_table_lookup (impl->properties, property);
|
|
existed = mir_property != NULL;
|
|
}
|
|
else
|
|
{
|
|
mir_property = NULL;
|
|
existed = g_hash_table_contains (impl->properties, property);
|
|
}
|
|
|
|
if (!mir_property)
|
|
{
|
|
/* format is measured in bits, but we need to know this in bytes */
|
|
mir_property = gdk_mir_property_new (type, format / 8, n_elements);
|
|
g_hash_table_insert (impl->properties, property, mir_property);
|
|
}
|
|
|
|
/* format is measured in bits, but we need to know this in bytes */
|
|
if (type != mir_property->type || format / 8 != g_array_get_element_size (mir_property->array))
|
|
return;
|
|
|
|
if (mode == GDK_PROP_MODE_PREPEND)
|
|
g_array_prepend_vals (mir_property->array, data, n_elements);
|
|
else
|
|
g_array_append_vals (mir_property->array, data, n_elements);
|
|
|
|
event = gdk_event_new (GDK_PROPERTY_NOTIFY);
|
|
event->property.window = g_object_ref (window);
|
|
event->property.send_event = FALSE;
|
|
event->property.atom = property;
|
|
event->property.time = GDK_CURRENT_TIME;
|
|
event->property.state = GDK_PROPERTY_NEW_VALUE;
|
|
|
|
gdk_event_put (event);
|
|
gdk_event_free (event);
|
|
|
|
if (property == gdk_atom_intern_static_string ("AVAILABLE_TARGETS"))
|
|
request_targets (window, (const GdkAtom *) data, n_elements);
|
|
else if (property == gdk_atom_intern_static_string ("REQUESTED_TARGETS") && existed)
|
|
create_paste (window, (const GdkAtom *) data, n_elements);
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_delete_property (GdkWindow *window,
|
|
GdkAtom property)
|
|
{
|
|
GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
|
|
GdkEvent *event;
|
|
|
|
if (g_hash_table_remove (impl->properties, property))
|
|
{
|
|
event = gdk_event_new (GDK_PROPERTY_NOTIFY);
|
|
event->property.window = g_object_ref (window);
|
|
event->property.send_event = FALSE;
|
|
event->property.atom = property;
|
|
event->property.time = GDK_CURRENT_TIME;
|
|
event->property.state = GDK_PROPERTY_DELETE;
|
|
|
|
gdk_event_put (event);
|
|
gdk_event_free (event);
|
|
}
|
|
}
|
|
|
|
static gint
|
|
gdk_mir_window_impl_get_scale_factor (GdkWindow *window)
|
|
{
|
|
GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
|
|
return impl->output_scale;
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_set_opaque_region (GdkWindow *window,
|
|
cairo_region_t *region)
|
|
{
|
|
/* FIXME: An optimisation to tell the compositor which regions of the window are fully transparent */
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_set_shadow_width (GdkWindow *window,
|
|
gint left,
|
|
gint right,
|
|
gint top,
|
|
gint bottom)
|
|
{
|
|
}
|
|
|
|
static gboolean
|
|
find_eglconfig_for_window (GdkWindow *window,
|
|
EGLConfig *egl_config_out,
|
|
GError **error)
|
|
{
|
|
GdkDisplay *display = gdk_window_get_display (window);
|
|
EGLDisplay *egl_display = _gdk_mir_display_get_egl_display (display);
|
|
GdkVisual *visual = gdk_window_get_visual (window);
|
|
EGLint attrs[MAX_EGL_ATTRS];
|
|
EGLint count;
|
|
EGLConfig *configs;
|
|
gboolean use_rgba;
|
|
|
|
int i = 0;
|
|
|
|
attrs[i++] = EGL_SURFACE_TYPE;
|
|
attrs[i++] = EGL_WINDOW_BIT;
|
|
|
|
attrs[i++] = EGL_COLOR_BUFFER_TYPE;
|
|
attrs[i++] = EGL_RGB_BUFFER;
|
|
|
|
attrs[i++] = EGL_RED_SIZE;
|
|
attrs[i++] = 1;
|
|
attrs[i++] = EGL_GREEN_SIZE;
|
|
attrs[i++] = 1;
|
|
attrs[i++] = EGL_BLUE_SIZE;
|
|
attrs[i++] = 1;
|
|
|
|
use_rgba = (visual == gdk_screen_get_rgba_visual (gdk_display_get_default_screen (display)));
|
|
|
|
if (use_rgba)
|
|
{
|
|
attrs[i++] = EGL_ALPHA_SIZE;
|
|
attrs[i++] = 1;
|
|
}
|
|
else
|
|
{
|
|
attrs[i++] = EGL_ALPHA_SIZE;
|
|
attrs[i++] = 0;
|
|
}
|
|
|
|
attrs[i++] = EGL_NONE;
|
|
g_assert (i < MAX_EGL_ATTRS);
|
|
|
|
if (!eglChooseConfig (egl_display, attrs, NULL, 0, &count) || count < 1)
|
|
{
|
|
g_set_error_literal (error, GDK_GL_ERROR,
|
|
GDK_GL_ERROR_UNSUPPORTED_FORMAT,
|
|
_("No available configurations for the given pixel format"));
|
|
return FALSE;
|
|
}
|
|
|
|
configs = g_new (EGLConfig, count);
|
|
|
|
if (!eglChooseConfig (egl_display, attrs, configs, count, &count) || count < 1)
|
|
{
|
|
g_set_error_literal (error, GDK_GL_ERROR,
|
|
GDK_GL_ERROR_UNSUPPORTED_FORMAT,
|
|
_("No available configurations for the given pixel format"));
|
|
return FALSE;
|
|
}
|
|
|
|
/* Pick first valid configuration i guess? */
|
|
|
|
if (egl_config_out != NULL)
|
|
*egl_config_out = configs[0];
|
|
|
|
g_free (configs);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static GdkGLContext *
|
|
gdk_mir_window_impl_create_gl_context (GdkWindow *window,
|
|
gboolean attached,
|
|
GdkGLContext *share,
|
|
GError **error)
|
|
{
|
|
GdkDisplay *display = gdk_window_get_display (window);
|
|
GdkMirGLContext *context;
|
|
EGLConfig config;
|
|
|
|
if (!_gdk_mir_display_init_egl_display (display))
|
|
{
|
|
g_set_error_literal (error, GDK_GL_ERROR,
|
|
GDK_GL_ERROR_NOT_AVAILABLE,
|
|
_("No GL implementation is available"));
|
|
return NULL;
|
|
}
|
|
|
|
if (!_gdk_mir_display_have_egl_khr_create_context (display))
|
|
{
|
|
g_set_error_literal (error, GDK_GL_ERROR,
|
|
GDK_GL_ERROR_UNSUPPORTED_PROFILE,
|
|
_("3.2 core GL profile is not available on EGL implementation"));
|
|
return NULL;
|
|
}
|
|
|
|
if (!find_eglconfig_for_window (window, &config, error))
|
|
return NULL;
|
|
|
|
context = g_object_new (GDK_TYPE_MIR_GL_CONTEXT,
|
|
"display", display,
|
|
"window", window,
|
|
"shared-context", share,
|
|
NULL);
|
|
|
|
context->egl_config = config;
|
|
context->is_attached = attached;
|
|
|
|
return GDK_GL_CONTEXT (context);
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_invalidate_for_new_frame (GdkWindow *window,
|
|
cairo_region_t *update_area)
|
|
{
|
|
cairo_rectangle_int_t window_rect;
|
|
GdkDisplay *display = gdk_window_get_display (window);
|
|
GdkMirGLContext *context_mir;
|
|
int buffer_age;
|
|
gboolean invalidate_all;
|
|
EGLSurface egl_surface;
|
|
|
|
/* Minimal update is ok if we're not drawing with gl */
|
|
if (window->gl_paint_context == NULL)
|
|
return;
|
|
|
|
context_mir = GDK_MIR_GL_CONTEXT (window->gl_paint_context);
|
|
buffer_age = 0;
|
|
|
|
egl_surface = _gdk_mir_window_get_egl_surface (window, context_mir->egl_config);
|
|
|
|
if (_gdk_mir_display_have_egl_buffer_age (display))
|
|
{
|
|
gdk_gl_context_make_current (window->gl_paint_context);
|
|
eglQuerySurface (_gdk_mir_display_get_egl_display (display), egl_surface,
|
|
EGL_BUFFER_AGE_EXT, &buffer_age);
|
|
}
|
|
|
|
invalidate_all = FALSE;
|
|
if (buffer_age == 0 || buffer_age >= 4)
|
|
invalidate_all = TRUE;
|
|
else
|
|
{
|
|
if (buffer_age >= 2)
|
|
{
|
|
if (window->old_updated_area[0])
|
|
cairo_region_union (update_area, window->old_updated_area[0]);
|
|
else
|
|
invalidate_all = TRUE;
|
|
}
|
|
if (buffer_age >= 3)
|
|
{
|
|
if (window->old_updated_area[1])
|
|
cairo_region_union (update_area, window->old_updated_area[1]);
|
|
else
|
|
invalidate_all = TRUE;
|
|
}
|
|
}
|
|
|
|
if (invalidate_all)
|
|
{
|
|
window_rect.x = 0;
|
|
window_rect.y = 0;
|
|
window_rect.width = gdk_window_get_width (window);
|
|
window_rect.height = gdk_window_get_height (window);
|
|
|
|
/* If nothing else is known, repaint everything so that the back
|
|
buffer is fully up-to-date for the swapbuffer */
|
|
cairo_region_union_rectangle (update_area, &window_rect);
|
|
}
|
|
}
|
|
|
|
EGLSurface
|
|
_gdk_mir_window_get_egl_surface (GdkWindow *window,
|
|
EGLConfig config)
|
|
{
|
|
GdkMirWindowImpl *impl;
|
|
|
|
impl = GDK_MIR_WINDOW_IMPL (window->impl);
|
|
|
|
if (!impl->egl_surface)
|
|
{
|
|
EGLDisplay egl_display;
|
|
EGLNativeWindowType egl_window;
|
|
|
|
ensure_no_mir_window (window);
|
|
ensure_mir_window_full (window, mir_buffer_usage_hardware);
|
|
|
|
egl_display = _gdk_mir_display_get_egl_display (gdk_window_get_display (window));
|
|
egl_window = (EGLNativeWindowType) mir_buffer_stream_get_egl_native_window (impl->buffer_stream);
|
|
|
|
impl->egl_surface =
|
|
eglCreateWindowSurface (egl_display, config, egl_window, NULL);
|
|
}
|
|
|
|
return impl->egl_surface;
|
|
}
|
|
|
|
EGLSurface
|
|
_gdk_mir_window_get_dummy_egl_surface (GdkWindow *window,
|
|
EGLConfig config)
|
|
{
|
|
GdkMirWindowImpl *impl;
|
|
|
|
impl = GDK_MIR_WINDOW_IMPL (window->impl);
|
|
|
|
if (!impl->dummy_egl_surface)
|
|
{
|
|
GdkDisplay *display;
|
|
EGLDisplay egl_display;
|
|
EGLNativeWindowType egl_window;
|
|
|
|
display = gdk_window_get_display (window);
|
|
egl_display = _gdk_mir_display_get_egl_display (display);
|
|
egl_window = (EGLNativeWindowType) mir_buffer_stream_get_egl_native_window (impl->buffer_stream);
|
|
|
|
impl->dummy_egl_surface =
|
|
eglCreateWindowSurface (egl_display, config, egl_window, NULL);
|
|
}
|
|
|
|
return impl->dummy_egl_surface;
|
|
}
|
|
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
|
|
|
MirSurface *
|
|
gdk_mir_window_get_mir_surface (GdkWindow *window)
|
|
{
|
|
return _gdk_mir_window_get_mir_window (window);
|
|
}
|
|
|
|
#pragma GCC diagnostic pop
|
|
|
|
MirWindow *
|
|
_gdk_mir_window_get_mir_window (GdkWindow *window)
|
|
{
|
|
g_return_val_if_fail (GDK_IS_MIR_WINDOW (window), NULL);
|
|
|
|
return GDK_MIR_WINDOW_IMPL (window->impl)->mir_window;
|
|
}
|
|
|
|
void
|
|
_gdk_mir_window_set_scale (GdkWindow *window,
|
|
gdouble scale)
|
|
{
|
|
GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
|
|
GdkRectangle area = {0, 0, window->width, window->height};
|
|
cairo_region_t *region;
|
|
gint new_scale = (gint) round (scale);
|
|
|
|
if (impl->output_scale != new_scale)
|
|
{
|
|
impl->output_scale = new_scale;
|
|
|
|
drop_cairo_surface (window);
|
|
|
|
if (impl->buffer_stream)
|
|
mir_buffer_stream_set_scale (impl->buffer_stream, (float) new_scale);
|
|
|
|
region = cairo_region_create_rectangle (&area);
|
|
_gdk_window_invalidate_for_expose (window, region);
|
|
cairo_region_destroy (region);
|
|
}
|
|
}
|
|
|
|
static void
|
|
gdk_mir_window_impl_class_init (GdkMirWindowImplClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
GdkWindowImplClass *impl_class = GDK_WINDOW_IMPL_CLASS (klass);
|
|
|
|
object_class->finalize = gdk_mir_window_impl_finalize;
|
|
|
|
impl_class->ref_cairo_surface = gdk_mir_window_impl_ref_cairo_surface;
|
|
impl_class->create_similar_image_surface = gdk_mir_window_impl_create_similar_image_surface;
|
|
impl_class->show = gdk_mir_window_impl_show;
|
|
impl_class->hide = gdk_mir_window_impl_hide;
|
|
impl_class->withdraw = gdk_mir_window_impl_withdraw;
|
|
impl_class->raise = gdk_mir_window_impl_raise;
|
|
impl_class->lower = gdk_mir_window_impl_lower;
|
|
impl_class->restack_under = gdk_mir_window_impl_restack_under;
|
|
impl_class->restack_toplevel = gdk_mir_window_impl_restack_toplevel;
|
|
impl_class->move_resize = gdk_mir_window_impl_move_resize;
|
|
impl_class->move_to_rect = gdk_mir_window_impl_move_to_rect;
|
|
impl_class->set_background = gdk_mir_window_impl_set_background;
|
|
impl_class->get_events = gdk_mir_window_impl_get_events;
|
|
impl_class->set_events = gdk_mir_window_impl_set_events;
|
|
impl_class->reparent = gdk_mir_window_impl_reparent;
|
|
impl_class->set_device_cursor = gdk_mir_window_impl_set_device_cursor;
|
|
impl_class->get_geometry = gdk_mir_window_impl_get_geometry;
|
|
impl_class->get_root_coords = gdk_mir_window_impl_get_root_coords;
|
|
impl_class->get_device_state = gdk_mir_window_impl_get_device_state;
|
|
impl_class->begin_paint = gdk_mir_window_impl_begin_paint;
|
|
impl_class->end_paint = gdk_mir_window_impl_end_paint;
|
|
impl_class->get_shape = gdk_mir_window_impl_get_shape;
|
|
impl_class->get_input_shape = gdk_mir_window_impl_get_input_shape;
|
|
impl_class->shape_combine_region = gdk_mir_window_impl_shape_combine_region;
|
|
impl_class->input_shape_combine_region = gdk_mir_window_impl_input_shape_combine_region;
|
|
impl_class->destroy = gdk_mir_window_impl_destroy;
|
|
impl_class->destroy_foreign = gdk_mir_window_impl_destroy_foreign;
|
|
impl_class->focus = gdk_mir_window_impl_focus;
|
|
impl_class->set_type_hint = gdk_mir_window_impl_set_type_hint;
|
|
impl_class->get_type_hint = gdk_mir_window_impl_get_type_hint;
|
|
impl_class->set_modal_hint = gdk_mir_window_impl_set_modal_hint;
|
|
impl_class->set_skip_taskbar_hint = gdk_mir_window_impl_set_skip_taskbar_hint;
|
|
impl_class->set_skip_pager_hint = gdk_mir_window_impl_set_skip_pager_hint;
|
|
impl_class->set_urgency_hint = gdk_mir_window_impl_set_urgency_hint;
|
|
impl_class->set_geometry_hints = gdk_mir_window_impl_set_geometry_hints;
|
|
impl_class->set_title = gdk_mir_window_impl_set_title;
|
|
impl_class->set_role = gdk_mir_window_impl_set_role;
|
|
impl_class->set_startup_id = gdk_mir_window_impl_set_startup_id;
|
|
impl_class->set_transient_for = gdk_mir_window_impl_set_transient_for;
|
|
impl_class->get_frame_extents = gdk_mir_window_impl_get_frame_extents;
|
|
impl_class->set_override_redirect = gdk_mir_window_impl_set_override_redirect;
|
|
impl_class->set_accept_focus = gdk_mir_window_impl_set_accept_focus;
|
|
impl_class->set_focus_on_map = gdk_mir_window_impl_set_focus_on_map;
|
|
impl_class->set_icon_list = gdk_mir_window_impl_set_icon_list;
|
|
impl_class->set_icon_name = gdk_mir_window_impl_set_icon_name;
|
|
impl_class->iconify = gdk_mir_window_impl_iconify;
|
|
impl_class->deiconify = gdk_mir_window_impl_deiconify;
|
|
impl_class->stick = gdk_mir_window_impl_stick;
|
|
impl_class->unstick = gdk_mir_window_impl_unstick;
|
|
impl_class->maximize = gdk_mir_window_impl_maximize;
|
|
impl_class->unmaximize = gdk_mir_window_impl_unmaximize;
|
|
impl_class->fullscreen = gdk_mir_window_impl_fullscreen;
|
|
impl_class->apply_fullscreen_mode = gdk_mir_window_impl_apply_fullscreen_mode;
|
|
impl_class->unfullscreen = gdk_mir_window_impl_unfullscreen;
|
|
impl_class->set_keep_above = gdk_mir_window_impl_set_keep_above;
|
|
impl_class->set_keep_below = gdk_mir_window_impl_set_keep_below;
|
|
impl_class->get_group = gdk_mir_window_impl_get_group;
|
|
impl_class->set_group = gdk_mir_window_impl_set_group;
|
|
impl_class->set_decorations = gdk_mir_window_impl_set_decorations;
|
|
impl_class->get_decorations = gdk_mir_window_impl_get_decorations;
|
|
impl_class->set_functions = gdk_mir_window_impl_set_functions;
|
|
impl_class->begin_resize_drag = gdk_mir_window_impl_begin_resize_drag;
|
|
impl_class->begin_move_drag = gdk_mir_window_impl_begin_move_drag;
|
|
impl_class->enable_synchronized_configure = gdk_mir_window_impl_enable_synchronized_configure;
|
|
impl_class->configure_finished = gdk_mir_window_impl_configure_finished;
|
|
impl_class->set_opacity = gdk_mir_window_impl_set_opacity;
|
|
impl_class->set_composited = gdk_mir_window_impl_set_composited;
|
|
impl_class->destroy_notify = gdk_mir_window_impl_destroy_notify;
|
|
impl_class->get_drag_protocol = gdk_mir_window_impl_get_drag_protocol;
|
|
impl_class->register_dnd = gdk_mir_window_impl_register_dnd;
|
|
impl_class->drag_begin = gdk_mir_window_impl_drag_begin;
|
|
impl_class->process_updates_recurse = gdk_mir_window_impl_process_updates_recurse;
|
|
impl_class->sync_rendering = gdk_mir_window_impl_sync_rendering;
|
|
impl_class->simulate_key = gdk_mir_window_impl_simulate_key;
|
|
impl_class->simulate_button = gdk_mir_window_impl_simulate_button;
|
|
impl_class->get_property = gdk_mir_window_impl_get_property;
|
|
impl_class->change_property = gdk_mir_window_impl_change_property;
|
|
impl_class->delete_property = gdk_mir_window_impl_delete_property;
|
|
impl_class->get_scale_factor = gdk_mir_window_impl_get_scale_factor;
|
|
impl_class->set_opaque_region = gdk_mir_window_impl_set_opaque_region;
|
|
impl_class->set_shadow_width = gdk_mir_window_impl_set_shadow_width;
|
|
impl_class->create_gl_context = gdk_mir_window_impl_create_gl_context;
|
|
impl_class->invalidate_for_new_frame = gdk_mir_window_impl_invalidate_for_new_frame;
|
|
}
|