1 /* Copyright (c) 2008 Vincent Povirk
3 Permission is hereby granted, free of charge, to any person
4 obtaining a copy of this software and associated documentation
5 files (the "Software"), to deal in the Software without
6 restriction, including without limitation the rights to use,
7 copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the
9 Software is furnished to do so, subject to the following
12 The above copyright notice and this permission notice shall be
13 included in all copies or substantial portions of the Software.
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17 OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 OTHER DEALINGS IN THE SOFTWARE.
25 #include "lucca-display-private.h"
27 /* Implementation of LuccaWindow */
29 static GObjectClass
* parent_class
= NULL
;
31 static GData
* state_atom_constants
;
40 static void lucca_window_init(GTypeInstance
* instance
, gpointer g_class
) {
41 LuccaWindow
* window
= LUCCA_WINDOW(instance
);
43 window
->valid
= FALSE
;
45 window
->dispose_has_run
= FALSE
;
47 window
->display
= NULL
;
48 window
->window
= NULL
;
50 window
->xwmhints
= NULL
;
51 window
->properties_set
= NULL
;
52 window
->window_parent
= NULL
;
53 window
->requested_title
= NULL
;
54 window
->owner_callback
= NULL
;
58 static void lucca_window_dispose(GObject
* obj
) {
59 LuccaWindow
* window
= LUCCA_WINDOW(obj
);
61 if (window
->dispose_has_run
) {
64 window
->dispose_has_run
= TRUE
;
66 window
->valid
= FALSE
;
68 g_object_unref(window
->display
);
69 window
->display
= NULL
;
71 g_object_unref(window
->window
);
72 window
->window
= NULL
;
75 g_object_unref(window
->bin
);
80 if (window
->xwmhints
) {
81 XFree(window
->xwmhints
);
84 g_datalist_clear(&window
->properties_set
);
86 g_object_unref(window
->window_parent
);
87 window
->window_parent
= NULL
;
89 g_free(window
->requested_title
);
90 window
->requested_title
= NULL
;
92 G_OBJECT_CLASS(parent_class
)->dispose(obj
);
95 static void lucca_window_get_property(GObject
* object
, guint property_id
, GValue
* value
, GParamSpec
* pspec
) {
96 LuccaWindow
* window
= LUCCA_WINDOW(object
);
98 switch (property_id
) {
100 g_value_set_boolean(value
, window
->valid
);
102 case PROP_REQUESTED_TITLE
:
103 g_value_set_string(value
, window
->requested_title
);
106 g_value_set_object(value
, window
->bin
);
109 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
,property_id
,pspec
);
114 static void lucca_window_class_init(gpointer g_class
, gpointer class_data
) {
115 LuccaWindowClass
* klass
= (LuccaWindowClass
*)g_class
;
116 GObjectClass
* gobclass
= G_OBJECT_CLASS(g_class
);
119 /* method overrides */
120 gobclass
->dispose
= lucca_window_dispose
;
121 gobclass
->get_property
= lucca_window_get_property
;
124 pspec
= g_param_spec_boolean(
127 "TRUE if this manages a display's windows",
128 0, /* default value */
130 g_object_class_install_property(gobclass
, PROP_VALID
, pspec
);
132 pspec
= g_param_spec_string(
135 "The title the application requested for this window",
136 "", /* default value */
138 g_object_class_install_property(gobclass
, PROP_REQUESTED_TITLE
, pspec
);
140 pspec
= g_param_spec_object(
143 "The GTK window for an internal LuccaWindow",
146 g_object_class_install_property(gobclass
, PROP_WINDOW
, pspec
);
150 klass
->withdraw_signal_id
= g_signal_new(
152 G_TYPE_FROM_CLASS(g_class
),
154 0, /* class_offset */
155 NULL
, /* accumulator */
156 NULL
, /* accu_data */
157 g_cclosure_marshal_VOID__VOID
,
162 parent_class
= g_type_class_peek_parent(klass
);
164 g_datalist_init(&state_atom_constants
);
165 g_datalist_set_data(&state_atom_constants
, "_NET_WM_STATE_MODAL", GINT_TO_POINTER(LUCCA_STATE_MODAL
));
166 g_datalist_set_data(&state_atom_constants
, "_NET_WM_STATE_STICKY", GINT_TO_POINTER(LUCCA_STATE_STICKY
));
167 g_datalist_set_data(&state_atom_constants
, "_NET_WM_STATE_MAXIMIZED_VIRT", GINT_TO_POINTER(LUCCA_STATE_MAXIMIZED_VIRT
));
168 g_datalist_set_data(&state_atom_constants
, "_NET_WM_STATE_MAXIMIZED_HORZ", GINT_TO_POINTER(LUCCA_STATE_MAXIMIZED_HORZ
));
169 g_datalist_set_data(&state_atom_constants
, "_NET_WM_STATE_SHADED", GINT_TO_POINTER(LUCCA_STATE_SHADED
));
170 g_datalist_set_data(&state_atom_constants
, "_NET_WM_STATE_SKIP_TASKBAR", GINT_TO_POINTER(LUCCA_STATE_SKIP_TASKBAR
));
171 g_datalist_set_data(&state_atom_constants
, "_NET_WM_STATE_SKIP_PAGER", GINT_TO_POINTER(LUCCA_STATE_SKIP_PAGER
));
172 g_datalist_set_data(&state_atom_constants
, "_NET_WM_STATE_HIDDEN", GINT_TO_POINTER(LUCCA_STATE_HIDDEN
));
173 g_datalist_set_data(&state_atom_constants
, "_NET_WM_STATE_FULLSCREEN", GINT_TO_POINTER(LUCCA_STATE_FULLSCREEN
));
174 g_datalist_set_data(&state_atom_constants
, "_NET_WM_STATE_ABOVE", GINT_TO_POINTER(LUCCA_STATE_ABOVE
));
175 g_datalist_set_data(&state_atom_constants
, "_NET_WM_STATE_BELOW", GINT_TO_POINTER(LUCCA_STATE_BELOW
));
176 g_datalist_set_data(&state_atom_constants
, "_NET_WM_STATE_DEMANDS_ATTENTION", GINT_TO_POINTER(LUCCA_STATE_DEMANDS_ATTENTION
));
179 GType
lucca_window_get_type() {
180 static GType type
= 0;
182 static const GTypeInfo info
= {
183 sizeof (LuccaWindowClass
),
184 NULL
, /* base_init */
185 NULL
, /* base_finalize */
186 lucca_window_class_init
,
187 NULL
, /* class_finalize */
188 NULL
, /* class_data */
189 sizeof (LuccaWindow
),
193 type
= g_type_register_static (G_TYPE_OBJECT
, "LuccaWindowType", &info
, 0);
198 /* Method definitions */
200 /* retrieves a window's title from the X server; the result should be freed with g_free() */
201 static gchar
* _get_requested_title(LuccaWindow
* window
) {
204 result
= lucca_window_get_utf8(window
, "_NET_WM_NAME");
206 if (result
== NULL
) {
207 result
= lucca_window_get_utf8(window
, "WM_NAME");
213 static XWMHints
* _get_wm_hints(LuccaWindow
* window
) {
216 if (window
->badwindow
|| !g_datalist_get_data(&window
->properties_set
, "WM_HINTS")) {
220 gdk_error_trap_push();
221 result
= XGetWMHints(window
->display
->xdisplay
, window
->xwindow
);
223 if (gdk_error_trap_pop() == BadWindow
) {
224 window
->badwindow
= TRUE
;
231 static void _update_normal_hints(LuccaWindow
* window
) {
234 if (window
->badwindow
|| !g_datalist_get_data(&window
->properties_set
, "WM_NORMAL_HINTS")) {
235 window
->xsizehints_supplied
= 0;
239 gdk_error_trap_push();
240 status
= XGetWMNormalHints(window
->display
->xdisplay
, window
->xwindow
, &window
->xsizehints
, &window
->xsizehints_supplied
);
242 if (gdk_error_trap_pop() == BadWindow
) {
243 window
->badwindow
= TRUE
;
244 window
->xsizehints_supplied
= 0;
248 LuccaWindow
* lucca_window_new(Window xwindow
, LuccaScreen
* screen
, gboolean existing
, gboolean internal
) {
249 XWindowAttributes xattr
;
251 GData
* properties_set
;
252 Atom
* property_atoms
;
256 GdkWindow
* gdkwindow
;
258 gdkwindow
= gdk_window_foreign_new_for_display(screen
->display
->display
, xwindow
);
259 if (g_hash_table_lookup(screen
->display
->valid_windows
, gdkwindow
)) {
263 /* make sure it wants to be managed */
264 gdk_error_trap_push();
265 status
= XGetWindowAttributes(screen
->display
->xdisplay
, xwindow
, &xattr
);
267 if (gdk_error_trap_pop()) {
268 /* the window doesn't exist anymore */
271 if ((existing
&& xattr
.map_state
!= IsViewable
) || (xattr
.override_redirect
&& !internal
)) {
272 /* this is either an existing unmapped window or a non-internal override_redirect window; ignore it */
276 /* get a list of properties for the window; knowing if a property exists makes requesting various information faster later */
277 g_datalist_init(&properties_set
);
278 gdk_error_trap_push();
279 property_atoms
= XListProperties(screen
->display
->xdisplay
, xwindow
, &property_count
);
281 if (gdk_error_trap_pop()) {
282 /* the window doesn't exist anymore */
283 g_datalist_clear(&properties_set
);
286 for (i
=0; i
<property_count
; i
++) {
287 g_datalist_set_data(&properties_set
, XGetAtomName(screen
->display
->xdisplay
, property_atoms
[i
]), GINT_TO_POINTER(1));
289 XFree(property_atoms
);
291 result
= g_object_new(LUCCA_TYPE_WINDOW
, NULL
);
293 result
->valid
= TRUE
;
294 result
->badwindow
= FALSE
;
295 result
->internal
= internal
;
296 result
->window
= gdkwindow
;
297 result
->xwindow
= xwindow
;
298 result
->xattr
= xattr
;
299 result
->display
= g_object_ref(screen
->display
);
300 result
->properties_set
= properties_set
;
302 if (xattr
.map_state
== IsViewable
) {
303 result
->icccm_state
= NormalState
;
306 result
->icccm_state
= WithdrawnState
;
309 /* get other information about the window from the server */
310 result
->requested_title
= _get_requested_title(result
);
311 result
->xwmhints
= _get_wm_hints(result
);
312 _update_normal_hints(result
);
313 result
->window_parent
= g_object_ref(screen
->root
);
315 g_hash_table_insert(screen
->display
->valid_windows
, result
->window
, result
);
317 if (!xattr
.override_redirect
) {
318 g_signal_emit(screen
->display
, LUCCA_DISPLAY_GET_CLASS(screen
->display
)->new_window_signal_id
, 0, result
);
324 LuccaWindow
* lucca_window_new_internal(LuccaBin
* bin
, LuccaScreen
* screen
) {
327 XWindowAttributes xattr
;
330 GData
* properties_set
;
331 Atom
* property_atoms
;
335 window
= g_object_ref(GTK_WIDGET(bin
)->window
);
336 xwindow
= GDK_WINDOW_XWINDOW(window
);
338 XGetWindowAttributes(screen
->display
->xdisplay
, xwindow
, &xattr
);
340 /* get a list of properties for the window; knowing if a property exists makes requesting various information faster later */
341 g_datalist_init(&properties_set
);
342 gdk_error_trap_push();
343 property_atoms
= XListProperties(screen
->display
->xdisplay
, xwindow
, &property_count
);
345 if (gdk_error_trap_pop()) {
346 /* the window doesn't exist anymore */
347 g_datalist_clear(&properties_set
);
350 for (i
=0; i
<property_count
; i
++) {
351 g_datalist_set_data(&properties_set
, XGetAtomName(screen
->display
->xdisplay
, property_atoms
[i
]), GINT_TO_POINTER(1));
353 XFree(property_atoms
);
355 result
= g_object_new(LUCCA_TYPE_WINDOW
, NULL
);
357 result
->valid
= TRUE
;
358 result
->badwindow
= FALSE
;
359 result
->internal
= TRUE
;
360 result
->xattr
= xattr
;
361 result
->window
= window
;
362 result
->xwindow
= xwindow
;
364 result
->display
= g_object_ref(screen
->display
);
365 result
->properties_set
= properties_set
;
366 result
->icccm_state
= WithdrawnState
;
368 /* get other information about the window from the server */
369 result
->requested_title
= _get_requested_title(result
);
370 result
->xwmhints
= _get_wm_hints(result
);
371 _update_normal_hints(result
);
372 result
->window_parent
= g_object_ref(screen
->root
);
374 hash_key
= g_malloc(sizeof(Window
));
376 g_hash_table_insert(screen
->display
->valid_windows
, hash_key
, result
);
378 if (!xattr
.override_redirect
) {
379 g_signal_emit(screen
->display
, LUCCA_DISPLAY_GET_CLASS(screen
->display
)->new_window_signal_id
, 0, result
);
385 gchar
* lucca_window_get_utf8(LuccaWindow
* window
, gchar
* property
) {
390 unsigned long nitems
;
391 unsigned long length
;
392 unsigned long bytes_after
;
393 unsigned char* data
=NULL
;
397 /* if the property isn't set, return no strings */
398 if (window
->badwindow
|| !g_datalist_get_data(&window
->properties_set
, property
)) {
402 prop
= XInternAtom(window
->display
->xdisplay
, property
, True
);
404 gdk_error_trap_push();
405 status
= XGetWindowProperty(
406 window
->display
->xdisplay
, /* display */
407 window
->xwindow
, /* window */
412 AnyPropertyType
, /* req_type */
413 &xactual_type
, /* actual_type_return */
414 &actual_format
, /* actual_format_return */
415 &nitems
, /* nitems_return */
416 &length
, /* bytes_after_return */
417 &data
/* prop_return */
423 if (status
== Success
) {
424 status
= XGetWindowProperty(
425 window
->display
->xdisplay
, /* display */
426 window
->xwindow
, /* window */
429 (length
+3)/4, /* long_length */
431 AnyPropertyType
, /* req_type */
432 &xactual_type
, /* actual_type_return */
433 &actual_format
, /* actual_format_return */
434 &nitems
, /* nitems_return */
435 &bytes_after
, /* bytes_after_return */
436 &data
/* prop_return */
439 if (status
== Success
) {
440 nitems
= gdk_text_property_to_utf8_list_for_display(
441 window
->display
->display
, /* display */
442 gdk_atom_intern(XGetAtomName(window
->display
->xdisplay
, xactual_type
), FALSE
), /* encoding */
443 actual_format
, /* format */
449 value
= g_strdup(list
[0]);
457 if (gdk_error_trap_pop() == BadWindow
) {
458 window
->badwindow
= TRUE
;
464 /* lucca_window_get_atoms: get a list of atoms in a window property, to be freed with XFree() */
465 Atom
* lucca_window_get_atoms(LuccaWindow
* window
, gchar
* property
, guint
* length
) {
470 unsigned long nitems
;
472 unsigned long bytes_after
;
473 unsigned char* data
=NULL
;
477 /* if the property isn't set, return no strings */
478 if (window
->badwindow
|| !g_datalist_get_data(&window
->properties_set
, property
)) {
482 prop
= XInternAtom(window
->display
->xdisplay
, property
, True
);
484 gdk_error_trap_push();
485 status
= XGetWindowProperty(
486 window
->display
->xdisplay
, /* display */
487 window
->xwindow
, /* window */
492 window
->display
->xatom_atom
, /* req_type */
493 &xactual_type
, /* actual_type_return */
494 &actual_format
, /* actual_format_return */
495 &nitems
, /* nitems_return */
496 &size
, /* bytes_after_return */
497 &data
/* prop_return */
503 if (status
== Success
) {
504 status
= XGetWindowProperty(
505 window
->display
->xdisplay
, /* display */
506 window
->xwindow
, /* window */
509 (size
+3)/4, /* long_length */
511 window
->display
->xatom_atom
, /* req_type */
512 &xactual_type
, /* actual_type_return */
513 &actual_format
, /* actual_format_return */
514 &nitems
, /* nitems_return */
515 &bytes_after
, /* bytes_after_return */
516 &data
/* prop_return */
519 if (status
== Success
) {
520 *length
= size
/sizeof(Atom
);
525 if (gdk_error_trap_pop() == BadWindow
) {
526 window
->badwindow
= TRUE
;
532 void lucca_window_get_geometry_hints(LuccaWindow
* window
, GdkGeometry
* geometry
, GdkWindowHints
* geom_mask
) {
533 g_assert(window
->valid
);
535 if (window
->xwmhints
== NULL
) {
540 if (window
->xsizehints_supplied
& USPosition
) {
541 *geom_mask
|= GDK_HINT_USER_POS
;
544 if (window
->xsizehints_supplied
& USSize
) {
545 *geom_mask
|= GDK_HINT_USER_SIZE
;
548 if (window
->xsizehints_supplied
& PPosition
) {
549 *geom_mask
|= GDK_HINT_POS
;
552 /* if (window->xsizehints_supplied & PSize) ... no field in GdkWindowHints corresponds to this */
554 if (window
->xsizehints_supplied
& PMinSize
) {
555 *geom_mask
|= GDK_HINT_MIN_SIZE
;
556 geometry
->min_width
= window
->xsizehints
.min_width
;
557 geometry
->min_height
= window
->xsizehints
.min_height
;
560 if (window
->xsizehints_supplied
& PMaxSize
) {
561 *geom_mask
|= GDK_HINT_MAX_SIZE
;
562 geometry
->max_width
= window
->xsizehints
.max_width
;
563 geometry
->max_height
= window
->xsizehints
.max_height
;
566 if (window
->xsizehints_supplied
& PResizeInc
) {
567 *geom_mask
|= GDK_HINT_RESIZE_INC
;
568 geometry
->width_inc
= window
->xsizehints
.width_inc
;
569 geometry
->height_inc
= window
->xsizehints
.height_inc
;
572 if (window
->xsizehints_supplied
& PAspect
) {
573 *geom_mask
|= GDK_HINT_ASPECT
;
574 geometry
->min_aspect
= (gdouble
)window
->xsizehints
.min_aspect
.x
/ (gdouble
)window
->xsizehints
.min_aspect
.y
;
575 geometry
->max_aspect
= (gdouble
)window
->xsizehints
.max_aspect
.x
/ (gdouble
)window
->xsizehints
.max_aspect
.y
;
578 if (window
->xsizehints_supplied
& PBaseSize
) {
579 *geom_mask
|= GDK_HINT_BASE_SIZE
;
580 geometry
->base_width
= window
->xsizehints
.base_width
;
581 geometry
->base_height
= window
->xsizehints
.base_height
;
584 if (window
->xsizehints_supplied
& PWinGravity
) {
585 *geom_mask
|= GDK_HINT_WIN_GRAVITY
;
586 geometry
->win_gravity
= (GdkGravity
)window
->xsizehints
.win_gravity
;
590 void lucca_window_get_requested_states(LuccaWindow
* window
, LuccaState
** states
, guint
* statecount
) {
592 guint state_atom_count
;
595 g_assert(window
->valid
);
597 state_atoms
= lucca_window_get_atoms(window
, "_NET_WM_STATE", &state_atom_count
);
599 if (state_atoms
== NULL
) {
600 /* no _NET_WM_STATE, fall back on WM_HINTS */
601 if ((window
->xwmhints
->flags
& StateHint
) && (window
->xwmhints
->initial_state
== IconicState
)) {
603 *states
= g_malloc(sizeof(LuccaState
));
604 *states
[0] = LUCCA_STATE_HIDDEN
;
612 *states
= g_malloc(sizeof(LuccaState
) * state_atom_count
);
614 for (i
=0; i
<state_atom_count
; i
++) {
615 LuccaState state
= GPOINTER_TO_INT(g_datalist_get_data(&state_atom_constants
, XGetAtomName(window
->display
->xdisplay
, state_atoms
[i
])));
617 *states
[j
++] = state
;
625 void lucca_window_configure(LuccaWindow
* window
, GdkWindow
* parent
, gint x
, gint y
, gint width
, gint height
, gboolean visible
) {
626 ICCCM_STATE new_icccm_state
;
627 gboolean window_is_mapped
;
630 g_assert(window
->valid
);
633 new_icccm_state
= NormalState
;
636 new_icccm_state
= IconicState
;
639 if (window
->badwindow
) {
640 /* the window doesn't exist anymore; pretend everything worked */
641 if (parent
!= window
->window_parent
) {
642 g_object_unref(window
->window_parent
);
643 window
->window_parent
= g_object_ref(parent
);
645 window
->icccm_state
= new_icccm_state
;
648 window
->xattr
.width
= width
;
649 window
->xattr
.height
= height
;
652 gdk_error_trap_push();
654 /* if the window is being reparented, we want to unmap, reparent, resize, and then remap it so that we don't end up with an intermediate step where the window is reparented with the wrong size; also, unmap it if we're asked to make it not visible */
655 if (((parent
!= window
->window_parent
) && (window
->icccm_state
== NormalState
)) || !visible
) {
656 if (window
->internal
) {
657 gtk_widget_hide(GTK_WIDGET(window
->bin
));
660 XUnmapWindow(window
->display
->xdisplay
, window
->xwindow
);
662 window_is_mapped
= FALSE
;
664 else if (window
->icccm_state
== NormalState
) {
665 window_is_mapped
= TRUE
;
668 window_is_mapped
= FALSE
;
671 if ((new_icccm_state
!= window
->icccm_state
) && (!window
->internal
)) {
672 ICCCM_WM_STATE new_wm_state
;
673 GdkAtom wm_state_atom
= gdk_atom_intern("WM_STATE", TRUE
);
674 new_wm_state
.state
= new_icccm_state
;
675 new_wm_state
.icon
= None
;
678 window
->window
, /* window */
679 wm_state_atom
, /* property */
680 wm_state_atom
, /* type */
682 GDK_PROP_MODE_REPLACE
, /* mode */
683 (guchar
*)&new_wm_state
, /* data */
686 window
->icccm_state
= new_icccm_state
;
689 if (parent
!= window
->window_parent
) {
690 if (window
->internal
) {
691 lucca_bin_set_parent(window
->bin
, parent
);
694 XReparentWindow(window
->display
->xdisplay
, window
->xwindow
, GDK_WINDOW_XWINDOW(parent
), x
, y
);
696 g_object_unref(window
->window_parent
);
697 window
->window_parent
= g_object_ref(parent
);
700 if (window
->internal
) {
701 lucca_bin_move_resize(window
->bin
, x
, y
, width
, height
);
704 XMoveResizeWindow(window
->display
->xdisplay
, window
->xwindow
, x
, y
, (unsigned)width
, (unsigned)height
);
707 if (visible
&& !window_is_mapped
) {
708 if (window
->internal
) {
709 gtk_widget_show(GTK_WIDGET(window
->bin
));
712 XMapWindow(window
->display
->xdisplay
, window
->xwindow
);
718 error
= gdk_error_trap_pop();
719 if (error
== BadWindow
) {
720 window
->badwindow
= TRUE
;
722 else if (error
!= 0) {
723 g_error("Unexpected X error: %i\n", error
);
728 void lucca_window_change_owner(LuccaWindow
* window
, GClosure
* callback
) {
729 if (window
->owner_callback
!= NULL
) {
732 g_value_init(&value
, LUCCA_TYPE_WINDOW
);
734 g_value_set_object(&value
, window
);
736 g_closure_invoke(window
->owner_callback
,
742 g_closure_unref(window
->owner_callback
);
744 g_value_unset(&value
);
747 window
->owner_callback
= callback
;
749 if (callback
!= NULL
) {
750 g_closure_ref(callback
);
751 g_closure_sink(callback
);
755 void lucca_window_withdraw_finish(LuccaWindow
* window
) {
756 if (!window
->badwindow
) {
760 wmstate
= gdk_atom_intern("WM_STATE", FALSE
);
762 gdk_error_trap_push();
764 gdk_property_delete(window
->window
, wmstate
);
768 error
= gdk_error_trap_pop();
769 if (error
== BadWindow
) {
770 window
->badwindow
= TRUE
;
772 else if (error
!= 0) {
773 g_error("Unexpected X error: %i\n", error
);
777 lucca_window_change_owner(window
, NULL
);
779 window
->badwindow
= TRUE
;
780 window
->valid
= FALSE
;
782 g_signal_emit(window
, LUCCA_WINDOW_GET_CLASS(window
)->withdraw_signal_id
, 0);