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