1 /* 2 * Copyright (c) 2011, 2014, 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 #ifndef GLASS_WINDOW_H 26 #define GLASS_WINDOW_H 27 28 #include <gtk/gtk.h> 29 #include <X11/Xlib.h> 30 31 #include <jni.h> 32 #include <set> 33 #include <vector> 34 35 #include "glass_view.h" 36 37 enum WindowFrameType { 38 TITLED, 39 UNTITLED, 40 TRANSPARENT 41 }; 42 43 enum WindowType { 44 NORMAL, 45 UTILITY, 46 POPUP 47 }; 48 49 enum request_type { 50 REQUEST_NONE, 51 REQUEST_RESIZABLE, 52 REQUEST_NOT_RESIZABLE 53 }; 54 55 struct WindowFrameExtents { 56 int top; 57 int left; 58 int bottom; 59 int right; 60 }; 61 62 static const guint MOUSE_BUTTONS_MASK = (guint) (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK); 63 64 enum BoundsType { 65 BOUNDSTYPE_CONTENT, 66 BOUNDSTYPE_WINDOW 67 }; 68 69 struct WindowGeometry { 70 WindowGeometry(): final_width(), final_height(), 71 refx(), refy(), gravity_x(), gravity_y(), current_width(), current_height(), extents() {} 72 // estimate of the final width the window will get after all pending 73 // configure requests are processed by the window manager 74 struct { 75 int value; 76 BoundsType type; 77 } final_width; 78 79 struct { 80 int value; 81 BoundsType type; 82 } final_height; 83 84 float refx; 85 float refy; 86 float gravity_x; 87 float gravity_y; 88 89 // the last width which was configured or obtained from configure 90 // notification 91 int current_width; 92 93 // the last height which was configured or obtained from configure 94 // notification 95 int current_height; 96 97 WindowFrameExtents extents; 98 99 }; 100 101 class WindowContextChild; 102 class WindowContextTop; 103 104 class WindowContext { 105 public: 106 virtual bool isEnabled() = 0; 107 virtual bool hasIME() = 0; 108 virtual bool filterIME(GdkEvent *) = 0; 109 virtual void enableOrResetIME() = 0; 110 virtual void disableIME() = 0; 111 virtual void paint(void* data, jint width, jint height) = 0; 112 virtual WindowFrameExtents get_frame_extents() = 0; 113 114 virtual void enter_fullscreen() = 0; 115 virtual void exit_fullscreen() = 0; 116 virtual void show_or_hide_children(bool) = 0; 117 virtual void set_visible(bool) = 0; 118 virtual bool is_visible() = 0; 119 virtual void set_bounds(int, int, bool, bool, int, int, int, int) = 0; 120 virtual void set_resizable(bool) = 0; 121 virtual void request_focus() = 0; 122 virtual void set_focusable(bool)= 0; 123 virtual bool grab_focus() = 0; 124 virtual bool grab_mouse_drag_focus() = 0; 125 virtual void ungrab_focus() = 0; 126 virtual void ungrab_mouse_drag_focus() = 0; 127 virtual void set_title(const char*) = 0; 128 virtual void set_alpha(double) = 0; 129 virtual void set_enabled(bool) = 0; 130 virtual void set_minimum_size(int, int) = 0; 131 virtual void set_maximum_size(int, int) = 0; 132 virtual void set_minimized(bool) = 0; 133 virtual void set_maximized(bool) = 0; 134 virtual void set_icon(GdkPixbuf*) = 0; 135 virtual void restack(bool) = 0; 136 virtual void set_cursor(GdkCursor*) = 0; 137 virtual void set_modal(bool, WindowContext* parent = NULL) = 0; 138 virtual void set_gravity(float, float) = 0; 139 virtual void set_level(int) = 0; 140 virtual void set_background(float, float, float) = 0; 141 142 virtual void process_property_notify(GdkEventProperty*) = 0; 143 virtual void process_configure(GdkEventConfigure*) = 0; 144 virtual void process_map() = 0; 145 virtual void process_focus(GdkEventFocus*) = 0; 146 virtual void process_destroy() = 0; 147 virtual void process_delete() = 0; 148 virtual void process_expose(GdkEventExpose*) = 0; 149 virtual void process_mouse_button(GdkEventButton*) = 0; 150 virtual void process_mouse_motion(GdkEventMotion*) = 0; 151 virtual void process_mouse_scroll(GdkEventScroll*) = 0; 152 virtual void process_mouse_cross(GdkEventCrossing*) = 0; 153 virtual void process_key(GdkEventKey*) = 0; 154 virtual void process_state(GdkEventWindowState*) = 0; 155 156 virtual void notify_state(jint) = 0; 157 virtual void notify_on_top(bool) {} 158 159 virtual void add_child(WindowContextTop* child) = 0; 160 virtual void remove_child(WindowContextTop* child) = 0; 161 virtual bool set_view(jobject) = 0; 162 163 virtual GdkWindow *get_gdk_window() = 0; 164 virtual GtkWindow *get_gtk_window() = 0; 165 virtual jobject get_jview() = 0; 166 virtual jobject get_jwindow() = 0; 167 168 virtual int getEmbeddedX() = 0; 169 virtual int getEmbeddedY() = 0; 170 171 172 virtual void increment_events_counter() = 0; 173 virtual void decrement_events_counter() = 0; 174 virtual size_t get_events_count() = 0; 175 virtual bool is_dead() = 0; 176 virtual ~WindowContext() {} 177 }; 178 179 class WindowContextBase: public WindowContext { 180 181 struct _XIM{ 182 XIM im; 183 XIC ic; 184 bool enabled; 185 } xim; 186 187 size_t events_processing_cnt; 188 bool can_be_deleted; 189 protected: 190 std::set<WindowContextTop*> children; 191 jobject jwindow; 192 jobject jview; 193 GtkWidget* gtk_widget; 194 GdkWindow* gdk_window; 195 196 bool is_iconified; 197 bool is_maximized; 198 bool is_mouse_entered; 199 200 /* 201 * sm_grab_window points to WindowContext holding a mouse grab. 202 * It is mostly used for popup windows. 203 */ 204 static WindowContext* sm_grab_window; 205 206 /* 207 * sm_mouse_drag_window points to a WindowContext from which a mouse drag started. 208 * This WindowContext holding a mouse grab during this drag. After releasing 209 * all mouse buttons sm_mouse_drag_window becomes NULL and sm_grab_window's 210 * mouse grab should be restored if present. 211 * 212 * This is done in order to mimic Windows behavior: 213 * All mouse events should be delivered to a window from which mouse drag 214 * started, until all mouse buttons released. No mouse ENTER/EXIT events 215 * should be reported during this drag. 216 */ 217 static WindowContext* sm_mouse_drag_window; 218 public: 219 bool isEnabled(); 220 bool hasIME(); 221 bool filterIME(GdkEvent *); 222 void enableOrResetIME(); 223 void disableIME(); 224 void paint(void*, jint, jint); 225 GdkWindow *get_gdk_window(); 226 jobject get_jwindow(); 227 jobject get_jview(); 228 229 void add_child(WindowContextTop*); 230 void remove_child(WindowContextTop*); 231 void show_or_hide_children(bool); 232 void reparent_children(WindowContext* parent); 233 void set_visible(bool); 234 bool is_visible(); 235 bool set_view(jobject); 236 bool grab_focus(); 237 bool grab_mouse_drag_focus(); 238 void ungrab_focus(); 239 void ungrab_mouse_drag_focus(); 240 void set_cursor(GdkCursor*); 241 void set_level(int) {} 242 void set_background(float, float, float); 243 244 void process_map() {} 245 void process_focus(GdkEventFocus*); 246 void process_destroy(); 247 void process_delete(); 248 void process_expose(GdkEventExpose*); 249 void process_mouse_button(GdkEventButton*); 250 void process_mouse_motion(GdkEventMotion*); 251 void process_mouse_scroll(GdkEventScroll*); 252 void process_mouse_cross(GdkEventCrossing*); 253 void process_key(GdkEventKey*); 254 void process_state(GdkEventWindowState*); 255 256 void notify_state(jint); 257 258 int getEmbeddedX() { return 0; } 259 int getEmbeddedY() { return 0; } 260 261 void increment_events_counter(); 262 void decrement_events_counter(); 263 size_t get_events_count(); 264 bool is_dead(); 265 266 ~WindowContextBase(); 267 protected: 268 virtual void applyShapeMask(void*, uint width, uint height) = 0; 269 private: 270 bool im_filter_keypress(GdkEventKey*); 271 }; 272 273 class WindowContextPlug: public WindowContextBase { 274 WindowContext* parent; 275 public: 276 bool set_view(jobject); 277 void set_bounds(int, int, bool, bool, int, int, int, int); 278 //WindowFrameExtents get_frame_extents() { return WindowFrameExtents{0, 0, 0, 0}; }; 279 WindowFrameExtents get_frame_extents() { WindowFrameExtents ext = {0, 0, 0, 0}; return ext;} 280 281 void enter_fullscreen() {} 282 void exit_fullscreen() {} 283 void set_resizable(bool) {} 284 void request_focus() {} 285 void set_focusable(bool) {} 286 void set_title(const char*) {} 287 void set_alpha(double) {} 288 void set_enabled(bool) {} 289 void set_minimum_size(int, int) {} 290 void set_maximum_size(int, int) {} 291 void set_minimized(bool) {} 292 void set_maximized(bool) {} 293 void set_icon(GdkPixbuf*) {} 294 void restack(bool) {} 295 void set_modal(bool, WindowContext*) {} 296 void set_gravity(float, float) {} 297 void process_property_notify(GdkEventProperty*) {} 298 void process_configure(GdkEventConfigure*); 299 void process_gtk_configure(GdkEventConfigure*); 300 301 void applyShapeMask(void*, uint width, uint height) {} 302 GtkWindow *get_gtk_window(); // TODO, get window from parent 303 304 WindowContextPlug(jobject, void*); 305 GtkWidget* gtk_container; 306 std::vector<WindowContextChild *> embedded_children; 307 private: 308 //HACK: remove once set_bounds is implemented correctly 309 void window_configure(XWindowChanges *, unsigned int); 310 WindowContextPlug(WindowContextPlug&); 311 WindowContextPlug& operator= (const WindowContextPlug&); 312 }; 313 314 class WindowContextChild: public WindowContextBase { 315 WindowContextPlug* parent; 316 WindowContextTop* full_screen_window; 317 GlassView* view; // not null while in Full Screen 318 public: 319 void process_mouse_button(GdkEventButton*); 320 bool set_view(jobject); 321 void set_bounds(int, int, bool, bool, int, int, int, int); 322 //WindowFrameExtents get_frame_extents() { return WindowFrameExtents{0, 0, 0, 0}; }; 323 WindowFrameExtents get_frame_extents() { WindowFrameExtents ext = {0, 0, 0, 0}; return ext;} 324 325 void enter_fullscreen(); 326 void exit_fullscreen(); 327 void set_resizable(bool) {} 328 void request_focus() {} 329 void set_focusable(bool) {} 330 void set_title(const char*) {} 331 void set_alpha(double) {} 332 void set_enabled(bool) {} 333 void set_minimum_size(int, int) {} 334 void set_maximum_size(int, int) {} 335 void set_minimized(bool) {} 336 void set_maximized(bool) {} 337 void set_icon(GdkPixbuf*) {} 338 void restack(bool); 339 void set_modal(bool, WindowContext*) {} 340 void set_gravity(float, float) {} 341 void process_property_notify(GdkEventProperty*) {} 342 void process_configure(GdkEventConfigure*); 343 void process_destroy(); 344 void set_visible(bool visible); 345 346 int getEmbeddedX(); 347 int getEmbeddedY(); 348 349 void applyShapeMask(void*, uint width, uint height) {} 350 GtkWindow *get_gtk_window(); // TODO, get window from parent 351 352 WindowContextChild(jobject, void*, GtkWidget *parent_widget, WindowContextPlug *parent_context); 353 private: 354 WindowContextChild(WindowContextChild&); 355 WindowContextChild& operator= (const WindowContextChild&); 356 }; 357 358 class WindowContextTop: public WindowContextBase { 359 jlong screen; 360 WindowFrameType frame_type; 361 struct WindowContext *owner; 362 WindowGeometry geometry; 363 int stale_config_notifications; 364 struct _Resizable{// we can't use set/get gtk_window_resizable function 365 _Resizable(): request(REQUEST_NONE), value(true), prev(false), 366 minw(-1), minh(-1), maxw(-1), maxh(-1){} 367 request_type request; //request for future setResizable 368 bool value; //actual value of resizable for a window 369 bool prev; //former resizable value (used in setEnabled for parents of modal window) 370 int minw, minh, maxw, maxh; //minimum and maximum window width/height; 371 } resizable; 372 373 bool frame_extents_initialized; 374 bool map_received; 375 bool location_assigned; 376 bool size_assigned; 377 bool on_top; 378 public: 379 WindowContextTop(jobject, WindowContext*, long, WindowFrameType, WindowType); 380 void process_map(); 381 void process_property_notify(GdkEventProperty*); 382 void process_configure(GdkEventConfigure*); 383 void process_destroy(); 384 void process_net_wm_property(); 385 386 WindowFrameExtents get_frame_extents(); 387 388 void set_minimized(bool); 389 void set_maximized(bool); 390 void set_bounds(int, int, bool, bool, int, int, int, int); 391 void set_resizable(bool); 392 void request_focus(); 393 void set_focusable(bool); 394 void set_title(const char*); 395 void set_alpha(double); 396 void set_enabled(bool); 397 void set_minimum_size(int, int); 398 void set_maximum_size(int, int); 399 void set_icon(GdkPixbuf*); 400 void restack(bool); 401 void set_modal(bool, WindowContext* parent = NULL); 402 void set_gravity(float, float); 403 void set_level(int); 404 void set_visible(bool); 405 void notify_on_top(bool); 406 407 void enter_fullscreen(); 408 void exit_fullscreen(); 409 410 void set_owner(WindowContext*); 411 412 GtkWindow *get_gtk_window(); 413 void detach_from_java(); 414 protected: 415 void applyShapeMask(void*, uint width, uint height); 416 private: 417 bool get_frame_extents_property(int *, int *, int *, int *); 418 void request_frame_extents(); 419 void initialize_frame_extents(); 420 void window_configure(XWindowChanges *, unsigned int); 421 void update_window_constraints(); 422 void set_window_resizable(bool, bool); 423 void update_ontop_tree(bool); 424 bool on_top_inherited(); 425 bool effective_on_top(); 426 WindowContextTop(WindowContextTop&); 427 WindowContextTop& operator= (const WindowContextTop&); 428 }; 429 430 void destroy_and_delete_ctx(WindowContext* ctx); 431 432 class EventsCounterHelper { 433 private: 434 WindowContext* ctx; 435 public: 436 explicit EventsCounterHelper(WindowContext* context) { 437 ctx = context; 438 ctx->increment_events_counter(); 439 } 440 ~EventsCounterHelper() { 441 ctx->decrement_events_counter(); 442 if (ctx->is_dead() && ctx->get_events_count() == 0) { 443 delete ctx; 444 } 445 ctx = NULL; 446 } 447 }; 448 449 #endif /* GLASS_WINDOW_H */ 450