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     if (event->state & GDK_SHIFT_MASK) {
 376         jdouble t = dy;
 377         dy = dx;
 378         dx = t;
 379     }
 380     if (jview) {
 381         mainEnv->CallVoidMethod(jview, jViewNotifyScroll,
 382                 (jint) event->x, (jint) event->y,
 383                 (jint) event->x_root, (jint) event->y_root,
 384                 dx, dy,
 385                 gdk_modifier_mask_to_glass(event->state),
 386                 (jint) 0, (jint) 0,
 387                 (jint) 0, (jint) 0,
 388                 (jdouble) 40.0, (jdouble) 40.0);
 389         CHECK_JNI_EXCEPTION(mainEnv)
 390     }
 391 
 392 }
 393 
 394 void WindowContextBase::process_mouse_cross(GdkEventCrossing* event) {
 395     bool enter = event->type == GDK_ENTER_NOTIFY;
 396     if (jview) {
 397         guint state = event->state;
 398         if (enter) { // workaround for RT-21590
 399             state &= ~MOUSE_BUTTONS_MASK;
 400         }
 401 
 402         if (enter != is_mouse_entered) {
 403             is_mouse_entered = enter;
 404             mainEnv->CallVoidMethod(jview, jViewNotifyMouse,
 405                     enter ? com_sun_glass_events_MouseEvent_ENTER : com_sun_glass_events_MouseEvent_EXIT,
 406                     com_sun_glass_events_MouseEvent_BUTTON_NONE,
 407                     (jint) event->x, (jint) event->y,
 408                     (jint) event->x_root, (jint) event->y_root,
 409                     gdk_modifier_mask_to_glass(state),
 410                     JNI_FALSE,
 411                     JNI_FALSE);
 412             CHECK_JNI_EXCEPTION(mainEnv)
 413         }
 414     }
 415 }
 416 
 417 void WindowContextBase::process_key(GdkEventKey* event) {
 418     bool press = event->type == GDK_KEY_PRESS;
 419     jint glassKey = get_glass_key(event);
 420     jint glassModifier = gdk_modifier_mask_to_glass(event->state);
 421     if (press) {
 422         glassModifier |= glass_key_to_modifier(glassKey);
 423     } else {
 424         glassModifier &= ~glass_key_to_modifier(glassKey);
 425     }
 426     jcharArray jChars = NULL;
 427     jchar key = gdk_keyval_to_unicode(event->keyval);
 428     if (key >= 'a' && key <= 'z' && (event->state & GDK_CONTROL_MASK)) {
 429         key = key - 'a' + 1; // map 'a' to ctrl-a, and so on.
 430     } else {
 431 #ifdef GLASS_GTK2
 432         if (key == 0) {
 433             // Work around "bug" fixed in gtk-3.0:
 434             // http://mail.gnome.org/archives/commits-list/2011-March/msg06832.html
 435             switch (event->keyval) {
 436             case 0xFF08 /* Backspace */: key =  '\b';
 437             case 0xFF09 /* Tab       */: key =  '\t';
 438             case 0xFF0A /* Linefeed  */: key =  '\n';
 439             case 0xFF0B /* Vert. Tab */: key =  '\v';
 440             case 0xFF0D /* Return    */: key =  '\r';
 441             case 0xFF1B /* Escape    */: key =  '\033';
 442             case 0xFFFF /* Delete    */: key =  '\177';
 443             }
 444         }
 445 #endif
 446     }
 447 
 448     if (key > 0) {
 449         jChars = mainEnv->NewCharArray(1);
 450         if (jChars) {
 451             mainEnv->SetCharArrayRegion(jChars, 0, 1, &key);
 452             CHECK_JNI_EXCEPTION(mainEnv)
 453         }
 454     } else {
 455         jChars = mainEnv->NewCharArray(0);
 456     }
 457     if (jview) {
 458         if (press) {
 459             mainEnv->CallVoidMethod(jview, jViewNotifyKey,
 460                     com_sun_glass_events_KeyEvent_PRESS,
 461                     glassKey,
 462                     jChars,
 463                     glassModifier);
 464             CHECK_JNI_EXCEPTION(mainEnv)
 465 
 466             if (jview && key > 0) { // TYPED events should only be sent for printable characters.
 467                 mainEnv->CallVoidMethod(jview, jViewNotifyKey,
 468                         com_sun_glass_events_KeyEvent_TYPED,
 469                         com_sun_glass_events_KeyEvent_VK_UNDEFINED,
 470                         jChars,
 471                         glassModifier);
 472                 CHECK_JNI_EXCEPTION(mainEnv)
 473             }
 474         } else {
 475             mainEnv->CallVoidMethod(jview, jViewNotifyKey,
 476                     com_sun_glass_events_KeyEvent_RELEASE,
 477                     glassKey,
 478                     jChars,
 479                     glassModifier);
 480             CHECK_JNI_EXCEPTION(mainEnv)
 481         }
 482     }
 483 }
 484 
 485 void WindowContextBase::paint(void* data, jint width, jint height)
 486 {
 487     if (!is_visible()) {
 488         return;
 489     }
 490 #ifdef GLASS_GTK3
 491     cairo_region_t *region = gdk_window_get_clip_region(gdk_window);
 492     gdk_window_begin_paint_region(gdk_window, region);
 493 #endif
 494     cairo_t* context;
 495     context = gdk_cairo_create(gdk_window);
 496 
 497     cairo_surface_t* cairo_surface;
 498     cairo_surface = cairo_image_surface_create_for_data(
 499             (unsigned char*)data,
 500             CAIRO_FORMAT_ARGB32,
 501             width, height, width * 4);
 502 
 503     applyShapeMask(data, width, height);
 504 
 505     cairo_set_source_surface(context, cairo_surface, 0, 0);
 506     cairo_set_operator (context, CAIRO_OPERATOR_SOURCE);
 507     cairo_paint(context);
 508 #ifdef GLASS_GTK3
 509     gdk_window_end_paint(gdk_window);
 510     cairo_region_destroy(region);
 511 #endif
 512 
 513     cairo_destroy(context);
 514     cairo_surface_destroy(cairo_surface);
 515 }
 516 
 517 void WindowContextBase::add_child(WindowContextTop* child) {
 518     children.insert(child);
 519     gtk_window_set_transient_for(child->get_gtk_window(), this->get_gtk_window());
 520 }
 521 
 522 void WindowContextBase::remove_child(WindowContextTop* child) {
 523     children.erase(child);
 524     gtk_window_set_transient_for(child->get_gtk_window(), NULL);
 525 }
 526 
 527 void WindowContextBase::show_or_hide_children(bool show) {
 528     std::set<WindowContextTop*>::iterator it;
 529     for (it = children.begin(); it != children.end(); ++it) {
 530         (*it)->set_minimized(!show);
 531         (*it)->show_or_hide_children(show);
 532     }
 533 }
 534 
 535 void WindowContextBase::reparent_children(WindowContext* parent) {
 536     std::set<WindowContextTop*>::iterator it;
 537     for (it = children.begin(); it != children.end(); ++it) {
 538         (*it)->set_owner(parent);
 539         parent->add_child(*it);
 540     }
 541     children.clear();
 542 }
 543 
 544 void WindowContextBase::set_visible(bool visible) {
 545     if (visible) {
 546         gtk_widget_show_all(gtk_widget);
 547     } else {
 548         gtk_widget_hide(gtk_widget);
 549         if (jview && is_mouse_entered) {
 550             is_mouse_entered = false;
 551             mainEnv->CallVoidMethod(jview, jViewNotifyMouse,
 552                     com_sun_glass_events_MouseEvent_EXIT,
 553                     com_sun_glass_events_MouseEvent_BUTTON_NONE,
 554                     0, 0,
 555                     0, 0,
 556                     0,
 557                     JNI_FALSE,
 558                     JNI_FALSE);
 559             CHECK_JNI_EXCEPTION(mainEnv)
 560         }
 561     }
 562 }
 563 
 564 bool WindowContextBase::is_visible() {
 565     return gtk_widget_get_visible(gtk_widget);
 566 }
 567 
 568 bool WindowContextBase::set_view(jobject view) {
 569 
 570     if (jview) {
 571         mainEnv->DeleteGlobalRef(jview);
 572     }
 573 
 574     if (view) {
 575         gint width, height;
 576         jview = mainEnv->NewGlobalRef(view);
 577         gtk_window_get_size(GTK_WINDOW(gtk_widget), &width, &height);
 578         mainEnv->CallVoidMethod(view, jViewNotifyResize, width, height);
 579         CHECK_JNI_EXCEPTION_RET(mainEnv, FALSE)
 580     } else {
 581         jview = NULL;
 582     }
 583     return TRUE;
 584 }
 585 
 586 bool WindowContextBase::grab_mouse_drag_focus() {
 587     if (glass_gdk_mouse_devices_grab_with_cursor(
 588             gdk_window, gdk_window_get_cursor(gdk_window), FALSE)) {
 589         WindowContextBase::sm_mouse_drag_window = this;
 590         return true;
 591     } else {
 592         return false;
 593     }
 594 }
 595 
 596 void WindowContextBase::ungrab_mouse_drag_focus() {
 597     WindowContextBase::sm_mouse_drag_window = NULL;
 598     glass_gdk_mouse_devices_ungrab();
 599     if (WindowContextBase::sm_grab_window) {
 600         WindowContextBase::sm_grab_window->grab_focus();
 601     }
 602 }
 603 
 604 bool WindowContextBase::grab_focus() {
 605     if (WindowContextBase::sm_mouse_drag_window
 606             || glass_gdk_mouse_devices_grab(gdk_window)) {
 607         WindowContextBase::sm_grab_window = this;
 608         return true;
 609     } else {
 610         return false;
 611     }
 612 }
 613 
 614 void WindowContextBase::ungrab_focus() {
 615     if (!WindowContextBase::sm_mouse_drag_window) {
 616         glass_gdk_mouse_devices_ungrab();
 617     }
 618     WindowContextBase::sm_grab_window = NULL;
 619 
 620     if (jwindow) {
 621         mainEnv->CallVoidMethod(jwindow, jWindowNotifyFocusUngrab);
 622         CHECK_JNI_EXCEPTION(mainEnv)
 623     }
 624 }
 625 
 626 void WindowContextBase::set_cursor(GdkCursor* cursor) {
 627     if (!is_in_drag()) {
 628         if (WindowContextBase::sm_mouse_drag_window) {
 629             glass_gdk_mouse_devices_grab_with_cursor(
 630                     WindowContextBase::sm_mouse_drag_window->get_gdk_window(), cursor, FALSE);
 631         } else if (WindowContextBase::sm_grab_window) {
 632             glass_gdk_mouse_devices_grab_with_cursor(
 633                     WindowContextBase::sm_grab_window->get_gdk_window(), cursor, TRUE);
 634         }
 635     }
 636     gdk_window_set_cursor(gdk_window, cursor);
 637 }
 638 
 639 void WindowContextBase::set_background(float r, float g, float b) {
 640 #ifdef GLASS_GTK3
 641     GdkRGBA rgba = {0, 0, 0, 1.};
 642     rgba.red = r;
 643     rgba.green = g;
 644     rgba.blue = b;
 645     gdk_window_set_background_rgba(gdk_window, &rgba);
 646 #else
 647     GdkColor color;
 648     color.red   = (guint16) (r * 65535);
 649     color.green = (guint16) (g * 65535);
 650     color.blue  = (guint16) (b * 65535);
 651     gtk_widget_modify_bg(gtk_widget, GTK_STATE_NORMAL, &color);
 652 #endif
 653 }
 654 
 655 WindowContextBase::~WindowContextBase() {
 656     if (xim.ic) {
 657         XDestroyIC(xim.ic);
 658         xim.ic = NULL;
 659     }
 660     if (xim.im) {
 661         XCloseIM(xim.im);
 662         xim.im = NULL;
 663     }
 664 
 665     gtk_widget_destroy(gtk_widget);
 666 }
 667 
 668 ////////////////////////////// WindowContextTop /////////////////////////////////
 669 
 670 
 671 WindowContextTop::WindowContextTop(jobject _jwindow, WindowContext* _owner, long _screen,
 672         WindowFrameType _frame_type, WindowType type, GdkWMFunction wmf) :
 673             WindowContextBase(),
 674             screen(_screen),
 675             frame_type(_frame_type),
 676             owner(_owner),
 677             geometry(),
 678             resizable(),
 679             frame_extents_initialized(),
 680             map_received(false),
 681             location_assigned(false),
 682             size_assigned(false),
 683             on_top(false),
 684             requested_bounds()
 685 {
 686     jwindow = mainEnv->NewGlobalRef(_jwindow);
 687 
 688     gtk_widget =  gtk_window_new(type == POPUP ? GTK_WINDOW_POPUP : GTK_WINDOW_TOPLEVEL);
 689 
 690     if (gchar* app_name = get_application_name()) {
 691         gtk_window_set_wmclass(GTK_WINDOW(gtk_widget), app_name, app_name);
 692         g_free(app_name);
 693     }
 694 
 695     if (owner) {
 696         owner->add_child(this);
 697         if (on_top_inherited()) {
 698             gtk_window_set_keep_above(GTK_WINDOW(gtk_widget), TRUE);
 699         }
 700     }
 701 
 702     if (type == UTILITY) {
 703         gtk_window_set_type_hint(GTK_WINDOW(gtk_widget), GDK_WINDOW_TYPE_HINT_UTILITY);
 704     }
 705 
 706 //    glong xdisplay = (glong)mainEnv->GetStaticLongField(jApplicationCls, jApplicationDisplay);
 707 //    gint  xscreenID = (gint)mainEnv->GetStaticIntField(jApplicationCls, jApplicationScreen);
 708     glong xvisualID = (glong)mainEnv->GetStaticLongField(jApplicationCls, jApplicationVisualID);
 709 
 710     if (xvisualID != 0) {
 711         GdkVisual *visual = gdk_x11_screen_lookup_visual(gdk_screen_get_default(), xvisualID);
 712         glass_gtk_window_configure_from_visual(gtk_widget, visual);
 713     }
 714 
 715     gtk_widget_set_size_request(gtk_widget, 0, 0);
 716     gtk_widget_set_events(gtk_widget, GDK_ALL_EVENTS_MASK);
 717     gtk_widget_set_app_paintable(gtk_widget, TRUE);
 718     if (frame_type != TITLED) {
 719         gtk_window_set_decorated(GTK_WINDOW(gtk_widget), FALSE);
 720     }
 721 
 722     glass_gtk_configure_transparency_and_realize(gtk_widget, frame_type == TRANSPARENT);
 723     gtk_window_set_title(GTK_WINDOW(gtk_widget), "");
 724 
 725     gdk_window = gtk_widget_get_window(gtk_widget);
 726 
 727     g_object_set_data_full(G_OBJECT(gdk_window), GDK_WINDOW_DATA_CONTEXT, this, NULL);
 728 
 729     gdk_window_register_dnd(gdk_window);
 730 
 731     gdk_windowManagerFunctions = wmf;
 732     if (wmf) {
 733         gdk_window_set_functions(gdk_window, wmf);
 734     }
 735 
 736     if (frame_type == TITLED) {
 737         request_frame_extents();
 738     }
 739 }
 740 
 741 // Applied to a temporary full screen window to prevent sending events to Java
 742 void WindowContextTop::detach_from_java() {
 743     if (jview) {
 744         mainEnv->DeleteGlobalRef(jview);
 745         jview = NULL;
 746     }
 747     if (jwindow) {
 748         mainEnv->DeleteGlobalRef(jwindow);
 749         jwindow = NULL;
 750     }
 751 }
 752 
 753 static GdkAtom
 754 get_net_frame_extents_atom() {
 755     static const char * extents_str = "_NET_FRAME_EXTENTS";
 756     return gdk_atom_intern(extents_str, TRUE);
 757 }
 758 
 759 void
 760 WindowContextTop::request_frame_extents() {
 761     Display *display = GDK_DISPLAY_XDISPLAY(gdk_window_get_display(gdk_window));
 762     Atom rfeAtom = XInternAtom(display, "_NET_REQUEST_FRAME_EXTENTS", True);
 763     if (rfeAtom != None) {
 764         XClientMessageEvent clientMessage;
 765         memset(&clientMessage, 0, sizeof(clientMessage));
 766 
 767         clientMessage.type = ClientMessage;
 768         clientMessage.window = GDK_WINDOW_XID(gdk_window);
 769         clientMessage.message_type = rfeAtom;
 770         clientMessage.format = 32;
 771 
 772         XSendEvent(display, XDefaultRootWindow(display), False,
 773                    SubstructureRedirectMask | SubstructureNotifyMask,
 774                    (XEvent *) &clientMessage);
 775         XFlush(display);
 776     }
 777 }
 778 
 779 void WindowContextTop::activate_window() {
 780     Display *display = GDK_DISPLAY_XDISPLAY (gdk_window_get_display (gdk_window));
 781     Atom navAtom = XInternAtom(display, "_NET_ACTIVE_WINDOW", True);
 782     if (navAtom != None) {
 783         XClientMessageEvent clientMessage;
 784         memset(&clientMessage, 0, sizeof(clientMessage));
 785 
 786         clientMessage.type = ClientMessage;
 787         clientMessage.window = GDK_WINDOW_XID(gdk_window);
 788         clientMessage.message_type = navAtom;
 789         clientMessage.format = 32;
 790         clientMessage.data.l[0] = 1;
 791         clientMessage.data.l[1] = gdk_x11_get_server_time(gdk_window);
 792         clientMessage.data.l[2] = 0;
 793 
 794         XSendEvent(display, XDefaultRootWindow(display), False,
 795                    SubstructureRedirectMask | SubstructureNotifyMask,
 796                    (XEvent *) &clientMessage);
 797         XFlush(display);
 798     }
 799 }
 800 
 801 void
 802 WindowContextTop::initialize_frame_extents() {
 803     int top, left, bottom, right;
 804     if (get_frame_extents_property(&top, &left, &bottom, &right)) {
 805         geometry.extents.top = top;
 806         geometry.extents.left = left;
 807         geometry.extents.bottom = bottom;
 808         geometry.extents.right = right;
 809     }
 810 }
 811 
 812 bool
 813 WindowContextTop::get_frame_extents_property(int *top, int *left,
 814         int *bottom, int *right) {
 815     unsigned long *extents;
 816 
 817     if (gdk_property_get(gdk_window,
 818             get_net_frame_extents_atom(),
 819             gdk_atom_intern("CARDINAL", FALSE),
 820             0,
 821             sizeof (unsigned long) * 4,
 822             FALSE,
 823             NULL,
 824             NULL,
 825             NULL,
 826             (guchar**) & extents)) {
 827         *left = extents [0];
 828         *right = extents [1];
 829         *top = extents [2];
 830         *bottom = extents [3];
 831 
 832         g_free(extents);
 833         return true;
 834     }
 835 
 836     return false;
 837 }
 838 
 839 static int geometry_get_window_width(const WindowGeometry *windowGeometry) {
 840      return (windowGeometry->final_width.type != BOUNDSTYPE_WINDOW)
 841                    ? windowGeometry->final_width.value
 842                          + windowGeometry->extents.left
 843                          + windowGeometry->extents.right
 844                    : windowGeometry->final_width.value;
 845 }
 846 
 847 static int geometry_get_window_height(const WindowGeometry *windowGeometry) {
 848     return (windowGeometry->final_height.type != BOUNDSTYPE_WINDOW)
 849                    ? windowGeometry->final_height.value
 850                          + windowGeometry->extents.top
 851                          + windowGeometry->extents.bottom
 852                    : windowGeometry->final_height.value;
 853 }
 854 
 855 static int geometry_get_content_width(WindowGeometry *windowGeometry) {
 856     return (windowGeometry->final_width.type != BOUNDSTYPE_CONTENT)
 857                    ? windowGeometry->final_width.value
 858                          - windowGeometry->extents.left
 859                          - windowGeometry->extents.right
 860                    : windowGeometry->final_width.value;
 861 }
 862 static int geometry_get_content_height(WindowGeometry *windowGeometry) {
 863     return (windowGeometry->final_height.type != BOUNDSTYPE_CONTENT)
 864                    ? windowGeometry->final_height.value
 865                          - windowGeometry->extents.top
 866                          - windowGeometry->extents.bottom
 867                    : windowGeometry->final_height.value;
 868 }
 869 
 870 static int geometry_get_window_x(const WindowGeometry *windowGeometry) {
 871     float value = windowGeometry->refx;
 872     if (windowGeometry->gravity_x != 0) {
 873         value -= geometry_get_window_width(windowGeometry)
 874                      * windowGeometry->gravity_x;
 875     }
 876     return (int) value;
 877 }
 878 
 879 static int geometry_get_window_y(const WindowGeometry *windowGeometry) {
 880     float value = windowGeometry->refy;
 881     if (windowGeometry->gravity_y != 0) {
 882         value -= geometry_get_window_height(windowGeometry)
 883                      * windowGeometry->gravity_y;
 884     }
 885     return (int) value;
 886 }
 887 
 888 static void geometry_set_window_x(WindowGeometry *windowGeometry, int value) {
 889     float newValue = value;
 890     if (windowGeometry->gravity_x != 0) {
 891         newValue += geometry_get_window_width(windowGeometry)
 892                 * windowGeometry->gravity_x;
 893     }
 894     windowGeometry->refx = newValue;
 895 }
 896 
 897 static void geometry_set_window_y(WindowGeometry *windowGeometry, int value) {
 898     float newValue = value;
 899     if (windowGeometry->gravity_y != 0) {
 900         newValue += geometry_get_window_height(windowGeometry)
 901                 * windowGeometry->gravity_y;
 902     }
 903     windowGeometry->refy = newValue;
 904 }
 905 
 906 void WindowContextTop::process_net_wm_property() {
 907     // Workaround for https://bugs.launchpad.net/unity/+bug/998073
 908 
 909     static GdkAtom atom_atom = gdk_atom_intern_static_string("ATOM");
 910     static GdkAtom atom_net_wm_state = gdk_atom_intern_static_string("_NET_WM_STATE");
 911     static GdkAtom atom_net_wm_state_hidden = gdk_atom_intern_static_string("_NET_WM_STATE_HIDDEN");
 912     static GdkAtom atom_net_wm_state_above = gdk_atom_intern_static_string("_NET_WM_STATE_ABOVE");
 913 
 914     gint length;
 915 
 916     glong* atoms = NULL;
 917 
 918     if (gdk_property_get(gdk_window, atom_net_wm_state, atom_atom,
 919             0, G_MAXLONG, FALSE, NULL, NULL, &length, (guchar**) &atoms)) {
 920 
 921         bool is_hidden = false;
 922         bool is_above = false;
 923         for (gint i = 0; i < (gint)(length / sizeof(glong)); i++) {
 924             if (atom_net_wm_state_hidden == (GdkAtom)atoms[i]) {
 925                 is_hidden = true;
 926             } else if (atom_net_wm_state_above == (GdkAtom)atoms[i]) {
 927                 is_above = true;
 928             }
 929         }
 930 
 931         g_free(atoms);
 932 
 933         if (is_iconified != is_hidden) {
 934             is_iconified = is_hidden;
 935 
 936             notify_state((is_hidden)
 937                     ? com_sun_glass_events_WindowEvent_MINIMIZE
 938                     : com_sun_glass_events_WindowEvent_RESTORE);
 939         }
 940 
 941         notify_on_top(is_above);
 942     }
 943 }
 944 
 945 void WindowContextTop::process_property_notify(GdkEventProperty* event) {
 946     static GdkAtom atom_net_wm_state = gdk_atom_intern_static_string("_NET_WM_STATE");
 947 
 948     if (event->atom == atom_net_wm_state && event->window == gdk_window) {
 949         process_net_wm_property();
 950     }
 951 }
 952 
 953 void WindowContextTop::process_configure(GdkEventConfigure* event) {
 954     gint x, y, w, h;
 955     bool updateWindowConstraints = false;
 956     if (gtk_window_get_decorated(GTK_WINDOW(gtk_widget))) {
 957         GdkRectangle frame;
 958         gint top, left, bottom, right;
 959 
 960         gdk_window_get_frame_extents(gdk_window, &frame);
 961         gint contentX, contentY;
 962         gdk_window_get_origin(gdk_window, &contentX, &contentY);
 963 #ifdef GLASS_GTK3
 964         gdk_window_get_geometry(gdk_window, NULL, NULL, &w, &h);
 965 #else
 966         gdk_window_get_geometry(gdk_window, NULL, NULL, &w, &h, NULL);
 967 #endif
 968         x = frame.x;
 969         y = frame.y;
 970         geometry.current_width = frame.width;
 971         geometry.current_height = frame.height;
 972 
 973         top = contentY - frame.y;
 974         left = contentX - frame.x;
 975         bottom = frame.y + frame.height - (contentY + h);
 976         right = frame.x + frame.width - (contentX + w);
 977         if (geometry.extents.top != top
 978                 || geometry.extents.left != left
 979                 || geometry.extents.bottom != bottom
 980                 || geometry.extents.right != right) {
 981             updateWindowConstraints = true;
 982             geometry.extents.top = top;
 983             geometry.extents.left = left;
 984             geometry.extents.bottom = bottom;
 985             geometry.extents.right = right;
 986             if (!frame_extents_initialized && !is_null_extents()) {
 987                 set_bounds(0, 0, false, false,
 988                     requested_bounds.width, requested_bounds.height,
 989                     requested_bounds.client_width, requested_bounds.client_height
 990                 );
 991                 frame_extents_initialized = true;
 992             }
 993         }
 994     } else {
 995         x = event->x;
 996         y = event->y;
 997         w = event->width;
 998         h = event->height;
 999     }
1000 
1001     if (size_assigned && w <= 1 && h <= 1 && (geometry.final_width.value > 1 ||
1002                                              geometry.final_height.value > 1)) {
1003         // skip artifact
1004         return;
1005     }
1006 
1007     geometry.final_width.value = w;
1008     geometry.final_width.type = BOUNDSTYPE_CONTENT;
1009     geometry.final_height.value = h;
1010     geometry.final_height.type = BOUNDSTYPE_CONTENT;
1011     geometry_set_window_x(&geometry, x);
1012     geometry_set_window_y(&geometry, y);
1013 
1014     if (jview) {
1015         mainEnv->CallVoidMethod(jview, jViewNotifyResize,
1016                 event->width,
1017                 event->height);
1018         CHECK_JNI_EXCEPTION(mainEnv)
1019         mainEnv->CallVoidMethod(jview, jViewNotifyView,
1020                 com_sun_glass_events_ViewEvent_MOVE);
1021         CHECK_JNI_EXCEPTION(mainEnv)
1022     }
1023     if (jwindow) {
1024         mainEnv->CallVoidMethod(jwindow, jWindowNotifyResize,
1025                 (is_maximized)
1026                     ? com_sun_glass_events_WindowEvent_MAXIMIZE
1027                     : com_sun_glass_events_WindowEvent_RESIZE,
1028                 geometry.current_width,
1029                 geometry.current_height);
1030         CHECK_JNI_EXCEPTION(mainEnv)
1031 
1032         mainEnv->CallVoidMethod(jwindow, jWindowNotifyMove, x, y);
1033         CHECK_JNI_EXCEPTION(mainEnv)
1034     }
1035 
1036     glong to_screen = getScreenPtrForLocation(x, y);
1037     if (to_screen != -1) {
1038         if (to_screen != screen) {
1039             if (jwindow) {
1040                 //notify screen changed
1041                 jobject jScreen = createJavaScreen(mainEnv, to_screen);
1042                 mainEnv->CallVoidMethod(jwindow, jWindowNotifyMoveToAnotherScreen, jScreen);
1043                 CHECK_JNI_EXCEPTION(mainEnv)
1044             }
1045             screen = to_screen;
1046         }
1047     }
1048 
1049     if (resizable.request != REQUEST_NONE) {
1050         set_window_resizable(resizable.request == REQUEST_RESIZABLE);
1051         resizable.request = REQUEST_NONE;
1052     } else if (!resizable.value) {
1053         set_window_resizable(false);
1054     } else if (updateWindowConstraints) {
1055         update_window_constraints();
1056     }
1057 }
1058 
1059 void WindowContextTop::update_window_constraints() {
1060     if (resizable.value) {
1061         GdkGeometry geom = {
1062             (resizable.minw == -1) ? 1
1063                     : resizable.minw - geometry.extents.left - geometry.extents.right,
1064             (resizable.minh == -1) ? 1
1065                     : resizable.minh - geometry.extents.top - geometry.extents.bottom,
1066             (resizable.maxw == -1) ? 100000
1067                     : resizable.maxw - geometry.extents.left - geometry.extents.right,
1068             (resizable.maxh == -1) ? 100000
1069                     : resizable.maxh - geometry.extents.top - geometry.extents.bottom,
1070             0, 0, 0, 0, 0.0, 0.0, GDK_GRAVITY_NORTH_WEST
1071         };
1072         gtk_window_set_geometry_hints(GTK_WINDOW(gtk_widget), NULL, &geom,
1073                 static_cast<GdkWindowHints> (GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE));
1074     }
1075 }
1076 
1077 void WindowContextTop::set_window_resizable(bool res) {
1078     if(!res) {
1079         int w = geometry_get_content_width(&geometry);
1080         int h = geometry_get_content_height(&geometry);
1081         if (w == -1 && h == -1) {
1082             gtk_window_get_size(GTK_WINDOW(gtk_widget), &w, &h);
1083         }
1084         GdkGeometry geom = {w, h, w, h, 0, 0, 0, 0, 0.0, 0.0, GDK_GRAVITY_NORTH_WEST};
1085         gtk_window_set_geometry_hints(GTK_WINDOW(gtk_widget), NULL, &geom,
1086                 static_cast<GdkWindowHints>(GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE));
1087         resizable.value = false;
1088     } else {
1089         resizable.value = true;
1090         update_window_constraints();
1091     }
1092 }
1093 
1094 void WindowContextTop::set_resizable(bool res) {
1095     resizable.prev = false;
1096     gint w, h;
1097     gtk_window_get_size(GTK_WINDOW(gtk_widget), &w, &h);
1098     if (map_received || w > 1 || h > 1) {
1099         set_window_resizable(res);
1100     } else {
1101         //Since window is not ready yet set only request for change of resizable.
1102         resizable.request  = res ? REQUEST_RESIZABLE : REQUEST_NOT_RESIZABLE;
1103     }
1104 }
1105 
1106 void WindowContextTop::set_visible(bool visible)
1107 {
1108     if (visible) {
1109         if (!size_assigned) {
1110             set_bounds(0, 0, false, false, 320, 200, -1, -1);
1111         }
1112         if (!location_assigned) {
1113             set_bounds(0, 0, true, true, -1, -1, -1, -1);
1114         }
1115     }
1116     WindowContextBase::set_visible(visible);
1117 }
1118 
1119 void WindowContextTop::set_bounds(int x, int y, bool xSet, bool ySet, int w, int h, int cw, int ch) {
1120     requested_bounds.width = w;
1121     requested_bounds.height = h;
1122     requested_bounds.client_width = cw;
1123     requested_bounds.client_height = ch;
1124 
1125     if (!frame_extents_initialized && frame_type == TITLED) {
1126         initialize_frame_extents();
1127         if (!is_null_extents()) {
1128             frame_extents_initialized = true;
1129         }
1130     }
1131 
1132     XWindowChanges windowChanges;
1133     unsigned int windowChangesMask = 0;
1134     if (w > 0) {
1135         geometry.final_width.value = w;
1136         geometry.final_width.type = BOUNDSTYPE_WINDOW;
1137         geometry.current_width = geometry_get_window_width(&geometry);
1138         windowChanges.width = geometry_get_content_width(&geometry);
1139         windowChangesMask |= CWWidth;
1140     } else if (cw > 0) {
1141         geometry.final_width.value = cw;
1142         geometry.final_width.type = BOUNDSTYPE_CONTENT;
1143         geometry.current_width = geometry_get_window_width(&geometry);
1144         windowChanges.width = geometry_get_content_width(&geometry);
1145         windowChangesMask |= CWWidth;
1146     }
1147 
1148     if (h > 0) {
1149         geometry.final_height.value = h;
1150         geometry.final_height.type = BOUNDSTYPE_WINDOW;
1151         geometry.current_height = geometry_get_window_height(&geometry);
1152         windowChanges.height = geometry_get_content_height(&geometry);
1153         windowChangesMask |= CWHeight;
1154     } else if (ch > 0) {
1155         geometry.final_height.value = ch;
1156         geometry.final_height.type = BOUNDSTYPE_CONTENT;
1157         geometry.current_height = geometry_get_window_height(&geometry);
1158         windowChanges.height = geometry_get_content_height(&geometry);
1159         windowChangesMask |= CWHeight;
1160     }
1161 
1162     if (xSet || ySet) {
1163         if (xSet) {
1164             geometry.refx = x + geometry.current_width * geometry.gravity_x;
1165         }
1166 
1167         windowChanges.x = geometry_get_window_x(&geometry);
1168         windowChangesMask |= CWX;
1169 
1170         if (ySet) {
1171             geometry.refy = y + geometry.current_height * geometry.gravity_y;
1172         }
1173 
1174         windowChanges.y = geometry_get_window_y(&geometry);
1175         windowChangesMask |= CWY;
1176 
1177         location_assigned = true;
1178     }
1179 
1180     if (w > 0 || h > 0 || cw > 0 || ch > 0) size_assigned = true;
1181 
1182     window_configure(&windowChanges, windowChangesMask);
1183 
1184 }
1185 
1186 void WindowContextTop::process_map() {
1187     map_received = true;
1188 }
1189 
1190 void WindowContextTop::window_configure(XWindowChanges *windowChanges,
1191         unsigned int windowChangesMask) {
1192     if (windowChangesMask == 0) {
1193         return;
1194     }
1195 
1196     if (windowChangesMask & (CWX | CWY)) {
1197         gint newX, newY;
1198         gtk_window_get_position(GTK_WINDOW(gtk_widget), &newX, &newY);
1199 
1200         if (windowChangesMask & CWX) {
1201             newX = windowChanges->x;
1202         }
1203         if (windowChangesMask & CWY) {
1204             newY = windowChanges->y;
1205         }
1206         gtk_window_move(GTK_WINDOW(gtk_widget), newX, newY);
1207     }
1208 
1209     if (windowChangesMask & (CWWidth | CWHeight)) {
1210         gint newWidth, newHeight;
1211         gtk_window_get_size(GTK_WINDOW(gtk_widget), &newWidth, &newHeight);
1212 
1213         if (windowChangesMask & CWWidth) {
1214             newWidth = windowChanges->width;
1215         }
1216         if (windowChangesMask & CWHeight) {
1217             newHeight = windowChanges->height;
1218         }
1219 
1220         if (!resizable.value) {
1221             GdkGeometry geom;
1222             GdkWindowHints hints = (GdkWindowHints)(GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE);
1223             geom.min_width = geom.max_width = newWidth;
1224             geom.min_height = geom.max_height = newHeight;
1225             gtk_window_set_geometry_hints(GTK_WINDOW(gtk_widget), NULL, &geom, hints);
1226         }
1227         gtk_window_resize(GTK_WINDOW(gtk_widget), newWidth, newHeight);
1228     }
1229 }
1230 
1231 void WindowContextTop::applyShapeMask(void* data, uint width, uint height)
1232 {
1233     if (frame_type != TRANSPARENT) {
1234         return;
1235     }
1236 
1237     glass_window_apply_shape_mask(gtk_widget_get_window(gtk_widget), data, width, height);
1238 }
1239 
1240 void WindowContextTop::ensure_window_size() {
1241     gint w, h;
1242 #ifdef GLASS_GTK3
1243     gdk_window_get_geometry(gdk_window, NULL, NULL, &w, &h);
1244 #else
1245     gdk_window_get_geometry(gdk_window, NULL, NULL, &w, &h, NULL);
1246 #endif
1247     if (size_assigned && (geometry.final_width.value != w
1248                        || geometry.final_height.value != h)) {
1249 
1250         gdk_window_resize(gdk_window, geometry.final_width.value,
1251                                       geometry.final_height.value);
1252     }
1253 }
1254 
1255 void WindowContextTop::set_minimized(bool minimize) {
1256     is_iconified = minimize;
1257     if (minimize) {
1258         if (frame_type == TRANSPARENT) {
1259             // https://bugs.launchpad.net/ubuntu/+source/unity/+bug/1245571
1260             glass_window_reset_input_shape_mask(gtk_widget_get_window(gtk_widget));
1261         }
1262 
1263         if ((gdk_windowManagerFunctions & GDK_FUNC_MINIMIZE) == 0) {
1264             // in this case - the window manager will not support the programatic
1265             // request to iconify - so we need to disable this until we are restored.
1266             GdkWMFunction wmf = (GdkWMFunction)(gdk_windowManagerFunctions | GDK_FUNC_MINIMIZE);
1267             gdk_window_set_functions(gdk_window, wmf);
1268         }
1269         gtk_window_iconify(GTK_WINDOW(gtk_widget));
1270     } else {
1271         gtk_window_deiconify(GTK_WINDOW(gtk_widget));
1272         activate_window();
1273     }
1274 }
1275 void WindowContextTop::set_maximized(bool maximize) {
1276     is_maximized = maximize;
1277     if (maximize) {
1278         ensure_window_size();
1279         gtk_window_maximize(GTK_WINDOW(gtk_widget));
1280     } else {
1281         gtk_window_unmaximize(GTK_WINDOW(gtk_widget));
1282     }
1283 }
1284 
1285 void WindowContextTop::enter_fullscreen() {
1286     ensure_window_size();
1287     gtk_window_fullscreen(GTK_WINDOW(gtk_widget));
1288 }
1289 
1290 void WindowContextTop::exit_fullscreen() {
1291     gtk_window_unfullscreen(GTK_WINDOW(gtk_widget));
1292 }
1293 
1294 void WindowContextTop::request_focus() {
1295     gtk_window_present(GTK_WINDOW(gtk_widget));
1296 }
1297 
1298 void WindowContextTop::set_focusable(bool focusable) {
1299     gtk_window_set_accept_focus(GTK_WINDOW(gtk_widget), focusable ? TRUE : FALSE);
1300 }
1301 
1302 void WindowContextTop::set_title(const char* title) {
1303     gtk_window_set_title(GTK_WINDOW(gtk_widget),title);
1304 }
1305 
1306 void WindowContextTop::set_alpha(double alpha) {
1307     gtk_window_set_opacity(GTK_WINDOW(gtk_widget), (gdouble)alpha);
1308 }
1309 
1310 void WindowContextTop::set_enabled(bool enabled) {
1311     if (enabled) {
1312         if (resizable.prev) {
1313             set_window_resizable(true);
1314         }
1315     } else {
1316         if (resizable.value) {
1317             set_window_resizable(false);
1318             resizable.prev = true;
1319         } else if (resizable.request == REQUEST_RESIZABLE) {
1320             resizable.request = REQUEST_NOT_RESIZABLE;
1321             resizable.prev = true;
1322         }
1323     }
1324 }
1325 
1326 void WindowContextTop::set_minimum_size(int w, int h) {
1327     resizable.minw = w;
1328     resizable.minh = h;
1329     update_window_constraints();
1330 }
1331 
1332 void WindowContextTop::set_maximum_size(int w, int h) {
1333     resizable.maxw = w;
1334     resizable.maxh = h;
1335     update_window_constraints();
1336 }
1337 
1338 void WindowContextTop::set_icon(GdkPixbuf* pixbuf) {
1339     gtk_window_set_icon(GTK_WINDOW(gtk_widget), pixbuf);
1340 }
1341 
1342 void WindowContextTop::restack(bool restack) {
1343     gdk_window_restack(gdk_window, NULL, restack ? TRUE : FALSE);
1344 }
1345 
1346 void WindowContextTop::set_modal(bool modal, WindowContext* parent) {
1347     if (modal) {
1348         //gtk_window_set_type_hint(GTK_WINDOW(gtk_widget), GDK_WINDOW_TYPE_HINT_DIALOG);
1349         if (parent) {
1350             gtk_window_set_transient_for(GTK_WINDOW(gtk_widget), parent->get_gtk_window());
1351         }
1352     }
1353     gtk_window_set_modal(GTK_WINDOW(gtk_widget), modal ? TRUE : FALSE);
1354 }
1355 
1356 GtkWindow *WindowContextTop::get_gtk_window() {
1357     return GTK_WINDOW(gtk_widget);
1358 }
1359 
1360 WindowFrameExtents WindowContextTop::get_frame_extents() {
1361     return geometry.extents;
1362 }
1363 
1364 void WindowContextTop::set_gravity(float x, float y) {
1365     int oldX = geometry_get_window_x(&geometry);
1366     int oldY = geometry_get_window_y(&geometry);
1367     geometry.gravity_x = x;
1368     geometry.gravity_y = y;
1369     geometry_set_window_x(&geometry, oldX);
1370     geometry_set_window_y(&geometry, oldY);
1371 }
1372 
1373 void WindowContextTop::update_ontop_tree(bool on_top) {
1374     bool effective_on_top = on_top || this->on_top;
1375     gtk_window_set_keep_above(GTK_WINDOW(gtk_widget), effective_on_top ? TRUE : FALSE);
1376     for (std::set<WindowContextTop*>::iterator it = children.begin(); it != children.end(); ++it) {
1377         (*it)->update_ontop_tree(effective_on_top);
1378     }
1379 }
1380 
1381 bool WindowContextTop::on_top_inherited() {
1382     WindowContext* o = owner;
1383     while (o) {
1384         WindowContextTop* topO = dynamic_cast<WindowContextTop*>(o);
1385         if (!topO) break;
1386         if (topO->on_top) {
1387             return true;
1388         }
1389         o = topO->owner;
1390     }
1391     return false;
1392 }
1393 
1394 bool WindowContextTop::effective_on_top() {
1395     if (owner) {
1396         WindowContextTop* topO = dynamic_cast<WindowContextTop*>(owner);
1397         return (topO && topO->effective_on_top()) || on_top;
1398     }
1399     return on_top;
1400 }
1401 
1402 void WindowContextTop::notify_on_top(bool top) {
1403     // Do not report effective (i.e. native) values to the FX, only if the user sets it manually
1404     if (top != effective_on_top() && jwindow) {
1405         if (on_top_inherited() && !top) {
1406             // Disallow user's "on top" handling on windows that inherited the property
1407             gtk_window_set_keep_above(GTK_WINDOW(gtk_widget), TRUE);
1408         } else {
1409             on_top = top;
1410             update_ontop_tree(top);
1411             mainEnv->CallVoidMethod(jwindow,
1412                     jWindowNotifyLevelChanged,
1413                     top ? com_sun_glass_ui_Window_Level_FLOATING :  com_sun_glass_ui_Window_Level_NORMAL);
1414             CHECK_JNI_EXCEPTION(mainEnv);
1415         }
1416     }
1417 }
1418 
1419 void WindowContextTop::set_level(int level) {
1420     if (level == com_sun_glass_ui_Window_Level_NORMAL) {
1421         on_top = false;
1422     } else if (level == com_sun_glass_ui_Window_Level_FLOATING
1423             || level == com_sun_glass_ui_Window_Level_TOPMOST) {
1424         on_top = true;
1425     }
1426     // We need to emulate always on top behaviour on child windows
1427 
1428     if (!on_top_inherited()) {
1429         update_ontop_tree(on_top);
1430     }
1431 }
1432 
1433 void WindowContextTop::set_owner(WindowContext * owner_ctx) {
1434     owner = owner_ctx;
1435 }
1436 
1437 void WindowContextTop::process_destroy() {
1438     if (owner) {
1439         owner->remove_child(this);
1440     }
1441 
1442     WindowContextBase::process_destroy();
1443 }
1444 
1445 ////////////////////////////// WindowContextPlug ////////////////////////////////
1446 
1447 static gboolean plug_configure(GtkWidget *widget, GdkEvent *event, gpointer user_data) {
1448     (void)widget;
1449 
1450     if (event->type == GDK_CONFIGURE) {
1451         ((WindowContextPlug*)user_data)->process_gtk_configure(&event->configure);
1452     }
1453     return FALSE;
1454 }
1455 
1456 WindowContextPlug::WindowContextPlug(jobject _jwindow, void* _owner) :
1457         WindowContextBase(),
1458         parent()
1459 {
1460     jwindow = mainEnv->NewGlobalRef(_jwindow);
1461 
1462     gtk_widget = gtk_plug_new((Window)PTR_TO_JLONG(_owner));
1463 
1464     g_signal_connect(G_OBJECT(gtk_widget), "configure-event", G_CALLBACK(plug_configure), this);
1465 
1466     gtk_widget_set_size_request(gtk_widget, 0, 0);
1467     gtk_widget_set_events(gtk_widget, GDK_ALL_EVENTS_MASK);
1468     gtk_widget_set_can_focus(GTK_WIDGET(gtk_widget), TRUE);
1469     gtk_widget_set_app_paintable(gtk_widget, TRUE);
1470 
1471     gtk_widget_realize(gtk_widget);
1472     gdk_window = gtk_widget_get_window(gtk_widget);
1473 
1474     g_object_set_data_full(G_OBJECT(gdk_window), GDK_WINDOW_DATA_CONTEXT, this, NULL);
1475     gdk_window_register_dnd(gdk_window);
1476 
1477     gtk_container = gtk_fixed_new();
1478     gtk_container_add (GTK_CONTAINER(gtk_widget), gtk_container);
1479     gtk_widget_realize(gtk_container);
1480 }
1481 
1482 GtkWindow *WindowContextPlug::get_gtk_window() {
1483     return GTK_WINDOW(gtk_widget);
1484 }
1485 
1486 void WindowContextPlug::process_configure(GdkEventConfigure* event) {
1487     (void)event;
1488 
1489     //Note: process_gtk_configure is used, so there's no need to handle GDK events
1490 }
1491 
1492 void WindowContextPlug::process_gtk_configure(GdkEventConfigure* event) {
1493     if (jview) {
1494         mainEnv->CallVoidMethod(jview, jViewNotifyResize,
1495                 event->width,
1496                 event->height);
1497         CHECK_JNI_EXCEPTION(mainEnv)
1498     }
1499 
1500     mainEnv->CallVoidMethod(jwindow, jWindowNotifyResize,
1501             com_sun_glass_events_WindowEvent_RESIZE,
1502             event->width,
1503             event->height);
1504     CHECK_JNI_EXCEPTION(mainEnv)
1505 
1506     if (!embedded_children.empty()) {
1507         WindowContextChild* child = embedded_children.back();
1508         child->process_configure(event);
1509     }
1510 }
1511 
1512 bool WindowContextPlug::set_view(jobject view) {
1513     // probably never called for applet window
1514     if (jview) {
1515         mainEnv->DeleteGlobalRef(jview);
1516     }
1517 
1518     if (view) {
1519         gint width, height;
1520         jview = mainEnv->NewGlobalRef(view);
1521         gtk_window_get_size(GTK_WINDOW(gtk_widget), &width, &height);
1522         mainEnv->CallVoidMethod(view, jViewNotifyResize, width, height);
1523         CHECK_JNI_EXCEPTION_RET(mainEnv, FALSE)
1524     } else {
1525         jview = NULL;
1526     }
1527     return TRUE;
1528 }
1529 
1530 void WindowContextPlug::window_configure(XWindowChanges *windowChanges,
1531         unsigned int windowChangesMask) {
1532     if (windowChangesMask == 0) {
1533         return;
1534     }
1535 
1536     if (windowChangesMask & (CWX | CWY)) {
1537         gint newX, newY;
1538         gtk_window_get_position(GTK_WINDOW(gtk_widget), &newX, &newY);
1539 
1540         if (windowChangesMask & CWX) {
1541             newX = windowChanges->x;
1542         }
1543         if (windowChangesMask & CWY) {
1544             newY = windowChanges->y;
1545         }
1546         gtk_window_move(GTK_WINDOW(gtk_widget), newX, newY);
1547     }
1548 
1549     if (windowChangesMask & (CWWidth | CWHeight)) {
1550         gint newWidth, newHeight;
1551         gtk_window_get_size(GTK_WINDOW(gtk_widget),
1552                 &newWidth, &newHeight);
1553 
1554         if (windowChangesMask & CWWidth) {
1555             newWidth = windowChanges->width;
1556         }
1557         if (windowChangesMask & CWHeight) {
1558             newHeight = windowChanges->height;
1559         };
1560         gtk_widget_set_size_request(gtk_widget, newWidth, newHeight);
1561     }
1562 }
1563 
1564 void WindowContextPlug::set_bounds(int x, int y, bool xSet, bool ySet, int w, int h, int cw, int ch) {
1565     XWindowChanges windowChanges;
1566     unsigned int windowChangesMask = 0;
1567 
1568     if (xSet) {
1569         windowChanges.x = x;
1570         windowChangesMask |= CWX;
1571     }
1572 
1573     if (ySet) {
1574         windowChanges.y = y;
1575         windowChangesMask |= CWY;
1576     }
1577 
1578     if (w > 0) {
1579         windowChanges.width = w;
1580         windowChangesMask |= CWWidth;
1581     } else if (cw > 0) {
1582         windowChanges.width = cw;
1583         windowChangesMask |= CWWidth;
1584     }
1585 
1586     if (h > 0) {
1587         windowChanges.height = h;
1588         windowChangesMask |= CWHeight;
1589     } else if (ch > 0) {
1590         windowChanges.height = ch;
1591         windowChangesMask |= CWHeight;
1592     }
1593 
1594     window_configure(&windowChanges, windowChangesMask);
1595 }
1596 ////////////////////////////// WindowContextChild ////////////////////////////////
1597 
1598 void WindowContextChild::process_mouse_button(GdkEventButton* event) {
1599     WindowContextBase::process_mouse_button(event);
1600    // gtk_window_set_focus (GTK_WINDOW (gtk_widget_get_ancestor(gtk_widget, GTK_TYPE_WINDOW)), NULL);
1601     gtk_widget_grab_focus(gtk_widget);
1602 }
1603 
1604 static gboolean child_focus_callback(GtkWidget *widget, GdkEvent *event, gpointer user_data)
1605 {
1606     (void)widget;
1607 
1608     WindowContext *ctx = (WindowContext *)user_data;
1609     ctx->process_focus(&event->focus_change);
1610     return TRUE;
1611 }
1612 
1613 WindowContextChild::WindowContextChild(jobject _jwindow,
1614                                        void* _owner,
1615                                        GtkWidget *parent_widget,
1616                                        WindowContextPlug *parent_ctx) :
1617         WindowContextBase(),
1618         parent(),
1619         full_screen_window(),
1620         view()
1621 {
1622     (void)_owner;
1623 
1624     jwindow = mainEnv->NewGlobalRef(_jwindow);
1625     gtk_widget = gtk_drawing_area_new();
1626     parent = parent_ctx;
1627 
1628     glong xvisualID = (glong) mainEnv->GetStaticLongField(jApplicationCls, jApplicationVisualID);
1629 
1630     if (xvisualID != 0) {
1631         GdkVisual *visual = gdk_x11_screen_lookup_visual(gdk_screen_get_default(), xvisualID);
1632         glass_gtk_window_configure_from_visual(gtk_widget, visual);
1633     }
1634 
1635     gtk_widget_set_events(gtk_widget, GDK_ALL_EVENTS_MASK);
1636     gtk_widget_set_can_focus(GTK_WIDGET(gtk_widget), TRUE);
1637     gtk_widget_set_app_paintable(gtk_widget, TRUE);
1638     gtk_container_add (GTK_CONTAINER(parent_widget), gtk_widget);
1639     gtk_widget_realize(gtk_widget);
1640     gdk_window = gtk_widget_get_window(gtk_widget);
1641     g_object_set_data_full(G_OBJECT(gdk_window), GDK_WINDOW_DATA_CONTEXT, this, NULL);
1642     gdk_window_register_dnd(gdk_window);
1643     g_signal_connect(gtk_widget, "focus-in-event", G_CALLBACK(child_focus_callback), this);
1644     g_signal_connect(gtk_widget, "focus-out-event", G_CALLBACK(child_focus_callback), this);
1645 }
1646 
1647 void WindowContextChild::set_visible(bool visible) {
1648     std::vector<WindowContextChild*> &embedded_children =
1649             dynamic_cast<WindowContextPlug*>(parent)->embedded_children;
1650 
1651     if (visible) {
1652         embedded_children.push_back(this);
1653     } else {
1654         std::vector<WindowContextChild*>::iterator pos
1655                 = std::find(embedded_children.begin(), embedded_children.end(), this);
1656         if (pos != embedded_children.end()) {
1657             embedded_children.erase((pos));
1658         }
1659     }
1660 
1661     WindowContextBase::set_visible(visible);
1662 }
1663 
1664 GtkWindow *WindowContextChild::get_gtk_window() {
1665     return GTK_WINDOW(gtk_widget_get_ancestor(gtk_widget, GTK_TYPE_WINDOW));
1666 }
1667 
1668 void WindowContextChild::process_configure(GdkEventConfigure* event) {
1669     if (jview) {
1670         mainEnv->CallVoidMethod(jview, jViewNotifyResize,
1671                 event->width,
1672                 event->height);
1673         CHECK_JNI_EXCEPTION(mainEnv)
1674     }
1675 
1676     gtk_widget_set_size_request(gtk_widget, event->width, event->height);
1677 
1678     if (jwindow) {
1679         mainEnv->CallVoidMethod(jwindow, jWindowNotifyResize,
1680                 com_sun_glass_events_WindowEvent_RESIZE,
1681                 event->width,
1682                 event->height);
1683         CHECK_JNI_EXCEPTION(mainEnv)
1684     }
1685 }
1686 
1687 bool WindowContextChild::set_view(jobject view) {
1688     if (jview) {
1689         mainEnv->DeleteGlobalRef(jview);
1690     }
1691 
1692     if (view) {
1693         gint width, height;
1694         jview = mainEnv->NewGlobalRef(view);
1695         GtkAllocation ws;
1696         gtk_widget_get_allocation(gtk_widget, &ws);
1697         width = ws.width;
1698         height = ws.height;
1699         mainEnv->CallVoidMethod(view, jViewNotifyResize, width, height);
1700         CHECK_JNI_EXCEPTION_RET(mainEnv, FALSE)
1701     } else {
1702         jview = NULL;
1703     }
1704     return TRUE;
1705 }
1706 
1707 void WindowContextChild::set_bounds(int x, int y, bool xSet, bool ySet, int w, int h, int cw, int ch) {
1708 
1709     if (x > 0 || y > 0 || xSet || ySet) {
1710         gint newX, newY;
1711         gdk_window_get_origin(gdk_window, &newX, &newY);
1712         if (jwindow) {
1713             mainEnv->CallVoidMethod(jwindow,
1714                     jWindowNotifyMove,
1715                     newX, newY);
1716             CHECK_JNI_EXCEPTION(mainEnv)
1717         }
1718     }
1719 
1720     // As we have no frames, there's no difference between the calls
1721     if ((cw | ch) > 0) {
1722         w = cw; h = ch;
1723     }
1724 
1725     if (w > 0 || h > 0) {
1726         gint newWidth, newHeight;
1727         GtkAllocation ws;
1728         gtk_widget_get_allocation(gtk_widget, &ws);
1729         newWidth = ws.width;
1730         newHeight = ws.height;
1731 
1732         if (w > 0) {
1733             newWidth = w;
1734         }
1735         if (h > 0) {
1736             newHeight = h;
1737         }
1738         gtk_widget_set_size_request(gtk_widget, newWidth, newHeight);
1739         // FIXME: hack to set correct size to view
1740         if (jview) {
1741             mainEnv->CallVoidMethod(jview,
1742                     jViewNotifyResize,
1743                     newWidth, newHeight);
1744             CHECK_JNI_EXCEPTION(mainEnv)
1745         }
1746     }
1747 }
1748 
1749 int WindowContextChild::getEmbeddedX() {
1750     int x;
1751     gdk_window_get_origin(gdk_window, &x, NULL);
1752     return x;
1753 }
1754 
1755 int WindowContextChild::getEmbeddedY() {
1756     int y;
1757     gdk_window_get_origin(gdk_window, NULL, &y);
1758     return y;
1759 
1760 }
1761 
1762 void WindowContextChild::restack(bool toFront) {
1763     std::vector<WindowContextChild*> &embedded_children =
1764                 dynamic_cast<WindowContextPlug*>(parent)->embedded_children;
1765 
1766     std::vector<WindowContextChild*>::iterator pos
1767         = std::find(embedded_children.begin(), embedded_children.end(), this);
1768 
1769     embedded_children.erase(pos);
1770     if (toFront) {
1771         embedded_children.push_back(this);
1772     } else {
1773         embedded_children.insert(embedded_children.begin(), this);
1774     }
1775 
1776     gdk_window_restack(gdk_window, NULL, toFront ? TRUE : FALSE);
1777 }
1778 
1779 void WindowContextChild::enter_fullscreen() {
1780     if (full_screen_window) {
1781         return;
1782     }
1783 
1784     full_screen_window = new WindowContextTop(jwindow, NULL, 0L, UNTITLED,
1785                                                 NORMAL, (GdkWMFunction) 0);
1786     int x, y, w, h;
1787     gdk_window_get_origin(gdk_window, &x, &y);
1788 #ifdef GLASS_GTK3
1789     gdk_window_get_geometry(gdk_window, NULL, NULL, &w, &h);
1790 #else
1791     gdk_window_get_geometry(gdk_window, NULL, NULL, &w, &h, NULL);
1792 #endif
1793     full_screen_window->set_bounds(x, y, true, true, w, h, -1, -1);
1794 
1795     if (WindowContextBase::sm_grab_window == this) {
1796         ungrab_focus();
1797     }
1798 
1799     reparent_children(full_screen_window);
1800 
1801     full_screen_window->set_visible(true);
1802     full_screen_window->enter_fullscreen();
1803 
1804     if (jwindow) {
1805         mainEnv->CallVoidMethod(jwindow, jWindowNotifyDelegatePtr, (jlong)full_screen_window);
1806         CHECK_JNI_EXCEPTION(mainEnv)
1807     }
1808 
1809     if (jview) {
1810         this->view = (GlassView*)mainEnv->GetLongField(jview, jViewPtr);
1811 
1812         this->view->current_window = full_screen_window;
1813         this->view->embedded_window = this;
1814         full_screen_window->set_view(jview);
1815         this->set_view(NULL);
1816     }
1817 }
1818 
1819 void WindowContextChild::exit_fullscreen() {
1820     if (!full_screen_window) {
1821         return;
1822     }
1823 
1824     if (WindowContextBase::sm_grab_window == this) {
1825         ungrab_focus();
1826     }
1827 
1828     full_screen_window->reparent_children(this);
1829 
1830     mainEnv->CallVoidMethod(jwindow, jWindowNotifyDelegatePtr, (jlong)NULL);
1831     CHECK_JNI_EXCEPTION(mainEnv)
1832 
1833     if (this->view) {
1834         this->view->current_window = this;
1835         this->view->embedded_window = NULL;
1836     }
1837     this->set_view(full_screen_window->get_jview());
1838 
1839     full_screen_window->detach_from_java();
1840 
1841     full_screen_window->set_view(NULL);
1842 
1843     full_screen_window->set_visible(false);
1844 
1845     destroy_and_delete_ctx(full_screen_window);
1846     full_screen_window = NULL;
1847     this->view = NULL;
1848 }
1849 
1850 void WindowContextChild::process_destroy() {
1851     if (full_screen_window) {
1852         destroy_and_delete_ctx(full_screen_window);
1853     }
1854 
1855     std::vector<WindowContextChild*> &embedded_children =
1856             dynamic_cast<WindowContextPlug*>(parent)->embedded_children;
1857 
1858     std::vector<WindowContextChild*>::iterator pos
1859                 = std::find(embedded_children.begin(), embedded_children.end(), this);
1860     if (pos != embedded_children.end()) {
1861         embedded_children.erase((pos));
1862     }
1863 
1864     WindowContextBase::process_destroy();
1865 }