frame.c

Go to the documentation of this file.
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
00002 
00003 /* Metacity X window decorations */
00004 
00005 /* 
00006  * Copyright (C) 2001 Havoc Pennington
00007  * Copyright (C) 2003, 2004 Red Hat, Inc.
00008  * Copyright (C) 2005 Elijah Newren
00009  * 
00010  * This program is free software; you can redistribute it and/or
00011  * modify it under the terms of the GNU General Public License as
00012  * published by the Free Software Foundation; either version 2 of the
00013  * License, or (at your option) any later version.
00014  *
00015  * This program is distributed in the hope that it will be useful, but
00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018  * General Public License for more details.
00019  * 
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software
00022  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
00023  * 02111-1307, USA.
00024  */
00025 
00026 #include <config.h>
00027 #include "frame-private.h"
00028 #include "bell.h"
00029 #include "errors.h"
00030 #include "keybindings.h"
00031 
00032 #ifdef HAVE_RENDER
00033 #include <X11/extensions/Xrender.h>
00034 #endif
00035 
00036 #define EVENT_MASK (SubstructureRedirectMask |                     \
00037                     StructureNotifyMask | SubstructureNotifyMask | \
00038                     ExposureMask |                                 \
00039                     ButtonPressMask | ButtonReleaseMask |          \
00040                     PointerMotionMask | PointerMotionHintMask |    \
00041                     EnterWindowMask | LeaveWindowMask |            \
00042                     FocusChangeMask |                              \
00043                     ColormapChangeMask)
00044 
00045 void
00046 meta_window_ensure_frame (MetaWindow *window)
00047 {
00048   MetaFrame *frame;
00049   XSetWindowAttributes attrs;
00050   Visual *visual;
00051   
00052   if (window->frame)
00053     return;
00054   
00055   /* See comment below for why this is required. */
00056   meta_display_grab (window->display);
00057   
00058   frame = g_new (MetaFrame, 1);
00059 
00060   frame->window = window;
00061   frame->xwindow = None;
00062 
00063   frame->rect = window->rect;
00064   frame->child_x = 0;
00065   frame->child_y = 0;
00066   frame->bottom_height = 0;
00067   frame->right_width = 0;
00068   frame->current_cursor = 0;
00069 
00070   frame->mapped = FALSE;
00071   frame->need_reapply_frame_shape = TRUE;
00072   frame->is_flashing = FALSE;
00073   
00074   meta_verbose ("Framing window %s: visual %s default, depth %d default depth %d\n",
00075                 window->desc,
00076                 XVisualIDFromVisual (window->xvisual) ==
00077                 XVisualIDFromVisual (window->screen->default_xvisual) ?
00078                 "is" : "is not",
00079                 window->depth, window->screen->default_depth);
00080   meta_verbose ("Frame geometry %d,%d  %dx%d\n",
00081                 frame->rect.x, frame->rect.y,
00082                 frame->rect.width, frame->rect.height);
00083   
00084   /* Default depth/visual handles clients with weird visuals; they can
00085    * always be children of the root depth/visual obviously, but
00086    * e.g. DRI games can't be children of a parent that has the same
00087    * visual as the client. NULL means default visual.
00088    *
00089    * We look for an ARGB visual if we can find one, otherwise use
00090    * the default of NULL.
00091    */
00092   
00093   /* Special case for depth 32 windows (assumed to be ARGB),
00094    * we use the window's visual. Otherwise we just use the system visual.
00095    */
00096   if (window->depth == 32)
00097     visual = window->xvisual;
00098   else
00099     visual = NULL;
00100   
00101   frame->xwindow = meta_ui_create_frame_window (window->screen->ui,
00102                                                 window->display->xdisplay,
00103                                                 visual,
00104                                                 frame->rect.x,
00105                                                 frame->rect.y,
00106                                                 frame->rect.width,
00107                                                 frame->rect.height,
00108                                                 frame->window->screen->number);
00109 
00110   meta_verbose ("Frame for %s is 0x%lx\n", frame->window->desc, frame->xwindow);
00111   attrs.event_mask = EVENT_MASK;
00112   XChangeWindowAttributes (window->display->xdisplay,
00113                            frame->xwindow, CWEventMask, &attrs);
00114   
00115   meta_display_register_x_window (window->display, &frame->xwindow, window);
00116 
00117   /* Now that frame->xwindow is registered with window, we can set its
00118    * background.
00119    */
00120   meta_ui_reset_frame_bg (window->screen->ui, frame->xwindow);
00121 
00122   /* Reparent the client window; it may be destroyed,
00123    * thus the error trap. We'll get a destroy notify later
00124    * and free everything. Comment in FVWM source code says
00125    * we need a server grab or the child can get its MapNotify
00126    * before we've finished reparenting and getting the decoration
00127    * window onscreen, so ensure_frame must be called with
00128    * a grab.
00129    */
00130   meta_error_trap_push (window->display);
00131   if (window->mapped)
00132     {
00133       window->mapped = FALSE; /* the reparent will unmap the window,
00134                                * we don't want to take that as a withdraw
00135                                */
00136       meta_topic (META_DEBUG_WINDOW_STATE,
00137                   "Incrementing unmaps_pending on %s for reparent\n", window->desc);
00138       window->unmaps_pending += 1;
00139     }
00140   /* window was reparented to this position */
00141   window->rect.x = 0;
00142   window->rect.y = 0;
00143 
00144   XReparentWindow (window->display->xdisplay,
00145                    window->xwindow,
00146                    frame->xwindow,
00147                    window->rect.x,
00148                    window->rect.y);
00149   /* FIXME handle this error */
00150   meta_error_trap_pop (window->display, FALSE);
00151   
00152   /* stick frame to the window */
00153   window->frame = frame;
00154   
00155   if (window->title)
00156     meta_ui_set_frame_title (window->screen->ui,
00157                              window->frame->xwindow,
00158                              window->title);
00159 
00160   /* Move keybindings to frame instead of window */
00161   meta_window_grab_keys (window);
00162 
00163   /* Shape mask */
00164   meta_ui_apply_frame_shape (frame->window->screen->ui,
00165                              frame->xwindow,
00166                              frame->rect.width,
00167                              frame->rect.height,
00168                              frame->window->has_shape);
00169   frame->need_reapply_frame_shape = FALSE;
00170   
00171   meta_display_ungrab (window->display);
00172 }
00173 
00174 void
00175 meta_window_destroy_frame (MetaWindow *window)
00176 {
00177   MetaFrame *frame;
00178   
00179   if (window->frame == NULL)
00180     return;
00181 
00182   meta_verbose ("Unframing window %s\n", window->desc);
00183   
00184   frame = window->frame;
00185   
00186   meta_bell_notify_frame_destroy (frame);
00187   
00188   /* Unparent the client window; it may be destroyed,
00189    * thus the error trap.
00190    */
00191   meta_error_trap_push (window->display);
00192   if (window->mapped)
00193     {
00194       window->mapped = FALSE; /* Keep track of unmapping it, so we
00195                                * can identify a withdraw initiated
00196                                * by the client.
00197                                */
00198       meta_topic (META_DEBUG_WINDOW_STATE,
00199                   "Incrementing unmaps_pending on %s for reparent back to root\n", window->desc);
00200       window->unmaps_pending += 1;
00201     }
00202   XReparentWindow (window->display->xdisplay,
00203                    window->xwindow,
00204                    window->screen->xroot,
00205                    /* Using anything other than meta_window_get_position()
00206                     * coordinates here means we'll need to ensure a configure
00207                     * notify event is sent; see bug 399552.
00208                     */
00209                    window->frame->rect.x,
00210                    window->frame->rect.y);
00211   meta_error_trap_pop (window->display, FALSE);
00212 
00213   meta_ui_destroy_frame_window (window->screen->ui, frame->xwindow);
00214 
00215   meta_display_unregister_x_window (window->display,
00216                                     frame->xwindow);
00217   
00218   window->frame = NULL;
00219 
00220   /* Move keybindings to window instead of frame */
00221   meta_window_grab_keys (window);
00222   
00223   g_free (frame);
00224   
00225   /* Put our state back where it should be */
00226   meta_window_queue (window, META_QUEUE_CALC_SHOWING);
00227 }
00228 
00229 
00230 MetaFrameFlags
00231 meta_frame_get_flags (MetaFrame *frame)
00232 {
00233   MetaFrameFlags flags;
00234 
00235   flags = 0;
00236 
00237   if (frame->window->border_only)
00238     {
00239       ; /* FIXME this may disable the _function_ as well as decor
00240          * in some cases, which is sort of wrong.
00241          */
00242     }
00243   else
00244     {
00245       flags |= META_FRAME_ALLOWS_MENU;
00246       
00247       if (frame->window->has_close_func)
00248         flags |= META_FRAME_ALLOWS_DELETE;
00249       
00250       if (frame->window->has_maximize_func)
00251         flags |= META_FRAME_ALLOWS_MAXIMIZE;
00252       
00253       if (frame->window->has_minimize_func)
00254         flags |= META_FRAME_ALLOWS_MINIMIZE;
00255       
00256       if (frame->window->has_shade_func)
00257         flags |= META_FRAME_ALLOWS_SHADE;
00258     }  
00259   
00260   if (META_WINDOW_ALLOWS_MOVE (frame->window))
00261     flags |= META_FRAME_ALLOWS_MOVE;
00262 
00263   if (META_WINDOW_ALLOWS_HORIZONTAL_RESIZE (frame->window))
00264     flags |= META_FRAME_ALLOWS_HORIZONTAL_RESIZE;
00265 
00266   if (META_WINDOW_ALLOWS_VERTICAL_RESIZE (frame->window))
00267     flags |= META_FRAME_ALLOWS_VERTICAL_RESIZE;
00268   
00269   if (frame->window->has_focus)
00270     flags |= META_FRAME_HAS_FOCUS;
00271 
00272   if (frame->window->shaded)
00273     flags |= META_FRAME_SHADED;
00274 
00275   if (frame->window->on_all_workspaces)
00276     flags |= META_FRAME_STUCK;
00277 
00278   /* FIXME: Should we have some kind of UI for windows that are just vertically
00279    * maximized or just horizontally maximized?
00280    */
00281   if (META_WINDOW_MAXIMIZED (frame->window))
00282     flags |= META_FRAME_MAXIMIZED;
00283 
00284   if (frame->window->fullscreen)
00285     flags |= META_FRAME_FULLSCREEN;
00286 
00287   if (frame->is_flashing)
00288     flags |= META_FRAME_IS_FLASHING;
00289 
00290   if (frame->window->wm_state_above)
00291     flags |= META_FRAME_ABOVE;
00292   
00293   return flags;
00294 }
00295 
00296 void
00297 meta_frame_calc_geometry (MetaFrame         *frame,
00298                           MetaFrameGeometry *geomp)
00299 {
00300   MetaFrameGeometry geom;
00301   MetaWindow *window;
00302 
00303   window = frame->window;
00304 
00305   meta_ui_get_frame_geometry (window->screen->ui,
00306                               frame->xwindow,
00307                               &geom.top_height,
00308                               &geom.bottom_height,
00309                               &geom.left_width,
00310                               &geom.right_width);
00311   
00312   *geomp = geom;
00313 }
00314 
00315 static void
00316 update_shape (MetaFrame *frame)
00317 {
00318   if (frame->need_reapply_frame_shape)
00319     {
00320       meta_ui_apply_frame_shape (frame->window->screen->ui,
00321                                  frame->xwindow,
00322                                  frame->rect.width,
00323                                  frame->rect.height,
00324                                  frame->window->has_shape);
00325       frame->need_reapply_frame_shape = FALSE;
00326     }
00327 }
00328 
00329 void
00330 meta_frame_sync_to_window (MetaFrame *frame,
00331                            int        resize_gravity,
00332                            gboolean   need_move,
00333                            gboolean   need_resize)
00334 {
00335   if (!(need_move || need_resize))
00336     {
00337       update_shape (frame);
00338       return;
00339     }
00340 
00341   meta_topic (META_DEBUG_GEOMETRY,
00342               "Syncing frame geometry %d,%d %dx%d (SE: %d,%d)\n",
00343               frame->rect.x, frame->rect.y,
00344               frame->rect.width, frame->rect.height,
00345               frame->rect.x + frame->rect.width,
00346               frame->rect.y + frame->rect.height);
00347 
00348   /* set bg to none to avoid flicker */
00349   if (need_resize)
00350     {
00351       meta_ui_unflicker_frame_bg (frame->window->screen->ui,
00352                                   frame->xwindow,
00353                                   frame->rect.width,
00354                                   frame->rect.height);
00355 
00356       /* we need new shape if we're resized */
00357       frame->need_reapply_frame_shape = TRUE;
00358     }
00359 
00360   /* Done before the window resize, because doing it before means
00361    * part of the window being resized becomes unshaped, which may
00362    * be sort of hard to see with bg = None. If we did it after
00363    * window resize, part of the window being resized would become
00364    * shaped, which might be more visible.
00365    */
00366   update_shape (frame);
00367   
00368   meta_ui_move_resize_frame (frame->window->screen->ui,
00369                              frame->xwindow,
00370                              frame->rect.x,
00371                              frame->rect.y,
00372                              frame->rect.width,
00373                              frame->rect.height);
00374 
00375   if (need_resize)
00376     {
00377       meta_ui_reset_frame_bg (frame->window->screen->ui,
00378                               frame->xwindow);
00379 
00380       /* If we're interactively resizing the frame, repaint
00381        * it immediately so we don't start to lag.
00382        */
00383       if (frame->window->display->grab_window ==
00384           frame->window)
00385         meta_ui_repaint_frame (frame->window->screen->ui,
00386                                frame->xwindow);
00387     }
00388 }
00389 
00390 void
00391 meta_frame_queue_draw (MetaFrame *frame)
00392 {
00393   meta_ui_queue_frame_draw (frame->window->screen->ui,
00394                             frame->xwindow);
00395 }
00396 
00397 void
00398 meta_frame_set_screen_cursor (MetaFrame *frame,
00399                               MetaCursor cursor)
00400 {
00401   Cursor xcursor;
00402   if (cursor == frame->current_cursor)
00403     return;
00404   frame->current_cursor = cursor;
00405   if (cursor == META_CURSOR_DEFAULT)
00406     XUndefineCursor (frame->window->display->xdisplay, frame->xwindow);
00407   else
00408     { 
00409       xcursor = meta_display_create_x_cursor (frame->window->display, cursor);
00410       XDefineCursor (frame->window->display->xdisplay, frame->xwindow, xcursor);
00411       XFlush (frame->window->display->xdisplay);
00412       XFreeCursor (frame->window->display->xdisplay, xcursor);
00413     }
00414 }
00415 
00416 Window
00417 meta_frame_get_xwindow (MetaFrame *frame)
00418 {
00419   return frame->xwindow;
00420 }

Generated on Sat Aug 23 22:04:16 2008 for metacity by  doxygen 1.5.5