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