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 <algorithm>
48
49 WindowContext * WindowContextBase::sm_grab_window = NULL;
50 WindowContext * WindowContextBase::sm_mouse_drag_window = NULL;
51
52 GdkAtom atom_net_wm_state = gdk_atom_intern_static_string("_NET_WM_STATE");
53
54 GdkWindow* WindowContextBase::get_gdk_window(){
55 return gdk_window;
56 }
57
58 jobject WindowContextBase::get_jview() {
59 return jview;
60 }
61
62 jobject WindowContextBase::get_jwindow() {
63 return jwindow;
64 }
65
66 bool WindowContextBase::isEnabled() {
67 if (jwindow) {
68 bool result = (JNI_TRUE == mainEnv->CallBooleanMethod(jwindow, jWindowIsEnabled));
69 LOG_EXCEPTION(mainEnv)
70 return result;
71 } else {
72 return false;
73 }
336
337 if (jview) {
338 mainEnv->CallVoidMethod(jview, jViewNotifyMouse,
339 isDrag ? com_sun_glass_events_MouseEvent_DRAG : com_sun_glass_events_MouseEvent_MOVE,
340 button,
341 (jint) event->x, (jint) event->y,
342 (jint) event->x_root, (jint) event->y_root,
343 glass_modifier,
344 JNI_FALSE,
345 JNI_FALSE);
346 CHECK_JNI_EXCEPTION(mainEnv)
347 }
348 }
349
350 void WindowContextBase::process_mouse_scroll(GdkEventScroll* event) {
351 jdouble dx = 0;
352 jdouble dy = 0;
353
354 // converting direction to change in pixels
355 switch (event->direction) {
356 case GDK_SCROLL_UP:
357 dy = 1;
358 break;
359 case GDK_SCROLL_DOWN:
360 dy = -1;
361 break;
362 case GDK_SCROLL_LEFT:
363 dx = 1;
364 break;
365 case GDK_SCROLL_RIGHT:
366 dx = -1;
367 break;
368 }
369
370 if (jview) {
371 mainEnv->CallVoidMethod(jview, jViewNotifyScroll,
372 (jint) event->x, (jint) event->y,
373 (jint) event->x_root, (jint) event->y_root,
374 dx, dy,
375 gdk_modifier_mask_to_glass(event->state),
401 JNI_FALSE);
402 CHECK_JNI_EXCEPTION(mainEnv)
403 }
404 }
405 }
406
407 void WindowContextBase::process_key(GdkEventKey* event) {
408 bool press = event->type == GDK_KEY_PRESS;
409 jint glassKey = get_glass_key(event);
410 jint glassModifier = gdk_modifier_mask_to_glass(event->state);
411 if (press) {
412 glassModifier |= glass_key_to_modifier(glassKey);
413 } else {
414 glassModifier &= ~glass_key_to_modifier(glassKey);
415 }
416 jcharArray jChars = NULL;
417 jchar key = gdk_keyval_to_unicode(event->keyval);
418 if (key >= 'a' && key <= 'z' && (event->state & GDK_CONTROL_MASK)) {
419 key = key - 'a' + 1; // map 'a' to ctrl-a, and so on.
420 } else {
421 key = glass_gtk_fixup_typed_key(key, event->keyval);
422 }
423
424 if (key > 0) {
425 jChars = mainEnv->NewCharArray(1);
426 if (jChars) {
427 mainEnv->SetCharArrayRegion(jChars, 0, 1, &key);
428 CHECK_JNI_EXCEPTION(mainEnv)
429 }
430 } else {
431 jChars = mainEnv->NewCharArray(0);
432 }
433 if (jview) {
434 if (press) {
435 mainEnv->CallVoidMethod(jview, jViewNotifyKey,
436 com_sun_glass_events_KeyEvent_PRESS,
437 glassKey,
438 jChars,
439 glassModifier);
440 CHECK_JNI_EXCEPTION(mainEnv)
441
447 glassModifier);
448 CHECK_JNI_EXCEPTION(mainEnv)
449 }
450 } else {
451 mainEnv->CallVoidMethod(jview, jViewNotifyKey,
452 com_sun_glass_events_KeyEvent_RELEASE,
453 glassKey,
454 jChars,
455 glassModifier);
456 CHECK_JNI_EXCEPTION(mainEnv)
457 }
458 }
459 }
460
461 void WindowContextBase::paint(void* data, jint width, jint height)
462 {
463 if (!is_visible()) {
464 return;
465 }
466
467 cairo_t* context;
468 context = gdk_cairo_create(GDK_DRAWABLE(gdk_window));
469
470 cairo_surface_t* cairo_surface;
471 cairo_surface = cairo_image_surface_create_for_data(
472 (unsigned char*)data,
473 CAIRO_FORMAT_ARGB32,
474 width, height, width * 4);
475
476 applyShapeMask(data, width, height);
477
478 cairo_set_source_surface(context, cairo_surface, 0, 0);
479 cairo_set_operator (context, CAIRO_OPERATOR_SOURCE);
480 cairo_paint(context);
481
482 cairo_destroy(context);
483 cairo_surface_destroy(cairo_surface);
484 }
485
486 void WindowContextBase::add_child(WindowContextTop* child) {
487 children.insert(child);
488 gtk_window_set_transient_for(child->get_gtk_window(), this->get_gtk_window());
489 }
490
491 void WindowContextBase::remove_child(WindowContextTop* child) {
492 children.erase(child);
493 gtk_window_set_transient_for(child->get_gtk_window(), NULL);
494 }
495
496 void WindowContextBase::show_or_hide_children(bool show) {
497 std::set<WindowContextTop*>::iterator it;
498 for (it = children.begin(); it != children.end(); ++it) {
499 (*it)->set_visible(show);
500 (*it)->show_or_hide_children(show);
501 }
502 }
503
504 void WindowContextBase::reparent_children(WindowContext* parent) {
505 std::set<WindowContextTop*>::iterator it;
506 for (it = children.begin(); it != children.end(); ++it) {
507 (*it)->set_owner(parent);
508 parent->add_child(*it);
509 }
510 children.clear();
511 }
512
513 void WindowContextBase::set_visible(bool visible) {
514 if (visible) {
515 gtk_widget_show_all(gtk_widget);
516 } else {
517 gtk_widget_hide(gtk_widget);
518 if (jview && is_mouse_entered) {
519 is_mouse_entered = false;
582
583 void WindowContextBase::ungrab_focus() {
584 if (!WindowContextBase::sm_mouse_drag_window) {
585 glass_gdk_mouse_devices_ungrab();
586 }
587 WindowContextBase::sm_grab_window = NULL;
588
589 if (jwindow) {
590 mainEnv->CallVoidMethod(jwindow, jWindowNotifyFocusUngrab);
591 CHECK_JNI_EXCEPTION(mainEnv)
592 }
593 }
594
595 void WindowContextBase::set_cursor(GdkCursor* cursor) {
596 if (!is_in_drag()) {
597 if (WindowContextBase::sm_mouse_drag_window) {
598 glass_gdk_mouse_devices_grab_with_cursor(
599 WindowContextBase::sm_mouse_drag_window->get_gdk_window(), cursor, FALSE);
600 } else if (WindowContextBase::sm_grab_window) {
601 glass_gdk_mouse_devices_grab_with_cursor(
602 WindowContextBase::sm_grab_window->get_gdk_window(), cursor);
603 }
604 }
605 gdk_window_set_cursor(gdk_window, cursor);
606 }
607
608 void WindowContextBase::set_background(float r, float g, float b) {
609 GdkColor color;
610 color.red = (guint16) (r * 65535);
611 color.green = (guint16) (g * 65535);
612 color.blue = (guint16) (b * 65535);
613 gtk_widget_modify_bg(gtk_widget, GTK_STATE_NORMAL, &color);
614 }
615
616 WindowContextBase::~WindowContextBase() {
617 if (xim.ic) {
618 XDestroyIC(xim.ic);
619 xim.ic = NULL;
620 }
621 if (xim.im) {
622 XCloseIM(xim.im);
623 xim.im = NULL;
624 }
625
626 gtk_widget_destroy(gtk_widget);
627 }
628
629 ////////////////////////////// WindowContextTop /////////////////////////////////
630
631
632 WindowContextTop::WindowContextTop(jobject _jwindow, WindowContext* _owner, long _screen,
633 WindowFrameType _frame_type, WindowType type, GdkWMFunction wmf) :
634 WindowContextBase(),
635 screen(_screen),
636 frame_type(_frame_type),
637 owner(_owner),
638 geometry(),
639 stale_config_notifications(),
640 resizable(),
641 frame_extents_initialized(),
642 map_received(false),
643 location_assigned(false),
644 size_assigned(false),
645 on_top(false)
646 {
647 jwindow = mainEnv->NewGlobalRef(_jwindow);
648
649 gtk_widget = gtk_window_new(type == POPUP ? GTK_WINDOW_POPUP : GTK_WINDOW_TOPLEVEL);
650
651 if (gchar* app_name = get_application_name()) {
652 gtk_window_set_wmclass(GTK_WINDOW(gtk_widget), app_name, app_name);
653 g_free(app_name);
654 }
655
656 if (owner) {
657 owner->add_child(this);
658 if (on_top_inherited()) {
659 gtk_window_set_keep_above(GTK_WINDOW(gtk_widget), TRUE);
702 // Applied to a temporary full screen window to prevent sending events to Java
703 void WindowContextTop::detach_from_java() {
704 if (jview) {
705 mainEnv->DeleteGlobalRef(jview);
706 jview = NULL;
707 }
708 if (jwindow) {
709 mainEnv->DeleteGlobalRef(jwindow);
710 jwindow = NULL;
711 }
712 }
713
714 static GdkAtom
715 get_net_frame_extents_atom() {
716 static const char * extents_str = "_NET_FRAME_EXTENTS";
717 return gdk_atom_intern(extents_str, TRUE);
718 }
719
720 void
721 WindowContextTop::request_frame_extents() {
722 Display *display = GDK_WINDOW_XDISPLAY(gdk_window);
723 Atom rfeAtom = XInternAtom(display, "_NET_REQUEST_FRAME_EXTENTS", True);
724 if (rfeAtom != None) {
725 XClientMessageEvent clientMessage;
726 memset(&clientMessage, 0, sizeof(clientMessage));
727
728 clientMessage.type = ClientMessage;
729 clientMessage.window = GDK_WINDOW_XID(gdk_window);
730 clientMessage.message_type = rfeAtom;
731 clientMessage.format = 32;
732
733 XSendEvent(display, XDefaultRootWindow(display), False,
734 SubstructureRedirectMask | SubstructureNotifyMask,
735 (XEvent *) &clientMessage);
736 XFlush(display);
737 }
738 }
739
740 void WindowContextTop::activate_window() {
741 Display *display = GDK_WINDOW_XDISPLAY(gdk_window);
742 Atom navAtom = XInternAtom(display, "_NET_ACTIVE_WINDOW", True);
743 if (navAtom != None) {
744 XClientMessageEvent clientMessage;
745 memset(&clientMessage, 0, sizeof(clientMessage));
746
747 clientMessage.type = ClientMessage;
748 clientMessage.window = GDK_WINDOW_XID(gdk_window);
749 clientMessage.message_type = navAtom;
750 clientMessage.format = 32;
751 clientMessage.data.l[0] = 1;
752 clientMessage.data.l[1] = gdk_x11_get_server_time(gdk_window);
753 clientMessage.data.l[2] = 0;
754
755 XSendEvent(display, XDefaultRootWindow(display), False,
756 SubstructureRedirectMask | SubstructureNotifyMask,
757 (XEvent *) &clientMessage);
758 XFlush(display);
759 }
760 }
761
780 gdk_atom_intern("CARDINAL", FALSE),
781 0,
782 sizeof (unsigned long) * 4,
783 FALSE,
784 NULL,
785 NULL,
786 NULL,
787 (guchar**) & extents)) {
788 *left = extents [0];
789 *right = extents [1];
790 *top = extents [2];
791 *bottom = extents [3];
792
793 g_free(extents);
794 return true;
795 }
796
797 return false;
798 }
799
800
801 static int geometry_get_window_width(const WindowGeometry *windowGeometry) {
802 return (windowGeometry->final_width.type != BOUNDSTYPE_WINDOW)
803 ? windowGeometry->final_width.value
804 + windowGeometry->extents.left
805 + windowGeometry->extents.right
806 : windowGeometry->final_width.value;
807 }
808
809 static int geometry_get_window_height(const WindowGeometry *windowGeometry) {
810 return (windowGeometry->final_height.type != BOUNDSTYPE_WINDOW)
811 ? windowGeometry->final_height.value
812 + windowGeometry->extents.top
813 + windowGeometry->extents.bottom
814 : windowGeometry->final_height.value;
815 }
816
817 static int geometry_get_content_width(WindowGeometry *windowGeometry) {
818 return (windowGeometry->final_width.type != BOUNDSTYPE_CONTENT)
819 ? windowGeometry->final_width.value
820 - windowGeometry->extents.left
852 if (windowGeometry->gravity_x != 0) {
853 newValue += geometry_get_window_width(windowGeometry)
854 * windowGeometry->gravity_x;
855 }
856 windowGeometry->refx = newValue;
857 }
858
859 static void geometry_set_window_y(WindowGeometry *windowGeometry, int value) {
860 float newValue = value;
861 if (windowGeometry->gravity_y != 0) {
862 newValue += geometry_get_window_height(windowGeometry)
863 * windowGeometry->gravity_y;
864 }
865 windowGeometry->refy = newValue;
866 }
867
868 void WindowContextTop::process_net_wm_property() {
869 // Workaround for https://bugs.launchpad.net/unity/+bug/998073
870
871 static GdkAtom atom_atom = gdk_atom_intern_static_string("ATOM");
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 if (event->atom == atom_net_wm_state && event->window == gdk_window) {
908 process_net_wm_property();
909 } else if (event->atom == get_net_frame_extents_atom() &&
910 event->window == gdk_window) {
911 int top, left, bottom, right;
912 if (get_frame_extents_property(&top, &left, &bottom, &right)) {
913 int oldX = geometry_get_window_x(&geometry);
914 int oldY = geometry_get_window_y(&geometry);
915 int oldWidth = geometry_get_content_width(&geometry);
916 int oldHeight = geometry_get_content_height(&geometry);
917
918 bool updateWindowConstraints = geometry.extents.top != top
919 || geometry.extents.left != left
920 || geometry.extents.bottom != bottom
921 || geometry.extents.right != right;
922
923 geometry.extents.top = top;
924 geometry.extents.left = left;
925 geometry.extents.bottom = bottom;
926 geometry.extents.right = right;
927
928 if (updateWindowConstraints) {
929 update_window_constraints();
930 }
931
932 XWindowChanges windowChanges;
933 unsigned int windowChangesMask = 0;
934
935 int newX = geometry_get_window_x(&geometry);
936 int newY = geometry_get_window_y(&geometry);
937 int newWidth = geometry_get_content_width(&geometry);
938 int newHeight = geometry_get_content_height(&geometry);
939
940 if (oldX != newX) {
941 windowChanges.x = newX;
942 windowChangesMask |= CWX;
943 }
944
945 if (oldY != newY) {
946 windowChanges.y = newY;
947 windowChangesMask |= CWY;
948 }
949
950 if (oldWidth != newWidth) {
951 windowChanges.width = newWidth;
952 windowChangesMask |= CWWidth;
953 }
954
955 if (oldHeight != newHeight) {
956 windowChanges.height = newHeight;
957 windowChangesMask |= CWHeight;
958 }
959
960 window_configure(&windowChanges, windowChangesMask);
961
962 if (jview) {
963 mainEnv->CallVoidMethod(jview, jViewNotifyView, com_sun_glass_events_ViewEvent_MOVE);
964 CHECK_JNI_EXCEPTION(mainEnv)
965 }
966 }
967 }
968 }
969
970 void WindowContextTop::process_configure(GdkEventConfigure* event) {
971
972 geometry.current_width = event->width + geometry.extents.left
973 + geometry.extents.right;
974 geometry.current_height = event->height + geometry.extents.top
975 + geometry.extents.bottom;
976 gint x, y;
977 if (gtk_window_get_decorated(GTK_WINDOW(gtk_widget))) {
978 gtk_window_get_position(GTK_WINDOW(gtk_widget), &x, &y);
979 } else {
980 x = event->x;
981 y = event->y;
982 }
983
984 if (stale_config_notifications == 0) {
985 if ((geometry_get_content_width(&geometry) != event->width)
986 || (geometry_get_content_height(&geometry) != event->height)) {
987 geometry.final_width.value = event->width;
988 geometry.final_width.type = BOUNDSTYPE_CONTENT;
989 geometry.final_height.value = event->height;
990 geometry.final_height.type = BOUNDSTYPE_CONTENT;
991 }
992 geometry_set_window_x(&geometry, x);
993 geometry_set_window_y(&geometry, y);
994 } else {
995 --stale_config_notifications;
996 }
997 if (jview) {
998 mainEnv->CallVoidMethod(jview, jViewNotifyResize,
999 event->width,
1000 event->height);
1001 CHECK_JNI_EXCEPTION(mainEnv)
1002 }
1003 if (jwindow) {
1004 mainEnv->CallVoidMethod(jwindow, jWindowNotifyResize,
1005 (is_maximized)
1006 ? com_sun_glass_events_WindowEvent_MAXIMIZE
1007 : com_sun_glass_events_WindowEvent_RESIZE,
1008 geometry.current_width,
1009 geometry.current_height);
1010 CHECK_JNI_EXCEPTION(mainEnv)
1011
1012 mainEnv->CallVoidMethod(jwindow, jWindowNotifyMove, x, y);
1013 CHECK_JNI_EXCEPTION(mainEnv)
1014 }
1015
1016 glong to_screen = getScreenPtrForLocation(x, y);
1017 if (to_screen != -1) {
1018 if (to_screen != screen) {
1019 if (jwindow) {
1020 //notify screen changed
1021 jobject jScreen = createJavaScreen(mainEnv, to_screen);
1022 mainEnv->CallVoidMethod(jwindow, jWindowNotifyMoveToAnotherScreen, jScreen);
1023 CHECK_JNI_EXCEPTION(mainEnv)
1024 }
1025 screen = to_screen;
1026 }
1027 }
1028
1029 if (resizable.request != REQUEST_NONE) {
1030 set_window_resizable(resizable.request == REQUEST_RESIZABLE, true);
1031 resizable.request = REQUEST_NONE;
1032 }
1033 }
1034
1035 void WindowContextTop::update_window_constraints() {
1036 if (resizable.value) {
1037 GdkGeometry geom = {
1038 (resizable.minw == -1) ? 1
1039 : resizable.minw - geometry.extents.left - geometry.extents.right,
1040 (resizable.minh == -1) ? 1
1041 : resizable.minh - geometry.extents.top - geometry.extents.bottom,
1042 (resizable.maxw == -1) ? 100000
1043 : resizable.maxw - geometry.extents.left - geometry.extents.right,
1044 (resizable.maxh == -1) ? 100000
1045 : resizable.maxh - geometry.extents.top - geometry.extents.bottom,
1046 0, 0, 0, 0, 0.0, 0.0, GDK_GRAVITY_NORTH_WEST
1047 };
1048 gtk_window_set_geometry_hints(GTK_WINDOW(gtk_widget), NULL, &geom,
1049 static_cast<GdkWindowHints> (GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE));
1050 }
1051 }
1052
1053 void WindowContextTop::set_window_resizable(bool res, bool grip) {
1054 if(!res) {
1055 int w = geometry_get_content_width(&geometry);
1056 int h = geometry_get_content_height(&geometry);
1057 if (w == -1 && h == -1) {
1058 gtk_window_get_size(GTK_WINDOW(gtk_widget), &w, &h);
1059 }
1060 GdkGeometry geom = {w, h, w, h, 0, 0, 0, 0, 0.0, 0.0, GDK_GRAVITY_NORTH_WEST};
1061 gtk_window_set_geometry_hints(GTK_WINDOW(gtk_widget), NULL, &geom,
1062 static_cast<GdkWindowHints>(GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE));
1063 GLASS_GTK_WINDOW_SET_HAS_RESIZE_GRIP(gdk_window, FALSE);
1064 resizable.prev = resizable.value;
1065 resizable.value = false;
1066 } else {
1067 resizable.prev = resizable.value;
1068 resizable.value = true;
1069 update_window_constraints();
1070 if (grip) {
1071 GLASS_GTK_WINDOW_SET_HAS_RESIZE_GRIP(gdk_window, TRUE);
1072 }
1073 }
1074 }
1075
1076 void WindowContextTop::set_resizable(bool res) {
1077 gint w, h;
1078 gtk_window_get_size(GTK_WINDOW(gtk_widget), &w, &h);
1079 if (map_received || w > 1 || h > 1) {
1080 set_window_resizable(res, true);
1081 } else {
1082 //Since window is not ready yet set only request for change of resizable.
1083 resizable.request = res ? REQUEST_RESIZABLE : REQUEST_NOT_RESIZABLE;
1084 }
1085 }
1086
1087 void WindowContextTop::set_visible(bool visible)
1088 {
1089 if (visible) {
1090 if (!size_assigned) {
1091 set_bounds(0, 0, false, false, 320, 200, -1, -1);
1092 }
1093 if (!location_assigned) {
1094 set_bounds(0, 0, true, true, -1, -1, -1, -1);
1095 }
1096 }
1097 WindowContextBase::set_visible(visible);
1098 }
1099
1100 void WindowContextTop::set_bounds(int x, int y, bool xSet, bool ySet, int w, int h, int cw, int ch) {
1153 windowChangesMask |= CWY;
1154 }
1155
1156 if (xSet || ySet) location_assigned = true;
1157 if (w > 0 || h > 0 || cw > 0 || ch > 0) size_assigned = true;
1158
1159 window_configure(&windowChanges, windowChangesMask);
1160
1161 }
1162
1163 void WindowContextTop::process_map() {
1164 map_received = true;
1165 }
1166
1167 void WindowContextTop::window_configure(XWindowChanges *windowChanges,
1168 unsigned int windowChangesMask) {
1169 if (windowChangesMask == 0) {
1170 return;
1171 }
1172
1173 if (!gtk_widget_get_visible(gtk_widget)) {
1174 // not visible yet, synchronize with gtk only
1175 if (windowChangesMask & (CWX | CWY)) {
1176 gint newX, newY;
1177 gtk_window_get_position(GTK_WINDOW(gtk_widget), &newX, &newY);
1178
1179 if (windowChangesMask & CWX) {
1180 newX = windowChanges->x;
1181 }
1182 if (windowChangesMask & CWY) {
1183 newY = windowChanges->y;
1184 }
1185
1186 gtk_window_move(GTK_WINDOW(gtk_widget), newX, newY);
1187 }
1188
1189 if (windowChangesMask & (CWWidth | CWHeight)) {
1190 gint newWidth, newHeight;
1191 gtk_window_get_size(GTK_WINDOW(gtk_widget),
1192 &newWidth, &newHeight);
1193
1194 if (windowChangesMask & CWWidth) {
1195 newWidth = windowChanges->width;
1196 }
1197 if (windowChangesMask & CWHeight) {
1198 newHeight = windowChanges->height;
1199 }
1200
1201 gtk_window_resize(GTK_WINDOW(gtk_widget), newWidth, newHeight);
1202 }
1203 stale_config_notifications = 1;
1204 return;
1205 }
1206
1207 ++stale_config_notifications;
1208
1209 if (!resizable.value && (windowChangesMask & (CWWidth | CWHeight))) {
1210 XSizeHints *sizeHints = XAllocSizeHints();
1211 if (sizeHints != NULL) {
1212 int fixedWidth = (windowChangesMask & CWWidth)
1213 ? windowChanges->width
1214 : geometry_get_content_width(&geometry);
1215 int fixedHeight = (windowChangesMask & CWHeight)
1216 ? windowChanges->height
1217 : geometry_get_content_height(&geometry);
1218
1219 sizeHints->flags = PMinSize | PMaxSize;
1220
1221 sizeHints->min_width = 1;
1222 sizeHints->min_height = 1;
1223 sizeHints->max_width = INT_MAX;
1224 sizeHints->max_height = INT_MAX;
1225 XSetWMNormalHints(GDK_WINDOW_XDISPLAY(gdk_window),
1226 GDK_WINDOW_XID(gdk_window),
1227 sizeHints);
1228
1229 XConfigureWindow(GDK_WINDOW_XDISPLAY(gdk_window),
1230 GDK_WINDOW_XID(gdk_window),
1231 windowChangesMask,
1232 windowChanges);
1233
1234 sizeHints->min_width = fixedWidth;
1235 sizeHints->min_height = fixedHeight;
1236 sizeHints->max_width = fixedWidth;
1237 sizeHints->max_height = fixedHeight;
1238 XSetWMNormalHints(GDK_WINDOW_XDISPLAY(gdk_window),
1239 GDK_WINDOW_XID(gdk_window),
1240 sizeHints);
1241
1242 XFree(sizeHints);
1243 return;
1244 }
1245 }
1246
1247 XConfigureWindow(GDK_WINDOW_XDISPLAY(gdk_window),
1248 GDK_WINDOW_XID(gdk_window),
1249 windowChangesMask,
1250 windowChanges);
1251 }
1252
1253 void WindowContextTop::applyShapeMask(void* data, uint width, uint height)
1254 {
1255 if (frame_type != TRANSPARENT) {
1256 return;
1257 }
1258
1259 GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data((guchar *) data,
1260 GDK_COLORSPACE_RGB, TRUE, 8, width, height, width * 4, NULL, NULL);
1261
1262 if (GDK_IS_PIXBUF(pixbuf)) {
1263 GdkBitmap* mask = NULL;
1264 gdk_pixbuf_render_pixmap_and_mask(pixbuf, NULL, &mask, 128);
1265
1266 gdk_window_input_shape_combine_mask(gdk_window, mask, 0, 0);
1267
1268 g_object_unref(pixbuf);
1269 if (mask) {
1270 g_object_unref(mask);
1271 }
1272 }
1273 }
1274
1275 void WindowContextTop::set_minimized(bool minimize) {
1276 is_iconified = minimize;
1277 if (minimize) {
1278 if (frame_type == TRANSPARENT) {
1279 // https://bugs.launchpad.net/ubuntu/+source/unity/+bug/1245571
1280 gdk_window_input_shape_combine_mask(gdk_window, NULL, 0, 0);
1281 }
1282
1283 if ((gdk_windowManagerFunctions & GDK_FUNC_MINIMIZE) == 0) {
1284 // in this case - the window manager will not support the programatic
1285 // request to iconify - so we need to disable this until we are restored.
1286 GdkWMFunction wmf = (GdkWMFunction)(gdk_windowManagerFunctions | GDK_FUNC_MINIMIZE);
1287 gdk_window_set_functions(gdk_window, wmf);
1288 }
1289 gtk_window_iconify(GTK_WINDOW(gtk_widget));
1290 } else {
1291 gtk_window_deiconify(GTK_WINDOW(gtk_widget));
1292 activate_window();
1293 }
1294 }
1295 void WindowContextTop::set_maximized(bool maximize) {
1296 is_maximized = maximize;
1297 if (maximize) {
1298 gtk_window_maximize(GTK_WINDOW(gtk_widget));
1299 } else {
1300 gtk_window_unmaximize(GTK_WINDOW(gtk_widget));
1301 }
1302 }
1303
1304 void WindowContextTop::enter_fullscreen() {
1305 gtk_window_fullscreen(GTK_WINDOW(gtk_widget));
1306 }
1307
1308 void WindowContextTop::exit_fullscreen() {
1309 gtk_window_unfullscreen(GTK_WINDOW(gtk_widget));
1310 }
1311
1312 void WindowContextTop::request_focus() {
1313 gtk_window_present(GTK_WINDOW(gtk_widget));
1314 }
1315
1316 void WindowContextTop::set_focusable(bool focusable) {
1317 gtk_window_set_accept_focus(GTK_WINDOW(gtk_widget), focusable ? TRUE : FALSE);
1318 }
1319
1320 void WindowContextTop::set_title(const char* title) {
1321 gtk_window_set_title(GTK_WINDOW(gtk_widget),title);
1322 }
1323
1324 void WindowContextTop::set_alpha(double alpha) {
1325 gtk_window_set_opacity(GTK_WINDOW(gtk_widget), (gdouble)alpha);
1326 }
1327
1328 void WindowContextTop::set_enabled(bool enabled) {
1329 if (enabled) {
1330 //set back proper resizable value.
1331 set_window_resizable(resizable.prev, true);
1332 } else {
1333 //disabled window can't be resizable.
1334 set_window_resizable(false, false);
1335 }
1336 }
1337
1338 void WindowContextTop::set_minimum_size(int w, int h) {
1339 resizable.minw = w;
1340 resizable.minh = h;
1341 update_window_constraints();
1342 }
1343
1344 void WindowContextTop::set_maximum_size(int w, int h) {
1345 resizable.maxw = w;
1346 resizable.maxh = h;
1347 update_window_constraints();
1348 }
1349
1350 void WindowContextTop::set_icon(GdkPixbuf* pixbuf) {
1351 gtk_window_set_icon(GTK_WINDOW(gtk_widget), pixbuf);
1352 }
1353
1354 void WindowContextTop::restack(bool restack) {
1454 WindowContextBase::process_destroy();
1455 }
1456
1457 ////////////////////////////// WindowContextPlug ////////////////////////////////
1458
1459 static gboolean plug_configure(GtkWidget *widget, GdkEvent *event, gpointer user_data) {
1460 (void)widget;
1461
1462 if (event->type == GDK_CONFIGURE) {
1463 ((WindowContextPlug*)user_data)->process_gtk_configure(&event->configure);
1464 }
1465 return FALSE;
1466 }
1467
1468 WindowContextPlug::WindowContextPlug(jobject _jwindow, void* _owner) :
1469 WindowContextBase(),
1470 parent()
1471 {
1472 jwindow = mainEnv->NewGlobalRef(_jwindow);
1473
1474 gtk_widget = gtk_plug_new((GdkNativeWindow)PTR_TO_JLONG(_owner));
1475
1476 g_signal_connect(G_OBJECT(gtk_widget), "configure-event", G_CALLBACK(plug_configure), this);
1477
1478 gtk_widget_set_size_request(gtk_widget, 0, 0);
1479 gtk_widget_set_events(gtk_widget, GDK_ALL_EVENTS_MASK);
1480 gtk_widget_set_can_focus(GTK_WIDGET(gtk_widget), TRUE);
1481 gtk_widget_set_app_paintable(gtk_widget, TRUE);
1482
1483 gtk_widget_realize(gtk_widget);
1484 gdk_window = gtk_widget_get_window(gtk_widget);
1485
1486 g_object_set_data_full(G_OBJECT(gdk_window), GDK_WINDOW_DATA_CONTEXT, this, NULL);
1487 gdk_window_register_dnd(gdk_window);
1488
1489 gtk_container = gtk_fixed_new();
1490 gtk_container_add (GTK_CONTAINER(gtk_widget), gtk_container);
1491 gtk_widget_realize(gtk_container);
1492 }
1493
1494 GtkWindow *WindowContextPlug::get_gtk_window() {
1687
1688 gtk_widget_set_size_request(gtk_widget, event->width, event->height);
1689
1690 if (jwindow) {
1691 mainEnv->CallVoidMethod(jwindow, jWindowNotifyResize,
1692 com_sun_glass_events_WindowEvent_RESIZE,
1693 event->width,
1694 event->height);
1695 CHECK_JNI_EXCEPTION(mainEnv)
1696 }
1697 }
1698
1699 bool WindowContextChild::set_view(jobject view) {
1700 if (jview) {
1701 mainEnv->DeleteGlobalRef(jview);
1702 }
1703
1704 if (view) {
1705 gint width, height;
1706 jview = mainEnv->NewGlobalRef(view);
1707 width = gtk_widget->allocation.width;
1708 height = gtk_widget->allocation.height;
1709 mainEnv->CallVoidMethod(view, jViewNotifyResize, width, height);
1710 CHECK_JNI_EXCEPTION_RET(mainEnv, FALSE)
1711 } else {
1712 jview = NULL;
1713 }
1714 return TRUE;
1715 }
1716
1717 void WindowContextChild::set_bounds(int x, int y, bool xSet, bool ySet, int w, int h, int cw, int ch) {
1718
1719 if (x > 0 || y > 0 || xSet || ySet) {
1720 gint newX, newY;
1721 gdk_window_get_origin(gdk_window, &newX, &newY);
1722 if (jwindow) {
1723 mainEnv->CallVoidMethod(jwindow,
1724 jWindowNotifyMove,
1725 newX, newY);
1726 CHECK_JNI_EXCEPTION(mainEnv)
1727 }
1728 }
1729
1730 // As we have no frames, there's no difference between the calls
1731 if ((cw | ch) > 0) {
1732 w = cw; h = ch;
1733 }
1734
1735 if (w > 0 || h > 0) {
1736 gint newWidth, newHeight;
1737 newWidth = gtk_widget->allocation.width;
1738 newHeight = gtk_widget->allocation.height;
1739
1740 if (w > 0) {
1741 newWidth = w;
1742 }
1743 if (h > 0) {
1744 newHeight = h;
1745 }
1746 gtk_widget_set_size_request(gtk_widget, newWidth, newHeight);
1747 // FIXME: hack to set correct size to view
1748 if (jview) {
1749 mainEnv->CallVoidMethod(jview,
1750 jViewNotifyResize,
1751 newWidth, newHeight);
1752 CHECK_JNI_EXCEPTION(mainEnv)
1753 }
1754 }
1755 }
1756
1757 int WindowContextChild::getEmbeddedX() {
1758 int x;
1776
1777 embedded_children.erase(pos);
1778 if (toFront) {
1779 embedded_children.push_back(this);
1780 } else {
1781 embedded_children.insert(embedded_children.begin(), this);
1782 }
1783
1784 gdk_window_restack(gdk_window, NULL, toFront ? TRUE : FALSE);
1785 }
1786
1787 void WindowContextChild::enter_fullscreen() {
1788 if (full_screen_window) {
1789 return;
1790 }
1791
1792 full_screen_window = new WindowContextTop(jwindow, NULL, 0L, UNTITLED,
1793 NORMAL, (GdkWMFunction) 0);
1794 int x, y, w, h;
1795 gdk_window_get_origin(gdk_window, &x, &y);
1796 gdk_window_get_geometry(gdk_window, NULL, NULL, &w, &h, NULL);
1797 full_screen_window->set_bounds(x, y, true, true, w, h, -1, -1);
1798
1799 if (WindowContextBase::sm_grab_window == this) {
1800 ungrab_focus();
1801 }
1802
1803 reparent_children(full_screen_window);
1804
1805 full_screen_window->set_visible(true);
1806 full_screen_window->enter_fullscreen();
1807
1808 if (jwindow) {
1809 mainEnv->CallVoidMethod(jwindow, jWindowNotifyDelegatePtr, (jlong)full_screen_window);
1810 CHECK_JNI_EXCEPTION(mainEnv)
1811 }
1812
1813 if (jview) {
1814 this->view = (GlassView*)mainEnv->GetLongField(jview, jViewPtr);
1815
1816 this->view->current_window = full_screen_window;
|
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
44 #ifdef GLASS_GTK3
45 #include <gtk/gtkx.h>
46 #endif
47
48 #include <string.h>
49
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 }
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),
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
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 #ifdef GLASS_GTK3
488 cairo_region_t *region = gdk_window_get_clip_region(gdk_window);
489 gdk_window_begin_paint_region(gdk_window, region);
490 #endif
491
492 cairo_t* context;
493 context = gdk_cairo_create(gdk_window);
494
495 cairo_surface_t* cairo_surface;
496 cairo_surface = cairo_image_surface_create_for_data(
497 (unsigned char*)data,
498 CAIRO_FORMAT_ARGB32,
499 width, height, width * 4);
500
501 applyShapeMask(data, width, height);
502
503 cairo_set_source_surface(context, cairo_surface, 0, 0);
504
505 cairo_set_operator (context, CAIRO_OPERATOR_SOURCE);
506 cairo_paint(context);
507 #ifdef GLASS_GTK3
508 gdk_window_end_paint(gdk_window);
509 cairo_region_destroy(region);
510 #endif
511
512 cairo_destroy(context);
513 cairo_surface_destroy(cairo_surface);
514 }
515
516 void WindowContextBase::add_child(WindowContextTop* child) {
517 children.insert(child);
518 gtk_window_set_transient_for(child->get_gtk_window(), this->get_gtk_window());
519 }
520
521 void WindowContextBase::remove_child(WindowContextTop* child) {
522 children.erase(child);
523 gtk_window_set_transient_for(child->get_gtk_window(), NULL);
524 }
525
526 void WindowContextBase::show_or_hide_children(bool show) {
527 std::set<WindowContextTop*>::iterator it;
528 for (it = children.begin(); it != children.end(); ++it) {
529 (*it)->set_minimized(!show);
530 (*it)->show_or_hide_children(show);
531 }
532 }
533
534 void WindowContextBase::reparent_children(WindowContext* parent) {
535 std::set<WindowContextTop*>::iterator it;
536 for (it = children.begin(); it != children.end(); ++it) {
537 (*it)->set_owner(parent);
538 parent->add_child(*it);
539 }
540 children.clear();
541 }
542
543 void WindowContextBase::set_visible(bool visible) {
544 if (visible) {
545 gtk_widget_show_all(gtk_widget);
546 } else {
547 gtk_widget_hide(gtk_widget);
548 if (jview && is_mouse_entered) {
549 is_mouse_entered = false;
612
613 void WindowContextBase::ungrab_focus() {
614 if (!WindowContextBase::sm_mouse_drag_window) {
615 glass_gdk_mouse_devices_ungrab();
616 }
617 WindowContextBase::sm_grab_window = NULL;
618
619 if (jwindow) {
620 mainEnv->CallVoidMethod(jwindow, jWindowNotifyFocusUngrab);
621 CHECK_JNI_EXCEPTION(mainEnv)
622 }
623 }
624
625 void WindowContextBase::set_cursor(GdkCursor* cursor) {
626 if (!is_in_drag()) {
627 if (WindowContextBase::sm_mouse_drag_window) {
628 glass_gdk_mouse_devices_grab_with_cursor(
629 WindowContextBase::sm_mouse_drag_window->get_gdk_window(), cursor, FALSE);
630 } else if (WindowContextBase::sm_grab_window) {
631 glass_gdk_mouse_devices_grab_with_cursor(
632 WindowContextBase::sm_grab_window->get_gdk_window(), cursor, TRUE);
633 }
634 }
635 gdk_window_set_cursor(gdk_window, cursor);
636 }
637
638 void WindowContextBase::set_background(float r, float g, float b) {
639 #ifdef GLASS_GTK3
640 GdkRGBA rgba = {0, 0, 0, 1.};
641 rgba.red = r;
642 rgba.green = g;
643 rgba.blue = b;
644 gdk_window_set_background_rgba(gdk_window, &rgba);
645 #else
646 GdkColor color;
647 color.red = (guint16) (r * 65535);
648 color.green = (guint16) (g * 65535);
649 color.blue = (guint16) (b * 65535);
650 gtk_widget_modify_bg(gtk_widget, GTK_STATE_NORMAL, &color);
651 #endif
652 }
653
654 WindowContextBase::~WindowContextBase() {
655 if (xim.ic) {
656 XDestroyIC(xim.ic);
657 xim.ic = NULL;
658 }
659 if (xim.im) {
660 XCloseIM(xim.im);
661 xim.im = NULL;
662 }
663
664 gtk_widget_destroy(gtk_widget);
665 }
666
667 ////////////////////////////// WindowContextTop /////////////////////////////////
668
669
670 WindowContextTop::WindowContextTop(jobject _jwindow, WindowContext* _owner, long _screen,
671 WindowFrameType _frame_type, WindowType type, GdkWMFunction wmf) :
672 WindowContextBase(),
673 screen(_screen),
674 frame_type(_frame_type),
675 owner(_owner),
676 geometry(),
677 resizable(),
678 frame_extents_initialized(),
679 map_received(false),
680 location_assigned(false),
681 size_assigned(false),
682 on_top(false)
683 {
684 jwindow = mainEnv->NewGlobalRef(_jwindow);
685
686 gtk_widget = gtk_window_new(type == POPUP ? GTK_WINDOW_POPUP : GTK_WINDOW_TOPLEVEL);
687
688 if (gchar* app_name = get_application_name()) {
689 gtk_window_set_wmclass(GTK_WINDOW(gtk_widget), app_name, app_name);
690 g_free(app_name);
691 }
692
693 if (owner) {
694 owner->add_child(this);
695 if (on_top_inherited()) {
696 gtk_window_set_keep_above(GTK_WINDOW(gtk_widget), TRUE);
739 // Applied to a temporary full screen window to prevent sending events to Java
740 void WindowContextTop::detach_from_java() {
741 if (jview) {
742 mainEnv->DeleteGlobalRef(jview);
743 jview = NULL;
744 }
745 if (jwindow) {
746 mainEnv->DeleteGlobalRef(jwindow);
747 jwindow = NULL;
748 }
749 }
750
751 static GdkAtom
752 get_net_frame_extents_atom() {
753 static const char * extents_str = "_NET_FRAME_EXTENTS";
754 return gdk_atom_intern(extents_str, TRUE);
755 }
756
757 void
758 WindowContextTop::request_frame_extents() {
759 Display *display = GDK_DISPLAY_XDISPLAY(gdk_window_get_display(gdk_window));
760 Atom rfeAtom = XInternAtom(display, "_NET_REQUEST_FRAME_EXTENTS", True);
761 if (rfeAtom != None) {
762 XClientMessageEvent clientMessage;
763 memset(&clientMessage, 0, sizeof(clientMessage));
764
765 clientMessage.type = ClientMessage;
766 clientMessage.window = GDK_WINDOW_XID(gdk_window);
767 clientMessage.message_type = rfeAtom;
768 clientMessage.format = 32;
769
770 XSendEvent(display, XDefaultRootWindow(display), False,
771 SubstructureRedirectMask | SubstructureNotifyMask,
772 (XEvent *) &clientMessage);
773 XFlush(display);
774 }
775 }
776
777 void WindowContextTop::activate_window() {
778 Display *display = GDK_DISPLAY_XDISPLAY (gdk_window_get_display (gdk_window));
779 Atom navAtom = XInternAtom(display, "_NET_ACTIVE_WINDOW", True);
780 if (navAtom != None) {
781 XClientMessageEvent clientMessage;
782 memset(&clientMessage, 0, sizeof(clientMessage));
783
784 clientMessage.type = ClientMessage;
785 clientMessage.window = GDK_WINDOW_XID(gdk_window);
786 clientMessage.message_type = navAtom;
787 clientMessage.format = 32;
788 clientMessage.data.l[0] = 1;
789 clientMessage.data.l[1] = gdk_x11_get_server_time(gdk_window);
790 clientMessage.data.l[2] = 0;
791
792 XSendEvent(display, XDefaultRootWindow(display), False,
793 SubstructureRedirectMask | SubstructureNotifyMask,
794 (XEvent *) &clientMessage);
795 XFlush(display);
796 }
797 }
798
817 gdk_atom_intern("CARDINAL", FALSE),
818 0,
819 sizeof (unsigned long) * 4,
820 FALSE,
821 NULL,
822 NULL,
823 NULL,
824 (guchar**) & extents)) {
825 *left = extents [0];
826 *right = extents [1];
827 *top = extents [2];
828 *bottom = extents [3];
829
830 g_free(extents);
831 return true;
832 }
833
834 return false;
835 }
836
837 static int geometry_get_window_width(const WindowGeometry *windowGeometry) {
838 return (windowGeometry->final_width.type != BOUNDSTYPE_WINDOW)
839 ? windowGeometry->final_width.value
840 + windowGeometry->extents.left
841 + windowGeometry->extents.right
842 : windowGeometry->final_width.value;
843 }
844
845 static int geometry_get_window_height(const WindowGeometry *windowGeometry) {
846 return (windowGeometry->final_height.type != BOUNDSTYPE_WINDOW)
847 ? windowGeometry->final_height.value
848 + windowGeometry->extents.top
849 + windowGeometry->extents.bottom
850 : windowGeometry->final_height.value;
851 }
852
853 static int geometry_get_content_width(WindowGeometry *windowGeometry) {
854 return (windowGeometry->final_width.type != BOUNDSTYPE_CONTENT)
855 ? windowGeometry->final_width.value
856 - windowGeometry->extents.left
888 if (windowGeometry->gravity_x != 0) {
889 newValue += geometry_get_window_width(windowGeometry)
890 * windowGeometry->gravity_x;
891 }
892 windowGeometry->refx = newValue;
893 }
894
895 static void geometry_set_window_y(WindowGeometry *windowGeometry, int value) {
896 float newValue = value;
897 if (windowGeometry->gravity_y != 0) {
898 newValue += geometry_get_window_height(windowGeometry)
899 * windowGeometry->gravity_y;
900 }
901 windowGeometry->refy = newValue;
902 }
903
904 void WindowContextTop::process_net_wm_property() {
905 // Workaround for https://bugs.launchpad.net/unity/+bug/998073
906
907 static GdkAtom atom_atom = gdk_atom_intern_static_string("ATOM");
908 static GdkAtom atom_net_wm_state = gdk_atom_intern_static_string("_NET_WM_STATE");
909 static GdkAtom atom_net_wm_state_hidden = gdk_atom_intern_static_string("_NET_WM_STATE_HIDDEN");
910 static GdkAtom atom_net_wm_state_above = gdk_atom_intern_static_string("_NET_WM_STATE_ABOVE");
911
912 gint length;
913
914 glong* atoms = NULL;
915
916 if (gdk_property_get(gdk_window, atom_net_wm_state, atom_atom,
917 0, G_MAXLONG, FALSE, NULL, NULL, &length, (guchar**) &atoms)) {
918
919 bool is_hidden = false;
920 bool is_above = false;
921 for (gint i = 0; i < (gint)(length / sizeof(glong)); i++) {
922 if (atom_net_wm_state_hidden == (GdkAtom)atoms[i]) {
923 is_hidden = true;
924 } else if (atom_net_wm_state_above == (GdkAtom)atoms[i]) {
925 is_above = true;
926 }
927 }
928
929 g_free(atoms);
930
931 if (is_iconified != is_hidden) {
932 is_iconified = is_hidden;
933
934 notify_state((is_hidden)
935 ? com_sun_glass_events_WindowEvent_MINIMIZE
936 : com_sun_glass_events_WindowEvent_RESTORE);
937 }
938
939 notify_on_top(is_above);
940 }
941 }
942
943 void WindowContextTop::process_property_notify(GdkEventProperty* event) {
944 static GdkAtom atom_net_wm_state = gdk_atom_intern_static_string("_NET_WM_STATE");
945
946 if (event->atom == atom_net_wm_state && event->window == gdk_window) {
947 process_net_wm_property();
948 }
949 }
950
951 void WindowContextTop::process_configure(GdkEventConfigure* event) {
952 gint x, y, w, h;
953 bool updateWindowConstraints = false;
954 if (gtk_window_get_decorated(GTK_WINDOW(gtk_widget))) {
955 GdkRectangle frame;
956 gint top, left, bottom, right;
957
958 gdk_window_get_frame_extents(gdk_window, &frame);
959 gint contentX, contentY;
960 gdk_window_get_origin(gdk_window, &contentX, &contentY);
961 #ifdef GLASS_GTK3
962 gdk_window_get_geometry(gdk_window, NULL, NULL, &w, &h);
963 #else
964 gdk_window_get_geometry(gdk_window, NULL, NULL, &w, &h, NULL);
965 #endif
966 x = frame.x;
967 y = frame.y;
968 geometry.current_width = frame.width;
969 geometry.current_height = frame.height;
970
971 top = contentY - frame.y;
972 left = contentX - frame.x;
973 bottom = frame.y + frame.height - (contentY + h);
974 right = frame.x + frame.width - (contentX + w);
975 if (geometry.extents.top != top
976 || geometry.extents.left != left
977 || geometry.extents.bottom != bottom
978 || geometry.extents.right != right) {
979 updateWindowConstraints = true;
980 geometry.extents.top = top;
981 geometry.extents.left = left;
982 geometry.extents.bottom = bottom;
983 geometry.extents.right = right;
984 }
985 } else {
986 x = event->x;
987 y = event->y;
988 w = event->width;
989 h = event->height;
990 }
991
992 if (size_assigned && w <= 1 && h <= 1 && (geometry.final_width.value > 1 ||
993 geometry.final_height.value > 1)) {
994 // skip artifact
995 return;
996 }
997
998 geometry.final_width.value = w;
999 geometry.final_width.type = BOUNDSTYPE_CONTENT;
1000 geometry.final_height.value = h;
1001 geometry.final_height.type = BOUNDSTYPE_CONTENT;
1002 geometry_set_window_x(&geometry, x);
1003 geometry_set_window_y(&geometry, y);
1004
1005 if (jview) {
1006 mainEnv->CallVoidMethod(jview, jViewNotifyResize,
1007 event->width,
1008 event->height);
1009 CHECK_JNI_EXCEPTION(mainEnv)
1010 mainEnv->CallVoidMethod(jview, jViewNotifyView,
1011 com_sun_glass_events_ViewEvent_MOVE);
1012 CHECK_JNI_EXCEPTION(mainEnv)
1013 }
1014
1015 if (jwindow) {
1016 mainEnv->CallVoidMethod(jwindow, jWindowNotifyResize,
1017 (is_maximized)
1018 ? com_sun_glass_events_WindowEvent_MAXIMIZE
1019 : com_sun_glass_events_WindowEvent_RESIZE,
1020 geometry.current_width,
1021 geometry.current_height);
1022 CHECK_JNI_EXCEPTION(mainEnv)
1023
1024 mainEnv->CallVoidMethod(jwindow, jWindowNotifyMove, x, y);
1025 CHECK_JNI_EXCEPTION(mainEnv)
1026 }
1027
1028 glong to_screen = getScreenPtrForLocation(x, y);
1029 if (to_screen != -1) {
1030 if (to_screen != screen) {
1031 if (jwindow) {
1032 //notify screen changed
1033 jobject jScreen = createJavaScreen(mainEnv, to_screen);
1034 mainEnv->CallVoidMethod(jwindow, jWindowNotifyMoveToAnotherScreen, jScreen);
1035 CHECK_JNI_EXCEPTION(mainEnv)
1036 }
1037 screen = to_screen;
1038 }
1039 }
1040
1041 if (resizable.request != REQUEST_NONE) {
1042 set_window_resizable(resizable.request == REQUEST_RESIZABLE);
1043 resizable.request = REQUEST_NONE;
1044 } else if (!resizable.value) {
1045 set_window_resizable(false);
1046 } else if (updateWindowConstraints) {
1047 update_window_constraints();
1048 }
1049 }
1050
1051 void WindowContextTop::update_window_constraints() {
1052 if (resizable.value) {
1053 GdkGeometry geom = {
1054 (resizable.minw == -1) ? 1
1055 : resizable.minw - geometry.extents.left - geometry.extents.right,
1056 (resizable.minh == -1) ? 1
1057 : resizable.minh - geometry.extents.top - geometry.extents.bottom,
1058 (resizable.maxw == -1) ? 100000
1059 : resizable.maxw - geometry.extents.left - geometry.extents.right,
1060 (resizable.maxh == -1) ? 100000
1061 : resizable.maxh - geometry.extents.top - geometry.extents.bottom,
1062 0, 0, 0, 0, 0.0, 0.0, GDK_GRAVITY_NORTH_WEST
1063 };
1064 gtk_window_set_geometry_hints(GTK_WINDOW(gtk_widget), NULL, &geom,
1065 static_cast<GdkWindowHints> (GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE));
1066 }
1067 }
1068
1069 void WindowContextTop::set_window_resizable(bool res) {
1070 if(!res) {
1071 int w = geometry_get_content_width(&geometry);
1072 int h = geometry_get_content_height(&geometry);
1073 if (w == -1 && h == -1) {
1074 gtk_window_get_size(GTK_WINDOW(gtk_widget), &w, &h);
1075 }
1076 GdkGeometry geom = {w, h, w, h, 0, 0, 0, 0, 0.0, 0.0, GDK_GRAVITY_NORTH_WEST};
1077 gtk_window_set_geometry_hints(GTK_WINDOW(gtk_widget), NULL, &geom,
1078 static_cast<GdkWindowHints>(GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE));
1079 resizable.value = false;
1080 } else {
1081 resizable.value = true;
1082 update_window_constraints();
1083 }
1084 }
1085
1086 void WindowContextTop::set_resizable(bool res) {
1087 resizable.prev = false;
1088 gint w, h;
1089 gtk_window_get_size(GTK_WINDOW(gtk_widget), &w, &h);
1090 if (map_received || w > 1 || h > 1) {
1091 set_window_resizable(res);
1092 } else {
1093 //Since window is not ready yet set only request for change of resizable.
1094 resizable.request = res ? REQUEST_RESIZABLE : REQUEST_NOT_RESIZABLE;
1095 }
1096 }
1097
1098 void WindowContextTop::set_visible(bool visible)
1099 {
1100 if (visible) {
1101 if (!size_assigned) {
1102 set_bounds(0, 0, false, false, 320, 200, -1, -1);
1103 }
1104 if (!location_assigned) {
1105 set_bounds(0, 0, true, true, -1, -1, -1, -1);
1106 }
1107 }
1108 WindowContextBase::set_visible(visible);
1109 }
1110
1111 void WindowContextTop::set_bounds(int x, int y, bool xSet, bool ySet, int w, int h, int cw, int ch) {
1164 windowChangesMask |= CWY;
1165 }
1166
1167 if (xSet || ySet) location_assigned = true;
1168 if (w > 0 || h > 0 || cw > 0 || ch > 0) size_assigned = true;
1169
1170 window_configure(&windowChanges, windowChangesMask);
1171
1172 }
1173
1174 void WindowContextTop::process_map() {
1175 map_received = true;
1176 }
1177
1178 void WindowContextTop::window_configure(XWindowChanges *windowChanges,
1179 unsigned int windowChangesMask) {
1180 if (windowChangesMask == 0) {
1181 return;
1182 }
1183
1184 if (windowChangesMask & (CWX | CWY)) {
1185 gint newX, newY;
1186 gtk_window_get_position(GTK_WINDOW(gtk_widget), &newX, &newY);
1187 if (windowChangesMask & CWX) {
1188 newX = windowChanges->x;
1189 }
1190 if (windowChangesMask & CWY) {
1191 newY = windowChanges->y;
1192 }
1193 gtk_window_move(GTK_WINDOW(gtk_widget), newX, newY);
1194 }
1195
1196 if (windowChangesMask & (CWWidth | CWHeight)) {
1197 gint newWidth, newHeight;
1198 gtk_window_get_size(GTK_WINDOW(gtk_widget), &newWidth, &newHeight);
1199
1200 if (windowChangesMask & CWWidth) {
1201 newWidth = windowChanges->width;
1202 }
1203 if (windowChangesMask & CWHeight) {
1204 newHeight = windowChanges->height;
1205 }
1206 if (!resizable.value) {
1207 GdkGeometry geom;
1208 GdkWindowHints hints = (GdkWindowHints)(GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE);
1209 geom.min_width = geom.max_width = newWidth;
1210 geom.min_height = geom.max_height = newHeight;
1211 gtk_window_set_geometry_hints(GTK_WINDOW(gtk_widget), NULL, &geom, hints);
1212 }
1213 gtk_window_resize(GTK_WINDOW(gtk_widget), newWidth, newHeight);
1214 }
1215 }
1216
1217 void WindowContextTop::applyShapeMask(void* data, uint width, uint height)
1218 {
1219 if (frame_type != TRANSPARENT) {
1220 return;
1221 }
1222
1223 glass_window_apply_shape_mask(gtk_widget_get_window(gtk_widget), data, width, height);
1224 }
1225
1226 void WindowContextTop::ensure_window_size() {
1227 gint w, h;
1228 #ifdef GLASS_GTK3
1229 gdk_window_get_geometry(gdk_window, NULL, NULL, &w, &h);
1230 #else
1231 gdk_window_get_geometry(gdk_window, NULL, NULL, &w, &h, NULL);
1232 #endif
1233 if (size_assigned && (geometry.final_width.value != w
1234 || geometry.final_height.value != h)) {
1235
1236 gdk_window_resize(gdk_window, geometry.final_width.value,
1237 geometry.final_height.value);
1238 }
1239 }
1240
1241 void WindowContextTop::set_minimized(bool minimize) {
1242 is_iconified = minimize;
1243 if (minimize) {
1244 if (frame_type == TRANSPARENT) {
1245 // https://bugs.launchpad.net/ubuntu/+source/unity/+bug/1245571
1246 glass_window_reset_input_shape_mask(gtk_widget_get_window(gtk_widget));
1247 }
1248
1249 if ((gdk_windowManagerFunctions & GDK_FUNC_MINIMIZE) == 0) {
1250 // in this case - the window manager will not support the programatic
1251 // request to iconify - so we need to disable this until we are restored.
1252 GdkWMFunction wmf = (GdkWMFunction)(gdk_windowManagerFunctions | GDK_FUNC_MINIMIZE);
1253 gdk_window_set_functions(gdk_window, wmf);
1254 }
1255 gtk_window_iconify(GTK_WINDOW(gtk_widget));
1256 } else {
1257 gtk_window_deiconify(GTK_WINDOW(gtk_widget));
1258 activate_window();
1259 }
1260 }
1261 void WindowContextTop::set_maximized(bool maximize) {
1262 is_maximized = maximize;
1263 if (maximize) {
1264 ensure_window_size();
1265 gtk_window_maximize(GTK_WINDOW(gtk_widget));
1266 } else {
1267 gtk_window_unmaximize(GTK_WINDOW(gtk_widget));
1268 }
1269 }
1270
1271 void WindowContextTop::enter_fullscreen() {
1272 ensure_window_size();
1273 gtk_window_fullscreen(GTK_WINDOW(gtk_widget));
1274 }
1275
1276 void WindowContextTop::exit_fullscreen() {
1277 gtk_window_unfullscreen(GTK_WINDOW(gtk_widget));
1278 }
1279
1280 void WindowContextTop::request_focus() {
1281 gtk_window_present(GTK_WINDOW(gtk_widget));
1282 }
1283
1284 void WindowContextTop::set_focusable(bool focusable) {
1285 gtk_window_set_accept_focus(GTK_WINDOW(gtk_widget), focusable ? TRUE : FALSE);
1286 }
1287
1288 void WindowContextTop::set_title(const char* title) {
1289 gtk_window_set_title(GTK_WINDOW(gtk_widget),title);
1290 }
1291
1292 void WindowContextTop::set_alpha(double alpha) {
1293 gtk_window_set_opacity(GTK_WINDOW(gtk_widget), (gdouble)alpha);
1294 }
1295
1296 void WindowContextTop::set_enabled(bool enabled) {
1297 if (enabled) {
1298 if (resizable.prev) {
1299 set_window_resizable(true);
1300 }
1301 } else {
1302 if (resizable.value) {
1303 set_window_resizable(false);
1304 resizable.prev = true;
1305 } else if (resizable.request == REQUEST_RESIZABLE) {
1306 resizable.request = REQUEST_NOT_RESIZABLE;
1307 resizable.prev = true;
1308 }
1309 }
1310 }
1311
1312 void WindowContextTop::set_minimum_size(int w, int h) {
1313 resizable.minw = w;
1314 resizable.minh = h;
1315 update_window_constraints();
1316 }
1317
1318 void WindowContextTop::set_maximum_size(int w, int h) {
1319 resizable.maxw = w;
1320 resizable.maxh = h;
1321 update_window_constraints();
1322 }
1323
1324 void WindowContextTop::set_icon(GdkPixbuf* pixbuf) {
1325 gtk_window_set_icon(GTK_WINDOW(gtk_widget), pixbuf);
1326 }
1327
1328 void WindowContextTop::restack(bool restack) {
1428 WindowContextBase::process_destroy();
1429 }
1430
1431 ////////////////////////////// WindowContextPlug ////////////////////////////////
1432
1433 static gboolean plug_configure(GtkWidget *widget, GdkEvent *event, gpointer user_data) {
1434 (void)widget;
1435
1436 if (event->type == GDK_CONFIGURE) {
1437 ((WindowContextPlug*)user_data)->process_gtk_configure(&event->configure);
1438 }
1439 return FALSE;
1440 }
1441
1442 WindowContextPlug::WindowContextPlug(jobject _jwindow, void* _owner) :
1443 WindowContextBase(),
1444 parent()
1445 {
1446 jwindow = mainEnv->NewGlobalRef(_jwindow);
1447
1448 WindowContext* parent = ((WindowContext*)JLONG_TO_PTR(_owner));
1449 Window win = GDK_WINDOW_XID(parent->get_gdk_window());
1450 gtk_widget = gtk_plug_new(win);
1451
1452 g_signal_connect(G_OBJECT(gtk_widget), "configure-event", G_CALLBACK(plug_configure), this);
1453
1454 gtk_widget_set_size_request(gtk_widget, 0, 0);
1455 gtk_widget_set_events(gtk_widget, GDK_ALL_EVENTS_MASK);
1456 gtk_widget_set_can_focus(GTK_WIDGET(gtk_widget), TRUE);
1457 gtk_widget_set_app_paintable(gtk_widget, TRUE);
1458
1459 gtk_widget_realize(gtk_widget);
1460 gdk_window = gtk_widget_get_window(gtk_widget);
1461
1462 g_object_set_data_full(G_OBJECT(gdk_window), GDK_WINDOW_DATA_CONTEXT, this, NULL);
1463 gdk_window_register_dnd(gdk_window);
1464
1465 gtk_container = gtk_fixed_new();
1466 gtk_container_add (GTK_CONTAINER(gtk_widget), gtk_container);
1467 gtk_widget_realize(gtk_container);
1468 }
1469
1470 GtkWindow *WindowContextPlug::get_gtk_window() {
1663
1664 gtk_widget_set_size_request(gtk_widget, event->width, event->height);
1665
1666 if (jwindow) {
1667 mainEnv->CallVoidMethod(jwindow, jWindowNotifyResize,
1668 com_sun_glass_events_WindowEvent_RESIZE,
1669 event->width,
1670 event->height);
1671 CHECK_JNI_EXCEPTION(mainEnv)
1672 }
1673 }
1674
1675 bool WindowContextChild::set_view(jobject view) {
1676 if (jview) {
1677 mainEnv->DeleteGlobalRef(jview);
1678 }
1679
1680 if (view) {
1681 gint width, height;
1682 jview = mainEnv->NewGlobalRef(view);
1683 GtkAllocation ws;
1684 gtk_widget_get_allocation(gtk_widget, &ws);
1685 width = ws.width;
1686 height = ws.height;
1687 mainEnv->CallVoidMethod(view, jViewNotifyResize, width, height);
1688 CHECK_JNI_EXCEPTION_RET(mainEnv, FALSE)
1689 } else {
1690 jview = NULL;
1691 }
1692 return TRUE;
1693 }
1694
1695 void WindowContextChild::set_bounds(int x, int y, bool xSet, bool ySet, int w, int h, int cw, int ch) {
1696
1697 if (x > 0 || y > 0 || xSet || ySet) {
1698 gint newX, newY;
1699 gdk_window_get_origin(gdk_window, &newX, &newY);
1700 if (jwindow) {
1701 mainEnv->CallVoidMethod(jwindow,
1702 jWindowNotifyMove,
1703 newX, newY);
1704 CHECK_JNI_EXCEPTION(mainEnv)
1705 }
1706 }
1707
1708 // As we have no frames, there's no difference between the calls
1709 if ((cw | ch) > 0) {
1710 w = cw; h = ch;
1711 }
1712
1713 if (w > 0 || h > 0) {
1714 gint newWidth, newHeight;
1715 GtkAllocation ws;
1716 gtk_widget_get_allocation(gtk_widget, &ws);
1717 newWidth = ws.width;
1718 newHeight = ws.height;
1719
1720 if (w > 0) {
1721 newWidth = w;
1722 }
1723 if (h > 0) {
1724 newHeight = h;
1725 }
1726 gtk_widget_set_size_request(gtk_widget, newWidth, newHeight);
1727 // FIXME: hack to set correct size to view
1728 if (jview) {
1729 mainEnv->CallVoidMethod(jview,
1730 jViewNotifyResize,
1731 newWidth, newHeight);
1732 CHECK_JNI_EXCEPTION(mainEnv)
1733 }
1734 }
1735 }
1736
1737 int WindowContextChild::getEmbeddedX() {
1738 int x;
1756
1757 embedded_children.erase(pos);
1758 if (toFront) {
1759 embedded_children.push_back(this);
1760 } else {
1761 embedded_children.insert(embedded_children.begin(), this);
1762 }
1763
1764 gdk_window_restack(gdk_window, NULL, toFront ? TRUE : FALSE);
1765 }
1766
1767 void WindowContextChild::enter_fullscreen() {
1768 if (full_screen_window) {
1769 return;
1770 }
1771
1772 full_screen_window = new WindowContextTop(jwindow, NULL, 0L, UNTITLED,
1773 NORMAL, (GdkWMFunction) 0);
1774 int x, y, w, h;
1775 gdk_window_get_origin(gdk_window, &x, &y);
1776 #ifdef GLASS_GTK3
1777 gdk_window_get_geometry(gdk_window, NULL, NULL, &w, &h);
1778 #else
1779 gdk_window_get_geometry(gdk_window, NULL, NULL, &w, &h, NULL);
1780 #endif
1781 full_screen_window->set_bounds(x, y, true, true, w, h, -1, -1);
1782
1783 if (WindowContextBase::sm_grab_window == this) {
1784 ungrab_focus();
1785 }
1786
1787 reparent_children(full_screen_window);
1788
1789 full_screen_window->set_visible(true);
1790 full_screen_window->enter_fullscreen();
1791
1792 if (jwindow) {
1793 mainEnv->CallVoidMethod(jwindow, jWindowNotifyDelegatePtr, (jlong)full_screen_window);
1794 CHECK_JNI_EXCEPTION(mainEnv)
1795 }
1796
1797 if (jview) {
1798 this->view = (GlassView*)mainEnv->GetLongField(jview, jViewPtr);
1799
1800 this->view->current_window = full_screen_window;
|