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 #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     GdkWMFunction gdk_windowManagerFunctions;
 196 
 197     bool is_iconified;
 198     bool is_maximized;
 199     bool is_mouse_entered;
 200 
 201     /*
 202      * sm_grab_window points to WindowContext holding a mouse grab.
 203      * It is mostly used for popup windows.
 204      */
 205     static WindowContext* sm_grab_window;
 206 
 207     /*
 208      * sm_mouse_drag_window points to a WindowContext from which a mouse drag started.
 209      * This WindowContext holding a mouse grab during this drag. After releasing
 210      * all mouse buttons sm_mouse_drag_window becomes NULL and sm_grab_window's
 211      * mouse grab should be restored if present.
 212      *
 213      * This is done in order to mimic Windows behavior:
 214      * All mouse events should be delivered to a window from which mouse drag
 215      * started, until all mouse buttons released. No mouse ENTER/EXIT events
 216      * should be reported during this drag.
 217      */
 218     static WindowContext* sm_mouse_drag_window;
 219 public:
 220     bool isEnabled();
 221     bool hasIME();
 222     bool filterIME(GdkEvent *);
 223     void enableOrResetIME();
 224     void disableIME();
 225     void paint(void*, jint, jint);
 226     GdkWindow *get_gdk_window();
 227     jobject get_jwindow();
 228     jobject get_jview();
 229 
 230     void add_child(WindowContextTop*);
 231     void remove_child(WindowContextTop*);
 232     void show_or_hide_children(bool);
 233     void reparent_children(WindowContext* parent);
 234     void set_visible(bool);
 235     bool is_visible();
 236     bool set_view(jobject);
 237     bool grab_focus();
 238     bool grab_mouse_drag_focus();
 239     void ungrab_focus();
 240     void ungrab_mouse_drag_focus();
 241     void set_cursor(GdkCursor*);
 242     void set_level(int) {}
 243     void set_background(float, float, float);
 244 
 245     void process_map() {}
 246     void process_focus(GdkEventFocus*);
 247     void process_destroy();
 248     void process_delete();
 249     void process_expose(GdkEventExpose*);
 250     void process_mouse_button(GdkEventButton*);
 251     void process_mouse_motion(GdkEventMotion*);
 252     void process_mouse_scroll(GdkEventScroll*);
 253     void process_mouse_cross(GdkEventCrossing*);
 254     void process_key(GdkEventKey*);
 255     void process_state(GdkEventWindowState*);
 256 
 257     void notify_state(jint);
 258 
 259     int getEmbeddedX() { return 0; }
 260     int getEmbeddedY() { return 0; }
 261 
 262     void increment_events_counter();
 263     void decrement_events_counter();
 264     size_t get_events_count();
 265     bool is_dead();
 266 
 267     ~WindowContextBase();
 268 protected:
 269     virtual void applyShapeMask(void*, uint width, uint height) = 0;
 270 private:
 271     bool im_filter_keypress(GdkEventKey*);
 272 };
 273 
 274 class WindowContextPlug: public WindowContextBase {
 275     WindowContext* parent;
 276 public:
 277     bool set_view(jobject);
 278     void set_bounds(int, int, bool, bool, int, int, int, int);
 279     //WindowFrameExtents get_frame_extents() { return WindowFrameExtents{0, 0, 0, 0}; };
 280     WindowFrameExtents get_frame_extents() { WindowFrameExtents ext = {0, 0, 0, 0}; return ext;}
 281 
 282     void enter_fullscreen() {}
 283     void exit_fullscreen() {}
 284     void set_resizable(bool) {}
 285     void request_focus() {}
 286     void set_focusable(bool) {}
 287     void set_title(const char*) {}
 288     void set_alpha(double) {}
 289     void set_enabled(bool) {}
 290     void set_minimum_size(int, int) {}
 291     void set_maximum_size(int, int) {}
 292     void set_minimized(bool) {}
 293     void set_maximized(bool) {}
 294     void set_icon(GdkPixbuf*) {}
 295     void restack(bool) {}
 296     void set_modal(bool, WindowContext*) {}
 297     void set_gravity(float, float) {}
 298     void process_property_notify(GdkEventProperty*) {}
 299     void process_configure(GdkEventConfigure*);
 300     void process_gtk_configure(GdkEventConfigure*);
 301 
 302     void applyShapeMask(void*, uint width, uint height) {
 303         (void)width;
 304         (void)height;
 305     }
 306     GtkWindow *get_gtk_window(); // TODO, get window from parent
 307 
 308     WindowContextPlug(jobject, void*);
 309     GtkWidget* gtk_container;
 310     std::vector<WindowContextChild *> embedded_children;
 311 private:
 312     //HACK: remove once set_bounds is implemented correctly
 313     void window_configure(XWindowChanges *, unsigned int);
 314     WindowContextPlug(WindowContextPlug&);
 315     WindowContextPlug& operator= (const WindowContextPlug&);
 316 };
 317 
 318 class WindowContextChild: public WindowContextBase {
 319     WindowContextPlug* parent;
 320     WindowContextTop* full_screen_window;
 321     GlassView* view; // not null while in Full Screen
 322 public:
 323     void process_mouse_button(GdkEventButton*);
 324     bool set_view(jobject);
 325     void set_bounds(int, int, bool, bool, int, int, int, int);
 326     //WindowFrameExtents get_frame_extents() { return WindowFrameExtents{0, 0, 0, 0}; };
 327     WindowFrameExtents get_frame_extents() { WindowFrameExtents ext = {0, 0, 0, 0}; return ext;}
 328 
 329     void enter_fullscreen();
 330     void exit_fullscreen();
 331     void set_resizable(bool) {}
 332     void request_focus() {}
 333     void set_focusable(bool) {}
 334     void set_title(const char*) {}
 335     void set_alpha(double) {}
 336     void set_enabled(bool) {}
 337     void set_minimum_size(int, int) {}
 338     void set_maximum_size(int, int) {}
 339     void set_minimized(bool) {}
 340     void set_maximized(bool) {}
 341     void set_icon(GdkPixbuf*) {}
 342     void restack(bool);
 343     void set_modal(bool, WindowContext*) {}
 344     void set_gravity(float, float) {}
 345     void process_property_notify(GdkEventProperty*) {}
 346     void process_configure(GdkEventConfigure*);
 347     void process_destroy();
 348     void set_visible(bool visible);
 349 
 350     int getEmbeddedX();
 351     int getEmbeddedY();
 352 
 353     void applyShapeMask(void*, uint width, uint height) {
 354         (void)width;
 355         (void)height;
 356     }
 357     GtkWindow *get_gtk_window(); // TODO, get window from parent
 358 
 359     WindowContextChild(jobject, void*, GtkWidget *parent_widget, WindowContextPlug *parent_context);
 360 private:
 361     WindowContextChild(WindowContextChild&);
 362     WindowContextChild& operator= (const WindowContextChild&);
 363 };
 364 
 365 class WindowContextTop: public WindowContextBase {
 366     jlong screen;
 367     WindowFrameType frame_type;
 368     struct WindowContext *owner;
 369     WindowGeometry geometry;
 370     int stale_config_notifications;
 371     struct _Resizable{// we can't use set/get gtk_window_resizable function
 372         _Resizable(): request(REQUEST_NONE), value(true), prev(false),
 373                 minw(-1), minh(-1), maxw(-1), maxh(-1){}
 374         request_type request; //request for future setResizable
 375         bool value; //actual value of resizable for a window
 376         bool prev; //former resizable value (used in setEnabled for parents of modal window)
 377         int minw, minh, maxw, maxh; //minimum and maximum window width/height;
 378     } resizable;
 379 
 380     bool frame_extents_initialized;
 381     bool map_received;
 382     bool location_assigned;
 383     bool size_assigned;
 384     bool on_top;
 385 public:
 386     WindowContextTop(jobject, WindowContext*, long, WindowFrameType, WindowType, GdkWMFunction);
 387     void process_map();
 388     void process_property_notify(GdkEventProperty*);
 389     void process_configure(GdkEventConfigure*);
 390     void process_destroy();
 391     void process_net_wm_property();
 392 
 393     WindowFrameExtents get_frame_extents();
 394 
 395     void set_minimized(bool);
 396     void set_maximized(bool);
 397     void set_bounds(int, int, bool, bool, int, int, int, int);
 398     void set_resizable(bool);
 399     void request_focus();
 400     void set_focusable(bool);
 401     void set_title(const char*);
 402     void set_alpha(double);
 403     void set_enabled(bool);
 404     void set_minimum_size(int, int);
 405     void set_maximum_size(int, int);
 406     void set_icon(GdkPixbuf*);
 407     void restack(bool);
 408     void set_modal(bool, WindowContext* parent = NULL);
 409     void set_gravity(float, float);
 410     void set_level(int);
 411     void set_visible(bool);
 412     void notify_on_top(bool);
 413 
 414     void enter_fullscreen();
 415     void exit_fullscreen();
 416 
 417     void set_owner(WindowContext*);
 418 
 419     GtkWindow *get_gtk_window();
 420     void detach_from_java();
 421 protected:
 422     void applyShapeMask(void*, uint width, uint height);
 423 private:
 424     bool get_frame_extents_property(int *, int *, int *, int *);
 425     void request_frame_extents();
 426     void activate_window();
 427     void initialize_frame_extents();
 428     void window_configure(XWindowChanges *, unsigned int);
 429     void update_window_constraints();
 430     void set_window_resizable(bool, bool);
 431     void update_ontop_tree(bool);
 432     bool on_top_inherited();
 433     bool effective_on_top();
 434     WindowContextTop(WindowContextTop&);
 435     WindowContextTop& operator= (const WindowContextTop&);
 436 };
 437 
 438 void destroy_and_delete_ctx(WindowContext* ctx);
 439 
 440 class EventsCounterHelper {
 441 private:
 442     WindowContext* ctx;
 443 public:
 444     explicit EventsCounterHelper(WindowContext* context) {
 445         ctx = context;
 446         ctx->increment_events_counter();
 447     }
 448     ~EventsCounterHelper() {
 449         ctx->decrement_events_counter();
 450         if (ctx->is_dead() && ctx->get_events_count() == 0) {
 451             delete ctx;
 452         }
 453         ctx = NULL;
 454     }
 455 };
 456 
 457 #endif        /* GLASS_WINDOW_H */
 458