1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * xstuff.c: assorted X11-specific routines for pho.
4 *
5 * Most of this comes from
6 * http://www.opensource.apple.com/source/gcc/gcc-5483/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkWindowPeer.c
7 *
8 * To build as a standalone demo:
9 gcc `pkg-config --cflags --libs gtk+-2.0` -o winman -DSTANDALONE=1 winman.c
10 */
11
12 #include <gtk/gtk.h>
13 #include <gdk/gdkx.h>
14
15 static Atom extents_atom = 0;
16
17 static Bool
property_notify_predicate(Display * xdisplay,XEvent * event,XPointer window_id)18 property_notify_predicate (Display *xdisplay __attribute__((unused)),
19 XEvent *event,
20 XPointer window_id)
21 {
22 unsigned long *window = (unsigned long *) window_id;
23
24 if (event->xany.type == PropertyNotify
25 && event->xany.window == *window
26 && event->xproperty.atom == extents_atom)
27 return True;
28 else
29 return False;
30 }
31
32 /* Requests that the window manager set window's
33 _NET_FRAME_EXTENTS property. */
34 void
request_frame_extents(GtkWidget * window)35 request_frame_extents (GtkWidget *window)
36 {
37 const char *request_str = "_NET_REQUEST_FRAME_EXTENTS";
38 GdkAtom request_extents = gdk_atom_intern (request_str, FALSE);
39
40 /* Check if the current window manager supports
41 _NET_REQUEST_FRAME_EXTENTS. */
42 if (gdk_net_wm_supports (request_extents))
43 {
44 GdkDisplay *display = gtk_widget_get_display (window);
45 Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
46
47 GdkWindow *root_window = gdk_get_default_root_window ();
48 Window xroot_window = GDK_WINDOW_XID (root_window);
49
50 Atom extents_request_atom =
51 gdk_x11_get_xatom_by_name_for_display (display, request_str);
52
53 XEvent xevent;
54 XEvent notify_xevent;
55
56 /* This doesn't work if window==GWin */
57 unsigned long window_id = GDK_WINDOW_XID (GDK_DRAWABLE(window->window));
58
59 if (!extents_atom)
60 {
61 const char *extents_str = "_NET_FRAME_EXTENTS";
62 extents_atom =
63 gdk_x11_get_xatom_by_name_for_display (display, extents_str);
64 }
65
66 xevent.xclient.type = ClientMessage;
67 xevent.xclient.message_type = extents_request_atom;
68 xevent.xclient.display = xdisplay;
69 xevent.xclient.window = window_id;
70 xevent.xclient.format = 32;
71 xevent.xclient.data.l[0] = 0;
72 xevent.xclient.data.l[1] = 0;
73 xevent.xclient.data.l[2] = 0;
74 xevent.xclient.data.l[3] = 0;
75 xevent.xclient.data.l[4] = 0;
76
77 XSendEvent (xdisplay, xroot_window, False,
78 (SubstructureRedirectMask | SubstructureNotifyMask),
79 &xevent);
80
81 XIfEvent(xdisplay, ¬ify_xevent,
82 property_notify_predicate, (XPointer) &window_id);
83 }
84 }
85
86 #ifdef STANDALONE
87 void
88 window_get_frame_extents (GtkWidget *window, int *width, int *height);
89
90 int gDebug = 1;
91
HandleExpose(GtkWidget * widget,GdkEventExpose * event)92 static gint HandleExpose(GtkWidget* widget, GdkEventExpose* event)
93 {
94 gint width, height;
95 gdk_drawable_get_size(widget->window, &width, &height);
96
97 printf("HandleExpose: area %dx%d +%d+%d in window %dx%d\n",
98 event->area.width, event->area.height,
99 event->area.x, event->area.y,
100 width, height);
101 if (event->area.x != 0 || event->area.y != 0) {
102 if (event->area.width != width || event->area.height != height)
103 printf("*** Expose different from window size!\n");
104 }
105 }
106
main(int argc,char ** argv)107 int main(int argc, char** argv)
108 {
109 int gMonitorWidth, gMonitorHeight;
110
111 gint sFrameWidth = -1;
112 gint sFrameHeight = -1;
113 static GdkColor sBlack;
114
115 GtkWidget *gWin = 0;
116 static GtkWidget *sDrawingArea = 0;
117
118 gtk_init(&argc, &argv);
119 gMonitorWidth = gdk_screen_width();
120 gMonitorHeight = gdk_screen_height();
121
122 gWin = gtk_window_new(GTK_WINDOW_TOPLEVEL);
123
124 // gtk_signal_connect(GTK_OBJECT(gWin), "key_press_event",
125 // (GtkSignalFunc)HandleGlobalKeys, 0);
126 sDrawingArea = gtk_drawing_area_new();
127 gtk_container_add(GTK_CONTAINER(gWin), sDrawingArea);
128 gtk_widget_show(sDrawingArea);
129
130 gtk_drawing_area_size(GTK_DRAWING_AREA(sDrawingArea),
131 gMonitorWidth, gMonitorHeight);
132 gtk_window_unfullscreen(GTK_WINDOW(gWin));
133
134 gtk_signal_connect(GTK_OBJECT(sDrawingArea), "expose_event",
135 (GtkSignalFunc)HandleExpose, 0);
136 gtk_widget_show(gWin);
137
138 int width, height;
139 window_get_frame_extents (gWin, &sFrameWidth, &sFrameHeight);
140 printf("Frame size: %d, %d\n", sFrameWidth, sFrameHeight);
141
142 gtk_window_resize(GTK_WINDOW(gWin),
143 gMonitorWidth-sFrameWidth, gMonitorHeight-sFrameHeight);
144 printf("Resizing after frame extents to %dx%d\n",
145 gMonitorWidth-sFrameWidth, gMonitorHeight-sFrameHeight);
146 }
147 #endif
148
149 /* Try to find the size of the window decorations,
150 * using _NET_REQUEST_FRAME_EXTENTS
151 * gdk_window_get_frame_extents doesn't work until after the
152 * window is realized, by which time it's too late.
153 * This method works once the window is mapped but not realized.
154 */
155 void
window_get_frame_extents(GtkWidget * window,int * width,int * height)156 window_get_frame_extents (GtkWidget *window, int *width, int *height)
157 {
158 unsigned long *extents = NULL;
159 extern int gDebug;
160
161 /* I'm not sure whether is_visible or is_viewable is better here.
162 * is_viewable requires that the window and its ancestors be mapped;
163 * is_visible, just the window. Unfortunately, there's no documentation
164 * on what's needed to make gdk_window_get_frame_extents() work.
165 */
166 if (gdk_window_is_viewable(window->window)) {
167 GdkRectangle rect;
168 gint winwidth, winheight;
169
170 gdk_drawable_get_size(window->window, &winwidth, &winheight);
171 gdk_window_get_frame_extents(window->window, &rect);
172 *width = rect.width - winwidth;
173 *height = rect.height - winheight;
174
175 if (gDebug)
176 printf("get_frame_extents from visible window: %dx%d\n",
177 *width, *height);
178 return;
179 }
180
181 /* Otherwise, the window isn't visible, so maybe we'll be able to
182 * get the X property (which just hangs if the window already exists).
183 */
184 if (gDebug)
185 printf("Window isn't visible; requestiong NET_FRAME_EXTENTS\n");
186
187 /* Guess frame extents in case _NET_FRAME_EXTENTS is not
188 supported. */
189 *height = 29;
190 *width = 12;
191
192 /* Request that the window manager set window's
193 _NET_FRAME_EXTENTS property.
194 */
195 request_frame_extents (window);
196
197 /* Attempt to retrieve window's frame extents. */
198 if (gdk_property_get (window->window,
199 gdk_atom_intern ("_NET_FRAME_EXTENTS", FALSE),
200 gdk_atom_intern ("CARDINAL", FALSE),
201 0,
202 sizeof (unsigned long) * 4,
203 FALSE,
204 NULL,
205 NULL,
206 NULL,
207 (guchar**)&extents))
208 {
209 *width = extents[0] + extents[1];
210 *height = extents[2] + extents[3];
211 }
212 }
213