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