1 /*
   2  * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 #include "glass_window.h"
  26 #include "glass_general.h"
  27 #include "glass_key.h"
  28 #include "glass_screen.h"
  29 #include "glass_dnd.h"
  30 
  31 #include <com_sun_glass_events_WindowEvent.h>
  32 #include <com_sun_glass_events_ViewEvent.h>
  33 #include <com_sun_glass_events_MouseEvent.h>
  34 #include <com_sun_glass_events_KeyEvent.h>
  35 
  36 #include <com_sun_glass_ui_Window_Level.h>
  37 
  38 #include <X11/extensions/shape.h>
  39 #include <cairo.h>
  40 #include <cairo-xlib.h>
  41 #include <gdk/gdkx.h>
  42 #include <gdk/gdk.h>
  43 #ifdef GLASS_GTK3
  44 #include <gtk/gtkx.h>
  45 #endif
  46 
  47 #include <string.h>
  48 
  49 #include <iostream>
  50 #include <algorithm>
  51 
  52 WindowContext * WindowContextBase::sm_grab_window = NULL;
  53 WindowContext * WindowContextBase::sm_mouse_drag_window = NULL;
  54 
  55 GdkWindow* WindowContextBase::get_gdk_window(){
  56     return gdk_window;
  57 }
  58 
  59 jobject WindowContextBase::get_jview() {
  60     return jview;
  61 }
  62 
  63 jobject WindowContextBase::get_jwindow() {
  64     return jwindow;
  65 }
  66 
  67 bool WindowContextBase::isEnabled() {
  68     if (jwindow) {
  69         bool result = (JNI_TRUE == mainEnv->CallBooleanMethod(jwindow, jWindowIsEnabled));
  70         LOG_EXCEPTION(mainEnv)
  71         return result;
  72     } else {
  73         return false;
  74     }
  75 }
  76 
  77 void WindowContextBase::notify_state(jint glass_state) {
  78     if (glass_state == com_sun_glass_events_WindowEvent_RESTORE) {
  79         if (is_maximized) {
  80             glass_state = com_sun_glass_events_WindowEvent_MAXIMIZE;
  81         }
  82 
  83         int w, h;
  84         glass_gdk_window_get_size(gdk_window, &w, &h);
  85         if (jview) {
  86             mainEnv->CallVoidMethod(jview,
  87                     jViewNotifyRepaint,
  88                     0, 0, w, h);
  89             CHECK_JNI_EXCEPTION(mainEnv);
  90         }
  91     }
  92 
  93     if (jwindow) {
  94        mainEnv->CallVoidMethod(jwindow,
  95                jGtkWindowNotifyStateChanged,
  96                glass_state);
  97        CHECK_JNI_EXCEPTION(mainEnv);
  98     }
  99 }
 100 
 101 void WindowContextBase::process_state(GdkEventWindowState* event) {
 102     if (event->changed_mask &
 103             (GDK_WINDOW_STATE_ICONIFIED | GDK_WINDOW_STATE_MAXIMIZED)) {
 104 
 105         if (event->changed_mask & GDK_WINDOW_STATE_ICONIFIED) {
 106             is_iconified = event->new_window_state & GDK_WINDOW_STATE_ICONIFIED;
 107         }
 108         if (event->changed_mask & GDK_WINDOW_STATE_MAXIMIZED) {
 109             is_maximized = event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED;
 110         }
 111 
 112         jint stateChangeEvent;
 113 
 114         if (is_iconified) {
 115             stateChangeEvent = com_sun_glass_events_WindowEvent_MINIMIZE;
 116         } else if (is_maximized) {
 117             stateChangeEvent = com_sun_glass_events_WindowEvent_MAXIMIZE;
 118         } else {
 119             stateChangeEvent = com_sun_glass_events_WindowEvent_RESTORE;
 120             if ((gdk_windowManagerFunctions & GDK_FUNC_MINIMIZE) == 0) {
 121                 // in this case - the window manager will not support the programatic
 122                 // request to iconify - so we need to restore it now.
 123                 gdk_window_set_functions(gdk_window, gdk_windowManagerFunctions);
 124             }
 125         }
 126 
 127         notify_state(stateChangeEvent);
 128     } else if (event->changed_mask & GDK_WINDOW_STATE_ABOVE) {
 129         notify_on_top( event->new_window_state & GDK_WINDOW_STATE_ABOVE);
 130     }
 131 }
 132 
 133 void WindowContextBase::process_focus(GdkEventFocus* event) {
 134     if (!event->in && WindowContextBase::sm_mouse_drag_window == this) {
 135         ungrab_mouse_drag_focus();
 136     }
 137     if (!event->in && WindowContextBase::sm_grab_window == this) {
 138         ungrab_focus();
 139     }
 140 
 141     if (xim.enabled && xim.ic) {
 142         if (event->in) {
 143             XSetICFocus(xim.ic);
 144         } else {
 145             XUnsetICFocus(xim.ic);
 146         }
 147     }
 148 
 149     if (jwindow) {
 150         if (!event->in || isEnabled()) {
 151             mainEnv->CallVoidMethod(jwindow, jWindowNotifyFocus,
 152                     event->in ? com_sun_glass_events_WindowEvent_FOCUS_GAINED : com_sun_glass_events_WindowEvent_FOCUS_LOST);
 153             CHECK_JNI_EXCEPTION(mainEnv)
 154         } else {
 155             mainEnv->CallVoidMethod(jwindow, jWindowNotifyFocusDisabled);
 156             CHECK_JNI_EXCEPTION(mainEnv)
 157         }
 158     }
 159 }
 160 
 161 void WindowContextBase::increment_events_counter() {
 162     ++events_processing_cnt;
 163 }
 164 
 165 void WindowContextBase::decrement_events_counter() {
 166     --events_processing_cnt;
 167 }
 168 
 169 size_t WindowContextBase::get_events_count() {
 170     return events_processing_cnt;
 171 }
 172 
 173 bool WindowContextBase::is_dead() {
 174     return can_be_deleted;
 175 }
 176 
 177 void destroy_and_delete_ctx(WindowContext* ctx) {
 178     if (ctx) {
 179         ctx->process_destroy();
 180 
 181         if (!ctx->get_events_count()) {
 182             delete ctx;
 183         }
 184         // else: ctx will be deleted in EventsCounterHelper after completing
 185         // an event processing
 186     }
 187 }
 188 
 189 void WindowContextBase::process_destroy() {
 190     if (WindowContextBase::sm_mouse_drag_window == this) {
 191         ungrab_mouse_drag_focus();
 192     }
 193 
 194     if (WindowContextBase::sm_grab_window == this) {
 195         ungrab_focus();
 196     }
 197 
 198     std::set<WindowContextTop*>::iterator it;
 199     for (it = children.begin(); it != children.end(); ++it) {
 200         (*it)->set_owner(NULL);
 201         destroy_and_delete_ctx(*it);
 202     }
 203     children.clear();
 204 
 205     if (jwindow) {
 206         mainEnv->CallVoidMethod(jwindow, jWindowNotifyDestroy);
 207         EXCEPTION_OCCURED(mainEnv);
 208     }
 209 
 210     if (jview) {
 211         mainEnv->DeleteGlobalRef(jview);
 212         jview = NULL;
 213     }
 214 
 215     if (jwindow) {
 216         mainEnv->DeleteGlobalRef(jwindow);
 217         jwindow = NULL;
 218     }
 219 
 220     can_be_deleted = true;
 221 }
 222 
 223 void WindowContextBase::process_delete() {
 224     if (jwindow && isEnabled()) {
 225         mainEnv->CallVoidMethod(jwindow, jWindowNotifyClose);
 226         CHECK_JNI_EXCEPTION(mainEnv)
 227     }
 228 }
 229 
 230 void WindowContextBase::process_expose(GdkEventExpose* event) {
 231     if (jview) {
 232         mainEnv->CallVoidMethod(jview, jViewNotifyRepaint, event->area.x, event->area.y, event->area.width, event->area.height);
 233         CHECK_JNI_EXCEPTION(mainEnv)
 234     }
 235 }
 236 
 237 static inline jint gtk_button_number_to_mouse_button(guint button) {
 238     switch (button) {
 239         case 1:
 240             return com_sun_glass_events_MouseEvent_BUTTON_LEFT;
 241         case 2:
 242             return com_sun_glass_events_MouseEvent_BUTTON_OTHER;
 243         case 3:
 244             return com_sun_glass_events_MouseEvent_BUTTON_RIGHT;
 245         default:
 246             // Other buttons are not supported by quantum and are not reported by other platforms
 247             return com_sun_glass_events_MouseEvent_BUTTON_NONE;
 248     }
 249 }
 250 
 251 void WindowContextBase::process_mouse_button(GdkEventButton* event) {
 252     bool press = event->type == GDK_BUTTON_PRESS;
 253     guint state = event->state;
 254     guint mask = 0;
 255 
 256     // We need to add/remove current mouse button from the modifier flags
 257     // as X lib state represents the state just prior to the event and
 258     // glass needs the state just after the event
 259     switch (event->button) {
 260         case 1:
 261             mask = GDK_BUTTON1_MASK;
 262             break;
 263         case 2:
 264             mask = GDK_BUTTON2_MASK;
 265             break;
 266         case 3:
 267             mask = GDK_BUTTON3_MASK;
 268             break;
 269     }
 270 
 271     if (press) {
 272         state |= mask;
 273     } else {
 274         state &= ~mask;
 275     }
 276 
 277     if (press) {
 278         GdkDevice* device = event->device;
 279 
 280         if (glass_gdk_device_is_grabbed(device)
 281                 && (glass_gdk_device_get_window_at_position(device, NULL, NULL)
 282                 == NULL)) {
 283             ungrab_focus();
 284             return;
 285         }
 286     }
 287 
 288     // Upper layers expects from us Windows behavior:
 289     // all mouse events should be delivered to window where drag begins
 290     // and no exit/enter event should be reported during this drag.
 291     // We can grab mouse pointer for these needs.
 292     if (press) {
 293         grab_mouse_drag_focus();
 294     } else if ((event->state & MOUSE_BUTTONS_MASK)
 295             && !(state & MOUSE_BUTTONS_MASK)) { // all buttons released
 296         ungrab_mouse_drag_focus();
 297     }
 298 
 299     jint button = gtk_button_number_to_mouse_button(event->button);
 300 
 301     if (jview && button != com_sun_glass_events_MouseEvent_BUTTON_NONE) {
 302         mainEnv->CallVoidMethod(jview, jViewNotifyMouse,
 303                 press ? com_sun_glass_events_MouseEvent_DOWN : com_sun_glass_events_MouseEvent_UP,
 304                 button,
 305                 (jint) event->x, (jint) event->y,
 306                 (jint) event->x_root, (jint) event->y_root,
 307                 gdk_modifier_mask_to_glass(state),
 308                 (event->button == 3 && press) ? JNI_TRUE : JNI_FALSE,
 309                 JNI_FALSE);
 310         CHECK_JNI_EXCEPTION(mainEnv)
 311 
 312         if (jview && event->button == 3 && press) {
 313             mainEnv->CallVoidMethod(jview, jViewNotifyMenu,
 314                     (jint)event->x, (jint)event->y,
 315                     (jint)event->x_root, (jint)event->y_root,
 316                     JNI_FALSE);
 317             CHECK_JNI_EXCEPTION(mainEnv)
 318         }
 319     }
 320 }
 321 
 322 void WindowContextBase::process_mouse_motion(GdkEventMotion* event) {
 323     jint glass_modifier = gdk_modifier_mask_to_glass(event->state);
 324     jint isDrag = glass_modifier & (
 325             com_sun_glass_events_KeyEvent_MODIFIER_BUTTON_PRIMARY |
 326             com_sun_glass_events_KeyEvent_MODIFIER_BUTTON_MIDDLE |
 327             com_sun_glass_events_KeyEvent_MODIFIER_BUTTON_SECONDARY);
 328     jint button = com_sun_glass_events_MouseEvent_BUTTON_NONE;
 329 
 330     if (glass_modifier & com_sun_glass_events_KeyEvent_MODIFIER_BUTTON_PRIMARY) {
 331         button = com_sun_glass_events_MouseEvent_BUTTON_LEFT;
 332     } else if (glass_modifier & com_sun_glass_events_KeyEvent_MODIFIER_BUTTON_MIDDLE) {
 333         button = com_sun_glass_events_MouseEvent_BUTTON_OTHER;
 334     } else if (glass_modifier & com_sun_glass_events_KeyEvent_MODIFIER_BUTTON_SECONDARY) {
 335         button = com_sun_glass_events_MouseEvent_BUTTON_RIGHT;
 336     }
 337 
 338     if (jview) {
 339         mainEnv->CallVoidMethod(jview, jViewNotifyMouse,
 340                 isDrag ? com_sun_glass_events_MouseEvent_DRAG : com_sun_glass_events_MouseEvent_MOVE,
 341                 button,
 342                 (jint) event->x, (jint) event->y,
 343                 (jint) event->x_root, (jint) event->y_root,
 344                 glass_modifier,
 345                 JNI_FALSE,
 346                 JNI_FALSE);
 347         CHECK_JNI_EXCEPTION(mainEnv)
 348     }
 349 }
 350 
 351 void WindowContextBase::process_mouse_scroll(GdkEventScroll* event) {
 352     jdouble dx = 0;
 353     jdouble dy = 0;
 354 
 355     // converting direction to change in pixels
 356     switch (event->direction) {
 357 #if GTK_CHECK_VERSION(3, 4, 0)
 358         case GDK_SCROLL_SMOOTH:
 359             //FIXME 3.4 ???
 360             break;
 361 #endif
 362         case GDK_SCROLL_UP:
 363             dy = 1;
 364             break;
 365         case GDK_SCROLL_DOWN:
 366             dy = -1;
 367             break;
 368         case GDK_SCROLL_LEFT:
 369             dx = 1;
 370             break;
 371         case GDK_SCROLL_RIGHT:
 372             dx = -1;
 373             break;
 374     }
 375 
 376     if (jview) {
 377         mainEnv->CallVoidMethod(jview, jViewNotifyScroll,
 378                 (jint) event->x, (jint) event->y,
 379                 (jint) event->x_root, (jint) event->y_root,
 380                 dx, dy,
 381                 gdk_modifier_mask_to_glass(event->state),
 382                 (jint) 0, (jint) 0,
 383                 (jint) 0, (jint) 0,
 384                 (jdouble) 40.0, (jdouble) 40.0);
 385         CHECK_JNI_EXCEPTION(mainEnv)
 386     }
 387 
 388 }
 389 
 390 void WindowContextBase::process_mouse_cross(GdkEventCrossing* event) {
 391     bool enter = event->type == GDK_ENTER_NOTIFY;
 392     if (jview) {
 393         guint state = event->state;
 394         if (enter) { // workaround for RT-21590
 395             state &= ~MOUSE_BUTTONS_MASK;
 396         }
 397 
 398         if (enter != is_mouse_entered) {
 399             is_mouse_entered = enter;
 400             mainEnv->CallVoidMethod(jview, jViewNotifyMouse,
 401                     enter ? com_sun_glass_events_MouseEvent_ENTER : com_sun_glass_events_MouseEvent_EXIT,
 402                     com_sun_glass_events_MouseEvent_BUTTON_NONE,
 403                     (jint) event->x, (jint) event->y,
 404                     (jint) event->x_root, (jint) event->y_root,
 405                     gdk_modifier_mask_to_glass(state),
 406                     JNI_FALSE,
 407                     JNI_FALSE);
 408             CHECK_JNI_EXCEPTION(mainEnv)
 409         }
 410     }
 411 }
 412 
 413 void WindowContextBase::process_key(GdkEventKey* event) {
 414     bool press = event->type == GDK_KEY_PRESS;
 415     jint glassKey = get_glass_key(event);
 416     jint glassModifier = gdk_modifier_mask_to_glass(event->state);
 417     if (press) {
 418         glassModifier |= glass_key_to_modifier(glassKey);
 419     } else {
 420         glassModifier &= ~glass_key_to_modifier(glassKey);
 421     }
 422     jcharArray jChars = NULL;
 423     jchar key = gdk_keyval_to_unicode(event->keyval);
 424     if (key >= 'a' && key <= 'z' && (event->state & GDK_CONTROL_MASK)) {
 425         key = key - 'a' + 1; // map 'a' to ctrl-a, and so on.
 426     } else {
 427 #ifdef GLASS_GTK2
 428         if (key == 0) {
 429             // Work around "bug" fixed in gtk-3.0:
 430             // http://mail.gnome.org/archives/commits-list/2011-March/msg06832.html
 431             switch (event->keyval) {
 432             case 0xFF08 /* Backspace */: key =  '\b';
 433             case 0xFF09 /* Tab       */: key =  '\t';
 434             case 0xFF0A /* Linefeed  */: key =  '\n';
 435             case 0xFF0B /* Vert. Tab */: key =  '\v';
 436             case 0xFF0D /* Return    */: key =  '\r';
 437             case 0xFF1B /* Escape    */: key =  '\033';
 438             case 0xFFFF /* Delete    */: key =  '\177';
 439             }
 440         }
 441 #endif
 442     }
 443 
 444     if (key > 0) {
 445         jChars = mainEnv->NewCharArray(1);
 446         if (jChars) {
 447             mainEnv->SetCharArrayRegion(jChars, 0, 1, &key);
 448             CHECK_JNI_EXCEPTION(mainEnv)
 449         }
 450     } else {
 451         jChars = mainEnv->NewCharArray(0);
 452     }
 453     if (jview) {
 454         if (press) {
 455             mainEnv->CallVoidMethod(jview, jViewNotifyKey,
 456                     com_sun_glass_events_KeyEvent_PRESS,
 457                     glassKey,
 458                     jChars,
 459                     glassModifier);
 460             CHECK_JNI_EXCEPTION(mainEnv)
 461 
 462             if (jview && key > 0) { // TYPED events should only be sent for printable characters.
 463                 mainEnv->CallVoidMethod(jview, jViewNotifyKey,
 464                         com_sun_glass_events_KeyEvent_TYPED,
 465                         com_sun_glass_events_KeyEvent_VK_UNDEFINED,
 466                         jChars,
 467                         glassModifier);
 468                 CHECK_JNI_EXCEPTION(mainEnv)
 469             }
 470         } else {
 471             mainEnv->CallVoidMethod(jview, jViewNotifyKey,
 472                     com_sun_glass_events_KeyEvent_RELEASE,
 473                     glassKey,
 474                     jChars,
 475                     glassModifier);
 476             CHECK_JNI_EXCEPTION(mainEnv)
 477         }
 478     }
 479 }
 480 
 481 void WindowContextBase::paint(void* data, jint width, jint height)
 482 {
 483     if (!is_visible()) {
 484         return;
 485     }
 486 #ifdef GLASS_GTK3
 487     cairo_region_t *region = gdk_window_get_clip_region(gdk_window);
 488     gdk_window_begin_paint_region(gdk_window, region);
 489 #endif
 490     cairo_t* context;
 491     context = gdk_cairo_create(gdk_window);
 492 
 493     cairo_surface_t* cairo_surface;
 494     cairo_surface = cairo_image_surface_create_for_data(
 495             (unsigned char*)data,
 496             CAIRO_FORMAT_ARGB32,
 497             width, height, width * 4);
 498 
 499     applyShapeMask(data, width, height);
 500 
 501     cairo_set_source_surface(context, cairo_surface, 0, 0);
 502     cairo_set_operator (context, CAIRO_OPERATOR_SOURCE);
 503     cairo_paint(context);
 504 #ifdef GLASS_GTK3
 505     gdk_window_end_paint(gdk_window);
 506     cairo_region_destroy(region);
 507 #endif
 508 
 509     cairo_destroy(context);
 510     cairo_surface_destroy(cairo_surface);
 511 }
 512 
 513 void WindowContextBase::add_child(WindowContextTop* child) {
 514     children.insert(child);
 515     gtk_window_set_transient_for(child->get_gtk_window(), this->get_gtk_window());
 516 }
 517 
 518 void WindowContextBase::remove_child(WindowContextTop* child) {
 519     children.erase(child);
 520     gtk_window_set_transient_for(child->get_gtk_window(), NULL);
 521 }
 522 
 523 void WindowContextBase::show_or_hide_children(bool show) {
 524     std::set<WindowContextTop*>::iterator it;
 525     for (it = children.begin(); it != children.end(); ++it) {
 526         (*it)->set_minimized(!show);
 527         (*it)->show_or_hide_children(show);
 528     }
 529 }
 530 
 531 void WindowContextBase::reparent_children(WindowContext* parent) {
 532     std::set<WindowContextTop*>::iterator it;
 533     for (it = children.begin(); it != children.end(); ++it) {
 534         (*it)->set_owner(parent);
 535         parent->add_child(*it);
 536     }
 537     children.clear();
 538 }
 539 
 540 void WindowContextBase::set_visible(bool visible) {
 541     if (visible) {
 542         gtk_widget_show_all(gtk_widget);
 543     } else {
 544         gtk_widget_hide(gtk_widget);
 545         if (jview && is_mouse_entered) {
 546             is_mouse_entered = false;
 547             mainEnv->CallVoidMethod(jview, jViewNotifyMouse,
 548                     com_sun_glass_events_MouseEvent_EXIT,
 549                     com_sun_glass_events_MouseEvent_BUTTON_NONE,
 550                     0, 0,
 551                     0, 0,
 552                     0,
 553                     JNI_FALSE,
 554                     JNI_FALSE);
 555             CHECK_JNI_EXCEPTION(mainEnv)
 556         }
 557     }
 558 }
 559 
 560 bool WindowContextBase::is_visible() {
 561     return gtk_widget_get_visible(gtk_widget);
 562 }
 563 
 564 bool WindowContextBase::set_view(jobject view) {
 565 
 566     if (jview) {
 567         mainEnv->DeleteGlobalRef(jview);
 568     }
 569 
 570     if (view) {
 571         gint width, height;
 572         jview = mainEnv->NewGlobalRef(view);
 573         gtk_window_get_size(GTK_WINDOW(gtk_widget), &width, &height);
 574         mainEnv->CallVoidMethod(view, jViewNotifyResize, width, height);
 575         CHECK_JNI_EXCEPTION_RET(mainEnv, FALSE)
 576     } else {
 577         jview = NULL;
 578     }
 579     return TRUE;
 580 }
 581 
 582 bool WindowContextBase::grab_mouse_drag_focus() {
 583     if (glass_gdk_mouse_devices_grab_with_cursor(
 584             gdk_window, gdk_window_get_cursor(gdk_window), FALSE)) {
 585         WindowContextBase::sm_mouse_drag_window = this;
 586         return true;
 587     } else {
 588         return false;
 589     }
 590 }
 591 
 592 void WindowContextBase::ungrab_mouse_drag_focus() {
 593     WindowContextBase::sm_mouse_drag_window = NULL;
 594     glass_gdk_mouse_devices_ungrab();
 595     if (WindowContextBase::sm_grab_window) {
 596         WindowContextBase::sm_grab_window->grab_focus();
 597     }
 598 }
 599 
 600 bool WindowContextBase::grab_focus() {
 601     if (WindowContextBase::sm_mouse_drag_window
 602             || glass_gdk_mouse_devices_grab(gdk_window)) {
 603         WindowContextBase::sm_grab_window = this;
 604         return true;
 605     } else {
 606         return false;
 607     }
 608 }
 609 
 610 void WindowContextBase::ungrab_focus() {
 611     if (!WindowContextBase::sm_mouse_drag_window) {
 612         glass_gdk_mouse_devices_ungrab();
 613     }
 614     WindowContextBase::sm_grab_window = NULL;
 615 
 616     if (jwindow) {
 617         mainEnv->CallVoidMethod(jwindow, jWindowNotifyFocusUngrab);
 618         CHECK_JNI_EXCEPTION(mainEnv)
 619     }
 620 }
 621 
 622 void WindowContextBase::set_cursor(GdkCursor* cursor) {
 623     if (!is_in_drag()) {
 624         if (WindowContextBase::sm_mouse_drag_window) {
 625             glass_gdk_mouse_devices_grab_with_cursor(
 626                     WindowContextBase::sm_mouse_drag_window->get_gdk_window(), cursor, FALSE);
 627         } else if (WindowContextBase::sm_grab_window) {
 628             glass_gdk_mouse_devices_grab_with_cursor(
 629                     WindowContextBase::sm_grab_window->get_gdk_window(), cursor, TRUE);
 630         }
 631     }
 632     gdk_window_set_cursor(gdk_window, cursor);
 633 }
 634 
 635 void WindowContextBase::set_background(float r, float g, float b) {
 636 #ifdef GLASS_GTK3
 637     GdkRGBA rgba = {0, 0, 0, 1.};
 638     rgba.red = r;
 639     rgba.green = g;
 640     rgba.blue = b;
 641     gdk_window_set_background_rgba(gdk_window, &rgba);
 642 #else
 643     GdkColor color;
 644     color.red   = (guint16) (r * 65535);
 645     color.green = (guint16) (g * 65535);
 646     color.blue  = (guint16) (b * 65535);
 647     gtk_widget_modify_bg(gtk_widget, GTK_STATE_NORMAL, &color);
 648 #endif
 649 }
 650 
 651 WindowContextBase::~WindowContextBase() {
 652     if (xim.ic) {
 653         XDestroyIC(xim.ic);
 654         xim.ic = NULL;
 655     }
 656     if (xim.im) {
 657         XCloseIM(xim.im);
 658         xim.im = NULL;
 659     }
 660 
 661     gtk_widget_destroy(gtk_widget);
 662 }
 663 
 664 ////////////////////////////// WindowContextTop /////////////////////////////////
 665 
 666 
 667 WindowContextTop::WindowContextTop(jobject _jwindow, WindowContext* _owner, long _screen,
 668         WindowFrameType _frame_type, WindowType type, GdkWMFunction wmf) :
 669             WindowContextBase(),
 670             screen(_screen),
 671             frame_type(_frame_type),
 672             owner(_owner),
 673             geometry(),
 674             resizable(),
 675             frame_extents_initialized(),
 676             map_received(false),
 677             location_assigned(false),
 678             size_assigned(false),
 679             on_top(false)
 680 {
 681     jwindow = mainEnv->NewGlobalRef(_jwindow);
 682 
 683     gtk_widget =  gtk_window_new(type == POPUP ? GTK_WINDOW_POPUP : GTK_WINDOW_TOPLEVEL);
 684 
 685     if (gchar* app_name = get_application_name()) {
 686         gtk_window_set_wmclass(GTK_WINDOW(gtk_widget), app_name, app_name);
 687         g_free(app_name);
 688     }
 689 
 690     if (owner) {
 691         owner->add_child(this);
 692         if (on_top_inherited()) {
 693             gtk_window_set_keep_above(GTK_WINDOW(gtk_widget), TRUE);
 694         }
 695     }
 696 
 697     if (type == UTILITY) {
 698         gtk_window_set_type_hint(GTK_WINDOW(gtk_widget), GDK_WINDOW_TYPE_HINT_UTILITY);
 699     }
 700 
 701 //    glong xdisplay = (glong)mainEnv->GetStaticLongField(jApplicationCls, jApplicationDisplay);
 702 //    gint  xscreenID = (gint)mainEnv->GetStaticIntField(jApplicationCls, jApplicationScreen);
 703     glong xvisualID = (glong)mainEnv->GetStaticLongField(jApplicationCls, jApplicationVisualID);
 704 
 705     if (xvisualID != 0) {
 706         GdkVisual *visual = gdk_x11_screen_lookup_visual(gdk_screen_get_default(), xvisualID);
 707         glass_gtk_window_configure_from_visual(gtk_widget, visual);
 708     }
 709 
 710     gtk_widget_set_size_request(gtk_widget, 0, 0);
 711     gtk_widget_set_events(gtk_widget, GDK_ALL_EVENTS_MASK);
 712     gtk_widget_set_app_paintable(gtk_widget, TRUE);
 713     if (frame_type != TITLED) {
 714         gtk_window_set_decorated(GTK_WINDOW(gtk_widget), FALSE);
 715     }
 716 
 717     glass_gtk_configure_transparency_and_realize(gtk_widget, frame_type == TRANSPARENT);
 718     gtk_window_set_title(GTK_WINDOW(gtk_widget), "");
 719 
 720     gdk_window = gtk_widget_get_window(gtk_widget);
 721 
 722     g_object_set_data_full(G_OBJECT(gdk_window), GDK_WINDOW_DATA_CONTEXT, this, NULL);
 723 
 724     gdk_window_register_dnd(gdk_window);
 725 
 726     gdk_windowManagerFunctions = wmf;
 727     if (wmf) {
 728         gdk_window_set_functions(gdk_window, wmf);
 729     }
 730 
 731     if (frame_type == TITLED) {
 732         request_frame_extents();
 733     }
 734 }
 735 
 736 // Applied to a temporary full screen window to prevent sending events to Java
 737 void WindowContextTop::detach_from_java() {
 738     if (jview) {
 739         mainEnv->DeleteGlobalRef(jview);
 740         jview = NULL;
 741     }
 742     if (jwindow) {
 743         mainEnv->DeleteGlobalRef(jwindow);
 744         jwindow = NULL;
 745     }
 746 }
 747 
 748 static GdkAtom
 749 get_net_frame_extents_atom() {
 750     static const char * extents_str = "_NET_FRAME_EXTENTS";
 751     return gdk_atom_intern(extents_str, TRUE);
 752 }
 753 
 754 void
 755 WindowContextTop::request_frame_extents() {
 756     Display *display = GDK_DISPLAY_XDISPLAY(gdk_window_get_display(gdk_window));
 757     Atom rfeAtom = XInternAtom(display, "_NET_REQUEST_FRAME_EXTENTS", True);
 758     if (rfeAtom != None) {
 759         XClientMessageEvent clientMessage;
 760         memset(&clientMessage, 0, sizeof(clientMessage));
 761 
 762         clientMessage.type = ClientMessage;
 763         clientMessage.window = GDK_WINDOW_XID(gdk_window);
 764         clientMessage.message_type = rfeAtom;
 765         clientMessage.format = 32;
 766 
 767         XSendEvent(display, XDefaultRootWindow(display), False,
 768                    SubstructureRedirectMask | SubstructureNotifyMask,
 769                    (XEvent *) &clientMessage);
 770         XFlush(display);
 771     }
 772 }
 773 
 774 void WindowContextTop::activate_window() {
 775     Display *display = GDK_DISPLAY_XDISPLAY (gdk_window_get_display (gdk_window));
 776     Atom navAtom = XInternAtom(display, "_NET_ACTIVE_WINDOW", True);
 777     if (navAtom != None) {
 778         XClientMessageEvent clientMessage;
 779         memset(&clientMessage, 0, sizeof(clientMessage));
 780 
 781         clientMessage.type = ClientMessage;
 782         clientMessage.window = GDK_WINDOW_XID(gdk_window);
 783         clientMessage.message_type = navAtom;
 784         clientMessage.format = 32;
 785         clientMessage.data.l[0] = 1;
 786         clientMessage.data.l[1] = gdk_x11_get_server_time(gdk_window);
 787         clientMessage.data.l[2] = 0;
 788 
 789         XSendEvent(display, XDefaultRootWindow(display), False,
 790                    SubstructureRedirectMask | SubstructureNotifyMask,
 791                    (XEvent *) &clientMessage);
 792         XFlush(display);
 793     }
 794 }
 795 
 796 void
 797 WindowContextTop::initialize_frame_extents() {
 798     int top, left, bottom, right;
 799     if (get_frame_extents_property(&top, &left, &bottom, &right)) {
 800         geometry.extents.top = top;
 801         geometry.extents.left = left;
 802         geometry.extents.bottom = bottom;
 803         geometry.extents.right = right;
 804     }
 805 }
 806 
 807 bool
 808 WindowContextTop::get_frame_extents_property(int *top, int *left,
 809         int *bottom, int *right) {
 810     unsigned long *extents;
 811 
 812     if (gdk_property_get(gdk_window,
 813             get_net_frame_extents_atom(),
 814             gdk_atom_intern("CARDINAL", FALSE),
 815             0,
 816             sizeof (unsigned long) * 4,
 817             FALSE,
 818             NULL,
 819             NULL,
 820             NULL,
 821             (guchar**) & extents)) {
 822         *left = extents [0];
 823         *right = extents [1];
 824         *top = extents [2];
 825         *bottom = extents [3];
 826 
 827         g_free(extents);
 828         return true;
 829     }
 830 
 831     return false;
 832 }
 833 
 834 static int geometry_get_window_width(const WindowGeometry *windowGeometry) {
 835      return (windowGeometry->final_width.type != BOUNDSTYPE_WINDOW)
 836                    ? windowGeometry->final_width.value
 837                          + windowGeometry->extents.left
 838                          + windowGeometry->extents.right
 839                    : windowGeometry->final_width.value;
 840 }
 841 
 842 static int geometry_get_window_height(const WindowGeometry *windowGeometry) {
 843     return (windowGeometry->final_height.type != BOUNDSTYPE_WINDOW)
 844                    ? windowGeometry->final_height.value
 845                          + windowGeometry->extents.top
 846                          + windowGeometry->extents.bottom
 847                    : windowGeometry->final_height.value;
 848 }
 849 
 850 static int geometry_get_content_width(WindowGeometry *windowGeometry) {
 851     return (windowGeometry->final_width.type != BOUNDSTYPE_CONTENT)
 852                    ? windowGeometry->final_width.value
 853                          - windowGeometry->extents.left
 854                          - windowGeometry->extents.right
 855                    : windowGeometry->final_width.value;
 856 }
 857 static int geometry_get_content_height(WindowGeometry *windowGeometry) {
 858     return (windowGeometry->final_height.type != BOUNDSTYPE_CONTENT)
 859                    ? windowGeometry->final_height.value
 860                          - windowGeometry->extents.top
 861                          - windowGeometry->extents.bottom
 862                    : windowGeometry->final_height.value;
 863 }
 864 
 865 static int geometry_get_window_x(const WindowGeometry *windowGeometry) {
 866     float value = windowGeometry->refx;
 867     if (windowGeometry->gravity_x != 0) {
 868         value -= geometry_get_window_width(windowGeometry)
 869                      * windowGeometry->gravity_x;
 870     }
 871     return (int) value;
 872 }
 873 
 874 static int geometry_get_window_y(const WindowGeometry *windowGeometry) {
 875     float value = windowGeometry->refy;
 876     if (windowGeometry->gravity_y != 0) {
 877         value -= geometry_get_window_height(windowGeometry)
 878                      * windowGeometry->gravity_y;
 879     }
 880     return (int) value;
 881 }
 882 
 883 static void geometry_set_window_x(WindowGeometry *windowGeometry, int value) {
 884     float newValue = value;
 885     if (windowGeometry->gravity_x != 0) {
 886         newValue += geometry_get_window_width(windowGeometry)
 887                 * windowGeometry->gravity_x;
 888     }
 889     windowGeometry->refx = newValue;
 890 }
 891 
 892 static void geometry_set_window_y(WindowGeometry *windowGeometry, int value) {
 893     float newValue = value;
 894     if (windowGeometry->gravity_y != 0) {
 895         newValue += geometry_get_window_height(windowGeometry)
 896                 * windowGeometry->gravity_y;
 897     }
 898     windowGeometry->refy = newValue;
 899 }
 900 
 901 void WindowContextTop::process_net_wm_property() {
 902     // Workaround for https://bugs.launchpad.net/unity/+bug/998073
 903 
 904     static GdkAtom atom_atom = gdk_atom_intern_static_string("ATOM");
 905     static GdkAtom atom_net_wm_state = gdk_atom_intern_static_string("_NET_WM_STATE");
 906     static GdkAtom atom_net_wm_state_hidden = gdk_atom_intern_static_string("_NET_WM_STATE_HIDDEN");
 907     static GdkAtom atom_net_wm_state_above = gdk_atom_intern_static_string("_NET_WM_STATE_ABOVE");
 908 
 909     gint length;
 910 
 911     glong* atoms = NULL;
 912 
 913     if (gdk_property_get(gdk_window, atom_net_wm_state, atom_atom,
 914             0, G_MAXLONG, FALSE, NULL, NULL, &length, (guchar**) &atoms)) {
 915 
 916         bool is_hidden = false;
 917         bool is_above = false;
 918         for (gint i = 0; i < (gint)(length / sizeof(glong)); i++) {
 919             if (atom_net_wm_state_hidden == (GdkAtom)atoms[i]) {
 920                 is_hidden = true;
 921             } else if (atom_net_wm_state_above == (GdkAtom)atoms[i]) {
 922                 is_above = true;
 923             }
 924         }
 925 
 926         g_free(atoms);
 927 
 928         if (is_iconified != is_hidden) {
 929             is_iconified = is_hidden;
 930 
 931             notify_state((is_hidden)
 932                     ? com_sun_glass_events_WindowEvent_MINIMIZE
 933                     : com_sun_glass_events_WindowEvent_RESTORE);
 934         }
 935 
 936         notify_on_top(is_above);
 937     }
 938 }
 939 
 940 void WindowContextTop::process_property_notify(GdkEventProperty* event) {
 941     static GdkAtom atom_net_wm_state = gdk_atom_intern_static_string("_NET_WM_STATE");
 942 
 943     if (event->atom == atom_net_wm_state && event->window == gdk_window) {
 944         process_net_wm_property();
 945     }
 946 }
 947 
 948 void WindowContextTop::process_configure(GdkEventConfigure* event) {
 949     gint x, y, w, h;
 950     bool updateWindowConstraints = false;
 951     if (gtk_window_get_decorated(GTK_WINDOW(gtk_widget))) {
 952         GdkRectangle frame;
 953         gint top, left, bottom, right;
 954 
 955         gdk_window_get_frame_extents(gdk_window, &frame);
 956         gint contentX, contentY;
 957         gdk_window_get_origin(gdk_window, &contentX, &contentY);
 958 #ifdef GLASS_GTK3
 959         gdk_window_get_geometry(gdk_window, NULL, NULL, &w, &h);
 960 #else
 961         gdk_window_get_geometry(gdk_window, NULL, NULL, &w, &h, NULL);
 962 #endif
 963         x = frame.x;
 964         y = frame.y;
 965         geometry.current_width = frame.width;
 966         geometry.current_height = frame.height;
 967 
 968         top = contentY - frame.y;
 969         left = contentX - frame.x;
 970         bottom = frame.y + frame.height - (contentY + h);
 971         right = frame.x + frame.width - (contentX + w);
 972         if (geometry.extents.top != top
 973                 || geometry.extents.left != left
 974                 || geometry.extents.bottom != bottom
 975                 || geometry.extents.right != right) {
 976             updateWindowConstraints = true;
 977             geometry.extents.top = top;
 978             geometry.extents.left = left;
 979             geometry.extents.bottom = bottom;
 980             geometry.extents.right = right;
 981         }
 982     } else {
 983         x = event->x;
 984         y = event->y;
 985         w = event->width;
 986         h = event->height;
 987     }
 988 
 989     if (size_assigned && w <= 1 && h <= 1 && (geometry.final_width.value > 1 ||
 990                                              geometry.final_height.value > 1)) {
 991         // skip artifact
 992         return;
 993     }
 994 
 995     geometry.final_width.value = w;
 996     geometry.final_width.type = BOUNDSTYPE_CONTENT;
 997     geometry.final_height.value = h;
 998     geometry.final_height.type = BOUNDSTYPE_CONTENT;
 999     geometry_set_window_x(&geometry, x);
1000     geometry_set_window_y(&geometry, y);
1001 
1002     if (jview) {
1003         mainEnv->CallVoidMethod(jview, jViewNotifyResize,
1004                 event->width,
1005                 event->height);
1006         CHECK_JNI_EXCEPTION(mainEnv)
1007         mainEnv->CallVoidMethod(jview, jViewNotifyView,
1008                 com_sun_glass_events_ViewEvent_MOVE);
1009         CHECK_JNI_EXCEPTION(mainEnv)
1010     }
1011     if (jwindow) {
1012         mainEnv->CallVoidMethod(jwindow, jWindowNotifyResize,
1013                 (is_maximized)
1014                     ? com_sun_glass_events_WindowEvent_MAXIMIZE
1015                     : com_sun_glass_events_WindowEvent_RESIZE,
1016                 geometry.current_width,
1017                 geometry.current_height);
1018         CHECK_JNI_EXCEPTION(mainEnv)
1019 
1020         mainEnv->CallVoidMethod(jwindow, jWindowNotifyMove, x, y);
1021         CHECK_JNI_EXCEPTION(mainEnv)
1022     }
1023 
1024     glong to_screen = getScreenPtrForLocation(x, y);
1025     if (to_screen != -1) {
1026         if (to_screen != screen) {
1027             if (jwindow) {
1028                 //notify screen changed
1029                 jobject jScreen = createJavaScreen(mainEnv, to_screen);
1030                 mainEnv->CallVoidMethod(jwindow, jWindowNotifyMoveToAnotherScreen, jScreen);
1031                 CHECK_JNI_EXCEPTION(mainEnv)
1032             }
1033             screen = to_screen;
1034         }
1035     }
1036 
1037     if (resizable.request != REQUEST_NONE) {
1038         set_window_resizable(resizable.request == REQUEST_RESIZABLE);
1039         resizable.request = REQUEST_NONE;
1040     } else if (!resizable.value) {
1041         set_window_resizable(false);
1042     } else if (updateWindowConstraints) {
1043         update_window_constraints();
1044     }
1045 }
1046 
1047 void WindowContextTop::update_window_constraints() {
1048     if (resizable.value) {
1049         GdkGeometry geom = {
1050             (resizable.minw == -1) ? 1
1051                     : resizable.minw - geometry.extents.left - geometry.extents.right,
1052             (resizable.minh == -1) ? 1
1053                     : resizable.minh - geometry.extents.top - geometry.extents.bottom,
1054             (resizable.maxw == -1) ? 100000
1055                     : resizable.maxw - geometry.extents.left - geometry.extents.right,
1056             (resizable.maxh == -1) ? 100000
1057                     : resizable.maxh - geometry.extents.top - geometry.extents.bottom,
1058             0, 0, 0, 0, 0.0, 0.0, GDK_GRAVITY_NORTH_WEST
1059         };
1060         gtk_window_set_geometry_hints(GTK_WINDOW(gtk_widget), NULL, &geom,
1061                 static_cast<GdkWindowHints> (GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE));
1062     }
1063 }
1064 
1065 void WindowContextTop::set_window_resizable(bool res) {
1066     if(!res) {
1067         int w = geometry_get_content_width(&geometry);
1068         int h = geometry_get_content_height(&geometry);
1069         if (w == -1 && h == -1) {
1070             gtk_window_get_size(GTK_WINDOW(gtk_widget), &w, &h);
1071         }
1072         GdkGeometry geom = {w, h, w, h, 0, 0, 0, 0, 0.0, 0.0, GDK_GRAVITY_NORTH_WEST};
1073         gtk_window_set_geometry_hints(GTK_WINDOW(gtk_widget), NULL, &geom,
1074                 static_cast<GdkWindowHints>(GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE));
1075         resizable.value = false;
1076     } else {
1077         resizable.value = true;
1078         update_window_constraints();
1079     }
1080 }
1081 
1082 void WindowContextTop::set_resizable(bool res) {
1083     resizable.prev = false;
1084     gint w, h;
1085     gtk_window_get_size(GTK_WINDOW(gtk_widget), &w, &h);
1086     if (map_received || w > 1 || h > 1) {
1087         set_window_resizable(res);
1088     } else {
1089         //Since window is not ready yet set only request for change of resizable.
1090         resizable.request  = res ? REQUEST_RESIZABLE : REQUEST_NOT_RESIZABLE;
1091     }
1092 }
1093 
1094 void WindowContextTop::set_visible(bool visible)
1095 {
1096     if (visible) {
1097         if (!size_assigned) {
1098             set_bounds(0, 0, false, false, 320, 200, -1, -1);
1099         }
1100         if (!location_assigned) {
1101             set_bounds(0, 0, true, true, -1, -1, -1, -1);
1102         }
1103     }
1104     WindowContextBase::set_visible(visible);
1105 }
1106 
1107 void WindowContextTop::set_bounds(int x, int y, bool xSet, bool ySet, int w, int h, int cw, int ch) {
1108     if (!frame_extents_initialized && frame_type == TITLED) {
1109         initialize_frame_extents();
1110         frame_extents_initialized = true;
1111     }
1112 
1113     XWindowChanges windowChanges;
1114     unsigned int windowChangesMask = 0;
1115     if (w > 0) {
1116         geometry.final_width.value = w;
1117         geometry.final_width.type = BOUNDSTYPE_WINDOW;
1118         geometry.current_width = geometry_get_window_width(&geometry);
1119         windowChanges.width = geometry_get_content_width(&geometry);
1120         windowChangesMask |= CWWidth;
1121     } else if (cw > 0) {
1122         geometry.final_width.value = cw;
1123         geometry.final_width.type = BOUNDSTYPE_CONTENT;
1124         geometry.current_width = geometry_get_window_width(&geometry);
1125         windowChanges.width = geometry_get_content_width(&geometry);
1126         windowChangesMask |= CWWidth;
1127     }
1128 
1129     if (h > 0) {
1130         geometry.final_height.value = h;
1131         geometry.final_height.type = BOUNDSTYPE_WINDOW;
1132         geometry.current_height = geometry_get_window_height(&geometry);
1133         windowChanges.height = geometry_get_content_height(&geometry);
1134         windowChangesMask |= CWHeight;
1135     } else if (ch > 0) {
1136         geometry.final_height.value = ch;
1137         geometry.final_height.type = BOUNDSTYPE_CONTENT;
1138         geometry.current_height = geometry_get_window_height(&geometry);
1139         windowChanges.height = geometry_get_content_height(&geometry);
1140         windowChangesMask |= CWHeight;
1141     }
1142 
1143     if (xSet || ySet) {
1144         if (xSet) {
1145             geometry.refx = x + geometry.current_width * geometry.gravity_x;
1146         }
1147 
1148         windowChanges.x = geometry_get_window_x(&geometry);
1149         windowChangesMask |= CWX;
1150 
1151         if (ySet) {
1152             geometry.refy = y + geometry.current_height * geometry.gravity_y;
1153         }
1154 
1155         windowChanges.y = geometry_get_window_y(&geometry);
1156         windowChangesMask |= CWY;
1157 
1158         location_assigned = true;
1159     }
1160 
1161     if (w > 0 || h > 0 || cw > 0 || ch > 0) size_assigned = true;
1162 
1163     window_configure(&windowChanges, windowChangesMask);
1164 
1165 }
1166 
1167 void WindowContextTop::process_map() {
1168     map_received = true;
1169 }
1170 
1171 void WindowContextTop::window_configure(XWindowChanges *windowChanges,
1172         unsigned int windowChangesMask) {
1173     if (windowChangesMask == 0) {
1174         return;
1175     }
1176 
1177     if (windowChangesMask & (CWX | CWY)) {
1178         gint newX, newY;
1179         gtk_window_get_position(GTK_WINDOW(gtk_widget), &newX, &newY);
1180 
1181         if (windowChangesMask & CWX) {
1182             newX = windowChanges->x;
1183         }
1184         if (windowChangesMask & CWY) {
1185             newY = windowChanges->y;
1186         }
1187         gtk_window_move(GTK_WINDOW(gtk_widget), newX, newY);
1188     }
1189 
1190     if (windowChangesMask & (CWWidth | CWHeight)) {
1191         gint newWidth, newHeight;
1192         gtk_window_get_size(GTK_WINDOW(gtk_widget), &newWidth, &newHeight);
1193 
1194         if (windowChangesMask & CWWidth) {
1195             newWidth = windowChanges->width;
1196         }
1197         if (windowChangesMask & CWHeight) {
1198             newHeight = windowChanges->height;
1199         }
1200 
1201         if (!resizable.value) {
1202             GdkGeometry geom;
1203             GdkWindowHints hints = (GdkWindowHints)(GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE);
1204             geom.min_width = geom.max_width = newWidth;
1205             geom.min_height = geom.max_height = newHeight;
1206             gtk_window_set_geometry_hints(GTK_WINDOW(gtk_widget), NULL, &geom, hints);
1207         }
1208         gtk_window_resize(GTK_WINDOW(gtk_widget), newWidth, newHeight);
1209     }
1210 }
1211 
1212 void WindowContextTop::applyShapeMask(void* data, uint width, uint height)
1213 {
1214     if (frame_type != TRANSPARENT) {
1215         return;
1216     }
1217 
1218     glass_window_apply_shape_mask(gtk_widget_get_window(gtk_widget), data, width, height);
1219 }
1220 
1221 void WindowContextTop::ensure_window_size() {
1222     gint w, h;
1223 #ifdef GLASS_GTK3
1224     gdk_window_get_geometry(gdk_window, NULL, NULL, &w, &h);
1225 #else
1226     gdk_window_get_geometry(gdk_window, NULL, NULL, &w, &h, NULL);
1227 #endif
1228     if (size_assigned && (geometry.final_width.value != w
1229                        || geometry.final_height.value != h)) {
1230 
1231         gdk_window_resize(gdk_window, geometry.final_width.value,
1232                                       geometry.final_height.value);
1233     }
1234 }
1235 
1236 void WindowContextTop::set_minimized(bool minimize) {
1237     is_iconified = minimize;
1238     if (minimize) {
1239         if (frame_type == TRANSPARENT) {
1240             // https://bugs.launchpad.net/ubuntu/+source/unity/+bug/1245571
1241             glass_window_reset_input_shape_mask(gtk_widget_get_window(gtk_widget));
1242         }
1243 
1244         if ((gdk_windowManagerFunctions & GDK_FUNC_MINIMIZE) == 0) {
1245             // in this case - the window manager will not support the programatic
1246             // request to iconify - so we need to disable this until we are restored.
1247             GdkWMFunction wmf = (GdkWMFunction)(gdk_windowManagerFunctions | GDK_FUNC_MINIMIZE);
1248             gdk_window_set_functions(gdk_window, wmf);
1249         }
1250         gtk_window_iconify(GTK_WINDOW(gtk_widget));
1251     } else {
1252         gtk_window_deiconify(GTK_WINDOW(gtk_widget));
1253         activate_window();
1254     }
1255 }
1256 void WindowContextTop::set_maximized(bool maximize) {
1257     is_maximized = maximize;
1258     if (maximize) {
1259         ensure_window_size();
1260         gtk_window_maximize(GTK_WINDOW(gtk_widget));
1261     } else {
1262         gtk_window_unmaximize(GTK_WINDOW(gtk_widget));
1263     }
1264 }
1265 
1266 void WindowContextTop::enter_fullscreen() {
1267     ensure_window_size();
1268     gtk_window_fullscreen(GTK_WINDOW(gtk_widget));
1269 }
1270 
1271 void WindowContextTop::exit_fullscreen() {
1272     gtk_window_unfullscreen(GTK_WINDOW(gtk_widget));
1273 }
1274 
1275 void WindowContextTop::request_focus() {
1276     gtk_window_present(GTK_WINDOW(gtk_widget));
1277 }
1278 
1279 void WindowContextTop::set_focusable(bool focusable) {
1280     gtk_window_set_accept_focus(GTK_WINDOW(gtk_widget), focusable ? TRUE : FALSE);
1281 }
1282 
1283 void WindowContextTop::set_title(const char* title) {
1284     gtk_window_set_title(GTK_WINDOW(gtk_widget),title);
1285 }
1286 
1287 void WindowContextTop::set_alpha(double alpha) {
1288     gtk_window_set_opacity(GTK_WINDOW(gtk_widget), (gdouble)alpha);
1289 }
1290 
1291 void WindowContextTop::set_enabled(bool enabled) {
1292     if (enabled) {
1293         if (resizable.prev) {
1294             set_window_resizable(true);
1295         }
1296     } else {
1297         if (resizable.value) {
1298             set_window_resizable(false);
1299             resizable.prev = true;
1300         } else if (resizable.request == REQUEST_RESIZABLE) {
1301             resizable.request = REQUEST_NOT_RESIZABLE;
1302             resizable.prev = true;
1303         }
1304     }
1305 }
1306 
1307 void WindowContextTop::set_minimum_size(int w, int h) {
1308     resizable.minw = w;
1309     resizable.minh = h;
1310     update_window_constraints();
1311 }
1312 
1313 void WindowContextTop::set_maximum_size(int w, int h) {
1314     resizable.maxw = w;
1315     resizable.maxh = h;
1316     update_window_constraints();
1317 }
1318 
1319 void WindowContextTop::set_icon(GdkPixbuf* pixbuf) {
1320     gtk_window_set_icon(GTK_WINDOW(gtk_widget), pixbuf);
1321 }
1322 
1323 void WindowContextTop::restack(bool restack) {
1324     gdk_window_restack(gdk_window, NULL, restack ? TRUE : FALSE);
1325 }
1326 
1327 void WindowContextTop::set_modal(bool modal, WindowContext* parent) {
1328     if (modal) {
1329         //gtk_window_set_type_hint(GTK_WINDOW(gtk_widget), GDK_WINDOW_TYPE_HINT_DIALOG);
1330         if (parent) {
1331             gtk_window_set_transient_for(GTK_WINDOW(gtk_widget), parent->get_gtk_window());
1332         }
1333     }
1334     gtk_window_set_modal(GTK_WINDOW(gtk_widget), modal ? TRUE : FALSE);
1335 }
1336 
1337 GtkWindow *WindowContextTop::get_gtk_window() {
1338     return GTK_WINDOW(gtk_widget);
1339 }
1340 
1341 WindowFrameExtents WindowContextTop::get_frame_extents() {
1342     return geometry.extents;
1343 }
1344 
1345 void WindowContextTop::set_gravity(float x, float y) {
1346     int oldX = geometry_get_window_x(&geometry);
1347     int oldY = geometry_get_window_y(&geometry);
1348     geometry.gravity_x = x;
1349     geometry.gravity_y = y;
1350     geometry_set_window_x(&geometry, oldX);
1351     geometry_set_window_y(&geometry, oldY);
1352 }
1353 
1354 void WindowContextTop::update_ontop_tree(bool on_top) {
1355     bool effective_on_top = on_top || this->on_top;
1356     gtk_window_set_keep_above(GTK_WINDOW(gtk_widget), effective_on_top ? TRUE : FALSE);
1357     for (std::set<WindowContextTop*>::iterator it = children.begin(); it != children.end(); ++it) {
1358         (*it)->update_ontop_tree(effective_on_top);
1359     }
1360 }
1361 
1362 bool WindowContextTop::on_top_inherited() {
1363     WindowContext* o = owner;
1364     while (o) {
1365         WindowContextTop* topO = dynamic_cast<WindowContextTop*>(o);
1366         if (!topO) break;
1367         if (topO->on_top) {
1368             return true;
1369         }
1370         o = topO->owner;
1371     }
1372     return false;
1373 }
1374 
1375 bool WindowContextTop::effective_on_top() {
1376     if (owner) {
1377         WindowContextTop* topO = dynamic_cast<WindowContextTop*>(owner);
1378         return (topO && topO->effective_on_top()) || on_top;
1379     }
1380     return on_top;
1381 }
1382 
1383 void WindowContextTop::notify_on_top(bool top) {
1384     // Do not report effective (i.e. native) values to the FX, only if the user sets it manually
1385     if (top != effective_on_top() && jwindow) {
1386         if (on_top_inherited() && !top) {
1387             // Disallow user's "on top" handling on windows that inherited the property
1388             gtk_window_set_keep_above(GTK_WINDOW(gtk_widget), TRUE);
1389         } else {
1390             on_top = top;
1391             update_ontop_tree(top);
1392             mainEnv->CallVoidMethod(jwindow,
1393                     jWindowNotifyLevelChanged,
1394                     top ? com_sun_glass_ui_Window_Level_FLOATING :  com_sun_glass_ui_Window_Level_NORMAL);
1395             CHECK_JNI_EXCEPTION(mainEnv);
1396         }
1397     }
1398 }
1399 
1400 void WindowContextTop::set_level(int level) {
1401     if (level == com_sun_glass_ui_Window_Level_NORMAL) {
1402         on_top = false;
1403     } else if (level == com_sun_glass_ui_Window_Level_FLOATING
1404             || level == com_sun_glass_ui_Window_Level_TOPMOST) {
1405         on_top = true;
1406     }
1407     // We need to emulate always on top behaviour on child windows
1408 
1409     if (!on_top_inherited()) {
1410         update_ontop_tree(on_top);
1411     }
1412 }
1413 
1414 void WindowContextTop::set_owner(WindowContext * owner_ctx) {
1415     owner = owner_ctx;
1416 }
1417 
1418 void WindowContextTop::process_destroy() {
1419     if (owner) {
1420         owner->remove_child(this);
1421     }
1422 
1423     WindowContextBase::process_destroy();
1424 }
1425 
1426 ////////////////////////////// WindowContextPlug ////////////////////////////////
1427 
1428 static gboolean plug_configure(GtkWidget *widget, GdkEvent *event, gpointer user_data) {
1429     (void)widget;
1430 
1431     if (event->type == GDK_CONFIGURE) {
1432         ((WindowContextPlug*)user_data)->process_gtk_configure(&event->configure);
1433     }
1434     return FALSE;
1435 }
1436 
1437 WindowContextPlug::WindowContextPlug(jobject _jwindow, void* _owner) :
1438         WindowContextBase(),
1439         parent()
1440 {
1441     jwindow = mainEnv->NewGlobalRef(_jwindow);
1442 
1443     gtk_widget = gtk_plug_new((Window)PTR_TO_JLONG(_owner));
1444 
1445     g_signal_connect(G_OBJECT(gtk_widget), "configure-event", G_CALLBACK(plug_configure), this);
1446 
1447     gtk_widget_set_size_request(gtk_widget, 0, 0);
1448     gtk_widget_set_events(gtk_widget, GDK_ALL_EVENTS_MASK);
1449     gtk_widget_set_can_focus(GTK_WIDGET(gtk_widget), TRUE);
1450     gtk_widget_set_app_paintable(gtk_widget, TRUE);
1451 
1452     gtk_widget_realize(gtk_widget);
1453     gdk_window = gtk_widget_get_window(gtk_widget);
1454 
1455     g_object_set_data_full(G_OBJECT(gdk_window), GDK_WINDOW_DATA_CONTEXT, this, NULL);
1456     gdk_window_register_dnd(gdk_window);
1457 
1458     gtk_container = gtk_fixed_new();
1459     gtk_container_add (GTK_CONTAINER(gtk_widget), gtk_container);
1460     gtk_widget_realize(gtk_container);
1461 }
1462 
1463 GtkWindow *WindowContextPlug::get_gtk_window() {
1464     return GTK_WINDOW(gtk_widget);
1465 }
1466 
1467 void WindowContextPlug::process_configure(GdkEventConfigure* event) {
1468     (void)event;
1469 
1470     //Note: process_gtk_configure is used, so there's no need to handle GDK events
1471 }
1472 
1473 void WindowContextPlug::process_gtk_configure(GdkEventConfigure* event) {
1474     if (jview) {
1475         mainEnv->CallVoidMethod(jview, jViewNotifyResize,
1476                 event->width,
1477                 event->height);
1478         CHECK_JNI_EXCEPTION(mainEnv)
1479     }
1480 
1481     mainEnv->CallVoidMethod(jwindow, jWindowNotifyResize,
1482             com_sun_glass_events_WindowEvent_RESIZE,
1483             event->width,
1484             event->height);
1485     CHECK_JNI_EXCEPTION(mainEnv)
1486 
1487     if (!embedded_children.empty()) {
1488         WindowContextChild* child = embedded_children.back();
1489         child->process_configure(event);
1490     }
1491 }
1492 
1493 bool WindowContextPlug::set_view(jobject view) {
1494     // probably never called for applet window
1495     if (jview) {
1496         mainEnv->DeleteGlobalRef(jview);
1497     }
1498 
1499     if (view) {
1500         gint width, height;
1501         jview = mainEnv->NewGlobalRef(view);
1502         gtk_window_get_size(GTK_WINDOW(gtk_widget), &width, &height);
1503         mainEnv->CallVoidMethod(view, jViewNotifyResize, width, height);
1504         CHECK_JNI_EXCEPTION_RET(mainEnv, FALSE)
1505     } else {
1506         jview = NULL;
1507     }
1508     return TRUE;
1509 }
1510 
1511 void WindowContextPlug::window_configure(XWindowChanges *windowChanges,
1512         unsigned int windowChangesMask) {
1513     if (windowChangesMask == 0) {
1514         return;
1515     }
1516 
1517     if (windowChangesMask & (CWX | CWY)) {
1518         gint newX, newY;
1519         gtk_window_get_position(GTK_WINDOW(gtk_widget), &newX, &newY);
1520 
1521         if (windowChangesMask & CWX) {
1522             newX = windowChanges->x;
1523         }
1524         if (windowChangesMask & CWY) {
1525             newY = windowChanges->y;
1526         }
1527         gtk_window_move(GTK_WINDOW(gtk_widget), newX, newY);
1528     }
1529 
1530     if (windowChangesMask & (CWWidth | CWHeight)) {
1531         gint newWidth, newHeight;
1532         gtk_window_get_size(GTK_WINDOW(gtk_widget),
1533                 &newWidth, &newHeight);
1534 
1535         if (windowChangesMask & CWWidth) {
1536             newWidth = windowChanges->width;
1537         }
1538         if (windowChangesMask & CWHeight) {
1539             newHeight = windowChanges->height;
1540         };
1541         gtk_widget_set_size_request(gtk_widget, newWidth, newHeight);
1542     }
1543 }
1544 
1545 void WindowContextPlug::set_bounds(int x, int y, bool xSet, bool ySet, int w, int h, int cw, int ch) {
1546     XWindowChanges windowChanges;
1547     unsigned int windowChangesMask = 0;
1548 
1549     if (xSet) {
1550         windowChanges.x = x;
1551         windowChangesMask |= CWX;
1552     }
1553 
1554     if (ySet) {
1555         windowChanges.y = y;
1556         windowChangesMask |= CWY;
1557     }
1558 
1559     if (w > 0) {
1560         windowChanges.width = w;
1561         windowChangesMask |= CWWidth;
1562     } else if (cw > 0) {
1563         windowChanges.width = cw;
1564         windowChangesMask |= CWWidth;
1565     }
1566 
1567     if (h > 0) {
1568         windowChanges.height = h;
1569         windowChangesMask |= CWHeight;
1570     } else if (ch > 0) {
1571         windowChanges.height = ch;
1572         windowChangesMask |= CWHeight;
1573     }
1574 
1575     window_configure(&windowChanges, windowChangesMask);
1576 }
1577 ////////////////////////////// WindowContextChild ////////////////////////////////
1578 
1579 void WindowContextChild::process_mouse_button(GdkEventButton* event) {
1580     WindowContextBase::process_mouse_button(event);
1581    // gtk_window_set_focus (GTK_WINDOW (gtk_widget_get_ancestor(gtk_widget, GTK_TYPE_WINDOW)), NULL);
1582     gtk_widget_grab_focus(gtk_widget);
1583 }
1584 
1585 static gboolean child_focus_callback(GtkWidget *widget, GdkEvent *event, gpointer user_data)
1586 {
1587     (void)widget;
1588 
1589     WindowContext *ctx = (WindowContext *)user_data;
1590     ctx->process_focus(&event->focus_change);
1591     return TRUE;
1592 }
1593 
1594 WindowContextChild::WindowContextChild(jobject _jwindow,
1595                                        void* _owner,
1596                                        GtkWidget *parent_widget,
1597                                        WindowContextPlug *parent_ctx) :
1598         WindowContextBase(),
1599         parent(),
1600         full_screen_window(),
1601         view()
1602 {
1603     (void)_owner;
1604 
1605     jwindow = mainEnv->NewGlobalRef(_jwindow);
1606     gtk_widget = gtk_drawing_area_new();
1607     parent = parent_ctx;
1608 
1609     glong xvisualID = (glong) mainEnv->GetStaticLongField(jApplicationCls, jApplicationVisualID);
1610 
1611     if (xvisualID != 0) {
1612         GdkVisual *visual = gdk_x11_screen_lookup_visual(gdk_screen_get_default(), xvisualID);
1613         glass_gtk_window_configure_from_visual(gtk_widget, visual);
1614     }
1615 
1616     gtk_widget_set_events(gtk_widget, GDK_ALL_EVENTS_MASK);
1617     gtk_widget_set_can_focus(GTK_WIDGET(gtk_widget), TRUE);
1618     gtk_widget_set_app_paintable(gtk_widget, TRUE);
1619     gtk_container_add (GTK_CONTAINER(parent_widget), gtk_widget);
1620     gtk_widget_realize(gtk_widget);
1621     gdk_window = gtk_widget_get_window(gtk_widget);
1622     g_object_set_data_full(G_OBJECT(gdk_window), GDK_WINDOW_DATA_CONTEXT, this, NULL);
1623     gdk_window_register_dnd(gdk_window);
1624     g_signal_connect(gtk_widget, "focus-in-event", G_CALLBACK(child_focus_callback), this);
1625     g_signal_connect(gtk_widget, "focus-out-event", G_CALLBACK(child_focus_callback), this);
1626 }
1627 
1628 void WindowContextChild::set_visible(bool visible) {
1629     std::vector<WindowContextChild*> &embedded_children =
1630             dynamic_cast<WindowContextPlug*>(parent)->embedded_children;
1631 
1632     if (visible) {
1633         embedded_children.push_back(this);
1634     } else {
1635         std::vector<WindowContextChild*>::iterator pos
1636                 = std::find(embedded_children.begin(), embedded_children.end(), this);
1637         if (pos != embedded_children.end()) {
1638             embedded_children.erase((pos));
1639         }
1640     }
1641 
1642     WindowContextBase::set_visible(visible);
1643 }
1644 
1645 GtkWindow *WindowContextChild::get_gtk_window() {
1646     return GTK_WINDOW(gtk_widget_get_ancestor(gtk_widget, GTK_TYPE_WINDOW));
1647 }
1648 
1649 void WindowContextChild::process_configure(GdkEventConfigure* event) {
1650     if (jview) {
1651         mainEnv->CallVoidMethod(jview, jViewNotifyResize,
1652                 event->width,
1653                 event->height);
1654         CHECK_JNI_EXCEPTION(mainEnv)
1655     }
1656 
1657     gtk_widget_set_size_request(gtk_widget, event->width, event->height);
1658 
1659     if (jwindow) {
1660         mainEnv->CallVoidMethod(jwindow, jWindowNotifyResize,
1661                 com_sun_glass_events_WindowEvent_RESIZE,
1662                 event->width,
1663                 event->height);
1664         CHECK_JNI_EXCEPTION(mainEnv)
1665     }
1666 }
1667 
1668 bool WindowContextChild::set_view(jobject view) {
1669     if (jview) {
1670         mainEnv->DeleteGlobalRef(jview);
1671     }
1672 
1673     if (view) {
1674         gint width, height;
1675         jview = mainEnv->NewGlobalRef(view);
1676         GtkAllocation ws;
1677         gtk_widget_get_allocation(gtk_widget, &ws);
1678         width = ws.width;
1679         height = ws.height;
1680         mainEnv->CallVoidMethod(view, jViewNotifyResize, width, height);
1681         CHECK_JNI_EXCEPTION_RET(mainEnv, FALSE)
1682     } else {
1683         jview = NULL;
1684     }
1685     return TRUE;
1686 }
1687 
1688 void WindowContextChild::set_bounds(int x, int y, bool xSet, bool ySet, int w, int h, int cw, int ch) {
1689 
1690     if (x > 0 || y > 0 || xSet || ySet) {
1691         gint newX, newY;
1692         gdk_window_get_origin(gdk_window, &newX, &newY);
1693         if (jwindow) {
1694             mainEnv->CallVoidMethod(jwindow,
1695                     jWindowNotifyMove,
1696                     newX, newY);
1697             CHECK_JNI_EXCEPTION(mainEnv)
1698         }
1699     }
1700 
1701     // As we have no frames, there's no difference between the calls
1702     if ((cw | ch) > 0) {
1703         w = cw; h = ch;
1704     }
1705 
1706     if (w > 0 || h > 0) {
1707         gint newWidth, newHeight;
1708         GtkAllocation ws;
1709         gtk_widget_get_allocation(gtk_widget, &ws);
1710         newWidth = ws.width;
1711         newHeight = ws.height;
1712 
1713         if (w > 0) {
1714             newWidth = w;
1715         }
1716         if (h > 0) {
1717             newHeight = h;
1718         }
1719         gtk_widget_set_size_request(gtk_widget, newWidth, newHeight);
1720         // FIXME: hack to set correct size to view
1721         if (jview) {
1722             mainEnv->CallVoidMethod(jview,
1723                     jViewNotifyResize,
1724                     newWidth, newHeight);
1725             CHECK_JNI_EXCEPTION(mainEnv)
1726         }
1727     }
1728 }
1729 
1730 int WindowContextChild::getEmbeddedX() {
1731     int x;
1732     gdk_window_get_origin(gdk_window, &x, NULL);
1733     return x;
1734 }
1735 
1736 int WindowContextChild::getEmbeddedY() {
1737     int y;
1738     gdk_window_get_origin(gdk_window, NULL, &y);
1739     return y;
1740 
1741 }
1742 
1743 void WindowContextChild::restack(bool toFront) {
1744     std::vector<WindowContextChild*> &embedded_children =
1745                 dynamic_cast<WindowContextPlug*>(parent)->embedded_children;
1746 
1747     std::vector<WindowContextChild*>::iterator pos
1748         = std::find(embedded_children.begin(), embedded_children.end(), this);
1749 
1750     embedded_children.erase(pos);
1751     if (toFront) {
1752         embedded_children.push_back(this);
1753     } else {
1754         embedded_children.insert(embedded_children.begin(), this);
1755     }
1756 
1757     gdk_window_restack(gdk_window, NULL, toFront ? TRUE : FALSE);
1758 }
1759 
1760 void WindowContextChild::enter_fullscreen() {
1761     if (full_screen_window) {
1762         return;
1763     }
1764 
1765     full_screen_window = new WindowContextTop(jwindow, NULL, 0L, UNTITLED,
1766                                                 NORMAL, (GdkWMFunction) 0);
1767     int x, y, w, h;
1768     gdk_window_get_origin(gdk_window, &x, &y);
1769 #ifdef GLASS_GTK3
1770     gdk_window_get_geometry(gdk_window, NULL, NULL, &w, &h);
1771 #else
1772     gdk_window_get_geometry(gdk_window, NULL, NULL, &w, &h, NULL);
1773 #endif
1774     full_screen_window->set_bounds(x, y, true, true, w, h, -1, -1);
1775 
1776     if (WindowContextBase::sm_grab_window == this) {
1777         ungrab_focus();
1778     }
1779 
1780     reparent_children(full_screen_window);
1781 
1782     full_screen_window->set_visible(true);
1783     full_screen_window->enter_fullscreen();
1784 
1785     if (jwindow) {
1786         mainEnv->CallVoidMethod(jwindow, jWindowNotifyDelegatePtr, (jlong)full_screen_window);
1787         CHECK_JNI_EXCEPTION(mainEnv)
1788     }
1789 
1790     if (jview) {
1791         this->view = (GlassView*)mainEnv->GetLongField(jview, jViewPtr);
1792 
1793         this->view->current_window = full_screen_window;
1794         this->view->embedded_window = this;
1795         full_screen_window->set_view(jview);
1796         this->set_view(NULL);
1797     }
1798 }
1799 
1800 void WindowContextChild::exit_fullscreen() {
1801     if (!full_screen_window) {
1802         return;
1803     }
1804 
1805     if (WindowContextBase::sm_grab_window == this) {
1806         ungrab_focus();
1807     }
1808 
1809     full_screen_window->reparent_children(this);
1810 
1811     mainEnv->CallVoidMethod(jwindow, jWindowNotifyDelegatePtr, (jlong)NULL);
1812     CHECK_JNI_EXCEPTION(mainEnv)
1813 
1814     if (this->view) {
1815         this->view->current_window = this;
1816         this->view->embedded_window = NULL;
1817     }
1818     this->set_view(full_screen_window->get_jview());
1819 
1820     full_screen_window->detach_from_java();
1821 
1822     full_screen_window->set_view(NULL);
1823 
1824     full_screen_window->set_visible(false);
1825 
1826     destroy_and_delete_ctx(full_screen_window);
1827     full_screen_window = NULL;
1828     this->view = NULL;
1829 }
1830 
1831 void WindowContextChild::process_destroy() {
1832     if (full_screen_window) {
1833         destroy_and_delete_ctx(full_screen_window);
1834     }
1835 
1836     std::vector<WindowContextChild*> &embedded_children =
1837             dynamic_cast<WindowContextPlug*>(parent)->embedded_children;
1838 
1839     std::vector<WindowContextChild*>::iterator pos
1840                 = std::find(embedded_children.begin(), embedded_children.end(), this);
1841     if (pos != embedded_children.end()) {
1842         embedded_children.erase((pos));
1843     }
1844 
1845     WindowContextBase::process_destroy();
1846 }