1 /*
  2  * Copyright �� 2006 Novell, Inc.
  3  *
  4  * This library is free software; you can redistribute it and/or
  5  * modify it under the terms of the GNU Lesser General Public
  6  * License as published by the Free Software Foundation; either
  7  * version 2 of the License, or (at your option) any later version.
  8  *
  9  * This library is distributed in the hope that it will be useful,
 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
 12  * Lesser General Public License for more details.
 13  *
 14  * You should have received a copy of the GNU Lesser General Public
 15  * License along with this library; if not, write to the
 16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 17  * Boston, MA 02111-1307, USA.
 18  *
 19  * Author: David Reveman <davidr@novell.com>
 20  *
 21  * 2D Mode: Copyright �� 2010 Sam Spilsbury <smspillaz@gmail.com>
 22  * Frames Management: Copright �� 2011 Canonical Ltd.
 23  *        Authored By: Sam Spilsbury <sam.spilsbury@canonical.com>
 24  */
 25 
 26 #include "gtk-window-decorator.h"
 27 #include "local-menus.h"
 28 
 29 const gchar *
 30 get_frame_type (WnckWindow *win)
 31 {
 32     WnckWindowType wnck_type = wnck_window_get_window_type (win);
 33 
 34     switch (wnck_type)
 35     {
 36 	case WNCK_WINDOW_NORMAL:
 37 	    return "normal";
 38 	case WNCK_WINDOW_DIALOG:
 39 	{
 40 	    Atom	  actual;
 41 	    int		  result, format;
 42 	    unsigned long n, left;
 43 	    unsigned char *data;
 44 
 45 	    result = XGetWindowProperty (gdk_x11_get_default_xdisplay (), wnck_window_get_xid (win),
 46 					 net_wm_state_atom,
 47 					 0L, 1024L, FALSE, XA_ATOM, &actual, &format,
 48 					 &n, &left, &data);
 49 
 50 	    if (result == Success && data)
 51 	    {
 52 		Atom *a = (Atom *) data;
 53 
 54 		while (n--)
 55 		    if (*a++ == net_wm_state_modal_atom)
 56 		    {
 57 			XFree ((void *) data);
 58 			return "modal_dialog";
 59 		    }
 60 
 61 
 62 	    }
 63 
 64 	    return "dialog";
 65 	}
 66 	case WNCK_WINDOW_MENU:
 67 	    return "menu";
 68 	case WNCK_WINDOW_UTILITY:
 69 	    return "utility";
 70 	default:
 71 	    return "bare";
 72     }
 73 
 74     return "normal";
 75 }
 76 
 77 static void
 78 window_name_changed (WnckWindow *win)
 79 {
 80     decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
 81 
 82     if (d->decorated)
 83     {
 84 	if (!update_window_decoration_size (win))
 85 	    queue_decor_draw (d);
 86     }
 87 }
 88 
 89 static void
 90 window_geometry_changed (WnckWindow *win)
 91 {
 92     decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
 93 
 94     if (d->decorated)
 95     {
 96 	int width, height;
 97 
 98 	wnck_window_get_client_window_geometry (win, NULL, NULL,
 99 						&width, &height);
100 
101 	if (width != d->client_width || height != d->client_height)
102 	{
103 	    d->client_width  = width;
104 	    d->client_height = height;
105 
106 	    update_window_decoration_size (win);
107 	    update_event_windows (win);
108 	}
109     }
110 }
111 
112 static void
113 window_icon_changed (WnckWindow *win)
114 {
115     decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
116 
117     if (d->decorated)
118     {
119 	update_window_decoration_icon (win);
120 	queue_decor_draw (d);
121     }
122 }
123 
124 static void
125 window_state_changed (WnckWindow *win)
126 {
127     decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
128 
129     if (d->decorated)
130     {
131 	update_window_decoration_state (win);
132 	if (!update_window_decoration_size (win))
133 	    queue_decor_draw (d);
134 
135 	update_event_windows (win);
136     }
137 }
138 
139 static void
140 window_actions_changed (WnckWindow *win)
141 {
142     decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
143 
144     if (d->decorated)
145     {
146 	update_window_decoration_actions (win);
147 	if (!update_window_decoration_size (win))
148 	    queue_decor_draw (d);
149 
150 	update_event_windows (win);
151     }
152 }
153 
154 void
155 update_frames_border_extents (gpointer key,
156 			      gpointer value,
157 			      gpointer user_data)
158 {
159     decor_frame_t *frame = (decor_frame_t *) value;
160 
161     (*theme_update_border_extents) (frame);
162 }
163 
164 void
165 decorations_changed (WnckScreen *screen)
166 {
167     GdkDisplay *gdkdisplay;
168     GdkScreen  *gdkscreen;
169     GList      *windows;
170     Window     select;
171 
172     gdkdisplay = gdk_display_get_default ();
173     gdkscreen  = gdk_display_get_default_screen (gdkdisplay);
174 
175     gwd_frames_foreach (set_frames_scales, (gpointer) settings->font);
176 
177     update_titlebar_font ();
178     gwd_process_frames (update_frames_border_extents,
179                         window_type_frames,
180 			WINDOW_TYPE_FRAMES_NUM,
181 			NULL);
182     update_shadow ();
183 
184     update_default_decorations (gdkscreen);
185 
186     if (minimal)
187 	return;
188 
189     /* Update all normal windows */
190 
191     windows = wnck_screen_get_windows (screen);
192     while (windows != NULL)
193     {
194 	decor_t *d = g_object_get_data (G_OBJECT (windows->data), "decor");
195 
196 	if (d->decorated)
197 	{
198 
199 #ifdef USE_METACITY
200 	    if (d->draw == draw_window_decoration ||
201 		d->draw == meta_draw_window_decoration)
202 		d->draw = theme_draw_window_decoration;
203 #endif
204 
205 	}
206 
207 	update_window_decoration (WNCK_WINDOW (windows->data));
208 	windows = windows->next;
209     }
210 
211     /* Update switcher window */
212 
213     if (switcher_window &&
214 	get_window_prop (switcher_window->prop_xid,
215 			 select_window_atom, &select))
216     {
217 	decor_t *d = switcher_window;
218 	/* force size update */
219 	d->context = NULL;
220 	d->width = d->height = 0;
221 
222 	update_switcher_window (d->prop_xid, select);
223     }
224 }
225 
226 void
227 restack_window (WnckWindow *win,
228 		int	   stack_mode)
229 {
230     Display    *xdisplay;
231     GdkDisplay *gdkdisplay;
232     GdkScreen  *screen;
233     Window     xroot;
234     XEvent     ev;
235 
236     gdkdisplay = gdk_display_get_default ();
237     xdisplay   = GDK_DISPLAY_XDISPLAY (gdkdisplay);
238     screen     = gdk_display_get_default_screen (gdkdisplay);
239     xroot      = RootWindowOfScreen (gdk_x11_screen_get_xscreen (screen));
240 
241     if (action_menu_mapped)
242     {
243 	gtk_object_destroy (GTK_OBJECT (action_menu));
244 	action_menu_mapped = FALSE;
245 	action_menu = NULL;
246 	return;
247     }
248 
249     ev.xclient.type    = ClientMessage;
250     ev.xclient.display = xdisplay;
251 
252     ev.xclient.serial	  = 0;
253     ev.xclient.send_event = TRUE;
254 
255     ev.xclient.window	    = wnck_window_get_xid (win);
256     ev.xclient.message_type = restack_window_atom;
257     ev.xclient.format	    = 32;
258 
259     ev.xclient.data.l[0] = 2;
260     ev.xclient.data.l[1] = None;
261     ev.xclient.data.l[2] = stack_mode;
262     ev.xclient.data.l[3] = 0;
263     ev.xclient.data.l[4] = 0;
264 
265     XSendEvent (xdisplay, xroot, FALSE,
266 		SubstructureRedirectMask | SubstructureNotifyMask,
267 		&ev);
268 
269     XSync (xdisplay, FALSE);
270 }
271 
272 
273 void
274 add_frame_window (WnckWindow *win,
275 		  Window     frame,
276 		  Bool	     mode)
277 {
278     Display		 *xdisplay;
279     XSetWindowAttributes attr;
280     gulong		 xid = wnck_window_get_xid (win);
281     decor_t		 *d = g_object_get_data (G_OBJECT (win), "decor");
282     gint		 i, j;
283 
284     xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
285 
286     /* If we have already done this, there is no need to do it again, except
287      * if the property changed.
288      *
289      * The reason this check is here is because sometimes the PropertyNotify X
290      * event can come a bit after the property on the window is actually set
291      * which might result in this function being called twice - once by
292      * wnck through window_opened and once through our X event handler
293      * event_filter_func
294      */
295 
296     if (d->created && mode && d->frame_window)
297 	return;
298 
299     d->active = wnck_window_is_active (win);
300     d->win = win;
301     d->frame = gwd_get_decor_frame (get_frame_type (win));
302     d->last_pos_entered = NULL;
303 
304     attr.event_mask = ButtonPressMask | EnterWindowMask |
305 		      LeaveWindowMask | ExposureMask;
306     attr.override_redirect = TRUE;
307 
308     gdk_error_trap_push ();
309 
310     if (mode)
311     {
312 	GdkColormap *colormap;
313 
314 	d->frame_window = create_gdk_window (frame);
315 	d->decor_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
316 
317 	colormap = get_colormap_for_drawable (GDK_DRAWABLE (d->frame_window));
318 
319 	d->decor_image = gtk_image_new ();
320 
321 	gtk_widget_set_colormap (d->decor_window, colormap);
322 	gtk_widget_set_colormap (d->decor_image, colormap);
323 
324 	d->decor_event_box = gtk_event_box_new ();
325 	gtk_event_box_set_visible_window (GTK_EVENT_BOX (d->decor_event_box),
326 					  FALSE);
327 	gtk_widget_set_events (d->decor_event_box, GDK_BUTTON_PRESS_MASK |
328 						   GDK_BUTTON_RELEASE_MASK |
329 						   GDK_POINTER_MOTION_MASK);
330 
331 	g_signal_connect (G_OBJECT (d->decor_event_box), "button-press-event",
332 			  G_CALLBACK (frame_handle_button_press),
333 			  (gpointer) (d));
334 
335 	g_signal_connect (G_OBJECT (d->decor_event_box), "button-release-event",
336 			  G_CALLBACK (frame_handle_button_release),
337 			  (gpointer) (d));
338 
339 	g_signal_connect (G_OBJECT (d->decor_event_box), "motion-notify-event",
340 			  G_CALLBACK (frame_handle_motion),
341 			  (gpointer) (d));
342 
343 	gtk_container_add (GTK_CONTAINER (d->decor_event_box), d->decor_image);
344 	gtk_event_box_set_above_child (GTK_EVENT_BOX (d->decor_event_box), TRUE);
345 	gtk_widget_show_all (d->decor_event_box);
346 	gtk_window_set_decorated (GTK_WINDOW (d->decor_window), FALSE);
347 	gtk_window_set_default_size (GTK_WINDOW (d->decor_window), 1000, 1000);
348 	gtk_container_add (GTK_CONTAINER (d->decor_window), d->decor_event_box);
349 
350 	/* Assumed realization happens here */
351 
352 	g_signal_connect (G_OBJECT (d->decor_window), "realize",
353 			  G_CALLBACK (frame_window_realized), (gpointer) d);
354 
355 	gtk_widget_show_all (d->decor_window);
356 	gtk_widget_show (d->decor_window);
357 
358 	g_object_set_data (G_OBJECT (d->frame_window),
359 			   "client_wnck_window", win);
360     }
361     else
362     {
363 	d->frame_window = NULL;
364 
365 	for (i = 0; i < 3; i++)
366 	{
367 	    for (j = 0; j < 3; j++)
368 	    {
369 		d->event_windows[i][j].window =
370 		XCreateWindow (xdisplay,
371 			       frame,
372 			       0, 0, 1, 1, 0,
373 			       CopyFromParent, CopyFromParent, CopyFromParent,
374 			       CWOverrideRedirect | CWEventMask, &attr);
375 
376 		if (cursor[i][j].cursor)
377 		    XDefineCursor (xdisplay, d->event_windows[i][j].window,
378 		    cursor[i][j].cursor);
379 
380 		XGrabButton (xdisplay,
381 			     Button1Mask,
382 			     AnyModifier,
383 			     d->event_windows[i][j].window,
384 			     FALSE,
385 			     ButtonPressMask |
386 			     ButtonReleaseMask |
387 			     PointerMotionMask,
388 			     GrabModeAsync,
389 			     GrabModeAsync,
390 			     None,
391 			     None);
392 	    }
393 	}
394 
395 	attr.event_mask |= ButtonReleaseMask;
396 
397 	for (i = 0; i < BUTTON_NUM; i++)
398 	{
399 	    d->button_windows[i].window =
400 	    XCreateWindow (xdisplay,
401 			   frame,
402 			   0, 0, 1, 1, 0,
403 			   CopyFromParent, CopyFromParent, CopyFromParent,
404 			   CWOverrideRedirect | CWEventMask, &attr);
405 
406 
407 	    XGrabButton (xdisplay,
408 			 Button1Mask,
409 			 AnyModifier,
410 			 d->button_windows[i].window,
411 			 FALSE,
412 			 ButtonPressMask |
413 			 ButtonReleaseMask |
414 			 PointerMotionMask,
415 			 GrabModeAsync,
416 			 GrabModeAsync,
417 			 None,
418 			 None);
419 
420 	    d->button_states[i] = 0;
421 	}
422     }
423 
424     gdk_display_sync (gdk_display_get_default ());
425     if (!gdk_error_trap_pop ())
426     {
427 	if (get_mwm_prop (xid) & (MWM_DECOR_ALL | MWM_DECOR_TITLE))
428 	    d->decorated = TRUE;
429 
430 	for (i = 0; i < 3; i++)
431 	    for (j = 0; j < 3; j++)
432 	    {
CID 10013 - PW.PARAMETER_HIDDEN
declaration hides parameter "win" (declared at line 274)
433 		Window win = d->event_windows[i][j].window;
434 		g_hash_table_insert (frame_table,
435 				     GINT_TO_POINTER (win),
436 				     GINT_TO_POINTER (xid));
437 	    }
438 
439 	for (i = 0; i < BUTTON_NUM; i++)
440 	    g_hash_table_insert (frame_table,
441 				 GINT_TO_POINTER (d->button_windows[i].window),
442 				 GINT_TO_POINTER (xid));
443 
444 	if (d->frame_window)
445 	{
446 	    g_hash_table_insert (frame_table,
447 				 GINT_TO_POINTER (frame),
448 				 GINT_TO_POINTER (xid));
449 	}
450 	update_window_decoration_state (win);
451 	update_window_decoration_actions (win);
452 	update_window_decoration_icon (win);
453 	update_window_decoration_size (win);
454 
455 	update_event_windows (win);
456     }
457     else
458     {
459 	for (i = 0; i < 3; i++)
460 	    for (j = 0; j < 3; j++)
461 		d->event_windows[i][j].window = None;
462     }
463 
464     d->created = TRUE;
465 }
466 
467 void
468 remove_frame_window (WnckWindow *win)
469 {
470     decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
471     Display *xdisplay;
472 
473     xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
474 
475     if (d->pixmap)
476     {
477 	g_object_unref (G_OBJECT (d->pixmap));
478 	d->pixmap = NULL;
479     }
480 
481     if (d->buffer_pixmap)
482     {
483 	g_object_unref (G_OBJECT (d->buffer_pixmap));
484 	d->buffer_pixmap = NULL;
485     }
486 
487     if (d->cr)
488     {
489 	cairo_destroy (d->cr);
490 	d->cr = NULL;
491     }
492 
493     if (d->picture && !d->frame_window)
494     {
495 	XRenderFreePicture (xdisplay, d->picture);
496 	d->picture = 0;
497     }
498 
499     if (d->name)
500     {
501 	g_free (d->name);
502 	d->name = NULL;
503     }
504 
505     if (d->layout)
506     {
507 	g_object_unref (G_OBJECT (d->layout));
508 	d->layout = NULL;
509     }
510 
511     if (d->icon)
512     {
513 	cairo_pattern_destroy (d->icon);
514 	d->icon = NULL;
515     }
516 
517     if (d->icon_pixmap)
518     {
519 	g_object_unref (G_OBJECT (d->icon_pixmap));
520 	d->icon_pixmap = NULL;
521     }
522 
523     if (d->icon_pixbuf)
524     {
525 	g_object_unref (G_OBJECT (d->icon_pixbuf));
526 	d->icon_pixbuf = NULL;
527     }
528 
529     if (d->force_quit_dialog)
530     {
531 	GtkWidget *dialog = d->force_quit_dialog;
532 
533 	d->force_quit_dialog = NULL;
534 	gtk_widget_destroy (dialog);
535     }
536 
537     if (d->frame_window)
538     {
539 	gdk_window_destroy (d->frame_window);
540 	d->frame_window = NULL;
541     }
542 
543     if (d->decor_image)
544     {
545 	g_object_unref (d->decor_image);
546 	d->decor_image = NULL;
547     }
548 
549     if (d->decor_event_box)
550     {
551 	g_object_unref (d->decor_event_box);
552 	d->decor_event_box = NULL;
553     }
554 
555     if (d->decor_window)
556     {
557 	g_object_unref (d->decor_window);
558 	d->decor_window = NULL;
559     }
560 
561     if (d->frame)
562     {
563 	gwd_decor_frame_unref (d->frame);
564 	d->frame = NULL;
565     }
566 
567     gdk_error_trap_push ();
568     XDeleteProperty (xdisplay, wnck_window_get_xid (win), win_decor_atom);
569     gdk_display_sync (gdk_display_get_default ());
570     gdk_error_trap_pop ();
571 
572     d->width  = 0;
573     d->height = 0;
574 
575     d->decorated = FALSE;
576 
577     d->state   = 0;
578     d->actions = 0;
579 
580     d->context = NULL;
581     d->shadow  = NULL;
582 
583     draw_list = g_slist_remove (draw_list, d);
584 }
585 
586 void
587 connect_window (WnckWindow *win)
588 {
589     g_signal_connect_object (win, "name_changed",
590 			     G_CALLBACK (window_name_changed),
591 			     0, 0);
592     g_signal_connect_object (win, "geometry_changed",
593 			     G_CALLBACK (window_geometry_changed),
594 			     0, 0);
595     g_signal_connect_object (win, "icon_changed",
596 			     G_CALLBACK (window_icon_changed),
597 			     0, 0);
598     g_signal_connect_object (win, "state_changed",
599 			     G_CALLBACK (window_state_changed),
600 			     0, 0);
601     g_signal_connect_object (win, "actions_changed",
602 			     G_CALLBACK (window_actions_changed),
603 			     0, 0);
604 }
605 
606 static void
607 active_window_changed (WnckScreen *screen)
608 {
609     WnckWindow *win;
610     decor_t    *d;
611 
612     win = wnck_screen_get_previously_active_window (screen);
613     if (win)
614     {
615 	d = g_object_get_data (G_OBJECT (win), "decor");
616 	if (d && d->pixmap)
617 	{
618 	    d->active = wnck_window_is_active (win);
619 
620             decor_frame_t *frame = d->decorated ? d->frame : gwd_get_decor_frame (get_frame_type (win));
621 
622 	    if ((d->state & META_MAXIMIZED) == META_MAXIMIZED)
623 	    {
624 		if (!d->frame_window)
625 		{
626 		   if (d->active)
627 		   {
628 		       d->context = &frame->max_window_context_active;
629 		       d->shadow  = frame->max_border_shadow_active;
630 		   }
631 		   else
632 		   {
633 		       d->context = &frame->max_window_context_inactive;
634 		       d->shadow  = frame->max_border_shadow_inactive;
635 		   }
636                 }
637                 else
638                 {
639 		   d->shadow  = d->frame->max_border_no_shadow;
640                 }
641 	    }
642 	    else
643 	    {
644 	       if (!d->frame_window)
645 	       {
646 		   if (d->active)
647 		   {
648 		       d->context = &frame->window_context_active;
649 		       d->shadow  = frame->border_shadow_active;
650 		   }
651 		   else
652 		   {
653 		       d->context = &frame->window_context_inactive;
654 		       d->shadow  = frame->border_shadow_inactive;
655 		   }
656 	       }
657 	       else
658 	       {
659 		   d->shadow  = d->frame->border_no_shadow;
660 	       }
661 	    }
662 
663             if (!d->decorated)
664                 gwd_decor_frame_unref (frame);
665 
666 	    /* We need to update the decoration size here
667 	    * since the shadow size might have changed and
668 	    * in that case the decoration will be redrawn,
669 	    * however if the shadow size doesn't change
670 	    * then we need to redraw the decoration anyways
671 	    * since the image would have changed */
672 	    if (d->win != NULL &&
673 		!update_window_decoration_size (d->win) &&
674 		d->decorated)
675 		queue_decor_draw (d);
676 
677 	}
678     }
679 
680     win = wnck_screen_get_active_window (screen);
681     if (win)
682     {
683 	d = g_object_get_data (G_OBJECT (win), "decor");
684 	if (d && d->pixmap)
685 	{
686 	    d->active = wnck_window_is_active (win);
687 
688             decor_frame_t *frame = d->decorated ? d->frame : gwd_get_decor_frame (get_frame_type (win));
689 
690 	    if ((d->state & META_MAXIMIZED) == META_MAXIMIZED)
691 	    {
692 		if (!d->frame_window)
693 		{
694 		   if (d->active)
695 		   {
696 		       d->context = &frame->max_window_context_active;
697 		       d->shadow  = frame->max_border_shadow_active;
698 		   }
699 		   else
700 		   {
701 		       d->context = &frame->max_window_context_inactive;
702 		       d->shadow  = frame->max_border_shadow_inactive;
703 		   }
704 		}
705 		else
706 		{
707 		   d->shadow  = frame->max_border_no_shadow;
708 		}
709 	    }
710 	    else
711 	    {
712 		if (!d->frame_window)
713 		{
714 		   if (d->active)
715 		   {
716 		       d->context = &frame->window_context_active;
717 		       d->shadow  = frame->border_shadow_active;
718 		   }
719 		   else
720 		   {
721 		       d->context = &frame->window_context_inactive;
722 		       d->shadow  = frame->border_shadow_inactive;
723 		   }
724 		}
725 		else
726 		{
727 		   d->shadow =  frame->border_no_shadow;
728 		}
729 	    }
730 
731             if (!d->decorated)
732                 gwd_decor_frame_unref (frame);
733 
734 	    /* We need to update the decoration size here
735 	    * since the shadow size might have changed and
736 	    * in that case the decoration will be redrawn,
737 	    * however if the shadow size doesn't change
738 	    * then we need to redraw the decoration anyways
739 	    * since the image would have changed */
740 	    if (d->win != NULL &&
741 		!update_window_decoration_size (d->win) &&
742 		d->decorated)
743 		queue_decor_draw (d);
744 
745 	}
746     }
747 }
748 
749 void
750 window_opened (WnckScreen *screen,
751 	       WnckWindow *win)
752 {
753     decor_t      *d;
754     Window       window;
755     gulong       xid;
756     unsigned int i, j;
757 
758     static event_callback callback[3][3] = {
759 	{ top_left_event,    top_event,    top_right_event    },
760 	{ left_event,	     title_event,  right_event	      },
761 	{ bottom_left_event, bottom_event, bottom_right_event }
762     };
763     static event_callback button_callback[BUTTON_NUM] = {
764 	close_button_event,
765 	max_button_event,
766 	min_button_event,
767 	menu_button_event,
768 	shade_button_event,
769 	above_button_event,
770 	stick_button_event,
771 	unshade_button_event,
772 	unabove_button_event,
773 	unstick_button_event,
774 	window_menu_button_event
775     };
776 
777     d = calloc (1, sizeof (decor_t));
778     if (!d)
779 	return;
780 
781     for (i = 0; i < 3; i++)
782 	for (j = 0; j < 3; j++)
783 	    d->event_windows[i][j].callback = callback[i][j];
784 
785     for (i = 0; i < BUTTON_NUM; i++)
786 	d->button_windows[i].callback = button_callback[i];
787 
788     wnck_window_get_client_window_geometry (win, NULL, NULL,
789 					    &d->client_width,
790 					    &d->client_height);
791 
792     d->draw = theme_draw_window_decoration;
793 
794     d->created = FALSE;
795     d->pixmap = NULL;
796     d->cr = NULL;
797     d->buffer_pixmap = NULL;
798     d->picture = None;
799 
800     connect_window (win);
801 
802     g_object_set_data (G_OBJECT (win), "decor", d);
803 
804     xid = wnck_window_get_xid (win);
805 
806     if (get_window_prop (xid, frame_input_window_atom, &window))
807     {
808 	add_frame_window (win, window, FALSE);
809     }
810     else if (get_window_prop (xid, frame_output_window_atom, &window))
811     {
812 	add_frame_window (win, window, TRUE);
813     }
814 }
815 
816 void
817 window_closed (WnckScreen *screen,
818 	       WnckWindow *win)
819 {
820     local_menu_cache_notify_window_destroyed (wnck_window_get_xid (win));
821 
822     decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
823 
824     if (d)
825     {
826 	remove_frame_window (win);
827 	g_object_set_data (G_OBJECT (win), "decor", NULL);
828 	g_free (d);
829     }
830 }
831 
832 void
833 connect_screen (WnckScreen *screen)
834 {
835     GList *windows;
836 
837     g_signal_connect_object (G_OBJECT (screen), "active_window_changed",
838                              G_CALLBACK (active_window_changed),
839                              0, 0);
840     g_signal_connect_object (G_OBJECT (screen), "window_opened",
841                              G_CALLBACK (window_opened),
842                              0, 0);
843     g_signal_connect_object (G_OBJECT (screen), "window_closed",
844                              G_CALLBACK (window_closed),
845                              0, 0);
846 
847     windows = wnck_screen_get_windows (screen);
848     while (windows != NULL)
849     {
850         window_opened (screen, windows->data);
851         windows = windows->next;
852     }
853 }