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